X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=database.cc;h=583bee82a2d3d95b81814002ac042489484a5122;hp=cd057846455605c2a01f270f84efa8731d6dcbb1;hb=f9bbd7baa07110c7f345c8413e2426d00382cb1c;hpb=be9e3ee3132457ea5936bd1225294bdfe3949a4c diff --git a/database.cc b/database.cc index cd057846..583bee82 100644 --- a/database.cc +++ b/database.cc @@ -24,7 +24,7 @@ #include -#include /* g_strdup_printf, g_free, GPtrArray, GHashTable */ +#include /* g_free, GPtrArray, GHashTable */ using namespace std; @@ -104,16 +104,23 @@ typedef struct { prefix_t BOOLEAN_PREFIX_INTERNAL[] = { { "type", "T" }, - { "thread", "G" }, { "ref", "XREFERENCE" }, { "timestamp", "XTIMESTAMP" }, }; prefix_t BOOLEAN_PREFIX_EXTERNAL[] = { + { "thread", "G" }, { "tag", "K" }, { "id", "Q" } }; +prefix_t PROBABILISTIC_PREFIX[]= { + { "from", "XFROM" }, + { "to", "XTO" }, + { "attachment", "XATTACHMENT" }, + { "subject", "XSUBJECT"} +}; + int _internal_error (const char *format, ...) { @@ -141,6 +148,10 @@ _find_prefix (const char *name) if (strcmp (name, BOOLEAN_PREFIX_EXTERNAL[i].name) == 0) return BOOLEAN_PREFIX_EXTERNAL[i].prefix; + for (i = 0; i < ARRAY_SIZE (PROBABILISTIC_PREFIX); i++) + if (strcmp (name, PROBABILISTIC_PREFIX[i].name) == 0) + return PROBABILISTIC_PREFIX[i].prefix; + INTERNAL_ERROR ("No prefix exists for '%s'\n", name); return ""; @@ -152,6 +163,8 @@ notmuch_status_to_string (notmuch_status_t status) switch (status) { case NOTMUCH_STATUS_SUCCESS: return "No error occurred"; + case NOTMUCH_STATUS_OUT_OF_MEMORY: + return "Out of memory"; case NOTMUCH_STATUS_XAPIAN_EXCEPTION: return "A Xapian exception occurred"; case NOTMUCH_STATUS_FILE_ERROR: @@ -164,35 +177,14 @@ notmuch_status_to_string (notmuch_status_t status) return "Erroneous NULL pointer"; case NOTMUCH_STATUS_TAG_TOO_LONG: return "Tag value is too long (exceeds NOTMUCH_TAG_MAX)"; + case NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: + return "Unblanced number of calls to notmuch_message_freeze/thaw"; default: case NOTMUCH_STATUS_LAST_STATUS: return "Unknown error status value"; } } -/* XXX: We should drop this function and convert all callers to call - * _notmuch_message_add_term instead. */ -static void -add_term (Xapian::Document doc, - const char *prefix_name, - const char *value) -{ - const char *prefix; - char *term; - - if (value == NULL) - return; - - prefix = _find_prefix (prefix_name); - - term = g_strdup_printf ("%s%s", prefix, value); - - if (strlen (term) <= NOTMUCH_TERM_MAX) - doc.add_term (term); - - g_free (term); -} - static void find_doc_ids (notmuch_database_t *notmuch, const char *prefix_name, @@ -203,13 +195,14 @@ find_doc_ids (notmuch_database_t *notmuch, Xapian::PostingIterator i; char *term; - term = g_strdup_printf ("%s%s", _find_prefix (prefix_name), value); + term = talloc_asprintf (notmuch, "%s%s", + _find_prefix (prefix_name), value); *begin = notmuch->xapian_db->postlist_begin (term); *end = notmuch->xapian_db->postlist_end (term); - free (term); + talloc_free (term); } static notmuch_private_status_t @@ -314,12 +307,11 @@ skip_space_and_comments (const char **str) * If not NULL, then *next will be made to point to the first character * not parsed, (possibly pointing to the final '\0' terminator. * - * Returns a newly allocated string which the caller should free() - * when done with it. + * Returns a newly talloc'ed string belonging to 'ctx'. * * Returns NULL if there is any error parsing the message-id. */ static char * -parse_message_id (const char *message_id, const char **next) +parse_message_id (void *ctx, const char *message_id, const char **next) { const char *s, *end; char *result; @@ -360,7 +352,7 @@ parse_message_id (const char *message_id, const char **next) if (end <= s) return NULL; - result = strndup (s, end - s + 1); + result = talloc_strndup (ctx, s, end - s + 1); /* Finally, collapse any whitespace that is within the message-id * itself. */ @@ -376,10 +368,11 @@ parse_message_id (const char *message_id, const char **next) return result; } -/* Parse a References header value, putting a copy of each referenced - * message-id into 'hash'. */ +/* Parse a References header value, putting a (talloc'ed under 'ctx') + * copy of each referenced message-id into 'hash'. */ static void -parse_references (GHashTable *hash, +parse_references (void *ctx, + GHashTable *hash, const char *refs) { char *ref; @@ -388,7 +381,7 @@ parse_references (GHashTable *hash, return; while (*refs) { - ref = parse_message_id (refs, &refs); + ref = parse_message_id (ctx, refs, &refs); if (ref) g_hash_table_insert (hash, ref, NULL); @@ -398,10 +391,17 @@ parse_references (GHashTable *hash, char * notmuch_database_default_path (void) { + char *path; + if (getenv ("NOTMUCH_BASE")) return strdup (getenv ("NOTMUCH_BASE")); - return g_strdup_printf ("%s/mail", getenv ("HOME")); + if (asprintf (&path, "%s/mail", getenv ("HOME")) == -1) { + fprintf (stderr, "Out of memory.\n"); + return xstrdup(""); + } + + return path; } notmuch_database_t * @@ -429,7 +429,7 @@ notmuch_database_create (const char *path) goto DONE; } - notmuch_path = g_strdup_printf ("%s/%s", path, ".notmuch"); + notmuch_path = talloc_asprintf (NULL, "%s/%s", path, ".notmuch"); err = mkdir (notmuch_path, 0755); @@ -443,7 +443,7 @@ notmuch_database_create (const char *path) DONE: if (notmuch_path) - free (notmuch_path); + talloc_free (notmuch_path); if (local_path) free (local_path); @@ -463,7 +463,11 @@ notmuch_database_open (const char *path) if (path == NULL) path = local_path = notmuch_database_default_path (); - notmuch_path = g_strdup_printf ("%s/%s", path, ".notmuch"); + if (asprintf (¬much_path, "%s/%s", path, ".notmuch") == -1) { + notmuch_path = NULL; + fprintf (stderr, "Out of memory\n"); + goto DONE; + } err = stat (notmuch_path, &st); if (err) { @@ -472,7 +476,11 @@ notmuch_database_open (const char *path) goto DONE; } - xapian_path = g_strdup_printf ("%s/%s", notmuch_path, "xapian"); + if (asprintf (&xapian_path, "%s/%s", notmuch_path, "xapian") == -1) { + xapian_path = NULL; + fprintf (stderr, "Out of memory\n"); + goto DONE; + } notmuch = talloc (NULL, notmuch_database_t); notmuch->path = talloc_strdup (notmuch, path); @@ -481,17 +489,28 @@ notmuch_database_open (const char *path) notmuch->xapian_db = new Xapian::WritableDatabase (xapian_path, Xapian::DB_CREATE_OR_OPEN); notmuch->query_parser = new Xapian::QueryParser; + notmuch->term_gen = new Xapian::TermGenerator; + notmuch->term_gen->set_stemmer (Xapian::Stem ("english")); + notmuch->query_parser->set_default_op (Xapian::Query::OP_AND); notmuch->query_parser->set_database (*notmuch->xapian_db); + notmuch->query_parser->set_stemmer (Xapian::Stem ("english")); + notmuch->query_parser->set_stemming_strategy (Xapian::QueryParser::STEM_SOME); for (i = 0; i < ARRAY_SIZE (BOOLEAN_PREFIX_EXTERNAL); i++) { prefix_t *prefix = &BOOLEAN_PREFIX_EXTERNAL[i]; notmuch->query_parser->add_boolean_prefix (prefix->name, prefix->prefix); } + + for (i = 0; i < ARRAY_SIZE (PROBABILISTIC_PREFIX); i++) { + prefix_t *prefix = &PROBABILISTIC_PREFIX[i]; + notmuch->query_parser->add_prefix (prefix->name, prefix->prefix); + } } catch (const Xapian::Error &error) { fprintf (stderr, "A Xapian exception occurred: %s\n", error.get_msg().c_str()); + notmuch = NULL; } DONE: @@ -508,6 +527,9 @@ notmuch_database_open (const char *path) void notmuch_database_close (notmuch_database_t *notmuch) { + notmuch->xapian_db->flush (); + + delete notmuch->term_gen; delete notmuch->query_parser; delete notmuch->xapian_db; talloc_free (notmuch); @@ -519,7 +541,7 @@ notmuch_database_get_path (notmuch_database_t *notmuch) return notmuch->path; } -notmuch_private_status_t +static notmuch_private_status_t find_timestamp_document (notmuch_database_t *notmuch, const char *db_key, Xapian::Document *doc, unsigned int *doc_id) { @@ -623,7 +645,7 @@ notmuch_database_get_timestamp (notmuch_database_t *notmuch, const char *key) * * Otherwise, returns a newly talloced string belonging to 'ctx'. */ -const char * +static const char * _resolve_message_id_to_thread_id (notmuch_database_t *notmuch, void *ctx, const char *message_id) @@ -680,6 +702,12 @@ _merge_threads (notmuch_database_t *notmuch, return ret; } +static void +_my_talloc_free_for_g_hash (void *ptr) +{ + talloc_free (ptr); +} + static notmuch_status_t _notmuch_database_link_message_to_parents (notmuch_database_t *notmuch, notmuch_message_t *message, @@ -692,13 +720,13 @@ _notmuch_database_link_message_to_parents (notmuch_database_t *notmuch, notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS; parents = g_hash_table_new_full (g_str_hash, g_str_equal, - free, NULL); + _my_talloc_free_for_g_hash, NULL); refs = notmuch_message_file_get_header (message_file, "references"); - parse_references (parents, refs); + parse_references (message, parents, refs); in_reply_to = notmuch_message_file_get_header (message_file, "in-reply-to"); - parse_references (parents, in_reply_to); + parse_references (message, parents, in_reply_to); keys = g_hash_table_get_keys (parents); for (l = keys; l; l = l->next) { @@ -820,7 +848,8 @@ _notmuch_database_link_message (notmuch_database_t *notmuch, notmuch_status_t notmuch_database_add_message (notmuch_database_t *notmuch, - const char *filename) + const char *filename, + notmuch_message_t **message_ret) { notmuch_message_file_t *message_file; notmuch_message_t *message; @@ -830,6 +859,9 @@ notmuch_database_add_message (notmuch_database_t *notmuch, const char *from, *to, *subject, *old_filename; char *message_id; + if (message_ret) + *message_ret = NULL; + message_file = notmuch_message_file_open (filename); if (message_file == NULL) { ret = NOTMUCH_STATUS_FILE_ERROR; @@ -851,11 +883,11 @@ notmuch_database_add_message (notmuch_database_t *notmuch, header = notmuch_message_file_get_header (message_file, "message-id"); if (header) { - message_id = parse_message_id (header, NULL); + message_id = parse_message_id (message_file, header, NULL); /* So the header value isn't RFC-compliant, but it's * better than no message-id at all. */ if (message_id == NULL) - message_id = xstrdup (header); + message_id = talloc_strdup (message_file, header); } else { /* No message-id at all, let's generate one by taking a * hash over the file's contents. */ @@ -867,7 +899,8 @@ notmuch_database_add_message (notmuch_database_t *notmuch, goto DONE; } - message_id = g_strdup_printf ("notmuch-sha1-%s", sha1); + message_id = talloc_asprintf (message_file, + "notmuch-sha1-%s", sha1); free (sha1); } @@ -880,7 +913,8 @@ notmuch_database_add_message (notmuch_database_t *notmuch, notmuch, message_id, &ret); - free (message_id); + + talloc_free (message_id); if (message == NULL) goto DONE; @@ -912,9 +946,11 @@ notmuch_database_add_message (notmuch_database_t *notmuch, { ret = NOTMUCH_STATUS_FILE_NOT_EMAIL; goto DONE; - } else { - _notmuch_message_sync (message); } + + _notmuch_message_index_file (message, filename); + + _notmuch_message_sync (message); } catch (const Xapian::Error &error) { fprintf (stderr, "A Xapian exception occurred: %s.\n", error.get_msg().c_str()); @@ -923,8 +959,13 @@ notmuch_database_add_message (notmuch_database_t *notmuch, } DONE: - if (message) - notmuch_message_destroy (message); + if (message) { + if (ret == NOTMUCH_STATUS_SUCCESS && message_ret) + *message_ret = message; + else + notmuch_message_destroy (message); + } + if (message_file) notmuch_message_file_close (message_file);