[PATCH v3 2/6] cli: refactor reply from guessing
authorJani Nikula <jani@nikula.org>
Mon, 3 Feb 2014 19:51:42 +0000 (21:51 +0200)
committerW. Trevor King <wking@tremily.us>
Fri, 7 Nov 2014 17:59:39 +0000 (09:59 -0800)
cd/00ef31f44b175ec928b671413c0e263cded75b [new file with mode: 0644]

diff --git a/cd/00ef31f44b175ec928b671413c0e263cded75b b/cd/00ef31f44b175ec928b671413c0e263cded75b
new file mode 100644 (file)
index 0000000..73f84f0
--- /dev/null
@@ -0,0 +1,328 @@
+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