Commit 24361598 24361598116c688aeabec17db0a133af03ed0d64 by Alain Magloire

The code for IMAP, is a pain, the rewrite should clean all those

	hacks.  Something to remember for the mailbox2 is to do some
	smart caching, the current buffered stream is not good enough.

	* configure.in: VERSION is set to 0.0.9a for the alpha.
	* frm/frm.c: Protype for usage(). get_personal() should use
	const char *.
	* mail/mail.c (main): Use mailbox_scan() instead of
	mailbox_messages_count () it is faster for IMAP.

	* mailbox/mbx_imap.c(imap_get_message0): Remove the
	stream_setbufsiz() it is no longer used.
	(imap_message_readline imap_body_readline):
	Bug fix, readline will only consume up to '\n' even though the
	buffer is bigger.  So we have to adjust the offset/lines/size
	to reflect what we consume.  This is not very good for example
	doing:
	{
	   off_t offset = 14;
	   char buffer[512];
	   stream_readline (stream, buffer, sizeof buffer, offset, NULL);
	   ...
	}
	Will send to the impap server.
	C: g445 FETCH 4 BODY.PEEK[2]<0.2048>
        S: * 4 FETCH (BODY[2]<0> {739}
	S: g445 OK FETCH completed

	This is waste since the first line is only 37 bytes.  We will
	have to come up on the second API with some smart caching.

	* mailbox/memory_stream.c (_memory_write): Nasty bug
	was not updating the stream size.
	* mailbox/stream.c(stream_readline): Take care of known
	case where the buflen is 0 or 1.
1 parent 9b87545a
1 2001-10-14 Alain Magloire 1 2001-10-14 Alain Magloire
2 2
3 The code for property.c has been change for a more simple approach, 3 The code for IMAP, is a pain, the rewrite should clean all those
4 it is the same approach as in mail/util.c(environment) settings. 4 hacks. Something to remember for the mailbox2 is to do some
5 The old code was simply overkill, property_t was seldomly use 5 smart caching, the current buffered stream is not good enough.
6 if at all and no need for heavy hash table and all that jazz. 6
7 * configure.in: VERSION is set to 0.0.9a for the alpha.
8 * frm/frm.c: Protype for usage(). get_personal() should use
9 const char *.
10 * mail/mail.c (main): Use mailbox_scan() instead of
11 mailbox_messages_count () it is faster for IMAP.
12
13 * mailbox/mbx_imap.c(imap_get_message0): Remove the
14 stream_setbufsiz() it is no longer used.
15 (imap_message_readline imap_body_readline):
16 Bug fix, readline will only consume up to '\n' even though the
17 buffer is bigger. So we have to adjust the offset/lines/size
18 to reflect what we consume. This is not very good for example
19 doing:
20 {
21 off_t offset = 14;
22 char buffer[512];
23 stream_readline (stream, buffer, sizeof buffer, offset, NULL);
24 ...
25 }
26 Will send to the impap server.
27 C: g445 FETCH 4 BODY.PEEK[2]<0.2048>
28 S: * 4 FETCH (BODY[2]<0> {739}
29 S: g445 OK FETCH completed
30
31 This is waste since the first line is only 37 bytes. We will
32 have to come up on the second API with some smart caching.
33
34 * mailbox/memory_stream.c (_memory_write): Nasty bug
35 was not updating the stream size.
36 * mailbox/stream.c(stream_readline): Take care of known
37 case where the buflen is 0 or 1.
7 38
8 * mailbox/property.c: New code, the same as mail/util.c 39 2001-10-14 Alain Magloire
9 environment. 40
41 The code for property.c has been changed for a more simple approach,
42 it is the same approach as mail/util.c(environment) settings.
43 The old code was simply overkill, property_t was seldomly used,
44 if at all, no need for heavy hash table and all that jazz.
45
46 * mailbox/property.c: New code, the same as mail/util.c environment.
10 * mailbox/mbx_mbox.c (_mbx_init): Remove property_add_defaults() etc .. 47 * mailbox/mbx_mbox.c (_mbx_init): Remove property_add_defaults() etc ..
11 no longer in use in the initialisation code. 48 no longer in use in the initialisation code.
12 * mailbox/mbx_imap.c: Likewised 49 * mailbox/mbx_imap.c: Likewised
13 * mailbox/mbx_pop.c: Likewised 50 * mailbox/mbx_pop.c: Likewised
14 * mailbox/mbx_mh.c: Likewised 51 * mailbox/mbx_mh.c: Likewised
15 * mailbox/header.c: Remove property code. 52 * mailbox/header.c: Removed property code.
16 * mailbox/body.c: Remove property code. 53 * mailbox/body.c: Removed property code.
17 * mailbox/message.c: Remove property code. 54 * mailbox/message.c: Removed property code.
18 * mailbox/filter.c: Change the code according to the new property_t. 55 * mailbox/filter.c: Changed the code according to the new property_t.
19 * mailbox/filter_rfc822.c: Change the code according to the new 56 * mailbox/filter_rfc822.c: Changed the code according to the new
20 property_t. 57 property_t structure.
21 * include/mailutils/header.h: Remove property. 58 * include/mailutils/header.h: Removed property.
22 * include/mailutils/body.h: Remove property. 59 * include/mailutils/body.h: Removed property.
23 * include/mailutils/message.h: Remove property. 60 * include/mailutils/message.h: Removed property.
24 * include/mailutils/property.h: Remove property_add_defaults() 61 * include/mailutils/property.h: Removed property_add_defaults()
25 property_set_valued () takes one more argument for overwrite. 62 property_set_valued () takes one more argument for overwrite.
26 * mailbox/include/header0.hy: Remove property field. 63 * mailbox/include/header0.hy: Removed property field.
27 * mailbox/include/body0.hy: Remove property field. 64 * mailbox/include/body0.hy: Removed property field.
28 * mailbox/include/message0.hy: Remove property field. 65 * mailbox/include/message0.hy: Removed property field.
29 * mailbox/mailbox.c(mailbox_get_property mailbox_set_property): 66 * mailbox/mailbox.c(mailbox_get_property mailbox_set_property):
30 Changed Property code. 67 Changed Property code.
31 * mailbox/mailer.c(mailer_set_property mailer_get_property): 68 * mailbox/mailer.c(mailer_set_property mailer_get_property):
32 Changed Property code. 69 Changed Property code.
33 70
34 * mailbox/folder_imap.c (imap_search imap_expunge imap_status): Stubs 71 * mailbox/folder_imap.c (imap_search imap_expunge imap_status): Stubs
35 Search is not implemented yet, STATUS neither and EXPUNGE is not used. 72 SEARCH is not implemented yet, STATUS neither and EXPUNGE is not used.
36 73
37 * mailbox/list.c: Rename variable index to indx to shutup 74 * mailbox/list.c: Renamed variable index to indx to shutup
38 gcc whos confusing with index() when warning level was high. 75 gcc whos confusing with index() when warning level was high.
39 * mailbox/md5-rsa.c: Likewised. 76 * mailbox/md5-rsa.c: Likewised.
40 77
...@@ -42,8 +79,8 @@ ...@@ -42,8 +79,8 @@
42 The debug object was being set on the folder not the mailbox. 79 The debug object was being set on the folder not the mailbox.
43 80
44 * mailbox/mbx_imap.c (imap_messages_count): Attempt to reconnect 81 * mailbox/mbx_imap.c (imap_messages_count): Attempt to reconnect
45 if the connection timeout. Is this wise ? 82 if the connection timeout. Is this wise?
46 (imap_scan0): Move gut of imap_scan() code tho here. 83 (imap_scan0): Moved gut of imap_scan() code here.
47 (imap_scan): Stub calling imap_scan0() with notification enable. 84 (imap_scan): Stub calling imap_scan0() with notification enable.
48 (imap_expunge): After CLOSE, call imap_scan0() wiht notification 85 (imap_expunge): After CLOSE, call imap_scan0() wiht notification
49 disable. 86 disable.
...@@ -52,13 +89,12 @@ ...@@ -52,13 +89,12 @@
52 of the recursive nature of the algorithm. Sam should buy me 89 of the recursive nature of the algorithm. Sam should buy me
53 a beer for this. 90 a beer for this.
54 91
55 * mailbox/parse822.c: Use more assert to catch errors. 92 * mailbox/parse822.c: Used more assert to catch errors.
56 (parse822_group): phrase was not free() in case of failure. 93 (parse822_group): phrase was not free() in case of failure.
57 (parse822_mail_box): Dead if branch remove and free phrase. 94 (parse822_mail_box): Dead "else if" branch removed and free phrase.
58 (parse822_route): accumulator was not being freed. 95 (parse822_route): accumulator was not being freed.
59 (parse822_local_part): Move down st_free(more). 96 (parse822_local_part): Moved down st_free(more).
60 (parse822_domain): Move down st_free(more). 97 (parse822_domain): Moved down st_free(more).
61
62 98
63 2001-10-14 Sergey Poznyakoff 99 2001-10-14 Sergey Poznyakoff
64 100
......
1 dnl Process this file with autoconf to procude a configure script. 1 dnl Process this file with autoconf to procude a configure script.
2 AC_INIT(mailbox/mailbox.c) 2 AC_INIT(mailbox/mailbox.c)
3 AM_INIT_AUTOMAKE(mailutils, 0.0.9) 3 AM_INIT_AUTOMAKE(mailutils, 0.0.9a)
4 AM_CONFIG_HEADER(config.h) 4 AM_CONFIG_HEADER(config.h)
5 5
6 dnl Check for programs 6 dnl Check for programs
...@@ -247,9 +247,9 @@ fi ...@@ -247,9 +247,9 @@ fi
247 247
248 dnl Output Makefiles 248 dnl Output Makefiles
249 AC_OUTPUT(Makefile mailutils.spec include/Makefile include/mailutils/Makefile 249 AC_OUTPUT(Makefile mailutils.spec include/Makefile include/mailutils/Makefile
250 m4/Makefile doc/Makefile doc/rfc/Makefile doc/texinfo/Makefile argp/Makefile 250 m4/Makefile doc/Makefile doc/rfc/Makefile doc/texinfo/Makefile argp/Makefile
251 lib/Makefile lib/posix/Makefile mailbox/Makefile imap4d/Makefile 251 lib/Makefile lib/posix/Makefile mailbox/Makefile imap4d/Makefile
252 mailbox/include/Makefile from/Makefile mail/Makefile pop3d/Makefile 252 mailbox/include/Makefile from/Makefile mail/Makefile pop3d/Makefile
253 frm/Makefile sieve/Makefile messages/Makefile scripts/Makefile 253 frm/Makefile sieve/Makefile messages/Makefile scripts/Makefile
254 libmu_scm/Makefile guimb/Makefile guimb/scm/Makefile 254 libmu_scm/Makefile guimb/Makefile guimb/scm/Makefile
255 MySql/Makefile) 255 MySql/Makefile)
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
33 #include <mailutils/address.h> 33 #include <mailutils/address.h>
34 34
35 static int action (observer_t, size_t); 35 static int action (observer_t, size_t);
36 static void usage (const char *argv);
36 37
37 static struct option long_options[] = 38 static struct option long_options[] =
38 { 39 {
...@@ -71,7 +72,7 @@ static int selected; ...@@ -71,7 +72,7 @@ static int selected;
71 72
72 /* Retrieve the Personal Name from the header To: or From: */ 73 /* Retrieve the Personal Name from the header To: or From: */
73 static int 74 static int
74 get_personal (header_t hdr, char *field, char *personal, size_t buflen) 75 get_personal (header_t hdr, const char *field, char *personal, size_t buflen)
75 { 76 {
76 char hfield[512]; 77 char hfield[512];
77 int status; 78 int status;
...@@ -193,7 +194,7 @@ action (observer_t o, size_t type) ...@@ -193,7 +194,7 @@ action (observer_t o, size_t type)
193 return 0; 194 return 0;
194 } 195 }
195 196
196 void 197 static void
197 usage (const char *argv) 198 usage (const char *argv)
198 { 199 {
199 printf ("GNU Mailutils.\n"); 200 printf ("GNU Mailutils.\n");
...@@ -323,7 +324,6 @@ main(int argc, char **argv) ...@@ -323,7 +324,6 @@ main(int argc, char **argv)
323 mailbox_t mbox; 324 mailbox_t mbox;
324 observer_t observer; 325 observer_t observer;
325 observable_t observable; 326 observable_t observable;
326 int status;
327 327
328 if ((status = mailbox_create_default (&mbox, mailbox_name) != 0) 328 if ((status = mailbox_create_default (&mbox, mailbox_name) != 0)
329 || (status = mailbox_open (mbox, MU_STREAM_READ) != 0)) 329 || (status = mailbox_open (mbox, MU_STREAM_READ) != 0))
......
...@@ -359,7 +359,7 @@ main (int argc, char **argv) ...@@ -359,7 +359,7 @@ main (int argc, char **argv)
359 exit (EXIT_FAILURE); 359 exit (EXIT_FAILURE);
360 } 360 }
361 361
362 if (mailbox_messages_count (mbox, &total) != 0) 362 if (mailbox_scan (mbox, 1, &total) != 0)
363 { 363 {
364 util_error ("Can not read mailbox"); 364 util_error ("Can not read mailbox");
365 exit (EXIT_FAILURE); 365 exit (EXIT_FAILURE);
......
...@@ -62,6 +62,8 @@ static int imap_message_size __P ((message_t, size_t *)); ...@@ -62,6 +62,8 @@ static int imap_message_size __P ((message_t, size_t *));
62 static int imap_message_lines __P ((message_t, size_t *)); 62 static int imap_message_lines __P ((message_t, size_t *));
63 static int imap_message_fd __P ((stream_t, int *)); 63 static int imap_message_fd __P ((stream_t, int *));
64 static int imap_message_read __P ((stream_t , char *, size_t, off_t, size_t *)); 64 static int imap_message_read __P ((stream_t , char *, size_t, off_t, size_t *));
65 static int imap_message_readline __P ((stream_t, char *, size_t, off_t,
66 size_t *));
65 static int imap_message_uid __P ((message_t, size_t *)); 67 static int imap_message_uid __P ((message_t, size_t *));
66 68
67 /* mime_t API. */ 69 /* mime_t API. */
...@@ -84,7 +86,10 @@ static int imap_header_get_value __P ((header_t, const char*, char *, size_t, s ...@@ -84,7 +86,10 @@ static int imap_header_get_value __P ((header_t, const char*, char *, size_t, s
84 static int imap_header_get_fvalue __P ((header_t, const char*, char *, size_t, size_t *)); 86 static int imap_header_get_fvalue __P ((header_t, const char*, char *, size_t, size_t *));
85 87
86 /* body_t API. */ 88 /* body_t API. */
87 static int imap_body_read __P ((stream_t, char *, size_t, off_t, size_t *)); 89 static int imap_body_read __P ((stream_t, char *, size_t, off_t,
90 size_t *));
91 static int imap_body_readline __P ((stream_t, char *, size_t, off_t,
92 size_t *));
88 static int imap_body_size __P ((body_t, size_t *)); 93 static int imap_body_size __P ((body_t, size_t *));
89 static int imap_body_lines __P ((body_t, size_t *)); 94 static int imap_body_lines __P ((body_t, size_t *));
90 static int imap_body_fd __P ((stream_t, int *)); 95 static int imap_body_fd __P ((stream_t, int *));
...@@ -372,9 +377,8 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg) ...@@ -372,9 +377,8 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg)
372 message_destroy (&msg, msg_imap); 377 message_destroy (&msg, msg_imap);
373 return status; 378 return status;
374 } 379 }
375 /* We want the buffering. */
376 stream_setbufsiz (stream, 128);
377 stream_set_read (stream, imap_message_read, msg); 380 stream_set_read (stream, imap_message_read, msg);
381 stream_set_readline (stream, imap_message_readline, msg);
378 stream_set_fd (stream, imap_message_fd, msg); 382 stream_set_fd (stream, imap_message_fd, msg);
379 message_set_stream (msg, stream, msg_imap); 383 message_set_stream (msg, stream, msg_imap);
380 message_set_size (msg, imap_message_size, msg_imap); 384 message_set_size (msg, imap_message_size, msg_imap);
...@@ -422,9 +426,8 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg) ...@@ -422,9 +426,8 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg)
422 message_destroy (&msg, msg_imap); 426 message_destroy (&msg, msg_imap);
423 return status; 427 return status;
424 } 428 }
425 /* We want the buffering. */
426 stream_setbufsiz (stream, 128);
427 stream_set_read (stream, imap_body_read, body); 429 stream_set_read (stream, imap_body_read, body);
430 stream_set_readline (stream, imap_body_readline, body);
428 stream_set_fd (stream, imap_body_fd, body); 431 stream_set_fd (stream, imap_body_fd, body);
429 body_set_size (body, imap_body_size, msg); 432 body_set_size (body, imap_body_size, msg);
430 body_set_lines (body, imap_body_lines, msg); 433 body_set_lines (body, imap_body_lines, msg);
...@@ -947,6 +950,41 @@ imap_copy_message (mailbox_t mailbox, message_t msg) ...@@ -947,6 +950,41 @@ imap_copy_message (mailbox_t mailbox, message_t msg)
947 950
948 /* Message read overload */ 951 /* Message read overload */
949 static int 952 static int
953 imap_message_readline (stream_t stream, char *buffer, size_t buflen,
954 off_t offset, size_t *plen)
955 {
956 message_t msg = stream_get_owner (stream);
957 msg_imap_t msg_imap = message_get_owner (msg);
958 m_imap_t m_imap = msg_imap->m_imap;
959 size_t lines = msg_imap->message_lines;
960 int status;
961 size_t len = 0;
962 char *nl = buffer;
963
964 /* Start over. */
965 if (offset == 0)
966 lines = 0;
967
968 buflen--; /* for the NULL. */
969 status = imap_message_read (stream, buffer, buflen, offset, &len);
970 if (len)
971 {
972 nl = memchr (buffer, '\n', len);
973 if (nl)
974 {
975 nl++;
976 *nl = '\0';
977 msg_imap->message_lines = lines + 1;
978 }
979 else
980 nl = buffer + len;
981 }
982 if (plen)
983 *plen = nl - buffer;
984 return status;
985 }
986
987 static int
950 imap_message_read (stream_t stream, char *buffer, size_t buflen, 988 imap_message_read (stream_t stream, char *buffer, size_t buflen,
951 off_t offset, size_t *plen) 989 off_t offset, size_t *plen)
952 { 990 {
...@@ -954,6 +992,22 @@ imap_message_read (stream_t stream, char *buffer, size_t buflen, ...@@ -954,6 +992,22 @@ imap_message_read (stream_t stream, char *buffer, size_t buflen,
954 msg_imap_t msg_imap = message_get_owner (msg); 992 msg_imap_t msg_imap = message_get_owner (msg);
955 m_imap_t m_imap = msg_imap->m_imap; 993 m_imap_t m_imap = msg_imap->m_imap;
956 f_imap_t f_imap = m_imap->f_imap; 994 f_imap_t f_imap = m_imap->f_imap;
995 char *oldbuf = NULL;
996 char newbuf[2];
997 int status;
998
999 /* This is so annoying, a buffer len of 1 is a killer. If you have for
1000 example "\n" to retrieve from the server, IMAP will transform this to
1001 "\r\n" and since you ask for only 1, the server will send '\r' only.
1002 And ... '\r' will be stripped by (imap_readline()) the number of char
1003 read will be 0 which means we're done .... sigh ... So we guard by at
1004 least ask for 2 chars. */
1005 if (buflen == 1)
1006 {
1007 oldbuf = buffer;
1008 buffer = newbuf;
1009 buflen = 2;
1010 }
957 1011
958 /* Start over. */ 1012 /* Start over. */
959 if (offset == 0) 1013 if (offset == 0)
...@@ -963,7 +1017,7 @@ imap_message_read (stream_t stream, char *buffer, size_t buflen, ...@@ -963,7 +1017,7 @@ imap_message_read (stream_t stream, char *buffer, size_t buflen,
963 if (f_imap->state == IMAP_NO_STATE) 1017 if (f_imap->state == IMAP_NO_STATE)
964 { 1018 {
965 char *section = NULL; 1019 char *section = NULL;
966 int status = imap_messages_count (m_imap->mailbox, NULL); 1020 status = imap_messages_count (m_imap->mailbox, NULL);
967 if (status != 0) 1021 if (status != 0)
968 return status; 1022 return status;
969 1023
...@@ -983,7 +1037,11 @@ imap_message_read (stream_t stream, char *buffer, size_t buflen, ...@@ -983,7 +1037,11 @@ imap_message_read (stream_t stream, char *buffer, size_t buflen,
983 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer); 1037 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer);
984 f_imap->state = IMAP_FETCH; 1038 f_imap->state = IMAP_FETCH;
985 } 1039 }
986 return fetch_operation (f_imap, msg_imap, buffer, buflen, plen); 1040 status = fetch_operation (f_imap, msg_imap, buffer, buflen, plen);
1041
1042 if (oldbuf)
1043 oldbuf[0] = buffer[0];
1044 return status;
987 } 1045 }
988 1046
989 static int 1047 static int
...@@ -1585,6 +1643,22 @@ imap_header_read (header_t header, char *buffer, size_t buflen, off_t offset, ...@@ -1585,6 +1643,22 @@ imap_header_read (header_t header, char *buffer, size_t buflen, off_t offset,
1585 msg_imap_t msg_imap = message_get_owner (msg); 1643 msg_imap_t msg_imap = message_get_owner (msg);
1586 m_imap_t m_imap = msg_imap->m_imap; 1644 m_imap_t m_imap = msg_imap->m_imap;
1587 f_imap_t f_imap = m_imap->f_imap; 1645 f_imap_t f_imap = m_imap->f_imap;
1646 char *oldbuf = NULL;
1647 char newbuf[2];
1648 int status;
1649
1650 /* This is so annoying, a buffer len of 1 is a killer. If you have for
1651 example "\n" to retrieve from the server, IMAP will transform this to
1652 "\r\n" and since you ask for only 1, the server will send '\r' only.
1653 And ... '\r' will be stripped by (imap_readline()) the number of char
1654 read will be 0 which means we're done .... sigh ... So we guard by at
1655 least ask for 2 chars. */
1656 if (buflen == 1)
1657 {
1658 oldbuf = buffer;
1659 buffer = newbuf;
1660 buflen = 2;
1661 }
1588 1662
1589 /* Start over. */ 1663 /* Start over. */
1590 if (offset == 0) 1664 if (offset == 0)
...@@ -1593,7 +1667,7 @@ imap_header_read (header_t header, char *buffer, size_t buflen, off_t offset, ...@@ -1593,7 +1667,7 @@ imap_header_read (header_t header, char *buffer, size_t buflen, off_t offset,
1593 /* Select first. */ 1667 /* Select first. */
1594 if (f_imap->state == IMAP_NO_STATE) 1668 if (f_imap->state == IMAP_NO_STATE)
1595 { 1669 {
1596 int status = imap_messages_count (m_imap->mailbox, NULL); 1670 status = imap_messages_count (m_imap->mailbox, NULL);
1597 if (status != 0) 1671 if (status != 0)
1598 return status; 1672 return status;
1599 /* We strip the \r, but the offset/size on the imap server is with that 1673 /* We strip the \r, but the offset/size on the imap server is with that
...@@ -1619,7 +1693,10 @@ imap_header_read (header_t header, char *buffer, size_t buflen, off_t offset, ...@@ -1619,7 +1693,10 @@ imap_header_read (header_t header, char *buffer, size_t buflen, off_t offset,
1619 f_imap->state = IMAP_FETCH; 1693 f_imap->state = IMAP_FETCH;
1620 1694
1621 } 1695 }
1622 return fetch_operation (f_imap, msg_imap, buffer, buflen, plen); 1696 status = fetch_operation (f_imap, msg_imap, buffer, buflen, plen);
1697 if (oldbuf)
1698 oldbuf[0] = buffer[0];
1699 return status;
1623 } 1700 }
1624 1701
1625 /* Body. */ 1702 /* Body. */
...@@ -1661,6 +1738,41 @@ imap_body_lines (body_t body, size_t *plines) ...@@ -1661,6 +1738,41 @@ imap_body_lines (body_t body, size_t *plines)
1661 return 0; 1738 return 0;
1662 } 1739 }
1663 1740
1741 static int
1742 imap_body_readline (stream_t stream, char *buffer, size_t buflen, off_t offset,
1743 size_t *plen)
1744 {
1745 message_t msg = stream_get_owner (stream);
1746 msg_imap_t msg_imap = message_get_owner (msg);
1747 m_imap_t m_imap = msg_imap->m_imap;
1748 size_t lines = msg_imap->body_lines;
1749 int status;
1750 size_t len = 0;
1751 char *nl = buffer;
1752
1753 /* Start over. */
1754 if (offset == 0)
1755 lines = 0;
1756
1757 buflen--; /* for the NULL. */
1758 status = imap_body_read (stream, buffer, buflen, offset, &len);
1759 if (len)
1760 {
1761 nl = memchr (buffer, '\n', len);
1762 if (nl)
1763 {
1764 nl++;
1765 *nl = '\0';
1766 msg_imap->body_lines = lines + 1;
1767 }
1768 else
1769 nl = buffer + len;
1770 }
1771 if (plen)
1772 *plen = nl - buffer;
1773 return status;
1774 }
1775
1664 /* FIXME: Send EISPIPE if trying to seek back. */ 1776 /* FIXME: Send EISPIPE if trying to seek back. */
1665 static int 1777 static int
1666 imap_body_read (stream_t stream, char *buffer, size_t buflen, off_t offset, 1778 imap_body_read (stream_t stream, char *buffer, size_t buflen, off_t offset,
...@@ -1673,7 +1785,7 @@ imap_body_read (stream_t stream, char *buffer, size_t buflen, off_t offset, ...@@ -1673,7 +1785,7 @@ imap_body_read (stream_t stream, char *buffer, size_t buflen, off_t offset,
1673 f_imap_t f_imap = m_imap->f_imap; 1785 f_imap_t f_imap = m_imap->f_imap;
1674 char *oldbuf = NULL; 1786 char *oldbuf = NULL;
1675 char newbuf[2]; 1787 char newbuf[2];
1676 int status = 0; 1788 int status;
1677 1789
1678 /* This is so annoying, a buffer len of 1 is a killer. If you have for 1790 /* This is so annoying, a buffer len of 1 is a killer. If you have for
1679 example "\n" to retrieve from the server, IMAP will transform this to 1791 example "\n" to retrieve from the server, IMAP will transform this to
......
...@@ -105,10 +105,10 @@ _memory_write (stream_t stream, const char *iptr, size_t isize, ...@@ -105,10 +105,10 @@ _memory_write (stream_t stream, const char *iptr, size_t isize,
105 if (tmp == NULL) 105 if (tmp == NULL)
106 return ENOMEM; 106 return ENOMEM;
107 mfs->ptr = tmp; 107 mfs->ptr = tmp;
108 mfs->size = offset + isize;
109 mfs->capacity = newsize; 108 mfs->capacity = newsize;
110 } 109 }
111 110
111 mfs->size = offset + isize;
112 memcpy (mfs->ptr + offset, iptr, isize); 112 memcpy (mfs->ptr + offset, iptr, isize);
113 if (nbytes) 113 if (nbytes)
114 *nbytes = isize; 114 *nbytes = isize;
......
...@@ -262,8 +262,14 @@ stream_readline (stream_t is, char *buf, size_t count, ...@@ -262,8 +262,14 @@ stream_readline (stream_t is, char *buf, size_t count,
262 262
263 is->state = MU_STREAM_STATE_READ; 263 is->state = MU_STREAM_STATE_READ;
264 264
265 if (count == 0) 265 switch (count)
266 { 266 {
267 case 1:
268 /* why would they do a thing like that?
269 stream_readline() is __always null terminated. */
270 if (buf)
271 *buf = '\0';
272 case 0: /* Buffer is empty noop. */
267 if (pnread) 273 if (pnread)
268 *pnread = 0; 274 *pnread = 0;
269 return 0; 275 return 0;
......