1 /* BMailMessageIO - Glue code for reading/writing messages directly from the 2 ** protocols but present a BPositionIO interface to the caller, while caching 3 ** the data read/written in a slave file. 4 ** 5 ** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. 6 */ 7 8 9 #include <BeBuild.h> 10 11 #include <stdio.h> 12 #include <malloc.h> 13 #include <string.h> 14 15 #include "MessageIO.h" 16 #include "SimpleMailProtocol.h" 17 18 BMailMessageIO::BMailMessageIO(SimpleMailProtocol *protocol, BPositionIO *dump_to, int32 seq_id) : 19 slave(dump_to), 20 message_id(seq_id), 21 network(protocol), 22 size(0), 23 state(READ_HEADER_NEXT) { 24 //-----do nothing, and do it well----- 25 } 26 27 28 ssize_t BMailMessageIO::ReadAt(off_t pos, void *buffer, size_t amountToRead) { 29 status_t errorCode; 30 char lastBytes [5]; 31 off_t old_pos = slave->Position(); 32 33 while ((pos + amountToRead) > size) { 34 if (state >= ALL_READING_DONE) 35 break; 36 switch (state) { 37 // Read (download from the mail server) just the message headers, 38 // and append a blank line if needed (so the header processing code 39 // can tell where the end of the headers is). Don't append too 40 // much otherwise the part after the header will appear mangled 41 // when it is overwritten in a full read. This can be useful for 42 // filters which discard the message after only reading the header, 43 // thus avoiding the time it takes to download the whole message. 44 case READ_HEADER_NEXT: 45 slave->SetSize(0); // Truncate the file. 46 slave->Seek(0,SEEK_SET); 47 errorCode = network->GetHeader(message_id,slave); 48 if (errorCode < 0) 49 return errorCode; 50 // See if it already ends in a blank line, if not, add enough 51 // end-of-lines to give a blank line. 52 slave->Seek (-4, SEEK_END); 53 strcpy (lastBytes, "xxxx"); 54 slave->Read (lastBytes, 4); 55 if (strcmp (lastBytes, "\r\n\r\n") != 0) { 56 if (strcmp (lastBytes + 2, "\r\n") == 0) 57 slave->Write("\r\n", 2); 58 else 59 slave->Write("\r\n\r\n", 4); 60 } 61 state = READ_BODY_NEXT; 62 break; 63 64 // OK, they want more than the headers. Read the whole message, 65 // starting from the beginning (network->Retrieve does a seek to 66 // the start of the file for POP3 so we have to read the whole 67 // thing). This wastes a slight amount of time on high speed 68 // connections, and on dial-up modem connections, hopefully the 69 // modem's V.90 data compression will make it very quick to 70 // retransmit the header portion. 71 case READ_BODY_NEXT: 72 slave->SetSize(0); // Truncate the file. 73 slave->Seek(0,SEEK_SET); 74 errorCode = network->Retrieve(message_id,slave); 75 if (errorCode < 0) 76 return errorCode; 77 state = ALL_READING_DONE; 78 break; 79 80 default: // Shouldn't happen. 81 return -1; 82 } 83 ResetSize(); 84 } 85 86 // Put the file position back at where it was, if possible. That's because 87 // ReadAt isn't supposed to affect the file position. 88 if (old_pos < size) 89 slave->Seek (old_pos, SEEK_SET); 90 else 91 slave->Seek (0, SEEK_END); 92 93 return slave->ReadAt(pos,buffer,amountToRead); 94 } 95 96 97 ssize_t BMailMessageIO::WriteAt(off_t pos, const void *buffer, size_t amountToWrite) { 98 ssize_t return_val; 99 100 return_val = slave->WriteAt(pos,buffer,amountToWrite); 101 ResetSize(); 102 103 return return_val; 104 } 105 106 off_t BMailMessageIO::Seek(off_t position, uint32 seek_mode) { 107 ssize_t errorCode; 108 char tempBuffer [1]; 109 110 if (seek_mode == SEEK_END) { 111 if (state != ALL_READING_DONE) { 112 // Force it to read the whole message to find the size of it. 113 state = READ_BODY_NEXT; // Skip the header reading step. 114 errorCode = ReadAt (size + 1, tempBuffer, sizeof (tempBuffer)); 115 if (errorCode < 0) 116 return errorCode; 117 } 118 } 119 return slave->Seek(position,seek_mode); 120 } 121 122 off_t BMailMessageIO::Position() const { 123 return slave->Position(); 124 } 125 126 void BMailMessageIO::ResetSize(void) { 127 off_t old = slave->Position(); 128 129 slave->Seek(0,SEEK_END); 130 size = slave->Position(); 131 132 slave->Seek(old,SEEK_SET); 133 } 134 135 BMailMessageIO::~BMailMessageIO() { 136 delete slave; 137 } 138 139