* 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.
Showing
14 changed files
with
719 additions
and
357 deletions
... | @@ -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) | ... | ... |
... | @@ -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,83 +521,78 @@ mbox_expunge (mailbox_t mailbox) | ... | @@ -512,83 +521,78 @@ 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); | 559 | { |
554 | if (tempfile == -1) | 560 | mbox_data_t tmp_mud; |
555 | { | 561 | char *m = alloca (5 + strlen (tmpmboxname) + 1); |
556 | free (tmpmboxname); | 562 | /* Try via the mbox: protocol. */ |
557 | fprintf (stderr, "Failed to create temporary file when expunging.\n"); | 563 | sprintf (m, "mbox:%s", tmpmboxname); |
558 | return errno; | 564 | status = mailbox_create (&tmpmailbox, m); |
559 | } | 565 | if (status != 0) |
560 | else | 566 | { |
561 | { | 567 | /* Do not give up just yet, maybe they register the path_record. */ |
562 | char *m = alloca (5 + strlen (tmpmboxname) + 1); | 568 | sprintf (m, "%s", tmpmboxname); |
563 | /* Try via the mbox: protocol. */ | 569 | status = mailbox_create (&tmpmailbox, m); |
564 | sprintf (m, "mbox:%s", tmpmboxname); | 570 | if (status != 0) |
565 | status = mailbox_create (&tmpmailbox, m); | 571 | { |
566 | if (status != 0) | 572 | /* Ok give up. */ |
567 | { | 573 | close (tempfile); |
568 | /* Do not give up just yet, maybe they register the path_record. */ | 574 | remove (tmpmboxname); |
569 | sprintf (m, "%s", tmpmboxname); | 575 | free (tmpmboxname); |
570 | status = mailbox_create (&tmpmailbox, m); | 576 | return status; |
571 | if (status != 0) | 577 | } |
572 | { | 578 | } |
573 | /* Ok give up. */ | ||
574 | close (tempfile); | ||
575 | remove (tmpmboxname); | ||
576 | free (tmpmboxname); | ||
577 | return status; | ||
578 | } | ||
579 | } | ||
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() |
582 | status = mailbox_open (tmpmailbox, MU_STREAM_CREAT | MU_STREAM_RDWR); | 581 | the file. */ |
583 | if (status != 0) | 582 | status = mailbox_open (tmpmailbox, MU_STREAM_CREAT | MU_STREAM_RDWR); |
584 | { | 583 | if (status != 0) |
585 | close (tempfile); | 584 | { |
586 | remove (tmpmboxname); | 585 | close (tempfile); |
587 | free (tmpmboxname); | 586 | remove (tmpmboxname); |
588 | return status; | 587 | free (tmpmboxname); |
589 | } | 588 | return status; |
590 | close (tempfile); /* This one is useless the mailbox have its own. */ | 589 | } |
591 | } | 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; | ||
595 | } | ||
592 | 596 | ||
593 | /* Get the File lock. */ | 597 | /* Get the File lock. */ |
594 | if (locker_lock (mailbox->locker, MU_LOCKER_WRLOCK) < 0) | 598 | if (locker_lock (mailbox->locker, MU_LOCKER_WRLOCK) < 0) |
... | @@ -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)) |
627 | continue; | 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; | ||
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,19 +996,26 @@ mbox_header_get_fvalue (header_t header, const char *name, char *buffer, | ... | @@ -964,19 +996,26 @@ 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++) |
967 | if (*name == *(fhdr_table[i]) && strcasecmp (fhdr_table[i], name) == 0) | 999 | { |
968 | { | 1000 | if (*name == *(fhdr_table[i]) && strcasecmp (fhdr_table[i], name) == 0) |
969 | fv_value = (mum->fhdr[i]) ? strlen (mum->fhdr[i]) : 0; | 1001 | { |
970 | if (buffer && buflen > 0) | 1002 | if (mum->fhdr[i]) |
971 | { | 1003 | { |
972 | buflen--; | 1004 | fv_value = strlen (mum->fhdr[i]); |
973 | fv_value = (fv_value < buflen) ? fv_value : buflen; | 1005 | if (buffer && buflen > 0) |
974 | memcpy (buffer, mum->fhdr[i], fv_value); | 1006 | { |
975 | buffer[fv_value] = '\0'; | 1007 | buflen--; |
976 | } | 1008 | fv_value = (fv_value < buflen) ? fv_value : buflen; |
977 | err = 0; | 1009 | memcpy (buffer, mum->fhdr[i], fv_value); |
978 | break; | 1010 | buffer[fv_value] = '\0'; |
979 | } | 1011 | } |
1012 | err = 0; | ||
1013 | } | ||
1014 | else | ||
1015 | err = ENOENT; | ||
1016 | break; | ||
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; | ||
1409 | |||
1410 | /* Write date. */ | ||
1411 | status = stream_write (mailbox->stream, mud->date, strlen(mud->date), | ||
1412 | *psize, &n); | ||
1413 | if (status != 0) | ||
1414 | break; | ||
1415 | *psize += n; | 1442 | *psize += n; |
1416 | 1443 | ||
1417 | status = stream_write (mailbox->stream, &nl , 1, *psize, &n); | 1444 | /* Add the newline, the above may be truncated. */ |
1418 | if (status != 0) | 1445 | stream_write (mailbox->stream, &nl , 1, *psize, &n); |
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; | 1693 | { |
1628 | for (total = j = 0; j < mud->messages_count; j++) | 1694 | mum = mud->umessages[j]; |
1695 | if (mum && ((mum->attr_flags == 0) || | ||
1696 | ! ((mum->attr_flags & MU_ATTRIBUTE_SEEN) | ||
1697 | && (mum->attr_flags & MU_ATTRIBUTE_READ)))) | ||
1698 | recent++; | ||
1699 | } | ||
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++) | ||
1629 | { | 1712 | { |
1630 | mum = mud->umessages[j]; | 1713 | mum = mud->umessages[j]; |
1631 | if (mum && mum->new_flags == 0) | 1714 | if (mum && ((mum->attr_flags == 0) || |
1632 | total++; | 1715 | ! ((mum->attr_flags & MU_ATTRIBUTE_SEEN) |
1716 | && (mum->attr_flags & MU_ATTRIBUTE_READ)))) | ||
1717 | { | ||
1718 | unseen = j + 1; | ||
1719 | break; | ||
1720 | } | ||
1633 | } | 1721 | } |
1634 | *pcount = total; | 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 | ... | ... |
... | @@ -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 ); | ... | ... |
-
Please register or sign in to post a comment