cli: refactor reply from guessing
authorJani Nikula <jani@nikula.org>
Mon, 3 Feb 2014 19:51:42 +0000 (21:51 +0200)
committerDavid Bremner <david@tethera.net>
Sun, 9 Mar 2014 13:13:17 +0000 (10:13 -0300)
The guess_from_received_header() function had grown quite big. Chop it
up into smaller functions.

No functional changes.

notmuch-reply.c

index 79cdc83397d3adf26678e6fcccd6e4a3883c49d1..47993d223090ee423b7c42126122dcd688215c8b 100644 (file)
@@ -369,78 +369,44 @@ add_recipients_from_message (GMimeMessage *reply,
     return from_addr;
 }
 
+/*
+ * Look for the user's address in " for <email@add.res>" in the
+ * received headers.
+ *
+ * Return the address that was found, if any, and NULL otherwise.
+ */
 static const char *
-guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message)
+guess_from_in_received_for (notmuch_config_t *config, const char *received)
 {
-    const char *addr, *received, *by;
-    char *mta,*ptr,*token;
-    char *domain=NULL;
-    char *tld=NULL;
-    const char *delim=". \t";
-    size_t i;
-
-    const char *to_headers[] = {
-       "Envelope-to",
-       "X-Original-To",
-       "Delivered-To",
-    };
-
-    /* sadly, there is no standard way to find out to which email
-     * address a mail was delivered - what is in the headers depends
-     * on the MTAs used along the way. So we are trying a number of
-     * heuristics which hopefully will answer this question.
-
-     * We only got here if none of the users email addresses are in
-     * the To: or Cc: header. From here we try the following in order:
-     * 1) check for an Envelope-to: header
-     * 2) check for an X-Original-To: header
-     * 3) check for a Delivered-To: header
-     * 4) check for a (for <email@add.res>) clause in Received: headers
-     * 5) check for the domain part of known email addresses in the
-     *    'by' part of Received headers
-     * If none of these work, we give up and return NULL
-     */
-    for (i = 0; i < ARRAY_SIZE (to_headers); i++) {
-       const char *tohdr = notmuch_message_get_header (message, to_headers[i]);
-
-       /* Note: tohdr potentially contains a list of email addresses. */
-       addr = user_address_in_string (tohdr, config);
-       if (addr)
-           return addr;
-    }
+    const char *ptr;
 
-    /* We get the concatenated Received: headers and search from the
-     * front (last Received: header added) and try to extract from
-     * them indications to which email address this message was
-     * delivered.
-     * The Received: header is special in our get_header function
-     * and is always concatenated.
-     */
-    received = notmuch_message_get_header (message, "received");
-    if (received == NULL)
+    ptr = strstr (received, " for ");
+    if (! ptr)
        return NULL;
 
-    /* First we look for a " for <email@add.res>" in the received
-     * header
-     */
-    ptr = strstr (received, " for ");
+    return user_address_in_string (ptr, config);
+}
 
