Commit 4290bdcd 4290bdcd312193ffedb77bcd9811b584db2a2529 by Alain Magloire

mbx_mbox.c mbx_mboxscan.c : I need to clean the expunge code

I realise that MBOX format means that we also have to escapes lines
that starting with "From " --> ">From ". So much for speed since
this will imply reading line by line.

mbx_pop.c : Some bug fixes, connection is close down if the client
is trying to seek() backward.

folder_imap.c mbx_imap.c : Unfinish business, but getting better.

stream.c : Don't force a flush on close, let the underlying implementatio
do that.
1 parent fb62000f
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
23 #include <string.h> 23 #include <string.h>
24 #include <stdlib.h> 24 #include <stdlib.h>
25 #include <assert.h> 25 #include <assert.h>
26 #include <time.h>
26 27
27 #include <mailutils/address.h> 28 #include <mailutils/address.h>
28 #include <mailbox0.h> 29 #include <mailbox0.h>
...@@ -83,6 +84,13 @@ static int message_operation (f_imap_t, msg_imap_t, enum imap_state, char *, ...@@ -83,6 +84,13 @@ static int message_operation (f_imap_t, msg_imap_t, enum imap_state, char *,
83 size_t, size_t *); 84 size_t, size_t *);
84 static void free_subparts (msg_imap_t); 85 static void free_subparts (msg_imap_t);
85 86
87 static const char *MONTHS[] =
88 {
89 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
90 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
91 };
92
93
86 /* Initialize the concrete object mailbox_t by overloading the function of the 94 /* Initialize the concrete object mailbox_t by overloading the function of the
87 structure. */ 95 structure. */
88 int 96 int
...@@ -890,6 +898,12 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen, ...@@ -890,6 +898,12 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen,
890 msg_imap_t msg_imap = message_get_owner (msg); 898 msg_imap_t msg_imap = message_get_owner (msg);
891 m_imap_t m_imap = msg_imap->m_imap; 899 m_imap_t m_imap = msg_imap->m_imap;
892 f_imap_t f_imap = m_imap->f_imap; 900 f_imap_t f_imap = m_imap->f_imap;
901 int year, mon, day, hour, min, sec;
902 int offt;
903 int i;
904 struct tm tm;
905 time_t now;
906 char month[5];
893 int status; 907 int status;
894 if (f_imap->state == IMAP_NO_STATE) 908 if (f_imap->state == IMAP_NO_STATE)
895 { 909 {
...@@ -904,7 +918,44 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen, ...@@ -904,7 +918,44 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen,
904 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer); 918 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer);
905 f_imap->state = IMAP_FETCH; 919 f_imap->state = IMAP_FETCH;
906 } 920 }
907 return message_operation (f_imap, msg_imap, 0, buffer, buflen, plen); 921 status = message_operation (f_imap, msg_imap, 0, buffer, buflen, plen);
922 if (status != 0)
923 return status;
924 day = mon = year = hour = min = sec = offt = 0;
925 month[0] = '\0';
926 sscanf (buffer, "%2d-%3s-%4d %2d:%2d:%2d %d", &day, month, &year,
927 &hour, &min, &sec, &offt);
928 tm.tm_sec = sec;
929 tm.tm_min = min;
930 tm.tm_hour = hour;
931 tm.tm_mday = day;
932 for (i = 0; i < 12; i++)
933 {
934 if (strncasecmp(month, MONTHS[i], 3) == 0)
935 {
936 mon = i;
937 break;
938 }
939 }
940 tm.tm_mon = mon;
941 tm.tm_year = (year > 1900) ? year - 1900 : year;
942 tm.tm_yday = 0; /* unknown. */
943 tm.tm_wday = 0; /* unknown. */
944 tm.tm_isdst = -1; /* unknown. */
945 /* What to do the timezone? */
946
947 now = mktime (&tm);
948 if (now == (time_t)-1)
949 {
950 /* Fall back to localtime. */
951 now = time (NULL);
952 snprintf (buffer, buflen, "%s", ctime(&now));
953 }
954 else
955 {
956 strftime (buffer, buflen, " %a %b %d %H:%M:%S %Y", &tm);
957 }
958 return 0;
908 } 959 }
909 960
910 /* Attributes. */ 961 /* Attributes. */
...@@ -1131,6 +1182,7 @@ imap_body_lines (body_t body, size_t *plines) ...@@ -1131,6 +1182,7 @@ imap_body_lines (body_t body, size_t *plines)
1131 return 0; 1182 return 0;
1132 } 1183 }
1133 1184
1185 /* FIXME: Send EISPIPE if trying to seek back. */
1134 static int 1186 static int
1135 imap_body_read (stream_t stream, char *buffer, size_t buflen, off_t offset, 1187 imap_body_read (stream_t stream, char *buffer, size_t buflen, off_t offset,
1136 size_t *plen) 1188 size_t *plen)
...@@ -1144,11 +1196,12 @@ imap_body_read (stream_t stream, char *buffer, size_t buflen, off_t offset, ...@@ -1144,11 +1196,12 @@ imap_body_read (stream_t stream, char *buffer, size_t buflen, off_t offset,
1144 char newbuf[2]; 1196 char newbuf[2];
1145 int status = 0; 1197 int status = 0;
1146 1198
1147 /* This so F*$&#g annoying, a buffer len of 1 is a killer. 1199 /* This is so annoying, a buffer len of 1 is a killer. If you have for
1148 If you have for example "\n", IMAP servers will transform 1200 example "\n" to retrieve from the server, IMAP will transform this to
1149 this to "\r\n" and since you ask for only 1 sends '\r' only. 1201 "\r\n" and since you ask for only 1, the server will send '\r' only.
1150 '\r' will be stripped and the number of char read will be 0 1202 And ... '\r' will be stripped by (imap_readline()) the number of char
1151 which means we're done. So we guard to at least ask for 2 chars. */ 1203 read will be 0 which means we're done .... sigh ... So we guard to at
1204 least ask for 2 chars. */
1152 if (buflen == 1) 1205 if (buflen == 1)
1153 { 1206 {
1154 oldbuf = buffer; 1207 oldbuf = buffer;
...@@ -1161,8 +1214,8 @@ imap_body_read (stream_t stream, char *buffer, size_t buflen, off_t offset, ...@@ -1161,8 +1214,8 @@ imap_body_read (stream_t stream, char *buffer, size_t buflen, off_t offset,
1161 status = imap_messages_count (m_imap->mailbox, NULL); 1214 status = imap_messages_count (m_imap->mailbox, NULL);
1162 if (status != 0) 1215 if (status != 0)
1163 return status; 1216 return status;
1164 /* We strip the \r, but the offset/size on the imap server is with that 1217 /* We strip the \r, but the offset/size on the imap server is with the
1165 octet so add it in the offset, since it's the number of lines. */ 1218 octet, so add it since it's the number of lines. */
1166 if (msg_imap->part) 1219 if (msg_imap->part)
1167 { 1220 {
1168 char *section = section_name (msg_imap); 1221 char *section = section_name (msg_imap);
......
...@@ -1255,7 +1255,7 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg) ...@@ -1255,7 +1255,7 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg)
1255 if (pmsg == NULL || mud == NULL) 1255 if (pmsg == NULL || mud == NULL)
1256 return EINVAL; 1256 return EINVAL;
1257 1257
1258 /* We did not start a scanning yet do it now. */ 1258 /* If we did not start a scanning yet do it now. */
1259 if (mud->messages_count == 0) 1259 if (mud->messages_count == 0)
1260 { 1260 {
1261 status = mbox_scan0 (mailbox, 1, NULL, 0); 1261 status = mbox_scan0 (mailbox, 1, NULL, 0);
...@@ -1397,8 +1397,8 @@ mbox_append_message (mailbox_t mailbox, message_t msg) ...@@ -1397,8 +1397,8 @@ mbox_append_message (mailbox_t mailbox, message_t msg)
1397 return 0; 1397 return 0;
1398 } 1398 }
1399 1399
1400 /* FIXME: We need to escape line body line that begins with "From ", this 1400 /* FIXME: We need to escape body line that begins with "From ", this
1401 will required to read the body by line instead of by chuncks hearting 1401 will required to read the body by line instead of by chuncks hurting
1402 perfomance big time when expunging. But should not this be the 1402 perfomance big time when expunging. But should not this be the
1403 responsability of the client ? */ 1403 responsability of the client ? */
1404 static int 1404 static int
...@@ -1734,6 +1734,13 @@ mbox_messages_recent (mailbox_t mailbox, size_t *pcount) ...@@ -1734,6 +1734,13 @@ mbox_messages_recent (mailbox_t mailbox, size_t *pcount)
1734 mbox_message_t mum; 1734 mbox_message_t mum;
1735 size_t j, recent; 1735 size_t j, recent;
1736 1736
1737 /* If we did not start a scanning yet do it now. */
1738 if (mud->messages_count == 0)
1739 {
1740 int status = mbox_scan0 (mailbox, 1, NULL, 0);
1741 if (status != 0)
1742 return status;
1743 }
1737 for (recent = j = 0; j < mud->messages_count; j++) 1744 for (recent = j = 0; j < mud->messages_count; j++)
1738 { 1745 {
1739 mum = mud->umessages[j]; 1746 mum = mud->umessages[j];
...@@ -1753,6 +1760,13 @@ mbox_message_unseen (mailbox_t mailbox, size_t *pmsgno) ...@@ -1753,6 +1760,13 @@ mbox_message_unseen (mailbox_t mailbox, size_t *pmsgno)
1753 mbox_message_t mum; 1760 mbox_message_t mum;
1754 size_t j, unseen; 1761 size_t j, unseen;
1755 1762
1763 /* If we did not start a scanning yet do it now. */
1764 if (mud->messages_count == 0)
1765 {
1766 int status = mbox_scan0 (mailbox, 1, NULL, 0);
1767 if (status != 0)
1768 return status;
1769 }
1756 for (unseen = j = 0; j < mud->messages_count; j++) 1770 for (unseen = j = 0; j < mud->messages_count; j++)
1757 { 1771 {
1758 mum = mud->umessages[j]; 1772 mum = mud->umessages[j];
...@@ -1775,6 +1789,13 @@ mbox_uidvalidity (mailbox_t mailbox, unsigned long *puidvalidity) ...@@ -1775,6 +1789,13 @@ mbox_uidvalidity (mailbox_t mailbox, unsigned long *puidvalidity)
1775 int status = mbox_messages_count (mailbox, NULL); 1789 int status = mbox_messages_count (mailbox, NULL);
1776 if (status != 0) 1790 if (status != 0)
1777 return status; 1791 return status;
1792 /* If we did not start a scanning yet do it now. */
1793 if (mud->messages_count == 0)
1794 {
1795 status = mbox_scan0 (mailbox, 1, NULL, 0);
1796 if (status != 0)
1797 return status;
1798 }
1778 if (puidvalidity) 1799 if (puidvalidity)
1779 *puidvalidity = mud->uidvalidity; 1800 *puidvalidity = mud->uidvalidity;
1780 return 0; 1801 return 0;
...@@ -1787,6 +1808,13 @@ mbox_uidnext (mailbox_t mailbox, size_t *puidnext) ...@@ -1787,6 +1808,13 @@ mbox_uidnext (mailbox_t mailbox, size_t *puidnext)
1787 int status = mbox_messages_count (mailbox, NULL); 1808 int status = mbox_messages_count (mailbox, NULL);
1788 if (status != 0) 1809 if (status != 0)
1789 return status; 1810 return status;
1811 /* If we did not start a scanning yet do it now. */
1812 if (mud->messages_count == 0)
1813 {
1814 status = mbox_scan0 (mailbox, 1, NULL, 0);
1815 if (status != 0)
1816 return status;
1817 }
1790 if (puidnext) 1818 if (puidnext)
1791 *puidnext = mud->uidnext; 1819 *puidnext = mud->uidnext;
1792 return 0; 1820 return 0;
......
...@@ -643,7 +643,8 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif) ...@@ -643,7 +643,8 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
643 mum->mud = mud; 643 mum->mud = mud;
644 mum->header_from = total - n; 644 mum->header_from = total - n;
645 mum->header_from_end = total; 645 mum->header_from_end = total;
646 //mum->body_end = mum->body = 0; 646 mum->body_end = mum->body = 0;
647 mum->attr_flags = 0;
647 lines = 0; 648 lines = 0;
648 sfield = NULL; 649 sfield = NULL;
649 for (j = 0; j < HDRSIZE; j++) 650 for (j = 0; j < HDRSIZE; j++)
......
...@@ -395,12 +395,13 @@ pop_user (authority_t auth) ...@@ -395,12 +395,13 @@ pop_user (authority_t auth)
395 CHECK_ERROR_CLOSE (mbox, mpd, EINVAL); 395 CHECK_ERROR_CLOSE (mbox, mpd, EINVAL);
396 } 396 }
397 status = pop_writeline (mpd, "PASS %s\r\n", mpd->passwd); 397 status = pop_writeline (mpd, "PASS %s\r\n", mpd->passwd);
398 MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer);
398 /* We have to nuke the passwd. */ 399 /* We have to nuke the passwd. */
399 memset (mpd->passwd, '\0', strlen (mpd->passwd)); 400 memset (mpd->passwd, '\0', strlen (mpd->passwd));
400 free (mpd->passwd); 401 free (mpd->passwd);
401 mpd->passwd = NULL; 402 mpd->passwd = NULL;
402 CHECK_ERROR_CLOSE (mbox, mpd, status); 403 CHECK_ERROR_CLOSE (mbox, mpd, status);
403 MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, "PASS *\n"); 404 //MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, "PASS *\n");
404 mpd->state = POP_AUTH_PASS; 405 mpd->state = POP_AUTH_PASS;
405 406
406 case POP_AUTH_PASS: 407 case POP_AUTH_PASS:
...@@ -908,8 +909,14 @@ pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount) ...@@ -908,8 +909,14 @@ pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
908 if (mbox->observable == NULL) 909 if (mbox->observable == NULL)
909 return 0; 910 return 0;
910 for (i = msgno; i <= count; i++) 911 for (i = msgno; i <= count; i++)
911 if (observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD) != 0) 912 {
912 break; 913 if (observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD) != 0)
914 break;
915 if (((i +1) % 10) == 0)
916 {
917 observable_notify (mbox->observable, MU_EVT_MAILBOX_PROGRESS);
918 }
919 }
913 return 0; 920 return 0;
914 } 921 }
915 922
...@@ -1306,6 +1313,9 @@ pop_top (header_t header, char *buffer, size_t buflen, ...@@ -1306,6 +1313,9 @@ pop_top (header_t header, char *buffer, size_t buflen,
1306 1313
1307 mpd = mpm->mpd; 1314 mpd = mpm->mpd;
1308 1315
1316 /* Busy ? */
1317 CHECK_BUSY (mpd->mbox, mpd, func, msg);
1318
1309 /* We start fresh then reset the sizes. */ 1319 /* We start fresh then reset the sizes. */
1310 if (mpd->state == POP_NO_STATE) 1320 if (mpd->state == POP_NO_STATE)
1311 mpm->header_size = 0; 1321 mpm->header_size = 0;
...@@ -1314,9 +1324,6 @@ pop_top (header_t header, char *buffer, size_t buflen, ...@@ -1314,9 +1324,6 @@ pop_top (header_t header, char *buffer, size_t buflen,
1314 if ((size_t)offset < mpm->header_size) 1324 if ((size_t)offset < mpm->header_size)
1315 return ESPIPE; 1325 return ESPIPE;
1316 1326
1317 /* Busy ? */
1318 CHECK_BUSY (mpd->mbox, mpd, func, msg);
1319
1320 /* Get the header. */ 1327 /* Get the header. */
1321 switch (mpd->state) 1328 switch (mpd->state)
1322 { 1329 {
...@@ -1408,17 +1415,17 @@ pop_header_read (header_t header, char *buffer, size_t buflen, off_t offset, ...@@ -1408,17 +1415,17 @@ pop_header_read (header_t header, char *buffer, size_t buflen, off_t offset,
1408 1415
1409 mpd = mpm->mpd; 1416 mpd = mpm->mpd;
1410 1417
1418 /* Busy ? */
1419 CHECK_BUSY (mpd->mbox, mpd, func, msg);
1420
1411 /* We start fresh then reset the sizes. */ 1421 /* We start fresh then reset the sizes. */
1412 if (mpd->state == POP_NO_STATE) 1422 if (mpd->state == POP_NO_STATE)
1413 mpm->header_size = 0; 1423 mpm->header_size = mpm->inbody = 0;
1414 1424
1415 /* Throw an error if trying to seek back. */ 1425 /* Throw an error if trying to seek back. */
1416 if ((size_t)offset < mpm->header_size) 1426 if ((size_t)offset < mpm->header_size)
1417 return ESPIPE; 1427 return ESPIPE;
1418 1428
1419 /* Busy ? */
1420 CHECK_BUSY (mpd->mbox, mpd, func, msg);
1421
1422 mpm->skip_header = 0; 1429 mpm->skip_header = 0;
1423 mpm->skip_body = 1; 1430 mpm->skip_body = 1;
1424 return pop_retr (mpm, buffer, buflen, offset, pnread); 1431 return pop_retr (mpm, buffer, buflen, offset, pnread);
...@@ -1441,17 +1448,17 @@ pop_body_read (stream_t is, char *buffer, size_t buflen, off_t offset, ...@@ -1441,17 +1448,17 @@ pop_body_read (stream_t is, char *buffer, size_t buflen, off_t offset,
1441 1448
1442 mpd = mpm->mpd; 1449 mpd = mpm->mpd;
1443 1450
1451 /* Busy ? */
1452 CHECK_BUSY (mpd->mbox, mpd, func, msg);
1453
1444 /* We start fresh then reset the sizes. */ 1454 /* We start fresh then reset the sizes. */
1445 if (mpd->state == POP_NO_STATE) 1455 if (mpd->state == POP_NO_STATE)
1446 mpm->body_size = 0; 1456 mpm->body_size = mpm->inbody = 0;
1447 1457
1448 /* Can not seek back this a stream socket. */ 1458 /* Can not seek back this a stream socket. */
1449 if ((size_t)offset < mpm->body_size) 1459 if ((size_t)offset < mpm->body_size)
1450 return ESPIPE; 1460 return ESPIPE;
1451 1461
1452 /* Busy ? */
1453 CHECK_BUSY (mpd->mbox, mpd, func, msg);
1454
1455 mpm->skip_header = 1; 1462 mpm->skip_header = 1;
1456 mpm->skip_body = 0; 1463 mpm->skip_body = 0;
1457 return pop_retr (mpm, buffer, buflen, offset, pnread); 1464 return pop_retr (mpm, buffer, buflen, offset, pnread);
...@@ -1472,17 +1479,17 @@ pop_message_read (stream_t is, char *buffer, size_t buflen, off_t offset, ...@@ -1472,17 +1479,17 @@ pop_message_read (stream_t is, char *buffer, size_t buflen, off_t offset,
1472 1479
1473 mpd = mpm->mpd; 1480 mpd = mpm->mpd;
1474 1481
1482 /* Busy ? */
1483 CHECK_BUSY (mpd->mbox, mpd, func, msg);
1484
1475 /* We start fresh then reset the sizes. */ 1485 /* We start fresh then reset the sizes. */
1476 if (mpd->state == POP_NO_STATE) 1486 if (mpd->state == POP_NO_STATE)
1477 mpm->header_size = mpm->body_size = 0; 1487 mpm->header_size = mpm->body_size = mpm->inbody = 0;
1478 1488
1479 /* Can not seek back this is a stream socket. */ 1489 /* Can not seek back this is a stream socket. */
1480 if ((size_t)offset < (mpm->body_size + mpm->header_size)) 1490 if ((size_t)offset < (mpm->body_size + mpm->header_size))
1481 return ESPIPE; 1491 return ESPIPE;
1482 1492
1483 /* Busy ? */
1484 CHECK_BUSY (mpd->mbox, mpd, func, msg);
1485
1486 mpm->skip_header = mpm->skip_body = 0; 1493 mpm->skip_header = mpm->skip_body = 0;
1487 return pop_retr (mpm, buffer, buflen, offset, pnread); 1494 return pop_retr (mpm, buffer, buflen, offset, pnread);
1488 } 1495 }
......
...@@ -102,8 +102,6 @@ stream_close (stream_t stream) ...@@ -102,8 +102,6 @@ stream_close (stream_t stream)
102 { 102 {
103 if (stream == NULL) 103 if (stream == NULL)
104 return EINVAL; 104 return EINVAL;
105 /* Make sure the writes were flush. */
106 stream_flush (stream);
107 stream->state = MU_STREAM_STATE_CLOSE; 105 stream->state = MU_STREAM_STATE_CLOSE;
108 /* Clear the buffer of any residue left. */ 106 /* Clear the buffer of any residue left. */
109 if (stream->rbuffer.base) 107 if (stream->rbuffer.base)
......