xref: /haiku/src/add-ons/mail_daemon/inbound_protocols/pop3/MessageIO.cpp (revision 893988af824e65e49e55f517b157db8386e8002b)
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