]> git.notmuchmail.org Git - notmuch/blobdiff - message-file.c
notmuch show: Remove custom "unread" hack, (printing tag in two locations).
[notmuch] / message-file.c
index cb2bf665006c4de4734f446e28c782c08a0f8a8a..75caba6d8b055e5c3b57b2d72d1926381ff11fc8 100644 (file)
@@ -22,6 +22,8 @@
 
 #include "notmuch-private.h"
 
+#include <gmime/gmime.h>
+
 #include <glib.h> /* GHashTable */
 
 typedef struct {
@@ -39,6 +41,7 @@ struct _notmuch_message_file {
     GHashTable *headers;
     int broken_headers;
     int good_headers;
+    size_t header_size; /* Length of full message header in bytes. */
 
     /* Parsing state */
     char *line;
@@ -70,12 +73,36 @@ strcase_hash (const void *ptr)
     return hash;
 }
 
+static int
+_notmuch_message_file_destructor (notmuch_message_file_t *message)
+{
+    if (message->line)
+       free (message->line);
+
+    if (message->value.size)
+       free (message->value.str);
+
+    if (message->headers)
+       g_hash_table_destroy (message->headers);
+
+    if (message->file)
+       fclose (message->file);
+
+    return 0;
+}
+
+/* Create a new notmuch_message_file_t for 'filename' with 'ctx' as
+ * the talloc owner. */
 notmuch_message_file_t *
-notmuch_message_file_open (const char *filename)
+_notmuch_message_file_open_ctx (void *ctx, const char *filename)
 {
     notmuch_message_file_t *message;
 
-    message = xcalloc (1, sizeof (notmuch_message_file_t));
+    message = talloc_zero (ctx, notmuch_message_file_t);
+    if (unlikely (message == NULL))
+       return NULL;
+
+    talloc_set_destructor (message, _notmuch_message_file_destructor);
 
     message->file = fopen (filename, "r");
     if (message->file == NULL)
@@ -98,25 +125,16 @@ notmuch_message_file_open (const char *filename)
     return NULL;
 }
 
+notmuch_message_file_t *
+notmuch_message_file_open (const char *filename)
+{
+    return _notmuch_message_file_open_ctx (NULL, filename);
+}
+
 void
 notmuch_message_file_close (notmuch_message_file_t *message)
 {
-    if (message == NULL)
-       return;
-
-    if (message->line)
-       free (message->line);
-
-    if (message->value.size)
-       free (message->value.str);
-
-    if (message->headers)
-       g_hash_table_destroy (message->headers);
-
-    if (message->file)
-       fclose (message->file);
-
-    free (message);
+    talloc_free (message);
 }
 
 void
@@ -149,7 +167,7 @@ notmuch_message_file_restrict_headers (notmuch_message_file_t *message, ...)
     notmuch_message_file_restrict_headersv (message, va_headers);
 }
 
-void
+static void
 copy_header_unfolding (header_value_closure_t *value,
                       const char *chunk)
 {
@@ -162,7 +180,7 @@ copy_header_unfolding (header_value_closure_t *value,
        chunk++;
 
     if (value->len + 1 + strlen (chunk) + 1 > value->size) {
-       int new_size = value->size;
+       unsigned int new_size = value->size;
        if (value->size == 0)
            new_size = strlen (chunk) + 1;
        else
@@ -189,28 +207,41 @@ copy_header_unfolding (header_value_closure_t *value,
     }
 }
 
+/* As a special-case, a value of NULL for header_desired will force
+ * the entire header to be parsed if it is not parsed already. This is
+ * used by the _notmuch_message_file_get_headers_end function. */
 const char *
 notmuch_message_file_get_header (notmuch_message_file_t *message,
                                 const char *header_desired)
 {
     int contains;
-    char *header, *value;
+    char *header, *decoded_value;
     const char *s, *colon;
     int match;
+    static int initialized = 0;
+
+    if (! initialized) {
+       g_mime_init (0);
+       initialized = 1;
+    }
 
     message->parsing_started = 1;
 
-    contains = g_hash_table_lookup_extended (message->headers,
-                                            header_desired, NULL,
-                                            (gpointer *) &value);
-    if (contains && value)
-       return value;
+    if (header_desired == NULL)
+       contains = 0;
+    else
+       contains = g_hash_table_lookup_extended (message->headers,
+                                                header_desired, NULL,
+                                                (gpointer *) &decoded_value);
+
+    if (contains && decoded_value)
+       return decoded_value;
 
     if (message->parsing_finished)
        return NULL;
 
 #define NEXT_HEADER_LINE(closure)                              \
-    do {                                                       \
+    while (1) {                                                        \
        ssize_t bytes_read = getline (&message->line,           \
                                      &message->line_size,      \
                                      message->file);           \
@@ -227,7 +258,11 @@ notmuch_message_file_get_header (notmuch_message_file_t *message,
        {                                                       \
            copy_header_unfolding ((closure), message->line);   \
        }                                                       \
-    } while (*message->line == ' ' || *message->line == '\t');
+       if (*message->line == ' ' || *message->line == '\t')    \
+           message->header_size += strlen (message->line);     \
+       else                                                    \
+           break;                                              \
+    }
 
     if (message->line == NULL)
        NEXT_HEADER_LINE (NULL);
@@ -253,6 +288,8 @@ notmuch_message_file_get_header (notmuch_message_file_t *message,
            continue;
        }
 
+       message->header_size += strlen (message->line);
+
        message->good_headers++;
 
        header = xstrndup (message->line, colon - message->line);
@@ -275,14 +312,17 @@ notmuch_message_file_get_header (notmuch_message_file_t *message,
 
        NEXT_HEADER_LINE (&message->value);
 
-       match = (strcasecmp (header, header_desired) == 0);
+       if (header_desired == 0)
+           match = 0;
+       else
+           match = (strcasecmp (header, header_desired) == 0);
 
-       value = xstrdup (message->value.str);
+       decoded_value = g_mime_utils_header_decode_text (message->value.str);
 
-       g_hash_table_insert (message->headers, header, value);
+       g_hash_table_insert (message->headers, header, decoded_value);
 
        if (match)
-           return value;
+           return decoded_value;
     }
 
     if (message->line)
@@ -299,7 +339,7 @@ notmuch_message_file_get_header (notmuch_message_file_t *message,
     /* We've parsed all headers and never found the one we're looking
      * for. It's probably just not there, but let's check that we
      * didn't make a mistake preventing us from seeing it. */
-    if (message->restrict_headers &&
+    if (message->restrict_headers && header_desired &&
        ! g_hash_table_lookup_extended (message->headers,
                                        header_desired, NULL, NULL))
     {