X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=message-file.c;h=0b39dc43e5dc13f127d7e99de4d8258a4c965acf;hp=2bd560569dda6aedda058d8942d65e53a4b32f80;hb=acdc9988a2a502accad860a116b094b0a1f62008;hpb=c7482b4dce114b1c09cbac2f4ef6d0defdb23258 diff --git a/message-file.c b/message-file.c index 2bd56056..0b39dc43 100644 --- a/message-file.c +++ b/message-file.c @@ -39,6 +39,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 +71,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 +123,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 @@ -189,6 +205,9 @@ 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) @@ -200,9 +219,13 @@ notmuch_message_file_get_header (notmuch_message_file_t *message, message->parsing_started = 1; - contains = g_hash_table_lookup_extended (message->headers, - header_desired, NULL, - (gpointer *) &value); + if (header_desired == NULL) + contains = 0; + else + contains = g_hash_table_lookup_extended (message->headers, + header_desired, NULL, + (gpointer *) &value); + if (contains && value) return value; @@ -210,7 +233,7 @@ notmuch_message_file_get_header (notmuch_message_file_t *message, return NULL; #define NEXT_HEADER_LINE(closure) \ - do { \ + while (1) { \ ssize_t bytes_read = getline (&message->line, \ &message->line_size, \ message->file); \ @@ -227,7 +250,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 +280,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,7 +304,10 @@ 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); @@ -299,7 +331,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)) { @@ -310,3 +342,40 @@ notmuch_message_file_get_header (notmuch_message_file_t *message, return NULL; } + +size_t +notmuch_message_file_get_header_size (notmuch_message_file_t *message) +{ + if (! message->parsing_finished) + notmuch_message_file_get_header (message, NULL); + + if (! message->parsing_finished) + INTERNAL_ERROR ("Parsing for NULL header did not force parsing to finish.\n"); + + return message->header_size; +} + +const char * +notmuch_message_file_get_all_headers (notmuch_message_file_t *message) +{ + char *headers = NULL; + size_t header_size = notmuch_message_file_get_header_size (message); + + if (header_size == 0) + return ""; + + headers = talloc_size (message, header_size + 1); + if (unlikely (headers == NULL)) + return NULL; + + rewind (message->file); + if (fread (headers, 1, header_size, message->file) != header_size) { + fprintf (stderr, "Error: Short read occurred trying to read message header.\n"); + talloc_free (headers); + return NULL; + } + + headers[header_size] = '\0'; + + return headers; +}