X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=lib%2Fmessage.cc;h=ee52672a6ca5e1c1d514a31bb63271ac03725baa;hp=1548076dc9decf91a09c5958ee94f8ae676f1e07;hb=4b6063397ffcc13f38757e7052e3dc6649d9703c;hpb=088801a14ab1ccf4c65e5bf7b50b3a1172c477d7 diff --git a/lib/message.cc b/lib/message.cc index 1548076d..ee52672a 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -32,7 +32,7 @@ struct _notmuch_message { char *message_id; char *thread_id; char *in_reply_to; - char *filename; + notmuch_filename_list_t *filename_list; char *author; notmuch_message_file_t *message_file; notmuch_message_list_t *replies; @@ -55,8 +55,7 @@ struct maildir_flag_tag flag2tag[] = { { 'F', "flagged", false}, { 'P', "passed", false}, { 'R', "replied", false}, - { 'S', "unread", true }, - { 'T', "deleted", false}, + { 'S', "unread", true } }; /* We end up having to call the destructor explicitly because we had @@ -102,7 +101,7 @@ _notmuch_message_create_for_document (const void *talloc_owner, message->message_id = NULL; message->thread_id = NULL; message->in_reply_to = NULL; - message->filename = NULL; + message->filename_list = NULL; message->message_file = NULL; message->author = NULL; @@ -433,9 +432,9 @@ _notmuch_message_add_filename (notmuch_message_t *message, void *local = talloc_new (message); char *direntry; - if (message->filename) { - talloc_free (message->filename); - message->filename = NULL; + if (message->filename_list) { + _notmuch_filename_list_destroy (message->filename_list); + message->filename_list = NULL; } if (filename == NULL) @@ -466,28 +465,23 @@ _notmuch_message_clear_data (notmuch_message_t *message) message->doc.set_data (""); } -const char * -notmuch_message_get_filename (notmuch_message_t *message) +static void +_notmuch_message_ensure_filename_list (notmuch_message_t *message) { const char *prefix = _find_prefix ("file-direntry"); int prefix_len = strlen (prefix); Xapian::TermIterator i; - char *colon, *direntry = NULL; - const char *db_path, *directory, *basename; - unsigned int directory_id; - void *local = talloc_new (message); - if (message->filename) - return message->filename; + if (message->filename_list) + return; + + message->filename_list = _notmuch_filename_list_create (message); i = message->doc.termlist_begin (); i.skip_to (prefix); - if (i != message->doc.termlist_end ()) - direntry = talloc_strdup (local, (*i).c_str ()); - if (i == message->doc.termlist_end () || - strncmp (direntry, prefix, prefix_len)) + strncmp ((*i).c_str (), prefix, prefix_len)) { /* A message document created by an old version of notmuch * (prior to rename support) will have the filename in the @@ -502,39 +496,77 @@ notmuch_message_get_filename (notmuch_message_t *message) if (data == NULL) INTERNAL_ERROR ("message with no filename"); - message->filename = talloc_strdup (message, data); + _notmuch_filename_list_add_filename (message->filename_list, data); - return message->filename; + return; } - direntry += prefix_len; + for (; i != message->doc.termlist_end (); i++) { + void *local = talloc_new (message); + const char *db_path, *directory, *basename, *filename; + char *colon, *direntry = NULL; + unsigned int directory_id; - directory_id = strtol (direntry, &colon, 10); + /* Terminate loop at first term without desired prefix. */ + if (strncmp ((*i).c_str (), prefix, prefix_len)) + break; - if (colon == NULL || *colon != ':') - INTERNAL_ERROR ("malformed direntry"); + direntry = talloc_strdup (local, (*i).c_str ()); - basename = colon + 1; + direntry += prefix_len; - *colon = '\0'; + directory_id = strtol (direntry, &colon, 10); - db_path = notmuch_database_get_path (message->notmuch); + if (colon == NULL || *colon != ':') + INTERNAL_ERROR ("malformed direntry"); - directory = _notmuch_database_get_directory_path (local, - message->notmuch, - directory_id); + basename = colon + 1; - if (strlen (directory)) - message->filename = talloc_asprintf (message, "%s/%s/%s", - db_path, directory, basename); - else - message->filename = talloc_asprintf (message, "%s/%s", - db_path, basename); - talloc_free ((void *) directory); + *colon = '\0'; - talloc_free (local); + db_path = notmuch_database_get_path (message->notmuch); + + directory = _notmuch_database_get_directory_path (local, + message->notmuch, + directory_id); + + if (strlen (directory)) + filename = talloc_asprintf (message, "%s/%s/%s", + db_path, directory, basename); + else + filename = talloc_asprintf (message, "%s/%s", + db_path, basename); - return message->filename; + _notmuch_filename_list_add_filename (message->filename_list, + filename); + + talloc_free (local); + } +} + +const char * +notmuch_message_get_filename (notmuch_message_t *message) +{ + _notmuch_message_ensure_filename_list (message); + + if (message->filename_list == NULL) + return NULL; + + if (message->filename_list->head == NULL || + message->filename_list->head->filename == NULL) + { + INTERNAL_ERROR ("message with no filename"); + } + + return message->filename_list->head->filename; +} + +notmuch_filenames_t * +notmuch_message_get_filenames (notmuch_message_t *message) +{ + _notmuch_message_ensure_filename_list (message); + + return _notmuch_filenames_create (message, message->filename_list); } notmuch_bool_t @@ -611,29 +643,15 @@ _notmuch_message_set_date (notmuch_message_t *message, Xapian::sortable_serialise (time_value)); } -static notmuch_private_status_t -_notmuch_message_tags_to_maildir (notmuch_message_t *message); - /* Synchronize changes made to message->doc out into the database. */ void _notmuch_message_sync (notmuch_message_t *message) { Xapian::WritableDatabase *db; - notmuch_private_status_t status; if (message->notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY) return; - if (// todo_sync_enabled && - !notmuch_message_get_flag(message, NOTMUCH_MESSAGE_FLAG_TAGS_INVALID)) { - status = _notmuch_message_tags_to_maildir (message); - if (status != NOTMUCH_PRIVATE_STATUS_SUCCESS) { - fprintf (stderr, "Error: Cannot sync tags to maildir (%s)\n", - notmuch_status_to_string ((notmuch_status_t)status)); - /* Exit to avoid unsynchronized mailstore. */ - exit(1); - } - } db = static_cast (message->notmuch->xapian_db); db->replace_document (message->doc_id, message->doc); } @@ -750,7 +768,7 @@ _notmuch_message_remove_term (notmuch_message_t *message, * This change will not be reflected in the database until the next * call to _notmuch_message_sync. */ -notmuch_private_status_t +notmuch_status_t _notmuch_message_rename (notmuch_message_t *message, const char *new_filename) { @@ -758,29 +776,31 @@ _notmuch_message_rename (notmuch_message_t *message, char *direntry; Xapian::PostingIterator i, end; Xapian::Document document; - notmuch_private_status_t pstatus; + notmuch_private_status_t private_status; notmuch_status_t status; const char *old_filename; old_filename = notmuch_message_get_filename(message); old_filename = talloc_reference(local, old_filename); - if (unlikely(!old_filename)) - return NOTMUCH_PRIVATE_STATUS_OUT_OF_MEMORY; + if (unlikely (! old_filename)) + return NOTMUCH_STATUS_OUT_OF_MEMORY; status = _notmuch_message_add_filename (message, new_filename); if (status) - return (notmuch_private_status_t)status; + return status; status = _notmuch_database_filename_to_direntry (local, message->notmuch, old_filename, &direntry); if (status) - return (notmuch_private_status_t)status; + return status; - pstatus = _notmuch_message_remove_term (message, "file-direntry", direntry); + private_status = _notmuch_message_remove_term (message, "file-direntry", direntry); + status = COERCE_STATUS (private_status, + "Unexpected error from _notmuch_message_remove_term"); talloc_free (local); - return pstatus; + return status; } notmuch_status_t @@ -840,48 +860,39 @@ notmuch_message_remove_tag (notmuch_message_t *message, const char *tag) } notmuch_status_t -notmuch_message_maildir_to_tags (notmuch_message_t *message, const char *filename) +notmuch_message_maildir_flags_to_tags (notmuch_message_t *message) { - const char *flags, *p; - char f; - bool valid, unread; - unsigned i; + const char *flags; notmuch_status_t status; + notmuch_filenames_t *filenames; + const char *filename; + char *combined_flags = talloc_strdup (message, ""); + unsigned i; - flags = strstr (filename, ":2,"); - if (!flags) - return NOTMUCH_STATUS_FILE_NOT_EMAIL; - flags += 3; - - /* Check that the letters are valid Maildir flags */ - f = 0; - valid = true; - for (p=flags; valid && *p; p++) { - switch (*p) { - case 'P': - case 'R': - case 'S': - case 'T': - case 'D': - case 'F': - if (*p > f) f=*p; - else valid = false; - break; - default: - valid = false; - } - } - if (!valid) { - fprintf (stderr, "Warning: Invalid maildir flags in filename %s\n", filename); - return NOTMUCH_STATUS_FILE_NOT_EMAIL; + for (filenames = notmuch_message_get_filenames (message); + notmuch_filenames_valid (filenames); + notmuch_filenames_move_to_next (filenames)) + { + filename = notmuch_filenames_get (filenames); + + flags = strstr (filename, ":2,"); + if (! flags) + continue; + + flags += 3; + + combined_flags = talloc_strdup_append (combined_flags, flags); } status = notmuch_message_freeze (message); if (status) return status; - unread = true; + for (i = 0; i < ARRAY_SIZE(flag2tag); i++) { - if ((strchr (flags, flag2tag[i].flag) != NULL) ^ flag2tag[i].inverse) { + if ((strchr (combined_flags, flag2tag[i].flag) != NULL) + ^ + flag2tag[i].inverse) + { status = notmuch_message_add_tag (message, flag2tag[i].tag); } else { status = notmuch_message_remove_tag (message, flag2tag[i].tag); @@ -891,9 +902,8 @@ notmuch_message_maildir_to_tags (notmuch_message_t *message, const char *filenam } status = notmuch_message_thaw (message); - /* From now on, we can synchronize the tags from the database to - * the mailstore. */ - notmuch_message_set_flag (message, NOTMUCH_MESSAGE_FLAG_TAGS_INVALID, FALSE); + talloc_free (combined_flags); + return status; } @@ -943,10 +953,14 @@ maildir_get_subdir (char *filename) return subdir; } -/* Rename the message file so that maildir flags corresponds to the - * tags and, if aplicable, move the message from new/ to cur/. */ -static notmuch_private_status_t -_notmuch_message_tags_to_maildir (notmuch_message_t *message) +/* XXX: Needs to iterate over all filenames in the message + * + * XXX: Needs to ensure that existing, unsupported flags in the + * filename are left unchanged (which also needs a test in the + * test suite). + */ +notmuch_status_t +notmuch_message_tags_to_maildir_flags (notmuch_message_t *message) { char flags[ARRAY_SIZE(flag2tag)+1]; const char *filename, *p; @@ -963,14 +977,15 @@ _notmuch_message_tags_to_maildir (notmuch_message_t *message) // Return if flags are not to be changed - this suppresses // moving the message from new/ to cur/ during initial // tagging. - return NOTMUCH_PRIVATE_STATUS_SUCCESS; + return NOTMUCH_STATUS_SUCCESS; } if (!p) p = filename + strlen(filename); filename_new = (char*)talloc_size(message, (p-filename) + 3 + sizeof(flags)); if (unlikely (filename_new == NULL)) - return NOTMUCH_PRIVATE_STATUS_OUT_OF_MEMORY; + return NOTMUCH_STATUS_OUT_OF_MEMORY; + memcpy(filename_new, filename, p-filename); filename_new[p-filename] = '\0'; @@ -992,7 +1007,7 @@ _notmuch_message_tags_to_maildir (notmuch_message_t *message) return _notmuch_message_rename (message, filename_new); /* _notmuch_message_sync is our caller. Do not call it here. */ } - return NOTMUCH_PRIVATE_STATUS_SUCCESS; + return NOTMUCH_STATUS_SUCCESS; } notmuch_status_t