mbox-sync-parse.c revision a486ed03dce069ff60ab5a65d0ae24a1862f22fc
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher/* Copyright (C) 2004 Timo Sirainen */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
ee359fe1384507fed6c2274e7bfe81d288de4542Stephen Gallagher/* MD5 header summing logic was pretty much copy&pasted from popa3d by
33396dc46ea52c18f47db1b5d590880806521005Sumit Bose Solar Designer */
ee359fe1384507fed6c2274e7bfe81d288de4542Stephen Gallagher
33396dc46ea52c18f47db1b5d590880806521005Sumit Bose#include "lib.h"
703dc1eb5b050b24235a6640f271d34ea008cf98Jan Engelhardt#include "ioloop.h"
703dc1eb5b050b24235a6640f271d34ea008cf98Jan Engelhardt#include "array.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include "buffer.h"
324fb26ba803a999bedc29e93c46c84f27abf5b7Sumit Bose#include "istream.h"
324fb26ba803a999bedc29e93c46c84f27abf5b7Sumit Bose#include "str.h"
324fb26ba803a999bedc29e93c46c84f27abf5b7Sumit Bose#include "write-full.h"
324fb26ba803a999bedc29e93c46c84f27abf5b7Sumit Bose#include "message-parser.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include "mail-index.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include "mbox-storage.h"
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher#include "mbox-md5.h"
5ebdc2391e96cfcc86ebdb8f223e159c00a0d82bLukas Slebodnik#include "mbox-sync-private.h"
5ebdc2391e96cfcc86ebdb8f223e159c00a0d82bLukas Slebodnik
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include <stdlib.h>
002f84aea86371aa079b867c0ec39396b97109d3Lukas Slebodnik
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#define IS_LWSP_LF(c) (IS_LWSP(c) || (c) == '\n')
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
700d45751e997c634504a4f22facd2edf82edea7Lukas Slebodnikstruct mbox_sync_header_func {
87d3b47abba6a40fcf809c85a2b138bc1013d9c5Jakub Hrozek const char *header;
87d3b47abba6a40fcf809c85a2b138bc1013d9c5Jakub Hrozek bool (*func)(struct mbox_sync_mail_context *ctx,
deeadf40db3a1eec64cf030e54afc4cb8612a8d5Lukas Slebodnik struct message_header_line *hdr);
ccf340e56364851f2e5b75e52d3d63701b662954Lukas Slebodnik};
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstruct mbox_flag_type mbox_status_flags[] = {
f0ea3ed816182fadf77f3e7f7ddb298b287007adLukas Slebodnik { 'R', MAIL_SEEN },
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher { 'O', MBOX_NONRECENT_KLUDGE },
cc98edd9479d4622634a1275c98058916c14059aStephen Gallagher { 0, 0 }
ee359fe1384507fed6c2274e7bfe81d288de4542Stephen Gallagher};
cc98edd9479d4622634a1275c98058916c14059aStephen Gallagher
d3da1c165cdb4c1ec126a8f4b6b544ca415b9d20Pavel Březinastruct mbox_flag_type mbox_xstatus_flags[] = {
d3da1c165cdb4c1ec126a8f4b6b544ca415b9d20Pavel Březina { 'A', MAIL_ANSWERED },
d3da1c165cdb4c1ec126a8f4b6b544ca415b9d20Pavel Březina { 'F', MAIL_FLAGGED },
c481179da5d5b53ce16d8784c0bd2857ffc2f061Lukas Slebodnik { 'T', MAIL_DRAFT },
1183d29d87c5c7439cf2364b7d7324d4a13b6e35Stephen Gallagher { 'D', MAIL_DELETED },
002f84aea86371aa079b867c0ec39396b97109d3Lukas Slebodnik { 0, 0 }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher};
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void parse_trailing_whitespace(struct mbox_sync_mail_context *ctx,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct message_header_line *hdr)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher size_t i, space = 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* the value may contain newlines. we can't count whitespace before
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher and after it as a single contiguous whitespace block, as that may
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher get us into situation where removing whitespace goes eg.
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher " \n \n" -> " \n\n" which would then be treated as end of headers.
c89589fa349f38214c9cb8d9389c0fd557e5dca2Simo Sorce
c89589fa349f38214c9cb8d9389c0fd557e5dca2Simo Sorce that could probably be avoided by being careful, but as newlines
f775337a7d4ca1c0be8eab683d0d753cbaee49e2Lukas Slebodnik should never be there (we don't generate them), it's not worth the
f775337a7d4ca1c0be8eab683d0d753cbaee49e2Lukas Slebodnik trouble. */
f775337a7d4ca1c0be8eab683d0d753cbaee49e2Lukas Slebodnik
86b61156743b7ebdc049450a6f88452890fd9a61Jakub Hrozek for (i = hdr->full_value_len; i > 0; i--) {
86b61156743b7ebdc049450a6f88452890fd9a61Jakub Hrozek if (!IS_LWSP(hdr->full_value[i-1]))
86b61156743b7ebdc049450a6f88452890fd9a61Jakub Hrozek break;
c89589fa349f38214c9cb8d9389c0fd557e5dca2Simo Sorce space++;
c89589fa349f38214c9cb8d9389c0fd557e5dca2Simo Sorce }
86b61156743b7ebdc049450a6f88452890fd9a61Jakub Hrozek
86b61156743b7ebdc049450a6f88452890fd9a61Jakub Hrozek if ((ssize_t)space > ctx->mail.space) {
86b61156743b7ebdc049450a6f88452890fd9a61Jakub Hrozek i_assert(space != 0);
86b61156743b7ebdc049450a6f88452890fd9a61Jakub Hrozek ctx->mail.offset = ctx->hdr_offset + str_len(ctx->header) + i;
86b61156743b7ebdc049450a6f88452890fd9a61Jakub Hrozek ctx->mail.space = space;
86b61156743b7ebdc049450a6f88452890fd9a61Jakub Hrozek }
86b61156743b7ebdc049450a6f88452890fd9a61Jakub Hrozek}
86b61156743b7ebdc049450a6f88452890fd9a61Jakub Hrozek
86b61156743b7ebdc049450a6f88452890fd9a61Jakub Hrozekstatic enum mail_flags mbox_flag_find(struct mbox_flag_type *flags, char chr)
86b61156743b7ebdc049450a6f88452890fd9a61Jakub Hrozek{
86b61156743b7ebdc049450a6f88452890fd9a61Jakub Hrozek int i;
48130eef6c5c64a07094b9e8582ba358b2048f24Jakub Hrozek
48130eef6c5c64a07094b9e8582ba358b2048f24Jakub Hrozek for (i = 0; flags[i].chr != 0; i++) {
48130eef6c5c64a07094b9e8582ba358b2048f24Jakub Hrozek if (flags[i].chr == chr)
48130eef6c5c64a07094b9e8582ba358b2048f24Jakub Hrozek return flags[i].flag;
1658c567191c35beaddffafdb079abe33248037bLukas Slebodnik }
1658c567191c35beaddffafdb079abe33248037bLukas Slebodnik
1658c567191c35beaddffafdb079abe33248037bLukas Slebodnik return 0;
faa16fc9f0c9a02b26497e7cf148a92586144c08David Disseldorp}
faa16fc9f0c9a02b26497e7cf148a92586144c08David Disseldorp
faa16fc9f0c9a02b26497e7cf148a92586144c08David Disseldorpstatic void parse_status_flags(struct mbox_sync_mail_context *ctx,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct message_header_line *hdr,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct mbox_flag_type *flags_list)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher size_t i;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->mail.flags ^= MBOX_NONRECENT_KLUDGE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (i = 0; i < hdr->full_value_len; i++) {
d921c1eba437662437847279f251a0a5d8f70127Maxim ctx->mail.flags |=
d921c1eba437662437847279f251a0a5d8f70127Maxim mbox_flag_find(flags_list, hdr->full_value[i]);
d921c1eba437662437847279f251a0a5d8f70127Maxim }
d921c1eba437662437847279f251a0a5d8f70127Maxim ctx->mail.flags ^= MBOX_NONRECENT_KLUDGE;
d921c1eba437662437847279f251a0a5d8f70127Maxim}
d921c1eba437662437847279f251a0a5d8f70127Maxim
d921c1eba437662437847279f251a0a5d8f70127Maximstatic bool parse_status(struct mbox_sync_mail_context *ctx,
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer struct message_header_line *hdr)
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer{
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer parse_status_flags(ctx, hdr, mbox_status_flags);
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer ctx->hdr_pos[MBOX_HDR_STATUS] = str_len(ctx->header);
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer return TRUE;
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer}
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer
327127bb7fcc07f882209f029e14026de1b23c94Maximstatic bool parse_x_status(struct mbox_sync_mail_context *ctx,
327127bb7fcc07f882209f029e14026de1b23c94Maxim struct message_header_line *hdr)
327127bb7fcc07f882209f029e14026de1b23c94Maxim{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher parse_status_flags(ctx, hdr, mbox_xstatus_flags);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->hdr_pos[MBOX_HDR_X_STATUS] = str_len(ctx->header);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return TRUE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool keyword_is_valid(const char *keyword)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce /* try to only prevent the most malicious looking keywords. */
bc9235cfb80bd64a3bfa959e8d26d5ad1be0bdf4Jakub Hrozek for (; *keyword != '\0'; keyword++) {
bc9235cfb80bd64a3bfa959e8d26d5ad1be0bdf4Jakub Hrozek if (*keyword == '(' || *keyword == ')' ||
07d82f79d2970a08628ebf71343441ec55faa6faPavel Březina *keyword == '{' || *keyword == '}' ||
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *keyword == '\\' || *keyword == '"' ||
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher (unsigned char)*keyword <= 32)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return FALSE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return TRUE;
4b6a0d0b3d42e5fdb457f47d9adfa5e66b160256Stephen Gallagher}
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose
03713859dffacc7142393e53c73d8d4cf7dee8d5Pavel Březinastatic void
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnikparse_imap_keywords_list(struct mbox_sync_mail_context *ctx,
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik struct message_header_line *hdr, size_t pos)
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *keyword;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher size_t keyword_start;
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek unsigned int idx, count;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
772464c842968d6e544118ae1aa7c49a7cda2ad6Stephen Gallagher count = 0;
32381402a4a9afc003782c9e2301fc59c9bda2a9Yassir Elley while (pos < hdr->full_value_len) {
068dbee9ca7bf5b37330eff91c94ae10f288d09fJakub Hrozek if (IS_LWSP_LF(hdr->full_value[pos])) {
98ce3c3e85a4bb2e1822bf8ab2a1c2ab9e3dd61dJakub Hrozek pos++;
be65f065fef1d387281096ef095a2acef39ecc12Jakub Hrozek continue;
e124844907ed6973915e4d56f5442ecd07535a12Jakub Hrozek }
f36078af138f052cd9a30360867b0ebd0805af5eJakub Hrozek
34c78b745eb349eef2b0f13ef2b722632aebe619Jan Cholasta /* read the keyword */
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek keyword_start = pos;
e07a94a66985b674c5df11ca466792902164c4e2George McCollister for (; pos < hdr->full_value_len; pos++) {
77c0d1f6074059dafd2293f9c42ea0f9d60f8aadJakub Hrozek if (IS_LWSP_LF(hdr->full_value[pos]))
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik break;
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer }
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer
a9c287bda3fc2a1e12cef2135ade96945f11ad01Sumit Bose /* add it to index's keyword list if it's not there already */
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek t_push();
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher keyword = t_strndup(hdr->full_value + keyword_start,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher pos - keyword_start);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (keyword_is_valid(keyword)) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher (void)mail_index_keyword_lookup(
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->sync_ctx->mbox->ibox.index,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher keyword, TRUE, &idx);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher t_pop();
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher count++;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (count != array_count(ctx->sync_ctx->mbox->ibox.keyword_names)) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* need to update this list */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->imapbase_rewrite = TRUE;
a5077712fc8c24e8cad08207b7b5a6603bde6a7cJakub Hrozek ctx->need_rewrite = TRUE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool parse_x_imap_base(struct mbox_sync_mail_context *ctx,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct message_header_line *hdr)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher size_t i, j, uid_last_pos;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher uint32_t uid_validity, uid_last;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek if (ctx->seq != 1 || ctx->seen_imapbase ||
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose ctx->sync_ctx->renumber_uids) {
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke /* Valid only in first message */
6b0a7c72bb841d6885a620c68bd51d55109b66c7Jakub Hrozek return FALSE;
9917c138d9a270deb5820915384fbde751190c2aLukas Slebodnik }
0e1dcef53d9d8465ce97d31ad11be4445a6e7eb8Lukas Slebodnik
c3889e5a101a075defe533d81f5296d5e680f639Lukas Slebodnik /* <uid-validity> 10x<uid-last> */
3fc158e59eebbc2f538fe0076a03928d0d4eab9fPavel Březina for (i = 0, uid_validity = 0; i < hdr->full_value_len; i++) {
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer if (hdr->full_value[i] < '0' || hdr->full_value[i] > '9') {
40b2be4f4312470044cdef460b02b66003f5c85fJakub Hrozek if (hdr->full_value[i] != ' ')
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek return FALSE;
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov break;
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek }
3fc158e59eebbc2f538fe0076a03928d0d4eab9fPavel Březina uid_validity = uid_validity * 10 + (hdr->full_value[i] - '0');
3fc158e59eebbc2f538fe0076a03928d0d4eab9fPavel Březina }
3fc158e59eebbc2f538fe0076a03928d0d4eab9fPavel Březina
3fc158e59eebbc2f538fe0076a03928d0d4eab9fPavel Březina if (uid_validity == 0) {
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher /* broken */
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher return FALSE;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher }
9dbdf62243f01f6aee41c2b5f2976c56da47f25dLukas Slebodnik
9dbdf62243f01f6aee41c2b5f2976c56da47f25dLukas Slebodnik for (; i < hdr->full_value_len; i++) {
9dbdf62243f01f6aee41c2b5f2976c56da47f25dLukas Slebodnik if (!IS_LWSP_LF(hdr->full_value[i]))
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher break;
9dbdf62243f01f6aee41c2b5f2976c56da47f25dLukas Slebodnik }
9dbdf62243f01f6aee41c2b5f2976c56da47f25dLukas Slebodnik uid_last_pos = i;
9dbdf62243f01f6aee41c2b5f2976c56da47f25dLukas Slebodnik
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher for (uid_last = 0, j = 0; i < hdr->full_value_len; i++, j++) {
9dbdf62243f01f6aee41c2b5f2976c56da47f25dLukas Slebodnik if (hdr->full_value[i] < '0' || hdr->full_value[i] > '9') {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!IS_LWSP_LF(hdr->full_value[i]))
539b1be3507abdf8ac235b06eeed5011b0b5cde2Ondrej Kos return FALSE;
539b1be3507abdf8ac235b06eeed5011b0b5cde2Ondrej Kos break;
574a1c20f114851071ae74112b34488c3d1aeeb3Ondrej Kos }
574a1c20f114851071ae74112b34488c3d1aeeb3Ondrej Kos uid_last = uid_last * 10 + (hdr->full_value[i] - '0');
574a1c20f114851071ae74112b34488c3d1aeeb3Ondrej Kos }
574a1c20f114851071ae74112b34488c3d1aeeb3Ondrej Kos
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek if (j != 10 ||
e6e26182d58c05d896f72f2925426658a6dc70b5Jakub Hrozek hdr->full_value_offset != ctx->hdr_offset + str_len(ctx->header)) {
e6e26182d58c05d896f72f2925426658a6dc70b5Jakub Hrozek /* uid-last field must be exactly 10 characters to make
9542512d7be40f2000298c86d3d2b728f4f0f65aStephen Gallagher rewriting it easier. also don't try to do this if some
e6e26182d58c05d896f72f2925426658a6dc70b5Jakub Hrozek headers have been removed */
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek ctx->imapbase_rewrite = TRUE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->need_rewrite = TRUE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->last_uid_value_start_pos = uid_last_pos;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->sync_ctx->base_uid_last_offset =
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher hdr->full_value_offset + uid_last_pos;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ctx->sync_ctx->next_uid-1 <= uid_last) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* new messages have been added since our last sync.
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher just update our internal next_uid. */
6b01dae732eedee808f32a9cdd4b5656a9f839c4Jakub Hrozek ctx->sync_ctx->next_uid = uid_last+1;
6b01dae732eedee808f32a9cdd4b5656a9f839c4Jakub Hrozek }
6b01dae732eedee808f32a9cdd4b5656a9f839c4Jakub Hrozek i_assert(ctx->sync_ctx->next_uid > ctx->sync_ctx->prev_msg_uid);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ctx->sync_ctx->base_uid_validity == 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* first time parsing this (ie. we're not rewriting).
6b01dae732eedee808f32a9cdd4b5656a9f839c4Jakub Hrozek save the values. */
6b01dae732eedee808f32a9cdd4b5656a9f839c4Jakub Hrozek ctx->sync_ctx->base_uid_validity = uid_validity;
6b01dae732eedee808f32a9cdd4b5656a9f839c4Jakub Hrozek ctx->sync_ctx->base_uid_last = uid_last;
6b01dae732eedee808f32a9cdd4b5656a9f839c4Jakub Hrozek }
6b01dae732eedee808f32a9cdd4b5656a9f839c4Jakub Hrozek
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->hdr_pos[MBOX_HDR_X_IMAPBASE] = str_len(ctx->header);
6b01dae732eedee808f32a9cdd4b5656a9f839c4Jakub Hrozek ctx->seen_imapbase = TRUE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher parse_imap_keywords_list(ctx, hdr, i);
b50dffea929ee5cd0c59ba3c4822337cc162ff92Kamil Dudka parse_trailing_whitespace(ctx, hdr);
b50dffea929ee5cd0c59ba3c4822337cc162ff92Kamil Dudka return TRUE;
b50dffea929ee5cd0c59ba3c4822337cc162ff92Kamil Dudka}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool parse_x_imap(struct mbox_sync_mail_context *ctx,
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek struct message_header_line *hdr)
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!parse_x_imap_base(ctx, hdr))
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek return FALSE;
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek /* this is the c-client style "FOLDER INTERNAL DATA" message.
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek skip it. */
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek ctx->pseudo = TRUE;
d9378e64499642e86989158f274372187314d5b2Lukas Slebodnik return TRUE;
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek}
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozekstatic bool parse_x_keywords(struct mbox_sync_mail_context *ctx,
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek struct message_header_line *hdr)
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek{
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek ARRAY_TYPE(keyword_indexes) keyword_list;
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek const unsigned int *list;
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek string_t *keyword;
6f51c802311fd81a409a26763ed45b28a3234d0dJakub Hrozek size_t keyword_start;
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek unsigned int i, idx, count;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher size_t pos;
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher if (array_is_created(&ctx->mail.keywords))
f5b6f977d4144c28e9c66f3f1c9d634d595d1117Marko Myllynen return FALSE; /* duplicate header, delete */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik /* read keyword indexes to temporary array first */
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik t_push();
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik keyword = t_str_new(128);
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik t_array_init(&keyword_list, 16);
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik for (pos = 0; pos < hdr->full_value_len; ) {
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik if (IS_LWSP_LF(hdr->full_value[pos])) {
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik pos++;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik continue;
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik }
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik /* read the keyword string */
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik keyword_start = pos;
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik for (; pos < hdr->full_value_len; pos++) {
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik if (IS_LWSP_LF(hdr->full_value[pos]))
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik break;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik }
dc4c30bae512c0b45ff925d9e998337f8fe97e94Lukas Slebodnik
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik str_truncate(keyword, 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_append_n(keyword, hdr->full_value + keyword_start,
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik pos - keyword_start);
72e60fd4eabcfbcdbfe01e8c38b94052bc6c2067Jakub Hrozek if (!mail_index_keyword_lookup(ctx->sync_ctx->mbox->ibox.index,
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik str_c(keyword), FALSE, &idx)) {
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik /* keyword wasn't found. that means the sent mail
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik originally contained X-Keywords header. Delete it. */
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik t_pop();
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik return FALSE;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik }
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik /* check that the keyword isn't already added there.
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik we don't want duplicates. */
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik list = array_get(&keyword_list, &count);
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik for (i = 0; i < count; i++) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (list[i] == idx)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher break;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik }
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik if (i == count)
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik array_append(&keyword_list, &idx, 1);
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik }
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik /* once we know how many keywords there are, we can allocate the array
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik from mail_keyword_pool without wasting memory. */
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik if (array_count(&keyword_list) > 0) {
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik p_array_init(&ctx->mail.keywords,
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik ctx->sync_ctx->mail_keyword_pool,
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik array_count(&keyword_list));
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik array_append_array(&ctx->mail.keywords, &keyword_list);
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik }
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] = str_len(ctx->header);
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik parse_trailing_whitespace(ctx, hdr);
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik t_pop();
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik return TRUE;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik}
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnikstatic bool parse_x_uid(struct mbox_sync_mail_context *ctx,
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik struct message_header_line *hdr)
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik{
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik uint32_t value = 0;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik size_t i;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik if (ctx->mail.uid != 0) {
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik /* duplicate */
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik return FALSE;
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov }
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (i = 0; i < hdr->full_value_len; i++) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (hdr->full_value[i] < '0' || hdr->full_value[i] > '9')
3d038d2e0dc7af04ec2f7c85ae325accb39f6237Jakub Hrozek break;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher value = value*10 + (hdr->full_value[i] - '0');
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (; i < hdr->full_value_len; i++) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!IS_LWSP_LF(hdr->full_value[i])) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* broken value */
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek return FALSE;
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek }
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek }
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek
77c0d1f6074059dafd2293f9c42ea0f9d60f8aadJakub Hrozek if (ctx->sync_ctx == NULL) {
77c0d1f6074059dafd2293f9c42ea0f9d60f8aadJakub Hrozek /* we're in mbox_sync_parse_match_mail().
77c0d1f6074059dafd2293f9c42ea0f9d60f8aadJakub Hrozek don't do any extra checks. */
77c0d1f6074059dafd2293f9c42ea0f9d60f8aadJakub Hrozek ctx->mail.uid = value;
77c0d1f6074059dafd2293f9c42ea0f9d60f8aadJakub Hrozek return TRUE;
e07a94a66985b674c5df11ca466792902164c4e2George McCollister }
e07a94a66985b674c5df11ca466792902164c4e2George McCollister
e07a94a66985b674c5df11ca466792902164c4e2George McCollister if (ctx->seq == 1 && !ctx->seen_imapbase) {
bf01e8179cbb2be476805340636098deda7e1366Sumit Bose /* Don't bother allowing X-UID before X-IMAPbase
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose header. c-client doesn't allow it either, and this
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose way the UID doesn't have to be reset if X-IMAPbase
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose header isn't what we expect it to be. */
172c07013d1ea99447a780fd36f49d5c3a76981bJakub Hrozek return FALSE;
9917c138d9a270deb5820915384fbde751190c2aLukas Slebodnik }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
336879aabae137f9a81304f147fb0d43001654b0Simo Sorce if (value == ctx->sync_ctx->next_uid) {
336879aabae137f9a81304f147fb0d43001654b0Simo Sorce /* X-UID is the next expected one. allow it because
336879aabae137f9a81304f147fb0d43001654b0Simo Sorce we'd just use this UID anyway. X-IMAPbase header
336879aabae137f9a81304f147fb0d43001654b0Simo Sorce still needs to be updated for this. */
336879aabae137f9a81304f147fb0d43001654b0Simo Sorce ctx->sync_ctx->next_uid++;
336879aabae137f9a81304f147fb0d43001654b0Simo Sorce } else if (value > ctx->sync_ctx->next_uid) {
336879aabae137f9a81304f147fb0d43001654b0Simo Sorce /* UID is larger than expected. Don't allow it because
336879aabae137f9a81304f147fb0d43001654b0Simo Sorce incoming mails can contain untrusted X-UID fields,
336879aabae137f9a81304f147fb0d43001654b0Simo Sorce causing possibly DoS if the UIDs get large enough. */
336879aabae137f9a81304f147fb0d43001654b0Simo Sorce ctx->mail.uid_broken = TRUE;
336879aabae137f9a81304f147fb0d43001654b0Simo Sorce return FALSE;
336879aabae137f9a81304f147fb0d43001654b0Simo Sorce }
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik if (value <= ctx->sync_ctx->prev_msg_uid) {
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik /* broken - UIDs must be growing */
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik ctx->mail.uid_broken = TRUE;
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik return FALSE;
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik }
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik ctx->sync_ctx->prev_msg_uid = value;
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik ctx->mail.uid = value;
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik /* if we had multiple X-UID headers, we could have
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik uid_broken=TRUE here. */
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik ctx->mail.uid_broken = FALSE;
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik if (ctx->sync_ctx->dest_first_mail && ctx->seq != 1) {
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik /* if we're expunging the first mail, delete this header since
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik otherwise X-IMAPbase header would be added after this, which
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik we don't like */
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik return FALSE;
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnik }
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnik
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnik ctx->hdr_pos[MBOX_HDR_X_UID] = str_len(ctx->header);
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnik ctx->parsed_uid = value;
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnik parse_trailing_whitespace(ctx, hdr);
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnik return TRUE;
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnik}
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnik
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnikstatic bool parse_content_length(struct mbox_sync_mail_context *ctx,
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnik struct message_header_line *hdr)
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnik{
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnik uoff_t value = 0;
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnik size_t i;
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnik
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnik if (ctx->content_length != (uoff_t)-1) {
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnik /* duplicate */
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnik return FALSE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (i = 0; i < hdr->full_value_len; i++) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (hdr->full_value[i] < '0' || hdr->full_value[i] > '9')
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher break;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher value = value*10 + (hdr->full_value[i] - '0');
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (; i < hdr->full_value_len; i++) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!IS_LWSP_LF(hdr->full_value[i])) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* broken value */
1c7f25390572025baa6783ede14523e22fc73043Lukas Slebodnik return FALSE;
40b2be4f4312470044cdef460b02b66003f5c85fJakub Hrozek }
40b2be4f4312470044cdef460b02b66003f5c85fJakub Hrozek }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek ctx->content_length = value;
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek return TRUE;
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek}
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashovstatic struct mbox_sync_header_func header_funcs[] = {
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher { "Content-Length", parse_content_length },
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher { "Status", parse_status },
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozek { "X-IMAP", parse_x_imap },
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozek { "X-IMAPbase", parse_x_imap_base },
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozek { "X-Keywords", parse_x_keywords },
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozek { "X-Status", parse_x_status },
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher { "X-UID", parse_x_uid }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher};
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#define HEADER_FUNCS_COUNT (sizeof(header_funcs) / sizeof(*header_funcs))
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
a8d887323f83984679a7d9b827a70146656bb7b2Sumit Bosestatic int mbox_sync_bsearch_header_func_cmp(const void *p1, const void *p2)
a8d887323f83984679a7d9b827a70146656bb7b2Sumit Bose{
a8d887323f83984679a7d9b827a70146656bb7b2Sumit Bose const char *key = p1;
96c73559adfbdac96720008fc022cb1d540b53c3Jakub Hrozek const struct mbox_sync_header_func *func = p2;
3be9e26dcd169d44ae105f1b8a0674464c700b77Sumit Bose
9542512d7be40f2000298c86d3d2b728f4f0f65aStephen Gallagher return strcasecmp(key, func->header);
428db8a58c0c149d5efccc6d788f70916c1d34d7Jakub Hrozek}
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
e0c86d21388bffe2e3919e780780c40d96186abbJakub Hrozekvoid mbox_sync_parse_next_mail(struct istream *input,
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose struct mbox_sync_mail_context *ctx)
2a9af1f71887f02935e2fb6ad5023afba5b6d43eSumit Bose{
2a9af1f71887f02935e2fb6ad5023afba5b6d43eSumit Bose struct mbox_sync_context *sync_ctx = ctx->sync_ctx;
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit Bose struct message_header_parser_ctx *hdr_ctx;
a7e27c11866a48742bb70564b88e15bf15e9367dPavel Březina struct message_header_line *hdr;
a7e27c11866a48742bb70564b88e15bf15e9367dPavel Březina struct mbox_sync_header_func *func;
f1ce53a3b5656361557f80f61dfd42a371230c65Stephen Gallagher struct mbox_md5_context *mbox_md5_ctx;
1a59af8245f183f22d87d067a90197d8e2ea958dJakub Hrozek size_t line_start_pos;
f1ce53a3b5656361557f80f61dfd42a371230c65Stephen Gallagher int i, ret;
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher
ctx->hdr_offset = ctx->mail.offset;
ctx->mail.flags = MAIL_RECENT; /* default to having recent flag */
ctx->header_first_change = (size_t)-1;
ctx->header_last_change = 0;
for (i = 0; i < MBOX_HDR_COUNT; i++)
ctx->hdr_pos[i] = (size_t)-1;
ctx->content_length = (uoff_t)-1;
str_truncate(ctx->header, 0);
mbox_md5_ctx = mbox_md5_init();
line_start_pos = 0;
hdr_ctx = message_parse_header_init(input, NULL, FALSE);
while ((ret = message_parse_header_next(hdr_ctx, &hdr)) > 0) {
if (hdr->eoh) {
ctx->have_eoh = TRUE;
break;
}
if (!hdr->continued) {
line_start_pos = str_len(ctx->header);
str_append(ctx->header, hdr->name);
str_append_n(ctx->header, hdr->middle, hdr->middle_len);
}
func = bsearch(hdr->name, header_funcs,
HEADER_FUNCS_COUNT, sizeof(*header_funcs),
mbox_sync_bsearch_header_func_cmp);
if (func != NULL) {
if (hdr->continues) {
hdr->use_full_value = TRUE;
continue;
}
if (!func->func(ctx, hdr)) {
/* this header is broken, remove it */
ctx->need_rewrite = TRUE;
str_truncate(ctx->header, line_start_pos);
if (ctx->header_first_change == (size_t)-1) {
ctx->header_first_change =
line_start_pos;
}
continue;
}
buffer_append(ctx->header, hdr->full_value,
hdr->full_value_len);
} else {
mbox_md5_continue(mbox_md5_ctx, hdr);
buffer_append(ctx->header, hdr->value,
hdr->value_len);
}
if (!hdr->no_newline) {
if (hdr->crlf_newline)
str_append_c(ctx->header, '\r');
str_append_c(ctx->header, '\n');
}
}
i_assert(ret != 0);
message_parse_header_deinit(&hdr_ctx);
mbox_md5_finish(mbox_md5_ctx, ctx->hdr_md5_sum);
if ((ctx->seq == 1 && !ctx->seen_imapbase) ||
(ctx->seq > 1 && sync_ctx->dest_first_mail)) {
/* missing X-IMAPbase */
ctx->need_rewrite = TRUE;
if (sync_ctx->base_uid_validity == 0) {
/* figure out a new UIDVALIDITY for us. */
sync_ctx->base_uid_validity =
sync_ctx->hdr->uid_validity != 0 &&
!sync_ctx->renumber_uids ?
sync_ctx->hdr->uid_validity :
I_MAX((uint32_t)ioloop_time, 1);
}
}
ctx->body_offset = input->v_offset;
}
int mbox_sync_parse_match_mail(struct mbox_mailbox *mbox,
struct mail_index_view *view, uint32_t seq)
{
struct mbox_sync_mail_context ctx;
struct message_header_parser_ctx *hdr_ctx;
struct message_header_line *hdr;
struct header_func *func;
struct mbox_md5_context *mbox_md5_ctx;
const void *data;
uint32_t uid;
int ret;
/* we only wish to be sure that this mail actually is what we expect
it to be. If there's X-UID header and it matches our UID, we use it.
Otherwise it could mean that the X-UID header is invalid and it's
just not yet been rewritten. In that case use MD5 sum, if it
exists. */
if (mail_index_lookup_uid(view, seq, &uid) < 0) {
mail_storage_set_index_error(&mbox->ibox);
return -1;
}
memset(&ctx, 0, sizeof(ctx));
mbox_md5_ctx = mbox_md5_init();
hdr_ctx = message_parse_header_init(mbox->mbox_stream, NULL, FALSE);
while ((ret = message_parse_header_next(hdr_ctx, &hdr)) > 0) {
if (hdr->eoh)
break;
func = bsearch(hdr->name, header_funcs,
HEADER_FUNCS_COUNT, sizeof(*header_funcs),
mbox_sync_bsearch_header_func_cmp);
if (func != NULL) {
if (strcasecmp(hdr->name, "X-UID") == 0) {
if (hdr->continues) {
hdr->use_full_value = TRUE;
continue;
}
(void)parse_x_uid(&ctx, hdr);
if (ctx.mail.uid == uid)
break;
}
} else {
mbox_md5_continue(mbox_md5_ctx, hdr);
}
}
i_assert(ret != 0);
message_parse_header_deinit(&hdr_ctx);
mbox_md5_finish(mbox_md5_ctx, ctx.hdr_md5_sum);
if (ctx.mail.uid == uid)
return TRUE;
/* match by MD5 sum */
mbox->mbox_save_md5 = TRUE;
if (mail_index_lookup_ext(view, seq, mbox->ibox.md5hdr_ext_idx,
&data) < 0) {
mail_storage_set_index_error(&mbox->ibox);
return -1;
}
return data == NULL ? 0 :
memcmp(data, ctx.hdr_md5_sum, 16) == 0;
}