From a1135f0b7e67db7056a4ef02d61b8ad0ec46e88b Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Wed, 28 Oct 2009 16:50:14 -0700 Subject: [PATCH] Fix add_message and get_filename to strip/re-add the database path. We now store only a relative path inside the database so the database is not nicely relocatable. --- database.cc | 19 ++++++++++------- message.cc | 54 ++++++++++++++++++++++++++++++++++++----------- notmuch-private.h | 2 +- notmuch.c | 24 +++++++++++++++++++++ notmuch.h | 18 ++++++++++------ 5 files changed, 89 insertions(+), 28 deletions(-) diff --git a/database.cc b/database.cc index d7cd26c7..3e00aa59 100644 --- a/database.cc +++ b/database.cc @@ -487,6 +487,9 @@ 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); @@ -856,9 +859,10 @@ 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) @@ -932,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); diff --git a/message.cc b/message.cc index 75e752c8..169b20c1 100644 --- a/message.cc +++ b/message.cc @@ -146,7 +146,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 +157,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 +173,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 +185,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; } @@ -297,21 +299,49 @@ 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; } diff --git a/notmuch-private.h b/notmuch-private.h index 440860ba..da36c300 100644 --- a/notmuch-private.h +++ b/notmuch-private.h @@ -172,7 +172,7 @@ 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); const char * _notmuch_message_get_subject (notmuch_message_t *message); diff --git a/notmuch.c b/notmuch.c index 5a0ca5c9..757f09d7 100644 --- a/notmuch.c +++ b/notmuch.c @@ -531,6 +531,30 @@ setup_command (unused (int argc), unused (char *argv[])) free (default_path); } + /* Coerce th directory into an absolute directory name. */ + if (*mail_directory != '/') { + char *cwd, *absolute_mail_directory; + + cwd = getcwd (NULL, 0); + if (cwd == NULL) { + fprintf (stderr, "Out of memory.\n"); + exit (1); + } + + if (asprintf (&absolute_mail_directory, "%s/%s", + cwd, mail_directory) < 0) + { + fprintf (stderr, "Out of memory.\n"); + exit (1); + } + + free (cwd); + free (mail_directory); + mail_directory = absolute_mail_directory; + + printf ("Abs: %s\n", mail_directory); + } + notmuch = notmuch_database_create (mail_directory); if (notmuch == NULL) { fprintf (stderr, "Failed to create new notmuch database at %s\n", diff --git a/notmuch.h b/notmuch.h index f4e59ab2..165fe852 100644 --- a/notmuch.h +++ b/notmuch.h @@ -246,11 +246,14 @@ notmuch_database_get_timestamp (notmuch_database_t *database, /* Add a new message to the given notmuch database. * * Here,'filename' should be a path relative to the the path of - * 'database' (see notmuch_database_get_path). The file should be a - * single mail message (not a multi-message mbox) that is expected to - * remain at its current location, (since the notmuch database will - * reference the filename, and will not copy the entire contents of - * the file. + * 'database' (see notmuch_database_get_path), or else should be an + * absolute filename with initial components that match the path of + * 'database'. + * + * The file should be a single mail message (not a multi-message mbox) + * that is expected to remain at its current location, (since the + * notmuch database will reference the filename, and will not copy the + * entire contents of the file. * * If 'message' is not NULL, then, on successful return '*message' * will be initialized to a message object that can be used for things @@ -605,8 +608,9 @@ notmuch_message_get_thread_id (notmuch_message_t *message); /* Get the filename for the email corresponding to 'message'. * - * The returned filename is relative to the base of the database from - * which 'message' was obtained. See notmuch_database_get_path() . + * The returned filename is an absolute filename, (the initial + * component will match notmuch_database_get_path() ). + * * The returned string belongs to the message so should not be * modified or freed by the caller (nor should it be referenced after * the message is destroyed). */