Re: [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane
[notmuch-archives.git] / a4 / 28a07579595f0cac1fc146e803523031cf05e6
1 Return-Path: <hohndel@gr8dns.org>\r
2 X-Original-To: notmuch@notmuchmail.org\r
3 Delivered-To: notmuch@notmuchmail.org\r
4 Received: from localhost (localhost [127.0.0.1])\r
5         by olra.theworths.org (Postfix) with ESMTP id DED3A417339\r
6         for <notmuch@notmuchmail.org>; Mon, 26 Apr 2010 12:58:53 -0700 (PDT)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: -1.9\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-1.9 tagged_above=-999 required=5\r
12         tests=[BAYES_00=-1.9] autolearn=ham\r
13 Received: from olra.theworths.org ([127.0.0.1])\r
14         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
15         with ESMTP id TcmZOx-CFKqj for <notmuch@notmuchmail.org>;\r
16         Mon, 26 Apr 2010 12:58:51 -0700 (PDT)\r
17 Received: from mail.hohndel.org (mail.hohndel.org [65.23.157.147])\r
18         by olra.theworths.org (Postfix) with ESMTP id 9149B4196F4\r
19         for <notmuch@notmuchmail.org>; Mon, 26 Apr 2010 12:58:49 -0700 (PDT)\r
20 Received: by mail.hohndel.org (Postfix, from userid 112)\r
21         id 2B2D3340F4; Mon, 26 Apr 2010 15:58:49 -0400 (EDT)\r
22 Received: from x200.gr8dns.org (unknown [65.23.157.147])\r
23         by mail.hohndel.org (Postfix) with ESMTP id 6EB25340F8;\r
24         Mon, 26 Apr 2010 15:58:42 -0400 (EDT)\r
25 Received: by x200.gr8dns.org (Postfix, from userid 500)\r
26         id 4EAC7CC903; Mon, 26 Apr 2010 12:58:42 -0700 (PDT)\r
27 From: Dirk Hohndel <hohndel@infradead.org>\r
28 To: <notmuch@notmuchmail.org>\r
29 Subject: [PATCH 2/2] Rearchitect From: header guessing code for replies\r
30 Date: Mon, 26 Apr 2010 12:58:35 -0700\r
31 Message-Id: <1272311915-30575-3-git-send-email-hohndel@infradead.org>\r
32 X-Mailer: git-send-email 1.6.6.1\r
33 In-Reply-To: <1272311915-30575-2-git-send-email-hohndel@infradead.org>\r
34 References: <m3sk6lcu9c.fsf@x200.gr8dns.org>\r
35         <1272311915-30575-1-git-send-email-hohndel@infradead.org>\r
36         <1272311915-30575-2-git-send-email-hohndel@infradead.org>\r
37 X-BeenThere: notmuch@notmuchmail.org\r
38 X-Mailman-Version: 2.1.13\r
39 Precedence: list\r
40 List-Id: "Use and development of the notmuch mail system."\r
41         <notmuch.notmuchmail.org>\r
42 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
43         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
44 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
45 List-Post: <mailto:notmuch@notmuchmail.org>\r
46 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
47 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
48         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
49 X-List-Received-Date: Mon, 26 Apr 2010 19:58:54 -0000\r
50 \r
51 We want to be able to correctly guess the best From: header to use when\r
52 replying to emails. This is what we are looking at now:\r
53  1 is one of the users' mail addresses in the To: or Cc: header\r
54  2 check for an Envelope-to: header\r
55  3 check for an X-Original-To: header\r
56  4 check for a (for <email@add.res>) clause in Received: headers\r
57  5 check for the domain part of known email addresses in the\r
58       'by' part of Received headers\r
59  6 fall back to the primary email address\r
60 \r
61 This patch changes the algorithm for steps 2-5 of this process. Prior to\r
62 this patch we had a first attempt to implement only step 5 - but this\r
63 broke in many email setups where mail delivery to the local machine added\r
64 additional Received: lines.\r
65 Steps 2-4 are new, step 5 now analyzes the concatenated Received: header\r
66 (this was in the previous patch) to do this analysis.\r
67 \r
68 Signed-off-by: Dirk Hohndel <hohndel@infradead.org>\r
69 ---\r
70  notmuch-reply.c |  125 +++++++++++++++++++++++++++++++++++++++++-------------\r
71  1 files changed, 95 insertions(+), 30 deletions(-)\r
72 \r
73 diff --git a/notmuch-reply.c b/notmuch-reply.c\r
74 index 7c43146..333e945 100644\r
75 --- a/notmuch-reply.c\r
76 +++ b/notmuch-reply.c\r
77 @@ -311,36 +311,100 @@ add_recipients_from_message (GMimeMessage *reply,\r
78  static const char *\r
79  guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message)\r
80  {\r
81 -    const char *received,*primary;\r
82 -    char **other;\r
83 -    char *by,*mta,*ptr,*token;\r
84 +    const char *received,*primary,*by;\r
85 +    char **other,*tohdr;\r
86 +    char *mta,*ptr,*token;\r
87      char *domain=NULL;\r
88      char *tld=NULL;\r
89      const char *delim=". \t";\r
90      size_t i,other_len;\r
91  \r
92 +    const char *to_headers[] = {"Envelope-to", "X-Original-To"};\r
93 +\r
94 +    primary = notmuch_config_get_user_primary_email (config);\r
95 +    other = notmuch_config_get_user_other_email (config, &other_len);\r
96 +\r
97 +    /* sadly, there is no standard way to find out to which email\r
98 +     * address a mail was delivered - what is in the headers depends\r
99 +     * on the MTAs used along the way. So we are trying a number of\r
100 +     * heuristics which hopefully will answer this question.\r
101 +\r
102 +     * We only got here if none of the users email addresses are in\r
103 +     * the To: or Cc: header. From here we try the following in order:\r
104 +     * 1) check for an Envelope-to: header\r
105 +     * 2) check for an X-Original-To: header\r
106 +     * 3) check for a (for <email@add.res>) clause in Received: headers\r
107 +     * 4) check for the domain part of known email addresses in the\r
108 +     *    'by' part of Received headers\r
109 +     * If none of these work, we give up and return NULL\r
110 +     */\r
111 +    for (i = 0; i < sizeof(to_headers)/sizeof(*to_headers); i++) {\r
112 +       tohdr = xstrdup(notmuch_message_get_header (message, to_headers[i]));\r
113 +       if (tohdr && *tohdr) {\r
114 +           /* tohdr is potentialy a list of email addresses, so here we\r
115 +            * check if one of the email addresses is a substring of tohdr\r
116 +            */\r
117 +           if (strcasestr(tohdr, primary)) {\r
118 +               free(tohdr);\r
119 +               return primary;\r
120 +           }\r
121 +           for (i = 0; i < other_len; i++)\r
122 +               if (strcasestr (tohdr, other[i])) {\r
123 +                   free(tohdr);\r
124 +                   return other[i];\r
125 +               }\r
126 +           free(tohdr);\r
127 +       }\r
128 +    }\r
129 +\r
130 +    /* We get the concatenated Received: headers and search from the\r
131 +     * front (last Received: header added) and try to extract from\r
132 +     * them indications to which email address this message was\r
133 +     * delivered.\r
134 +     * The Received: header is special in our get_header function\r
135 +     * and is always concated.\r
136 +     */\r
137      received = notmuch_message_get_header (message, "received");\r
138      if (received == NULL)\r
139         return NULL;\r
140  \r
141 -    by = strstr (received, " by ");\r
142 -    if (by && *(by+4)) {\r
143 -       /* sadly, the format of Received: headers is a bit inconsistent,\r
144 -        * depending on the MTA used. So we try to extract just the MTA\r
145 -        * here by removing leading whitespace and assuming that the MTA\r
146 -        * name ends at the next whitespace\r
147 -        * we test for *(by+4) to be non-'\0' to make sure there's something\r
148 -        * there at all - and then assume that the first whitespace delimited\r
149 -        * token that follows is the last receiving server\r
150 +    /* First we look for a " for <email@add.res>" in the received\r
151 +     * header\r
152 +     */\r
153 +    ptr = strstr (received, " for ");\r
154 +    if (ptr) {\r
155 +       /* the text following is potentialy a list of email addresses,\r
156 +        * so again we check if one of the email addresses is a\r
157 +        * substring of ptr\r
158          */\r
159 -       mta = strdup (by+4);\r
160 -       if (mta == NULL)\r
161 -           return NULL;\r
162 +       if (strcasestr(ptr, primary)) {\r
163 +           return primary;\r
164 +       }\r
165 +       for (i = 0; i < other_len; i++)\r
166 +           if (strcasestr (ptr, other[i])) {\r
167 +               return other[i];\r
168 +           }\r
169 +    }\r
170 +    /* Finally, we parse all the " by MTA ..." headers to guess the\r
171 +     * email address that this was originally delivered to.\r
172 +     * We extract just the MTA here by removing leading whitespace and\r
173 +     * assuming that the MTA name ends at the next whitespace.\r
174 +     * We test for *(by+4) to be non-'\0' to make sure there's\r
175 +     * something there at all - and then assume that the first\r
176 +     * whitespace delimited token that follows is the receiving\r
177 +     * system in this step of the receive chain\r
178 +     */\r
179 +    by = received;\r
180 +    while((by = strstr (by, " by ")) != NULL) {\r
181 +       by += 4;\r
182 +       if (*by == '\0')\r
183 +           break;\r
184 +       mta = xstrdup (by);\r
185         token = strtok(mta," \t");\r
186         if (token == NULL)\r
187 -           return NULL;\r
188 +           break;\r
189         /* Now extract the last two components of the MTA host name\r
190 -        * as domain and tld\r
191 +        * as domain and tld.\r
192          */\r
193         while ((ptr = strsep (&token, delim)) != NULL) {\r
194             if (*ptr == '\0')\r
195 @@ -350,23 +414,24 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message\r
196         }\r
197  \r
198         if (domain) {\r
199 -           /* recombine domain and tld and look for it among the configured\r
200 -            * email addresses\r
201 +           /* Recombine domain and tld and look for it among the configured\r
202 +            * email addresses.\r
203 +            * This time we have a known domain name and nothing else - so\r
204 +            * the test is the other way around: we check if this is a\r
205 +            * substring of one of the email addresses.\r
206              */\r
207             *(tld-1) = '.';\r
208 -           primary = notmuch_config_get_user_primary_email (config);\r
209 -           if (strcasestr (primary, domain)) {\r
210 -               free (mta);\r
211 -               return primary;\r
212 +\r
213 +           if (strcasestr(primary, domain)) {\r
214 +               free(mta);\r
215 +           return primary;\r
216 +       }\r
217 +       for (i = 0; i < other_len; i++)\r
218 +           if (strcasestr (other[i],domain)) {\r
219 +               free(mta);\r
220 +               return other[i];\r
221             }\r
222 -           other = notmuch_config_get_user_other_email (config, &other_len);\r
223 -           for (i = 0; i < other_len; i++)\r
224 -               if (strcasestr (other[i], domain)) {\r
225 -                   free (mta);\r
226 -                   return other[i];\r
227 -               }\r
228         }\r
229 -\r
230         free (mta);\r
231      }\r
232  \r
233 -- \r
234 1.6.6.1\r
235 \r