--- /dev/null
+Return-Path: <hohndel@gr8dns.org>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+ by olra.theworths.org (Postfix) with ESMTP id 1A1C2418C34\r
+ for <notmuch@notmuchmail.org>; Mon, 26 Apr 2010 12:58:50 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: -1.9\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=-1.9 tagged_above=-999 required=5\r
+ tests=[BAYES_00=-1.9] autolearn=ham\r
+Received: from olra.theworths.org ([127.0.0.1])\r
+ by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
+ with ESMTP id ghW6EbU4IuoM for <notmuch@notmuchmail.org>;\r
+ Mon, 26 Apr 2010 12:58:48 -0700 (PDT)\r
+Received: from mail.hohndel.org (mail.hohndel.org [65.23.157.147])\r
+ by olra.theworths.org (Postfix) with ESMTP id 549DD431FC1\r
+ for <notmuch@notmuchmail.org>; Mon, 26 Apr 2010 12:58:48 -0700 (PDT)\r
+Received: by mail.hohndel.org (Postfix, from userid 112)\r
+ id A5965340FA; Mon, 26 Apr 2010 15:58:47 -0400 (EDT)\r
+Received: from x200.gr8dns.org (unknown [65.23.157.147])\r
+ by mail.hohndel.org (Postfix) with ESMTP id 6BB76340F4;\r
+ Mon, 26 Apr 2010 15:58:42 -0400 (EDT)\r
+Received: by x200.gr8dns.org (Postfix, from userid 500)\r
+ id 5483FCC906; Mon, 26 Apr 2010 12:58:42 -0700 (PDT)\r
+From: Dirk Hohndel <hohndel@infradead.org>\r
+To: <notmuch@notmuchmail.org>\r
+Subject: [PATCH 1/2] Make Received: header special in\r
+ notmuch_message_file_get_header\r
+Date: Mon, 26 Apr 2010 12:58:34 -0700\r
+Message-Id: <1272311915-30575-2-git-send-email-hohndel@infradead.org>\r
+X-Mailer: git-send-email 1.6.6.1\r
+In-Reply-To: <1272311915-30575-1-git-send-email-hohndel@infradead.org>\r
+References: <m3sk6lcu9c.fsf@x200.gr8dns.org>\r
+ <1272311915-30575-1-git-send-email-hohndel@infradead.org>\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.13\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+ <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Mon, 26 Apr 2010 19:58:50 -0000\r
+\r
+With this patch the Received: header becomes special in the way\r
+we treat headers - this is the only header for which we concatenate\r
+all the instances we find (instead of just returning the first one).\r
+\r
+This will be used in the From guessing code for replies as we need to\r
+be able to walk ALL of the Received: headers in a message to have a\r
+good chance to guess which mailbox this email was delivered to.\r
+\r
+Signed-off-by: Dirk Hohndel <hohndel@infradead.org>\r
+---\r
+ lib/message-file.c | 58 ++++++++++++++++++++++++++++++++++++++-----------\r
+ lib/notmuch-private.h | 3 ++\r
+ 2 files changed, 48 insertions(+), 13 deletions(-)\r
+\r
+diff --git a/lib/message-file.c b/lib/message-file.c\r
+index 0c152a3..7722832 100644\r
+--- a/lib/message-file.c\r
++++ b/lib/message-file.c\r
+@@ -209,17 +209,24 @@ copy_header_unfolding (header_value_closure_t *value,\r
+ \r
+ /* As a special-case, a value of NULL for header_desired will force\r
+ * the entire header to be parsed if it is not parsed already. This is\r
+- * used by the _notmuch_message_file_get_headers_end function. */\r
++ * used by the _notmuch_message_file_get_headers_end function.\r
++ * Another special case is the Received: header. For this header we\r
++ * want to concatenate all instances of the header instead of just\r
++ * hashing the first instance as we use this when analyzing the path\r
++ * the mail has taken from sender to recipient.\r
++ */\r
+ const char *\r
+ notmuch_message_file_get_header (notmuch_message_file_t *message,\r
+ const char *header_desired)\r
+ {\r
+ int contains;\r
+- char *header, *decoded_value;\r
++ char *header, *decoded_value, *header_sofar, *combined_header;\r
+ const char *s, *colon;\r
+- int match;\r
++ int match, newhdr, hdrsofar, is_received;\r
+ static int initialized = 0;\r
+ \r
++ is_received = (strcmp(header_desired,"received") == 0);\r
++\r
+ if (! initialized) {\r
+ g_mime_init (0);\r
+ initialized = 1;\r
+@@ -312,22 +319,39 @@ notmuch_message_file_get_header (notmuch_message_file_t *message,\r
+ \r
+ NEXT_HEADER_LINE (&message->value);\r
+ \r
+- if (header_desired == 0)\r
++ if (header_desired == NULL)\r
+ match = 0;\r
+ else\r
+ match = (strcasecmp (header, header_desired) == 0);\r
+ \r
+ decoded_value = g_mime_utils_header_decode_text (message->value.str);\r
+- if (g_hash_table_lookup (message->headers, header) == NULL) {\r
+- /* Only insert if we don't have a value for this header, yet.\r
+- * This way we always return the FIRST instance of any header\r
+- * we search for\r
+- * FIXME: we should be returning ALL instances of a header\r
+- * or at least provide a way to iterate over them\r
+- */\r
+- g_hash_table_insert (message->headers, header, decoded_value);\r
++ header_sofar = (char *)g_hash_table_lookup (message->headers, header);\r
++ /* we treat the Received: header special - we want to concat ALL of \r
++ * the Received: headers we encounter.\r
++ * for everything else we return the first instance of a header */\r
++ if (is_received) {\r
++ if (header_sofar == NULL) {\r
++ /* first Received: header we encountered; just add it */\r
++ g_hash_table_insert (message->headers, header, decoded_value);\r
++ } else {\r
++ /* we need to add the header to those we already collected */\r
++ newhdr = strlen(decoded_value);\r
++ hdrsofar = strlen(header_sofar);\r
++ combined_header = xmalloc(hdrsofar + newhdr + 2);\r
++ strncpy(combined_header,header_sofar,hdrsofar);\r
++ *(combined_header+hdrsofar) = ' ';\r
++ strncpy(combined_header+hdrsofar+1,decoded_value,newhdr+1);\r
++ g_hash_table_insert (message->headers, header, combined_header);\r
++ }\r
++ } else {\r
++ if (header_sofar == NULL) {\r
++ /* Only insert if we don't have a value for this header, yet. */\r
++ g_hash_table_insert (message->headers, header, decoded_value);\r
++ }\r
+ }\r
+- if (match)\r
++ /* if we found a match we can bail - unless of course we are\r
++ * collecting all the Received: headers */\r
++ if (match && !is_received)\r
+ return decoded_value;\r
+ }\r
+ \r
+@@ -347,6 +371,14 @@ notmuch_message_file_get_header (notmuch_message_file_t *message,\r
+ message->value.len = 0;\r
+ }\r
+ \r
++ /* For the Received: header we actually might end up here even\r
++ * though we found the header (as we force continued parsing\r
++ * in that case). So let's check if that's the header we were\r
++ * looking for and return the value that we found (if any)\r
++ */\r
++ if (is_received)\r
++ return (char *)g_hash_table_lookup (message->headers, "received");\r
++\r
+ /* We've parsed all headers and never found the one we're looking\r
+ * for. It's probably just not there, but let's check that we\r
+ * didn't make a mistake preventing us from seeing it. */\r
+diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h\r
+index 6e83cc3..3768d6f 100644\r
+--- a/lib/notmuch-private.h\r
++++ b/lib/notmuch-private.h\r
+@@ -344,6 +344,9 @@ notmuch_message_file_restrict_headersv (notmuch_message_file_t *message,\r
+ *\r
+ * The header name is case insensitive.\r
+ *\r
++ * The Received: header is special - for it all Received: headers in\r
++ * the message are concatenated\r
++ *\r
+ * The returned value is owned by the notmuch message and is valid\r
+ * only until the message is closed. The caller should copy it if\r
+ * needing to modify the value or to hold onto it for longer.\r
+-- \r
+1.6.6.1\r
+\r