[PATCH v2 2/7] cli: refactor reply from guessing
authorJani Nikula <jani@nikula.org>
Sat, 30 Nov 2013 15:33:51 +0000 (17:33 +0200)
committerW. Trevor King <wking@tremily.us>
Fri, 7 Nov 2014 17:58:31 +0000 (09:58 -0800)
c2/bf6053828a9574bf8e19564c55840d90babdd1 [new file with mode: 0644]

diff --git a/c2/bf6053828a9574bf8e19564c55840d90babdd1 b/c2/bf6053828a9574bf8e19564c55840d90babdd1
new file mode 100644 (file)
index 0000000..d9cf435
--- /dev/null
@@ -0,0 +1,304 @@
+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 583E4431FDB\r
+       for <notmuch@notmuchmail.org>; Sat, 30 Nov 2013 07:34:16 -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 XzhUjj97E1Rg for <notmuch@notmuchmail.org>;\r
+       Sat, 30 Nov 2013 07:34:09 -0800 (PST)\r
+Received: from mail-ea0-f172.google.com (mail-ea0-f172.google.com\r
+       [209.85.215.172]) (using TLSv1 with cipher RC4-SHA (128/128 bits))\r
+       (No client certificate requested)\r
+       by olra.theworths.org (Postfix) with ESMTPS id 3F7B6431FBC\r
+       for <notmuch@notmuchmail.org>; Sat, 30 Nov 2013 07:34:06 -0800 (PST)\r
+Received: by mail-ea0-f172.google.com with SMTP id q10so7520437ead.17\r
+       for <notmuch@notmuchmail.org>; Sat, 30 Nov 2013 07:34:05 -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=zoe9OLsyJ3LsuNeOyW7iaJql4J5nfEBgb4WIHrp3w80=;\r
+       b=AlrPC0vcIV01vOF6eqvsnr+4wAPHrRBG+TC8E3lmkI9VPFWepaZYZueBHt7K9sWF1a\r
+       8zOI491KcMpOTxHJNW6a0ugdwRnHPzUZ9ZAWNSTwfoZij2HAtMa8n9F4NiM47eb1EvbG\r
+       7gb1iYMuMEEd9sOE6Gu34cwT6rzXKmr4ST2K/okE/BWL4iM25LU1jDHmm4WXWksGcWjJ\r
+       RhltnRci+qhxfzLIrR9KceecJhfqBWyrp9CQIOSOODYW94sP0lBaZhx4D5aGKGe2dXbJ\r
+       IiqQi7teBOJ8K0qcw1QbqZOvQ/uQfGVOcHH0jWrz0AgmXOs1705MaGqS4p86KWOJAOLh\r
+       BDoQ==\r
+X-Gm-Message-State:\r
+ ALoCoQkxdJzqLxjO6L8RyLdoRYc4yowXg5yJ3+vyz7N/bbGrBx4ci+d6GYS/saYeq+Znhz/5Y7X/\r
+X-Received: by 10.15.101.9 with SMTP id bo9mr7572255eeb.32.1385825645230;\r
+       Sat, 30 Nov 2013 07:34:05 -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
+       o47sm52032280eem.21.2013.11.30.07.34.03 for <multiple recipients>\r
+       (version=TLSv1.2 cipher=RC4-SHA bits=128/128);\r
+       Sat, 30 Nov 2013 07:34:04 -0800 (PST)\r
+From: Jani Nikula <jani@nikula.org>\r
+To: notmuch@notmuchmail.org\r
+Subject: [PATCH v2 2/7] cli: refactor reply from guessing\r
+Date: Sat, 30 Nov 2013 17:33:51 +0200\r
+Message-Id:\r
+ <c877beb316c1ebab5d5b7224483ce9fac4f69598.1385825425.git.jani@nikula.org>\r
+X-Mailer: git-send-email 1.8.4.2\r
+In-Reply-To: <cover.1385825425.git.jani@nikula.org>\r
+References: <cover.1385825425.git.jani@nikula.org>\r
+In-Reply-To: <cover.1385825425.git.jani@nikula.org>\r
+References: <cover.1385825425.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: Sat, 30 Nov 2013 15:34:16 -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 | 178 +++++++++++++++++++++++++++++++++-----------------------\r
+ 1 file changed, 105 insertions(+), 73 deletions(-)\r
+\r
+diff --git a/notmuch-reply.c b/notmuch-reply.c\r
+index 9d6f843..ca41405 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_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_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
+@@ -454,7 +420,7 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message\r
+        * as 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 +428,13 @@ 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
++          /* 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 +448,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_received_header (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_received_for (config, received);\r
++    if (! addr)\r
++      addr = guess_from_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, such as Envelope-To, X-Original-To, and\r
++ * Delivered-To.\r
++ *\r
++ * Return the address that was found, if any, and NULL otherwise.\r
++ */\r
++static const char *\r
++from_from_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,6 +531,15 @@ 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. So we are trying a number of\r
++     * heuristics which hopefully will answer this question.\r
++     */\r
++    if (from_addr == NULL)\r
++      from_addr = from_from_to_headers (config, message);\r
++\r
+     if (from_addr == NULL)\r
+       from_addr = guess_from_received_header (config, message);\r
\r
+-- \r
+1.8.4.2\r
+\r