#include <signal.h>
#include <glib.h> /* g_free, GPtrArray, GHashTable */
+#include <glib-object.h> /* g_type_init */
+
+#include <gmime/gmime.h> /* g_mime_init */
using namespace std;
* STRING is the name of a file within that
* directory for this mail message.
*
- * A mail document also has two values:
+ * A mail document also has four values:
*
* TIMESTAMP: The time_t value corresponding to the message's
* Date header.
*
* MESSAGE_ID: The unique ID of the mail mess (see "id" above)
*
+ * FROM: The value of the "From" header
+ *
+ * SUBJECT: The value of the "Subject" header
+ *
* 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
{ "folder", "XFOLDER"}
};
-int
-_internal_error (const char *format, ...)
-{
- va_list va_args;
-
- va_start (va_args, format);
-
- fprintf (stderr, "Internal error: ");
- vfprintf (stderr, format, va_args);
-
- exit (1);
-
- return 1;
-}
-
const char *
_find_prefix (const char *name)
{
return compressed;
}
-notmuch_message_t *
+notmuch_status_t
notmuch_database_find_message (notmuch_database_t *notmuch,
- const char *message_id)
+ const char *message_id,
+ notmuch_message_t **message_ret)
{
notmuch_private_status_t status;
unsigned int doc_id;
+ if (message_ret == NULL)
+ return NOTMUCH_STATUS_NULL_POINTER;
+
if (strlen (message_id) > NOTMUCH_MESSAGE_ID_MAX)
message_id = _message_id_compressed (notmuch, message_id);
message_id, &doc_id);
if (status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND)
- return NULL;
+ *message_ret = NULL;
+ else {
+ *message_ret = _notmuch_message_create (notmuch, notmuch, doc_id,
+ NULL);
+ if (*message_ret == NULL)
+ return NOTMUCH_STATUS_OUT_OF_MEMORY;
+ }
- return _notmuch_message_create (notmuch, notmuch, doc_id, NULL);
+ return NOTMUCH_STATUS_SUCCESS;
} catch (const Xapian::Error &error) {
fprintf (stderr, "A Xapian exception occurred finding message: %s.\n",
error.get_msg().c_str());
notmuch->exception_reported = TRUE;
- return NULL;
+ *message_ret = NULL;
+ return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
}
}
notmuch_database_open (const char *path,
notmuch_database_mode_t mode)
{
+ void *local = talloc_new (NULL);
notmuch_database_t *notmuch = NULL;
- char *notmuch_path = NULL, *xapian_path = NULL;
+ char *notmuch_path, *xapian_path;
struct stat st;
int err;
unsigned int i, version;
+ static int initialized = 0;
- if (asprintf (¬much_path, "%s/%s", path, ".notmuch") == -1) {
- notmuch_path = NULL;
+ if (! (notmuch_path = talloc_asprintf (local, "%s/%s", path, ".notmuch"))) {
fprintf (stderr, "Out of memory\n");
goto DONE;
}
goto DONE;
}
- if (asprintf (&xapian_path, "%s/%s", notmuch_path, "xapian") == -1) {
- xapian_path = NULL;
+ if (! (xapian_path = talloc_asprintf (local, "%s/%s", notmuch_path, "xapian"))) {
fprintf (stderr, "Out of memory\n");
goto DONE;
}
- notmuch = talloc (NULL, notmuch_database_t);
+ /* Initialize the GLib type system and threads */
+ g_type_init ();
+
+ /* Initialize gmime */
+ if (! initialized) {
+ g_mime_init (0);
+ initialized = 1;
+ }
+
+ notmuch = talloc_zero (NULL, notmuch_database_t);
notmuch->exception_reported = FALSE;
notmuch->path = talloc_strdup (notmuch, path);
} catch (const Xapian::Error &error) {
fprintf (stderr, "A Xapian exception occurred opening database: %s\n",
error.get_msg().c_str());
+ notmuch_database_close (notmuch);
notmuch = NULL;
}
DONE:
- if (notmuch_path)
- free (notmuch_path);
- if (xapian_path)
- free (xapian_path);
+ talloc_free (local);
return notmuch;
}
* However, we rely on flushing to test atomicity. */
const char *thresh = getenv ("XAPIAN_FLUSH_THRESHOLD");
if (thresh && atoi (thresh) == 1)
- db->commit ();
+ db->flush ();
} catch (const Xapian::Error &error) {
fprintf (stderr, "A Xapian exception occurred committing transaction: %s.\n",
error.get_msg().c_str());
/* Find the thread ID to which the message with 'message_id' belongs.
*
- * Always returns a newly talloced string belonging to 'ctx'.
+ * Note: 'thread_id_ret' must not be NULL!
+ * On success '*thread_id_ret' is set to a newly talloced string belonging to
+ * 'ctx'.
*
* Note: If there is no message in the database with the given
* 'message_id' then a new thread_id will be allocated for this
* thread ID can be looked up if the message is added to the database
* later).
*/
-static const char *
+static notmuch_status_t
_resolve_message_id_to_thread_id (notmuch_database_t *notmuch,
void *ctx,
- const char *message_id)
+ const char *message_id,
+ const char **thread_id_ret)
{
+ notmuch_status_t status;
notmuch_message_t *message;
string thread_id_string;
- const char *thread_id;
char *metadata_key;
Xapian::WritableDatabase *db;
- message = notmuch_database_find_message (notmuch, message_id);
+ status = notmuch_database_find_message (notmuch, message_id, &message);
+
+ if (status)
+ return status;
if (message) {
- thread_id = talloc_steal (ctx, notmuch_message_get_thread_id (message));
+ *thread_id_ret = talloc_steal (ctx,
+ notmuch_message_get_thread_id (message));
notmuch_message_destroy (message);
- return thread_id;
+ return NOTMUCH_STATUS_SUCCESS;
}
/* Message has not been seen yet.
thread_id_string = notmuch->xapian_db->get_metadata (metadata_key);
if (thread_id_string.empty()) {
- thread_id = _notmuch_database_generate_thread_id (notmuch);
- db->set_metadata (metadata_key, thread_id);
+ *thread_id_ret = talloc_strdup (ctx,
+ _notmuch_database_generate_thread_id (notmuch));
+ db->set_metadata (metadata_key, *thread_id_ret);
} else {
- thread_id = thread_id_string.c_str();
+ *thread_id_ret = talloc_strdup (ctx, thread_id_string.c_str());
}
talloc_free (metadata_key);
- return talloc_strdup (ctx, thread_id);
+ return NOTMUCH_STATUS_SUCCESS;
}
static notmuch_status_t
keys = g_hash_table_get_keys (parents);
for (l = keys; l; l = l->next) {
char *parent_message_id;
- const char *parent_thread_id;
+ const char *parent_thread_id = NULL;
parent_message_id = (char *) l->data;
_notmuch_message_add_term (message, "reference",
parent_message_id);
- parent_thread_id = _resolve_message_id_to_thread_id (notmuch,
- message,
- parent_message_id);
+ ret = _resolve_message_id_to_thread_id (notmuch,
+ message,
+ parent_message_id,
+ &parent_thread_id);
+ if (ret)
+ goto DONE;
if (*thread_id == NULL) {
*thread_id = talloc_strdup (message, parent_thread_id);
goto DONE;
date = notmuch_message_file_get_header (message_file, "date");
- _notmuch_message_set_date (message, date);
+ _notmuch_message_set_header_values (message, date, from, subject);
_notmuch_message_index_file (message, filename);
} else {
notmuch_database_remove_message (notmuch_database_t *notmuch,
const char *filename)
{
- notmuch_message_t *message =
- notmuch_database_find_message_by_filename (notmuch, filename);
- notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
+ notmuch_status_t status;
+ notmuch_message_t *message;
- if (message) {
+ status = notmuch_database_find_message_by_filename (notmuch, filename,
+ &message);
+
+ if (status == NOTMUCH_STATUS_SUCCESS && message) {
status = _notmuch_message_remove_filename (message, filename);
if (status == NOTMUCH_STATUS_SUCCESS)
_notmuch_message_delete (message);
return status;
}
-notmuch_message_t *
+notmuch_status_t
notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
- const char *filename)
+ const char *filename,
+ notmuch_message_t **message_ret)
{
void *local;
const char *prefix = _find_prefix ("file-direntry");
char *direntry, *term;
Xapian::PostingIterator i, end;
- notmuch_message_t *message = NULL;
notmuch_status_t status;
+ if (message_ret == NULL)
+ return NOTMUCH_STATUS_NULL_POINTER;
+
local = talloc_new (notmuch);
try {
status = _notmuch_database_filename_to_direntry (local, notmuch,
filename, &direntry);
if (status)
- return NULL;
+ goto DONE;
term = talloc_asprintf (local, "%s%s", prefix, direntry);
if (i != end) {
notmuch_private_status_t private_status;
- message = _notmuch_message_create (notmuch, notmuch,
- *i, &private_status);
+ *message_ret = _notmuch_message_create (notmuch, notmuch, *i,
+ &private_status);
+ if (*message_ret == NULL)
+ status = NOTMUCH_STATUS_OUT_OF_MEMORY;
}
} catch (const Xapian::Error &error) {
fprintf (stderr, "Error: A Xapian exception occurred finding message by filename: %s\n",
error.get_msg().c_str());
notmuch->exception_reported = TRUE;
- message = NULL;
+ status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
}
+ DONE:
talloc_free (local);
- return message;
+ if (status && *message_ret) {
+ notmuch_message_destroy (*message_ret);
+ *message_ret = NULL;
+ }
+ return status;
}
notmuch_string_list_t *