--- /dev/null
+Return-Path: <jani@nikula.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 39DC9431FBC\r
+ for <notmuch@notmuchmail.org>; Mon, 3 Feb 2014 11:52:06 -0800 (PST)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Amavis-Alert: BAD HEADER SECTION, Duplicate header field: "References"\r
+X-Spam-Flag: NO\r
+X-Spam-Score: -0.7\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5\r
+ tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled\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 mr5GTSKgSzzv for <notmuch@notmuchmail.org>;\r
+ Mon, 3 Feb 2014 11:52:02 -0800 (PST)\r
+Received: from mail-ea0-f175.google.com (mail-ea0-f175.google.com\r
+ [209.85.215.175]) (using TLSv1 with cipher RC4-SHA (128/128 bits))\r
+ (No client certificate requested)\r
+ by olra.theworths.org (Postfix) with ESMTPS id 56581431FC9\r
+ for <notmuch@notmuchmail.org>; Mon, 3 Feb 2014 11:52:01 -0800 (PST)\r
+Received: by mail-ea0-f175.google.com with SMTP id z10so3917405ead.6\r
+ for <notmuch@notmuchmail.org>; Mon, 03 Feb 2014 11:52:00 -0800 (PST)\r
+X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;\r
+ d=1e100.net; s=20130820;\r
+ h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\r
+ :references:in-reply-to:references;\r
+ bh=4e8aKDlGpBD64reo7VuZkvREzQASRH8PEYY2XRnTaAc=;\r
+ b=DAAcyEskFTYZhNdg5t+3RUoAno0Dil3RBKCiXYTQD5u0KmShRJxQjLm0K0Yx+IuZRr\r
+ BKVuOSYcx3U87VSDFFtgd4XuCJNI6fICavDEq6hCLMtenSz4awDNGiVZfiwBYPC+WUQK\r
+ aazXTo1TyHvAVOJ6Xw8TQg7e8svfCDqJyad7F/MBCuHIgRKkxxhmLGdU+CgyG+Ab1muT\r
+ Kkbypfxk1wWZOJLqCysDDzhhZI/YymdLe6fLWwBFtInbMY0arF0EJOW0rD5t144ZaJTN\r
+ ZrMuHc+P05zek/EN4uQZrU3/Ag6RZtggXSZNIf99IKql23lMb0sfpNfG8zXGextDnkrt\r
+ Kmow==\r
+X-Gm-Message-State:\r
+ ALoCoQliQ2WJoaGom0rxSqK6i2iZ4BHQXJp8IDWmonxJWGdeN+E4vW/ouqmL3gUrVkgEVA7lLQy5\r
+X-Received: by 10.14.246.68 with SMTP id p44mr5139536eer.72.1391457120191;\r
+ Mon, 03 Feb 2014 11:52:00 -0800 (PST)\r
+Received: from localhost (dsl-hkibrasgw2-58c36f-91.dhcp.inet.fi.\r
+ [88.195.111.91]) by mx.google.com with ESMTPSA id\r
+ y47sm31524300eel.14.2014.02.03.11.51.58 for <multiple recipients>\r
+ (version=TLSv1.2 cipher=RC4-SHA bits=128/128);\r
+ Mon, 03 Feb 2014 11:51:59 -0800 (PST)\r
+From: Jani Nikula <jani@nikula.org>\r
+To: notmuch@notmuchmail.org\r
+Subject: [PATCH v3 2/6] cli: refactor reply from guessing\r
+Date: Mon, 3 Feb 2014 21:51:42 +0200\r
+Message-Id:\r
+ <db939e2df53b4cb9e333b1696daf2e8962bc8d15.1391456555.git.jani@nikula.org>\r
+X-Mailer: git-send-email 1.8.5.2\r
+In-Reply-To: <cover.1391456555.git.jani@nikula.org>\r
+References: <cover.1391456555.git.jani@nikula.org>\r
+In-Reply-To: <cover.1391456555.git.jani@nikula.org>\r
+References: <cover.1391456555.git.jani@nikula.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, 03 Feb 2014 19:52:06 -0000\r
+\r
+The guess_from_received_header() function had grown quite big. Chop it\r
+up into smaller functions.\r
+\r
+No functional changes.\r
+---\r
+ notmuch-reply.c | 198 ++++++++++++++++++++++++++++++++++----------------------\r
+ 1 file changed, 122 insertions(+), 76 deletions(-)\r
+\r
+diff --git a/notmuch-reply.c b/notmuch-reply.c\r
+index 79cdc83..47993d2 100644\r
+--- a/notmuch-reply.c\r
++++ b/notmuch-reply.c\r
+@@ -369,78 +369,44 @@ add_recipients_from_message (GMimeMessage *reply,\r
+ return from_addr;\r
+ }\r
+ \r
++/*\r
++ * Look for the user's address in " for <email@add.res>" in the\r
++ * received headers.\r
++ *\r
++ * Return the address that was found, if any, and NULL otherwise.\r
++ */\r
+ static const char *\r
+-guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message)\r
++guess_from_in_received_for (notmuch_config_t *config, const char *received)\r
+ {\r
+- const char *addr, *received, *by;\r
+- char *mta,*ptr,*token;\r
+- char *domain=NULL;\r
+- char *tld=NULL;\r
+- const char *delim=". \t";\r
+- size_t i;\r
+-\r
+- const char *to_headers[] = {\r
+- "Envelope-to",\r
+- "X-Original-To",\r
+- "Delivered-To",\r
+- };\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 Delivered-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
+- * If none of these work, we give up and return NULL\r
+- */\r
+- for (i = 0; i < ARRAY_SIZE (to_headers); i++) {\r
+- const char *tohdr = notmuch_message_get_header (message, to_headers[i]);\r
+-\r
+- /* Note: tohdr potentially contains a list of email addresses. */\r
+- addr = user_address_in_string (tohdr, config);\r
+- if (addr)\r
+- return addr;\r
+- }\r
++ const char *ptr;\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 concatenated.\r
+- */\r
+- received = notmuch_message_get_header (message, "received");\r
+- if (received == NULL)\r
++ ptr = strstr (received, " for ");\r
++ if (! ptr)\r
+ return NULL;\r
+ \r
+- /* First we look for a " for <email@add.res>" in the received\r
+- * header\r
+- */\r
+- ptr = strstr (received, " for ");\r
++ return user_address_in_string (ptr, config);\r
++}\r
+ \r
+- /* Note: ptr potentially contains a list of email addresses. */\r
+- addr = user_address_in_string (ptr, config);\r
+- if (addr)\r
+- return addr;\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
++/*\r
++ * Parse all the " by MTA ..." parts in received headers to guess the\r
++ * email address that this was originally delivered to.\r
++ *\r
++ * Extract just the MTA here by removing leading whitespace and\r
++ * assuming that the MTA name ends at the next whitespace. Test for\r
++ * *(by+4) to be non-'\0' to make sure there's something there at all\r
++ * - and then assume that the first whitespace delimited token that\r
++ * follows is the receiving system in this step of the receive chain.\r
++ *\r
++ * Return the address that was found, if any, and NULL otherwise.\r
++ */\r
++static const char *\r
++guess_from_in_received_by (notmuch_config_t *config, const char *received)\r
++{\r
++ const char *addr;\r
++ const char *by = received;\r
++ char *domain, *tld, *mta, *ptr, *token;\r
++\r
++ while ((by = strstr (by, " by ")) != NULL) {\r
+ by += 4;\r
+ if (*by == '\0')\r
+ break;\r
+@@ -450,11 +416,12 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message\r
+ free (mta);\r
+ break;\r
+ }\r
+- /* Now extract the last two components of the MTA host name\r
+- * as domain and tld.\r
++ /*\r
++ * Now extract the last two components of the MTA host name as\r
++ * domain and tld.\r
+ */\r
+ domain = tld = NULL;\r
+- while ((ptr = strsep (&token, delim)) != NULL) {\r
++ while ((ptr = strsep (&token, ". \t")) != NULL) {\r
+ if (*ptr == '\0')\r
+ continue;\r
+ domain = tld;\r
+@@ -462,13 +429,14 @@ 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
+- * 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
++ * Recombine domain and tld and look for it among the\r
++ * configured email addresses. This time we have a known\r
++ * domain name and nothing else - so the test is the other\r
++ * way around: we check if this is a substring of one of\r
++ * the email addresses.\r
+ */\r
+- *(tld-1) = '.';\r
++ *(tld - 1) = '.';\r
+ \r
+ addr = string_in_user_address (domain, config);\r
+ if (addr) {\r
+@@ -482,6 +450,63 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message\r
+ return NULL;\r
+ }\r
+ \r
++/*\r
++ * Get the concatenated Received: headers and search from the front\r
++ * (last Received: header added) and try to extract from them\r
++ * indications to which email address this message was delivered.\r
++ *\r
++ * The Received: header is special in our get_header function and is\r
++ * always concatenated.\r
++ *\r
++ * Return the address that was found, if any, and NULL otherwise.\r
++ */\r
++static const char *\r
++guess_from_in_received_headers (notmuch_config_t *config,\r
++ notmuch_message_t *message)\r
++{\r
++ const char *received, *addr;\r
++\r
++ received = notmuch_message_get_header (message, "received");\r
++ if (! received)\r
++ return NULL;\r
++\r
++ addr = guess_from_in_received_for (config, received);\r
++ if (! addr)\r
++ addr = guess_from_in_received_by (config, received);\r
++\r
++ return addr;\r
++}\r
++\r
++/*\r
++ * Try to find user's email address in one of the extra To-like\r
++ * headers: Envelope-To, X-Original-To, and Delivered-To (searched in\r
++ * that order).\r
++ *\r
++ * Return the address that was found, if any, and NULL otherwise.\r
++ */\r
++static const char *\r
++get_from_in_to_headers (notmuch_config_t *config, notmuch_message_t *message)\r
++{\r
++ size_t i;\r
++ const char *tohdr, *addr;\r
++ const char *to_headers[] = {\r
++ "Envelope-to",\r
++ "X-Original-To",\r
++ "Delivered-To",\r
++ };\r
++\r
++ for (i = 0; i < ARRAY_SIZE (to_headers); i++) {\r
++ tohdr = notmuch_message_get_header (message, to_headers[i]);\r
++\r
++ /* Note: tohdr potentially contains a list of email addresses. */\r
++ addr = user_address_in_string (tohdr, config);\r
++ if (addr)\r
++ return addr;\r
++ }\r
++\r
++ return NULL;\r
++}\r
++\r
+ static GMimeMessage *\r
+ create_reply_message(void *ctx,\r
+ notmuch_config_t *config,\r
+@@ -508,9 +533,30 @@ create_reply_message(void *ctx,\r
+ from_addr = add_recipients_from_message (reply, config,\r
+ message, reply_all);\r
+ \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.\r
++ *\r
++ * If none of the user's email addresses are in the To: or Cc:\r
++ * headers, we try a number of heuristics which hopefully will\r
++ * answer this question.\r
++ *\r
++ * First, check for Envelope-To:, X-Original-To:, and\r
++ * Delivered-To: headers.\r
++ */\r
++ if (from_addr == NULL)\r
++ from_addr = get_from_in_to_headers (config, message);\r
++\r
++ /*\r
++ * Check for a (for <email@add.res>) clause in Received: headers,\r
++ * and the domain part of known email addresses in the 'by' part\r
++ * of Received: headers\r
++ */\r
+ if (from_addr == NULL)\r
+- from_addr = guess_from_received_header (config, message);\r
++ from_addr = guess_from_in_received_headers (config, message);\r
+ \r
++ /* Default to user's primary address. */\r
+ if (from_addr == NULL)\r
+ from_addr = notmuch_config_get_user_primary_email (config);\r
+ \r
+-- \r
+1.8.5.2\r
+\r