]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
maildir: uidlist can now override message's GUID
authorTimo Sirainen <tss@iki.fi>
Thu, 16 Sep 2010 15:28:58 +0000 (16:28 +0100)
committerTimo Sirainen <tss@iki.fi>
Thu, 16 Sep 2010 15:28:58 +0000 (16:28 +0100)
src/lib-storage/index/maildir/maildir-mail.c
src/lib-storage/index/maildir/maildir-save.c
src/lib-storage/index/maildir/maildir-uidlist.c
src/lib-storage/index/maildir/maildir-uidlist.h

index 4e1c1354f698d7fbf13b2b1e90b6984a625bcef9..366774c0bf8f864a5d9b6d1f349eae421905f246 100644 (file)
@@ -469,11 +469,20 @@ maildir_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
 {
        struct index_mail *mail = (struct index_mail *)_mail;
        struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
-       const char *path, *fname, *end, *uidl;
+       const char *path, *fname, *end, *guid, *uidl;
 
        switch (field) {
-       case MAIL_FETCH_UIDL_FILE_NAME:
        case MAIL_FETCH_GUID:
+               /* use GUID from uidlist if it exists */
+               guid = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
+                                                 MAILDIR_UIDLIST_REC_EXT_GUID);
+               if (guid != NULL) {
+                       *value_r = guid;
+                       return 0;
+               }
+
+               /* default to base filename: */
+       case MAIL_FETCH_UIDL_FILE_NAME:
                if (mail->data.guid != NULL) {
                        *value_r = mail->data.guid;
                        return 0;
index bfb42046512b090cf7148b3231e6abbc684cec78..88e610c1f594d44aa095e3441b3fe6b49d3f57b1 100644 (file)
@@ -33,6 +33,7 @@ struct maildir_filename {
        uoff_t size, vsize;
        enum mail_flags flags;
        unsigned int preserve_filename:1;
+       unsigned int save_guid:1; /* tmp_name contains the GUID */
        unsigned int keywords_count;
        /* unsigned int keywords[]; */
 };
@@ -786,6 +787,7 @@ maildir_filename_check_conflicts(struct maildir_save_context *ctx,
                mf->dest_basename = p_strdup(ctx->pool,
                                             maildir_filename_generate());
                mf->preserve_filename = FALSE;
+               mf->save_guid = TRUE;
        }
 }
 
@@ -828,6 +830,7 @@ static void maildir_save_sync_uidlist(struct maildir_save_context *ctx)
        struct maildir_filename *mf;
        struct seq_range_iter iter;
        enum maildir_uidlist_rec_flag flags;
+       struct maildir_uidlist_rec *rec;
        unsigned int n = 0;
        uint32_t uid;
        bool newdir, bret;
@@ -845,8 +848,13 @@ static void maildir_save_sync_uidlist(struct maildir_save_context *ctx)
                if (newdir)
                        flags |= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR;
                ret = maildir_uidlist_sync_next_uid(ctx->uidlist_sync_ctx,
-                                                   dest, uid, flags);
+                                                   dest, uid, flags, &rec);
                i_assert(ret > 0);
+               i_assert(rec != NULL);
+               if (mf->save_guid) {
+                       maildir_uidlist_sync_set_ext(ctx->uidlist_sync_ctx, rec,
+                               MAILDIR_UIDLIST_REC_EXT_GUID, mf->tmp_name);
+               }
        } T_END;
        i_assert(!seq_range_array_iter_nth(&iter, n, &uid));
 }
index 76a6675e65660ddb4c66c0a2ab3f7aec4ae8a67d..59dc620f732f8bfdcdbad4c12731de0468bf84ff 100644 (file)
@@ -1141,33 +1141,16 @@ void maildir_uidlist_set_next_uid(struct maildir_uidlist *uidlist,
 }
 
 static void
