X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=message.cc;h=154efa0fd47ebde90460ed1516256715b902f723;hp=6e15b51118be82b960fb13aae667241fdbf36048;hb=fa226a7a10ba95f8d8a7ff92dbfc44f6404d9d4d;hpb=31db02a8c1afdb025da6e0e7e62630ffffc69eb7 diff --git a/message.cc b/message.cc index 6e15b511..154efa0f 100644 --- a/message.cc +++ b/message.cc @@ -21,6 +21,8 @@ #include "notmuch-private.h" #include "database-private.h" +#include + #include struct _notmuch_message { @@ -146,7 +148,8 @@ _notmuch_message_create (const void *talloc_owner, * If there is already a document with message ID 'message_id' in the * database, then the returned message can be used to query/modify the * document. Otherwise, a new document will be inserted into the - * database before this function returns. + * database before this function returns, (and *status will be set + * to NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND). * * If an error occurs, this function will return NULL and *status * will be set as appropriate. (The status pointer argument must @@ -156,15 +159,14 @@ notmuch_message_t * _notmuch_message_create_for_message_id (const void *talloc_owner, notmuch_database_t *notmuch, const char *message_id, - notmuch_status_t *status) + notmuch_private_status_t *status_ret) { - notmuch_private_status_t private_status; notmuch_message_t *message; Xapian::Document doc; unsigned int doc_id; char *term; - *status = NOTMUCH_STATUS_SUCCESS; + *status_ret = NOTMUCH_PRIVATE_STATUS_SUCCESS; message = notmuch_database_find_message (notmuch, message_id); if (message) @@ -173,7 +175,7 @@ _notmuch_message_create_for_message_id (const void *talloc_owner, term = talloc_asprintf (NULL, "%s%s", _find_prefix ("id"), message_id); if (term == NULL) { - *status = NOTMUCH_STATUS_OUT_OF_MEMORY; + *status_ret = NOTMUCH_PRIVATE_STATUS_OUT_OF_MEMORY; return NULL; } @@ -185,15 +187,17 @@ _notmuch_message_create_for_message_id (const void *talloc_owner, doc_id = notmuch->xapian_db->add_document (doc); } catch (const Xapian::Error &error) { - *status = NOTMUCH_STATUS_XAPIAN_EXCEPTION; + *status_ret = NOTMUCH_PRIVATE_STATUS_XAPIAN_EXCEPTION; return NULL; } message = _notmuch_message_create (talloc_owner, notmuch, - doc_id, &private_status); + doc_id, status_ret); - *status = COERCE_STATUS (private_status, - "Failed to find dcocument after inserting it."); + /* We want to inform the caller that we had to create a new + * document. */ + if (*status_ret == NOTMUCH_PRIVATE_STATUS_SUCCESS) + *status_ret = NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND; return message; } @@ -230,26 +234,50 @@ notmuch_message_get_message_id (notmuch_message_t *message) return message->message_id; } +static void +_notmuch_message_ensure_message_file (notmuch_message_t *message) +{ + const char *filename; + + if (message->message_file) + return; + + filename = notmuch_message_get_filename (message); + if (unlikely (filename == NULL)) + return; + + message->message_file = _notmuch_message_file_open_ctx (message, filename); +} + +const char * +notmuch_message_get_header (notmuch_message_t *message, const char *header) +{ + _notmuch_message_ensure_message_file (message); + if (message->message_file == NULL) + return NULL; + + return notmuch_message_file_get_header (message->message_file, header); +} + const char * -_notmuch_message_get_subject (notmuch_message_t *message) +notmuch_message_get_all_headers (notmuch_message_t *message) { - if (! message->message_file) { - notmuch_message_file_t *message_file; - const char *filename; + _notmuch_message_ensure_message_file (message); + if (message->message_file == NULL) + return NULL; - filename = notmuch_message_get_filename (message); - if (unlikely (filename == NULL)) - return NULL; + return notmuch_message_file_get_all_headers (message->message_file); +} - message_file = _notmuch_message_file_open_ctx (message, filename); - if (unlikely (message_file == NULL)) - return NULL; +size_t +notmuch_message_get_header_size (notmuch_message_t *message) +{ + _notmuch_message_ensure_message_file (message); + if (message->message_file == NULL) + return 0; - message->message_file = message_file; - } + return notmuch_message_file_get_header_size (message->message_file); - return notmuch_message_file_get_header (message->message_file, - "subject"); } const char * @@ -276,8 +304,10 @@ notmuch_message_get_thread_id (notmuch_message_t *message) strncmp ((*i).c_str (), _find_prefix ("thread"), strlen (_find_prefix ("thread"))) == 0) { - INTERNAL_ERROR ("Message with document ID of %d has duplicate thread IDs.\n", - message->doc_id); + INTERNAL_ERROR ("Message %s has duplicate thread IDs: %s and %s\n", + notmuch_message_get_message_id (message), + message->thread_id, + (*i).c_str () + 1); } #endif @@ -295,25 +325,68 @@ void _notmuch_message_set_filename (notmuch_message_t *message, const char *filename) { - if (message->filename) + const char *s; + const char *db_path; + unsigned int db_path_len; + + if (message->filename) { talloc_free (message->filename); - message->doc.set_data (filename); + message->filename = NULL; + } + + if (filename == NULL) + INTERNAL_ERROR ("Message filename cannot be NULL."); + + s = filename; + + db_path = notmuch_database_get_path (message->notmuch); + db_path_len = strlen (db_path); + + if (*s == '/' && strncmp (s, db_path, db_path_len) == 0 + && strlen (s) > db_path_len) + { + s += db_path_len + 1; + } + + message->doc.set_data (s); } const char * notmuch_message_get_filename (notmuch_message_t *message) { std::string filename_str; + const char *db_path; if (message->filename) return message->filename; filename_str = message->doc.get_data (); - message->filename = talloc_strdup (message, filename_str.c_str ()); + db_path = notmuch_database_get_path (message->notmuch); + + if (filename_str[0] != '/') + message->filename = talloc_asprintf (message, "%s/%s", db_path, + filename_str.c_str ()); + else + message->filename = talloc_strdup (message, filename_str.c_str ()); return message->filename; } +time_t +notmuch_message_get_date (notmuch_message_t *message) +{ + std::string value; + + try { + value = message->doc.get_value (NOTMUCH_VALUE_TIMESTAMP); + } catch (Xapian::Error &error) { + INTERNAL_ERROR ("Failed to read timestamp value from document."); + return 0; + } + + return Xapian::sortable_unserialise (value); +} + notmuch_tags_t * notmuch_message_get_tags (notmuch_message_t *message) { @@ -357,7 +430,7 @@ _notmuch_message_set_date (notmuch_message_t *message, { time_t time_value; - time_value = notmuch_parse_date (date, NULL); + time_value = g_mime_utils_header_decode_date (date, NULL); message->doc.add_value (NOTMUCH_VALUE_TIMESTAMP, Xapian::sortable_serialise (time_value)); @@ -442,6 +515,32 @@ _notmuch_message_add_term (notmuch_message_t *message, return NOTMUCH_PRIVATE_STATUS_SUCCESS; } +/* Parse 'text' and add a term to 'message' for each parsed word. Each + * term will be added both prefixed (if prefix_name is not NULL) and + * also unprefixed). */ +notmuch_private_status_t +_notmuch_message_gen_terms (notmuch_message_t *message, + const char *prefix_name, + const char *text) +{ + Xapian::TermGenerator *term_gen = message->notmuch->term_gen; + + if (text == NULL) + return NOTMUCH_PRIVATE_STATUS_NULL_POINTER; + + term_gen->set_document (message->doc); + + if (prefix_name) { + const char *prefix = _find_prefix (prefix_name); + + term_gen->index_text (text, 1, prefix); + } + + term_gen->index_text (text); + + return NOTMUCH_PRIVATE_STATUS_SUCCESS; +} + /* Remove a name:value term from 'message', (the actual term will be * encoded by prefixing the value with a short prefix). See * NORMAL_PREFIX and BOOLEAN_PREFIX arrays for the mapping of term @@ -465,7 +564,14 @@ _notmuch_message_remove_term (notmuch_message_t *message, if (strlen (term) > NOTMUCH_TERM_MAX) return NOTMUCH_PRIVATE_STATUS_TERM_TOO_LONG; - message->doc.remove_term (term); + try { + message->doc.remove_term (term); + } catch (const Xapian::InvalidArgumentError) { + /* We'll let the philosopher's try to wrestle with the + * question of whether failing to remove that which was not + * there in the first place is failure. For us, we'll silently + * consider it all good. */ + } talloc_free (term);