const char *prefix;
} prefix_t;
-#define NOTMUCH_DATABASE_VERSION 1
+#define NOTMUCH_DATABASE_VERSION 2
#define STRINGIFY(s) _SUB_STRINGIFY(s)
#define _SUB_STRINGIFY(s) #s
* In addition, terms from the content of the message are added with
* "from", "to", "attachment", and "subject" prefixes for use by the
* user in searching. Similarly, terms from the path of the mail
- * message are added with a "folder" prefix. But the database doesn't
- * really care itself about any of these.
+ * message are added with "folder" and "path" prefixes. But the
+ * database doesn't really care itself about any of these.
*
* The data portion of a mail document is empty.
*
{ "thread", "G" },
{ "tag", "K" },
{ "is", "K" },
- { "id", "Q" }
+ { "id", "Q" },
+ { "path", "P" },
+ /*
+ * Without the ":", since this is a multi-letter prefix, Xapian
+ * will add a colon itself if the first letter of the path is
+ * upper-case ASCII. Including the ":" forces there to always be a
+ * colon, which keeps our own logic simpler.
+ */
+ { "folder", "XFOLDER:" },
};
static prefix_t PROBABILISTIC_PREFIX[]= {
{ "to", "XTO" },
{ "attachment", "XATTACHMENT" },
{ "subject", "XSUBJECT"},
- { "folder", "XFOLDER"}
};
const char *
{
char *sha1, *compressed;
- sha1 = notmuch_sha1_of_string (message_id);
+ sha1 = _notmuch_sha1_of_string (message_id);
compressed = talloc_asprintf (ctx, "notmuch-sha1-%s", sha1);
free (sha1);
return status;
}
-void
+notmuch_status_t
notmuch_database_close (notmuch_database_t *notmuch)
{
+ notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
+
try {
if (notmuch->xapian_db != NULL &&
notmuch->mode == NOTMUCH_DATABASE_MODE_READ_WRITE)
(static_cast <Xapian::WritableDatabase *> (notmuch->xapian_db))->flush ();
} catch (const Xapian::Error &error) {
+ status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
if (! notmuch->exception_reported) {
fprintf (stderr, "Error: A Xapian exception occurred flushing database: %s\n",
error.get_msg().c_str());
try {
notmuch->xapian_db->close();
} catch (const Xapian::Error &error) {
- /* do nothing */
+ /* don't clobber previous error status */
+ if (status == NOTMUCH_STATUS_SUCCESS)
+ status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
}
}
notmuch->value_range_processor = NULL;
delete notmuch->date_range_processor;
notmuch->date_range_processor = NULL;
+
+ return status;
}
#if HAVE_XAPIAN_COMPACT
}
if (rename (xapian_path, backup_path)) {
- fprintf (stderr, "Error moving old database out of the way\n");
+ fprintf (stderr, "Error moving %s to %s: %s\n",
+ xapian_path, backup_path, strerror (errno));
ret = NOTMUCH_STATUS_FILE_ERROR;
goto DONE;
}
if (rename (compact_xapian_path, xapian_path)) {
- fprintf (stderr, "Error moving compacted database\n");
+ fprintf (stderr, "Error moving %s to %s: %s\n",
+ compact_xapian_path, xapian_path, strerror (errno));
ret = NOTMUCH_STATUS_FILE_ERROR;
goto DONE;
}
- if (! keep_backup)
- rmtree (backup_path);
+ if (! keep_backup) {
+ if (rmtree (backup_path)) {
+ fprintf (stderr, "Error removing old database %s: %s\n",
+ backup_path, strerror (errno));
+ ret = NOTMUCH_STATUS_FILE_ERROR;
+ goto DONE;
+ }
+ }
DONE:
- if (notmuch)
- notmuch_database_destroy (notmuch);
+ if (notmuch) {
+ notmuch_status_t ret2;
+
+ ret2 = notmuch_database_destroy (notmuch);
+
+ /* don't clobber previous error status */
+ if (ret == NOTMUCH_STATUS_SUCCESS && ret2 != NOTMUCH_STATUS_SUCCESS)
+ ret = ret2;
+ }
talloc_free (local);
}
#endif
-void
+notmuch_status_t
notmuch_database_destroy (notmuch_database_t *notmuch)
{
- notmuch_database_close (notmuch);
+ notmuch_status_t status;
+
+ status = notmuch_database_close (notmuch);
talloc_free (notmuch);
+
+ return status;
}
const char *
}
}
+ /*
+ * Prior to version 2, the "folder:" prefix was probabilistic and
+ * stemmed. Change it to the current boolean prefix. Add "path:"
+ * prefixes while at it.
+ */
+ if (version < 2) {
+ notmuch_query_t *query = notmuch_query_create (notmuch, "");
+ notmuch_messages_t *messages;
+ notmuch_message_t *message;
+
+ count = 0;
+ total = notmuch_query_count_messages (query);
+
+ for (messages = notmuch_query_search_messages (query);
+ notmuch_messages_valid (messages);
+ notmuch_messages_move_to_next (messages)) {
+ if (do_progress_notify) {
+ progress_notify (closure, (double) count / total);
+ do_progress_notify = 0;
+ }
+
+ message = notmuch_messages_get (messages);
+
+ _notmuch_message_upgrade_folder (message);
+ _notmuch_message_sync (message);
+
+ notmuch_message_destroy (message);
+
+ count++;
+ }
+
+ notmuch_query_destroy (query);
+ }
+
db->set_metadata ("version", STRINGIFY (NOTMUCH_DATABASE_VERSION));
db->flush ();
int term_len = strlen (_find_prefix ("directory")) + strlen (path);
if (term_len > NOTMUCH_TERM_MAX)
- return notmuch_sha1_of_string (path);
+ return _notmuch_sha1_of_string (path);
else
return path;
}
_my_talloc_free_for_g_hash, NULL);
this_message_id = notmuch_message_get_message_id (message);
- refs = notmuch_message_file_get_header (message_file, "references");
+ refs = _notmuch_message_file_get_header (message_file, "references");
last_ref_message_id = parse_references (message,
this_message_id,
parents, refs);
- in_reply_to = notmuch_message_file_get_header (message_file, "in-reply-to");
+ in_reply_to = _notmuch_message_file_get_header (message_file, "in-reply-to");
in_reply_to_message_id = parse_references (message,
this_message_id,
parents, in_reply_to);
if (ret)
return ret;
- message_file = notmuch_message_file_open (filename);
+ message_file = _notmuch_message_file_open (filename);
if (message_file == NULL)
return NOTMUCH_STATUS_FILE_ERROR;
if (ret)
goto DONE;
- notmuch_message_file_restrict_headers (message_file,
- "date",
- "from",
- "in-reply-to",
- "message-id",
- "references",
- "subject",
- "to",
- (char *) NULL);
+ /* Parse message up front to get better error status. */
+ ret = _notmuch_message_file_parse (message_file);
+ if (ret)
+ goto DONE;
try {
/* Before we do any real work, (especially before doing a
* 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");
+ 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 || *from == '\0') &&
(subject == NULL || *subject == '\0') &&
/* 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");
+ header = _notmuch_message_file_get_header (message_file, "message-id");
if (header && *header != '\0') {
message_id = _parse_message_id (message_file, header, NULL);
if (message_id == NULL ) {
/* No message-id at all, let's generate one by taking a
* hash over the file's contents. */
- char *sha1 = notmuch_sha1_of_file (filename);
+ char *sha1 = _notmuch_sha1_of_file (filename);
/* If that failed too, something is really wrong. Give up. */
if (sha1 == NULL) {
if (ret)
goto DONE;
- date = notmuch_message_file_get_header (message_file, "date");
+ date = _notmuch_message_file_get_header (message_file, "date");
_notmuch_message_set_header_values (message, date, from, subject);
- ret = _notmuch_message_index_file (message, filename);
+ ret = _notmuch_message_index_file (message, message_file);
if (ret)
goto DONE;
} else {
}
if (message_file)
- notmuch_message_file_close (message_file);
+ _notmuch_message_file_close (message_file);
ret2 = notmuch_database_end_atomic (notmuch);
if ((ret == NOTMUCH_STATUS_SUCCESS ||