-    /* Note: ptr potentially contains a list of email addresses. */
-    addr = user_address_in_string (ptr, config);
-    if (addr)
-       return addr;
-
-    /* Finally, we parse all the " by MTA ..." headers to guess the
-     * email address that this was originally delivered to.
-     * We extract just the MTA here by removing leading whitespace and
-     * assuming that the MTA name ends at the next whitespace.
-     * We test for *(by+4) to be non-'\0' to make sure there's
-     * something there at all - and then assume that the first
-     * whitespace delimited token that follows is the receiving
-     * system in this step of the receive chain
-     */
-    by = received;
-    while((by = strstr (by, " by ")) != NULL) {
+/*
+ * Parse all the " by MTA ..." parts in received headers to guess the
+ * email address that this was originally delivered to.
+ *
+ * Extract just the MTA here by removing leading whitespace and
+ * assuming that the MTA name ends at the next whitespace. Test for
+ * *(by+4) to be non-'\0' to make sure there's something there at all
+ * - and then assume that the first whitespace delimited token that
+ * follows is the receiving system in this step of the receive chain.
+ *
+ * Return the address that was found, if any, and NULL otherwise.
+ */
+static const char *
+guess_from_in_received_by (notmuch_config_t *config, const char *received)
+{
+    const char *addr;
+    const char *by = received;
+    char *domain, *tld, *mta, *ptr, *token;
+
+    while ((by = strstr (by, " by ")) != NULL) {
        by += 4;
        if (*by == '\0')
            break;
@@ -450,11 +416,12 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message
            free (mta);
            break;
        }
-       /* Now extract the last two components of the MTA host name
-        * as domain and tld.
+       /*
+        * Now extract the last two components of the MTA host name as
+        * domain and tld.
         */
        domain = tld = NULL;
-       while ((ptr = strsep (&token, delim)) != NULL) {
+       while ((ptr = strsep (&token, ". \t")) != NULL) {
            if (*ptr == '\0')
                continue;
            domain = tld;
@@ -462,13 +429,14 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message
        }
 
        if (domain) {
-           /* Recombine domain and tld and look for it among the configured
-            * email addresses.
-            * This time we have a known domain name and nothing else - so
-            * the test is the other way around: we check if this is a
-            * substring of one of the email addresses.
+           /*
+            * Recombine domain and tld and look for it among the
+            * configured email addresses. This time we have a known
+            * domain name and nothing else - so the test is the other
+            * way around: we check if this is a substring of one of
+            * the email addresses.
             */
-           *(tld-1) = '.';
+           *(tld - 1) = '.';
 
            addr = string_in_user_address (domain, config);
            if (addr) {
@@ -482,6 +450,63 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message
     return NULL;
 }
 
+/*
+ * Get the concatenated Received: headers and search from the front
+ * (last Received: header added) and try to extract from them
+ * indications to which email address this message was delivered.
+ *
+ * The Received: header is special in our get_header function and is
+ * always concatenated.
+ *
+ * Return the address that was found, if any, and NULL otherwise.
+ */
+static const char *
+guess_from_in_received_headers (notmuch_config_t *config,
+                               notmuch_message_t *message)
+{
+    const char *received, *addr;
+
+    received = notmuch_message_get_header (message, "received");
+    if (! received)
+       return NULL;
+
+    addr = guess_from_in_received_for (config, received);
+    if (! addr)
+       addr = guess_from_in_received_by (config, received);
+
+    return addr;
+}
+
+/*
+ * Try to find user's email address in one of the extra To-like
+ * headers: Envelope-To, X-Original-To, and Delivered-To (searched in
+ * that order).
+ *
+ * Return the address that was found, if any, and NULL otherwise.
+ */
+static const char *
+get_from_in_to_headers (notmuch_config_t *config, notmuch_message_t *message)
+{
+    size_t i;
+    const char *tohdr, *addr;
+    const char *to_headers[] = {
+       "Envelope-to",
+       "X-Original-To",
+       "Delivered-To",
+    };
+
+    for (i = 0; i < ARRAY_SIZE (to_headers); i++) {
+       tohdr = notmuch_message_get_header (message, to_headers[i]);
+
+       /* Note: tohdr potentially contains a list of email addresses. */
+       addr = user_address_in_string (tohdr, config);
+       if (addr)
+           return addr;
+    }
+
+    return NULL;
+}
+
 static GMimeMessage *
 create_reply_message(void *ctx,
                     notmuch_config_t *config,
@@ -508,9 +533,30 @@ create_reply_message(void *ctx,
     from_addr = add_recipients_from_message (reply, config,
                                             message, reply_all);
 
+    /*
+     * Sadly, there is no standard way to find out to which email
+     * address a mail was delivered - what is in the headers depends
+     * on the MTAs used along the way.
+     *
+     * If none of the user's email addresses are in the To: or Cc:
+     * headers, we try a number of heuristics which hopefully will
+     * answer this question.
+     *
+     * First, check for Envelope-To:, X-Original-To:, and
+     * Delivered-To: headers.
+     */
+    if (from_addr == NULL)
+       from_addr = get_from_in_to_headers (config, message);
+
+    /*
+     * Check for a (for <email@add.res>) clause in Received: headers,
+     * and the domain part of known email addresses in the 'by' part
+     * of Received: headers
+     */
     if (from_addr == NULL)
-       from_addr = guess_from_received_header (config, message);
+       from_addr = guess_from_in_received_headers (config, message);
 
+    /* Default to user's primary address. */
     if (from_addr == NULL)
        from_addr = notmuch_config_get_user_primary_email (config);