MYLDFLAGS=`pkg-config --libs glib-2.0 talloc` `xapian-config --libs`
+MODULES= \
+ notmuch.o \
+ database.o \
+ date.o \
+ message.o \
+ message-file.o \
+ query.o \
+ sha1.o \
+ libsha1.o \
+ xutil.o
+
all: $(PROGS)
%.o: %.cc
%.o: %.c
$(CC) -c $(CFLAGS) $(MYCFLAGS) $< -o $@
-notmuch: notmuch.o database.o date.o message.o message-file.o query.o xutil.o
+notmuch: $(MODULES)
$(CC) $(MYLDFLAGS) $^ -o $@
Makefile.dep: *.c *.cc
return "No error occurred";
case NOTMUCH_STATUS_XAPIAN_EXCEPTION:
return "A Xapian exception occurred";
+ case NOTMUCH_STATUS_FILE_ERROR:
+ return "Something went wrong trying to read or write a file";
case NOTMUCH_STATUS_FILE_NOT_EMAIL:
return "File is not an email";
case NOTMUCH_STATUS_NULL_POINTER:
Xapian::WritableDatabase *db = notmuch->xapian_db;
Xapian::Document doc;
notmuch_message_file_t *message;
+ notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
GPtrArray *parents, *thread_ids;
if (message_id == NULL)
message_id = xstrdup (header);
} else {
- /* XXX: Should generate a message_id here, (such as a SHA1
- * sum of the message itself) */
- 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);
+
+ /* If that failed too, something is really wrong. Give up. */
+ if (sha1 == NULL) {
+ ret = NOTMUCH_STATUS_FILE_ERROR;
+ goto DONE;
+ }
+
+ message_id = g_strdup_printf ("notmuch-sha1-%s", sha1);
+ free (sha1);
}
thread_ids = find_thread_ids (notmuch, parents, message_id);
for (i = 0; i < parents->len; i++)
g_free (g_ptr_array_index (parents, i));
g_ptr_array_free (parents, TRUE);
- if (message_id) {
- add_term (doc, "msgid", message_id);
- doc.add_value (NOTMUCH_VALUE_MESSAGE_ID, message_id);
- }
+
+ add_term (doc, "msgid", message_id);
+ doc.add_value (NOTMUCH_VALUE_MESSAGE_ID, message_id);
+
+ free (message_id);
if (thread_ids->len) {
unsigned int i;
}
doc.add_value (NOTMUCH_VALUE_THREAD, thread_id->str);
g_string_free (thread_id, TRUE);
- } else if (message_id) {
+ } else {
/* If not part of any existing thread, generate a new thread_id. */
thread_id_t thread_id;
g_ptr_array_free (thread_ids, TRUE);
- free (message_id);
-
date = notmuch_message_file_get_header (message, "date");
time_value = notmuch_parse_date (date, NULL);
subject == NULL &&
to == NULL)
{
- notmuch_message_file_close (message);
- return NOTMUCH_STATUS_FILE_NOT_EMAIL;
+ ret = NOTMUCH_STATUS_FILE_NOT_EMAIL;
+ goto DONE;
} else {
db->add_document (doc);
}
} catch (const Xapian::Error &error) {
fprintf (stderr, "A Xapian exception occurred: %s.\n",
error.get_msg().c_str());
- return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
+ ret = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
+ goto DONE;
}
- notmuch_message_file_close (message);
+ DONE:
+ if (message)
+ notmuch_message_file_close (message);
- return NOTMUCH_STATUS_SUCCESS;
+ return ret;
}
time_t
notmuch_parse_date (const char *str, int *tz_offset);
+/* sha1.c */
+
+/* Create a hexadecimal string version of the SHA-1 digest of the
+ * named file.
+ *
+ * This function returns a newly allocated string which the caller
+ * should free() when finished.
+ *
+ * If any error occurs while reading the file, (permission denied,
+ * file not found, etc.), this function returns NULL.
+ */
+char *
+notmuch_sha1_of_file (const char *filename);
+
NOTMUCH_END_DECLS
#endif
*
* NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
*
+ * NOTMUCH_STATUS_FILE_ERROR: An error occurred trying to read or
+ * write to a file (this could be file not found, permission
+ * denied, etc.)
+ *
* NOTMUCH_STATUS_FILE_NOT_EMAIL: A file was presented that doesn't
* appear to be an email message.
*
typedef enum _notmuch_status {
NOTMUCH_STATUS_SUCCESS = 0,
NOTMUCH_STATUS_XAPIAN_EXCEPTION,
+ NOTMUCH_STATUS_FILE_ERROR,
NOTMUCH_STATUS_FILE_NOT_EMAIL,
NOTMUCH_STATUS_NULL_POINTER,
NOTMUCH_STATUS_TAG_TOO_LONG,
*
* NOTMUCH_STATUS_SUCCESS: Message successfully added to database.
*
+ * NOTMUCH_STATUS_FILE_ERROR: an error occurred trying to open the
+ * file, (such as permission denied, or file not found,
+ * etc.). Nothing added to the database.
+ *
* NOTMUCH_STATUS_FILE_NOT_EMAIL: the contents of filename don't look
* like an email message. Nothing added to the database.
*/
--- /dev/null
+/* sha1.c - Interfaces to SHA-1 hash for the notmuch mail system
+ *
+ * Copyright © 2009 Carl Worth
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/ .
+ *
+ * Author: Carl Worth <cworth@cworth.org>
+ */
+
+#include "notmuch-private.h"
+
+#include "libsha1.h"
+
+/* Just some simple interfaces on top of libsha1 so that we can leave
+ * libsha1 as untouched as possible. */
+
+char *
+notmuch_sha1_of_file (const char *filename)
+{
+ FILE *file;
+#define BLOCK_SIZE 4096
+ unsigned char block[BLOCK_SIZE];
+ size_t bytes_read;
+ sha1_ctx sha1;
+ unsigned char digest[SHA1_DIGEST_SIZE];
+ char *result, *r;
+ int i;
+
+ file = fopen (filename, "r");
+ if (file == NULL)
+ return NULL;
+
+ sha1_begin (&sha1);
+
+ while (1) {
+ bytes_read = fread (block, 1, 4096, file);
+ if (bytes_read == 0) {
+ if (feof (file)) {
+ break;
+ } else if (ferror (file)) {
+ fclose (file);
+ return NULL;
+ }
+ } else {
+ sha1_hash (block, bytes_read, &sha1);
+ }
+ }
+
+ sha1_end (digest, &sha1);
+
+ result = calloc (SHA1_DIGEST_SIZE * 2 + 1, 1);
+ if (result == NULL)
+ return NULL;
+
+ for (r = result, i = 0;
+ i < SHA1_DIGEST_SIZE;
+ r += 2, i++)
+ {
+ sprintf (r, "%02x", digest[i]);
+ }
+
+ fclose (file);
+
+ return result;
+}
+