]> granicus.if.org Git - neomutt/commitdiff
sync flags for all duplicate messages
authorKarel Zak <kzak@redhat.com>
Mon, 17 Sep 2012 07:31:54 +0000 (09:31 +0200)
committerRichard Russon <rich@flatcap.org>
Mon, 4 Apr 2016 15:30:06 +0000 (16:30 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
mh.c
mutt_notmuch.c
mx.h

diff --git a/mh.c b/mh.c
index 2f9f06e756c5ae3cab1ec54d10b38f21d45e081d..8fa900904ce7dca1d105e506be408f3297160f30 100644 (file)
--- a/mh.c
+++ b/mh.c
@@ -1307,7 +1307,7 @@ static int ch_compar (const void *a, const void *b)
   return (int)( *((const char *) a) - *((const char *) b));
 }
 
-static void maildir_flags (char *dest, size_t destlen, HEADER * hdr)
+void maildir_flags (char *dest, size_t destlen, HEADER * hdr)
 {
   *dest = '\0';
 
index 4b824a70480141d04f3b91de042db15e632a2486..0ffe83d38a0d878763a9d94df93e461c82daccf2 100644 (file)
@@ -657,6 +657,34 @@ static int init_header(HEADER *h, const char *path, notmuch_message_t *msg)
        return 0;
 }
 
+/**
+static void debug_print_filenames(notmuch_message_t *msg)
+{
+       notmuch_filenames_t *ls;
+       const char *id = notmuch_message_get_message_id(msg);
+
+       for (ls = notmuch_message_get_filenames(msg);
+            ls && notmuch_filenames_valid(ls);
+            notmuch_filenames_move_to_next(ls)) {
+
+               dprint(2, (debugfile, "nm: %s: %s\n", id, notmuch_filenames_get(ls)));
+       }
+}
+
+static void debug_print_tags(notmuch_message_t *msg)
+{
+       notmuch_tags_t *tags;
+       const char *id = notmuch_message_get_message_id(msg);
+
+       for (tags = notmuch_message_get_tags(msg);
+            tags && notmuch_tags_valid(tags);
+            notmuch_tags_move_to_next(tags)) {
+
+               dprint(2, (debugfile, "nm: %s: %s\n", id, notmuch_tags_get(tags)));
+       }
+}
+***/
+
 static const char *get_message_last_filename(notmuch_message_t *msg)
 {
        notmuch_filenames_t *ls;
@@ -977,12 +1005,57 @@ done:
        return rc;
 }
 
+static int rename_maildir_filename(const char *old, char *newpath, size_t newsz, HEADER *h)
+{
+       char filename[_POSIX_PATH_MAX];
+       char suffix[_POSIX_PATH_MAX];
+       char folder[_POSIX_PATH_MAX];
+       char *p;
+
+       strfcpy(folder, old, sizeof(folder));
+       p = strrchr(folder, '/');
+       if (p)
+               *p = '\0';
+
+       p++;
+       strfcpy(filename, p, sizeof(filename));
+
+       /* remove (new,cur,...) from folder path */
+       p = strrchr(folder, '/');
+       if (p)
+               *p = '\0';
+
+       /* remove old flags from filename */
+       if ((p = strchr(filename, ':')))
+               *p = '\0';
+
+       /* compose new flags */
+       maildir_flags(suffix, sizeof(suffix), h);
+
+       snprintf(newpath, newsz, "%s/%s/%s%s",
+                       folder,
+                       (h->read || h->old) ? "cur" : "new",
+                       filename,
+                       suffix);
+
+       if (strcmp(old, newpath) == 0)
+               return 1;
+
+       if (rename(old, newpath) != 0) {
+               dprint(1, (debugfile, "nm: rename(2) failed %s -> %s\n", old, newpath));
+               return -1;
+       }
+
+       return 0;
+}
+
 static int remove_filename(notmuch_database_t *db, const char *path)
 {
        notmuch_status_t st;
+       notmuch_filenames_t *ls;
        notmuch_message_t *msg = NULL;
 
-       dprint(2, (debugfile, "nm: removing filename '%s'\n", path));
+       dprint(2, (debugfile, "nm: remove filename '%s'\n", path));
 
        st = notmuch_database_begin_atomic(db);
        if (st)
@@ -992,74 +1065,111 @@ static int remove_filename(notmuch_database_t *db, const char *path)
        if (st || !msg)
                return -1;
 
+       /*
+        * note that unlink() is probably unecessary here, it's already removed
+        * by mh_sync_mailbox_message(), but for sure...
+        */
        st = notmuch_database_remove_message(db, path);
-       if (st != NOTMUCH_STATUS_SUCCESS &&
-           st != NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID)
-               dprint(1, (debugfile, "nm: failed to remove '%s' [st=%d]\n",
-                                               path, (int) st));
+       switch (st) {
+       case NOTMUCH_STATUS_SUCCESS:
+               unlink(path);
+               break;
+       case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
+               unlink(path);
+               for (ls = notmuch_message_get_filenames(msg);
+                    ls && notmuch_filenames_valid(ls);
+                    notmuch_filenames_move_to_next(ls)) {
 
-       if (st == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID)
-               notmuch_message_maildir_flags_to_tags(msg);
+                       path = notmuch_filenames_get(ls);
+
+                       dprint(2, (debugfile, "nm: remove duplicate: '%s'\n", path));
+                       unlink(path);
+                       notmuch_database_remove_message(db, path);
+               }
+               break;
+       default:
+               dprint(1, (debugfile, "nm: failed to remove '%s' [st=%d]\n", path, (int) st));
+               break;
+       }
 
        notmuch_message_destroy(msg);
        notmuch_database_end_atomic(db);
        return 0;
 }
 