-maildir_uidlist_set_ext_real(struct maildir_uidlist *uidlist, uint32_t uid,
-                            enum maildir_uidlist_rec_ext_key key,
-                            const char *value)
+maildir_uidlist_rec_set_ext(struct maildir_uidlist_rec *rec, pool_t pool,
+                           enum maildir_uidlist_rec_ext_key key,
+                           const char *value)
 {
-       struct maildir_uidlist_rec *rec;
        const unsigned char *p;
        buffer_t *buf;
        unsigned int len;
-       int ret;
-
-       ret = maildir_uidlist_lookup_rec(uidlist, uid, &rec);
-       if (ret <= 0) {
-               if (ret < 0)
-                       return;
-
-               /* maybe it's a new message */
-               if (maildir_uidlist_refresh(uidlist) < 0)
-                       return;
-               if (maildir_uidlist_lookup_rec(uidlist, uid, &rec) <= 0) {
-                       /* message is already expunged, ignore */
-                       return;
-               }
-       }
-
-       buf = buffer_create_dynamic(pool_datastack_create(), 128);
 
        /* copy existing extensions, except for the one we're updating */
+       buf = buffer_create_dynamic(pool_datastack_create(), 128);
        if (rec->extensions != NULL) {
                p = rec->extensions;
                while (*p != '\0') {
@@ -1184,22 +1167,40 @@ maildir_uidlist_set_ext_real(struct maildir_uidlist *uidlist, uint32_t uid,
        }
        buffer_append_c(buf, '\0');
 
-       rec->extensions = p_malloc(uidlist->record_pool, buf->used);
+       rec->extensions = p_malloc(pool, buf->used);
        memcpy(rec->extensions, buf->data, buf->used);
-
-       if (rec->uid != (uint32_t)-1) {
-               /* message already exists in uidlist, need to recreate it */
-               uidlist->recreate = TRUE;
-       }
 }
 
 void maildir_uidlist_set_ext(struct maildir_uidlist *uidlist, uint32_t uid,
                             enum maildir_uidlist_rec_ext_key key,
                             const char *value)
 {
+       struct maildir_uidlist_rec *rec;
+       int ret;
+
+       ret = maildir_uidlist_lookup_rec(uidlist, uid, &rec);
+       if (ret <= 0) {
+               if (ret < 0)
+                       return;
+
+               /* maybe it's a new message */
+               if (maildir_uidlist_refresh(uidlist) < 0)
+                       return;
+               if (maildir_uidlist_lookup_rec(uidlist, uid, &rec) <= 0) {
+                       /* message is already expunged, ignore */
+                       return;
+               }
+       }
+
        T_BEGIN {
-               maildir_uidlist_set_ext_real(uidlist, uid, key, value);
+               maildir_uidlist_rec_set_ext(rec, uidlist->record_pool,
+                                           key, value);
        } T_END;
+
+       if (rec->uid != (uint32_t)-1) {
+               /* message already exists in uidlist, need to recreate it */
+               uidlist->recreate = TRUE;
+       }
 }
 
 static void
@@ -1645,10 +1646,12 @@ int maildir_uidlist_sync_init(struct maildir_uidlist *uidlist,
 static int
 maildir_uidlist_sync_next_partial(struct maildir_uidlist_sync_ctx *ctx,
                                  const char *filename, uint32_t uid,
-                                 enum maildir_uidlist_rec_flag flags)
+                                 enum maildir_uidlist_rec_flag flags,
+                                 struct maildir_uidlist_rec **rec_r)
 {
        struct maildir_uidlist *uidlist = ctx->uidlist;
-       struct maildir_uidlist_rec *rec;
+       struct maildir_uidlist_rec *rec, *const *recs;
+       unsigned int count;
 
        /* we'll update uidlist directly */
        rec = hash_table_lookup(uidlist->files, filename);
@@ -1686,6 +1689,11 @@ maildir_uidlist_sync_next_partial(struct maildir_uidlist_sync_ctx *ctx,
                rec->uid = uid;
                if (uidlist->next_uid <= uid)
                        uidlist->next_uid = uid + 1;
+               else {
+                       recs = array_get(&uidlist->records, &count);
+                       if (count > 1 && uid < recs[count-1]->uid)
+                               uidlist->unsorted = TRUE;
+               }
        }
 
        rec->flags = (rec->flags | flags) & ~MAILDIR_UIDLIST_REC_FLAG_NONSYNCED;
@@ -1693,6 +1701,7 @@ maildir_uidlist_sync_next_partial(struct maildir_uidlist_sync_ctx *ctx,
        hash_table_insert(uidlist->files, rec->filename, rec);
 
        ctx->finished = FALSE;
+       *rec_r = rec;
        return 1;
 }
 
@@ -1719,17 +1728,22 @@ int maildir_uidlist_sync_next(struct maildir_uidlist_sync_ctx *ctx,
                              const char *filename,
                              enum maildir_uidlist_rec_flag flags)
 {
-       return maildir_uidlist_sync_next_uid(ctx, filename, 0, flags);
+       struct maildir_uidlist_rec *rec;
+
+       return maildir_uidlist_sync_next_uid(ctx, filename, 0, flags, &rec);
 }
 
 int maildir_uidlist_sync_next_uid(struct maildir_uidlist_sync_ctx *ctx,
                                  const char *filename, uint32_t uid,
-                                 enum maildir_uidlist_rec_flag flags)
+                                 enum maildir_uidlist_rec_flag flags,
+                                 struct maildir_uidlist_rec **rec_r)
 {
        struct maildir_uidlist *uidlist = ctx->uidlist;
        struct maildir_uidlist_rec *rec, *old_rec;
        const char *p, *dir;
 
+       *rec_r = NULL;
+
        if (ctx->failed)
                return -1;
        for (p = filename; *p != '\0'; p++) {
@@ -1746,7 +1760,7 @@ int maildir_uidlist_sync_next_uid(struct maildir_uidlist_sync_ctx *ctx,
 
        if (ctx->partial) {
                return maildir_uidlist_sync_next_partial(ctx, filename,
-                                                        uid, flags);
+                                                        uid, flags, rec_r);
        }
 
        rec = hash_table_lookup(ctx->files, filename);
@@ -1791,6 +1805,7 @@ int maildir_uidlist_sync_next_uid(struct maildir_uidlist_sync_ctx *ctx,
        rec->flags = (rec->flags | flags) & ~MAILDIR_UIDLIST_REC_FLAG_NONSYNCED;
        rec->filename = p_strdup(ctx->record_pool, filename);
        hash_table_insert(ctx->files, rec->filename, rec);
+       *rec_r = rec;
        return 1;
 }
 
@@ -1823,6 +1838,17 @@ void maildir_uidlist_sync_remove(struct maildir_uidlist_sync_ctx *ctx,
        ctx->uidlist->recreate = TRUE;
 }
 
+void maildir_uidlist_sync_set_ext(struct maildir_uidlist_sync_ctx *ctx,
+                                 struct maildir_uidlist_rec *rec,
+                                 enum maildir_uidlist_rec_ext_key key,
+                                 const char *value)
+{
+       pool_t pool = ctx->partial ?
+               ctx->uidlist->record_pool : ctx->record_pool;
+
+       maildir_uidlist_rec_set_ext(rec, pool, key, value);
+}
+
 const char *
 maildir_uidlist_sync_get_full_filename(struct maildir_uidlist_sync_ctx *ctx,
                                       const char *filename)
index 50f66a50058bf6373c8291aa86898aba11bb28d0..bdd9cb8cc12ba1fb94efa7a3e04e37f9650a8684 100644 (file)
@@ -10,6 +10,7 @@
 struct maildir_mailbox;
 struct maildir_uidlist;
 struct maildir_uidlist_sync_ctx;
+struct maildir_uidlist_rec;
 
 enum maildir_uidlist_sync_flags {
        MAILDIR_UIDLIST_SYNC_PARTIAL    = 0x01,
@@ -44,7 +45,9 @@ enum maildir_uidlist_rec_ext_key {
           isn't written to uidlist. */
        MAILDIR_UIDLIST_REC_EXT_VSIZE           = 'W',
        /* POP3 UIDL overriding the default format */
-       MAILDIR_UIDLIST_REC_EXT_POP3_UIDL       = 'P'
+       MAILDIR_UIDLIST_REC_EXT_POP3_UIDL       = 'P',
+       /* Message GUID (default is the base filename) */
+       MAILDIR_UIDLIST_REC_EXT_GUID            = 'G'
 };
 
 int maildir_uidlist_lock(struct maildir_uidlist *uidlist);
@@ -109,9 +112,14 @@ int maildir_uidlist_sync_next(struct maildir_uidlist_sync_ctx *ctx,
                              enum maildir_uidlist_rec_flag flags);
 int maildir_uidlist_sync_next_uid(struct maildir_uidlist_sync_ctx *ctx,
                                  const char *filename, uint32_t uid,
-                                 enum maildir_uidlist_rec_flag flags);
+                                 enum maildir_uidlist_rec_flag flags,
+                                 struct maildir_uidlist_rec **rec_r);
 void maildir_uidlist_sync_remove(struct maildir_uidlist_sync_ctx *ctx,
                                 const char *filename);
+void maildir_uidlist_sync_set_ext(struct maildir_uidlist_sync_ctx *ctx,
+                                 struct maildir_uidlist_rec *rec,
+                                 enum maildir_uidlist_rec_ext_key key,
+                                 const char *value);
 const char *
 maildir_uidlist_sync_get_full_filename(struct maildir_uidlist_sync_ctx *ctx,
                                       const char *filename);