mbox-sync-parse.c revision 84e1634acc701d14e358e27f1beff5ad74f5004a
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (C) 2004 Timo Sirainen */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen/* MD5 header summing logic was pretty much copy&pasted from popa3d by
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen Solar Designer */
65cca8364f483126b396aeb2036dc879ad45ab8dTimo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "lib.h"
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen#include "ioloop.h"
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen#include "buffer.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include "istream.h"
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen#include "str.h"
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen#include "write-full.h"
b1f37113a5760bee842c5a7678bb5fa6f5bd8b60Timo Sirainen#include "message-parser.h"
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen#include "mail-index.h"
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen#include "mbox-storage.h"
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainen#include "mbox-md5.h"
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen#include "mbox-sync-private.h"
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include <stdlib.h>
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen#define IS_LWSP_LF(c) (IS_LWSP(c) || (c) == '\n')
13d98ffa534f2e7d04a832c9d0153fc9c568b878Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstruct mbox_sync_header_func {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *header;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen int (*func)(struct mbox_sync_mail_context *ctx,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct message_header_line *hdr);
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen};
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainenstruct mbox_flag_type mbox_status_flags[] = {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen { 'R', MAIL_SEEN },
1bf1a24a902d5861f577df3d39e27b373b12c719Timo Sirainen { 'O', MBOX_NONRECENT_KLUDGE },
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen { 0, 0 }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen};
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
1bf1a24a902d5861f577df3d39e27b373b12c719Timo Sirainenstruct mbox_flag_type mbox_xstatus_flags[] = {
1bf1a24a902d5861f577df3d39e27b373b12c719Timo Sirainen { 'A', MAIL_ANSWERED },
1bf1a24a902d5861f577df3d39e27b373b12c719Timo Sirainen { 'F', MAIL_FLAGGED },
1bf1a24a902d5861f577df3d39e27b373b12c719Timo Sirainen { 'T', MAIL_DRAFT },
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen { 'D', MAIL_DELETED },
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen { 0, 0 }
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen};
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainenstatic void parse_trailing_whitespace(struct mbox_sync_mail_context *ctx,
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen struct message_header_line *hdr)
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen{
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen size_t i, space = 0;
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* the value may contain newlines. we can't count whitespace before
220e21750948941dc6e33b8f11b552fa21d7f81eTimo Sirainen and after it as a single contiguous whitespace block, as that may
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen get us into situation where removing whitespace goes eg.
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen " \n \n" -> " \n\n" which would then be treated as end of headers.
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen that could probably be avoided by being careful, but as newlines
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen should never be there (we don't generate them), it's not worth the
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen trouble. */
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen for (i = hdr->full_value_len; i > 0; i--) {
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen if (!IS_LWSP(hdr->full_value[i-1]))
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen break;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen space++;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen }
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen if ((ssize_t)space > ctx->mail.space) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_assert(space != 0);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ctx->mail.offset = hdr->full_value_offset + i;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ctx->mail.space = space;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic enum mail_flags mbox_flag_find(struct mbox_flag_type *flags, char chr)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen int i;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen for (i = 0; flags[i].chr != 0; i++) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (flags[i].chr == chr)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return flags[i].flag;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return 0;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenstatic void parse_status_flags(struct mbox_sync_mail_context *ctx,
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen struct message_header_line *hdr,
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen struct mbox_flag_type *flags_list)
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen size_t i;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ctx->mail.flags ^= MBOX_NONRECENT_KLUDGE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen for (i = 0; i < hdr->full_value_len; i++) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ctx->mail.flags |=
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mbox_flag_find(flags_list, hdr->full_value[i]);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ctx->mail.flags ^= MBOX_NONRECENT_KLUDGE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic int parse_status(struct mbox_sync_mail_context *ctx,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct message_header_line *hdr)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen parse_status_flags(ctx, hdr, mbox_status_flags);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ctx->hdr_pos[MBOX_HDR_STATUS] = str_len(ctx->header);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return TRUE;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen}
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainenstatic int parse_x_status(struct mbox_sync_mail_context *ctx,
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen struct message_header_line *hdr)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen{
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen parse_status_flags(ctx, hdr, mbox_xstatus_flags);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen ctx->hdr_pos[MBOX_HDR_X_STATUS] = str_len(ctx->header);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen return TRUE;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen}
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainenstatic void
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainenparse_imap_keywords_list(struct mbox_sync_mail_context *ctx,
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen struct message_header_line *hdr, size_t pos)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen const char *keyword;
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen size_t keyword_start;
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen unsigned int idx, count;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen count = 0;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen while (pos < hdr->full_value_len) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (IS_LWSP_LF(hdr->full_value[pos])) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pos++;
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen continue;
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* read the keyword */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen keyword_start = pos;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen for (; pos < hdr->full_value_len; pos++) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (IS_LWSP_LF(hdr->full_value[pos]))
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen break;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* add it to index's keyword list if it's not there already */
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen t_push();
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen keyword = t_strndup(hdr->full_value + keyword_start,
63e207529879438e9f4412d97cdc34bdc82a3702Timo Sirainen pos - keyword_start);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen (void)mail_index_keyword_lookup(ctx->sync_ctx->ibox->index,
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen keyword, TRUE, &idx);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen t_pop();
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen count++;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen }
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (count != array_count(ctx->sync_ctx->ibox->keyword_names)) {
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen /* need to update this list */
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen ctx->imapbase_rewrite = TRUE;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen ctx->need_rewrite = TRUE;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic int parse_x_imap_base(struct mbox_sync_mail_context *ctx,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct message_header_line *hdr)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen size_t i, j, uid_last_pos;
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen uint32_t uid_validity, uid_last;
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen if (ctx->seq != 1 || ctx->seen_imapbase) {
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen /* Valid only in first message */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return FALSE;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen /* <uid-validity> 10x<uid-last> */
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen for (i = 0, uid_validity = 0; i < hdr->full_value_len; i++) {
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen if (hdr->full_value[i] < '0' || hdr->full_value[i] > '9') {
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen if (hdr->full_value[i] != ' ')
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen return FALSE;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen break;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen }
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen uid_validity = uid_validity * 10 + (hdr->full_value[i] - '0');
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen }
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen if (uid_validity == 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* broken */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return FALSE;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
5214b67a7dabab87da74e04bb8b227f94b95bce4Timo Sirainen for (; i < hdr->full_value_len; i++) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (!IS_LWSP_LF(hdr->full_value[i]))
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen break;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
27586e4785d56aeb76e1fd96af8db799688dc64aTimo Sirainen uid_last_pos = i;
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen for (uid_last = 0, j = 0; i < hdr->full_value_len; i++, j++) {
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen if (hdr->full_value[i] < '0' || hdr->full_value[i] > '9') {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (!IS_LWSP_LF(hdr->full_value[i]))
5214b67a7dabab87da74e04bb8b227f94b95bce4Timo Sirainen return FALSE;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen break;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen uid_last = uid_last * 10 + (hdr->full_value[i] - '0');
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (j != 10) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* uid-last field must be exactly 10 characters to make
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen rewriting it easier. */
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen ctx->imapbase_rewrite = TRUE;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ctx->need_rewrite = TRUE;
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen } else {
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen ctx->last_uid_value_start_pos = uid_last_pos;
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen ctx->sync_ctx->base_uid_last_offset =
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen hdr->full_value_offset + uid_last_pos;
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen }
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen if (ctx->sync_ctx->next_uid-1 <= uid_last) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* new messages have been added since our last sync.
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen just update our internal next_uid. */
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk ctx->sync_ctx->next_uid = uid_last+1;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk }
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_assert(ctx->sync_ctx->next_uid > ctx->sync_ctx->prev_msg_uid);
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk if (ctx->sync_ctx->base_uid_validity == 0) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk /* first time parsing this (ie. we're not rewriting).
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk save the values. */
7920a47321690c932ffd4d286cd16b4048d22d41Timo Sirainen ctx->sync_ctx->base_uid_validity = uid_validity;
7920a47321690c932ffd4d286cd16b4048d22d41Timo Sirainen ctx->sync_ctx->base_uid_last = uid_last;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen ctx->hdr_pos[MBOX_HDR_X_IMAPBASE] = str_len(ctx->header);
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen ctx->seen_imapbase = TRUE;
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen parse_imap_keywords_list(ctx, hdr, i);
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen parse_trailing_whitespace(ctx, hdr);
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen return TRUE;
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen}
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainenstatic int parse_x_imap(struct mbox_sync_mail_context *ctx,
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen struct message_header_line *hdr)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen{
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (!parse_x_imap_base(ctx, hdr))
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return FALSE;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* this is the c-client style "FOLDER INTERNAL DATA" message.
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen skip it. */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen ctx->pseudo = TRUE;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen return TRUE;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen}
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainenstatic int parse_x_keywords(struct mbox_sync_mail_context *ctx,
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen struct message_header_line *hdr)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen{
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen array_t ARRAY_DEFINE(keyword_list, unsigned int);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen string_t *keyword;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen size_t keyword_start;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen unsigned int idx;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen size_t pos;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (array_is_created(&ctx->mail.keywords))
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen return FALSE; /* duplicate header, delete */
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen /* read keyword indexes to temporary array first */
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen t_push();
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen keyword = t_str_new(128);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen ARRAY_CREATE(&keyword_list, pool_datastack_create(), unsigned int, 16);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen for (pos = 0; pos < hdr->full_value_len; ) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (IS_LWSP_LF(hdr->full_value[pos])) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen pos++;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen continue;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen }
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* read the keyword string */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen keyword_start = pos;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen for (; pos < hdr->full_value_len; pos++) {
5c597df6aa8d81de4053c6986fab7739f3b44b20Timo Sirainen if (IS_LWSP_LF(hdr->full_value[pos]))
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen break;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen }
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen str_truncate(keyword, 0);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen str_append_n(keyword, hdr->full_value + keyword_start,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen pos - keyword_start);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (!mail_index_keyword_lookup(ctx->sync_ctx->ibox->index,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen str_c(keyword), FALSE, &idx)) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* keyword wasn't found. that means the sent mail
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen originally contained X-Keywords header. Delete it. */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen t_pop();
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen return FALSE;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen }
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen array_append(&keyword_list, &idx, 1);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* once we know how many keywords there are, we can allocate the array
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen from mail_keyword_pool without wasting memory. */
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (array_count(&keyword_list) > 0) {
5214b67a7dabab87da74e04bb8b227f94b95bce4Timo Sirainen ARRAY_CREATE(&ctx->mail.keywords,
5214b67a7dabab87da74e04bb8b227f94b95bce4Timo Sirainen ctx->sync_ctx->mail_keyword_pool,
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen unsigned int, array_count(&keyword_list));
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen array_append_array(&ctx->mail.keywords, &keyword_list);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] = str_len(ctx->header);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen parse_trailing_whitespace(ctx, hdr);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen t_pop();
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen return TRUE;
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen}
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainenstatic int parse_x_uid(struct mbox_sync_mail_context *ctx,
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen struct message_header_line *hdr)
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen{
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen uint32_t value = 0;
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen size_t i;
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (ctx->mail.uid != 0) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* duplicate */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen return FALSE;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen }
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen for (i = 0; i < hdr->full_value_len; i++) {
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen if (hdr->full_value[i] < '0' || hdr->full_value[i] > '9')
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen break;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen value = value*10 + (hdr->full_value[i] - '0');
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen for (; i < hdr->full_value_len; i++) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (!IS_LWSP_LF(hdr->full_value[i])) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* broken value */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return FALSE;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (ctx->sync_ctx == NULL) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* we're in mbox_sync_parse_match_mail().
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen don't do any extra checks. */
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen ctx->mail.uid = value;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen return TRUE;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (ctx->sync_ctx->dest_first_mail && !ctx->seen_imapbase) {
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen /* Don't bother allowing X-UID before X-IMAPbase
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen header. c-client doesn't allow it either, and this
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen way the UID doesn't have to be reset if X-IMAPbase
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen header isn't what we expect it to be. */
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen return FALSE;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (value == ctx->sync_ctx->next_uid) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* X-UID is the next expected one. allow it because
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen we'd just use this UID anyway. X-IMAPbase header
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen still needs to be updated for this. */
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen ctx->sync_ctx->next_uid++;
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen } else if (value > ctx->sync_ctx->next_uid) {
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen /* UID is larger than expected. Don't allow it because
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen incoming mails can contain untrusted X-UID fields,
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen causing possibly DoS if the UIDs get large enough. */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen ctx->uid_broken = TRUE;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return FALSE;
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen }
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (value <= ctx->sync_ctx->prev_msg_uid) {
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen /* broken - UIDs must be growing */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen ctx->uid_broken = TRUE;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return FALSE;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen ctx->sync_ctx->prev_msg_uid = value;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen ctx->mail.uid = value;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen ctx->hdr_pos[MBOX_HDR_X_UID] = str_len(ctx->header);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen ctx->parsed_uid = value;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen parse_trailing_whitespace(ctx, hdr);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen return TRUE;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen}
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainenstatic int parse_content_length(struct mbox_sync_mail_context *ctx,
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen struct message_header_line *hdr)
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen uoff_t value = 0;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen size_t i;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (ctx->content_length != (uoff_t)-1) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* duplicate */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return FALSE;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen for (i = 0; i < hdr->full_value_len; i++) {
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen if (hdr->full_value[i] < '0' || hdr->full_value[i] > '9')
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen break;
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen value = value*10 + (hdr->full_value[i] - '0');
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen }
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen for (; i < hdr->full_value_len; i++) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (!IS_LWSP_LF(hdr->full_value[i])) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* broken value */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return FALSE;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen ctx->content_length = value;
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen return TRUE;
4a514fb20e04df397842cde11cc9ea92abfe9728Timo Sirainen}
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenstatic struct mbox_sync_header_func header_funcs[] = {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen { "Content-Length", parse_content_length },
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen { "Status", parse_status },
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen { "X-IMAP", parse_x_imap },
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen { "X-IMAPbase", parse_x_imap_base },
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen { "X-Keywords", parse_x_keywords },
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen { "X-Status", parse_x_status },
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen { "X-UID", parse_x_uid }
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen};
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen#define HEADER_FUNCS_COUNT (sizeof(header_funcs) / sizeof(*header_funcs))
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenstatic int mbox_sync_bsearch_header_func_cmp(const void *p1, const void *p2)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen{
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen const char *key = p1;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen const struct mbox_sync_header_func *func = p2;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen return strcasecmp(key, func->header);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen}
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainenvoid mbox_sync_parse_next_mail(struct istream *input,
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen struct mbox_sync_mail_context *ctx)
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen{
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen struct mbox_sync_context *sync_ctx = ctx->sync_ctx;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen struct message_header_parser_ctx *hdr_ctx;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen struct message_header_line *hdr;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen struct mbox_sync_header_func *func;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen struct mbox_md5_context *mbox_md5_ctx;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen size_t line_start_pos;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen int i, ret;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen ctx->hdr_offset = ctx->mail.offset;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen ctx->mail.flags = MAIL_RECENT; /* default to having recent flag */
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen ctx->header_first_change = (size_t)-1;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen ctx->header_last_change = 0;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen for (i = 0; i < MBOX_HDR_COUNT; i++)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ctx->hdr_pos[i] = (size_t)-1;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ctx->content_length = (uoff_t)-1;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen str_truncate(ctx->header, 0);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mbox_md5_ctx = mbox_md5_init();
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen line_start_pos = 0;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen hdr_ctx = message_parse_header_init(input, NULL, FALSE);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen while ((ret = message_parse_header_next(hdr_ctx, &hdr)) > 0) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (hdr->eoh) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ctx->have_eoh = TRUE;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen break;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (!hdr->continued) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen line_start_pos = str_len(ctx->header);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen str_append(ctx->header, hdr->name);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen str_append_n(ctx->header, hdr->middle, hdr->middle_len);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen func = bsearch(hdr->name, header_funcs,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen HEADER_FUNCS_COUNT, sizeof(*header_funcs),
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mbox_sync_bsearch_header_func_cmp);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen if (func != NULL) {
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen if (hdr->continues) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen hdr->use_full_value = TRUE;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen continue;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (!func->func(ctx, hdr)) {
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen /* this header is broken, remove it */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (ctx->sync_ctx->sync_restart)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen break;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ctx->need_rewrite = TRUE;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen str_truncate(ctx->header, line_start_pos);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (ctx->header_first_change == (size_t)-1) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ctx->header_first_change =
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen line_start_pos;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen continue;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen buffer_append(ctx->header, hdr->full_value,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen hdr->full_value_len);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen } else {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen mbox_md5_continue(mbox_md5_ctx, hdr);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen buffer_append(ctx->header, hdr->value,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen hdr->value_len);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (!hdr->no_newline)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen str_append_c(ctx->header, '\n');
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen i_assert(ret != 0);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen message_parse_header_deinit(hdr_ctx);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen mbox_md5_finish(mbox_md5_ctx, ctx->hdr_md5_sum);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if ((ctx->seq == 1 && !ctx->seen_imapbase) ||
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen (ctx->seq > 1 && sync_ctx->dest_first_mail)) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* missing X-IMAPbase */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ctx->need_rewrite = TRUE;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (sync_ctx->base_uid_validity == 0) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* figure out a new UIDVALIDITY for us. */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen sync_ctx->base_uid_validity =
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen sync_ctx->hdr->uid_validity != 0 ?
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen sync_ctx->hdr->uid_validity :
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen I_MAX((uint32_t)ioloop_time, 1);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ctx->body_offset = input->v_offset;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenint mbox_sync_parse_match_mail(struct index_mailbox *ibox,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct mail_index_view *view, uint32_t seq)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct mbox_sync_mail_context ctx;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct message_header_parser_ctx *hdr_ctx;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct message_header_line *hdr;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct header_func *func;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct mbox_md5_context *mbox_md5_ctx;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen const void *data;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen uint32_t uid;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen int ret;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* we only wish to be sure that this mail actually is what we expect
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen it to be. If there's X-UID header, it's used. Otherwise use
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen the MD5 sum. */
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen memset(&ctx, 0, sizeof(ctx));
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen mbox_md5_ctx = mbox_md5_init();
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen hdr_ctx = message_parse_header_init(ibox->mbox_stream, NULL, FALSE);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen while ((ret = message_parse_header_next(hdr_ctx, &hdr)) > 0) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (hdr->eoh)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen break;
494a5de15db3b2806ab31d5ecc3e1c306ae14d06Timo Sirainen
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen func = bsearch(hdr->name, header_funcs,
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen HEADER_FUNCS_COUNT, sizeof(*header_funcs),
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen mbox_sync_bsearch_header_func_cmp);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (func != NULL) {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (strcasecmp(hdr->name, "X-UID") == 0) {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (hdr->continues) {
9d4c027e7de01ab948d6221bc27c9b45d32d1ea5Timo Sirainen hdr->use_full_value = TRUE;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen continue;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen (void)parse_x_uid(&ctx, hdr);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen if (ctx.mail.uid != 0)
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen break;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } else {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen mbox_md5_continue(mbox_md5_ctx, hdr);
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen }
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen }
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen i_assert(ret != 0);
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen message_parse_header_deinit(hdr_ctx);
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen mbox_md5_finish(mbox_md5_ctx, ctx.hdr_md5_sum);
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (ctx.mail.uid != 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* match by X-UID header */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (mail_index_lookup_uid(view, seq, &uid) < 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen mail_storage_set_index_error(ibox);
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen return -1;
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen }
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen return ctx.mail.uid == uid;
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen }
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen /* match by MD5 sum */
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen ibox->mbox_save_md5 = TRUE;
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (mail_index_lookup_ext(view, seq, ibox->md5hdr_ext_idx, &data) < 0) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen mail_storage_set_index_error(ibox);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return -1;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return data == NULL ? 0 :
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen memcmp(data, ctx.hdr_md5_sum, 16) == 0;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen