]> git.notmuchmail.org Git - notmuch/blobdiff - database.cc
notmuch.el: Implement visual feedback for add/remove tags.
[notmuch] / database.cc
index 9831d79cdf912f50da160289268c1db504d6d836..604062835427f0c539dd16791b24d84aab7d1da0 100644 (file)
@@ -84,7 +84,7 @@ typedef struct {
  *
  * and has a single value:
  *
- *     TIMETAMPS:      The time_t value from the user.
+ *     TIMESTAMP:      The time_t value from the user.
  */
 
 /* With these prefix values we follow the conventions published here:
@@ -104,16 +104,24 @@ typedef struct {
 
 prefix_t BOOLEAN_PREFIX_INTERNAL[] = {
     { "type", "T" },
-    { "thread", "G" },
     { "ref", "XREFERENCE" },
     { "timestamp", "XTIMESTAMP" },
+    { "contact", "XCONTACT" }
 };
 
 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, ...)
 {
@@ -121,6 +129,7 @@ _internal_error (const char *format, ...)
 
     va_start (va_args, format);
 
+    fprintf (stderr, "Internal error: ");
     vfprintf (stderr, format, va_args);
 
     exit (1);
@@ -141,6 +150,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 "";
@@ -474,21 +487,35 @@ notmuch_database_open (const char *path)
     notmuch = talloc (NULL, notmuch_database_t);
     notmuch->path = talloc_strdup (notmuch, path);
 
+    if (notmuch->path[strlen (notmuch->path) - 1] == '/')
+       notmuch->path[strlen (notmuch->path) - 1] = '\0';
+
     try {
        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:
@@ -505,6 +532,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);
@@ -829,11 +859,15 @@ notmuch_database_add_message (notmuch_database_t *notmuch,
     notmuch_message_file_t *message_file;
     notmuch_message_t *message;
     notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
+    notmuch_private_status_t private_status;
 
     const char *date, *header;
-    const char *from, *to, *subject, *old_filename;
+    const char *from, *to, *subject;
     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,7 +885,25 @@ notmuch_database_add_message (notmuch_database_t *notmuch,
                                           (char *) NULL);
 
     try {
-       /* The first order of business is to find/create a message ID. */
+       /* Before we do any real work, (especially before doing a
+        * potential SHA-1 computation on the entire file's contents),
+        * let's make sure that what we're looking at looks like an
+        * actual email message.
+        */
+       from = notmuch_message_file_get_header (message_file, "from");
+       subject = notmuch_message_file_get_header (message_file, "subject");
+       to = notmuch_message_file_get_header (message_file, "to");
+
+       if (from == NULL &&
+           subject == NULL &&
+           to == NULL)
+       {
+           ret = NOTMUCH_STATUS_FILE_NOT_EMAIL;
+           goto DONE;
+       }
+
+       /* Now that we're sure it's mail, the first order of business
+        * is to find a message ID (or else create one ourselves). */
 
        header = notmuch_message_file_get_header (message_file, "message-id");
        if (header) {
@@ -884,21 +936,20 @@ notmuch_database_add_message (notmuch_database_t *notmuch,
        message = _notmuch_message_create_for_message_id (NULL,
                                                          notmuch,
                                                          message_id,
-                                                         &ret);
+                                                         &private_status);
 
        talloc_free (message_id);
 
        if (message == NULL)
            goto DONE;
 
-       /* Has a message previously been added with the same ID? */
-       old_filename = notmuch_message_get_filename (message);
-       if (old_filename && strlen (old_filename)) {
-           ret = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID;
-           goto DONE;
-       } else {
+       /* Is this a newly created message object? */
+       if (private_status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND) {
            _notmuch_message_set_filename (message, filename);
            _notmuch_message_add_term (message, "type", "mail");
+       } else {
+           ret = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID;
+           goto DONE;
        }
 
        ret = _notmuch_database_link_message (notmuch, message, message_file);
@@ -908,19 +959,9 @@ notmuch_database_add_message (notmuch_database_t *notmuch,
        date = notmuch_message_file_get_header (message_file, "date");
        _notmuch_message_set_date (message, date);
 
-       from = notmuch_message_file_get_header (message_file, "from");
-       subject = notmuch_message_file_get_header (message_file, "subject");
-       to = notmuch_message_file_get_header (message_file, "to");
+       _notmuch_message_index_file (message, filename);
 
-       if (from == NULL &&
-           subject == NULL &&
-           to == NULL)
-       {
-           ret = NOTMUCH_STATUS_FILE_NOT_EMAIL;
-           goto DONE;
-       } else {
-           _notmuch_message_sync (message);
-       }
+       _notmuch_message_sync (message);
     } catch (const Xapian::Error &error) {
        fprintf (stderr, "A Xapian exception occurred: %s.\n",
                 error.get_msg().c_str());
@@ -930,7 +971,7 @@ notmuch_database_add_message (notmuch_database_t *notmuch,
 
   DONE:
     if (message) {
-       if (message_ret)
+       if (ret == NOTMUCH_STATUS_SUCCESS && message_ret)
            *message_ret = message;
        else
            notmuch_message_destroy (message);