--- /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 DED3A417339\r
+ for <notmuch@notmuchmail.org>; Mon, 26 Apr 2010 12:58:53 -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 TcmZOx-CFKqj for <notmuch@notmuchmail.org>;\r
+ Mon, 26 Apr 2010 12:58:51 -0700 (PDT)\r
+Received: from mail.hohndel.org (mail.hohndel.org [65.23.157.147])\r
+ by olra.theworths.org (Postfix) with ESMTP id 9149B4196F4\r
+ for <notmuch@notmuchmail.org>; Mon, 26 Apr 2010 12:58:49 -0700 (PDT)\r
+Received: by mail.hohndel.org (Postfix, from userid 112)\r
+ id 2B2D3340F4; Mon, 26 Apr 2010 15:58:49 -0400 (EDT)\r
+Received: from x200.gr8dns.org (unknown [65.23.157.147])\r
+ by mail.hohndel.org (Postfix) with ESMTP id 6EB25340F8;\r
+ Mon, 26 Apr 2010 15:58:42 -0400 (EDT)\r
+Received: by x200.gr8dns.org (Postfix, from userid 500)\r
+ id 4EAC7CC903; Mon, 26 Apr 2010 12:58:42 -0700 (PDT)\r
+From: Dirk Hohndel <hohndel@infradead.org>\r
+To: <notmuch@notmuchmail.org>\r
+Subject: [PATCH 2/2] Rearchitect From: header guessing code for replies\r
+Date: Mon, 26 Apr 2010 12:58:35 -0700\r
+Message-Id: <1272311915-30575-3-git-send-email-hohndel@infradead.org>\r
+X-Mailer: git-send-email 1.6.6.1\r
+In-Reply-To: <1272311915-30575-2-git-send-email-hohndel@infradead.org>\r
+References: <m3sk6lcu9c.fsf@x200.gr8dns.org>\r
+ <1272311915-30575-1-git-send-email-hohndel@infradead.org>\r
+ <1272311915-30575-2-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:54 -0000\r
+\r
+We want to be able to correctly guess the best From: header to use when\r
+replying to emails. This is what we are looking at now:\r
+ 1 is one of the users' mail addresses in the To: or Cc: header\r
+ 2 check for an Envelope-to: header\r
+ 3 check for an X-Original-To: header\r
+ 4 check for a (for <email@add.res>) clause in Received: headers\r
+ 5 check for the domain part of known email addresses in the\r
+ 'by' part of Received headers\r
+ 6 fall back to the primary email address\r
+\r
+This patch changes the algorithm for steps 2-5 of this process. Prior to\r
+this patch we had a first attempt to implement only step 5 - but this\r
+broke in many email setups where mail delivery to the local machine added\r
+additional Received: lines.\r
+Steps 2-4 are new, step 5 now analyzes the concatenated Received: header\r
+(this was in the previous patch) to do this analysis.\r
+\r
+Signed-off-by: Dirk Hohndel <hohndel@infradead.org>\r
+---\r
+ notmuch-reply.c | 125 +++++++++++++++++++++++++++++++++++++++++-------------\r
+ 1 files changed, 95 insertions(+), 30 deletions(-)\r
+\r
+diff --git a/notmuch-reply.c b/notmuch-reply.c\r
+index 7c43146..333e945 100644\r
+--- a/notmuch-reply.c\r
++++ b/notmuch-reply.c\r
+@@ -311,36 +311,100 @@ add_recipients_from_message (GMimeMessage *reply,\r
+ static const char *\r
+ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message)\r
+ {\r
+- const char *received,*primary;\r
+- char **other;\r
+- char *by,*mta,*ptr,*token;\r
++ const char *received,*primary,*by;\r
++ char **other,*tohdr;\r
++ char *mta,*ptr,*token;\r
+ char *domain=NULL;\r
+ char *tld=NULL;\r
+ const char *delim=". \t";\r
+ size_t i,other_len;\r
+ \r
++ const char *to_headers[] = {"Envelope-to", "X-Original-To"};\r
++\r
++ primary = notmuch_config_get_user_primary_email (config);\r
++ other = notmuch_config_get_user_other_email (config, &other_len);\r
++\r
++ /* sadly, there is no standard way to find out to which email\r
++ * address a mail was delivered - what is in the headers depends\r
++ * on the MTAs used along the way. So we are trying a number of\r
++ * heuristics which hopefully will answer this question.\r
++\r
++ * We only got here if none of the users email addresses are in\r
++ * the To: or Cc: header. From here we try the following in order:\r
++ * 1) check for an Envelope-to: header\r
++ * 2) check for an X-Original-To: header\r
++ * 3) check for a (for <email@add.res>) clause in Received: headers\r
++ * 4) check for the domain part of known email addresses in the\r
++ * 'by' part of Received headers\r
++ * If none of these work, we give up and return NULL\r
++ */\r
++ for (i = 0; i < sizeof(to_headers)/sizeof(*to_headers); i++) {\r
++ tohdr = xstrdup(notmuch_message_get_header (message, to_headers[i]));\r
++ if (tohdr && *tohdr) {\r
++ /* tohdr is potentialy a list of email addresses, so here we\r
++ * check if one of the email addresses is a substring of tohdr\r
++ */\r
++ if (strcasestr(tohdr, primary)) {\r
++ free(tohdr);\r
++ return primary;\r
++ }\r
++ for (i = 0; i < other_len; i++)\r
++ if (strcasestr (tohdr, other[i])) {\r
++ free(tohdr);\r
++ return other[i];\r
++ }\r
++ free(tohdr);\r
++ }\r
++ }\r
++\r
++ /* We get the concatenated Received: headers and search from the\r
++ * front (last Received: header added) and try to extract from\r
++ * them indications to which email address this message was\r
++ * delivered.\r
++ * The Received: header is special in our get_header function\r
++ * and is always concated.\r
++ */\r
+ received = notmuch_message_get_header (message, "received");\r
+ if (received == NULL)\r
+ return NULL;\r
+ \r
+- by = strstr (received, " by ");\r
+- if (by && *(by+4)) {\r
+- /* sadly, the format of Received: headers is a bit inconsistent,\r
+- * depending on the MTA used. So we try to extract just the MTA\r
+- * here by removing leading whitespace and assuming that the MTA\r
+- * name ends at the next whitespace\r
+- * we test for *(by+4) to be non-'\0' to make sure there's something\r
+- * there at all - and then assume that the first whitespace delimited\r
+- * token that follows is the last receiving server\r
++ /* First we look for a " for <email@add.res>" in the received\r
++ * header\r
++ */\r
++ ptr = strstr (received, " for ");\r
++ if (ptr) {\r
++ /* the text following is potentialy a list of email addresses,\r
++ * so again we check if one of the email addresses is a\r
++ * substring of ptr\r
+ */\r
+- mta = strdup (by+4);\r
+- if (mta == NULL)\r
+- return NULL;\r
++ if (strcasestr(ptr, primary)) {\r
++ return primary;\r
++ }\r
++ for (i = 0; i < other_len; i++)\r
++ if (strcasestr (ptr, other[i])) {\r
++ return other[i];\r
++ }\r
++ }\r
++ /* Finally, we parse all the " by MTA ..." headers to guess the\r
++ * email address that this was originally delivered to.\r
++ * We extract just the MTA here by removing leading whitespace and\r
++ * assuming that the MTA name ends at the next whitespace.\r
++ * We test for *(by+4) to be non-'\0' to make sure there's\r
++ * something there at all - and then assume that the first\r
++ * whitespace delimited token that follows is the receiving\r
++ * system in this step of the receive chain\r
++ */\r
++ by = received;\r
++ while((by = strstr (by, " by ")) != NULL) {\r
++ by += 4;\r
++ if (*by == '\0')\r
++ break;\r
++ mta = xstrdup (by);\r
+ token = strtok(mta," \t");\r
+ if (token == NULL)\r
+- return NULL;\r
++ break;\r
+ /* Now extract the last two components of the MTA host name\r
+- * as domain and tld\r
++ * as domain and tld.\r
+ */\r
+ while ((ptr = strsep (&token, delim)) != NULL) {\r
+ if (*ptr == '\0')\r
+@@ -350,23 +414,24 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message\r
+ }\r
+ \r
+ if (domain) {\r
+- /* recombine domain and tld and look for it among the configured\r
+- * email addresses\r
++ /* Recombine domain and tld and look for it among the configured\r
++ * email addresses.\r
++ * This time we have a known domain name and nothing else - so\r
++ * the test is the other way around: we check if this is a\r
++ * substring of one of the email addresses.\r
+ */\r
+ *(tld-1) = '.';\r
+- primary = notmuch_config_get_user_primary_email (config);\r
+- if (strcasestr (primary, domain)) {\r
+- free (mta);\r
+- return primary;\r
++\r
++ if (strcasestr(primary, domain)) {\r
++ free(mta);\r
++ return primary;\r
++ }\r
++ for (i = 0; i < other_len; i++)\r
++ if (strcasestr (other[i],domain)) {\r
++ free(mta);\r
++ return other[i];\r
+ }\r
+- other = notmuch_config_get_user_other_email (config, &other_len);\r
+- for (i = 0; i < other_len; i++)\r
+- if (strcasestr (other[i], domain)) {\r
+- free (mta);\r
+- return other[i];\r
+- }\r
+ }\r
+-\r
+ free (mta);\r
+ }\r
+ \r
+-- \r
+1.6.6.1\r
+\r