mbox-sync-parse.c revision 6825360d446542046757b06064282301c4c6b27c
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (C) 2004 Timo Sirainen */
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde/* MD5 header summing logic was pretty much copy&pasted from popa3d by
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen Solar Designer */
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "lib.h"
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen#include "ioloop.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "array.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "buffer.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "istream.h"
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen#include "str.h"
d99107ddf4d9bccb710994482daf65276a9d6321Timo Sirainen#include "write-full.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "message-parser.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "mail-index.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "mbox-storage.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "mbox-md5.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "mbox-sync-private.h"
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen#include <stdlib.h>
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen#define IS_LWSP_LF(c) (IS_LWSP(c) || (c) == '\n')
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
fc71e94957d0c2959a609450a2f303640d681858Sascha Wildestruct mbox_sync_header_func {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen const char *header;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde bool (*func)(struct mbox_sync_mail_context *ctx,
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct message_header_line *hdr);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen};
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenstruct mbox_flag_type mbox_status_flags[] = {
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen { 'R', MAIL_SEEN },
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen { 'O', MBOX_NONRECENT_KLUDGE },
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde { 0, 0 }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen};
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc71e94957d0c2959a609450a2f303640d681858Sascha Wildestruct mbox_flag_type mbox_xstatus_flags[] = {
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde { 'A', MAIL_ANSWERED },
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen { 'F', MAIL_FLAGGED },
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen { 'T', MAIL_DRAFT },
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde { 'D', MAIL_DELETED },
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen { 0, 0 }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen};
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenstatic void parse_trailing_whitespace(struct mbox_sync_mail_context *ctx,
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct message_header_line *hdr)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde{
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen size_t i, space = 0;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* the value may contain newlines. we can't count whitespace before
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde and after it as a single contiguous whitespace block, as that may
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde get us into situation where removing whitespace goes eg.
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen " \n \n" -> " \n\n" which would then be treated as end of headers.
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen that could probably be avoided by being careful, but as newlines
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen should never be there (we don't generate them), it's not worth the
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen trouble. */
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen for (i = hdr->full_value_len; i > 0; i--) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (!IS_LWSP(hdr->full_value[i-1]))
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen break;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen space++;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if ((ssize_t)space > ctx->mail.space) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen i_assert(space != 0);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx->mail.offset = ctx->hdr_offset + str_len(ctx->header) + i;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx->mail.space = space;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen}
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic enum mail_flags mbox_flag_find(struct mbox_flag_type *flags, char chr)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde{
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen int i;
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde for (i = 0; flags[i].chr != 0; i++) {
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen if (flags[i].chr == chr)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde return flags[i].flag;
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return 0;
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen}
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
fc71e94957d0c2959a609450a2f303640d681858Sascha Wildestatic void parse_status_flags(struct mbox_sync_mail_context *ctx,
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde struct message_header_line *hdr,
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde struct mbox_flag_type *flags_list)
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen{
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde size_t i;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde ctx->mail.flags ^= MBOX_NONRECENT_KLUDGE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen for (i = 0; i < hdr->full_value_len; i++) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen ctx->mail.flags |=
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen mbox_flag_find(flags_list, hdr->full_value[i]);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen ctx->mail.flags ^= MBOX_NONRECENT_KLUDGE;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde}
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenstatic bool parse_status(struct mbox_sync_mail_context *ctx,
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde struct message_header_line *hdr)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde{
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen parse_status_flags(ctx, hdr, mbox_status_flags);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde ctx->hdr_pos[MBOX_HDR_STATUS] = str_len(ctx->header);
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen return TRUE;
1c6dd898551d7d4d61970b24a8372438f6b72f97Timo Sirainen}
1c6dd898551d7d4d61970b24a8372438f6b72f97Timo Sirainen
fc71e94957d0c2959a609450a2f303640d681858Sascha Wildestatic bool parse_x_status(struct mbox_sync_mail_context *ctx,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen struct message_header_line *hdr)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde{
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde parse_status_flags(ctx, hdr, mbox_xstatus_flags);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde ctx->hdr_pos[MBOX_HDR_X_STATUS] = str_len(ctx->header);
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen return TRUE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen}
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenstatic bool keyword_is_valid(const char *keyword)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen{
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* try to only prevent the most malicious looking keywords. */
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen for (; *keyword != '\0'; keyword++) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (*keyword == '(' || *keyword == ')' ||
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen *keyword == '{' || *keyword == '}' ||
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen *keyword == '\\' || *keyword == '"' ||
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen (unsigned char)*keyword <= 32)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return FALSE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return TRUE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen}
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenstatic void
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenparse_imap_keywords_list(struct mbox_sync_mail_context *ctx,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen struct message_header_line *hdr, size_t pos)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen{
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen const char *keyword;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen size_t keyword_start;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen unsigned int idx, count;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen count = 0;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen while (pos < hdr->full_value_len) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (IS_LWSP_LF(hdr->full_value[pos])) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen pos++;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde continue;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde }
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen /* read the keyword */
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen keyword_start = pos;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen for (; pos < hdr->full_value_len; pos++) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (IS_LWSP_LF(hdr->full_value[pos]))
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen break;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen /* add it to index's keyword list if it's not there already */
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen t_push();
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen keyword = t_strndup(hdr->full_value + keyword_start,
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen pos - keyword_start);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (keyword_is_valid(keyword)) {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen mail_index_keyword_lookup_or_create(
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen ctx->sync_ctx->mbox->ibox.index, keyword, &idx);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen t_pop();
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen count++;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen if (count != array_count(ctx->sync_ctx->mbox->ibox.keyword_names)) {
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen /* need to update this list */
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx->imapbase_rewrite = TRUE;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen ctx->need_rewrite = TRUE;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen }
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen}
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainenstatic bool parse_x_imap_base(struct mbox_sync_mail_context *ctx,
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen struct message_header_line *hdr)
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen{
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen size_t i, j, uid_last_pos;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen uint32_t uid_validity, uid_last;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (ctx->seq != 1 || ctx->seen_imapbase ||
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen ctx->sync_ctx->renumber_uids) {
2ba63f475f74b2aa87f9fd9e28a6c5738deb0878Timo Sirainen /* Valid only in first message */
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen return FALSE;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen }
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen /* <uid-validity> 10x<uid-last> */
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen for (i = 0, uid_validity = 0; i < hdr->full_value_len; i++) {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (hdr->full_value[i] < '0' || hdr->full_value[i] > '9') {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (hdr->full_value[i] != ' ')
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen return FALSE;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen break;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen }
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen uid_validity = uid_validity * 10 + (hdr->full_value[i] - '0');
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen }
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (uid_validity == 0) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen /* broken */
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen return FALSE;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen for (; i < hdr->full_value_len; i++) {
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen if (!IS_LWSP_LF(hdr->full_value[i]))
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen break;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen }
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen uid_last_pos = i;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen for (uid_last = 0, j = 0; i < hdr->full_value_len; i++, j++) {
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen if (hdr->full_value[i] < '0' || hdr->full_value[i] > '9') {
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen if (!IS_LWSP_LF(hdr->full_value[i]))
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen return FALSE;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen break;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen }
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen uid_last = uid_last * 10 + (hdr->full_value[i] - '0');
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen }
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen if (j != 10 ||
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen hdr->full_value_offset != ctx->hdr_offset + str_len(ctx->header)) {
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen /* uid-last field must be exactly 10 characters to make
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen rewriting it easier. also don't try to do this if some
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen headers have been removed */
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen ctx->imapbase_rewrite = TRUE;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen ctx->need_rewrite = TRUE;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen } else {
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen ctx->last_uid_value_start_pos = uid_last_pos;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen ctx->sync_ctx->base_uid_last_offset =
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen hdr->full_value_offset + uid_last_pos;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen }
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen if (ctx->sync_ctx->base_uid_validity == 0) {
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde /* first time parsing this (ie. we're not rewriting).
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen save the values. */
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen ctx->sync_ctx->base_uid_validity = uid_validity;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde ctx->sync_ctx->base_uid_last = uid_last;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde if (ctx->sync_ctx->next_uid-1 <= uid_last) {
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde /* new messages have been added since our last sync.
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde just update our internal next_uid. */
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde ctx->sync_ctx->next_uid = uid_last+1;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen } else {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen /* we need to rewrite the next-uid */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen ctx->need_rewrite = TRUE;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde i_assert(ctx->sync_ctx->next_uid > ctx->sync_ctx->prev_msg_uid);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx->hdr_pos[MBOX_HDR_X_IMAPBASE] = str_len(ctx->header);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen ctx->seen_imapbase = TRUE;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde parse_imap_keywords_list(ctx, hdr, i);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde parse_trailing_whitespace(ctx, hdr);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde return TRUE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen}
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
fc71e94957d0c2959a609450a2f303640d681858Sascha Wildestatic bool parse_x_imap(struct mbox_sync_mail_context *ctx,
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde struct message_header_line *hdr)
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen{
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen if (!parse_x_imap_base(ctx, hdr))
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen return FALSE;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen /* this is the c-client style "FOLDER INTERNAL DATA" message.
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen skip it. */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen ctx->mail.pseudo = TRUE;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde return TRUE;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde}
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenstatic bool parse_x_keywords(struct mbox_sync_mail_context *ctx,
21c1655dbc5fe861a152dc9a8a388d0d64f5ae20Timo Sirainen struct message_header_line *hdr)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen{
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen ARRAY_TYPE(keyword_indexes) keyword_list;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen const unsigned int *list;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen string_t *keyword;
21c1655dbc5fe861a152dc9a8a388d0d64f5ae20Timo Sirainen size_t keyword_start;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen unsigned int i, idx, count;
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen size_t pos;
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen if (array_is_created(&ctx->mail.keywords))
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen return FALSE; /* duplicate header, delete */
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen /* read keyword indexes to temporary array first */
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen t_push();
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen keyword = t_str_new(128);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen t_array_init(&keyword_list, 16);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen for (pos = 0; pos < hdr->full_value_len; ) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (IS_LWSP_LF(hdr->full_value[pos])) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen pos++;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde continue;
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde /* read the keyword string */
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen keyword_start = pos;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde for (; pos < hdr->full_value_len; pos++) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (IS_LWSP_LF(hdr->full_value[pos]))
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen break;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen str_truncate(keyword, 0);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen str_append_n(keyword, hdr->full_value + keyword_start,
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde pos - keyword_start);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde if (!mail_index_keyword_lookup(ctx->sync_ctx->mbox->ibox.index,
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde str_c(keyword), &idx)) {
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen /* keyword wasn't found. that means the sent mail
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen originally contained X-Keywords header. Delete it. */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen t_pop();
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return FALSE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* check that the keyword isn't already added there.
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen we don't want duplicates. */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen list = array_get(&keyword_list, &count);
d99107ddf4d9bccb710994482daf65276a9d6321Timo Sirainen for (i = 0; i < count; i++) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (list[i] == idx)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen break;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen if (i == count)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen array_append(&keyword_list, &idx, 1);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* once we know how many keywords there are, we can allocate the array
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen from mail_keyword_pool without wasting memory. */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (array_count(&keyword_list) > 0) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen p_array_init(&ctx->mail.keywords,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen ctx->sync_ctx->mail_keyword_pool,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen array_count(&keyword_list));
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen array_append_array(&ctx->mail.keywords, &keyword_list);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] = str_len(ctx->header);
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen parse_trailing_whitespace(ctx, hdr);
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen t_pop();
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return TRUE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen}
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenstatic bool parse_x_uid(struct mbox_sync_mail_context *ctx,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen struct message_header_line *hdr)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen{
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen uint32_t value = 0;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen size_t i;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (ctx->mail.uid != 0) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* duplicate */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return FALSE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen for (i = 0; i < hdr->full_value_len; i++) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (hdr->full_value[i] < '0' || hdr->full_value[i] > '9')
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen break;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde value = value*10 + (hdr->full_value[i] - '0');
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde for (; i < hdr->full_value_len; i++) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (!IS_LWSP_LF(hdr->full_value[i])) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* broken value */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return FALSE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (ctx->sync_ctx == NULL) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* we're in mbox_sync_parse_match_mail().
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen don't do any extra checks. */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen ctx->mail.uid = value;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return TRUE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (ctx->seq == 1 && !ctx->seen_imapbase) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* Don't bother allowing X-UID before X-IMAPbase
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde header. c-client doesn't allow it either, and this
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen way the UID doesn't have to be reset if X-IMAPbase
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen header isn't what we expect it to be. */
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde return FALSE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (value == ctx->sync_ctx->next_uid) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* X-UID is the next expected one. allow it because
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen we'd just use this UID anyway. X-IMAPbase header
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen still needs to be updated for this. */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen ctx->sync_ctx->next_uid++;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen } else if (value > ctx->sync_ctx->next_uid) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* UID is larger than expected. Don't allow it because
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen incoming mails can contain untrusted X-UID fields,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen causing possibly DoS if the UIDs get large enough. */
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx->mail.uid_broken = TRUE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return FALSE;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (value <= ctx->sync_ctx->prev_msg_uid) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen /* broken - UIDs must be growing */
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ctx->mail.uid_broken = TRUE;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return FALSE;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ctx->mail.uid = value;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen /* if we had multiple X-UID headers, we could have
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen uid_broken=TRUE here. */
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ctx->mail.uid_broken = FALSE;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (ctx->sync_ctx->dest_first_mail && ctx->seq != 1) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen /* if we're expunging the first mail, delete this header since
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen otherwise X-IMAPbase header would be added after this, which
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen we don't like */
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return FALSE;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ctx->hdr_pos[MBOX_HDR_X_UID] = str_len(ctx->header);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ctx->parsed_uid = value;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen parse_trailing_whitespace(ctx, hdr);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return TRUE;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen}
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenstatic bool parse_content_length(struct mbox_sync_mail_context *ctx,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen struct message_header_line *hdr)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen{
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen uoff_t value = 0;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen size_t i;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen if (ctx->content_length != (uoff_t)-1) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen /* duplicate */
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen return FALSE;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen for (i = 0; i < hdr->full_value_len; i++) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (hdr->full_value[i] < '0' || hdr->full_value[i] > '9')
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen break;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen value = value*10 + (hdr->full_value[i] - '0');
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen for (; i < hdr->full_value_len; i++) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (!IS_LWSP_LF(hdr->full_value[i])) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen /* broken value */
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen return FALSE;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen }
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx->content_length = value;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen return TRUE;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen}
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenstatic struct mbox_sync_header_func header_funcs[] = {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen { "Content-Length", parse_content_length },
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen { "Status", parse_status },
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen { "X-IMAP", parse_x_imap },
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen { "X-IMAPbase", parse_x_imap_base },
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen { "X-Keywords", parse_x_keywords },
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen { "X-Status", parse_x_status },
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen { "X-UID", parse_x_uid }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen};
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen#define HEADER_FUNCS_COUNT (sizeof(header_funcs) / sizeof(*header_funcs))
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainenstatic int mbox_sync_bsearch_header_func_cmp(const void *p1, const void *p2)
a3f5bd60d81b456b7e4b79b26a825b71b836a537Timo Sirainen{
a3f5bd60d81b456b7e4b79b26a825b71b836a537Timo Sirainen const char *key = p1;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen const struct mbox_sync_header_func *func = p2;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen return strcasecmp(key, func->header);
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen}
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainenvoid mbox_sync_parse_next_mail(struct istream *input,
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen struct mbox_sync_mail_context *ctx)
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen{
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct mbox_sync_context *sync_ctx = ctx->sync_ctx;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct message_header_parser_ctx *hdr_ctx;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct message_header_line *hdr;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen struct mbox_sync_header_func *func;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen struct mbox_md5_context *mbox_md5_ctx;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen size_t line_start_pos;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen int i, ret;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen ctx->hdr_offset = ctx->mail.offset;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen ctx->mail.flags = MAIL_RECENT; /* default to having recent flag */
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen ctx->header_first_change = (size_t)-1;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen ctx->header_last_change = 0;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen for (i = 0; i < MBOX_HDR_COUNT; i++)
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen ctx->hdr_pos[i] = (size_t)-1;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen ctx->content_length = (uoff_t)-1;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen str_truncate(ctx->header, 0);
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen mbox_md5_ctx = mbox_md5_init();
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen line_start_pos = 0;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen hdr_ctx = message_parse_header_init(input, NULL, 0);
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen while ((ret = message_parse_header_next(hdr_ctx, &hdr)) > 0) {
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen if (hdr->eoh) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ctx->have_eoh = TRUE;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen break;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (!hdr->continued) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen line_start_pos = str_len(ctx->header);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str_append(ctx->header, hdr->name);
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen str_append_n(ctx->header, hdr->middle, hdr->middle_len);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen func = bsearch(hdr->name, header_funcs,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen HEADER_FUNCS_COUNT, sizeof(*header_funcs),
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen mbox_sync_bsearch_header_func_cmp);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (func != NULL) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (hdr->continues) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen hdr->use_full_value = TRUE;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen continue;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen if (!func->func(ctx, hdr)) {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen /* this header is broken, remove it */
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ctx->need_rewrite = TRUE;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen str_truncate(ctx->header, line_start_pos);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (ctx->header_first_change == (size_t)-1) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ctx->header_first_change =
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen line_start_pos;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen continue;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen buffer_append(ctx->header, hdr->full_value,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen hdr->full_value_len);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen } else {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen mbox_md5_continue(mbox_md5_ctx, hdr);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen buffer_append(ctx->header, hdr->value,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen hdr->value_len);
a3f5bd60d81b456b7e4b79b26a825b71b836a537Timo Sirainen }
a3f5bd60d81b456b7e4b79b26a825b71b836a537Timo Sirainen if (!hdr->no_newline) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (hdr->crlf_newline)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str_append_c(ctx->header, '\r');
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str_append_c(ctx->header, '\n');
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen i_assert(ret != 0);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen message_parse_header_deinit(&hdr_ctx);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen mbox_md5_finish(mbox_md5_ctx, ctx->hdr_md5_sum);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if ((ctx->seq == 1 && !ctx->seen_imapbase) ||
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen (ctx->seq > 1 && sync_ctx->dest_first_mail)) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen /* missing X-IMAPbase */
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx->need_rewrite = TRUE;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (sync_ctx->base_uid_validity == 0) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen /* figure out a new UIDVALIDITY for us. */
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen sync_ctx->base_uid_validity =
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen sync_ctx->hdr->uid_validity != 0 &&
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen !sync_ctx->renumber_uids ?
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen sync_ctx->hdr->uid_validity :
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen I_MAX((uint32_t)ioloop_time, 1);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx->body_offset = input->v_offset;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen}
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenbool mbox_sync_parse_match_mail(struct mbox_mailbox *mbox,
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct mail_index_view *view, uint32_t seq)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen{
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct mbox_sync_mail_context ctx;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct message_header_parser_ctx *hdr_ctx;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct message_header_line *hdr;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct header_func *func;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct mbox_md5_context *mbox_md5_ctx;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen const void *data;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen uint32_t uid;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen int ret;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen /* we only wish to be sure that this mail actually is what we expect
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen it to be. If there's X-UID header and it matches our UID, we use it.
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen Otherwise it could mean that the X-UID header is invalid and it's
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen just not yet been rewritten. In that case use MD5 sum, if it
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen exists. */
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen mail_index_lookup_uid(view, seq, &uid);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen memset(&ctx, 0, sizeof(ctx));
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen mbox_md5_ctx = mbox_md5_init();
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen hdr_ctx = message_parse_header_init(mbox->mbox_stream, NULL, 0);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen while ((ret = message_parse_header_next(hdr_ctx, &hdr)) > 0) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (hdr->eoh)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen break;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen func = bsearch(hdr->name, header_funcs,
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen HEADER_FUNCS_COUNT, sizeof(*header_funcs),
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen mbox_sync_bsearch_header_func_cmp);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (func != NULL) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (strcasecmp(hdr->name, "X-UID") == 0) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (hdr->continues) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen hdr->use_full_value = TRUE;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen continue;
69d60dcff2614c4bfc8ad59e8fdc09e39c9dd0dcTimo Sirainen }
69d60dcff2614c4bfc8ad59e8fdc09e39c9dd0dcTimo Sirainen (void)parse_x_uid(&ctx, hdr);
69d60dcff2614c4bfc8ad59e8fdc09e39c9dd0dcTimo Sirainen
69d60dcff2614c4bfc8ad59e8fdc09e39c9dd0dcTimo Sirainen if (ctx.mail.uid == uid)
69d60dcff2614c4bfc8ad59e8fdc09e39c9dd0dcTimo Sirainen break;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen } else {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen mbox_md5_continue(mbox_md5_ctx, hdr);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen i_assert(ret != 0);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen message_parse_header_deinit(&hdr_ctx);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen mbox_md5_finish(mbox_md5_ctx, ctx.hdr_md5_sum);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
if (ctx.mail.uid == uid)
return TRUE;
/* match by MD5 sum */
mbox->mbox_save_md5 = TRUE;
mail_index_lookup_ext(view, seq, mbox->ibox.md5hdr_ext_idx,
&data, NULL);
return data == NULL ? 0 :
memcmp(data, ctx.hdr_md5_sum, 16) == 0;
}