Commit efd8da5e efd8da5ebbdd6411f4d0869f14d934e5006e1372 by Alain Magloire

* mailbox/message.c (message_get_uid) : Add message_get_uid() for

the UID of the message (IMAP definition) and message_get_uidl() for
the POP3 definition.
* mailbox/attachment.c : Indentation fixes.
* mailbox/file_stream.c : Make sure that the FILE* is close before
opening.
* mailbox/folder_imap.c : Use strcasecmp() not strcmp().
* mailbox/mailbox.c : Added mailbox_uidnext() and mailbox_uidvalidity.
* mailbox/mapfile_stream.c : When munmap() failed we should check
against MAP_FAILED, not NULL.
* mailbox/mbx_imap.c : Implement imap_uidnext(), imap_uidvalidity()
imap_message_uid().
* mailbox/mbx_mbox.c : Implement mbox_uidnext(), mbox_uidvalidity()
mbox_message_uid().
* mailbox/mbx_mboxscan.c : Implement uidvalidity, it is save int the
header of the first message, "X-IMAPbase: 127673838 123", a la c-client.
Save UID, it is save in "X-UID".
* mailbox/mbx_pop.c : Implement pop_messages_recent(),
pop_message_unseen() and pop_uid().
* mailbox/trans_stream.c : Indentation fixes.
1 parent 0d961fe9
...@@ -31,6 +31,9 @@ ...@@ -31,6 +31,9 @@
31 #define MAX_HDR_LEN 256 31 #define MAX_HDR_LEN 256
32 #define BUF_SIZE 2048 32 #define BUF_SIZE 2048
33 33
34 /* FIXME: this should be in a public header. */
35 extern int message_attachment_filename __P ((message_t, const char **filename));
36
34 struct _msg_info { 37 struct _msg_info {
35 char *buf; 38 char *buf;
36 size_t nbytes; 39 size_t nbytes;
...@@ -174,7 +177,7 @@ static char *_header_get_param(char *field_body, const char *param, size_t *len) ...@@ -174,7 +177,7 @@ static char *_header_get_param(char *field_body, const char *param, size_t *len)
174 return NULL; 177 return NULL;
175 } 178 }
176 179
177 int message_attachment_filename(message_t msg, char **filename) 180 int message_attachment_filename(message_t msg, const char **filename)
178 { 181 {
179 char *pTmp, *fname = NULL; 182 char *pTmp, *fname = NULL;
180 header_t hdr; 183 header_t hdr;
...@@ -219,7 +222,8 @@ int message_save_attachment(message_t msg, const char *filename, void **data) ...@@ -219,7 +222,8 @@ int message_save_attachment(message_t msg, const char *filename, void **data)
219 size_t size; 222 size_t size;
220 size_t nbytes; 223 size_t nbytes;
221 header_t hdr; 224 header_t hdr;
222 const char *content_encoding, *fname = NULL; 225 char *content_encoding;
226 const char *fname = NULL;
223 227
224 if ( msg == NULL || filename == NULL) 228 if ( msg == NULL || filename == NULL)
225 return EINVAL; 229 return EINVAL;
...@@ -240,7 +244,7 @@ int message_save_attachment(message_t msg, const char *filename, void **data) ...@@ -240,7 +244,7 @@ int message_save_attachment(message_t msg, const char *filename, void **data)
240 ret = ENOMEM; 244 ret = ENOMEM;
241 header_get_value(hdr, "Content-Transfer-Encoding", content_encoding, size+1, 0); 245 header_get_value(hdr, "Content-Transfer-Encoding", content_encoding, size+1, 0);
242 } else 246 } else
243 content_encoding = "7bit"; 247 content_encoding = (char *)"7bit";
244 ret = decoder_stream_create(&info->ostream, fstream, content_encoding); 248 ret = decoder_stream_create(&info->ostream, fstream, content_encoding);
245 } 249 }
246 } 250 }
......
...@@ -227,6 +227,12 @@ _file_open (stream_t stream, const char *filename, int port, int flags) ...@@ -227,6 +227,12 @@ _file_open (stream_t stream, const char *filename, int port, int flags)
227 if (fs == NULL) 227 if (fs == NULL)
228 return EINVAL; 228 return EINVAL;
229 229
230 if (fs->file)
231 {
232 fclose (fs->file);
233 fs->file = NULL;
234 }
235
230 /* Map the flags to the system equivalent. */ 236 /* Map the flags to the system equivalent. */
231 if (flags & MU_STREAM_WRITE) 237 if (flags & MU_STREAM_WRITE)
232 flg = O_WRONLY; 238 flg = O_WRONLY;
......
...@@ -1155,35 +1155,35 @@ imap_flags (f_imap_t f_imap) ...@@ -1155,35 +1155,35 @@ imap_flags (f_imap_t f_imap)
1155 msg_imap_t msg_imap = f_imap->callback.msg_imap; 1155 msg_imap_t msg_imap = f_imap->callback.msg_imap;
1156 while ((flag = strtok_r (flags, " ()", &sp)) != NULL) 1156 while ((flag = strtok_r (flags, " ()", &sp)) != NULL)
1157 { 1157 {
1158 if (strcmp (flag, "\\Seen") == 0) 1158 if (strcasecmp (flag, "\\Seen") == 0)
1159 { 1159 {
1160 if (msg_imap) 1160 if (msg_imap)
1161 msg_imap->flags |= MU_ATTRIBUTE_SEEN; 1161 msg_imap->flags |= MU_ATTRIBUTE_SEEN;
1162 else 1162 else
1163 f_imap->flags |= MU_ATTRIBUTE_SEEN; 1163 f_imap->flags |= MU_ATTRIBUTE_SEEN;
1164 } 1164 }
1165 else if (strcmp (flag, "\\Answered") == 0) 1165 else if (strcasecmp (flag, "\\Answered") == 0)
1166 { 1166 {
1167 if (msg_imap) 1167 if (msg_imap)
1168 msg_imap->flags |= MU_ATTRIBUTE_ANSWERED; 1168 msg_imap->flags |= MU_ATTRIBUTE_ANSWERED;
1169 else 1169 else
1170 f_imap->flags |= MU_ATTRIBUTE_ANSWERED; 1170 f_imap->flags |= MU_ATTRIBUTE_ANSWERED;
1171 } 1171 }
1172 else if (strcmp (flag, "\\Flagged") == 0) 1172 else if (strcasecmp (flag, "\\Flagged") == 0)
1173 { 1173 {
1174 if (msg_imap) 1174 if (msg_imap)
1175 msg_imap->flags |= MU_ATTRIBUTE_FLAGGED; 1175 msg_imap->flags |= MU_ATTRIBUTE_FLAGGED;
1176 else 1176 else
1177 f_imap->flags |= MU_ATTRIBUTE_FLAGGED; 1177 f_imap->flags |= MU_ATTRIBUTE_FLAGGED;
1178 } 1178 }
1179 else if (strcmp (flag, "\\Deleted") == 0) 1179 else if (strcasecmp (flag, "\\Deleted") == 0)
1180 { 1180 {
1181 if (msg_imap) 1181 if (msg_imap)
1182 msg_imap->flags |= MU_ATTRIBUTE_DELETED; 1182 msg_imap->flags |= MU_ATTRIBUTE_DELETED;
1183 else 1183 else
1184 f_imap->flags |= MU_ATTRIBUTE_DELETED; 1184 f_imap->flags |= MU_ATTRIBUTE_DELETED;
1185 } 1185 }
1186 else if (strcmp (flag, "\\Draft") == 0) 1186 else if (strcasecmp (flag, "\\Draft") == 0)
1187 { 1187 {
1188 if (msg_imap) 1188 if (msg_imap)
1189 msg_imap->flags |= MU_ATTRIBUTE_DRAFT; 1189 msg_imap->flags |= MU_ATTRIBUTE_DRAFT;
...@@ -1256,8 +1256,7 @@ imap_fetch (f_imap_t f_imap) ...@@ -1256,8 +1256,7 @@ imap_fetch (f_imap_t f_imap)
1256 { 1256 {
1257 status = imap_flags (f_imap); 1257 status = imap_flags (f_imap);
1258 } 1258 }
1259 /* This the short form for BODYSTRUCTURE. */ 1259 else if (strcasecmp (command, "BODY") == 0)
1260 else if (strcmp (command, "BODY") == 0)
1261 { 1260 {
1262 status = imap_bodystructure (f_imap); 1261 status = imap_bodystructure (f_imap);
1263 } 1262 }
...@@ -1269,12 +1268,18 @@ imap_fetch (f_imap_t f_imap) ...@@ -1269,12 +1268,18 @@ imap_fetch (f_imap_t f_imap)
1269 { 1268 {
1270 command = strtok_r (NULL, " ()\n", &sp); 1269 command = strtok_r (NULL, " ()\n", &sp);
1271 if (f_imap->callback.msg_imap) 1270 if (f_imap->callback.msg_imap)
1272 f_imap->callback.msg_imap->message_size = strtol (command, NULL, 10); 1271 f_imap->callback.msg_imap->message_size = strtoul (command, NULL, 10);
1273 } 1272 }
1274 else if (strncmp (command, "BODY", 4) == 0) 1273 else if (strncmp (command, "BODY", 4) == 0)
1275 { 1274 {
1276 status = imap_string (f_imap); 1275 status = imap_string (f_imap);
1277 } 1276 }
1277 else if (strncmp (command, "UID", 3) == 0)
1278 {
1279 command = strtok_r (NULL, " ()\n", &sp);
1280 if (f_imap->callback.msg_imap)
1281 f_imap->callback.msg_imap->uid = strtoul (command, NULL, 10);
1282 }
1278 return status; 1283 return status;
1279 } 1284 }
1280 1285
...@@ -1483,7 +1488,7 @@ imap_parse (f_imap_t f_imap) ...@@ -1483,7 +1488,7 @@ imap_parse (f_imap_t f_imap)
1483 { 1488 {
1484 1489
1485 /* Is it a Status Response. */ 1490 /* Is it a Status Response. */
1486 if (strcmp (response, "OK") == 0) 1491 if (strcasecmp (response, "OK") == 0)
1487 { 1492 {
1488 /* Check for status response [code]. */ 1493 /* Check for status response [code]. */
1489 if (*remainder == '[') 1494 if (*remainder == '[')
...@@ -1496,13 +1501,14 @@ imap_parse (f_imap_t f_imap) ...@@ -1496,13 +1501,14 @@ imap_parse (f_imap_t f_imap)
1496 subtag = strtok_r (cruft, " ", &sp); 1501 subtag = strtok_r (cruft, " ", &sp);
1497 if (!subtag) subtag = empty; 1502 if (!subtag) subtag = empty;
1498 1503
1499 if (strcmp (subtag, "ALERT") == 0) 1504 if (strcasecmp (subtag, "ALERT") == 0)
1500 { 1505 {
1501 /* The human-readable text contains a special alert that 1506 /* The human-readable text contains a special alert that
1502 MUST be presented to the user in a fashion that calls 1507 MUST be presented to the user in a fashion that calls
1503 the user's attention to the message. */ 1508 the user's attention to the message. */
1509 fprintf (stderr, "ALERT: %s\n", (sp) ? sp : "");
1504 } 1510 }
1505 else if (strcmp (subtag, "BADCHARSET") == 0) 1511 else if (strcasecmp (subtag, "BADCHARSET") == 0)
1506 { 1512 {
1507 /* Optionally followed by a parenthesized list of 1513 /* Optionally followed by a parenthesized list of
1508 charsets. A SEARCH failed because the given charset 1514 charsets. A SEARCH failed because the given charset
...@@ -1510,7 +1516,7 @@ imap_parse (f_imap_t f_imap) ...@@ -1510,7 +1516,7 @@ imap_parse (f_imap_t f_imap)
1510 optional list of charsets is given, this lists the 1516 optional list of charsets is given, this lists the
1511 charsets that are supported by this implementation. */ 1517 charsets that are supported by this implementation. */
1512 } 1518 }
1513 else if (strcmp (subtag, "CAPABILITY") == 0) 1519 else if (strcasecmp (subtag, "CAPABILITY") == 0)
1514 { 1520 {
1515 /* Followed by a list of capabilities. This can appear 1521 /* Followed by a list of capabilities. This can appear
1516 in the initial OK or PREAUTH response to transmit an 1522 in the initial OK or PREAUTH response to transmit an
...@@ -1521,7 +1527,7 @@ imap_parse (f_imap_t f_imap) ...@@ -1521,7 +1527,7 @@ imap_parse (f_imap_t f_imap)
1521 free (f_imap->capa); 1527 free (f_imap->capa);
1522 f_imap->capa = strdup (cruft); 1528 f_imap->capa = strdup (cruft);
1523 } 1529 }
1524 else if (strcmp (subtag, "NEWNAME") == 0) 1530 else if (strcasecmp (subtag, "NEWNAME") == 0)
1525 { 1531 {
1526 /* Followed by a mailbox name and a new mailbox name. A 1532 /* Followed by a mailbox name and a new mailbox name. A
1527 SELECT or EXAMINE failed because the target mailbox 1533 SELECT or EXAMINE failed because the target mailbox
...@@ -1530,13 +1536,13 @@ imap_parse (f_imap_t f_imap) ...@@ -1530,13 +1536,13 @@ imap_parse (f_imap_t f_imap)
1530 operation can succeed if the SELECT or EXAMINE is 1536 operation can succeed if the SELECT or EXAMINE is
1531 reissued with the new mailbox name. */ 1537 reissued with the new mailbox name. */
1532 } 1538 }
1533 else if (strcmp (subtag, "PARSE") == 0) 1539 else if (strcasecmp (subtag, "PARSE") == 0)
1534 { 1540 {
1535 /* The human-readable text represents an error in 1541 /* The human-readable text represents an error in
1536 parsing the [RFC-822] header or [MIME-IMB] headers 1542 parsing the [RFC-822] header or [MIME-IMB] headers
1537 of a message in the mailbox. */ 1543 of a message in the mailbox. */
1538 } 1544 }
1539 else if (strcmp (subtag, "PERMANENTFLAGS") == 0) 1545 else if (strcasecmp (subtag, "PERMANENTFLAGS") == 0)
1540 { 1546 {
1541 /* Followed by a parenthesized list of flags, indicates 1547 /* Followed by a parenthesized list of flags, indicates
1542 which of the known flags that the client can change 1548 which of the known flags that the client can change
...@@ -1551,19 +1557,19 @@ imap_parse (f_imap_t f_imap) ...@@ -1551,19 +1557,19 @@ imap_parse (f_imap_t f_imap)
1551 that it is possible to create new keywords by 1557 that it is possible to create new keywords by
1552 attempting to store those flags in the mailbox. */ 1558 attempting to store those flags in the mailbox. */
1553 } 1559 }
1554 else if (strcmp (subtag, "READ-ONLY") == 0) 1560 else if (strcasecmp (subtag, "READ-ONLY") == 0)
1555 { 1561 {
1556 /* The mailbox is selected read-only, or its access 1562 /* The mailbox is selected read-only, or its access
1557 while selected has changed from read-write to 1563 while selected has changed from read-write to
1558 read-only. */ 1564 read-only. */
1559 } 1565 }
1560 else if (strcmp (subtag, "READ-WRITE") == 0) 1566 else if (strcasecmp (subtag, "READ-WRITE") == 0)
1561 { 1567 {
1562 /* The mailbox is selected read-write, or its access 1568 /* The mailbox is selected read-write, or its access
1563 while selected has changed from read-only to 1569 while selected has changed from read-only to
1564 read-write. */ 1570 read-write. */
1565 } 1571 }
1566 else if (strcmp (subtag, "TRYCREATE") == 0) 1572 else if (strcasecmp (subtag, "TRYCREATE") == 0)
1567 { 1573 {
1568 /* An APPEND or COPY attempt is failing because the 1574 /* An APPEND or COPY attempt is failing because the
1569 target mailbox does not exist (as opposed to some 1575 target mailbox does not exist (as opposed to some
...@@ -1571,13 +1577,15 @@ imap_parse (f_imap_t f_imap) ...@@ -1571,13 +1577,15 @@ imap_parse (f_imap_t f_imap)
1571 the operation can succeed if the mailbox is first 1577 the operation can succeed if the mailbox is first
1572 created by the CREATE command. */ 1578 created by the CREATE command. */
1573 } 1579 }
1574 else if (strcmp (subtag, "UIDNEXT") == 0) 1580 else if (strcasecmp (subtag, "UIDNEXT") == 0)
1575 { 1581 {
1576 /* Followed by a decimal number, indicates the next 1582 /* Followed by a decimal number, indicates the next
1577 unique identifier value. Refer to section 2.3.1.1 1583 unique identifier value. Refer to section 2.3.1.1
1578 for more information. */ 1584 for more information. */
1585 char *value = strtok_r (NULL, " ", &sp);
1586 f_imap->selected->uidnext = strtol (value, NULL, 10);
1579 } 1587 }
1580 else if (strcmp (subtag, "UIDVALIDITY") == 0) 1588 else if (strcasecmp (subtag, "UIDVALIDITY") == 0)
1581 { 1589 {
1582 /* Followed by a decimal number, indicates the unique 1590 /* Followed by a decimal number, indicates the unique
1583 identifier validity value. Refer to section 2.3.1.1 1591 identifier validity value. Refer to section 2.3.1.1
...@@ -1585,7 +1593,7 @@ imap_parse (f_imap_t f_imap) ...@@ -1585,7 +1593,7 @@ imap_parse (f_imap_t f_imap)
1585 char *value = strtok_r (NULL, " ", &sp); 1593 char *value = strtok_r (NULL, " ", &sp);
1586 f_imap->selected->uidvalidity = strtol (value, NULL, 10); 1594 f_imap->selected->uidvalidity = strtol (value, NULL, 10);
1587 } 1595 }
1588 else if (strcmp (subtag, "UNSEEN") == 0) 1596 else if (strcasecmp (subtag, "UNSEEN") == 0)
1589 { 1597 {
1590 /* Followed by a decimal number, indicates the number of 1598 /* Followed by a decimal number, indicates the number of
1591 the first message without the \Seen flag set. */ 1599 the first message without the \Seen flag set. */
...@@ -1608,66 +1616,66 @@ imap_parse (f_imap_t f_imap) ...@@ -1608,66 +1616,66 @@ imap_parse (f_imap_t f_imap)
1608 printf("Untagged OK: %s\n", remainder); 1616 printf("Untagged OK: %s\n", remainder);
1609 } 1617 }
1610 } 1618 }
1611 else if (strcmp (response, "NO") == 0) 1619 else if (strcasecmp (response, "NO") == 0)
1612 { 1620 {
1613 /* This does not mean failure but rather a strong warning. */ 1621 /* This does not mean failure but rather a strong warning. */
1614 printf ("Untagged NO: %s\n", remainder); 1622 printf ("Untagged NO: %s\n", remainder);
1615 } 1623 }
1616 else if (strcmp (response, "BAD") == 0) 1624 else if (strcasecmp (response, "BAD") == 0)
1617 { 1625 {
1618 /* We're dead, protocol/syntax error. */ 1626 /* We're dead, protocol/syntax error. */
1619 printf ("Untagged BAD: %s\n", remainder); 1627 printf ("Untagged BAD: %s\n", remainder);
1620 } 1628 }
1621 else if (strcmp (response, "PREAUTH") == 0) 1629 else if (strcasecmp (response, "PREAUTH") == 0)
1622 { 1630 {
1623 } 1631 }
1624 else if (strcmp (response, "BYE") == 0) 1632 else if (strcasecmp (response, "BYE") == 0)
1625 { 1633 {
1626 /* We should close the stream. This is not recoverable. */ 1634 /* We should close the stream. This is not recoverable. */
1627 done = 1; 1635 done = 1;
1628 f_imap->isopen = 0; 1636 f_imap->isopen = 0;
1629 stream_close (f_imap->folder->stream); 1637 stream_close (f_imap->folder->stream);
1630 } 1638 }
1631 else if (strcmp (response, "CAPABILITY") == 0) 1639 else if (strcasecmp (response, "CAPABILITY") == 0)
1632 { 1640 {
1633 if (f_imap->capa) 1641 if (f_imap->capa)
1634 free (f_imap->capa); 1642 free (f_imap->capa);
1635 f_imap->capa = strdup (remainder); 1643 f_imap->capa = strdup (remainder);
1636 } 1644 }
1637 else if (strcmp (remainder, "EXISTS") == 0) 1645 else if (strcasecmp (remainder, "EXISTS") == 0)
1638 { 1646 {
1639 f_imap->selected->messages_count = strtol (response, NULL, 10); 1647 f_imap->selected->messages_count = strtol (response, NULL, 10);
1640 } 1648 }
1641 else if (strcmp (remainder, "EXPUNGE") == 0) 1649 else if (strcasecmp (remainder, "EXPUNGE") == 0)
1642 { 1650 {
1643 } 1651 }
1644 else if (strncmp (remainder, "FETCH", 5) == 0) 1652 else if (strncasecmp (remainder, "FETCH", 5) == 0)
1645 { 1653 {
1646 status = imap_fetch (f_imap); 1654 status = imap_fetch (f_imap);
1647 if (status != 0) 1655 if (status != 0)
1648 break; 1656 break;
1649 } 1657 }
1650 else if (strcmp (response, "FLAGS") == 0) 1658 else if (strcasecmp (response, "FLAGS") == 0)
1651 { 1659 {
1652 /* Flags define on the mailbox not a message flags. */ 1660 /* Flags define on the mailbox not a message flags. */
1653 status = imap_flags (f_imap); 1661 status = imap_flags (f_imap);
1654 } 1662 }
1655 else if (strcmp (response, "LIST") == 0) 1663 else if (strcasecmp (response, "LIST") == 0)
1656 { 1664 {
1657 status = imap_list (f_imap); 1665 status = imap_list (f_imap);
1658 } 1666 }
1659 else if (strcmp (response, "LSUB") == 0) 1667 else if (strcasecmp (response, "LSUB") == 0)
1660 { 1668 {
1661 status = imap_list (f_imap); 1669 status = imap_list (f_imap);
1662 } 1670 }
1663 else if (strcmp (remainder, "RECENT") == 0) 1671 else if (strcasecmp (remainder, "RECENT") == 0)
1664 { 1672 {
1665 f_imap->selected->recent = strtol (response, NULL, 10); 1673 f_imap->selected->recent = strtol (response, NULL, 10);
1666 } 1674 }
1667 else if (strcmp (response, "SEARCH") == 0) 1675 else if (strcasecmp (response, "SEARCH") == 0)
1668 { 1676 {
1669 } 1677 }
1670 else if (strcmp (response, "STATUS") == 0) 1678 else if (strcasecmp (response, "STATUS") == 0)
1671 { 1679 {
1672 } 1680 }
1673 else 1681 else
...@@ -1686,12 +1694,12 @@ imap_parse (f_imap_t f_imap) ...@@ -1686,12 +1694,12 @@ imap_parse (f_imap_t f_imap)
1686 { 1694 {
1687 /* Every transaction ends with a tagged response. */ 1695 /* Every transaction ends with a tagged response. */
1688 done = 1; 1696 done = 1;
1689 if (strcmp (response, "OK") == 0) 1697 if (strcasecmp (response, "OK") == 0)
1690 { 1698 {
1691 } 1699 }
1692 else /* NO and BAD */ 1700 else /* NO and BAD */
1693 { 1701 {
1694 if (strncmp (remainder, "LOGIN", 5) == 0) 1702 if (strncasecmp (remainder, "LOGIN", 5) == 0)
1695 { 1703 {
1696 observable_t observable = NULL; 1704 observable_t observable = NULL;
1697 folder_get_observable (f_imap->folder, &observable); 1705 folder_get_observable (f_imap->folder, &observable);
......
...@@ -166,7 +166,8 @@ struct _m_imap ...@@ -166,7 +166,8 @@ struct _m_imap
166 msg_imap_t *imessages; 166 msg_imap_t *imessages;
167 size_t recent; 167 size_t recent;
168 size_t unseen; 168 size_t unseen;
169 size_t uidvalidity; 169 unsigned long uidvalidity;
170 size_t uidnext;
170 char *name; 171 char *name;
171 }; 172 };
172 173
...@@ -181,7 +182,7 @@ struct _msg_imap ...@@ -181,7 +182,7 @@ struct _msg_imap
181 msg_imap_t *parts; 182 msg_imap_t *parts;
182 msg_imap_t parent; 183 msg_imap_t parent;
183 int flags; 184 int flags;
184 char *uid; 185 size_t uid;
185 186
186 size_t message_size; 187 size_t message_size;
187 size_t message_lines; 188 size_t message_lines;
......
...@@ -69,8 +69,11 @@ struct _mailbox ...@@ -69,8 +69,11 @@ struct _mailbox
69 int (*_get_message) __P ((mailbox_t, size_t msgno, message_t *msg)); 69 int (*_get_message) __P ((mailbox_t, size_t msgno, message_t *msg));
70 int (*_append_message) __P ((mailbox_t, message_t msg)); 70 int (*_append_message) __P ((mailbox_t, message_t msg));
71 int (*_messages_count) __P ((mailbox_t, size_t *num)); 71 int (*_messages_count) __P ((mailbox_t, size_t *num));
72 int (*_unseen_count) __P ((mailbox_t, size_t *num)); 72 int (*_messages_recent) __P ((mailbox_t, size_t *num));
73 int (*_message_unseen) __P ((mailbox_t, size_t *num));
73 int (*_expunge) __P ((mailbox_t)); 74 int (*_expunge) __P ((mailbox_t));
75 int (*_uidvalidity) __P ((mailbox_t, unsigned long *num));
76 int (*_uidnext) __P ((mailbox_t, size_t *num));
74 77
75 int (*_scan) __P ((mailbox_t, size_t msgno, size_t *count)); 78 int (*_scan) __P ((mailbox_t, size_t msgno, size_t *count));
76 int (*_is_updated) __P ((mailbox_t)); 79 int (*_is_updated) __P ((mailbox_t));
......
1 /* GNU mailutils - a suite of utilities for electronic mail 1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3 3
4 This program is free software; you can redistribute it and/or modify 4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by 5 it under the terms of the GNU General Library Public License as published by
...@@ -65,7 +65,8 @@ struct _message ...@@ -65,7 +65,8 @@ struct _message
65 size_t hdr_buflen; 65 size_t hdr_buflen;
66 int hdr_done; 66 int hdr_done;
67 67
68 int (*_get_uid) __P ((message_t, char *, size_t, size_t *)); 68 int (*_get_uidl) __P ((message_t, char *, size_t, size_t *));
69 int (*_get_uid) __P ((message_t, size_t *));
69 int (*_get_num_parts) __P ((message_t, size_t *)); 70 int (*_get_num_parts) __P ((message_t, size_t *));
70 int (*_get_part) __P ((message_t, size_t, message_t *)); 71 int (*_get_part) __P ((message_t, size_t, message_t *));
71 int (*_is_multipart) __P ((message_t, int *)); 72 int (*_is_multipart) __P ((message_t, int *));
......
...@@ -220,11 +220,18 @@ mailbox_messages_count (mailbox_t mbox, size_t *num) ...@@ -220,11 +220,18 @@ mailbox_messages_count (mailbox_t mbox, size_t *num)
220 } 220 }
221 221
222 int 222 int
223 mailbox_unseen_count (mailbox_t mbox, size_t *num) 223 mailbox_messages_recent (mailbox_t mbox, size_t *num)
224 { 224 {
225 if (mbox && mbox->_unseen_count) 225 if (mbox == NULL || mbox->_messages_recent == NULL)
226 return mbox->_unseen_count (mbox, num); 226 return ENOSYS;
227 return mailbox_messages_count (mbox, num); 227 return mbox->_messages_recent (mbox, num);
228 }
229 int
230 mailbox_message_unseen (mailbox_t mbox, size_t *num)
231 {
232 if (mbox == NULL || mbox->_message_unseen == NULL)
233 return ENOSYS;
234 return mbox->_message_unseen (mbox, num);
228 } 235 }
229 236
230 int 237 int
...@@ -259,6 +266,22 @@ mailbox_size (mailbox_t mbox, off_t *psize) ...@@ -259,6 +266,22 @@ mailbox_size (mailbox_t mbox, off_t *psize)
259 return mbox->_size (mbox, psize); 266 return mbox->_size (mbox, psize);
260 } 267 }
261 268
269 int
270 mailbox_uidvalidity (mailbox_t mbox, unsigned long *pvalid)
271 {
272 if (mbox == NULL || mbox->_uidvalidity == NULL)
273 return 0;
274 return mbox->_uidvalidity (mbox, pvalid);
275 }
276
277 int
278 mailbox_uidnext (mailbox_t mbox, size_t *puidnext)
279 {
280 if (mbox == NULL || mbox->_uidnext == NULL)
281 return 0;
282 return mbox->_uidnext (mbox, puidnext);
283 }
284
262 /* locking */ 285 /* locking */
263 int 286 int
264 mailbox_set_locker (mailbox_t mbox, locker_t locker) 287 mailbox_set_locker (mailbox_t mbox, locker_t locker)
......
...@@ -48,7 +48,7 @@ _mapfile_destroy (stream_t stream) ...@@ -48,7 +48,7 @@ _mapfile_destroy (stream_t stream)
48 { 48 {
49 struct _mapfile_stream *mfs = stream_get_owner (stream); 49 struct _mapfile_stream *mfs = stream_get_owner (stream);
50 50
51 if (mfs && mfs->ptr) 51 if (mfs && mfs->ptr != MAP_FAILED)
52 { 52 {
53 munmap (mfs->ptr, mfs->size); 53 munmap (mfs->ptr, mfs->size);
54 close (mfs->fd); 54 close (mfs->fd);
...@@ -63,7 +63,7 @@ _mapfile_read (stream_t stream, char *optr, size_t osize, ...@@ -63,7 +63,7 @@ _mapfile_read (stream_t stream, char *optr, size_t osize,
63 struct _mapfile_stream *mfs = stream_get_owner (stream); 63 struct _mapfile_stream *mfs = stream_get_owner (stream);
64 size_t n; 64 size_t n;
65 65
66 if (mfs == NULL || mfs->ptr == NULL) 66 if (mfs == NULL || mfs->ptr == MAP_FAILED)
67 return EINVAL; 67 return EINVAL;
68 68
69 if (offset >= (off_t)mfs->size) 69 if (offset >= (off_t)mfs->size)
...@@ -89,7 +89,7 @@ _mapfile_readline (stream_t stream, char *optr, size_t osize, ...@@ -89,7 +89,7 @@ _mapfile_readline (stream_t stream, char *optr, size_t osize,
89 char *nl; 89 char *nl;
90 size_t n = 0; 90 size_t n = 0;
91 91
92 if (mfs == NULL || mfs->ptr == NULL) 92 if (mfs == NULL || mfs->ptr == MAP_FAILED)
93 return EINVAL; 93 return EINVAL;
94 /* Save space for the null byte. */ 94 /* Save space for the null byte. */
95 osize--; 95 osize--;
...@@ -116,7 +116,7 @@ _mapfile_write (stream_t stream, const char *iptr, size_t isize, ...@@ -116,7 +116,7 @@ _mapfile_write (stream_t stream, const char *iptr, size_t isize,
116 { 116 {
117 struct _mapfile_stream *mfs = stream_get_owner (stream); 117 struct _mapfile_stream *mfs = stream_get_owner (stream);
118 118
119 if (mfs == NULL || mfs->ptr == NULL) 119 if (mfs == NULL || mfs->ptr == MAP_FAILED)
120 return EINVAL; 120 return EINVAL;
121 121
122 if (! (mfs->flags & PROT_WRITE)) 122 if (! (mfs->flags & PROT_WRITE))
...@@ -155,7 +155,7 @@ static int ...@@ -155,7 +155,7 @@ static int
155 _mapfile_truncate (stream_t stream, off_t len) 155 _mapfile_truncate (stream_t stream, off_t len)
156 { 156 {
157 struct _mapfile_stream *mfs = stream_get_owner (stream); 157 struct _mapfile_stream *mfs = stream_get_owner (stream);
158 if (mfs == NULL || mfs->ptr == NULL) 158 if (mfs == NULL || mfs->ptr == MAP_FAILED)
159 return EINVAL; 159 return EINVAL;
160 /* Remap. */ 160 /* Remap. */
161 if (munmap (mfs->ptr, mfs->size) != 0) 161 if (munmap (mfs->ptr, mfs->size) != 0)
...@@ -185,7 +185,7 @@ _mapfile_size (stream_t stream, off_t *psize) ...@@ -185,7 +185,7 @@ _mapfile_size (stream_t stream, off_t *psize)
185 struct stat stbuf; 185 struct stat stbuf;
186 int err = 0; 186 int err = 0;
187 187
188 if (mfs == NULL || mfs->ptr == NULL) 188 if (mfs == NULL || mfs->ptr == MAP_FAILED)
189 return EINVAL; 189 return EINVAL;
190 msync (mfs->ptr, mfs->size, MS_SYNC); 190 msync (mfs->ptr, mfs->size, MS_SYNC);
191 if (fstat(mfs->fd, &stbuf) != 0) 191 if (fstat(mfs->fd, &stbuf) != 0)
...@@ -204,7 +204,7 @@ _mapfile_size (stream_t stream, off_t *psize) ...@@ -204,7 +204,7 @@ _mapfile_size (stream_t stream, off_t *psize)
204 } 204 }
205 if (err != 0) 205 if (err != 0)
206 { 206 {
207 mfs->ptr = NULL; 207 mfs->ptr = MAP_FAILED;
208 close (mfs->fd); 208 close (mfs->fd);
209 mfs->fd = -1; 209 mfs->fd = -1;
210 } 210 }
...@@ -241,13 +241,13 @@ _mapfile_close (stream_t stream) ...@@ -241,13 +241,13 @@ _mapfile_close (stream_t stream)
241 { 241 {
242 struct _mapfile_stream *mfs = stream_get_owner (stream); 242 struct _mapfile_stream *mfs = stream_get_owner (stream);
243 int err = 0; 243 int err = 0;
244 if (mfs && mfs->ptr) 244 if (mfs && mfs->ptr != MAP_FAILED)
245 { 245 {
246 if (munmap (mfs->ptr, mfs->size) != 0) 246 if (munmap (mfs->ptr, mfs->size) != 0)
247 err = errno; 247 err = errno;
248 if (close (mfs->fd) != 0) 248 if (close (mfs->fd) != 0)
249 err = errno; 249 err = errno;
250 mfs->ptr = NULL; 250 mfs->ptr = MAP_FAILED;
251 mfs->fd = -1; 251 mfs->fd = -1;
252 } 252 }
253 return err; 253 return err;
...@@ -265,6 +265,17 @@ _mapfile_open (stream_t stream, const char *filename, int port, int flags) ...@@ -265,6 +265,17 @@ _mapfile_open (stream_t stream, const char *filename, int port, int flags)
265 if (mfs == NULL) 265 if (mfs == NULL)
266 return EINVAL; 266 return EINVAL;
267 267
268 /* Close any previous file. */
269 if (mfs->ptr != MAP_FAILED)
270 {
271 munmap (mfs->ptr, mfs->size);
272 mfs->ptr = MAP_FAILED;
273 }
274 if (mfs->fd != -1)
275 {
276 close (mfs->fd);
277 mfs->fd = -1;
278 }
268 /* Map the flags to the system equivalent */ 279 /* Map the flags to the system equivalent */
269 if (flags & MU_STREAM_WRITE) 280 if (flags & MU_STREAM_WRITE)
270 { 281 {
...@@ -299,7 +310,7 @@ _mapfile_open (stream_t stream, const char *filename, int port, int flags) ...@@ -299,7 +310,7 @@ _mapfile_open (stream_t stream, const char *filename, int port, int flags)
299 { 310 {
300 int err = errno; 311 int err = errno;
301 close (mfs->fd); 312 close (mfs->fd);
302 mfs->ptr = NULL; 313 mfs->ptr = MAP_FAILED;
303 return err; 314 return err;
304 } 315 }
305 mfs->flags = mflag; 316 mfs->flags = mflag;
...@@ -325,6 +336,9 @@ mapfile_stream_create (stream_t *stream) ...@@ -325,6 +336,9 @@ mapfile_stream_create (stream_t *stream)
325 if (fs == NULL) 336 if (fs == NULL)
326 return ENOMEM; 337 return ENOMEM;
327 338
339 fs->fd = -1;
340 fs->ptr = MAP_FAILED;
341
328 ret = stream_create (stream, MU_STREAM_NO_CHECK, fs); 342 ret = stream_create (stream, MU_STREAM_NO_CHECK, fs);
329 if (ret != 0) 343 if (ret != 0)
330 { 344 {
......
...@@ -33,10 +33,13 @@ ...@@ -33,10 +33,13 @@
33 static void mailbox_imap_destroy (mailbox_t); 33 static void mailbox_imap_destroy (mailbox_t);
34 static int mailbox_imap_open (mailbox_t, int); 34 static int mailbox_imap_open (mailbox_t, int);
35 static int mailbox_imap_close (mailbox_t); 35 static int mailbox_imap_close (mailbox_t);
36 static int imap_uidvalidity (mailbox_t, unsigned long *);
37 static int imap_uidnext (mailbox_t, size_t *);
36 static int imap_expunge (mailbox_t); 38 static int imap_expunge (mailbox_t);
37 static int imap_get_message (mailbox_t, size_t, message_t *); 39 static int imap_get_message (mailbox_t, size_t, message_t *);
38 static int imap_messages_count (mailbox_t, size_t *); 40 static int imap_messages_count (mailbox_t, size_t *);
39 static int imap_unseen_count (mailbox_t, size_t *); 41 static int imap_messages_recent (mailbox_t, size_t *);
42 static int imap_message_unseen (mailbox_t, size_t *);
40 static int imap_scan (mailbox_t, size_t, size_t *); 43 static int imap_scan (mailbox_t, size_t, size_t *);
41 static int imap_is_updated (mailbox_t); 44 static int imap_is_updated (mailbox_t);
42 static int imap_append_message (mailbox_t, message_t); 45 static int imap_append_message (mailbox_t, message_t);
...@@ -47,7 +50,7 @@ static int imap_message_size (message_t, size_t *); ...@@ -47,7 +50,7 @@ static int imap_message_size (message_t, size_t *);
47 static int imap_message_lines (message_t, size_t *); 50 static int imap_message_lines (message_t, size_t *);
48 static int imap_message_fd (stream_t, int *); 51 static int imap_message_fd (stream_t, int *);
49 static int imap_message_read (stream_t , char *, size_t, off_t, size_t *); 52 static int imap_message_read (stream_t , char *, size_t, off_t, size_t *);
50 static int imap_message_uid (message_t, char *, size_t, size_t *); 53 static int imap_message_uid (message_t, size_t *);
51 54
52 /* Mime handling. */ 55 /* Mime handling. */
53 static int imap_is_multipart (message_t, int *); 56 static int imap_is_multipart (message_t, int *);
...@@ -66,7 +69,6 @@ static int imap_attr_unset_flags (attribute_t, int); ...@@ -66,7 +69,6 @@ static int imap_attr_unset_flags (attribute_t, int);
66 /* Header. */ 69 /* Header. */
67 static int imap_header_read (header_t, char*, size_t, off_t, size_t *); 70 static int imap_header_read (header_t, char*, size_t, off_t, size_t *);
68 static int imap_header_get_value (header_t, const char*, char *, size_t, size_t *); 71 static int imap_header_get_value (header_t, const char*, char *, size_t, size_t *);
69 static int imap_header_fd (stream_t, int *);
70 72
71 /* Body. */ 73 /* Body. */
72 static int imap_body_read (stream_t, char *, size_t, off_t, size_t *); 74 static int imap_body_read (stream_t, char *, size_t, off_t, size_t *);
...@@ -116,8 +118,11 @@ _mailbox_imap_init (mailbox_t mailbox) ...@@ -116,8 +118,11 @@ _mailbox_imap_init (mailbox_t mailbox)
116 mailbox->_get_message = imap_get_message; 118 mailbox->_get_message = imap_get_message;
117 mailbox->_append_message = imap_append_message; 119 mailbox->_append_message = imap_append_message;
118 mailbox->_messages_count = imap_messages_count; 120 mailbox->_messages_count = imap_messages_count;
119 mailbox->_unseen_count = imap_unseen_count; 121 mailbox->_messages_recent = imap_messages_recent;
122 mailbox->_message_unseen = imap_message_unseen;
120 mailbox->_expunge = imap_expunge; 123 mailbox->_expunge = imap_expunge;
124 mailbox->_uidvalidity = imap_uidvalidity;
125 mailbox->_uidnext = imap_uidnext;
121 126
122 mailbox->_scan = imap_scan; 127 mailbox->_scan = imap_scan;
123 mailbox->_is_updated = imap_is_updated; 128 mailbox->_is_updated = imap_is_updated;
...@@ -142,8 +147,6 @@ free_subparts (msg_imap_t msg_imap) ...@@ -142,8 +147,6 @@ free_subparts (msg_imap_t msg_imap)
142 147
143 if (msg_imap->message) 148 if (msg_imap->message)
144 message_destroy (&(msg_imap->message), msg_imap); 149 message_destroy (&(msg_imap->message), msg_imap);
145 if (msg_imap->uid)
146 free (msg_imap->uid);
147 if (msg_imap->parts) 150 if (msg_imap->parts)
148 free (msg_imap->parts); 151 free (msg_imap->parts);
149 free(msg_imap); 152 free(msg_imap);
...@@ -411,7 +414,7 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg) ...@@ -411,7 +414,7 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg)
411 message_set_get_num_parts (msg, imap_get_num_parts, msg_imap); 414 message_set_get_num_parts (msg, imap_get_num_parts, msg_imap);
412 message_set_get_part (msg, imap_get_part, msg_imap); 415 message_set_get_part (msg, imap_get_part, msg_imap);
413 416
414 /* Set the UIDL call on the message. */ 417 /* Set the UID on the message. */
415 message_set_uid (msg, imap_message_uid, msg_imap); 418 message_set_uid (msg, imap_message_uid, msg_imap);
416 419
417 *pmsg = msg; 420 *pmsg = msg;
...@@ -419,12 +422,37 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg) ...@@ -419,12 +422,37 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg)
419 } 422 }
420 423
421 static int 424 static int
422 imap_unseen_count (mailbox_t mailbox, size_t *pnum) 425 imap_message_unseen (mailbox_t mailbox, size_t *punseen)
426 {
427 m_imap_t m_imap = mailbox->data;
428 *punseen = m_imap->unseen;
429 return 0;
430 }
431
432 static int
433 imap_messages_recent (mailbox_t mailbox, size_t *precent)
423 { 434 {
424 m_imap_t m_imap = mailbox->data; 435 m_imap_t m_imap = mailbox->data;
425 *pnum = m_imap->unseen; 436 *precent = m_imap->recent;
426 return 0; 437 return 0;
427 } 438 }
439
440 static int
441 imap_uidvalidity (mailbox_t mailbox, unsigned long *puidvalidity)
442 {
443 m_imap_t m_imap = mailbox->data;
444 *puidvalidity = m_imap->uidvalidity;
445 return 0;
446 }
447
448 static int
449 imap_uidnext (mailbox_t mailbox, size_t *puidnext)
450 {
451 m_imap_t m_imap = mailbox->data;
452 *puidnext = m_imap->uidnext;
453 return 0;
454 }
455
428 /* There is no explicit call to get the message count. The count is send on 456 /* There is no explicit call to get the message count. The count is send on
429 a SELECT/EXAMINE command it is also sent async, meaning it will be piggy 457 a SELECT/EXAMINE command it is also sent async, meaning it will be piggy
430 back on other server response as an untag "EXIST" response. But we still 458 back on other server response as an untag "EXIST" response. But we still
...@@ -687,12 +715,37 @@ imap_message_size (message_t msg, size_t *psize) ...@@ -687,12 +715,37 @@ imap_message_size (message_t msg, size_t *psize)
687 } 715 }
688 716
689 static int 717 static int
690 imap_message_uid (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) 718 imap_message_uid (message_t msg, size_t *puid)
691 { 719 {
692 (void)msg; (void)buffer; (void)buflen; 720 msg_imap_t msg_imap = message_get_owner (msg);
693 if (pnwriten) 721 m_imap_t m_imap = msg_imap->m_imap;
694 *pnwriten = 0; 722 f_imap_t f_imap = m_imap->f_imap;
695 return ENOSYS; 723 int status;
724
725 if (puid)
726 return 0;
727 /* Select first. */
728 if (f_imap->state == IMAP_NO_STATE)
729 {
730 if (msg_imap->uid)
731 {
732 *puid = msg_imap->uid;
733 return 0;
734 }
735 status = imap_messages_count (m_imap->mailbox, NULL);
736 if (status != 0)
737 return status;
738 status = imap_writeline (f_imap, "g%d FETCH %d UID\r\n",
739 f_imap->seq++, msg_imap->num);
740 CHECK_ERROR (f_imap, status);
741 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer);
742 f_imap->state = IMAP_FETCH;
743 }
744 status = message_operation (f_imap, msg_imap, 0, 0, 0, 0);
745 if (status != 0)
746 return status;
747 *puid = msg_imap->uid;
748 return 0;
696 } 749 }
697 750
698 static int 751 static int
...@@ -1057,16 +1110,6 @@ imap_header_read (header_t header, char *buffer, size_t buflen, off_t offset, ...@@ -1057,16 +1110,6 @@ imap_header_read (header_t header, char *buffer, size_t buflen, off_t offset,
1057 plen); 1110 plen);
1058 } 1111 }
1059 1112
1060 static int
1061 imap_header_fd (stream_t stream, int *pfd)
1062 {
1063 header_t header = stream_get_owner (stream);
1064 message_t msg = header_get_owner (header);
1065 msg_imap_t msg_imap = message_get_owner (msg);
1066 return imap_get_fd (msg_imap, pfd);
1067 }
1068
1069
1070 /* Body. */ 1113 /* Body. */
1071 static int 1114 static int
1072 imap_body_size (body_t body, size_t *psize) 1115 imap_body_size (body_t body, size_t *psize)
......
...@@ -58,7 +58,8 @@ struct _mbox_data; ...@@ -58,7 +58,8 @@ struct _mbox_data;
58 typedef struct _mbox_data* mbox_data_t; 58 typedef struct _mbox_data* mbox_data_t;
59 typedef struct _mbox_message* mbox_message_t; 59 typedef struct _mbox_message* mbox_message_t;
60 60
61 #define HDRSIZE 8 61 /* These represent the header field-name that we are caching for speed. */
62 #define HDRSIZE 9
62 const char *fhdr_table[] = 63 const char *fhdr_table[] =
63 { 64 {
64 #define HFROM 0 65 #define HFROM 0
...@@ -71,38 +72,36 @@ const char *fhdr_table[] = ...@@ -71,38 +72,36 @@ const char *fhdr_table[] =
71 "Subject", 72 "Subject",
72 #define HDATE 4 73 #define HDATE 4
73 "Date", 74 "Date",
74 #define HX_UIDL 5 75 #define HX_IMAPBASE 5
76 "X-IMAPbase",
77 #define HX_UIDL 6
75 "X-UIDL", 78 "X-UIDL",
76 #define HX_UID 6 79 #define HX_UID 7
77 "X-UID", 80 "X-UID",
78 #define HCONTENT_TYPE 7 81 #define HCONTENT_TYPE 8
79 "Content-Type", 82 "Content-Type",
80 }; 83 };
81 /* Keep the position of where the header and body starts and ends. 84
82 old_flags is the "Status:" message. */ 85 /* Keep the positions of where the headers and bodies start and end.
86 attr_flags is the "Status:" message. */
83 struct _mbox_message 87 struct _mbox_message
84 { 88 {
85 /* Offset of the parts of the messages in the mailbox. */ 89 /* Offset of the parts of the messages in the mailbox. */
86 off_t header_from; 90 off_t header_from;
87 off_t header_from_end; 91 off_t header_from_end;
88 /* Little hack to make things easier when updating the attribute. */
89 off_t header_status;
90 off_t header_status_end;
91 off_t body; 92 off_t body;
92 off_t body_end; 93 off_t body_end;
93 94
94 /* Fast header retrieve, we save here the most common header. Reasons this 95 /* Fast header retrieve, we save here the most common header. This will
95 will speed the header search. The header are copied on write or if we 96 speed the header search. The header are copied when modified by the
96 the fast status failed. */ 97 header_t object, we should not worry about updating them. */
97 char *fhdr[HDRSIZE]; 98 char *fhdr[HDRSIZE];
98 99
99 /* The old_flags contains the definition of Header. */ 100 /* IMAP uid. */
100 int old_flags; 101 size_t uid;
101 /* The new_flags holds the attributes changes for the current session. We 102
102 use this so when expunging we can tell when an attribute been modified. 103 /* The attr_flags contains the "Status:" attribute */
103 This is a big help so we can jump to the first modify email for speed 104 int attr_flags;
104 in expunging (see mark dirty). */
105 int new_flags;
106 105
107 size_t header_lines; 106 size_t header_lines;
108 size_t body_lines; 107 size_t body_lines;
...@@ -125,6 +124,8 @@ struct _mbox_data ...@@ -125,6 +124,8 @@ struct _mbox_data
125 size_t messages_count; /* How many valid entry in umessages[]. */ 124 size_t messages_count; /* How many valid entry in umessages[]. */
126 stream_t stream; 125 stream_t stream;
127 off_t size; 126 off_t size;
127 unsigned long uidvalidity;
128 size_t uidnext;
128 char *name; 129 char *name;
129 130
130 /* The variables below are use to hold the state when appending messages. */ 131 /* The variables below are use to hold the state when appending messages. */
...@@ -132,7 +133,7 @@ struct _mbox_data ...@@ -132,7 +133,7 @@ struct _mbox_data
132 { 133 {
133 MBOX_NO_STATE = 0, 134 MBOX_NO_STATE = 0,
134 MBOX_STATE_APPEND_SENDER, MBOX_STATE_APPEND_DATE, MBOX_STATE_APPEND_HEADER, 135 MBOX_STATE_APPEND_SENDER, MBOX_STATE_APPEND_DATE, MBOX_STATE_APPEND_HEADER,
135 MBOX_STATE_APPEND_ATTRIBUTE, MBOX_STATE_APPEND_BODY, 136 MBOX_STATE_APPEND_ATTRIBUTE, MBOX_STATE_APPEND_UID, MBOX_STATE_APPEND_BODY,
136 MBOX_STATE_APPEND_MESSAGE 137 MBOX_STATE_APPEND_MESSAGE
137 } state ; 138 } state ;
138 char *sender; 139 char *sender;
...@@ -147,8 +148,11 @@ static int mbox_close __P ((mailbox_t)); ...@@ -147,8 +148,11 @@ static int mbox_close __P ((mailbox_t));
147 static int mbox_get_message __P ((mailbox_t, size_t, message_t *)); 148 static int mbox_get_message __P ((mailbox_t, size_t, message_t *));
148 static int mbox_append_message __P ((mailbox_t, message_t)); 149 static int mbox_append_message __P ((mailbox_t, message_t));
149 static int mbox_messages_count __P ((mailbox_t, size_t *)); 150 static int mbox_messages_count __P ((mailbox_t, size_t *));
150 static int mbox_unseen_count __P ((mailbox_t, size_t *)); 151 static int mbox_messages_recent __P ((mailbox_t, size_t *));
152 static int mbox_message_unseen __P ((mailbox_t, size_t *));
151 static int mbox_expunge __P ((mailbox_t)); 153 static int mbox_expunge __P ((mailbox_t));
154 static int mbox_uidvalidity __P ((mailbox_t, unsigned long *));
155 static int mbox_uidnext __P ((mailbox_t, size_t *));
152 static int mbox_scan __P ((mailbox_t, size_t, size_t *)); 156 static int mbox_scan __P ((mailbox_t, size_t, size_t *));
153 static int mbox_is_updated __P ((mailbox_t)); 157 static int mbox_is_updated __P ((mailbox_t));
154 static int mbox_size __P ((mailbox_t, off_t *)); 158 static int mbox_size __P ((mailbox_t, off_t *));
...@@ -156,7 +160,8 @@ static int mbox_size __P ((mailbox_t, off_t *)); ...@@ -156,7 +160,8 @@ static int mbox_size __P ((mailbox_t, off_t *));
156 /* private stuff */ 160 /* private stuff */
157 static int mbox_scan0 __P ((mailbox_t, size_t, size_t *, int)); 161 static int mbox_scan0 __P ((mailbox_t, size_t, size_t *, int));
158 static int mbox_append_message0 __P ((mailbox_t, message_t, off_t *, 162 static int mbox_append_message0 __P ((mailbox_t, message_t, off_t *,
159 int)); 163 int, int));
164 static int mbox_message_uid __P ((message_t, size_t *));
160 static int mbox_header_fill __P ((header_t, char *, size_t, off_t, 165 static int mbox_header_fill __P ((header_t, char *, size_t, off_t,
161 size_t *)); 166 size_t *));
162 static int mbox_get_header_readstream __P ((message_t, char *, size_t, off_t, 167 static int mbox_get_header_readstream __P ((message_t, char *, size_t, off_t,
...@@ -212,7 +217,7 @@ _mailbox_mbox_init (mailbox_t mailbox) ...@@ -212,7 +217,7 @@ _mailbox_mbox_init (mailbox_t mailbox)
212 for example if we receive: "mbox:///var/mail/alain" the mailbox name 217 for example if we receive: "mbox:///var/mail/alain" the mailbox name
213 will be "///var/mail/alain", we let open() do the right thing. 218 will be "///var/mail/alain", we let open() do the right thing.
214 So it will let things like this "mbox://390/var/mail/alain" where 219 So it will let things like this "mbox://390/var/mail/alain" where
215 "//390/var/mail/alain" _is_ the filename, pass correctely. */ 220 the "//" _is_ part of the filename, pass correctely. */
216 url_get_path (mailbox->url, NULL, 0, &name_len); 221 url_get_path (mailbox->url, NULL, 0, &name_len);
217 mud->name = calloc (name_len + 1, sizeof (char)); 222 mud->name = calloc (name_len + 1, sizeof (char));
218 if (mud->name == NULL) 223 if (mud->name == NULL)
...@@ -225,7 +230,7 @@ _mailbox_mbox_init (mailbox_t mailbox) ...@@ -225,7 +230,7 @@ _mailbox_mbox_init (mailbox_t mailbox)
225 230
226 mud->state = MBOX_NO_STATE; 231 mud->state = MBOX_NO_STATE;
227 232
228 /* Overloading the default. */ 233 /* Overloading the defaults. */
229 mailbox->_destroy = mbox_destroy; 234 mailbox->_destroy = mbox_destroy;
230 235
231 mailbox->_open = mbox_open; 236 mailbox->_open = mbox_open;
...@@ -235,8 +240,11 @@ _mailbox_mbox_init (mailbox_t mailbox) ...@@ -235,8 +240,11 @@ _mailbox_mbox_init (mailbox_t mailbox)
235 mailbox->_get_message = mbox_get_message; 240 mailbox->_get_message = mbox_get_message;
236 mailbox->_append_message = mbox_append_message; 241 mailbox->_append_message = mbox_append_message;
237 mailbox->_messages_count = mbox_messages_count; 242 mailbox->_messages_count = mbox_messages_count;
238 mailbox->_unseen_count = mbox_unseen_count; 243 mailbox->_messages_recent = mbox_messages_recent;
244 mailbox->_message_unseen = mbox_message_unseen;
239 mailbox->_expunge = mbox_expunge; 245 mailbox->_expunge = mbox_expunge;
246 mailbox->_uidvalidity = mbox_uidvalidity;
247 mailbox->_uidnext = mbox_uidnext;
240 248
241 mailbox->_scan = mbox_scan; 249 mailbox->_scan = mbox_scan;
242 mailbox->_is_updated = mbox_is_updated; 250 mailbox->_is_updated = mbox_is_updated;
...@@ -281,7 +289,8 @@ mbox_destroy (mailbox_t mailbox) ...@@ -281,7 +289,8 @@ mbox_destroy (mailbox_t mailbox)
281 } 289 }
282 } 290 }
283 291
284 /* Open the file. */ 292 /* Open the file. For MU_STREAM_READ, the code tries mmap() first and fall
293 back to normal file. */
285 static int 294 static int
286 mbox_open (mailbox_t mailbox, int flags) 295 mbox_open (mailbox_t mailbox, int flags)
287 { 296 {
...@@ -296,8 +305,6 @@ mbox_open (mailbox_t mailbox, int flags) ...@@ -296,8 +305,6 @@ mbox_open (mailbox_t mailbox, int flags)
296 /* Get a stream. */ 305 /* Get a stream. */
297 if (mailbox->stream == NULL) 306 if (mailbox->stream == NULL)
298 { 307 {
299 /* FIXME: for small mbox we should try to mmap (). */
300
301 /* We do not try to mmap for CREAT or APPEND, it is not supported. */ 308 /* We do not try to mmap for CREAT or APPEND, it is not supported. */
302 status = (flags & MU_STREAM_CREAT) 309 status = (flags & MU_STREAM_CREAT)
303 || (mailbox->flags & MU_STREAM_APPEND); 310 || (mailbox->flags & MU_STREAM_APPEND);
...@@ -393,7 +400,7 @@ mbox_close (mailbox_t mailbox) ...@@ -393,7 +400,7 @@ mbox_close (mailbox_t mailbox)
393 return stream_close (mailbox->stream); 400 return stream_close (mailbox->stream);
394 } 401 }
395 402
396 /* Mailbox Parsing. */ 403 /* Mailbox Parsing. Routing was way to ugly to put here. */
397 #include "mbx_mboxscan.c" 404 #include "mbx_mboxscan.c"
398 405
399 static int 406 static int
...@@ -404,7 +411,6 @@ mbox_scan (mailbox_t mailbox, size_t msgno, size_t *pcount) ...@@ -404,7 +411,6 @@ mbox_scan (mailbox_t mailbox, size_t msgno, size_t *pcount)
404 return mbox_scan0 (mailbox, msgno, pcount, 1); 411 return mbox_scan0 (mailbox, msgno, pcount, 1);
405 } 412 }
406 413
407
408 /* FIXME: How to handle a shrink ? meaning, the &^$^@%#@^& user start two 414 /* FIXME: How to handle a shrink ? meaning, the &^$^@%#@^& user start two
409 browsers and deleted emails in one. My views is that we should scream 415 browsers and deleted emails in one. My views is that we should scream
410 bloody murder and hunt them with a machette. But for now just play dumb, 416 bloody murder and hunt them with a machette. But for now just play dumb,
...@@ -420,7 +426,9 @@ mbox_is_updated (mailbox_t mailbox) ...@@ -420,7 +426,9 @@ mbox_is_updated (mailbox_t mailbox)
420 { 426 {
421 observable_notify (mailbox->observable, MU_EVT_MAILBOX_CORRUPT); 427 observable_notify (mailbox->observable, MU_EVT_MAILBOX_CORRUPT);
422 /* And be verbose. */ 428 /* And be verbose. */
423 fprintf (stderr, "Mailbox corrupted, shrink size\n"); 429 fprintf (stderr, "Mailbox corrupted, shrank size\n");
430 /* FIXME: I should crash. */
431 return 1;
424 } 432 }
425 return (mud->size == size); 433 return (mud->size == size);
426 } 434 }
...@@ -473,8 +481,8 @@ mbox_tmpfile (mailbox_t mailbox, char **pbox) ...@@ -473,8 +481,8 @@ mbox_tmpfile (mailbox_t mailbox, char **pbox)
473 481
474 /* For the expunge bits we took a very cautionnary approach, meaning 482 /* For the expunge bits we took a very cautionnary approach, meaning
475 we create a temporary mailbox in the tmpdir copy all the message not mark 483 we create a temporary mailbox in the tmpdir copy all the message not mark
476 deleted(Actually we copy all the message that may have been modified, we 484 deleted(Actually we copy all the message that may have been modified
477 do not have(yet) an api call to tell whether a message was modified) 485 i.e new header values set; UIDL or UID or etc ....
478 and skip the deleted ones, truncate the real mailbox to the desired size 486 and skip the deleted ones, truncate the real mailbox to the desired size
479 and overwrite with the tmp mailbox. The approach to do everyting 487 and overwrite with the tmp mailbox. The approach to do everyting
480 in core is tempting but require 488 in core is tempting but require
...@@ -485,7 +493,7 @@ mbox_tmpfile (mailbox_t mailbox, char **pbox) ...@@ -485,7 +493,7 @@ mbox_tmpfile (mailbox_t mailbox, char **pbox)
485 a new message while your expunging etc ... 493 a new message while your expunging etc ...
486 The real downside to the approach we take is that when things go wrong 494 The real downside to the approach we take is that when things go wrong
487 the temporary file may be left in /tmp, which is not all that bad 495 the temporary file may be left in /tmp, which is not all that bad
488 because at least, we have something to recuparate when failure. */ 496 because at least, we have something to recuperate when failure. */
489 static int 497 static int
490 mbox_expunge (mailbox_t mailbox) 498 mbox_expunge (mailbox_t mailbox)
491 { 499 {
...@@ -494,11 +502,12 @@ mbox_expunge (mailbox_t mailbox) ...@@ -494,11 +502,12 @@ mbox_expunge (mailbox_t mailbox)
494 int status = 0; 502 int status = 0;
495 sigset_t signalset; 503 sigset_t signalset;
496 int tempfile; 504 int tempfile;
497 size_t i, j, dirty; 505 size_t i, j, dirty; /* dirty will indicate the first modified message. */
498 off_t marker = 0; 506 off_t marker = 0; /* marker will be the position to truncate. */
499 off_t total = 0; 507 off_t total = 0;
500 char *tmpmboxname = NULL; 508 char *tmpmboxname = NULL;
501 mailbox_t tmpmailbox = NULL; 509 mailbox_t tmpmailbox = NULL;
510 size_t save_imapbase = 0; /* uidvalidity is save in the first message. */
502 #ifdef WITH_PTHREAD 511 #ifdef WITH_PTHREAD
503 int state; 512 int state;
504 #endif 513 #endif
...@@ -512,53 +521,43 @@ mbox_expunge (mailbox_t mailbox) ...@@ -512,53 +521,43 @@ mbox_expunge (mailbox_t mailbox)
512 if (mud->messages_count == 0) 521 if (mud->messages_count == 0)
513 return 0; 522 return 0;
514 523
515 /* Mark dirty the first mum(concrete message) with a message pointer. */ 524 /* Find the first dirty(modified) message. */
516 /* FIXME: This is not right, the way to really know if a message is modified
517 is by changing the API, we should have an message_is_modified (). */
518 for (dirty = 0; dirty < mud->messages_count; dirty++) 525 for (dirty = 0; dirty < mud->messages_count; dirty++)
519 { 526 {
520 mum = mud->umessages[dirty]; 527 mum = mud->umessages[dirty];
521 #if 0
522 /* No, cheking if the attribute was changed is not enough, for example
523 They may have modified a header, say adding the X-UIDL field. Those
524 changes are not save yet but still in memory part of the header blurb.
525 So unless we have a message_is_modified() call we should assume that
526 the message was modified. */
527 if (mum->new_flags &&
528 ! ATTRIBUTE_IS_EQUAL (mum->old_flags, mum->new_flags))
529 break;
530 #else
531 /* Message may have been tampered, break here. */ 528 /* Message may have been tampered, break here. */
532 if (mum->message && message_is_modified (mum->message)) 529 if ((mum->attr_flags & MU_ATTRIBUTE_MODIFIED) ||
530 (mum->message && message_is_modified (mum->message)))
533 break; 531 break;
534 #endif
535 } 532 }
536 533
537 /* Did something change ? */ 534 /* Did something change ? */
538 if (dirty == mud->messages_count) 535 if (dirty == mud->messages_count)
539 return 0; /* Nothing change, bail out. */ 536 return 0; /* Nothing change, bail out. */
540 537
538 /* Create a temporary file. */
539 tempfile = mbox_tmpfile (mailbox, &tmpmboxname);
540 if (tempfile == -1)
541 {
542 if (tmpmboxname)
543 free (tmpmboxname);
544 fprintf (stderr, "Failed to create temporary file when expunging.\n");
545 return errno;
546 }
547
541 /* This is redundant, we go to the loop again. But it's more secure here 548 /* This is redundant, we go to the loop again. But it's more secure here
542 since we don't want to be disturb when expunging. Destroy all the 549 since we don't want to be disturb when expunging. Destroy all the
543 messages mark for deletion. */ 550 messages mark for deletion. */
544 for (j = 0; j < mud->messages_count; j++) 551 for (j = 0; j < mud->messages_count; j++)
545 { 552 {
546 mum = mud->umessages[j]; 553 mum = mud->umessages[j];
547 if (mum && mum->message && mum->new_flags && 554 if (mum && mum->message && ATTRIBUTE_IS_DELETED (mum->attr_flags))
548 ATTRIBUTE_IS_DELETED (mum->new_flags))
549 message_destroy (&(mum->message), mum); 555 message_destroy (&(mum->message), mum);
550 } 556 }
551 557
552 /* Create a temporary file. */ 558 /* Create temporary mailbox_t. */
553 tempfile = mbox_tmpfile (mailbox, &tmpmboxname);
554 if (tempfile == -1)
555 {
556 free (tmpmboxname);
557 fprintf (stderr, "Failed to create temporary file when expunging.\n");
558 return errno;
559 }
560 else
561 { 559 {
560 mbox_data_t tmp_mud;
562 char *m = alloca (5 + strlen (tmpmboxname) + 1); 561 char *m = alloca (5 + strlen (tmpmboxname) + 1);
563 /* Try via the mbox: protocol. */ 562 /* Try via the mbox: protocol. */
564 sprintf (m, "mbox:%s", tmpmboxname); 563 sprintf (m, "mbox:%s", tmpmboxname);
...@@ -578,7 +577,8 @@ mbox_expunge (mailbox_t mailbox) ...@@ -578,7 +577,8 @@ mbox_expunge (mailbox_t mailbox)
578 } 577 }
579 } 578 }
580 579
581 /* Must be flag create if not the open will try to mmap() the file. */ 580 /* Must be flag CREATE if not the mailbox_open will try to mmap()
581 the file. */
582 status = mailbox_open (tmpmailbox, MU_STREAM_CREAT | MU_STREAM_RDWR); 582 status = mailbox_open (tmpmailbox, MU_STREAM_CREAT | MU_STREAM_RDWR);
583 if (status != 0) 583 if (status != 0)
584 { 584 {
...@@ -588,6 +588,10 @@ mbox_expunge (mailbox_t mailbox) ...@@ -588,6 +588,10 @@ mbox_expunge (mailbox_t mailbox)
588 return status; 588 return status;
589 } 589 }
590 close (tempfile); /* This one is useless the mailbox have its own. */ 590 close (tempfile); /* This one is useless the mailbox have its own. */
591 tmp_mud = tmpmailbox->data;
592 /* May need when appending. */
593 tmp_mud->uidvalidity = mud->uidvalidity;
594 tmp_mud->uidnext = mud->uidnext;
591 } 595 }
592 596
593 /* Get the File lock. */ 597 /* Get the File lock. */
...@@ -617,18 +621,26 @@ mbox_expunge (mailbox_t mailbox) ...@@ -617,18 +621,26 @@ mbox_expunge (mailbox_t mailbox)
617 marker = mud->umessages[dirty]->header_from; 621 marker = mud->umessages[dirty]->header_from;
618 total = 0; 622 total = 0;
619 623
620 /* Copy to tempfile emails not mark deleted. */ 624 /* Copy to the temporary mailbox emails not mark deleted. */
621 for (i = dirty; i < mud->messages_count; i++) 625 for (i = dirty; i < mud->messages_count; i++)
622 { 626 {
623 mum = mud->umessages[i]; 627 mum = mud->umessages[i];
624 628
625 /* Skip it, if mark for deletion. */ 629 /* Skip it, if mark for deletion. */
626 if (ATTRIBUTE_IS_DELETED (mum->new_flags)) 630 if (ATTRIBUTE_IS_DELETED (mum->attr_flags))
631 {
632 /* We save the uidvalidity in the first message, if it is being
633 deleted we need to the header to the first available(non-deleted)
634 message. */
635 if (i == 0)
636 save_imapbase = i + 1;
627 continue; 637 continue;
638 }
628 639
629 if (mum->message) 640 if (mum->message)
630 { 641 {
631 status = mbox_append_message0 (tmpmailbox, mum->message, &total, 1); 642 status = mbox_append_message0 (tmpmailbox, mum->message,
643 &total, 1, (i == save_imapbase));
632 if (status != 0) 644 if (status != 0)
633 { 645 {
634 fprintf (stderr, "Error expunge:%d: %s", __LINE__, 646 fprintf (stderr, "Error expunge:%d: %s", __LINE__,
...@@ -672,9 +684,8 @@ mbox_expunge (mailbox_t mailbox) ...@@ -672,9 +684,8 @@ mbox_expunge (mailbox_t mailbox)
672 } /* for (;;) */ 684 } /* for (;;) */
673 685
674 /* Caution: before ftruncate()ing the file see 686 /* Caution: before ftruncate()ing the file see
675 - if we've receive new mails. 687 - if we've receive new mails. Some programs may not respect the lock,
676 Some programs may not respect the lock, or the lock was held for too 688 or the lock was held for too long.
677 long.
678 - The mailbox may not have been properly updated before expunging. */ 689 - The mailbox may not have been properly updated before expunging. */
679 { 690 {
680 off_t size = 0; 691 off_t size = 0;
...@@ -740,7 +751,8 @@ mbox_expunge (mailbox_t mailbox) ...@@ -740,7 +751,8 @@ mbox_expunge (mailbox_t mailbox)
740 status = stream_truncate (mailbox->stream, total + marker); 751 status = stream_truncate (mailbox->stream, total + marker);
741 if (status != 0) 752 if (status != 0)
742 { 753 {
743 fprintf (stderr, "Error expunging:%d: %s\n", __LINE__, strerror (status)); 754 fprintf (stderr, "Error expunging:%d: %s\n", __LINE__,
755 strerror (status));
744 goto bailout; 756 goto bailout;
745 } 757 }
746 758
...@@ -771,7 +783,7 @@ mbox_expunge (mailbox_t mailbox) ...@@ -771,7 +783,7 @@ mbox_expunge (mailbox_t mailbox)
771 /* Clear all the references, any attach messages been already 783 /* Clear all the references, any attach messages been already
772 destroy above. */ 784 destroy above. */
773 mum = mud->umessages[j]; 785 mum = mud->umessages[j];
774 if (mum->new_flags && ATTRIBUTE_IS_DELETED (mum->new_flags)) 786 if (ATTRIBUTE_IS_DELETED (mum->attr_flags))
775 { 787 {
776 if ((j + 1) <= dlast) 788 if ((j + 1) <= dlast)
777 { 789 {
...@@ -780,13 +792,13 @@ mbox_expunge (mailbox_t mailbox) ...@@ -780,13 +792,13 @@ mbox_expunge (mailbox_t mailbox)
780 memmove (mud->umessages + j, mud->umessages + j + 1, 792 memmove (mud->umessages + j, mud->umessages + j + 1,
781 (dlast - j) * sizeof (mum)); 793 (dlast - j) * sizeof (mum));
782 //mum->header_from = mum->header_from_end = 0; 794 //mum->header_from = mum->header_from_end = 0;
783 //mum->header_status = mum->header_status_end = 0;
784 //mum->body = mum->body_end = 0; 795 //mum->body = mum->body_end = 0;
785 //mum->header_lines = mum->body_lines = 0; 796 //mum->header_lines = mum->body_lines = 0;
786 for (i = 0; i < HDRSIZE; i++) 797 for (i = 0; i < HDRSIZE; i++)
787 if (mum->fhdr[i]) 798 if (mum->fhdr[i])
788 { 799 {
789 free (mum->fhdr[i]); 800 free (mum->fhdr[i]);
801 mum->fhdr[i] = NULL;
790 } 802 }
791 memset (mum, 0, sizeof (*mum)); 803 memset (mum, 0, sizeof (*mum));
792 /* We are not free()ing the useless mum, but instead 804 /* We are not free()ing the useless mum, but instead
...@@ -803,7 +815,6 @@ mbox_expunge (mailbox_t mailbox) ...@@ -803,7 +815,6 @@ mbox_expunge (mailbox_t mailbox)
803 } 815 }
804 } 816 }
805 mum->header_from = mum->header_from_end = 0; 817 mum->header_from = mum->header_from_end = 0;
806 mum->header_status = mum->header_status_end = 0;
807 mum->body = mum->body_end = 0; 818 mum->body = mum->body_end = 0;
808 mum->header_lines = mum->body_lines = 0; 819 mum->header_lines = mum->body_lines = 0;
809 } 820 }
...@@ -816,6 +827,15 @@ mbox_expunge (mailbox_t mailbox) ...@@ -816,6 +827,15 @@ mbox_expunge (mailbox_t mailbox)
816 } 827 }
817 828
818 static int 829 static int
830 mbox_message_uid (message_t msg, size_t *puid)
831 {
832 mbox_message_t mum = message_get_owner (msg);
833 if (puid)
834 *puid = mum->uid;
835 return 0;
836 }
837
838 static int
819 mbox_get_body_fd (stream_t is, int *pfd) 839 mbox_get_body_fd (stream_t is, int *pfd)
820 { 840 {
821 body_t body = stream_get_owner (is); 841 body_t body = stream_get_owner (is);
...@@ -843,7 +863,7 @@ mbox_get_attr_flags (attribute_t attr, int *pflags) ...@@ -843,7 +863,7 @@ mbox_get_attr_flags (attribute_t attr, int *pflags)
843 if (mum == NULL) 863 if (mum == NULL)
844 return EINVAL; 864 return EINVAL;
845 if (pflags) 865 if (pflags)
846 *pflags = mum->new_flags; 866 *pflags = mum->attr_flags;
847 return 0; 867 return 0;
848 } 868 }
849 869
...@@ -855,7 +875,7 @@ mbox_set_attr_flags (attribute_t attr, int flags) ...@@ -855,7 +875,7 @@ mbox_set_attr_flags (attribute_t attr, int flags)
855 875
856 if (mum == NULL) 876 if (mum == NULL)
857 return EINVAL; 877 return EINVAL;
858 mum->new_flags |= flags; 878 mum->attr_flags |= flags;
859 return 0; 879 return 0;
860 } 880 }
861 881
...@@ -867,7 +887,7 @@ mbox_unset_attr_flags (attribute_t attr, int flags) ...@@ -867,7 +887,7 @@ mbox_unset_attr_flags (attribute_t attr, int flags)
867 887
868 if (mum == NULL) 888 if (mum == NULL)
869 return EINVAL; 889 return EINVAL;
870 mum->new_flags &= ~flags; 890 mum->attr_flags &= ~flags;
871 return 0; 891 return 0;
872 } 892 }
873 893
...@@ -920,8 +940,8 @@ mbox_body_readstream (stream_t is, char *buffer, size_t buflen, ...@@ -920,8 +940,8 @@ mbox_body_readstream (stream_t is, char *buffer, size_t buflen,
920 { 940 {
921 status = stream_readline (mum->stream, buffer, buflen, 941 status = stream_readline (mum->stream, buffer, buflen,
922 mum->body + off, &nread); 942 mum->body + off, &nread);
923 /* This mean we went pass the message boundary, thechnically it 943 /* This mean we went pass the message boundary, technically it
924 should not be sine we are reading by line, but just in case 944 should not be since we are reading by line, but just in case
925 truncate the string. */ 945 truncate the string. */
926 if (nread > (size_t)ln) 946 if (nread > (size_t)ln)
927 { 947 {
...@@ -952,6 +972,18 @@ mbox_header_fill (header_t header, char *buffer, size_t len, ...@@ -952,6 +972,18 @@ mbox_header_fill (header_t header, char *buffer, size_t len,
952 off_t off, size_t *pnread) 972 off_t off, size_t *pnread)
953 { 973 {
954 message_t msg = header_get_owner (header); 974 message_t msg = header_get_owner (header);
975 mbox_message_t mum = message_get_owner (msg);
976 size_t j;
977 /* Since we are filling the header there is no need for the cache headers
978 discard them. */
979 for (j = 0; j < HDRSIZE; j++)
980 {
981 if (mum->fhdr[j])
982 {
983 free (mum->fhdr[j]);
984 mum->fhdr[j] = NULL;
985 }
986 }
955 return mbox_get_header_readstream (msg, buffer, len, off, pnread, 0); 987 return mbox_get_header_readstream (msg, buffer, len, off, pnread, 0);
956 } 988 }
957 989
...@@ -964,9 +996,12 @@ mbox_header_get_fvalue (header_t header, const char *name, char *buffer, ...@@ -964,9 +996,12 @@ mbox_header_get_fvalue (header_t header, const char *name, char *buffer,
964 mbox_message_t mum = message_get_owner (msg); 996 mbox_message_t mum = message_get_owner (msg);
965 int err = ENOENT; 997 int err = ENOENT;
966 for (i = 0; i < HDRSIZE; i++) 998 for (i = 0; i < HDRSIZE; i++)
999 {
967 if (*name == *(fhdr_table[i]) && strcasecmp (fhdr_table[i], name) == 0) 1000 if (*name == *(fhdr_table[i]) && strcasecmp (fhdr_table[i], name) == 0)
968 { 1001 {
969 fv_value = (mum->fhdr[i]) ? strlen (mum->fhdr[i]) : 0; 1002 if (mum->fhdr[i])
1003 {
1004 fv_value = strlen (mum->fhdr[i]);
970 if (buffer && buflen > 0) 1005 if (buffer && buflen > 0)
971 { 1006 {
972 buflen--; 1007 buflen--;
...@@ -975,8 +1010,12 @@ mbox_header_get_fvalue (header_t header, const char *name, char *buffer, ...@@ -975,8 +1010,12 @@ mbox_header_get_fvalue (header_t header, const char *name, char *buffer,
975 buffer[fv_value] = '\0'; 1010 buffer[fv_value] = '\0';
976 } 1011 }
977 err = 0; 1012 err = 0;
1013 }
1014 else
1015 err = ENOENT;
978 break; 1016 break;
979 } 1017 }
1018 }
980 1019
981 if (pnread) 1020 if (pnread)
982 *pnread = fv_value; 1021 *pnread = fv_value;
...@@ -1228,7 +1267,6 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg) ...@@ -1228,7 +1267,6 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg)
1228 message_destroy (&msg, mum); 1267 message_destroy (&msg, mum);
1229 return status; 1268 return status;
1230 } 1269 }
1231 mum->new_flags = mum->old_flags;
1232 attribute_set_get_flags (attribute, mbox_get_attr_flags, msg); 1270 attribute_set_get_flags (attribute, mbox_get_attr_flags, msg);
1233 attribute_set_set_flags (attribute, mbox_set_attr_flags, msg); 1271 attribute_set_set_flags (attribute, mbox_set_attr_flags, msg);
1234 attribute_set_unset_flags (attribute, mbox_unset_attr_flags, msg); 1272 attribute_set_unset_flags (attribute, mbox_unset_attr_flags, msg);
...@@ -1270,6 +1308,9 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg) ...@@ -1270,6 +1308,9 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg)
1270 message_set_envelope (msg, envelope, mum); 1308 message_set_envelope (msg, envelope, mum);
1271 } 1309 }
1272 1310
1311 /* Set the UID. */
1312 message_set_uid (msg, mbox_message_uid, mum);
1313
1273 /* Attach the message to the mailbox mbox data. */ 1314 /* Attach the message to the mailbox mbox data. */
1274 mum->message = msg; 1315 mum->message = msg;
1275 message_set_mailbox (msg, mailbox); 1316 message_set_mailbox (msg, mailbox);
...@@ -1299,7 +1340,7 @@ mbox_append_message (mailbox_t mailbox, message_t msg) ...@@ -1299,7 +1340,7 @@ mbox_append_message (mailbox_t mailbox, message_t msg)
1299 int status; 1340 int status;
1300 /* Move to the end of the file, not necesary if _APPEND mode. */ 1341 /* Move to the end of the file, not necesary if _APPEND mode. */
1301 if ((status = stream_size (mailbox->stream, &size)) != 0 1342 if ((status = stream_size (mailbox->stream, &size)) != 0
1302 || (status = mbox_append_message0 (mailbox, msg, &size, 0)) != 0) 1343 || (status = mbox_append_message0 (mailbox, msg, &size, 0, 0)) != 0)
1303 { 1344 {
1304 if (status != EAGAIN) 1345 if (status != EAGAIN)
1305 locker_unlock (mailbox->locker); 1346 locker_unlock (mailbox->locker);
...@@ -1311,9 +1352,13 @@ mbox_append_message (mailbox_t mailbox, message_t msg) ...@@ -1311,9 +1352,13 @@ mbox_append_message (mailbox_t mailbox, message_t msg)
1311 return 0; 1352 return 0;
1312 } 1353 }
1313 1354
1355 /* FIXME: We need to escape line body line that begins with "From ", this
1356 will required to read the body by line instead of by chuncks hearting
1357 perfomance big time when expunging. But should not this be the
1358 responsability of the client ? */
1314 static int 1359 static int
1315 mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize, 1360 mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize,
1316 int is_expunging) 1361 int is_expunging, int first)
1317 { 1362 {
1318 mbox_data_t mud = mailbox->data; 1363 mbox_data_t mud = mailbox->data;
1319 int status = 0; 1364 int status = 0;
...@@ -1370,6 +1415,7 @@ mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize, ...@@ -1370,6 +1415,7 @@ mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize,
1370 char *s; 1415 char *s;
1371 size_t len = 0; 1416 size_t len = 0;
1372 envelope_t envelope; 1417 envelope_t envelope;
1418 char buffer[1024];
1373 message_get_envelope (msg, &envelope); 1419 message_get_envelope (msg, &envelope);
1374 status = envelope_date (envelope, mud->date, 128, &len); 1420 status = envelope_date (envelope, mud->date, 128, &len);
1375 if (status != 0) 1421 if (status != 0)
...@@ -1390,41 +1436,21 @@ mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize, ...@@ -1390,41 +1436,21 @@ mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize,
1390 *s = '\0'; 1436 *s = '\0';
1391 1437
1392 /* Write the separator to the mailbox. */ 1438 /* Write the separator to the mailbox. */
1393 status = stream_write (mailbox->stream, "From ", 5, *psize, &n); 1439 n = snprintf (buffer, sizeof (buffer), "From %s %s",
1394 if (status != 0) 1440 mud->sender, mud->date);
1395 break; 1441 stream_write (mailbox->stream, buffer, n, *psize, &n);
1396 *psize += n;
1397
1398 /* Write sender. */
1399 status = stream_write (mailbox->stream, mud->sender,
1400 strlen (mud->sender), *psize, &n);
1401 if (status != 0)
1402 break;
1403 *psize += n;
1404
1405 status = stream_write (mailbox->stream, " ", 1, *psize, &n);
1406 if (status != 0)
1407 break;
1408 *psize += n; 1442 *psize += n;
1409 1443
1410 /* Write date. */ 1444 /* Add the newline, the above may be truncated. */
1411 status = stream_write (mailbox->stream, mud->date, strlen(mud->date), 1445 stream_write (mailbox->stream, &nl , 1, *psize, &n);
1412 *psize, &n);
1413 if (status != 0)
1414 break;
1415 *psize += n;
1416
1417 status = stream_write (mailbox->stream, &nl , 1, *psize, &n);
1418 if (status != 0)
1419 break;
1420 *psize += n; 1446 *psize += n;
1421 1447
1422 free (mud->sender); 1448 free (mud->sender);
1423 free (mud->date); 1449 free (mud->date);
1424 mud->sender = mud->date = NULL; 1450 mud->sender = mud->date = NULL;
1425 /* If we are not expunging get the message in one block via the stream 1451 /* If we are not expunging get the message in one block via the stream
1426 message instead of the header/body. This is good for example for 1452 message instead of the header/body. This is good for POP where
1427 POP where there is no separtation between header and body. */ 1453 there is no separation between header and body(RETR). */
1428 if (! is_expunging) 1454 if (! is_expunging)
1429 { 1455 {
1430 mud->state = MBOX_STATE_APPEND_MESSAGE; 1456 mud->state = MBOX_STATE_APPEND_MESSAGE;
...@@ -1460,12 +1486,15 @@ mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize, ...@@ -1460,12 +1486,15 @@ mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize,
1460 break; 1486 break;
1461 1487
1462 /* We do not copy the Status since it is rewritten by the 1488 /* We do not copy the Status since it is rewritten by the
1463 attribute code below. */ 1489 attribute code below. Ditto for X-UID and X-IMAPBase.
1464 /* FIXME: - We have a problem here the header field may not fit 1490 FIXME:
1465 the buffer. 1491 - We have a problem here the header may not fit the buffer.
1466 - Should we skip the IMAP "X-Status"? 1492 - Should we skip the IMAP "X-Status"? */
1467 strncasecmp (buffer, "X-Status", 8) == 0) */ 1493 if ((strncasecmp (buffer, "Status", 6) == 0)
1468 if (strncasecmp (buffer, "Status", 6) == 0) 1494 || (strncasecmp (buffer, "X-IMAPbase", 10) == 0)
1495 || (strncasecmp (buffer, "X-UID", 4) == 0
1496 && (buffer[5] == ':' || buffer[5] == ' '
1497 || buffer[5] == '\t')))
1469 continue; 1498 continue;
1470 1499
1471 status = stream_write (mailbox->stream, buffer, nread, 1500 status = stream_write (mailbox->stream, buffer, nread,
...@@ -1476,6 +1505,15 @@ mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize, ...@@ -1476,6 +1505,15 @@ mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize,
1476 } 1505 }
1477 while (nread > 0); 1506 while (nread > 0);
1478 mud->off = 0; 1507 mud->off = 0;
1508
1509 /* Rewrite the X-IMAPbase marker. */
1510 if (first && is_expunging)
1511 {
1512 n = sprintf (buffer, "X-IMAPbase: %lu %u\n",
1513 mud->uidvalidity, mud->uidnext);
1514 stream_write (mailbox->stream, buffer, n, *psize, &n);
1515 *psize += n;
1516 }
1479 mud->state = MBOX_STATE_APPEND_ATTRIBUTE; 1517 mud->state = MBOX_STATE_APPEND_ATTRIBUTE;
1480 } 1518 }
1481 1519
...@@ -1494,6 +1532,34 @@ mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize, ...@@ -1494,6 +1532,34 @@ mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize,
1494 break; 1532 break;
1495 *psize += n; 1533 *psize += n;
1496 1534
1535 mud->state = MBOX_STATE_APPEND_UID;
1536 }
1537
1538 case MBOX_STATE_APPEND_UID:
1539 /* The new X-UID. */
1540 {
1541 char suid[64];
1542 size_t uid = 0;
1543 if (is_expunging)
1544 {
1545 status = message_get_uid (msg, &uid);
1546 if (status == EAGAIN)
1547 return status;
1548 }
1549 else
1550 uid = mud->uidnext++;
1551
1552 if (status == 0 || uid != 0)
1553 {
1554 n = sprintf (suid, "X-UID: %d\n", uid);
1555 /* Put the UID. */
1556 status = stream_write (mailbox->stream, suid, n, *psize, &n);
1557 if (status != 0)
1558 break;
1559 *psize += n;
1560 }
1561
1562 /* New line separator of the Header. */
1497 status = stream_write (mailbox->stream, &nl , 1, *psize, &n); 1563 status = stream_write (mailbox->stream, &nl , 1, *psize, &n);
1498 if (status != 0) 1564 if (status != 0)
1499 break; 1565 break;
...@@ -1608,7 +1674,7 @@ mbox_messages_count (mailbox_t mailbox, size_t *pcount) ...@@ -1608,7 +1674,7 @@ mbox_messages_count (mailbox_t mailbox, size_t *pcount)
1608 return EINVAL; 1674 return EINVAL;
1609 1675
1610 if (! mbox_is_updated (mailbox)) 1676 if (! mbox_is_updated (mailbox))
1611 return mbox_scan0 (mailbox, 1, pcount, 1); 1677 return mbox_scan0 (mailbox, mud->messages_count, pcount, 1);
1612 1678
1613 if (pcount) 1679 if (pcount)
1614 *pcount = mud->messages_count; 1680 *pcount = mud->messages_count;
...@@ -1617,21 +1683,67 @@ mbox_messages_count (mailbox_t mailbox, size_t *pcount) ...@@ -1617,21 +1683,67 @@ mbox_messages_count (mailbox_t mailbox, size_t *pcount)
1617 } 1683 }
1618 1684
1619 static int 1685 static int
1620 mbox_unseen_count (mailbox_t mailbox, size_t *pcount) 1686 mbox_messages_recent (mailbox_t mailbox, size_t *pcount)
1621 { 1687 {
1622 mbox_data_t mud = mailbox->data; 1688 mbox_data_t mud = mailbox->data;
1623 mbox_message_t mum; 1689 mbox_message_t mum;
1624 size_t j, total; 1690 size_t j, recent;
1625 1691
1626 if (pcount) 1692 for (recent = j = 0; j < mud->messages_count; j++)
1627 return EINVAL;
1628 for (total = j = 0; j < mud->messages_count; j++)
1629 { 1693 {
1630 mum = mud->umessages[j]; 1694 mum = mud->umessages[j];
1631 if (mum && mum->new_flags == 0) 1695 if (mum && ((mum->attr_flags == 0) ||
1632 total++; 1696 ! ((mum->attr_flags & MU_ATTRIBUTE_SEEN)
1697 && (mum->attr_flags & MU_ATTRIBUTE_READ))))
1698 recent++;
1633 } 1699 }
1634 *pcount = total; 1700 *pcount = recent;
1701 return 0;
1702 }
1703
1704 static int
1705 mbox_message_unseen (mailbox_t mailbox, size_t *pmsgno)
1706 {
1707 mbox_data_t mud = mailbox->data;
1708 mbox_message_t mum;
1709 size_t j, unseen;
1710
1711 for (unseen = j = 0; j < mud->messages_count; j++)
1712 {
1713 mum = mud->umessages[j];
1714 if (mum && ((mum->attr_flags == 0) ||
1715 ! ((mum->attr_flags & MU_ATTRIBUTE_SEEN)
1716 && (mum->attr_flags & MU_ATTRIBUTE_READ))))
1717 {
1718 unseen = j + 1;
1719 break;
1720 }
1721 }
1722 *pmsgno = unseen;
1723 return 0;
1724 }
1725
1726 static int
1727 mbox_uidvalidity (mailbox_t mailbox, unsigned long *puidvalidity)
1728 {
1729 mbox_data_t mud = mailbox->data;
1730 int status = mbox_messages_count (mailbox, NULL);
1731 if (status != 0)
1732 return status;
1733 if (puidvalidity)
1734 *puidvalidity = mud->uidvalidity;
1735 return 0;
1736 }
1737
1738 static int
1739 mbox_uidnext (mailbox_t mailbox, size_t *puidnext)
1740 {
1741 mbox_data_t mud = mailbox->data;
1742 int status = mbox_messages_count (mailbox, NULL);
1743 if (status != 0)
1744 return status;
1745 if (puidnext)
1746 *puidnext = mud->uidnext;
1635 return 0; 1747 return 0;
1636 } 1748 }
1637 1749
......
...@@ -156,7 +156,7 @@ do \ ...@@ -156,7 +156,7 @@ do \
156 { \ 156 { \
157 if (*s == c0 || *s == c1) \ 157 if (*s == c0 || *s == c1) \
158 { \ 158 { \
159 (mum)->old_flags |= (type); \ 159 (mum)->attr_flags |= (type); \
160 break; \ 160 break; \
161 } \ 161 } \
162 } \ 162 } \
...@@ -220,6 +220,19 @@ do \ ...@@ -220,6 +220,19 @@ do \
220 && (buf[1] == 'O' || buf[1] == 'o') \ 220 && (buf[1] == 'O' || buf[1] == 'o') \
221 && (buf[2] == ':' || buf[2] == ' ' || buf[2] == '\t')) 221 && (buf[2] == ':' || buf[2] == ' ' || buf[2] == '\t'))
222 222
223 #define ISX_IMAPBASE(buf) (\
224 (buf[0] == 'X' || buf[0] == 'x') \
225 && (buf[1] == '-') \
226 && (buf[2] == 'I' || buf[2] == 'i') \
227 && (buf[3] == 'M' || buf[3] == 'm') \
228 && (buf[4] == 'A' || buf[4] == 'a') \
229 && (buf[5] == 'P' || buf[5] == 'p') \
230 && (buf[6] == 'B' || buf[6] == 'b') \
231 && (buf[7] == 'A' || buf[7] == 'a') \
232 && (buf[8] == 'S' || buf[8] == 's') \
233 && (buf[9] == 'E' || buf[9] == 'e') \
234 && (buf[10] == ':' || buf[10] == ' ' || buf[10] == '\t'))
235
223 #define ISX_UIDL(buf) (\ 236 #define ISX_UIDL(buf) (\
224 (buf[0] == 'X' || buf[0] == 'x') \ 237 (buf[0] == 'X' || buf[0] == 'x') \
225 && (buf[1] == '-') \ 238 && (buf[1] == '-') \
...@@ -268,8 +281,6 @@ do { \ ...@@ -268,8 +281,6 @@ do { \
268 } \ 281 } \
269 } while (0) 282 } while (0)
270 283
271 //fprintf (stderr, "%d %d <%s> <%s>\n", i, l, (i)?field:"", p);
272
273 #define FAST_HCONTENT_TYPE(mum,sf,buf,n) \ 284 #define FAST_HCONTENT_TYPE(mum,sf,buf,n) \
274 FAST_HEADER(mum->fhdr[HCONTENT_TYPE],buf,n); \ 285 FAST_HEADER(mum->fhdr[HCONTENT_TYPE],buf,n); \
275 sf = &(mum->fhdr[HCONTENT_TYPE]) 286 sf = &(mum->fhdr[HCONTENT_TYPE])
...@@ -294,6 +305,10 @@ sf = &(mum->fhdr[HSUBJECT]) ...@@ -294,6 +305,10 @@ sf = &(mum->fhdr[HSUBJECT])
294 FAST_HEADER(mum->fhdr[HTO],buf,n); \ 305 FAST_HEADER(mum->fhdr[HTO],buf,n); \
295 sf = &(mum->fhdr[HTO]) 306 sf = &(mum->fhdr[HTO])
296 307
308 #define FAST_HX_IMAPBASE(mum,sf,buf,n) \
309 FAST_HEADER(mum->fhdr[HX_IMAPBASE],buf,n); \
310 sf = &(mum->fhdr[HX_UID])
311
297 #define FAST_HX_UIDL(mum,sf,buf,n) \ 312 #define FAST_HX_UIDL(mum,sf,buf,n) \
298 FAST_HEADER(mum->fhdr[HX_UIDL],buf,n); \ 313 FAST_HEADER(mum->fhdr[HX_UIDL],buf,n); \
299 sf = &(mum->fhdr[HX_UIDL]) 314 sf = &(mum->fhdr[HX_UIDL])
...@@ -483,45 +498,47 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif) ...@@ -483,45 +498,47 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
483 mum->fhdr[j] = NULL; 498 mum->fhdr[j] = NULL;
484 } 499 }
485 } 500 }
486 else if (/*(n > 7) && */ ISSTATUS(buf)) 501 else if (ISSTATUS(buf))
487 { 502 {
488 mum->header_status = total - n;
489 mum->header_status_end = total;
490 ATTRIBUTE_SET(buf, mum, 'r', 'R', MU_ATTRIBUTE_READ); 503 ATTRIBUTE_SET(buf, mum, 'r', 'R', MU_ATTRIBUTE_READ);
491 ATTRIBUTE_SET(buf, mum, 'o', 'O', MU_ATTRIBUTE_SEEN); 504 ATTRIBUTE_SET(buf, mum, 'o', 'O', MU_ATTRIBUTE_SEEN);
492 ATTRIBUTE_SET(buf, mum, 'a', 'A', MU_ATTRIBUTE_ANSWERED); 505 ATTRIBUTE_SET(buf, mum, 'a', 'A', MU_ATTRIBUTE_ANSWERED);
493 ATTRIBUTE_SET(buf, mum, 'd', 'D', MU_ATTRIBUTE_DELETED); 506 ATTRIBUTE_SET(buf, mum, 'd', 'D', MU_ATTRIBUTE_DELETED);
494 sfield = NULL; 507 sfield = NULL;
495 } 508 }
496 else if (/*(n > 12) && */ ISCONTENT_TYPE(buf)) 509 else if (ISCONTENT_TYPE(buf))
497 { 510 {
498 FAST_HCONTENT_TYPE(mum, sfield, buf, n); 511 FAST_HCONTENT_TYPE(mum, sfield, buf, n);
499 } 512 }
500 else if (/*(n > 3) && */ ISCC(buf)) 513 else if (ISCC(buf))
501 { 514 {
502 FAST_HCC(mum, sfield, buf, n); 515 FAST_HCC(mum, sfield, buf, n);
503 } 516 }
504 else if (/*(n > 5) && */ ISDATE(buf)) 517 else if (ISDATE(buf))
505 { 518 {
506 FAST_HDATE(mum, sfield, buf, n); 519 FAST_HDATE(mum, sfield, buf, n);
507 } 520 }
508 else if (/*(n > 5) && */ ISFROM(buf)) 521 else if (ISFROM(buf))
509 { 522 {
510 FAST_HFROM(mum, sfield, buf, n); 523 FAST_HFROM(mum, sfield, buf, n);
511 } 524 }
512 else if (/*(n > 8) && */ ISSUBJECT(buf)) 525 else if (ISSUBJECT(buf))
513 { 526 {
514 FAST_HSUBJECT (mum, sfield, buf, n); 527 FAST_HSUBJECT (mum, sfield, buf, n);
515 } 528 }
516 else if (/*(n > 3) && */ ISTO(buf)) 529 else if (ISTO(buf))
517 { 530 {
518 FAST_HTO (mum, sfield, buf, n); 531 FAST_HTO (mum, sfield, buf, n);
519 } 532 }
520 else if (/*(n > 7) && */ ISX_UIDL(buf)) 533 else if (ISX_IMAPBASE(buf))
534 {
535 FAST_HX_IMAPBASE (mum, sfield, buf, n);
536 }
537 else if (ISX_UIDL(buf))
521 { 538 {
522 FAST_HX_UIDL (mum, sfield, buf, n); 539 FAST_HX_UIDL (mum, sfield, buf, n);
523 } 540 }
524 else if (/*(n > 6) && */ ISX_UID(buf)) 541 else if (ISX_UID(buf))
525 { 542 {
526 FAST_HX_UID (mum, sfield, buf, n); 543 FAST_HX_UID (mum, sfield, buf, n);
527 } 544 }
...@@ -551,11 +568,11 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif) ...@@ -551,11 +568,11 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
551 568
552 newline = nl; 569 newline = nl;
553 570
554 /* Every 50 mesgs update the lock, it should be every minute. */ 571 /* Every 100 mesgs update the lock, it should be every minute. */
555 if ((mud->messages_count % 50) == 0) 572 if ((mud->messages_count % 100) == 0)
556 locker_touchlock (mailbox->locker); 573 locker_touchlock (mailbox->locker);
557 574
558 /* Ping them every 1000 lines. */ 575 /* Ping them every 1000 lines. Should be tunable. */
559 if (do_notif) 576 if (do_notif)
560 if (((lines +1) % 1000) == 0) 577 if (((lines +1) % 1000) == 0)
561 DISPATCH_PROGRESS(mailbox, mud); 578 DISPATCH_PROGRESS(mailbox, mud);
...@@ -574,6 +591,72 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif) ...@@ -574,6 +591,72 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
574 locker_unlock (mailbox->locker); 591 locker_unlock (mailbox->locker);
575 monitor_unlock (mailbox->monitor); 592 monitor_unlock (mailbox->monitor);
576 593
594 /* Reset the uidvalidity. */
595 if (mud->messages_count > 0)
596 {
597 mum = mud->umessages[0];
598 if (mum->fhdr[HX_IMAPBASE])
599 {
600 char *s = mum->fhdr[HX_IMAPBASE];
601 while (*s && !isdigit (*s)) s++;
602 mud->uidvalidity = strtoul (s, &s, 10);
603 mud->uidnext = strtoul (s, NULL, 10);
604 }
605 if (mud->uidvalidity == 0)
606 {
607 char u[64];
608 mud->uidvalidity = (unsigned long)time (NULL);
609 mud->uidnext = mud->messages_count + 1;
610 if (mum->fhdr[HX_IMAPBASE])
611 free (mum->fhdr[HX_IMAPBASE]);
612 sprintf (u, "%lu %u", mud->uidvalidity, mud->uidnext);
613 mum->fhdr[HX_IMAPBASE] = strdup (u);
614 /* Tell that we have been modified for expunging. */
615 mum->attr_flags |= MU_ATTRIBUTE_MODIFIED;
616 }
617 }
618 /* Reset the IMAP uids, if necessary. */
619 {
620 size_t uid;
621 size_t ouid;
622 size_t i;
623 for (uid = ouid = i = 0; i < mud->messages_count; i++)
624 {
625 char *s;
626 mum = mud->umessages[i];
627 s = mum->fhdr[HX_UID];
628 if (s)
629 {
630 while (*s && !isdigit (*s)) s++;
631 uid = strtoul (s, &s, 10);
632 }
633 else
634 uid = 0;
635 if (uid <= ouid)
636 {
637 char u[64];
638 uid = ouid + 1;
639 sprintf (u, "%d", uid);
640 if (mum->fhdr[HX_UID])
641 free (mum->fhdr[HX_UID]);
642 mum->fhdr[HX_UID] = strdup (u);
643 /* Note that we have modified for expunging. */
644 mum->attr_flags |= MU_ATTRIBUTE_MODIFIED;
645 }
646 mum->uid = ouid = uid;
647 }
648 if (uid > mud->messages_count)
649 {
650 char u[64];
651 mud->uidnext = uid + 1;
652 mum = mud->umessages[0];
653 if (mum->fhdr[HX_IMAPBASE])
654 free (mum->fhdr[HX_IMAPBASE]);
655 sprintf (u, "%lu %u", mud->uidvalidity, uid + 1);
656 mum->fhdr[HX_IMAPBASE] = strdup (u);
657 mum->attr_flags |= MU_ATTRIBUTE_MODIFIED;
658 }
659 }
577 #ifdef WITH_PTHREAD 660 #ifdef WITH_PTHREAD
578 pthread_cleanup_pop (0); 661 pthread_cleanup_pop (0);
579 #endif 662 #endif
......
...@@ -77,6 +77,8 @@ static int pop_open __P ((mailbox_t, int)); ...@@ -77,6 +77,8 @@ static int pop_open __P ((mailbox_t, int));
77 static int pop_close __P ((mailbox_t)); 77 static int pop_close __P ((mailbox_t));
78 static int pop_get_message __P ((mailbox_t, size_t, message_t *)); 78 static int pop_get_message __P ((mailbox_t, size_t, message_t *));
79 static int pop_messages_count __P ((mailbox_t, size_t *)); 79 static int pop_messages_count __P ((mailbox_t, size_t *));
80 static int pop_messages_recent __P ((mailbox_t, size_t *));
81 static int pop_message_unseen __P ((mailbox_t, size_t *));
80 static int pop_expunge __P ((mailbox_t)); 82 static int pop_expunge __P ((mailbox_t));
81 static int pop_scan __P ((mailbox_t, size_t, size_t *)); 83 static int pop_scan __P ((mailbox_t, size_t, size_t *));
82 static int pop_is_updated __P ((mailbox_t)); 84 static int pop_is_updated __P ((mailbox_t));
...@@ -97,7 +99,8 @@ static int pop_top __P ((header_t, char *, size_t, off_t, size_t *)); ...@@ -97,7 +99,8 @@ static int pop_top __P ((header_t, char *, size_t, off_t, size_t *));
97 static int pop_retr __P ((pop_message_t, char *, size_t, off_t, size_t *)); 99 static int pop_retr __P ((pop_message_t, char *, size_t, off_t, size_t *));
98 static int pop_get_fd __P ((pop_message_t, int *)); 100 static int pop_get_fd __P ((pop_message_t, int *));
99 static int pop_attr_flags __P ((attribute_t, int *)); 101 static int pop_attr_flags __P ((attribute_t, int *));
100 static int pop_uid __P ((message_t, char *, size_t, size_t *)); 102 static int pop_uidl __P ((message_t, char *, size_t, size_t *));
103 static int pop_uid __P ((message_t, size_t *));
101 static int fill_buffer __P ((pop_data_t, char *, size_t)); 104 static int fill_buffer __P ((pop_data_t, char *, size_t));
102 static int pop_readline __P ((pop_data_t)); 105 static int pop_readline __P ((pop_data_t));
103 static int pop_read_ack __P ((pop_data_t)); 106 static int pop_read_ack __P ((pop_data_t));
...@@ -122,7 +125,7 @@ struct _pop_message ...@@ -122,7 +125,7 @@ struct _pop_message
122 size_t header_lines; 125 size_t header_lines;
123 size_t message_size; 126 size_t message_size;
124 size_t num; 127 size_t num;
125 char *uid; /* Cache the uid string. */ 128 char *uidl; /* Cache the uidl string. */
126 message_t message; 129 message_t message;
127 pop_data_t mpd; /* Back pointer. */ 130 pop_data_t mpd; /* Back pointer. */
128 }; 131 };
...@@ -280,6 +283,8 @@ _mailbox_pop_init (mailbox_t mbox) ...@@ -280,6 +283,8 @@ _mailbox_pop_init (mailbox_t mbox)
280 /* Messages. */ 283 /* Messages. */
281 mbox->_get_message = pop_get_message; 284 mbox->_get_message = pop_get_message;
282 mbox->_messages_count = pop_messages_count; 285 mbox->_messages_count = pop_messages_count;
286 mbox->_messages_recent = pop_messages_recent;
287 mbox->_message_unseen = pop_message_unseen;
283 mbox->_expunge = pop_expunge; 288 mbox->_expunge = pop_expunge;
284 289
285 mbox->_scan = pop_scan; 290 mbox->_scan = pop_scan;
...@@ -306,8 +311,8 @@ pop_destroy (mailbox_t mbox) ...@@ -306,8 +311,8 @@ pop_destroy (mailbox_t mbox)
306 { 311 {
307 message_destroy (&(mpd->pmessages[i]->message), 312 message_destroy (&(mpd->pmessages[i]->message),
308 mpd->pmessages[i]); 313 mpd->pmessages[i]);
309 if (mpd->pmessages[i]->uid) 314 if (mpd->pmessages[i]->uidl)
310 free (mpd->pmessages[i]->uid); 315 free (mpd->pmessages[i]->uidl);
311 free (mpd->pmessages[i]); 316 free (mpd->pmessages[i]);
312 mpd->pmessages[i] = NULL; 317 mpd->pmessages[i] = NULL;
313 } 318 }
...@@ -624,8 +629,8 @@ pop_close (mailbox_t mbox) ...@@ -624,8 +629,8 @@ pop_close (mailbox_t mbox)
624 { 629 {
625 message_destroy (&(mpd->pmessages[i]->message), 630 message_destroy (&(mpd->pmessages[i]->message),
626 mpd->pmessages[i]); 631 mpd->pmessages[i]);
627 if (mpd->pmessages[i]->uid) 632 if (mpd->pmessages[i]->uidl)
628 free (mpd->pmessages[i]->uid); 633 free (mpd->pmessages[i]->uidl);
629 free (mpd->pmessages[i]); 634 free (mpd->pmessages[i]);
630 mpd->pmessages[i] = NULL; 635 mpd->pmessages[i] = NULL;
631 } 636 }
...@@ -753,6 +758,9 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) ...@@ -753,6 +758,9 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
753 } 758 }
754 759
755 /* Set the UIDL call on the message. */ 760 /* Set the UIDL call on the message. */
761 message_set_uidl (msg, pop_uidl, mpm);
762
763 /* Set the UID on the message. */
756 message_set_uid (msg, pop_uid, mpm); 764 message_set_uid (msg, pop_uid, mpm);
757 765
758 /* Add it to the list. */ 766 /* Add it to the list. */
...@@ -780,6 +788,30 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) ...@@ -780,6 +788,30 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
780 return 0; 788 return 0;
781 } 789 }
782 790
791 /* There is no such thing in pop all messages should be consider recent.
792 FIXME: We could cheat and peek at the status if it was not strip
793 by the server ... */
794 static int
795 pop_messages_recent (mailbox_t mbox, size_t *precent)
796 {
797 return pop_messages_count (mbox, precent);
798 }
799
800 /* There is no such thing in pop all messages should be consider unseen.
801 FIXME: We could cheat and peek at the status if it was not strip
802 by the server ... */
803 static int
804 pop_message_unseen (mailbox_t mbox, size_t *punseen)
805 {
806 size_t count = 0;
807 int status = pop_messages_count (mbox, &count);
808 if (status != 0)
809 return status;
810 if (punseen)
811 *punseen = (count > 0) ? 1 : 0;
812 return 0;
813 }
814
783 /* How many messages we have. Done with STAT. */ 815 /* How many messages we have. Done with STAT. */
784 static int 816 static int
785 pop_messages_count (mailbox_t mbox, size_t *pcount) 817 pop_messages_count (mailbox_t mbox, size_t *pcount)
...@@ -1025,7 +1057,7 @@ pop_message_size (message_t msg, size_t *psize) ...@@ -1025,7 +1057,7 @@ pop_message_size (message_t msg, size_t *psize)
1025 1057
1026 default: 1058 default:
1027 /* 1059 /*
1028 fprintf (stderr, "pop_uid state\n"); 1060 fprintf (stderr, "pop_message_size state\n");
1029 */ 1061 */
1030 break; 1062 break;
1031 } 1063 }
...@@ -1141,19 +1173,28 @@ pop_get_fd (pop_message_t mpm, int *pfd) ...@@ -1141,19 +1173,28 @@ pop_get_fd (pop_message_t mpm, int *pfd)
1141 return EINVAL; 1173 return EINVAL;
1142 } 1174 }
1143 1175
1176 static int
1177 pop_uid (message_t msg, size_t *puid)
1178 {
1179 pop_message_t mpm = message_get_owner (msg);
1180 if (puid)
1181 *puid = mpm->num;
1182 return 0;
1183 }
1184
1144 /* Get the UIDL. Client should be prepare since it may fail. UIDL is 1185 /* Get the UIDL. Client should be prepare since it may fail. UIDL is
1145 optional on many POP servers. 1186 optional on many POP servers.
1146 FIXME: We should check this with CAPA and fall back to a md5 scheme ? 1187 FIXME: We should check this with CAPA and fall back to a md5 scheme ?
1147 Or maybe check for "X-UIDL" a la Qpopper ? */ 1188 Or maybe check for "X-UIDL" a la Qpopper ? */
1148 static int 1189 static int
1149 pop_uid (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) 1190 pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
1150 { 1191 {
1151 pop_message_t mpm = message_get_owner (msg); 1192 pop_message_t mpm = message_get_owner (msg);
1152 pop_data_t mpd; 1193 pop_data_t mpd;
1153 int status = 0; 1194 int status = 0;
1154 void *func = (void *)pop_uid; 1195 void *func = (void *)pop_uidl;
1155 size_t num; 1196 size_t num;
1156 /* According to the RFC uid's are no longer then 70 chars. Still playit 1197 /* According to the RFC uidl's are no longer then 70 chars. Still playit
1157 safe */ 1198 safe */
1158 char uniq[128]; 1199 char uniq[128];
1159 1200
...@@ -1161,14 +1202,14 @@ pop_uid (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) ...@@ -1161,14 +1202,14 @@ pop_uid (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
1161 return EINVAL; 1202 return EINVAL;
1162 1203
1163 /* Is it cache ? */ 1204 /* Is it cache ? */
1164 if (mpm->uid) 1205 if (mpm->uidl)
1165 { 1206 {
1166 size_t len = strlen (mpm->uid); 1207 size_t len = strlen (mpm->uidl);
1167 if (buffer) 1208 if (buffer)
1168 { 1209 {
1169 buflen--; /* Leave space for the null. */ 1210 buflen--; /* Leave space for the null. */
1170 buflen = (len > buflen) ? buflen : len; 1211 buflen = (len > buflen) ? buflen : len;
1171 memcpy (buffer, mpm->uid, buflen); 1212 memcpy (buffer, mpm->uidl, buflen);
1172 buffer[buflen] = '\0'; 1213 buffer[buflen] = '\0';
1173 } 1214 }
1174 else 1215 else
...@@ -1207,7 +1248,7 @@ pop_uid (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) ...@@ -1207,7 +1248,7 @@ pop_uid (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
1207 1248
1208 default: 1249 default:
1209 /* 1250 /*
1210 fprintf (stderr, "pop_uid state\n"); 1251 fprintf (stderr, "pop_uidl state\n");
1211 */ 1252 */
1212 break; 1253 break;
1213 } 1254 }
...@@ -1233,7 +1274,7 @@ pop_uid (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) ...@@ -1233,7 +1274,7 @@ pop_uid (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
1233 } 1274 }
1234 else 1275 else
1235 buflen = num - 1; /* Do not count newline. */ 1276 buflen = num - 1; /* Do not count newline. */
1236 mpm->uid = strdup (uniq); 1277 mpm->uidl = strdup (uniq);
1237 status = 0; 1278 status = 0;
1238 } 1279 }
1239 1280
......
...@@ -411,9 +411,19 @@ message_set_attribute (message_t msg, attribute_t attribute, void *owner) ...@@ -411,9 +411,19 @@ message_set_attribute (message_t msg, attribute_t attribute, void *owner)
411 return 0; 411 return 0;
412 } 412 }
413 413
414 /* FIXME: not nonblocking safe. */
415 int 414 int
416 message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten) 415 message_get_uid (message_t msg, size_t *puid)
416 {
417 if (msg == NULL)
418 return EINVAL;
419 if (msg->_get_uid)
420 return msg->_get_uid (msg, puid);
421 *puid = 0;
422 return 0;
423 }
424
425 int
426 message_get_uidl (message_t msg, char *buffer, size_t buflen, size_t *pwriten)
417 { 427 {
418 header_t header = NULL; 428 header_t header = NULL;
419 size_t n = 0; 429 size_t n = 0;
...@@ -424,9 +434,9 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten) ...@@ -424,9 +434,9 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten)
424 434
425 buffer[0] = '\0'; 435 buffer[0] = '\0';
426 /* Try the function overload if error fallback. */ 436 /* Try the function overload if error fallback. */
427 if (msg->_get_uid) 437 if (msg->_get_uidl)
428 { 438 {
429 status = msg->_get_uid (msg, buffer, buflen, pwriten); 439 status = msg->_get_uidl (msg, buffer, buflen, pwriten);
430 if (status == 0) 440 if (status == 0)
431 return status; 441 return status;
432 } 442 }
...@@ -458,7 +468,7 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten) ...@@ -458,7 +468,7 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten)
458 } 468 }
459 else 469 else
460 { 470 {
461 static unsigned long seq; 471 size_t uid = 0;
462 struct md5_ctx md5context; 472 struct md5_ctx md5context;
463 stream_t stream = NULL; 473 stream_t stream = NULL;
464 char buf[1024]; 474 char buf[1024];
...@@ -466,6 +476,7 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten) ...@@ -466,6 +476,7 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten)
466 unsigned char md5digest[16]; 476 unsigned char md5digest[16];
467 char *tmp; 477 char *tmp;
468 n = 0; 478 n = 0;
479 message_get_uid (msg, &uid);
469 message_get_stream (msg, &stream); 480 message_get_stream (msg, &stream);
470 md5_init_ctx (&md5context); 481 md5_init_ctx (&md5context);
471 while (stream_read (stream, buf, sizeof (buf), offset, &n) == 0 482 while (stream_read (stream, buf, sizeof (buf), offset, &n) == 0
...@@ -479,10 +490,8 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten) ...@@ -479,10 +490,8 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten)
479 for (n = 0; n < 16; n++, tmp += 2) 490 for (n = 0; n < 16; n++, tmp += 2)
480 sprintf (tmp, "%02x", md5digest[n]); 491 sprintf (tmp, "%02x", md5digest[n]);
481 *tmp = '\0'; 492 *tmp = '\0';
482 /* Access to sequence is not thread-safe, but that is not a problem. */
483 seq++;
484 /* POP3 rfc says that an UID should not be longer than 70. */ 493 /* POP3 rfc says that an UID should not be longer than 70. */
485 snprintf (buf + 32, 70, ".%lu.%lu", (unsigned long)time (NULL), seq); 494 snprintf (buf + 32, 70, ".%lu.%u", (unsigned long)time (NULL), uid);
486 495
487 header_set_value (header, "X-UIDL", buf, 1); 496 header_set_value (header, "X-UIDL", buf, 1);
488 buflen--; /* leave space for the NULL. */ 497 buflen--; /* leave space for the NULL. */
...@@ -492,8 +501,8 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten) ...@@ -492,8 +501,8 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten)
492 } 501 }
493 502
494 int 503 int
495 message_set_uid (message_t msg, int (* _get_uid) 504 message_set_uid (message_t msg, int (*_get_uid) __P ((message_t, size_t *)),
496 __P ((message_t, char *, size_t, size_t *)), void *owner) 505 void *owner)
497 { 506 {
498 if (msg == NULL) 507 if (msg == NULL)
499 return EINVAL; 508 return EINVAL;
...@@ -504,6 +513,18 @@ message_set_uid (message_t msg, int (* _get_uid) ...@@ -504,6 +513,18 @@ message_set_uid (message_t msg, int (* _get_uid)
504 } 513 }
505 514
506 int 515 int
516 message_set_uidl (message_t msg, int (* _get_uidl)
517 __P ((message_t, char *, size_t, size_t *)), void *owner)
518 {
519 if (msg == NULL)
520 return EINVAL;
521 if (msg->owner != owner)
522 return EACCES;
523 msg->_get_uidl = _get_uidl;
524 return 0;
525 }
526
527 int
507 message_set_is_multipart (message_t msg, int (*_is_multipart) 528 message_set_is_multipart (message_t msg, int (*_is_multipart)
508 __P ((message_t, int *)), void *owner) 529 __P ((message_t, int *)), void *owner)
509 { 530 {
......
1 /* GNU mailutils - a suite of utilities for electronic mail 1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3 3
4 This program is free software; you can redistribute it and/or modify 4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by 5 it under the terms of the GNU General Library Public License as published by
...@@ -72,12 +72,13 @@ static int _qp_decode(const char *iptr, size_t isize, char *optr, size_t osize, ...@@ -72,12 +72,13 @@ static int _qp_decode(const char *iptr, size_t isize, char *optr, size_t osize,
72 static int _qp_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len); 72 static int _qp_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len);
73 73
74 #define NUM_TRANSCODERS 5 74 #define NUM_TRANSCODERS 5
75 struct _ts_desc tslist[NUM_TRANSCODERS] = { { "base64", _base64_init, _base64_decode, _base64_encode}, 75 struct _ts_desc tslist[NUM_TRANSCODERS] = {
76 { "base64", _base64_init, _base64_decode, _base64_encode},
76 { "quoted-printable", _qp_init, _qp_decode, _qp_encode}, 77 { "quoted-printable", _qp_init, _qp_decode, _qp_encode},
77 { "7bit", NULL}, 78 { "7bit", NULL, NULL, NULL},
78 { "8bit", NULL}, 79 { "8bit", NULL, NULL, NULL},
79 { "binary", NULL} 80 { "binary", NULL, NULL, NULL}
80 }; 81 };
81 82
82 static void 83 static void
83 _trans_destroy(stream_t stream) 84 _trans_destroy(stream_t stream)
...@@ -153,7 +154,6 @@ static int ...@@ -153,7 +154,6 @@ static int
153 _trans_write(stream_t stream, const char *iptr, size_t isize, off_t offset, size_t *nbytes) 154 _trans_write(stream_t stream, const char *iptr, size_t isize, off_t offset, size_t *nbytes)
154 { 155 {
155 struct _trans_stream *ts = stream_get_owner(stream); 156 struct _trans_stream *ts = stream_get_owner(stream);
156 int ret = 0;
157 157
158 if ( nbytes == NULL || iptr == NULL || isize == 0 ) 158 if ( nbytes == NULL || iptr == NULL || isize == 0 )
159 return EINVAL; 159 return EINVAL;
...@@ -326,6 +326,7 @@ _qp_init(struct _trans_stream *ts, int type) ...@@ -326,6 +326,7 @@ _qp_init(struct _trans_stream *ts, int type)
326 return 0; 326 return 0;
327 } 327 }
328 328
329 #if 0
329 static int 330 static int
330 _ishex(int c) 331 _ishex(int c)
331 { 332 {
...@@ -340,6 +341,7 @@ _ishex(int c) ...@@ -340,6 +341,7 @@ _ishex(int c)
340 341
341 return 0; 342 return 0;
342 } 343 }
344 #endif
343 345
344 static int 346 static int
345 _qp_decode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len) 347 _qp_decode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len)
......