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)
423 { 426 {
424 m_imap_t m_imap = mailbox->data; 427 m_imap_t m_imap = mailbox->data;
425 *pnum = m_imap->unseen; 428 *punseen = m_imap->unseen;
426 return 0; 429 return 0;
427 } 430 }
431
432 static int
433 imap_messages_recent (mailbox_t mailbox, size_t *precent)
434 {
435 m_imap_t m_imap = mailbox->data;
436 *precent = m_imap->recent;
437 return 0;
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)
......
...@@ -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
......
...@@ -70,39 +70,42 @@ enum pop_state ...@@ -70,39 +70,42 @@ enum pop_state
70 POP_AUTH_PASS, POP_AUTH_PASS_ACK 70 POP_AUTH_PASS, POP_AUTH_PASS_ACK
71 }; 71 };
72 72
73 static void pop_destroy __P ((mailbox_t)); 73 static void pop_destroy __P ((mailbox_t));
74 74
75 /* Functions/Methods that implements the mailbox_t API. */ 75 /* Functions/Methods that implements the mailbox_t API. */
76 static int pop_open __P ((mailbox_t, int)); 76 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_expunge __P ((mailbox_t)); 80 static int pop_messages_recent __P ((mailbox_t, size_t *));
81 static int pop_scan __P ((mailbox_t, size_t, size_t *)); 81 static int pop_message_unseen __P ((mailbox_t, size_t *));
82 static int pop_is_updated __P ((mailbox_t)); 82 static int pop_expunge __P ((mailbox_t));
83 static int pop_scan __P ((mailbox_t, size_t, size_t *));
84 static int pop_is_updated __P ((mailbox_t));
83 85
84 /* The implementation of message_t */ 86 /* The implementation of message_t */
85 static int pop_user __P ((authority_t)); 87 static int pop_user __P ((authority_t));
86 static int pop_size __P ((mailbox_t, off_t *)); 88 static int pop_size __P ((mailbox_t, off_t *));
87 /* We use pop_top for retreiving headers. */ 89 /* We use pop_top for retreiving headers. */
88 /* static int pop_header_read (header_t, char *, size_t, off_t, size_t *); */ 90 /* static int pop_header_read (header_t, char *, size_t, off_t, size_t *); */
89 static int pop_body_fd __P ((stream_t, int *)); 91 static int pop_body_fd __P ((stream_t, int *));
90 static int pop_body_size __P ((body_t, size_t *)); 92 static int pop_body_size __P ((body_t, size_t *));
91 static int pop_body_lines __P ((body_t, size_t *)); 93 static int pop_body_lines __P ((body_t, size_t *));
92 static int pop_body_read __P ((stream_t, char *, size_t, off_t, size_t *)); 94 static int pop_body_read __P ((stream_t, char *, size_t, off_t, size_t *));
93 static int pop_message_read __P ((stream_t, char *, size_t, off_t, size_t *)); 95 static int pop_message_read __P ((stream_t, char *, size_t, off_t, size_t *));
94 static int pop_message_size __P ((message_t, size_t *)); 96 static int pop_message_size __P ((message_t, size_t *));
95 static int pop_message_fd __P ((stream_t, int *)); 97 static int pop_message_fd __P ((stream_t, int *));
96 static int pop_top __P ((header_t, char *, size_t, off_t, size_t *)); 98 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 *));
101 static int fill_buffer __P ((pop_data_t, char *, size_t)); 103 static int pop_uid __P ((message_t, size_t *));
102 static int pop_readline __P ((pop_data_t)); 104 static int fill_buffer __P ((pop_data_t, char *, size_t));
103 static int pop_read_ack __P ((pop_data_t)); 105 static int pop_readline __P ((pop_data_t));
104 static int pop_writeline __P ((pop_data_t, const char *, ...)); 106 static int pop_read_ack __P ((pop_data_t));
105 static int pop_write __P ((pop_data_t)); 107 static int pop_writeline __P ((pop_data_t, const char *, ...));
108 static int pop_write __P ((pop_data_t));
106 109
107 /* This structure holds the info for a message. The pop_message_t 110 /* This structure holds the info for a message. The pop_message_t
108 type, will serve as the owner of the message_t and contains the command to 111 type, will serve as the owner of the message_t and contains the command to
...@@ -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
...@@ -16,9 +16,9 @@ ...@@ -16,9 +16,9 @@
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ 16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17 17
18 /* Notes: 18 /* Notes:
19 19
20 */ 20 */
21 21
22 22
23 #ifdef HAVE_CONFIG_H 23 #ifdef HAVE_CONFIG_H
24 # include <config.h> 24 # include <config.h>
...@@ -39,22 +39,22 @@ struct _trans_stream ...@@ -39,22 +39,22 @@ struct _trans_stream
39 { 39 {
40 stream_t stream; /* encoder/decoder read/writes data to/from here */ 40 stream_t stream; /* encoder/decoder read/writes data to/from here */
41 int t_offset; 41 int t_offset;
42 42
43 int min_size; 43 int min_size;
44 int s_offset; 44 int s_offset;
45 char *s_buf; /* used when read it not big enough to handle min_size for decoder/encoder */ 45 char *s_buf; /* used when read it not big enough to handle min_size for decoder/encoder */
46 46
47 int offset; /* current stream offset */ 47 int offset; /* current stream offset */
48 int line_len; 48 int line_len;
49 49
50 int w_rhd; /* working buffer read head */ 50 int w_rhd; /* working buffer read head */
51 int w_whd; /* working buffer write head */ 51 int w_whd; /* working buffer write head */
52 char w_buf[MU_TRANS_BSIZE]; /* working source/dest buffer */ 52 char w_buf[MU_TRANS_BSIZE]; /* working source/dest buffer */
53 53
54 int (*transcoder)(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len); 54 int (*transcoder)(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len);
55 }; 55 };
56 56
57 struct _ts_desc 57 struct _ts_desc
58 { 58 {
59 const char *encoding; 59 const char *encoding;
60 60
...@@ -72,14 +72,15 @@ static int _qp_decode(const char *iptr, size_t isize, char *optr, size_t osize, ...@@ -72,14 +72,15 @@ 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 { "quoted-printable", _qp_init, _qp_decode, _qp_encode}, 76 { "base64", _base64_init, _base64_decode, _base64_encode},
77 { "7bit", NULL}, 77 { "quoted-printable", _qp_init, _qp_decode, _qp_encode},
78 { "8bit", NULL}, 78 { "7bit", NULL, NULL, NULL},
79 { "binary", NULL} 79 { "8bit", NULL, NULL, NULL},
80 }; 80 { "binary", NULL, NULL, NULL}
81 81 };
82 static void 82
83 static void
83 _trans_destroy(stream_t stream) 84 _trans_destroy(stream_t stream)
84 { 85 {
85 struct _trans_stream *ts = stream_get_owner(stream); 86 struct _trans_stream *ts = stream_get_owner(stream);
...@@ -88,13 +89,13 @@ _trans_destroy(stream_t stream) ...@@ -88,13 +89,13 @@ _trans_destroy(stream_t stream)
88 free(ts); 89 free(ts);
89 } 90 }
90 91
91 static int 92 static int
92 _trans_read(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nbytes) 93 _trans_read(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nbytes)
93 { 94 {
94 struct _trans_stream *ts = stream_get_owner(stream); 95 struct _trans_stream *ts = stream_get_owner(stream);
95 size_t obytes, wbytes; 96 size_t obytes, wbytes;
96 int ret = 0, i; 97 int ret = 0, i;
97 98
98 if ( nbytes == NULL || optr == NULL || osize == 0 ) 99 if ( nbytes == NULL || optr == NULL || osize == 0 )
99 return EINVAL; 100 return EINVAL;
100 101
...@@ -107,7 +108,7 @@ _trans_read(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nby ...@@ -107,7 +108,7 @@ _trans_read(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nby
107 108
108 if ( offset == 0 ) 109 if ( offset == 0 )
109 ts->s_offset = ts->t_offset = ts->w_whd = ts->w_rhd = ts->offset = ts->line_len = 0; 110 ts->s_offset = ts->t_offset = ts->w_whd = ts->w_rhd = ts->offset = ts->line_len = 0;
110 111
111 while ( *nbytes < osize ) { 112 while ( *nbytes < osize ) {
112 if ( ( ts->w_rhd + ts->min_size ) >= ts->w_whd ) { 113 if ( ( ts->w_rhd + ts->min_size ) >= ts->w_whd ) {
113 memmove(ts->w_buf, ts->w_buf + ts->w_rhd, ts->w_whd - ts->w_rhd); 114 memmove(ts->w_buf, ts->w_buf + ts->w_rhd, ts->w_whd - ts->w_rhd);
...@@ -149,11 +150,10 @@ _trans_read(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nby ...@@ -149,11 +150,10 @@ _trans_read(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nby
149 } 150 }
150 151
151 152
152 static int 153 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;
...@@ -171,7 +171,7 @@ _trans_write(stream_t stream, const char *iptr, size_t isize, off_t offset, size ...@@ -171,7 +171,7 @@ _trans_write(stream_t stream, const char *iptr, size_t isize, off_t offset, size
171 return EINVAL; 171 return EINVAL;
172 } 172 }
173 173
174 static int 174 static int
175 _trans_open (stream_t stream, const char *filename, int port, int flags) 175 _trans_open (stream_t stream, const char *filename, int port, int flags)
176 { 176 {
177 struct _trans_stream *ts = stream_get_owner(stream); 177 struct _trans_stream *ts = stream_get_owner(stream);
...@@ -179,7 +179,7 @@ _trans_open (stream_t stream, const char *filename, int port, int flags) ...@@ -179,7 +179,7 @@ _trans_open (stream_t stream, const char *filename, int port, int flags)
179 return stream_open(ts->stream, filename, port, flags); 179 return stream_open(ts->stream, filename, port, flags);
180 } 180 }
181 181
182 static int 182 static int
183 _trans_truncate (stream_t stream, off_t len) 183 _trans_truncate (stream_t stream, off_t len)
184 { 184 {
185 struct _trans_stream *ts = stream_get_owner(stream); 185 struct _trans_stream *ts = stream_get_owner(stream);
...@@ -187,22 +187,22 @@ _trans_truncate (stream_t stream, off_t len) ...@@ -187,22 +187,22 @@ _trans_truncate (stream_t stream, off_t len)
187 return stream_truncate(ts->stream, len); 187 return stream_truncate(ts->stream, len);
188 } 188 }
189 189
190 static int 190 static int
191 _trans_size (stream_t stream, off_t *psize) 191 _trans_size (stream_t stream, off_t *psize)
192 { 192 {
193 struct _trans_stream *ts = stream_get_owner(stream); 193 struct _trans_stream *ts = stream_get_owner(stream);
194 194
195 return stream_size(ts->stream, psize); 195 return stream_size(ts->stream, psize);
196 } 196 }
197 197
198 static int 198 static int
199 _trans_flush (stream_t stream) 199 _trans_flush (stream_t stream)
200 { 200 {
201 struct _trans_stream *ts = stream_get_owner(stream); 201 struct _trans_stream *ts = stream_get_owner(stream);
202 202
203 return stream_flush(ts->stream); 203 return stream_flush(ts->stream);
204 } 204 }
205 static int 205 static int
206 _trans_get_fd (stream_t stream, int *pfd) 206 _trans_get_fd (stream_t stream, int *pfd)
207 { 207 {
208 struct _trans_stream *ts = stream_get_owner(stream); 208 struct _trans_stream *ts = stream_get_owner(stream);
...@@ -210,7 +210,7 @@ _trans_get_fd (stream_t stream, int *pfd) ...@@ -210,7 +210,7 @@ _trans_get_fd (stream_t stream, int *pfd)
210 return stream_get_fd(ts->stream, pfd); 210 return stream_get_fd(ts->stream, pfd);
211 } 211 }
212 212
213 static int 213 static int
214 _trans_close (stream_t stream) 214 _trans_close (stream_t stream)
215 { 215 {
216 struct _trans_stream *ts = stream_get_owner(stream); 216 struct _trans_stream *ts = stream_get_owner(stream);
...@@ -222,7 +222,7 @@ _trans_close (stream_t stream) ...@@ -222,7 +222,7 @@ _trans_close (stream_t stream)
222 * base64 encode/decode 222 * base64 encode/decode
223 *----------------------------------------------------*/ 223 *----------------------------------------------------*/
224 224
225 static int 225 static int
226 _b64_input(char c) 226 _b64_input(char c)
227 { 227 {
228 const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 228 const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
...@@ -235,7 +235,7 @@ _b64_input(char c) ...@@ -235,7 +235,7 @@ _b64_input(char c)
235 return -1; 235 return -1;
236 } 236 }
237 237
238 static int 238 static int
239 _base64_init(struct _trans_stream *ts, int type) 239 _base64_init(struct _trans_stream *ts, int type)
240 { 240 {
241 ts->min_size = 4; 241 ts->min_size = 4;
...@@ -244,7 +244,7 @@ _base64_init(struct _trans_stream *ts, int type) ...@@ -244,7 +244,7 @@ _base64_init(struct _trans_stream *ts, int type)
244 return 0; 244 return 0;
245 } 245 }
246 246
247 static int 247 static int
248 _base64_decode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len) 248 _base64_decode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len)
249 { 249 {
250 int i = 0, tmp = 0, pad = 0; 250 int i = 0, tmp = 0, pad = 0;
...@@ -281,13 +281,13 @@ _base64_decode(const char *iptr, size_t isize, char *optr, size_t osize, size_t ...@@ -281,13 +281,13 @@ _base64_decode(const char *iptr, size_t isize, char *optr, size_t osize, size_t
281 } 281 }
282 282
283 #define BASE64_LINE_MAX 77 283 #define BASE64_LINE_MAX 77
284 static int 284 static int
285 _base64_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len) 285 _base64_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len)
286 { 286 {
287 size_t consumed = 0; 287 size_t consumed = 0;
288 int pad = 0; 288 int pad = 0;
289 const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 289 const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
290 290
291 *nbytes = 0; 291 *nbytes = 0;
292 if ( isize <= 3 ) 292 if ( isize <= 3 )
293 pad = 1; 293 pad = 1;
...@@ -317,7 +317,7 @@ _base64_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t ...@@ -317,7 +317,7 @@ _base64_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t
317 *------------------------------------------------------*/ 317 *------------------------------------------------------*/
318 static const char _hexdigits[16] = "0123456789ABCDEF"; 318 static const char _hexdigits[16] = "0123456789ABCDEF";
319 319
320 static int 320 static int
321 _qp_init(struct _trans_stream *ts, int type) 321 _qp_init(struct _trans_stream *ts, int type)
322 { 322 {
323 ts->min_size = 4; 323 ts->min_size = 4;
...@@ -326,7 +326,8 @@ _qp_init(struct _trans_stream *ts, int type) ...@@ -326,7 +326,8 @@ _qp_init(struct _trans_stream *ts, int type)
326 return 0; 326 return 0;
327 } 327 }
328 328
329 static int 329 #if 0
330 static int
330 _ishex(int c) 331 _ishex(int c)
331 { 332 {
332 int i; 333 int i;
...@@ -340,8 +341,9 @@ _ishex(int c) ...@@ -340,8 +341,9 @@ _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)
346 { 348 {
347 char c; 349 char c;
...@@ -403,7 +405,7 @@ _qp_decode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nby ...@@ -403,7 +405,7 @@ _qp_decode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nby
403 } 405 }
404 406
405 407
406 static int 408 static int
407 _qp_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len) 409 _qp_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len)
408 { 410 {
409 #define QP_LINE_MAX 76 411 #define QP_LINE_MAX 76
...@@ -449,7 +451,7 @@ _qp_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nby ...@@ -449,7 +451,7 @@ _qp_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nby
449 return consumed; 451 return consumed;
450 } 452 }
451 453
452 int 454 int
453 encoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding) 455 encoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding)
454 { 456 {
455 struct _trans_stream *ts; 457 struct _trans_stream *ts;
...@@ -479,7 +481,7 @@ encoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding) ...@@ -479,7 +481,7 @@ encoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding)
479 stream_set_flush(*stream, _trans_flush, ts ); 481 stream_set_flush(*stream, _trans_flush, ts );
480 ts->stream = iostream; 482 ts->stream = iostream;
481 if ( tslist[i]._init != NULL && (ret = tslist[i]._init(ts, MU_TRANS_ENCODE)) != 0 ) 483 if ( tslist[i]._init != NULL && (ret = tslist[i]._init(ts, MU_TRANS_ENCODE)) != 0 )
482 stream_destroy(stream, NULL); 484 stream_destroy(stream, NULL);
483 else { 485 else {
484 stream_set_read(*stream, _trans_read, ts ); 486 stream_set_read(*stream, _trans_read, ts );
485 stream_set_write(*stream, _trans_write, ts ); 487 stream_set_write(*stream, _trans_write, ts );
...@@ -488,7 +490,7 @@ encoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding) ...@@ -488,7 +490,7 @@ encoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding)
488 return ret; 490 return ret;
489 } 491 }
490 492
491 int 493 int
492 decoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding) 494 decoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding)
493 { 495 {
494 struct _trans_stream *ts; 496 struct _trans_stream *ts;
...@@ -519,7 +521,7 @@ decoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding) ...@@ -519,7 +521,7 @@ decoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding)
519 stream_set_flush(*stream, _trans_flush, ts ); 521 stream_set_flush(*stream, _trans_flush, ts );
520 ts->stream = iostream; 522 ts->stream = iostream;
521 if ( tslist[i]._init != NULL && (ret = tslist[i]._init(ts, MU_TRANS_DECODE)) != 0 ) 523 if ( tslist[i]._init != NULL && (ret = tslist[i]._init(ts, MU_TRANS_DECODE)) != 0 )
522 stream_destroy(stream, NULL); 524 stream_destroy(stream, NULL);
523 else { 525 else {
524 stream_set_read(*stream, _trans_read, ts ); 526 stream_set_read(*stream, _trans_read, ts );
525 stream_set_write(*stream, _trans_write, ts ); 527 stream_set_write(*stream, _trans_write, ts );
......