Commit 4e0913bf 4e0913bf210cabf46e36866617158ef96ca90a91 by Alain Magloire

The big change: For getting the header we use "TOP # 0" but since TOP is an

optionnal command, we fallback to RETR and ignore the body part.  This ugly
and wastefull and it made the code unnecessary complexe.  But fortunately
I do not know of any POP server that does not have TOP. It's a mess.
The other stuff was little cleanups.
1 parent 526e7396
1 The current maintainer Alain Magloire <alainm@rcsm.ece.mcgill.ca> 1 The current maintainer Alain Magloire <alainm@gnu.org>
2 2
3 Brian Edmond <briane@qnx.com>
4 Dave Inglis <dinglis@qnx.com>
3 Jakob Kaivo <jkaivo@ndn.net> 5 Jakob Kaivo <jkaivo@ndn.net>
4 Jeff Bailey <jbailey@gnu.org> 6 Jeff Bailey <jbailey@gnu.org>
5 Sean 'Shaleh' Perry <shaleh@debian.org> 7 Sean 'Shaleh' Perry <shaleh@debian.org>
8
......
1 2000--5-19 Sean 'Shaleh' Perry <shaleh@debian.org> 1 2000-09-01 Alain Magloire
2
3 *
4 2000-5-19 Sean 'Shaleh' Perry <shaleh@debian.org>
2 5
3 * libmailbox/mh.c: fleshed out mh_open() some more 6 * libmailbox/mh.c: fleshed out mh_open() some more
4 7
......
...@@ -47,13 +47,11 @@ extern int body_get_filename __P ((body_t, char *, size_t, size_t *)); ...@@ -47,13 +47,11 @@ extern int body_get_filename __P ((body_t, char *, size_t, size_t *));
47 extern int body_set_filename __P ((body_t, const char*)); 47 extern int body_set_filename __P ((body_t, const char*));
48 48
49 extern int body_size __P ((body_t, size_t*)); 49 extern int body_size __P ((body_t, size_t*));
50 extern int body_set_size __P ((body_t, 50 extern int body_set_size __P ((body_t, int (*_size)
51 int (*_size) __P ((body_t, size_t*)), 51 __P ((body_t, size_t*)), void *owner));
52 void *owner));
53 extern int body_lines __P ((body_t, size_t *)); 52 extern int body_lines __P ((body_t, size_t *));
54 extern int body_set_lines __P ((body_t, 53 extern int body_set_lines __P ((body_t, int (*_lines)
55 int (*_lines) __P ((body_t, size_t*)), 54 __P ((body_t, size_t*)), void *owner));
56 void *owner));
57 55
58 #ifdef _cplusplus 56 #ifdef _cplusplus
59 } 57 }
......
...@@ -70,24 +70,29 @@ typedef struct _header * header_t; ...@@ -70,24 +70,29 @@ typedef struct _header * header_t;
70 extern int header_create __P ((header_t *, const char *, 70 extern int header_create __P ((header_t *, const char *,
71 size_t, void *)); 71 size_t, void *));
72 extern void header_destroy __P ((header_t *, void *)); 72 extern void header_destroy __P ((header_t *, void *));
73
73 extern int header_set_value __P ((header_t, const char *, 74 extern int header_set_value __P ((header_t, const char *,
74 const char *, int)); 75 const char *, int));
76 extern int header_set_set_value __P ((header_t, int (*_set_value)
77 __P ((header_t, const char *,
78 const char *, int)), void *));
79
75 extern int header_get_value __P ((header_t, const char *, char *, 80 extern int header_get_value __P ((header_t, const char *, char *,
76 size_t, size_t *)); 81 size_t, size_t *));
77 extern int header_get_stream __P ((header_t, stream_t *)); 82 extern int header_set_get_value __P ((header_t, int (*_get_value)
78 extern int header_size __P ((header_t, size_t *)); 83 __P ((header_t, const char *, char *,
79 extern int header_lines __P ((header_t, size_t *)); 84 size_t, size_t *)), void *));
80 85
86 extern int header_get_stream __P ((header_t, stream_t *));
81 extern int header_set_stream __P ((header_t, stream_t, void *)); 87 extern int header_set_stream __P ((header_t, stream_t, void *));
82 88
83 extern int header_set_set_value __P ((header_t, int (*_set_value) 89 extern int header_size __P ((header_t, size_t *));
84 __P ((header_t, const char *, 90 extern int header_set_size __P ((header_t, int (*_size)
85 const char *, int)), 91 __P ((header_t, size_t *)), void *));
86 void *)); 92
87 extern int header_set_get_value __P ((header_t, int (*_get_value) 93 extern int header_lines __P ((header_t, size_t *));
88 __P ((header_t, const char *, 94 extern int header_set_lines __P ((header_t, int (*_lines)
89 char *, size_t, size_t *)), 95 __P ((header_t, size_t *)), void *));
90 void *));
91 96
92 #ifdef _cplusplus 97 #ifdef _cplusplus
93 } 98 }
......
...@@ -55,39 +55,49 @@ extern int message_get_body __P ((message_t, body_t *)); ...@@ -55,39 +55,49 @@ extern int message_get_body __P ((message_t, body_t *));
55 extern int message_set_body __P ((message_t, body_t, void *owner)); 55 extern int message_set_body __P ((message_t, body_t, void *owner));
56 56
57 extern int message_get_stream __P ((message_t, stream_t *)); 57 extern int message_get_stream __P ((message_t, stream_t *));
58 extern int message_set_stream __P ((message_t, stream_t, void *owner));
58 59
59 extern int message_is_mime __P ((message_t)); 60 extern int message_is_multipart __P ((message_t, int *));
61 extern int message_set_is_multipart __P ((message_t, int (*_is_multipart)
62 __P ((message_t, int *)), void *));
60 63
61 extern int message_size __P ((message_t, size_t *)); 64 extern int message_size __P ((message_t, size_t *));
65 extern int message_set_size __P ((message_t, int (*_size)
66 __P ((message_t, size_t *)),
67 void *owner));
68
62 extern int message_lines __P ((message_t, size_t *)); 69 extern int message_lines __P ((message_t, size_t *));
70 extern int message_set_lines __P ((message_t, int (*_lines)
71 __P ((message_t, size_t *)),
72 void *owner));
63 73
64 extern int message_from __P ((message_t, char *, size_t, size_t *)); 74 extern int message_from __P ((message_t, char *, size_t, size_t *));
65 extern int message_set_from __P ((message_t, 75 extern int message_set_from __P ((message_t, int (*_from)
66 int (*_from) __P ((message_t, char *, 76 __P ((message_t, char *, size_t,
67 size_t, size_t *)), 77 size_t *)), void *owner));
68 void *owner)); 78
69 extern int message_received __P ((message_t, char *, size_t, size_t *)); 79 extern int message_received __P ((message_t, char *, size_t, size_t *));
70 extern int message_set_received __P ((message_t, int (*_received) 80 extern int message_set_received __P ((message_t, int (*_received)
71 __P ((message_t, char *, size_t, 81 __P ((message_t, char *, size_t,
72 size_t *)), void *owner)); 82 size_t *)), void *owner));
73 83
74 extern int message_get_attribute __P ((message_t, attribute_t *)); 84 extern int message_get_attribute __P ((message_t, attribute_t *));
75 extern int message_set_attribute __P ((message_t, attribute_t, void *owner)); 85 extern int message_set_attribute __P ((message_t, attribute_t, void *));
76 86
77 extern int message_get_num_parts __P ((message_t, size_t *nparts)); 87 extern int message_get_num_parts __P ((message_t, size_t *nparts));
78 extern int message_set_get_num_parts __P ((message_t, int (*_getNum_parts) 88 extern int message_set_get_num_parts __P ((message_t, int (*_get_num_parts)
79 __P ((message_t, size_t *)), 89 __P ((message_t, size_t *)),
80 void *owner)); 90 void *owner));
81 91
82 extern int message_get_part __P ((message_t, size_t part, message_t *msg)); 92 extern int message_get_part __P ((message_t, size_t, message_t *));
83 extern int message_set_get_part __P ((message_t, int (*_get_part) 93 extern int message_set_get_part __P ((message_t, int (*_get_part)
84 __P ((message_t, size_t, message_t *)), 94 __P ((message_t, size_t,
85 void *owner)); 95 message_t *)), void *owner));
86 96
87 extern int message_get_uidl __P ((message_t, char *buffer, size_t, size_t *)); 97 extern int message_get_uidl __P ((message_t, char *, size_t, size_t *));
88 extern int message_set_uidl __P ((message_t, int (*_get_uidl) 98 extern int message_set_uidl __P ((message_t, int (*_get_uidl)
89 __P ((message_t, char *, size_t, size_t *)), 99 __P ((message_t, char *, size_t,
90 void *owner)); 100 size_t *)), void *owner));
91 101
92 /* events */ 102 /* events */
93 #define MU_EVT_MSG_DESTROY 32 103 #define MU_EVT_MSG_DESTROY 32
......
...@@ -198,7 +198,8 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace) ...@@ -198,7 +198,8 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace)
198 if (header == NULL || fn == NULL || fv == NULL) 198 if (header == NULL || fn == NULL || fv == NULL)
199 return EINVAL; 199 return EINVAL;
200 200
201 if (header->_set_value != NULL) 201 /* Overload. */
202 if (header->_set_value)
202 return header->_set_value (header, fn, fv, replace); 203 return header->_set_value (header, fn, fv, replace);
203 204
204 /* Try to fill out the buffer, if we know how. */ 205 /* Try to fill out the buffer, if we know how. */
...@@ -268,7 +269,8 @@ header_get_value (header_t header, const char *name, char *buffer, ...@@ -268,7 +269,8 @@ header_get_value (header_t header, const char *name, char *buffer,
268 if (header == NULL || name == NULL) 269 if (header == NULL || name == NULL)
269 return EINVAL; 270 return EINVAL;
270 271
271 if (header->_get_value != NULL) 272 /* Overload. */
273 if (header->_get_value)
272 return header->_get_value (header, name, buffer, buflen, pn); 274 return header->_get_value (header, name, buffer, buflen, pn);
273 275
274 /* Try to fill out the buffer, if we know how. */ 276 /* Try to fill out the buffer, if we know how. */
...@@ -320,27 +322,36 @@ header_get_value (header_t header, const char *name, char *buffer, ...@@ -320,27 +322,36 @@ header_get_value (header_t header, const char *name, char *buffer,
320 if (pn) 322 if (pn)
321 *pn = total; 323 *pn = total;
322 324
323 /* Check if they provided a hook. */
324 if (total == 0) 325 if (total == 0)
325 {
326 err = ENOENT; 326 err = ENOENT;
327 if (header->_get_value != NULL) 327
328 err = header->_get_value (header, name, buffer, buflen, pn);
329 /* Success. Cache it locally. */
330 if (err == 0)
331 header_set_value (header, name, buffer, 0);
332 }
333 return err; 328 return err;
334 } 329 }
335 330
336 int 331 int
332 header_set_lines (header_t header, int (*_lines)
333 (header_t, size_t *), void *owner)
334 {
335 if (header == NULL)
336 return EINVAL;
337 if (header->owner != owner)
338 return EACCES;
339 header->_lines = _lines;
340 return 0;
341 }
342
343 int
337 header_lines (header_t header, size_t *plines) 344 header_lines (header_t header, size_t *plines)
338 { 345 {
339 int n; 346 int n;
340 size_t lines = 0; 347 size_t lines = 0;
341 if (header == NULL) 348 if (header == NULL || plines == NULL)
342 return EINVAL; 349 return EINVAL;
343 350
351 /* Overload. */
352 if (header->_lines)
353 return header->_lines (header, plines);
354
344 /* Try to fill out the buffer, if we know how. */ 355 /* Try to fill out the buffer, if we know how. */
345 if (header->blurb == NULL) 356 if (header->blurb == NULL)
346 { 357 {
...@@ -360,11 +371,27 @@ header_lines (header_t header, size_t *plines) ...@@ -360,11 +371,27 @@ header_lines (header_t header, size_t *plines)
360 } 371 }
361 372
362 int 373 int
363 header_size (header_t header, size_t *pnum) 374 header_set_size (header_t header, int (*_size)
375 (header_t, size_t *), void *owner)
376 {
377 if (header == NULL)
378 return EINVAL;
379 if (header->owner != owner)
380 return EACCES;
381 header->_size = _size;
382 return 0;
383 }
384
385 int
386 header_size (header_t header, size_t *psize)
364 { 387 {
365 if (header == NULL) 388 if (header == NULL)
366 return EINVAL; 389 return EINVAL;
367 390
391 /* Overload. */
392 if (header->_size)
393 return header->_size (header, psize);
394
368 /* Try to fill out the buffer, if we know how. */ 395 /* Try to fill out the buffer, if we know how. */
369 if (header->blurb == NULL) 396 if (header->blurb == NULL)
370 { 397 {
...@@ -373,8 +400,8 @@ header_size (header_t header, size_t *pnum) ...@@ -373,8 +400,8 @@ header_size (header_t header, size_t *pnum)
373 return err; 400 return err;
374 } 401 }
375 402
376 if (pnum) 403 if (psize)
377 *pnum = header->blurb_len; 404 *psize = header->blurb_len;
378 return 0; 405 return 0;
379 } 406 }
380 407
......
...@@ -43,6 +43,9 @@ mailbox_create (mailbox_t *pmbox, const char *name, int id) ...@@ -43,6 +43,9 @@ mailbox_create (mailbox_t *pmbox, const char *name, int id)
43 struct mailbox_registrar *mreg; 43 struct mailbox_registrar *mreg;
44 url_t url = NULL; 44 url_t url = NULL;
45 45
46 if (pmbox == NULL)
47 return EINVAL;
48
46 url_create (&url, name); 49 url_create (&url, name);
47 50
48 /* 1st guest: if an ID is specify, shortcut */ 51 /* 1st guest: if an ID is specify, shortcut */
...@@ -151,6 +154,14 @@ mailbox_scan (mailbox_t mbox, size_t msgno, size_t *pcount) ...@@ -151,6 +154,14 @@ mailbox_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
151 return mbox->_scan (mbox, msgno, pcount); 154 return mbox->_scan (mbox, msgno, pcount);
152 } 155 }
153 156
157 int
158 mailbox_size (mailbox_t mbox, off_t *psize)
159 {
160 if (mbox == NULL || mbox->_size == NULL)
161 return 0;
162 return mbox->_size (mbox, psize);
163 }
164
154 /* locking */ 165 /* locking */
155 int 166 int
156 mailbox_set_locker (mailbox_t mbox, locker_t locker) 167 mailbox_set_locker (mailbox_t mbox, locker_t locker)
......
...@@ -32,14 +32,20 @@ ...@@ -32,14 +32,20 @@
32 #include <header0.h> 32 #include <header0.h>
33 #include <attribute0.h> 33 #include <attribute0.h>
34 34
35 /* Advance declarations. */
36 struct _pop_data;
37 struct _pop_message;
38 struct _bio;
35 39
36 /* The different possible states of a Pop client, it maps to the POP3 commands. 40 typedef struct _pop_data * pop_data_t;
37 Note that POP3 is not reentrant. It is only one channel. */ 41 typedef struct _pop_message * pop_message_t;
42 typedef struct _bio *bio_t;
43
44 /* The different possible states of a Pop client, Note that POP3 is not
45 reentrant. It is only one channel. */
38 enum pop_state 46 enum pop_state
39 { 47 {
40 /* The initialisation of POP_NO_STATE is redundant but it is here for 48 POP_NO_STATE = 0, POP_STATE_DONE,
41 info purposes meaning 0 is the starting state. */
42 POP_NO_STATE = 0,
43 POP_OPEN_CONNECTION, 49 POP_OPEN_CONNECTION,
44 POP_GREETINGS, 50 POP_GREETINGS,
45 POP_APOP_TX, POP_APOP_ACK, 51 POP_APOP_TX, POP_APOP_ACK,
...@@ -54,8 +60,6 @@ enum pop_state ...@@ -54,8 +60,6 @@ enum pop_state
54 POP_TOP_TX, POP_TOP_ACK, POP_TOP_RX, 60 POP_TOP_TX, POP_TOP_ACK, POP_TOP_RX,
55 POP_UIDL_TX, POP_UIDL_ACK, 61 POP_UIDL_TX, POP_UIDL_ACK,
56 POP_USER_TX, POP_USER_ACK, 62 POP_USER_TX, POP_USER_ACK,
57 POP_CLOSE_CONNECTION /* I do not think a shutdown of a connection will
58 block. More for the symmetry. */
59 }; 63 };
60 64
61 /* Those two are exportable funtions i.e. they are visible/call when you 65 /* Those two are exportable funtions i.e. they are visible/call when you
...@@ -82,13 +86,17 @@ static int pop_is_updated (mailbox_t); ...@@ -82,13 +86,17 @@ static int pop_is_updated (mailbox_t);
82 86
83 /* The implementation of message_t */ 87 /* The implementation of message_t */
84 static int pop_size (mailbox_t, off_t *); 88 static int pop_size (mailbox_t, off_t *);
85 static int pop_readstream (stream_t, char *, size_t, off_t, size_t *); 89 static int pop_top (stream_t, char *, size_t, off_t, size_t *);
90 static int pop_read_header (stream_t, char *, size_t, off_t, size_t *);
91 static int pop_read_body (stream_t, char *, size_t, off_t, size_t *);
92 static int pop_read_message (stream_t, char *, size_t, off_t, size_t *);
93 static int pop_retr (pop_message_t, char *, size_t, off_t, size_t *);
86 static int pop_get_fd (stream_t, int *); 94 static int pop_get_fd (stream_t, int *);
87 static int pop_get_flags (attribute_t, int *); 95 static int pop_get_flags (attribute_t, int *);
88 static int pop_body_size (body_t, size_t *); 96 static int pop_body_size (body_t, size_t *);
89 static int pop_body_lines (body_t body, size_t *plines); 97 static int pop_body_lines (body_t body, size_t *plines);
90 static int pop_header_read (stream_t, char *, size_t, off_t, size_t *);
91 static int pop_uidl (message_t, char *, size_t, size_t *); 98 static int pop_uidl (message_t, char *, size_t, size_t *);
99 static int fill_buffer (bio_t bio, char *buffer, size_t buflen);
92 100
93 /* According to the rfc: 101 /* According to the rfc:
94 RFC 2449 POP3 Extension Mechanism November 1998 102 RFC 2449 POP3 Extension Mechanism November 1998
...@@ -130,7 +138,6 @@ struct _bio ...@@ -130,7 +138,6 @@ struct _bio
130 char *ptr; 138 char *ptr;
131 char *nl; 139 char *nl;
132 }; 140 };
133 typedef struct _bio *bio_t;
134 141
135 static int bio_create (bio_t *, stream_t); 142 static int bio_create (bio_t *, stream_t);
136 static void bio_destroy (bio_t *); 143 static void bio_destroy (bio_t *);
...@@ -138,12 +145,6 @@ static int bio_readline (bio_t); ...@@ -138,12 +145,6 @@ static int bio_readline (bio_t);
138 static int bio_read (bio_t); 145 static int bio_read (bio_t);
139 static int bio_write (bio_t); 146 static int bio_write (bio_t);
140 147
141 /* Advance declarations. */
142 struct _pop_data;
143 struct _pop_message;
144
145 typedef struct _pop_data * pop_data_t;
146 typedef struct _pop_message * pop_message_t;
147 148
148 /* This structure holds the info when for a pop_get_message() the 149 /* This structure holds the info when for a pop_get_message() the
149 pop_message_t type will serve as the owner of the message_t and contains 150 pop_message_t type will serve as the owner of the message_t and contains
...@@ -156,6 +157,8 @@ typedef struct _pop_message * pop_message_t; ...@@ -156,6 +157,8 @@ typedef struct _pop_message * pop_message_t;
156 struct _pop_message 157 struct _pop_message
157 { 158 {
158 int inbody; 159 int inbody;
160 int skip_header;
161 int skip_body;
159 size_t body_size; 162 size_t body_size;
160 size_t body_lines; 163 size_t body_lines;
161 size_t num; 164 size_t num;
...@@ -215,7 +218,7 @@ pop_create (mailbox_t *pmbox, const char *name) ...@@ -215,7 +218,7 @@ pop_create (mailbox_t *pmbox, const char *name)
215 size_t name_len; 218 size_t name_len;
216 219
217 /* Sanity check. */ 220 /* Sanity check. */
218 if (pmbox == NULL || name == NULL || *name == '\0') 221 if (name == NULL || *name == '\0')
219 return EINVAL; 222 return EINVAL;
220 223
221 name_len = strlen (name); 224 name_len = strlen (name);
...@@ -394,7 +397,7 @@ pop_authenticate (auth_t auth, char **user, char **passwd) ...@@ -394,7 +397,7 @@ pop_authenticate (auth_t auth, char **user, char **passwd)
394 static int 397 static int
395 pop_open (mailbox_t mbox, int flags) 398 pop_open (mailbox_t mbox, int flags)
396 { 399 {
397 pop_data_t mpd; 400 pop_data_t mpd = mbox->data;
398 int status; 401 int status;
399 bio_t bio; 402 bio_t bio;
400 void *func = (void *)pop_open; 403 void *func = (void *)pop_open;
...@@ -402,7 +405,7 @@ pop_open (mailbox_t mbox, int flags) ...@@ -402,7 +405,7 @@ pop_open (mailbox_t mbox, int flags)
402 long port; 405 long port;
403 406
404 /* Sanity checks. */ 407 /* Sanity checks. */
405 if (mbox == NULL || mbox->url == NULL || (mpd = mbox->data) == NULL) 408 if (mbox->url == NULL || mpd == NULL)
406 return EINVAL; 409 return EINVAL;
407 410
408 /* Fetch the pop server name and the port in the url_t. */ 411 /* Fetch the pop server name and the port in the url_t. */
...@@ -549,13 +552,13 @@ pop_open (mailbox_t mbox, int flags) ...@@ -549,13 +552,13 @@ pop_open (mailbox_t mbox, int flags)
549 static int 552 static int
550 pop_close (mailbox_t mbox) 553 pop_close (mailbox_t mbox)
551 { 554 {
552 pop_data_t mpd; 555 pop_data_t mpd = mbox->data;
553 void *func = (void *)pop_close; 556 void *func = (void *)pop_close;
554 int status; 557 int status;
555 bio_t bio; 558 bio_t bio;
556 size_t i; 559 size_t i;
557 560
558 if (mbox == NULL || (mpd = mbox->data) == NULL) 561 if (mpd == NULL)
559 return EINVAL; 562 return EINVAL;
560 563
561 if (mpd->func && mpd->func != func) 564 if (mpd->func && mpd->func != func)
...@@ -623,13 +626,13 @@ pop_close (mailbox_t mbox) ...@@ -623,13 +626,13 @@ pop_close (mailbox_t mbox)
623 static int 626 static int
624 pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) 627 pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
625 { 628 {
626 pop_data_t mpd; 629 pop_data_t mpd = mbox->data;
627 int status; 630 int status;
628 pop_message_t mpm; 631 pop_message_t mpm;
629 size_t i; 632 size_t i;
630 633
631 /* Sanity. */ 634 /* Sanity. */
632 if (mbox == NULL || pmsg == NULL || (mpd = mbox->data) == NULL) 635 if (pmsg == NULL || mpd == NULL)
633 return EINVAL; 636 return EINVAL;
634 637
635 /* See if we have already this message. */ 638 /* See if we have already this message. */
...@@ -655,12 +658,15 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) ...@@ -655,12 +658,15 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
655 /* Create the message. */ 658 /* Create the message. */
656 { 659 {
657 message_t msg; 660 message_t msg;
658 status = message_create (&msg, mpm); 661 stream_t is;
659 if (status != 0) 662 if ((status = message_create (&msg, mpm)) != 0
663 || (status = stream_create (&is, MU_STREAM_READ, mpm)) != 0)
660 { 664 {
661 free (mpm); 665 free (mpm);
662 return status; 666 return status;
663 } 667 }
668 stream_set_read (is, pop_read_message, mpm);
669 message_set_stream (msg, is, mpm);
664 /* The message. */ 670 /* The message. */
665 mpm->message = msg; 671 mpm->message = msg;
666 } 672 }
...@@ -676,7 +682,8 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) ...@@ -676,7 +682,8 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
676 free (mpm); 682 free (mpm);
677 return status; 683 return status;
678 } 684 }
679 stream_set_read (stream, pop_header_read, mpm); 685 //stream_set_read (stream, pop_read_header, mpm);
686 stream_set_read (stream, pop_top, mpm);
680 stream_set_fd (stream, pop_get_fd, mpm); 687 stream_set_fd (stream, pop_get_fd, mpm);
681 stream_set_flags (stream, MU_STREAM_READ, mpm); 688 stream_set_flags (stream, MU_STREAM_READ, mpm);
682 header_set_stream (header, stream, mpm); 689 header_set_stream (header, stream, mpm);
...@@ -701,21 +708,14 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) ...@@ -701,21 +708,14 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
701 { 708 {
702 stream_t stream; 709 stream_t stream;
703 body_t body; 710 body_t body;
704 status = body_create (&body, mpm); 711 if ((status = body_create (&body, mpm)) != 0
705 if (status != 0) 712 || (status = stream_create (&stream, MU_STREAM_READ, mpm)) != 0)
706 {
707 message_destroy (&(mpm->message), mpm);
708 free (mpm);
709 return status;
710 }
711 status = stream_create (&stream, MU_STREAM_READ, mpm);
712 if (status != 0)
713 { 713 {
714 message_destroy (&(mpm->message), mpm); 714 message_destroy (&(mpm->message), mpm);
715 free (mpm); 715 free (mpm);
716 return status; 716 return status;
717 } 717 }
718 stream_set_read (stream, pop_readstream, mpm); 718 stream_set_read (stream, pop_read_body, mpm);
719 stream_set_fd (stream, pop_get_fd, mpm); 719 stream_set_fd (stream, pop_get_fd, mpm);
720 stream_set_flags (stream, mpd->flags, mpm); 720 stream_set_flags (stream, mpd->flags, mpm);
721 body_set_size (body, pop_body_size, mpm); 721 body_set_size (body, pop_body_size, mpm);
...@@ -750,12 +750,12 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) ...@@ -750,12 +750,12 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
750 static int 750 static int
751 pop_messages_count (mailbox_t mbox, size_t *pcount) 751 pop_messages_count (mailbox_t mbox, size_t *pcount)
752 { 752 {
753 pop_data_t mpd; 753 pop_data_t mpd = mbox->data;
754 int status; 754 int status;
755 void *func = (void *)pop_messages_count; 755 void *func = (void *)pop_messages_count;
756 bio_t bio; 756 bio_t bio;
757 757
758 if (mbox == NULL || (mpd = (pop_data_t)mbox->data) == NULL) 758 if (mpd == NULL)
759 return EINVAL; 759 return EINVAL;
760 760
761 if (pop_is_updated (mbox)) 761 if (pop_is_updated (mbox))
...@@ -817,8 +817,8 @@ pop_messages_count (mailbox_t mbox, size_t *pcount) ...@@ -817,8 +817,8 @@ pop_messages_count (mailbox_t mbox, size_t *pcount)
817 static int 817 static int
818 pop_is_updated (mailbox_t mbox) 818 pop_is_updated (mailbox_t mbox)
819 { 819 {
820 pop_data_t mpd; 820 pop_data_t mpd = mbox->data;
821 if ((mpd = (pop_data_t)mbox->data) == NULL) 821 if (mpd == NULL)
822 return 0; 822 return 0;
823 return mpd->is_updated; 823 return mpd->is_updated;
824 } 824 }
...@@ -826,11 +826,11 @@ pop_is_updated (mailbox_t mbox) ...@@ -826,11 +826,11 @@ pop_is_updated (mailbox_t mbox)
826 static int 826 static int
827 pop_num_deleted (mailbox_t mbox, size_t *pnum) 827 pop_num_deleted (mailbox_t mbox, size_t *pnum)
828 { 828 {
829 pop_data_t mpd; 829 pop_data_t mpd = mbox->data;
830 size_t i, total; 830 size_t i, total;
831 attribute_t attr; 831 attribute_t attr;
832 832
833 if (mbox == NULL || (mpd = (pop_data_t) mbox->data) == NULL) 833 if (mpd == NULL)
834 return EINVAL; 834 return EINVAL;
835 835
836 for (i = total = 0; i < mpd->messages_count; i++) 836 for (i = total = 0; i < mpd->messages_count; i++)
...@@ -867,14 +867,14 @@ pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount) ...@@ -867,14 +867,14 @@ pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
867 static int 867 static int
868 pop_expunge (mailbox_t mbox) 868 pop_expunge (mailbox_t mbox)
869 { 869 {
870 pop_data_t mpd; 870 pop_data_t mpd = mbox->data;
871 size_t i; 871 size_t i;
872 attribute_t attr; 872 attribute_t attr;
873 bio_t bio; 873 bio_t bio;
874 int status; 874 int status;
875 void *func = (void *)pop_expunge; 875 void *func = (void *)pop_expunge;
876 876
877 if (mbox == NULL || (mpd = (pop_data_t) mbox->data) == NULL) 877 if (mpd == NULL)
878 return EINVAL; 878 return EINVAL;
879 879
880 /* Busy ? */ 880 /* Busy ? */
...@@ -958,10 +958,10 @@ pop_expunge (mailbox_t mbox) ...@@ -958,10 +958,10 @@ pop_expunge (mailbox_t mbox)
958 static int 958 static int
959 pop_size (mailbox_t mbox, off_t *psize) 959 pop_size (mailbox_t mbox, off_t *psize)
960 { 960 {
961 pop_data_t mpd; 961 pop_data_t mpd = mbox->data;
962 int status = 0; 962 int status = 0;
963 963
964 if (mbox == NULL || (mpd = (pop_data_t)mbox->data) == NULL) 964 if (mpd == NULL)
965 return EINVAL; 965 return EINVAL;
966 966
967 if (! pop_is_updated (mbox)) 967 if (! pop_is_updated (mbox))
...@@ -974,8 +974,8 @@ pop_size (mailbox_t mbox, off_t *psize) ...@@ -974,8 +974,8 @@ pop_size (mailbox_t mbox, off_t *psize)
974 static int 974 static int
975 pop_body_size (body_t body, size_t *psize) 975 pop_body_size (body_t body, size_t *psize)
976 { 976 {
977 pop_message_t mpm; 977 pop_message_t mpm = body->owner;
978 if (body == NULL || (mpm = body->owner) == NULL) 978 if (mpm == NULL)
979 return EINVAL; 979 return EINVAL;
980 if (psize) 980 if (psize)
981 *psize = mpm->body_size; 981 *psize = mpm->body_size;
...@@ -985,8 +985,8 @@ pop_body_size (body_t body, size_t *psize) ...@@ -985,8 +985,8 @@ pop_body_size (body_t body, size_t *psize)
985 static int 985 static int
986 pop_body_lines (body_t body, size_t *plines) 986 pop_body_lines (body_t body, size_t *plines)
987 { 987 {
988 pop_message_t mpm; 988 pop_message_t mpm = body->owner;
989 if (body == NULL || (mpm = body->owner) == NULL) 989 if (mpm == NULL)
990 return EINVAL; 990 return EINVAL;
991 if (plines) 991 if (plines)
992 *plines = mpm->body_lines; 992 *plines = mpm->body_lines;
...@@ -996,12 +996,12 @@ pop_body_lines (body_t body, size_t *plines) ...@@ -996,12 +996,12 @@ pop_body_lines (body_t body, size_t *plines)
996 static int 996 static int
997 pop_get_flags (attribute_t attr, int *pflags) 997 pop_get_flags (attribute_t attr, int *pflags)
998 { 998 {
999 pop_message_t mpm; 999 pop_message_t mpm = attr->owner;
1000 char hdr_status[64]; 1000 char hdr_status[64];
1001 header_t header = NULL; 1001 header_t header = NULL;
1002 int err; 1002 int err;
1003 1003
1004 if (attr == NULL || (mpm = attr->owner) == NULL) 1004 if (mpm == NULL)
1005 return EINVAL; 1005 return EINVAL;
1006 hdr_status[0] = '\0'; 1006 hdr_status[0] = '\0';
1007 message_get_header (mpm->message, &header); 1007 message_get_header (mpm->message, &header);
...@@ -1015,8 +1015,8 @@ pop_get_flags (attribute_t attr, int *pflags) ...@@ -1015,8 +1015,8 @@ pop_get_flags (attribute_t attr, int *pflags)
1015 static int 1015 static int
1016 pop_get_fd (stream_t stream, int *pfd) 1016 pop_get_fd (stream_t stream, int *pfd)
1017 { 1017 {
1018 pop_message_t mpm; 1018 pop_message_t mpm = stream->owner;
1019 if (stream == NULL || (mpm = stream->owner) == NULL) 1019 if (mpm == NULL)
1020 return EINVAL; 1020 return EINVAL;
1021 if (mpm->mpd->bio) 1021 if (mpm->mpd->bio)
1022 return stream_get_fd (mpm->mpd->bio->stream, pfd); 1022 return stream_get_fd (mpm->mpd->bio->stream, pfd);
...@@ -1026,7 +1026,7 @@ pop_get_fd (stream_t stream, int *pfd) ...@@ -1026,7 +1026,7 @@ pop_get_fd (stream_t stream, int *pfd)
1026 static int 1026 static int
1027 pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) 1027 pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
1028 { 1028 {
1029 pop_message_t mpm; 1029 pop_message_t mpm = msg->owner;
1030 pop_data_t mpd; 1030 pop_data_t mpd;
1031 bio_t bio; 1031 bio_t bio;
1032 int status = 0; 1032 int status = 0;
...@@ -1035,7 +1035,7 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) ...@@ -1035,7 +1035,7 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
1035 /* According to the RFC uidl's are no longer then 70 chars. */ 1035 /* According to the RFC uidl's are no longer then 70 chars. */
1036 char uniq[128]; 1036 char uniq[128];
1037 1037
1038 if (msg == NULL || (mpm = msg->owner) == NULL) 1038 if (mpm == NULL)
1039 return EINVAL; 1039 return EINVAL;
1040 1040
1041 mpd = mpm->mpd; 1041 mpd = mpm->mpd;
...@@ -1099,19 +1099,20 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) ...@@ -1099,19 +1099,20 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
1099 } 1099 }
1100 1100
1101 static int 1101 static int
1102 pop_header_read (stream_t is, char *buffer, size_t buflen, 1102 pop_top (stream_t is, char *buffer, size_t buflen,
1103 off_t offset, size_t *pnread) 1103 off_t offset, size_t *pnread)
1104 { 1104 {
1105 pop_message_t mpm; 1105 pop_message_t mpm = is->owner;
1106 pop_data_t mpd; 1106 pop_data_t mpd;
1107 bio_t bio; 1107 bio_t bio;
1108 size_t nread = 0; 1108 size_t nread = 0;
1109 int status = 0; 1109 int status = 0;
1110 void *func = (void *)pop_header_read; 1110 void *func = (void *)pop_top;
1111 1111
1112 if (is == NULL || (mpm = is->owner) == NULL) 1112 if (mpm == NULL)
1113 return EINVAL; 1113 return EINVAL;
1114 1114
1115 /* We do not carry the offset(for pop), should be doc somewhere. */
1115 (void)offset; 1116 (void)offset;
1116 mpd = mpm->mpd; 1117 mpd = mpm->mpd;
1117 bio = mpd->bio; 1118 bio = mpd->bio;
...@@ -1147,9 +1148,12 @@ pop_header_read (stream_t is, char *buffer, size_t buflen, ...@@ -1147,9 +1148,12 @@ pop_header_read (stream_t is, char *buffer, size_t buflen,
1147 mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer); 1148 mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
1148 if (strncasecmp (bio->buffer, "+OK", 3) != 0) 1149 if (strncasecmp (bio->buffer, "+OK", 3) != 0)
1149 { 1150 {
1150 fprintf (stderr, "TOP not implmented\n"); 1151 /* fprintf (stderr, "TOP not implmented\n"); */
1151 CLEAR_STATE (mpd); 1152 /* Fall back to RETR call. */
1152 return ENOSYS; 1153 mpd->state = POP_NO_STATE;
1154 mpm->skip_header = 0;
1155 mpm->skip_body = 1;
1156 return pop_retr (mpm, buffer, buflen, offset, pnread);
1153 } 1157 }
1154 mpd->state = POP_TOP_RX; 1158 mpd->state = POP_TOP_RX;
1155 bio->current = bio->nl; 1159 bio->current = bio->nl;
...@@ -1185,8 +1189,10 @@ pop_header_read (stream_t is, char *buffer, size_t buflen, ...@@ -1185,8 +1189,10 @@ pop_header_read (stream_t is, char *buffer, size_t buflen,
1185 } 1189 }
1186 break; 1190 break;
1187 default: 1191 default:
1188 /* fprintf (stderr, "pop_header_blurb unknown state\n"); */ 1192 /* Probabaly TOP was not supported so we fall back to RETR. */
1189 break; 1193 mpm->skip_header = 0;
1194 mpm->skip_body = 1;
1195 return pop_retr (mpm, buffer, buflen, offset, pnread);
1190 } /* switch (state) */ 1196 } /* switch (state) */
1191 1197
1192 if (nread == 0) 1198 if (nread == 0)
...@@ -1199,41 +1205,114 @@ pop_header_read (stream_t is, char *buffer, size_t buflen, ...@@ -1199,41 +1205,114 @@ pop_header_read (stream_t is, char *buffer, size_t buflen,
1199 } 1205 }
1200 1206
1201 static int 1207 static int
1202 pop_readstream (stream_t is, char *buffer, size_t buflen, 1208 pop_read_header (stream_t is, char *buffer, size_t buflen, off_t offset,
1203 off_t offset, size_t *pnread) 1209 size_t *pnread)
1210 {
1211 pop_message_t mpm = is->owner;
1212 pop_data_t mpd;
1213 void *func = (void *)pop_read_header;
1214
1215 if (mpm == NULL)
1216 return EINVAL;
1217 /* Busy ? */
1218 if (mpd->func && mpd->func != func)
1219 return EBUSY;
1220 mpd->func = func;
1221
1222 mpm->skip_header = 0;
1223 mpm->skip_body = 1;
1224 return pop_retr (mpm, buffer, buflen, offset, pnread);
1225 }
1226
1227 static int
1228 pop_read_body (stream_t is, char *buffer, size_t buflen, off_t offset,
1229 size_t *pnread)
1230 {
1231 pop_message_t mpm = is->owner;
1232 pop_data_t mpd;
1233 void *func = (void *)pop_read_body;
1234
1235 if (mpm == NULL)
1236 return EINVAL;
1237 /* Busy ? */
1238 if (mpd->func && mpd->func != func)
1239 return EBUSY;
1240 mpd->func = func;
1241
1242 mpm->skip_header = 1;
1243 mpm->skip_body = 0;
1244 return pop_retr (mpm, buffer, buflen, offset, pnread);
1245 }
1246
1247 static int
1248 pop_read_message (stream_t is, char *buffer, size_t buflen, off_t offset,
1249 size_t *pnread)
1250 {
1251 pop_message_t mpm = is->owner;
1252 pop_data_t mpd;
1253 void *func = (void *)pop_read_message;
1254
1255 if (mpm == NULL)
1256 return EINVAL;
1257 mpd = mpm->mpd;
1258 /* Busy ? */
1259 if (mpd->func && mpd->func != func)
1260 return EBUSY;
1261 mpd->func = func;
1262
1263 mpm->skip_header = mpm->skip_body = 0;
1264 return pop_retr (mpm, buffer, buflen, offset, pnread);
1265 }
1266
1267 static int
1268 fill_buffer (bio_t bio, char *buffer, size_t buflen)
1269 {
1270 int nleft, n, nread = 0;
1271 n = bio->nl - bio->current;
1272 nleft = buflen - n;
1273 /* We got more then requested. */
1274 if (nleft <= 0)
1275 {
1276 memcpy (buffer, bio->current, buflen);
1277 bio->current += buflen;
1278 nread = buflen;
1279 }
1280 else
1281 {
1282 /* Drain the buffer. */
1283 memcpy (buffer, bio->current, n);
1284 bio->current += n;
1285 nread = n;
1286 }
1287 return nread;
1288 }
1289
1290 static int
1291 pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset,
1292 size_t *pnread)
1204 { 1293 {
1205 pop_message_t mpm;
1206 pop_data_t mpd; 1294 pop_data_t mpd;
1207 size_t nread = 0; 1295 size_t nread = 0;
1208 bio_t bio; 1296 bio_t bio;
1209 int status = 0; 1297 int status = 0;
1210 void *func = (void *)pop_readstream;
1211 1298
1212 (void)offset; 1299 (void)offset;
1213 if (is == NULL || (mpm = is->owner) == NULL)
1214 return EINVAL;
1215 1300
1216 /* Take care of the obvious. */
1217 if (buffer == NULL || buflen == 0)
1218 {
1219 if (pnread) 1301 if (pnread)
1220 *pnread = nread; 1302 *pnread = nread;
1303 /* Take care of the obvious. */
1304 if (buffer == NULL || buflen == 0)
1221 return 0; 1305 return 0;
1222 }
1223 1306
1224 mpd = mpm->mpd; 1307 mpd = mpm->mpd;
1225 bio = mpd->bio; 1308 bio = mpd->bio;
1226 1309
1227 /* Busy ? */
1228 if (mpd->func && mpd->func != func)
1229 return EBUSY;
1230
1231 mpd->func = func;
1232
1233 switch (mpd->state) 1310 switch (mpd->state)
1234 { 1311 {
1235 case POP_NO_STATE: 1312 case POP_NO_STATE:
1313 mpm->body_lines = mpm->body_size = 0;
1236 bio->len = sprintf (bio->buffer, "RETR %d\r\n", mpm->num); 1314 bio->len = sprintf (bio->buffer, "RETR %d\r\n", mpm->num);
1315 bio->ptr = bio->buffer;
1237 mpd->state = POP_RETR_TX; 1316 mpd->state = POP_RETR_TX;
1238 1317
1239 case POP_RETR_TX: 1318 case POP_RETR_TX:
...@@ -1251,14 +1330,33 @@ pop_readstream (stream_t is, char *buffer, size_t buflen, ...@@ -1251,14 +1330,33 @@ pop_readstream (stream_t is, char *buffer, size_t buflen,
1251 CLEAR_STATE (mpd); 1330 CLEAR_STATE (mpd);
1252 return EACCES; 1331 return EACCES;
1253 } 1332 }
1333 bio->current = bio->nl;
1254 mpd->state = POP_RETR_RX_HDR; 1334 mpd->state = POP_RETR_RX_HDR;
1255 1335
1256 case POP_RETR_RX_HDR: 1336 case POP_RETR_RX_HDR:
1257 /* Skip the header. */ 1337 /* Skip the header. */
1258 while (!mpm->inbody) 1338 while (!mpm->inbody)
1259 { 1339 {
1340 /* Do we need to fill up. */
1341 if (bio->current >= bio->nl)
1342 {
1343 bio->current = bio->buffer;
1260 status = bio_readline (bio); 1344 status = bio_readline (bio);
1261 CHECK_NON_RECOVERABLE (mpd, status); 1345 CHECK_NON_RECOVERABLE (mpd, status);
1346 }
1347 if (mpm->skip_header == 0)
1348 {
1349 nread = fill_buffer (bio, buffer, buflen);
1350 if (pnread)
1351 *pnread += nread;
1352 buflen -= nread ;
1353 if (buflen > 0)
1354 buffer += nread;
1355 else
1356 return 0;
1357 }
1358 else
1359 bio->current = bio->nl;
1262 if (bio->buffer[0] == '\n') 1360 if (bio->buffer[0] == '\n')
1263 { 1361 {
1264 mpm->inbody = 1; 1362 mpm->inbody = 1;
...@@ -1266,50 +1364,58 @@ pop_readstream (stream_t is, char *buffer, size_t buflen, ...@@ -1266,50 +1364,58 @@ pop_readstream (stream_t is, char *buffer, size_t buflen,
1266 } 1364 }
1267 } 1365 }
1268 /* Skip the newline. */ 1366 /* Skip the newline. */
1269 bio_readline (bio); 1367 //bio_readline (bio);
1270 bio->current = bio->current;
1271 mpd->state = POP_RETR_RX_BODY; 1368 mpd->state = POP_RETR_RX_BODY;
1272 1369
1273 case POP_RETR_RX_BODY: 1370 case POP_RETR_RX_BODY:
1274 /* Start taking the body. */ 1371 /* Start taking the body. */
1275 { 1372 {
1276 int nleft, n; 1373 while (mpm->inbody)
1374 {
1277 /* Do we need to fill up. */ 1375 /* Do we need to fill up. */
1278 if (bio->current >= bio->nl) 1376 if (bio->current >= bio->nl)
1279 { 1377 {
1280 bio->current = bio->buffer; 1378 bio->current = bio->buffer;
1281 status = bio_readline (bio); 1379 status = bio_readline (bio);
1282 CHECK_NON_RECOVERABLE (mpd, status); 1380 CHECK_NON_RECOVERABLE (mpd, status);
1381 mpm->body_lines++;
1283 } 1382 }
1284 n = bio->nl - bio->current; 1383 if (mpm->skip_body == 0)
1285 nleft = buflen - n;
1286 /* We got more then requested. */
1287 if (nleft <= 0)
1288 { 1384 {
1289 memcpy (buffer, bio->current, buflen); 1385 nread = fill_buffer (bio, buffer, buflen);
1290 bio->current += buflen; 1386 mpm->body_size += nread;
1291 nread = buflen; 1387 if (pnread)
1388 *pnread += nread;
1389 buflen -= nread ;
1390 if (buflen > 0)
1391 buffer += nread;
1392 else
1393 return 0;
1292 } 1394 }
1293 else 1395 else
1294 { 1396 {
1295 /* Drain the buffer. */ 1397 mpm->body_size += (bio->nl - bio->current);
1296 memcpy (buffer, bio->current, n); 1398 bio->current = bio->nl;
1297 bio->current += n;
1298 nread = n;
1299 } 1399 }
1400 if (bio->buffer[0] == '\0')
1401 {
1402 mpm->inbody = 0;
1300 break; 1403 break;
1301 } 1404 }
1405 }
1406 }
1407 mpd->state = POP_STATE_DONE;
1408 return 0;
1409 case POP_STATE_DONE:
1410 /* A convenient break, this is here so we can return 0 read on next
1411 call meaning we're done. */
1302 default: 1412 default:
1303 /* fprintf (stderr, "pop_readstream unknow state\n"); */ 1413 /* fprintf (stderr, "pop_retr unknow state\n"); */
1304 break; 1414 break;
1305 } /* Switch state. */ 1415 } /* Switch state. */
1306 1416
1307 if (nread == 0)
1308 {
1309 CLEAR_STATE (mpd); 1417 CLEAR_STATE (mpd);
1310 } 1418 mpm->skip_header = mpm->skip_body = 0;
1311 if (pnread)
1312 *pnread = nread;
1313 return 0; 1419 return 0;
1314 } 1420 }
1315 1421
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
23 #include <url0.h> 23 #include <url0.h>
24 #include <stream0.h> 24 #include <stream0.h>
25 #include <body0.h> 25 #include <body0.h>
26 #include <header0.h>
26 #include <attribute0.h> 27 #include <attribute0.h>
27 #include <mailutils/header.h> 28 #include <mailutils/header.h>
28 #include <mailutils/auth.h> 29 #include <mailutils/auth.h>
...@@ -103,13 +104,20 @@ typedef struct _unix_data ...@@ -103,13 +104,20 @@ typedef struct _unix_data
103 size_t umessages_count; 104 size_t umessages_count;
104 size_t messages_count; 105 size_t messages_count;
105 stream_t stream; 106 stream_t stream;
106 char *dirname;
107 char *basename;
108 #ifdef HAVE_PTHREAD_H 107 #ifdef HAVE_PTHREAD_H
109 pthread_mutex_t mutex; 108 pthread_mutex_t mutex;
110 #endif 109 #endif
111 off_t size; 110 off_t size;
112 111
112 /* The variables below are use to hold the state when appending messages. */
113 enum unix_state
114 {
115 UNIX_NO_STATE=0, UNIX_STATE_FROM, UNIX_STATE_DATE, UNIX_STATE_APPEND
116 } state ;
117 char *from;
118 char *date;
119 off_t off;
120
113 } *unix_data_t; 121 } *unix_data_t;
114 122
115 static int unix_open (mailbox_t mbox, int flag); 123 static int unix_open (mailbox_t mbox, int flag);
...@@ -134,6 +142,8 @@ static int unix_set_flags (attribute_t, int); ...@@ -134,6 +142,8 @@ static int unix_set_flags (attribute_t, int);
134 static int unix_unset_flags (attribute_t, int); 142 static int unix_unset_flags (attribute_t, int);
135 static int unix_readstream (stream_t is, char *buffer, size_t buflen, 143 static int unix_readstream (stream_t is, char *buffer, size_t buflen,
136 off_t off, size_t *pnread); 144 off_t off, size_t *pnread);
145 static int unix_header_size (header_t header, size_t *psize);
146 static int unix_header_lines (header_t header, size_t *plines);
137 static int unix_body_size (body_t body, size_t *psize); 147 static int unix_body_size (body_t body, size_t *psize);
138 static int unix_body_lines (body_t body, size_t *plines); 148 static int unix_body_lines (body_t body, size_t *plines);
139 static int unix_msg_from (message_t msg, char *buf, size_t len, 149 static int unix_msg_from (message_t msg, char *buf, size_t len,
...@@ -155,7 +165,6 @@ unix_create (mailbox_t *pmbox, const char *name) ...@@ -155,7 +165,6 @@ unix_create (mailbox_t *pmbox, const char *name)
155 { 165 {
156 mailbox_t mbox; 166 mailbox_t mbox;
157 unix_data_t mud; 167 unix_data_t mud;
158 const char *sep;
159 size_t name_len; 168 size_t name_len;
160 169
161 /* Sanity check. */ 170 /* Sanity check. */
...@@ -169,18 +178,18 @@ unix_create (mailbox_t *pmbox, const char *name) ...@@ -169,18 +178,18 @@ unix_create (mailbox_t *pmbox, const char *name)
169 #define SEPARATOR '/' 178 #define SEPARATOR '/'
170 179
171 /* Skip the url scheme. */ 180 /* Skip the url scheme. */
172 if (name_len > UNIX_SCHEME_LEN && 181 if (name_len > UNIX_SCHEME_LEN
173 (name[0] == 'u' || name[0] == 'U') && 182 && (name[0] == 'u' || name[0] == 'U')
174 (name[1] == 'n' || name[1] == 'N') && 183 && (name[1] == 'n' || name[1] == 'N')
175 (name[2] == 'i' || name[2] == 'i') && 184 && (name[2] == 'i' || name[2] == 'i')
176 (name[3] == 'x' || name[3] == 'x' ) && 185 && (name[3] == 'x' || name[3] == 'x' )
177 name[4] == ':') 186 && name[4] == ':')
178 { 187 {
179 name += UNIX_SCHEME_LEN; 188 name += UNIX_SCHEME_LEN;
180 name_len -= UNIX_SCHEME_LEN; 189 name_len -= UNIX_SCHEME_LEN;
181 } 190 }
182 191
183 /* Allocate memory for mbox. */ 192 /* Allocate memory for mbox (mailbox_t). */
184 mbox = calloc (1, sizeof (*mbox)); 193 mbox = calloc (1, sizeof (*mbox));
185 if (mbox == NULL) 194 if (mbox == NULL)
186 return ENOMEM; 195 return ENOMEM;
...@@ -193,7 +202,14 @@ unix_create (mailbox_t *pmbox, const char *name) ...@@ -193,7 +202,14 @@ unix_create (mailbox_t *pmbox, const char *name)
193 return ENOMEM; 202 return ENOMEM;
194 } 203 }
195 204
196 /* Copy the name. */ 205 /* Copy the name.
206 We do not do any further interpretation after the scheme "unix:"
207 Because for example on distributed system like QnX4 a file name is
208 //390/etc/passwd. So the best approach is to let the OS handle it
209 for example if we receive: "unix:///var/mail/alain" the mailbox name
210 will be "///var/mail/alain" we let open() do the right thing.
211 So it will let things like this "unix://390/var/mail/alain" where
212 "//390/var/mail/alain" _is_ the filename, pass correctely. */
197 mbox->name = calloc (name_len + 1, sizeof (char)); 213 mbox->name = calloc (name_len + 1, sizeof (char));
198 if (mbox->name == NULL) 214 if (mbox->name == NULL)
199 { 215 {
...@@ -202,50 +218,6 @@ unix_create (mailbox_t *pmbox, const char *name) ...@@ -202,50 +218,6 @@ unix_create (mailbox_t *pmbox, const char *name)
202 } 218 }
203 memcpy (mbox->name, name, name_len); 219 memcpy (mbox->name, name, name_len);
204 220
205 /* Save the basename and dirname. We split the name, but this should
206 probably be supported via "maildir:" or the mailbox mgr. */
207 sep = strrchr (name, SEPARATOR);
208 if (sep)
209 {
210 /* Split it into two. */
211 mud->dirname = calloc ((sep - name) + 1, sizeof (char));
212 if (mud->dirname == NULL)
213 {
214 unix_destroy (&mbox);
215 return ENOMEM;
216 }
217 memcpy (mud->dirname, name, sep - name);
218
219 ++sep;
220 mud->basename = calloc (name_len - (sep - name) + 1, sizeof (char));
221 if (mud->basename == NULL)
222 {
223 unix_destroy (&mbox);
224 return ENOMEM;
225 }
226 memcpy (mud->basename, sep, name_len - (sep - name));
227 }
228 else
229 {
230 /* Use the relative directory ".". */
231 /* FIXME: should we call getcwd () instead ? */
232 mud->dirname = calloc (2 , sizeof (char));
233 if (mud->dirname == NULL)
234 {
235 unix_destroy (&mbox);
236 return ENOMEM;
237 }
238 mud->dirname[0] = '.';
239
240 mud->basename = calloc (name_len + 1, sizeof (char));
241 if (mud->basename == NULL)
242 {
243 unix_destroy (&mbox);
244 return ENOMEM;
245 }
246 memcpy (mud->basename, name, name_len);
247 }
248
249 #ifdef HAVE_PHTREAD_H 221 #ifdef HAVE_PHTREAD_H
250 /* Mutex when accessing the structure fields. */ 222 /* Mutex when accessing the structure fields. */
251 /* FIXME: should we use rdwr locks instead ?? */ 223 /* FIXME: should we use rdwr locks instead ?? */
...@@ -270,8 +242,8 @@ unix_create (mailbox_t *pmbox, const char *name) ...@@ -270,8 +242,8 @@ unix_create (mailbox_t *pmbox, const char *name)
270 242
271 mbox->_size = unix_size; 243 mbox->_size = unix_size;
272 244
273 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_create (%s/%s)\n", 245 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_create(%s)\n",
274 mud->dirname, mud->basename); 246 mbox->name);
275 (*pmbox) = mbox; 247 (*pmbox) = mbox;
276 248
277 return 0; /* okdoke */ 249 return 0; /* okdoke */
...@@ -289,10 +261,7 @@ unix_destroy (mailbox_t *pmbox) ...@@ -289,10 +261,7 @@ unix_destroy (mailbox_t *pmbox)
289 size_t i; 261 size_t i;
290 unix_data_t mud = mbox->data; 262 unix_data_t mud = mbox->data;
291 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, 263 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE,
292 "unix_destroy (%s/%s)\n", 264 "unix_destroy (%s/%s)\n", mbox->name);
293 mud->dirname, mud->basename);
294 free (mud->dirname);
295 free (mud->basename);
296 for (i = 0; i < mud->umessages_count; i++) 265 for (i = 0; i < mud->umessages_count; i++)
297 { 266 {
298 unix_message_t mum = mud->umessages[i]; 267 unix_message_t mum = mud->umessages[i];
...@@ -331,11 +300,10 @@ unix_destroy (mailbox_t *pmbox) ...@@ -331,11 +300,10 @@ unix_destroy (mailbox_t *pmbox)
331 static int 300 static int
332 unix_open (mailbox_t mbox, int flags) 301 unix_open (mailbox_t mbox, int flags)
333 { 302 {
334 unix_data_t mud; 303 unix_data_t mud = mbox->data;
335 int status = 0; 304 int status = 0;
336 305
337 if (mbox == NULL || 306 if (mud == NULL)
338 (mud = (unix_data_t)mbox->data) == NULL)
339 return EINVAL; 307 return EINVAL;
340 308
341 /* Authentication prologues. */ 309 /* Authentication prologues. */
...@@ -384,10 +352,10 @@ unix_open (mailbox_t mbox, int flags) ...@@ -384,10 +352,10 @@ unix_open (mailbox_t mbox, int flags)
384 static int 352 static int
385 unix_close (mailbox_t mbox) 353 unix_close (mailbox_t mbox)
386 { 354 {
387 unix_data_t mud; 355 unix_data_t mud = mbox->data;
388 size_t i; 356 size_t i;
389 357
390 if (mbox == NULL || (mud = (unix_data_t)mbox->data) == NULL) 358 if (mud == NULL)
391 return EINVAL; 359 return EINVAL;
392 360
393 /* Make sure we do not hold any lock for that file. */ 361 /* Make sure we do not hold any lock for that file. */
...@@ -428,13 +396,15 @@ unix_scan (mailbox_t mbox, size_t msgno, size_t *pcount) ...@@ -428,13 +396,15 @@ unix_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
428 396
429 /* FIXME: How to handle a shrink ? meaning, the &^$^@%#@^& user start two 397 /* FIXME: How to handle a shrink ? meaning, the &^$^@%#@^& user start two
430 browsers and delete files in one. My views is that we should scream 398 browsers and delete files in one. My views is that we should scream
431 bloody murder and hunt them with a machette. */ 399 bloody murder and hunt them with a machette. But for now just play dumb,
400 but maybe the best approach is to pack our things and leave .i.e exit(). */
432 static int 401 static int
433 unix_is_updated (mailbox_t mbox) 402 unix_is_updated (mailbox_t mbox)
434 { 403 {
435 off_t size; 404 off_t size;
436 unix_data_t mud; 405 unix_data_t mud = mbox->data;
437 if (mbox == NULL || (mud = (unix_data_t) mbox->data) == NULL) 406
407 if (mud == NULL)
438 return EINVAL; 408 return EINVAL;
439 if (stream_size (mbox->stream, &size) != 0) 409 if (stream_size (mbox->stream, &size) != 0)
440 return 0; 410 return 0;
...@@ -444,10 +414,10 @@ unix_is_updated (mailbox_t mbox) ...@@ -444,10 +414,10 @@ unix_is_updated (mailbox_t mbox)
444 static int 414 static int
445 unix_num_deleted (mailbox_t mbox, size_t *pnum) 415 unix_num_deleted (mailbox_t mbox, size_t *pnum)
446 { 416 {
447 unix_data_t mud; 417 unix_data_t mud = mbox->data;
448 unix_message_t mum; 418 unix_message_t mum;
449 size_t i, total; 419 size_t i, total;
450 if (mbox == NULL || (mud = (unix_data_t) mbox->data) == NULL) 420 if (mud == NULL)
451 return EINVAL; 421 return EINVAL;
452 for (i = total = 0; i < mud->messages_count; i++) 422 for (i = total = 0; i < mud->messages_count; i++)
453 { 423 {
...@@ -462,15 +432,14 @@ unix_num_deleted (mailbox_t mbox, size_t *pnum) ...@@ -462,15 +432,14 @@ unix_num_deleted (mailbox_t mbox, size_t *pnum)
462 } 432 }
463 433
464 /* FIXME: the use of tmpfile() on some system can lead to race condition, We 434 /* FIXME: the use of tmpfile() on some system can lead to race condition, We
465 should use a safer approach. We take a very naive approach for this, it 435 should use a safer approach. */
466 involves unfortunately two copies. */
467 static FILE * 436 static FILE *
468 unix_tmpfile (mailbox_t mbox, char **pbox) 437 unix_tmpfile (mailbox_t mbox, char **pbox)
469 { 438 {
470 const char *tmpdir; 439 const char *tmpdir;
471 int fd; 440 int fd;
472 FILE *fp; 441 FILE *fp;
473 unix_data_t mud = (unix_data_t)mbox->data; 442 const char *basename;
474 443
475 /* P_tmpdir should be define in <stdio.h>. */ 444 /* P_tmpdir should be define in <stdio.h>. */
476 #ifndef P_tmpdir 445 #ifndef P_tmpdir
...@@ -478,11 +447,16 @@ unix_tmpfile (mailbox_t mbox, char **pbox) ...@@ -478,11 +447,16 @@ unix_tmpfile (mailbox_t mbox, char **pbox)
478 #endif 447 #endif
479 448
480 tmpdir = getenv ("TEMPDIR") ? getenv ("TEMPDIR") : P_tmpdir; 449 tmpdir = getenv ("TEMPDIR") ? getenv ("TEMPDIR") : P_tmpdir;
481 *pbox = calloc (1, strlen (tmpdir) + strlen ("MBOX_") + 450 basename = strrchr (mbox->name, '/');
482 strlen (mud->basename) + 1); 451 if (basename)
452 basename++;
453 else
454 basename = mbox->name;
455 *pbox = calloc (strlen (tmpdir) + strlen ("MBOX_") +
456 strlen (basename) + 1, sizeof (char));
483 if (*pbox == NULL) 457 if (*pbox == NULL)
484 return NULL; 458 return NULL;
485 sprintf (*pbox, "%s/%s%s", tmpdir, "MBOX_", mud->basename); 459 sprintf (*pbox, "%s/%s%s", tmpdir, "MBOX_", basename);
486 460
487 /* FIXME: I don't think this is the righ approach, creating an anonymous 461 /* FIXME: I don't think this is the righ approach, creating an anonymous
488 file would be better ? no trace left behind. */ 462 file would be better ? no trace left behind. */
...@@ -508,10 +482,21 @@ unix_tmpfile (mailbox_t mbox, char **pbox) ...@@ -508,10 +482,21 @@ unix_tmpfile (mailbox_t mbox, char **pbox)
508 return fp; 482 return fp;
509 } 483 }
510 484
485 /* For the expunge bits we took a very cautionnary approach, meaning
486 we create temporary file in the tmpdir copy all the file not mark deleted,
487 and skip the deleted ones, truncate the real mailbox to the desired size
488 and overwrite with the tmp mailbox. The approach to do everyting
489 in core is tempting but require to much memory, it is not rare now
490 a day to have 30 Megs mailbox, also there is danger for filesystems
491 with quotas, or some program may not respect the advisory lock and
492 decide to append a new message while your expunging etc ...
493 The real downside to the approach we take is that when things go wrong
494 the temporary file bay be left in /tmp, which is not all that bad
495 because at least have something to recuparate when failure. */
511 static int 496 static int
512 unix_expunge (mailbox_t mbox) 497 unix_expunge (mailbox_t mbox)
513 { 498 {
514 unix_data_t mud; 499 unix_data_t mud = mbox->data;
515 unix_message_t mum; 500 unix_message_t mum;
516 int status = 0; 501 int status = 0;
517 sigset_t sigset; 502 sigset_t sigset;
...@@ -523,7 +508,7 @@ unix_expunge (mailbox_t mbox) ...@@ -523,7 +508,7 @@ unix_expunge (mailbox_t mbox)
523 char buffer [BUFSIZ]; 508 char buffer [BUFSIZ];
524 char *tmpmbox = NULL; 509 char *tmpmbox = NULL;
525 510
526 if (mbox == NULL || (mud = (unix_data_t)mbox->data) == NULL) 511 if (mud == NULL)
527 return EINVAL; 512 return EINVAL;
528 513
529 /* Noop. */ 514 /* Noop. */
...@@ -569,7 +554,11 @@ unix_expunge (mailbox_t mbox) ...@@ -569,7 +554,11 @@ unix_expunge (mailbox_t mbox)
569 /* Create a tempory file. */ 554 /* Create a tempory file. */
570 tempfile = unix_tmpfile (mbox, &tmpmbox); 555 tempfile = unix_tmpfile (mbox, &tmpmbox);
571 if (tempfile == NULL) 556 if (tempfile == NULL)
557 {
558 fprintf (stderr, "Failed to create temporary file when expunging.\n");
559 free (tmpmbox);
572 return errno; 560 return errno;
561 }
573 562
574 /* Get the lock. */ 563 /* Get the lock. */
575 if (unix_lock (mbox, MU_LOCKER_WRLOCK) < 0) 564 if (unix_lock (mbox, MU_LOCKER_WRLOCK) < 0)
...@@ -640,9 +629,9 @@ unix_expunge (mailbox_t mbox) ...@@ -640,9 +629,9 @@ unix_expunge (mailbox_t mbox)
640 { 629 {
641 if (status == 0) 630 if (status == 0)
642 status = errno; 631 status = errno;
643 fprintf (stderr, "expunge:%d: (%s)\n", __LINE__, 632 fprintf (stderr, "Error expunge:%d: (%s)\n", __LINE__,
644 strerror (status)); 633 strerror (status));
645 goto bailout; 634 goto bailout0;
646 } 635 }
647 len -= n; 636 len -= n;
648 total += n; 637 total += n;
...@@ -676,9 +665,9 @@ unix_expunge (mailbox_t mbox) ...@@ -676,9 +665,9 @@ unix_expunge (mailbox_t mbox)
676 { 665 {
677 if (status == 0) 666 if (status == 0)
678 status = errno; 667 status = errno;
679 fprintf (stderr, "expunge:%d: %s", __LINE__, 668 fprintf (stderr, "Error expunge:%d: %s", __LINE__,
680 strerror (status)); 669 strerror (status));
681 goto bailout; 670 goto bailout0;
682 } 671 }
683 len -= n; 672 len -= n;
684 total += n; 673 total += n;
...@@ -701,9 +690,9 @@ unix_expunge (mailbox_t mbox) ...@@ -701,9 +690,9 @@ unix_expunge (mailbox_t mbox)
701 { 690 {
702 if (status == 0) 691 if (status == 0)
703 status = errno; 692 status = errno;
704 fprintf (stderr, "expunge:%d: %s", __LINE__, 693 fprintf (stderr, "Error expunge:%d: %s", __LINE__,
705 strerror (status)); 694 strerror (status));
706 goto bailout; 695 goto bailout0;
707 } 696 }
708 len -= n; 697 len -= n;
709 total += n; 698 total += n;
...@@ -731,9 +720,9 @@ unix_expunge (mailbox_t mbox) ...@@ -731,9 +720,9 @@ unix_expunge (mailbox_t mbox)
731 { 720 {
732 if (status == 0) 721 if (status == 0)
733 status = errno; 722 status = errno;
734 fprintf (stderr, "expunge:%d: %s", __LINE__, 723 fprintf (stderr, "Error expunge:%d: %s", __LINE__,
735 strerror (status)); 724 strerror (status));
736 goto bailout; 725 goto bailout0;
737 } 726 }
738 len -= n; 727 len -= n;
739 total += n; 728 total += n;
...@@ -755,7 +744,11 @@ unix_expunge (mailbox_t mbox) ...@@ -755,7 +744,11 @@ unix_expunge (mailbox_t mbox)
755 { 744 {
756 status = stream_write (mbox->stream, buffer, nread, offset, &n); 745 status = stream_write (mbox->stream, buffer, nread, offset, &n);
757 if (status != 0) 746 if (status != 0)
747 {
748 fprintf (stderr, "Error expunge:%d: %s\n", __LINE__,
749 strerror (status));
758 goto bailout; 750 goto bailout;
751 }
759 nread -= n; 752 nread -= n;
760 offset += n; 753 offset += n;
761 } 754 }
...@@ -770,12 +763,12 @@ unix_expunge (mailbox_t mbox) ...@@ -770,12 +763,12 @@ unix_expunge (mailbox_t mbox)
770 status = stream_truncate (mbox->stream, total); 763 status = stream_truncate (mbox->stream, total);
771 if (status != 0) 764 if (status != 0)
772 { 765 {
773 fprintf (stderr, "expunge:%d: %s", __LINE__, 766 fprintf (stderr, "Error expunging:%d: %s", __LINE__, strerror (status));
774 strerror (status));
775 goto bailout; 767 goto bailout;
776 } 768 }
777 769
778 /* Don't remove the tmp mbox in case of errors. */ 770 bailout0:
771 /* Don't remove the tmp mbox in case of errors, when writing back. */
779 remove (tmpmbox); 772 remove (tmpmbox);
780 773
781 bailout: 774 bailout:
...@@ -814,7 +807,7 @@ unix_expunge (mailbox_t mbox) ...@@ -814,7 +807,7 @@ unix_expunge (mailbox_t mbox)
814 mum->body = mum->body_end = 0; 807 mum->body = mum->body_end = 0;
815 mum->header_lines = mum->body_lines = 0; 808 mum->header_lines = mum->body_lines = 0;
816 } 809 }
817 /* This is should reset the messages_count, the last * argument 0 means 810 /* This is should reset the messages_count, the last argument 0 means
818 not to send event notification. */ 811 not to send event notification. */
819 unix_scan0 (mbox, dirty, NULL, 0); 812 unix_scan0 (mbox, dirty, NULL, 0);
820 } 813 }
...@@ -824,9 +817,9 @@ unix_expunge (mailbox_t mbox) ...@@ -824,9 +817,9 @@ unix_expunge (mailbox_t mbox)
824 static int 817 static int
825 unix_get_fd (stream_t is, int *pfd) 818 unix_get_fd (stream_t is, int *pfd)
826 { 819 {
827 unix_message_t mum; 820 unix_message_t mum = is->owner;
828 821
829 if (is == NULL || (mum = is->owner) == NULL) 822 if (mum == NULL)
830 return EINVAL; 823 return EINVAL;
831 824
832 return stream_get_fd (mum->stream, pfd); 825 return stream_get_fd (mum->stream, pfd);
...@@ -835,9 +828,9 @@ unix_get_fd (stream_t is, int *pfd) ...@@ -835,9 +828,9 @@ unix_get_fd (stream_t is, int *pfd)
835 static int 828 static int
836 unix_get_flags (attribute_t attr, int *pflags) 829 unix_get_flags (attribute_t attr, int *pflags)
837 { 830 {
838 unix_message_t mum; 831 unix_message_t mum = attr->owner;
839 832
840 if (attr == NULL || (mum = attr->owner) == NULL) 833 if (mum == NULL)
841 return EINVAL; 834 return EINVAL;
842 835
843 if (pflags) 836 if (pflags)
...@@ -848,9 +841,9 @@ unix_get_flags (attribute_t attr, int *pflags) ...@@ -848,9 +841,9 @@ unix_get_flags (attribute_t attr, int *pflags)
848 static int 841 static int
849 unix_set_flags (attribute_t attr, int flags) 842 unix_set_flags (attribute_t attr, int flags)
850 { 843 {
851 unix_message_t mum; 844 unix_message_t mum = attr->owner;
852 845
853 if (attr == NULL || (mum = attr->owner) == NULL) 846 if (mum == NULL)
854 return EINVAL; 847 return EINVAL;
855 848
856 mum->new_flags |= flags; 849 mum->new_flags |= flags;
...@@ -860,12 +853,12 @@ unix_set_flags (attribute_t attr, int flags) ...@@ -860,12 +853,12 @@ unix_set_flags (attribute_t attr, int flags)
860 static int 853 static int
861 unix_unset_flags (attribute_t attr, int flags) 854 unix_unset_flags (attribute_t attr, int flags)
862 { 855 {
863 unix_message_t mum; 856 unix_message_t mum = attr->owner;
864 857
865 if (attr == NULL || (mum = attr->owner) == NULL) 858 if (mum == NULL)
866 return EINVAL; 859 return EINVAL;
867 860
868 mum->new_flags &= flags; 861 mum->new_flags &= ~flags;
869 return 0; 862 return 0;
870 } 863 }
871 864
...@@ -873,10 +866,10 @@ static int ...@@ -873,10 +866,10 @@ static int
873 unix_readstream (stream_t is, char *buffer, size_t buflen, 866 unix_readstream (stream_t is, char *buffer, size_t buflen,
874 off_t off, size_t *pnread) 867 off_t off, size_t *pnread)
875 { 868 {
876 unix_message_t mum; 869 unix_message_t mum = is->owner;
877 size_t nread = 0; 870 size_t nread = 0;
878 871
879 if (is == NULL || (mum = (unix_message_t)is->owner) == NULL) 872 if (mum == NULL)
880 return EINVAL; 873 return EINVAL;
881 874
882 if (buffer == NULL || buflen == 0) 875 if (buffer == NULL || buflen == 0)
...@@ -909,12 +902,12 @@ static int ...@@ -909,12 +902,12 @@ static int
909 unix_get_header_read (stream_t is, char *buffer, size_t len, 902 unix_get_header_read (stream_t is, char *buffer, size_t len,
910 off_t off, size_t *pnread) 903 off_t off, size_t *pnread)
911 { 904 {
912 unix_message_t mum; 905 unix_message_t mum = is->owner;
913 size_t nread = 0; 906 size_t nread = 0;
914 int status = 0; 907 int status = 0;
915 off_t ln; 908 off_t ln;
916 909
917 if (is == NULL || (mum = is->owner) == NULL) 910 if (mum == NULL)
918 return EINVAL; 911 return EINVAL;
919 912
920 ln = mum->body - (mum->header_from_end + off); 913 ln = mum->body - (mum->header_from_end + off);
...@@ -931,13 +924,35 @@ unix_get_header_read (stream_t is, char *buffer, size_t len, ...@@ -931,13 +924,35 @@ unix_get_header_read (stream_t is, char *buffer, size_t len,
931 } 924 }
932 925
933 static int 926 static int
927 unix_header_size (header_t header, size_t *psize)
928 {
929 unix_message_t mum = header->owner;
930 if (mum == NULL)
931 return EINVAL;
932 if (psize)
933 *psize = mum->body - mum->header_from_end;
934 return 0;
935 }
936
937 static int
938 unix_header_lines (header_t header, size_t *plines)
939 {
940 unix_message_t mum = header->owner;
941 if (mum == NULL)
942 return EINVAL;
943 if (plines)
944 *plines = mum->header_lines;
945 return 0;
946 }
947
948 static int
934 unix_body_size (body_t body, size_t *psize) 949 unix_body_size (body_t body, size_t *psize)
935 { 950 {
936 unix_message_t mum = body->owner; 951 unix_message_t mum = body->owner;
937 if (mum == NULL) 952 if (mum == NULL)
938 return EINVAL; 953 return EINVAL;
939 if (psize) 954 if (psize)
940 *psize = mum->body_end - mum->body; 955 *psize = mum->body_end - mum->body + 1;
941 return 0; 956 return 0;
942 } 957 }
943 958
...@@ -1046,13 +1061,12 @@ static int ...@@ -1046,13 +1061,12 @@ static int
1046 unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) 1061 unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
1047 { 1062 {
1048 int status; 1063 int status;
1049 unix_data_t mud; 1064 unix_data_t mud = mbox->data;
1050 unix_message_t mum; 1065 unix_message_t mum;
1051 message_t msg = NULL; 1066 message_t msg = NULL;
1052 1067
1053 /* Sanity checks. */ 1068 /* Sanity checks. */
1054 if (mbox == NULL || pmsg == NULL || (mud = (unix_data_t)mbox->data) == NULL 1069 if (pmsg == NULL || mud == NULL || (!(mud->messages_count > 0 && msgno > 0
1055 || (!(mud->messages_count > 0 && msgno > 0
1056 && msgno <= mud->messages_count))) 1070 && msgno <= mud->messages_count)))
1057 return EINVAL; 1071 return EINVAL;
1058 1072
...@@ -1088,6 +1102,8 @@ unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) ...@@ -1088,6 +1102,8 @@ unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
1088 stream_set_fd (stream, unix_get_fd, mum); 1102 stream_set_fd (stream, unix_get_fd, mum);
1089 stream_set_flags (stream, MU_STREAM_READ, mum); 1103 stream_set_flags (stream, MU_STREAM_READ, mum);
1090 header_set_stream (header, stream, mum); 1104 header_set_stream (header, stream, mum);
1105 header_set_size (header, unix_header_size, mum);
1106 header_set_lines (header, unix_header_lines, mum);
1091 message_set_header (msg, header, mum); 1107 message_set_header (msg, header, mum);
1092 } 1108 }
1093 1109
...@@ -1143,9 +1159,8 @@ unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) ...@@ -1143,9 +1159,8 @@ unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
1143 static int 1159 static int
1144 unix_append_message (mailbox_t mbox, message_t msg) 1160 unix_append_message (mailbox_t mbox, message_t msg)
1145 { 1161 {
1146 unix_data_t mud; 1162 unix_data_t mud = mbox->data;
1147 if (mbox == NULL || msg == NULL || 1163 if (msg == NULL || mud == NULL)
1148 (mud = (unix_data_t)mbox->data) == NULL)
1149 return EINVAL; 1164 return EINVAL;
1150 1165
1151 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, 1166 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE,
...@@ -1166,53 +1181,129 @@ unix_append_message (mailbox_t mbox, message_t msg) ...@@ -1166,53 +1181,129 @@ unix_append_message (mailbox_t mbox, message_t msg)
1166 return status; 1181 return status;
1167 } 1182 }
1168 1183
1184 switch (mud->state)
1185 {
1186 case UNIX_NO_STATE:
1187 mud->from = calloc (128, sizeof (char));
1188 if (mud->from == NULL)
1189 {
1190 unix_unlock (mbox);
1191 return ENOMEM;
1192 }
1193 mud->date = calloc (128, sizeof (char));
1194 if (mud->date == NULL)
1195 {
1196 free (mud->from);
1197 mud->from = NULL;
1198 mud->state = UNIX_NO_STATE;
1199 unix_unlock (mbox);
1200 return ENOMEM;
1201 }
1202 mud->off = 0;
1203 mud->state = UNIX_STATE_FROM;
1204
1205 case UNIX_STATE_FROM:
1169 /* Generate a "From " separator. */ 1206 /* Generate a "From " separator. */
1170 { 1207 {
1171 char from[128];
1172 char date[128];
1173 char *s; 1208 char *s;
1174 size_t f = 0, d = 0; 1209 size_t len = 0;
1175 *date = *from = '\0'; 1210 status = message_from (msg, mud->from, 127, &len);
1176 message_from (msg, from, sizeof (from), &f); 1211 if (status != 0)
1177 s = memchr (from, nl, f);
1178 if (s)
1179 { 1212 {
1180 *s = '\0'; 1213 if (status != EAGAIN)
1181 f--; 1214 {
1215 free (mud->from);
1216 free (mud->date);
1217 mud->date = mud->from = NULL;
1218 mud->state = UNIX_NO_STATE;
1219 unix_unlock (mbox);
1182 } 1220 }
1183 message_received (msg, date, sizeof (date), &d); 1221 return status;
1184 s = memchr (date, nl, d); 1222 }
1223 /* Nuke trailing newline. */
1224 s = memchr (mud->from, nl, len);
1185 if (s) 1225 if (s)
1186 {
1187 *s = '\0'; 1226 *s = '\0';
1188 d--; 1227 mud->state = UNIX_STATE_DATE;
1228 }
1229
1230 case UNIX_STATE_DATE:
1231 /* Generate a date for the "From " separator. */
1232 {
1233 char *s;
1234 size_t len = 0;
1235 status = message_received (msg, mud->date, 127, &len);
1236 if (status != 0)
1237 {
1238 if (status != EAGAIN)
1239 {
1240 free (mud->from);
1241 free (mud->date);
1242 mud->date = mud->from = NULL;
1243 mud->state = UNIX_NO_STATE;
1244 unix_unlock (mbox);
1245 }
1246 return status;
1189 } 1247 }
1190 stream_write (mbox->stream, "From ", 5, size, &n); size += n; 1248 /* Nuke trailing newline. */
1191 stream_write (mbox->stream, from, f, size, &n); size += n; 1249 s = memchr (mud->date, nl, len);
1192 stream_write (mbox->stream, " ", 1, size, &n); size += n; 1250 if (s)
1193 stream_write (mbox->stream, date, d, size, &n); size += n; 1251 *s = '\0';
1194 stream_write (mbox->stream, &nl , 1, size, &n); size += n; 1252 /* Write the separator to the mailbox. */
1253 stream_write (mbox->stream, "From ", 5, size, &n);
1254 size += n;
1255 stream_write (mbox->stream, mud->from, strlen (mud->from), size, &n);
1256 size += n;
1257 stream_write (mbox->stream, " ", 1, size, &n);
1258 size += n;
1259 stream_write (mbox->stream, mud->date, strlen (mud->date), size, &n);
1260 size += n;
1261 stream_write (mbox->stream, &nl , 1, size, &n);
1262 size += n;
1263 free (mud->from);
1264 free (mud->date);
1265 mud->from = mud->date = NULL;
1266 mud->state = UNIX_STATE_APPEND;
1195 } 1267 }
1196 1268
1269 case UNIX_STATE_APPEND:
1197 /* Append the Message. */ 1270 /* Append the Message. */
1198 { 1271 {
1199 char buffer[BUFSIZ]; 1272 char buffer[BUFSIZ];
1200 size_t nread = 0; 1273 size_t nread = 0;
1201 off_t off = 0;
1202 stream_t is; 1274 stream_t is;
1203 message_get_stream (msg, &is); 1275 message_get_stream (msg, &is);
1204 do 1276 do
1205 { 1277 {
1206 stream_read (is, buffer, sizeof (buffer), off, &nread); 1278 status = stream_read (is, buffer, sizeof (buffer), mud->off,
1279 &nread);
1280 if (status != 0)
1281 {
1282 if (status != EAGAIN)
1283 {
1284 free (mud->from);
1285 free (mud->date);
1286 mud->date = mud->from = NULL;
1287 mud->state = UNIX_NO_STATE;
1288 unix_unlock (mbox);
1289 }
1290 stream_flush (mbox->stream);
1291 return status;
1292 }
1207 stream_write (mbox->stream, buffer, nread, size, &n); 1293 stream_write (mbox->stream, buffer, nread, size, &n);
1208 off += nread; 1294 mud->off += nread;
1209 size += n; 1295 size += n;
1210 } 1296 }
1211 while (nread > 0); 1297 while (nread > 0);
1212 stream_write (mbox->stream, &nl, 1, size, &n); 1298 stream_write (mbox->stream, &nl, 1, size, &n);
1213 } 1299 }
1300
1301 default:
1302 break;
1303 }
1214 } 1304 }
1215 stream_flush (mbox->stream); 1305 stream_flush (mbox->stream);
1306 mud->state = UNIX_NO_STATE;
1216 unix_unlock (mbox); 1307 unix_unlock (mbox);
1217 return 0; 1308 return 0;
1218 } 1309 }
...@@ -1238,8 +1329,8 @@ unix_size (mailbox_t mbox, off_t *psize) ...@@ -1238,8 +1329,8 @@ unix_size (mailbox_t mbox, off_t *psize)
1238 static int 1329 static int
1239 unix_messages_count (mailbox_t mbox, size_t *pcount) 1330 unix_messages_count (mailbox_t mbox, size_t *pcount)
1240 { 1331 {
1241 unix_data_t mud; 1332 unix_data_t mud = mbox->data;
1242 if (mbox == NULL || (mud = (unix_data_t) mbox->data) == NULL) 1333 if (mud == NULL)
1243 return EINVAL; 1334 return EINVAL;
1244 1335
1245 if (! unix_is_updated (mbox)) 1336 if (! unix_is_updated (mbox))
......
...@@ -153,6 +153,17 @@ message_set_body (message_t msg, body_t body, void *owner) ...@@ -153,6 +153,17 @@ message_set_body (message_t msg, body_t body, void *owner)
153 } 153 }
154 154
155 int 155 int
156 message_set_stream (message_t msg, stream_t stream, void *owner)
157 {
158 if (msg == NULL)
159 return EINVAL;
160 if (msg->owner != owner)
161 return EACCES;
162 msg->stream = stream;
163 return 0;
164 }
165
166 int
156 message_get_stream (message_t msg, stream_t *pstream) 167 message_get_stream (message_t msg, stream_t *pstream)
157 { 168 {
158 if (msg == NULL || pstream == NULL) 169 if (msg == NULL || pstream == NULL)
...@@ -177,11 +188,26 @@ message_get_stream (message_t msg, stream_t *pstream) ...@@ -177,11 +188,26 @@ message_get_stream (message_t msg, stream_t *pstream)
177 } 188 }
178 189
179 int 190 int
191 message_set_lines (message_t msg, int (*_lines)
192 (message_t, size_t *), void *owner)
193 {
194 if (msg == NULL)
195 return EINVAL;
196 if (msg->owner != owner)
197 return EACCES;
198 msg->_lines = _lines;
199 return 0;
200 }
201
202 int
180 message_lines (message_t msg, size_t *plines) 203 message_lines (message_t msg, size_t *plines)
181 { 204 {
182 size_t hlines, blines; 205 size_t hlines, blines;
183 if (msg == NULL) 206 if (msg == NULL)
184 return EINVAL; 207 return EINVAL;
208 /* Overload */
209 if (msg->_lines)
210 return msg->_lines (msg, plines);
185 if (plines) 211 if (plines)
186 { 212 {
187 hlines = blines = 0; 213 hlines = blines = 0;
...@@ -193,11 +219,26 @@ message_lines (message_t msg, size_t *plines) ...@@ -193,11 +219,26 @@ message_lines (message_t msg, size_t *plines)
193 } 219 }
194 220
195 int 221 int
222 message_set_size (message_t msg, int (*_size)
223 (message_t, size_t *), void *owner)
224 {
225 if (msg == NULL)
226 return EINVAL;
227 if (msg->owner != owner)
228 return EACCES;
229 msg->_size = _size;
230 return 0;
231 }
232
233 int
196 message_size (message_t msg, size_t *psize) 234 message_size (message_t msg, size_t *psize)
197 { 235 {
198 size_t hsize, bsize; 236 size_t hsize, bsize;
199 if (msg == NULL) 237 if (msg == NULL)
200 return EINVAL; 238 return EINVAL;
239 /* Overload ? */
240 if (msg->_size)
241 return msg->_size (msg, psize);
201 if (psize) 242 if (psize)
202 { 243 {
203 hsize = bsize = 0; 244 hsize = bsize = 0;
...@@ -235,14 +276,14 @@ message_from (message_t msg, char *buf, size_t len, size_t *pnwrite) ...@@ -235,14 +276,14 @@ message_from (message_t msg, char *buf, size_t len, size_t *pnwrite)
235 if (msg->_from) 276 if (msg->_from)
236 return msg->_from (msg, buf, len, pnwrite); 277 return msg->_from (msg, buf, len, pnwrite);
237 278
238 /* can it be extracted from the FROM: */ 279 /* can it be extracted from the From: */
239 message_get_header (msg, &header); 280 message_get_header (msg, &header);
240 status = header_get_value (header, "FROM", NULL, 0, &n); 281 status = header_get_value (header, MU_HEADER_FROM, NULL, 0, &n);
241 if (status == 0 && n != 0) 282 if (status == 0 && n != 0)
242 { 283 {
243 char *from = calloc (1, n + 1); 284 char *from = calloc (1, n + 1);
244 char *addr; 285 char *addr;
245 header_get_value (header, "FROM", from, n + 1, NULL); 286 header_get_value (header, MU_HEADER_FROM, from, n + 1, NULL);
246 if (extract_addr (from, n, &addr, &n) == 0) 287 if (extract_addr (from, n, &addr, &n) == 0)
247 { 288 {
248 n = (n > len) ? len : n; 289 n = (n > len) ? len : n;
...@@ -258,6 +299,8 @@ message_from (message_t msg, char *buf, size_t len, size_t *pnwrite) ...@@ -258,6 +299,8 @@ message_from (message_t msg, char *buf, size_t len, size_t *pnwrite)
258 return 0; 299 return 0;
259 } 300 }
260 } 301 }
302 else if (status == EAGAIN)
303 return status;
261 304
262 /* oops */ 305 /* oops */
263 n = (7 > len) ? len: 7; 306 n = (7 > len) ? len: 7;
...@@ -374,16 +417,43 @@ message_set_uidl (message_t msg, int (* _get_uidl) ...@@ -374,16 +417,43 @@ message_set_uidl (message_t msg, int (* _get_uidl)
374 } 417 }
375 418
376 int 419 int
377 message_is_mime (message_t msg) 420 message_set_is_multipart (message_t msg, int (*_is_multipart)
421 __P ((message_t, int *)), void *owner)
422 {
423 if (msg == NULL)
424 return EINVAL;
425 if (msg->owner != owner)
426 return EACCES;
427 msg->_is_multipart = _is_multipart;
428 return 0;
429 }
430
431 int
432 message_is_multipart (message_t msg, int *p_is_mp)
378 { 433 {
379 header_t header; 434 header_t header;
380 int status; 435 int status;
436 size_t len = 0;
381 437
382 status = message_get_header(msg, &header); 438 if (msg == NULL || p_is_mp)
383 if (status != 0) 439 return EINVAL;
440
441 message_get_header(msg, &header);
442 status = header_get_value (header, "Content-Type", NULL, 0, &len);
443 if (status == 0)
444 {
445 char *content_type = calloc (len + 1, sizeof (char));
446 if (content_type == NULL)
447 return ENOMEM;
448 status = header_get_value (header, "Content-Type", content_type,
449 len, NULL);
450 *p_is_mp = strncasecmp ("multipart", content_type,
451 strlen ("multipart")) ? 0: 1;
452 free (content_type);
453 }
454 else
455 *p_is_mp = 0;
384 return status; 456 return status;
385 status = header_get_value (header, "Mime-Version", NULL, 0, NULL);
386 return (status == 0);
387 } 457 }
388 458
389 int 459 int
...@@ -422,6 +492,7 @@ message_get_part (message_t msg, size_t part, message_t *pmsg) ...@@ -422,6 +492,7 @@ message_get_part (message_t msg, size_t part, message_t *pmsg)
422 if (msg == NULL || pmsg == NULL) 492 if (msg == NULL || pmsg == NULL)
423 return EINVAL; 493 return EINVAL;
424 494
495 /* Overload. */
425 if (msg->_get_part) 496 if (msg->_get_part)
426 return msg->_get_part (msg, part, pmsg); 497 return msg->_get_part (msg, part, pmsg);
427 498
...@@ -518,12 +589,11 @@ static int ...@@ -518,12 +589,11 @@ static int
518 message_read (stream_t is, char *buf, size_t buflen, 589 message_read (stream_t is, char *buf, size_t buflen,
519 off_t off, size_t *pnread ) 590 off_t off, size_t *pnread )
520 { 591 {
521 message_t msg; 592 message_t msg = is->owner;
522 stream_t his, bis; 593 stream_t his, bis;
523 size_t hread, hsize, bread, bsize; 594 size_t hread, hsize, bread, bsize;
524 595
525 596 if (msg == NULL)
526 if (is == NULL || (msg = is->owner) == NULL)
527 return EINVAL; 597 return EINVAL;
528 598
529 bsize = hsize = bread = hread = 0; 599 bsize = hsize = bread = hread = 0;
...@@ -536,16 +606,10 @@ message_read (stream_t is, char *buf, size_t buflen, ...@@ -536,16 +606,10 @@ message_read (stream_t is, char *buf, size_t buflen,
536 until you start reading them. So by checking hsize == bsize == 0, 606 until you start reading them. So by checking hsize == bsize == 0,
537 this kludge is a way of detecting the anomalie and start by the 607 this kludge is a way of detecting the anomalie and start by the
538 header. */ 608 header. */
539 if ((size_t)off <= hsize || (hsize == 0 && bsize == 0)) 609 if ((size_t)off < hsize || (hsize == 0 && bsize == 0))
540 { 610 {
541 header_get_stream (msg->header, &his); 611 header_get_stream (msg->header, &his);
542 stream_read (his, buf, buflen, off, &hread); 612 stream_read (his, buf, buflen, off, &hread);
543 /* still room left for some body, .. a pun ;-) */
544 if ((buflen - hread) > 0)
545 {
546 body_get_stream (msg->body, &bis);
547 stream_read (bis, buf + hread, buflen - hread, 0, &bread);
548 }
549 } 613 }
550 else 614 else
551 { 615 {
......