X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=lib%2Fmessage.cc;h=c91f3a59836f65ceb9b92a8e337603ea2d2a69ea;hp=00754254b87bc387420529a66082a3887ec69a4e;hb=29f125212619ebca8621dd2106b412b22e1b6d22;hpb=ac8576de63b4383aef597e1db5af939e3b46594c diff --git a/lib/message.cc b/lib/message.cc index 00754254..c91f3a59 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -266,18 +266,18 @@ _notmuch_message_get_term (notmuch_message_t *message, const char *prefix) { int prefix_len = strlen (prefix); - const char *term = NULL; char *value; i.skip_to (prefix); - if (i != end) - term = (*i).c_str (); + if (i == end) + return NULL; - if (!term || strncmp (term, prefix, prefix_len)) + std::string term = *i; + if (strncmp (term.c_str(), prefix, prefix_len)) return NULL; - value = talloc_strdup (message, term + prefix_len); + value = talloc_strdup (message, term.c_str() + prefix_len); #if DEBUG_DATABASE_SANITY i++; @@ -412,19 +412,27 @@ _notmuch_message_ensure_message_file (notmuch_message_t *message) const char * notmuch_message_get_header (notmuch_message_t *message, const char *header) { - std::string value; + try { + std::string value; - /* Fetch header from the appropriate xapian value field if - * available */ - if (strcasecmp (header, "from") == 0) - value = message->doc.get_value (NOTMUCH_VALUE_FROM); - else if (strcasecmp (header, "subject") == 0) - value = message->doc.get_value (NOTMUCH_VALUE_SUBJECT); - else if (strcasecmp (header, "message-id") == 0) - value = message->doc.get_value (NOTMUCH_VALUE_MESSAGE_ID); + /* Fetch header from the appropriate xapian value field if + * available */ + if (strcasecmp (header, "from") == 0) + value = message->doc.get_value (NOTMUCH_VALUE_FROM); + else if (strcasecmp (header, "subject") == 0) + value = message->doc.get_value (NOTMUCH_VALUE_SUBJECT); + else if (strcasecmp (header, "message-id") == 0) + value = message->doc.get_value (NOTMUCH_VALUE_MESSAGE_ID); - if (!value.empty()) - return talloc_strdup (message, value.c_str ()); + if (!value.empty()) + return talloc_strdup (message, value.c_str ()); + + } catch (Xapian::Error &error) { + fprintf (stderr, "A Xapian exception occurred when reading header: %s\n", + error.get_msg().c_str()); + message->notmuch->exception_reported = TRUE; + return NULL; + } /* Otherwise fall back to parsing the file */ _notmuch_message_ensure_message_file (message); @@ -462,9 +470,9 @@ notmuch_message_get_thread_id (notmuch_message_t *message) void _notmuch_message_add_reply (notmuch_message_t *message, - notmuch_message_node_t *reply) + notmuch_message_t *reply) { - _notmuch_message_list_append (message->replies, reply); + _notmuch_message_list_add_message (message->replies, reply); } notmuch_messages_t * @@ -495,9 +503,8 @@ _notmuch_message_add_filename (notmuch_message_t *message, if (status) return status; - status = _notmuch_database_filename_to_direntry (local, - message->notmuch, - filename, &direntry); + status = _notmuch_database_filename_to_direntry ( + local, message->notmuch, filename, NOTMUCH_FIND_CREATE, &direntry); if (status) return status; @@ -541,9 +548,9 @@ _notmuch_message_remove_filename (notmuch_message_t *message, notmuch_status_t status; Xapian::TermIterator i, last; - status = _notmuch_database_filename_to_direntry (local, message->notmuch, - filename, &direntry); - if (status) + status = _notmuch_database_filename_to_direntry ( + local, message->notmuch, filename, NOTMUCH_FIND_LOOKUP, &direntry); + if (status || !direntry) return status; /* Unlink this file from its parent directory. */ @@ -767,7 +774,9 @@ notmuch_message_get_date (notmuch_message_t *message) try { value = message->doc.get_value (NOTMUCH_VALUE_TIMESTAMP); } catch (Xapian::Error &error) { - INTERNAL_ERROR ("Failed to read timestamp value from document."); + fprintf (stderr, "A Xapian exception occurred when reading date: %s\n", + error.get_msg().c_str()); + message->notmuch->exception_reported = TRUE; return 0; } @@ -789,7 +798,9 @@ notmuch_message_get_tags (notmuch_message_t *message) * possible to modify the message tags (which talloc_unlink's the * current list from the message) while still iterating because * the iterator will keep the current list alive. */ - talloc_reference (message, message->tag_list); + if (!talloc_reference (message, message->tag_list)) + return NULL; + return tags; } @@ -1028,13 +1039,54 @@ notmuch_message_remove_tag (notmuch_message_t *message, const char *tag) return NOTMUCH_STATUS_SUCCESS; } +/* Is the given filename within a maildir directory? + * + * Specifically, is the final directory component of 'filename' either + * "cur" or "new". If so, return a pointer to that final directory + * component within 'filename'. If not, return NULL. + * + * A non-NULL return value is guaranteed to be a valid string pointer + * pointing to the characters "new/" or "cur/", (but not + * NUL-terminated). + */ +static const char * +_filename_is_in_maildir (const char *filename) +{ + const char *slash, *dir = NULL; + + /* Find the last '/' separating directory from filename. */ + slash = strrchr (filename, '/'); + if (slash == NULL) + return NULL; + + /* Jump back 4 characters to where the previous '/' will be if the + * directory is named "cur" or "new". */ + if (slash - filename < 4) + return NULL; + + slash -= 4; + + if (*slash != '/') + return NULL; + + dir = slash + 1; + + if (STRNCMP_LITERAL (dir, "cur/") == 0 || + STRNCMP_LITERAL (dir, "new/") == 0) + { + return dir; + } + + return NULL; +} + notmuch_status_t notmuch_message_maildir_flags_to_tags (notmuch_message_t *message) { const char *flags; notmuch_status_t status; notmuch_filenames_t *filenames; - const char *filename; + const char *filename, *dir; char *combined_flags = talloc_strdup (message, ""); unsigned i; int seen_maildir_info = 0; @@ -1044,15 +1096,25 @@ notmuch_message_maildir_flags_to_tags (notmuch_message_t *message) notmuch_filenames_move_to_next (filenames)) { filename = notmuch_filenames_get (filenames); + dir = _filename_is_in_maildir (filename); - flags = strstr (filename, ":2,"); - if (! flags) + if (! dir) continue; - seen_maildir_info = 1; - flags += 3; - - combined_flags = talloc_strdup_append (combined_flags, flags); + flags = strstr (filename, ":2,"); + if (flags) { + seen_maildir_info = 1; + flags += 3; + combined_flags = talloc_strdup_append (combined_flags, flags); + } else if (STRNCMP_LITERAL (dir, "new/") == 0) { + /* Messages are delivered to new/ with no "info" part, but + * they effectively have default maildir flags. According + * to the spec, we should ignore the info part for + * messages in new/, but some MUAs (mutt) can set maildir + * flags on messages in new/, so we're liberal in what we + * accept. */ + seen_maildir_info = 1; + } } /* If none of the filenames have any maildir info field (not even @@ -1084,47 +1146,6 @@ notmuch_message_maildir_flags_to_tags (notmuch_message_t *message) return status; } -/* Is the given filename within a maildir directory? - * - * Specifically, is the final directory component of 'filename' either - * "cur" or "new". If so, return a pointer to that final directory - * component within 'filename'. If not, return NULL. - * - * A non-NULL return value is guaranteed to be a valid string pointer - * pointing to the characters "new/" or "cur/", (but not - * NUL-terminated). - */ -static const char * -_filename_is_in_maildir (const char *filename) -{ - const char *slash, *dir = NULL; - - /* Find the last '/' separating directory from filename. */ - slash = strrchr (filename, '/'); - if (slash == NULL) - return NULL; - - /* Jump back 4 characters to where the previous '/' will be if the - * directory is named "cur" or "new". */ - if (slash - filename < 4) - return NULL; - - slash -= 4; - - if (*slash != '/') - return NULL; - - dir = slash + 1; - - if (STRNCMP_LITERAL (dir, "cur/") == 0 || - STRNCMP_LITERAL (dir, "new/") == 0) - { - return dir; - } - - return NULL; -} - /* From the set of tags on 'message' and the flag2tag table, compute a * set of maildir-flag actions to be taken, (flags that should be * either set or cleared). @@ -1184,7 +1205,9 @@ _get_maildir_flag_actions (notmuch_message_t *message, * compute the new maildir filename. * * If the existing filename is in the directory "new", the new - * filename will be in the directory "cur". + * filename will be in the directory "cur", except for the case when + * no flags are changed and the existing filename does not contain + * maildir info (starting with ",2:"). * * After a sequence of ":2," in the filename, any subsequent * single-character flags will be added or removed according to the @@ -1207,6 +1230,7 @@ _new_maildir_filename (void *ctx, char *filename_new, *dir; char flag_map[128]; int flags_in_map = 0; + notmuch_bool_t flags_changed = FALSE; unsigned int i; char *s; @@ -1247,6 +1271,7 @@ _new_maildir_filename (void *ctx, if (flag_map[flag] == 0) { flag_map[flag] = 1; flags_in_map++; + flags_changed = TRUE; } } @@ -1255,9 +1280,16 @@ _new_maildir_filename (void *ctx, if (flag_map[flag]) { flag_map[flag] = 0; flags_in_map--; + flags_changed = TRUE; } } + /* Messages in new/ without maildir info can be kept in new/ if no + * flags have changed. */ + dir = (char *) _filename_is_in_maildir (filename); + if (dir && STRNCMP_LITERAL (dir, "new/") == 0 && !*info && !flags_changed) + return talloc_strdup (ctx, filename); + filename_new = (char *) talloc_size (ctx, info - filename + strlen (":2,") + flags_in_map + 1);