-static int add_filename(notmuch_database_t *db, const char *path, HEADER *h)
+static int rename_filename(notmuch_database_t *db,
+                       const char *old, const char *new, HEADER *h)
 {
        int rc = -1;
        notmuch_status_t st;
+       notmuch_filenames_t *ls;
        notmuch_message_t *msg;
 
-       dprint(2, (debugfile, "nm: adding filename '%s'\n", path));
+       if (!db || !new || !old || access(new, F_OK) != 0)
+               return -1;
 
+       dprint(1, (debugfile, "nm: rename filename, %s -> %s\n", old, new));
        st = notmuch_database_begin_atomic(db);
        if (st)
                return -1;
 
-       st = notmuch_database_add_message(db, path, &msg);
+       dprint(2, (debugfile, "nm: rename: add '%s'\n", new));
+       st = notmuch_database_add_message(db, new, &msg);
+
+       if (st != NOTMUCH_STATUS_SUCCESS &&
+           st != NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {
+               dprint(1, (debugfile, "nm: failed to add '%s' [st=%d]\n", new, (int) st));
+               goto done;
+       }
+
+       dprint(2, (debugfile, "nm: rename: rem '%s'\n", old));
+       st = notmuch_database_remove_message(db, old);
        switch (st) {
        case NOTMUCH_STATUS_SUCCESS:
-               if (h)
-                       update_tags(msg, nm_header_get_tags(h));
                break;
        case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
-               notmuch_message_maildir_flags_to_tags(msg);
+               dprint(2, (debugfile, "nm: rename: syncing duplicate filename\n"));
+               notmuch_message_destroy(msg);
+               msg = NULL;
+               notmuch_database_find_message_by_filename(db, new, &msg);
+
+               for (ls = notmuch_message_get_filenames(msg);
+                    msg && ls && notmuch_filenames_valid(ls);
+                    notmuch_filenames_move_to_next(ls)) {
+
+                       const char *path = notmuch_filenames_get(ls);
+                       char newpath[_POSIX_PATH_MAX];
+
+                       if (strcmp(new, path) == 0)
+                               continue;
+
+                       if (rename_maildir_filename(path, newpath, sizeof(newpath), h) == 0) {
+                               dprint(2, (debugfile, "nm: rename dup %s -> %s\n", path, newpath));
+                               notmuch_database_remove_message(db, path);
+                               notmuch_database_add_message(db, newpath, NULL);
+                       }
+               }
+               st = NOTMUCH_STATUS_SUCCESS;
                break;
        default:
-               dprint(1, (debugfile, "nm: failed to add '%s' [st=%d]\n",
-                                       path, (int) st));
-               goto done;
+               dprint(1, (debugfile, "nm: failed to remove '%s' [st=%d]\n",
+                                       old, (int) st));
+               break;
        }
 
-       st = notmuch_database_end_atomic(db);
-       if (st)
-           goto done;
+       if (st == NOTMUCH_STATUS_SUCCESS && h && msg) {
+               notmuch_message_maildir_flags_to_tags(msg);
+               update_tags(msg, nm_header_get_tags(h));
+       }
 
        rc = 0;
 done:
        if (msg)
-           notmuch_message_destroy(msg);
+               notmuch_message_destroy(msg);
+       notmuch_database_end_atomic(db);
        return rc;
 }
 
-static int rename_filename(notmuch_database_t *db,
-                       const char *old, const char *new, HEADER *h)
-{
-       if (!db)
-               return -1;
-
-       dprint(1, (debugfile, "nm: rename filename, %s -> %s\n", old, new));
-
-       if (new && access(new, F_OK) == 0 && add_filename(db, new, h) != 0)
-               return -1;
-       if (old && remove_filename(db, old) != 0)
-               return -1;
-
-       return 0;
-}
-
 int nm_update_filename(CONTEXT *ctx, const char *old, const char *new, HEADER *h)
 {
        struct nm_ctxdata *data = get_ctxdata(ctx);
diff --git a/mx.h b/mx.h
index 8939d682bde2ff6599038e638e89b7ed78822745..3db436ab8654eb9cb628a94b6146ab833621b646 100644 (file)
--- a/mx.h
+++ b/mx.h
@@ -72,6 +72,7 @@ HEADER *maildir_parse_message (int magic, const char *fname, int is_old, HEADER
 HEADER *maildir_parse_stream (int magic, FILE *f, const char *fname, int is_old, HEADER * _h);
 void maildir_parse_flags (HEADER * h, const char *path);
 void maildir_update_flags (CONTEXT *ctx, HEADER *o, HEADER *n);
+void maildir_flags(char *dest, size_t destlen, HEADER * hdr);
 
 #if USE_HCACHE
 #include <hcache.h>