From 5b8b0377cb68904eac8fc58a933d47f605a81725 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Mon, 26 Apr 2010 12:58:34 -0700 Subject: [PATCH] Make Received: header special in notmuch_message_file_get_header With this patch the Received: header becomes special in the way we treat headers - this is the only header for which we concatenate all the instances we find (instead of just returning the first one). This will be used in the From guessing code for replies as we need to be able to walk ALL of the Received: headers in a message to have a good chance to guess which mailbox this email was delivered to. Signed-off-by: Dirk Hohndel --- lib/message-file.c | 58 +++++++++++++++++++++++++++++++++---------- lib/notmuch-private.h | 3 +++ 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/lib/message-file.c b/lib/message-file.c index 0c152a39..7722832e 100644 --- a/lib/message-file.c +++ b/lib/message-file.c @@ -209,17 +209,24 @@ 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. */ + * used by the _notmuch_message_file_get_headers_end function. + * Another special case is the Received: header. For this header we + * want to concatenate all instances of the header instead of just + * hashing the first instance as we use this when analyzing the path + * the mail has taken from sender to recipient. + */ const char * notmuch_message_file_get_header (notmuch_message_file_t *message, const char *header_desired) { int contains; - char *header, *decoded_value; + char *header, *decoded_value, *header_sofar, *combined_header; const char *s, *colon; - int match; + int match, newhdr, hdrsofar, is_received; static int initialized = 0; + is_received = (strcmp(header_desired,"received") == 0); + if (! initialized) { g_mime_init (0); initialized = 1; @@ -312,22 +319,39 @@ notmuch_message_file_get_header (notmuch_message_file_t *message, NEXT_HEADER_LINE (&message->value); - if (header_desired == 0) + if (header_desired == NULL) match = 0; else match = (strcasecmp (header, header_desired) == 0); decoded_value = g_mime_utils_header_decode_text (message->value.str); - if (g_hash_table_lookup (message->headers, header) == NULL) { - /* Only insert if we don't have a value for this header, yet. - * This way we always return the FIRST instance of any header - * we search for - * FIXME: we should be returning ALL instances of a header - * or at least provide a way to iterate over them - */ - g_hash_table_insert (message->headers, header, decoded_value); + header_sofar = (char *)g_hash_table_lookup (message->headers, header); + /* we treat the Received: header special - we want to concat ALL of + * the Received: headers we encounter. + * for everything else we return the first instance of a header */ + if (is_received) { + if (header_sofar == NULL) { + /* first Received: header we encountered; just add it */ + g_hash_table_insert (message->headers, header, decoded_value); + } else { + /* we need to add the header to those we already collected */ + newhdr = strlen(decoded_value); + hdrsofar = strlen(header_sofar); + combined_header = xmalloc(hdrsofar + newhdr + 2); + strncpy(combined_header,header_sofar,hdrsofar); + *(combined_header+hdrsofar) = ' '; + strncpy(combined_header+hdrsofar+1,decoded_value,newhdr+1); + g_hash_table_insert (message->headers, header, combined_header); + } + } else { + if (header_sofar == NULL) { + /* Only insert if we don't have a value for this header, yet. */ + g_hash_table_insert (message->headers, header, decoded_value); + } } - if (match) + /* if we found a match we can bail - unless of course we are + * collecting all the Received: headers */ + if (match && !is_received) return decoded_value; } @@ -347,6 +371,14 @@ notmuch_message_file_get_header (notmuch_message_file_t *message, message->value.len = 0; } + /* For the Received: header we actually might end up here even + * though we found the header (as we force continued parsing + * in that case). So let's check if that's the header we were + * looking for and return the value that we found (if any) + */ + if (is_received) + return (char *)g_hash_table_lookup (message->headers, "received"); + /* 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. */ diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index 6e83cc37..3768d6f8 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -344,6 +344,9 @@ notmuch_message_file_restrict_headersv (notmuch_message_file_t *message, * * The header name is case insensitive. * + * The Received: header is special - for it all Received: headers in + * the message are concatenated + * * The returned value is owned by the notmuch message and is valid * only until the message is closed. The caller should copy it if * needing to modify the value or to hold onto it for longer.