mbox-sync-parse.c revision 84e1634acc701d14e358e27f1beff5ad74f5004a
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (C) 2004 Timo Sirainen */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen/* MD5 header summing logic was pretty much copy&pasted from popa3d by
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen Solar Designer */
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen#define IS_LWSP_LF(c) (IS_LWSP(c) || (c) == '\n')
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen int (*func)(struct mbox_sync_mail_context *ctx,
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainenstatic void parse_trailing_whitespace(struct mbox_sync_mail_context *ctx,
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.
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
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ctx->mail.offset = hdr->full_value_offset + i;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic enum mail_flags mbox_flag_find(struct mbox_flag_type *flags, char chr)
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenstatic void parse_status_flags(struct mbox_sync_mail_context *ctx,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mbox_flag_find(flags_list, hdr->full_value[i]);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic int parse_status(struct mbox_sync_mail_context *ctx,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen parse_status_flags(ctx, hdr, mbox_status_flags);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ctx->hdr_pos[MBOX_HDR_STATUS] = str_len(ctx->header);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainenstatic int parse_x_status(struct mbox_sync_mail_context *ctx,
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen parse_status_flags(ctx, hdr, mbox_xstatus_flags);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen ctx->hdr_pos[MBOX_HDR_X_STATUS] = str_len(ctx->header);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainenparse_imap_keywords_list(struct mbox_sync_mail_context *ctx,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* read the keyword */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* add it to index's keyword list if it's not there already */
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen keyword = t_strndup(hdr->full_value + keyword_start,
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen (void)mail_index_keyword_lookup(ctx->sync_ctx->ibox->index,
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (count != array_count(ctx->sync_ctx->ibox->keyword_names)) {
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen /* need to update this list */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic int parse_x_imap_base(struct mbox_sync_mail_context *ctx,
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen /* Valid only in first message */
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 uid_validity = uid_validity * 10 + (hdr->full_value[i] - '0');
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 uid_last = uid_last * 10 + (hdr->full_value[i] - '0');
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (j != 10) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* uid-last field must be exactly 10 characters to make
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen rewriting it easier. */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* new messages have been added since our last sync.
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen just update our internal next_uid. */
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_assert(ctx->sync_ctx->next_uid > ctx->sync_ctx->prev_msg_uid);
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;
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen ctx->hdr_pos[MBOX_HDR_X_IMAPBASE] = str_len(ctx->header);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainenstatic int parse_x_imap(struct mbox_sync_mail_context *ctx,
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* this is the c-client style "FOLDER INTERNAL DATA" message.
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainenstatic int parse_x_keywords(struct mbox_sync_mail_context *ctx,
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen array_t ARRAY_DEFINE(keyword_list, unsigned int);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen unsigned int idx;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen /* read keyword indexes to temporary array first */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen ARRAY_CREATE(&keyword_list, pool_datastack_create(), unsigned int, 16);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* read the keyword string */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen str_append_n(keyword, hdr->full_value + keyword_start,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (!mail_index_keyword_lookup(ctx->sync_ctx->ibox->index,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* keyword wasn't found. that means the sent mail
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen originally contained X-Keywords header. Delete it. */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* once we know how many keywords there are, we can allocate the array
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen from mail_keyword_pool without wasting memory. */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen array_append_array(&ctx->mail.keywords, &keyword_list);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] = str_len(ctx->header);
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainenstatic int parse_x_uid(struct mbox_sync_mail_context *ctx,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* duplicate */
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen if (hdr->full_value[i] < '0' || hdr->full_value[i] > '9')
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen value = value*10 + (hdr->full_value[i] - '0');
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* broken value */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* we're in mbox_sync_parse_match_mail().
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen don't do any extra checks. */
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. */
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. */
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. */
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen /* broken - UIDs must be growing */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen ctx->hdr_pos[MBOX_HDR_X_UID] = str_len(ctx->header);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainenstatic int parse_content_length(struct mbox_sync_mail_context *ctx,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* duplicate */
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen if (hdr->full_value[i] < '0' || hdr->full_value[i] > '9')
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen value = value*10 + (hdr->full_value[i] - '0');
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* broken value */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenstatic struct mbox_sync_header_func header_funcs[] = {
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen#define HEADER_FUNCS_COUNT (sizeof(header_funcs) / sizeof(*header_funcs))
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenstatic int mbox_sync_bsearch_header_func_cmp(const void *p1, const void *p2)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen const struct mbox_sync_header_func *func = p2;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainenvoid mbox_sync_parse_next_mail(struct istream *input,
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen struct mbox_sync_context *sync_ctx = ctx->sync_ctx;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen ctx->mail.flags = MAIL_RECENT; /* default to having recent flag */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen for (i = 0; i < MBOX_HDR_COUNT; i++)
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 str_append_n(ctx->header, hdr->middle, hdr->middle_len);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen /* this header is broken, remove it */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen mbox_md5_finish(mbox_md5_ctx, ctx->hdr_md5_sum);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen (ctx->seq > 1 && sync_ctx->dest_first_mail)) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* missing X-IMAPbase */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* figure out a new UIDVALIDITY for us. */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenint mbox_sync_parse_match_mail(struct index_mailbox *ibox,
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. */
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) {
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen mbox_md5_finish(mbox_md5_ctx, ctx.hdr_md5_sum);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* match by X-UID header */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (mail_index_lookup_uid(view, seq, &uid) < 0) {
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen /* match by MD5 sum */