Re: Synchronization success stories?
[notmuch-archives.git] / cd / 00ef31f44b175ec928b671413c0e263cded75b
1 Return-Path: <jani@nikula.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 39DC9431FBC\r
6         for <notmuch@notmuchmail.org>; Mon,  3 Feb 2014 11:52:06 -0800 (PST)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Amavis-Alert: BAD HEADER SECTION, Duplicate header field: "References"\r
9 X-Spam-Flag: NO\r
10 X-Spam-Score: -0.7\r
11 X-Spam-Level: \r
12 X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5\r
13         tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled\r
14 Received: from olra.theworths.org ([127.0.0.1])\r
15         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
16         with ESMTP id mr5GTSKgSzzv for <notmuch@notmuchmail.org>;\r
17         Mon,  3 Feb 2014 11:52:02 -0800 (PST)\r
18 Received: from mail-ea0-f175.google.com (mail-ea0-f175.google.com\r
19         [209.85.215.175]) (using TLSv1 with cipher RC4-SHA (128/128 bits))\r
20         (No client certificate requested)\r
21         by olra.theworths.org (Postfix) with ESMTPS id 56581431FC9\r
22         for <notmuch@notmuchmail.org>; Mon,  3 Feb 2014 11:52:01 -0800 (PST)\r
23 Received: by mail-ea0-f175.google.com with SMTP id z10so3917405ead.6\r
24         for <notmuch@notmuchmail.org>; Mon, 03 Feb 2014 11:52:00 -0800 (PST)\r
25 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;\r
26         d=1e100.net; s=20130820;\r
27         h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\r
28         :references:in-reply-to:references;\r
29         bh=4e8aKDlGpBD64reo7VuZkvREzQASRH8PEYY2XRnTaAc=;\r
30         b=DAAcyEskFTYZhNdg5t+3RUoAno0Dil3RBKCiXYTQD5u0KmShRJxQjLm0K0Yx+IuZRr\r
31         BKVuOSYcx3U87VSDFFtgd4XuCJNI6fICavDEq6hCLMtenSz4awDNGiVZfiwBYPC+WUQK\r
32         aazXTo1TyHvAVOJ6Xw8TQg7e8svfCDqJyad7F/MBCuHIgRKkxxhmLGdU+CgyG+Ab1muT\r
33         Kkbypfxk1wWZOJLqCysDDzhhZI/YymdLe6fLWwBFtInbMY0arF0EJOW0rD5t144ZaJTN\r
34         ZrMuHc+P05zek/EN4uQZrU3/Ag6RZtggXSZNIf99IKql23lMb0sfpNfG8zXGextDnkrt\r
35         Kmow==\r
36 X-Gm-Message-State:\r
37  ALoCoQliQ2WJoaGom0rxSqK6i2iZ4BHQXJp8IDWmonxJWGdeN+E4vW/ouqmL3gUrVkgEVA7lLQy5\r
38 X-Received: by 10.14.246.68 with SMTP id p44mr5139536eer.72.1391457120191;\r
39         Mon, 03 Feb 2014 11:52:00 -0800 (PST)\r
40 Received: from localhost (dsl-hkibrasgw2-58c36f-91.dhcp.inet.fi.\r
41         [88.195.111.91]) by mx.google.com with ESMTPSA id\r
42         y47sm31524300eel.14.2014.02.03.11.51.58 for <multiple recipients>\r
43         (version=TLSv1.2 cipher=RC4-SHA bits=128/128);\r
44         Mon, 03 Feb 2014 11:51:59 -0800 (PST)\r
45 From: Jani Nikula <jani@nikula.org>\r
46 To: notmuch@notmuchmail.org\r
47 Subject: [PATCH v3 2/6] cli: refactor reply from guessing\r
48 Date: Mon,  3 Feb 2014 21:51:42 +0200\r
49 Message-Id:\r
50  <db939e2df53b4cb9e333b1696daf2e8962bc8d15.1391456555.git.jani@nikula.org>\r
51 X-Mailer: git-send-email 1.8.5.2\r
52 In-Reply-To: <cover.1391456555.git.jani@nikula.org>\r
53 References: <cover.1391456555.git.jani@nikula.org>\r
54 In-Reply-To: <cover.1391456555.git.jani@nikula.org>\r
55 References: <cover.1391456555.git.jani@nikula.org>\r
56 X-BeenThere: notmuch@notmuchmail.org\r
57 X-Mailman-Version: 2.1.13\r
58 Precedence: list\r
59 List-Id: "Use and development of the notmuch mail system."\r
60         <notmuch.notmuchmail.org>\r
61 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
62         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
63 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
64 List-Post: <mailto:notmuch@notmuchmail.org>\r
65 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
66 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
67         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
68 X-List-Received-Date: Mon, 03 Feb 2014 19:52:06 -0000\r
69 \r
70 The guess_from_received_header() function had grown quite big. Chop it\r
71 up into smaller functions.\r
72 \r
73 No functional changes.\r
74 ---\r
75  notmuch-reply.c | 198 ++++++++++++++++++++++++++++++++++----------------------\r
76  1 file changed, 122 insertions(+), 76 deletions(-)\r
77 \r
78 diff --git a/notmuch-reply.c b/notmuch-reply.c\r
79 index 79cdc83..47993d2 100644\r
80 --- a/notmuch-reply.c\r
81 +++ b/notmuch-reply.c\r
82 @@ -369,78 +369,44 @@ add_recipients_from_message (GMimeMessage *reply,\r
83      return from_addr;\r
84  }\r
85  \r
86 +/*\r
87 + * Look for the user's address in " for <email@add.res>" in the\r
88 + * received headers.\r
89 + *\r
90 + * Return the address that was found, if any, and NULL otherwise.\r
91 + */\r
92  static const char *\r
93 -guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message)\r
94 +guess_from_in_received_for (notmuch_config_t *config, const char *received)\r
95  {\r
96 -    const char *addr, *received, *by;\r
97 -    char *mta,*ptr,*token;\r
98 -    char *domain=NULL;\r
99 -    char *tld=NULL;\r
100 -    const char *delim=". \t";\r
101 -    size_t i;\r
102 -\r
103 -    const char *to_headers[] = {\r
104 -       "Envelope-to",\r
105 -       "X-Original-To",\r
106 -       "Delivered-To",\r
107 -    };\r
108 -\r
109 -    /* sadly, there is no standard way to find out to which email\r
110 -     * address a mail was delivered - what is in the headers depends\r
111 -     * on the MTAs used along the way. So we are trying a number of\r
112 -     * heuristics which hopefully will answer this question.\r
113 -\r
114 -     * We only got here if none of the users email addresses are in\r
115 -     * the To: or Cc: header. From here we try the following in order:\r
116 -     * 1) check for an Envelope-to: header\r
117 -     * 2) check for an X-Original-To: header\r
118 -     * 3) check for a Delivered-To: header\r
119 -     * 4) check for a (for <email@add.res>) clause in Received: headers\r
120 -     * 5) check for the domain part of known email addresses in the\r
121 -     *    'by' part of Received headers\r
122 -     * If none of these work, we give up and return NULL\r
123 -     */\r
124 -    for (i = 0; i < ARRAY_SIZE (to_headers); i++) {\r
125 -       const char *tohdr = notmuch_message_get_header (message, to_headers[i]);\r
126 -\r
127 -       /* Note: tohdr potentially contains a list of email addresses. */\r
128 -       addr = user_address_in_string (tohdr, config);\r
129 -       if (addr)\r
130 -           return addr;\r
131 -    }\r
132 +    const char *ptr;\r
133  \r
134 -    /* We get the concatenated Received: headers and search from the\r
135 -     * front (last Received: header added) and try to extract from\r
136 -     * them indications to which email address this message was\r
137 -     * delivered.\r
138 -     * The Received: header is special in our get_header function\r
139 -     * and is always concatenated.\r
140 -     */\r
141 -    received = notmuch_message_get_header (message, "received");\r
142 -    if (received == NULL)\r
143 +    ptr = strstr (received, " for ");\r
144 +    if (! ptr)\r
145         return NULL;\r
146  \r
147 -    /* First we look for a " for <email@add.res>" in the received\r
148 -     * header\r
149 -     */\r
150 -    ptr = strstr (received, " for ");\r
151 +    return user_address_in_string (ptr, config);\r
152 +}\r
153  \r
154 -    /* Note: ptr potentially contains a list of email addresses. */\r
155 -    addr = user_address_in_string (ptr, config);\r
156 -    if (addr)\r
157 -       return addr;\r
158 -\r
159 -    /* Finally, we parse all the " by MTA ..." headers to guess the\r
160 -     * email address that this was originally delivered to.\r
161 -     * We extract just the MTA here by removing leading whitespace and\r
162 -     * assuming that the MTA name ends at the next whitespace.\r
163 -     * We test for *(by+4) to be non-'\0' to make sure there's\r
164 -     * something there at all - and then assume that the first\r
165 -     * whitespace delimited token that follows is the receiving\r
166 -     * system in this step of the receive chain\r
167 -     */\r
168 -    by = received;\r
169 -    while((by = strstr (by, " by ")) != NULL) {\r
170 +/*\r
171 + * Parse all the " by MTA ..." parts in received headers to guess the\r
172 + * email address that this was originally delivered to.\r
173 + *\r
174 + * Extract just the MTA here by removing leading whitespace and\r
175 + * assuming that the MTA name ends at the next whitespace. Test for\r
176 + * *(by+4) to be non-'\0' to make sure there's something there at all\r
177 + * - and then assume that the first whitespace delimited token that\r
178 + * follows is the receiving system in this step of the receive chain.\r
179 + *\r
180 + * Return the address that was found, if any, and NULL otherwise.\r
181 + */\r
182 +static const char *\r
183 +guess_from_in_received_by (notmuch_config_t *config, const char *received)\r
184 +{\r
185 +    const char *addr;\r
186 +    const char *by = received;\r
187 +    char *domain, *tld, *mta, *ptr, *token;\r
188 +\r
189 +    while ((by = strstr (by, " by ")) != NULL) {\r
190         by += 4;\r
191         if (*by == '\0')\r
192             break;\r
193 @@ -450,11 +416,12 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message\r
194             free (mta);\r
195             break;\r
196         }\r
197 -       /* Now extract the last two components of the MTA host name\r
198 -        * as domain and tld.\r
199 +       /*\r
200 +        * Now extract the last two components of the MTA host name as\r
201 +        * domain and tld.\r
202          */\r
203         domain = tld = NULL;\r
204 -       while ((ptr = strsep (&token, delim)) != NULL) {\r
205 +       while ((ptr = strsep (&token, ". \t")) != NULL) {\r
206             if (*ptr == '\0')\r
207                 continue;\r
208             domain = tld;\r
209 @@ -462,13 +429,14 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message\r
210         }\r
211  \r
212         if (domain) {\r
213 -           /* Recombine domain and tld and look for it among the configured\r
214 -            * email addresses.\r
215 -            * This time we have a known domain name and nothing else - so\r
216 -            * the test is the other way around: we check if this is a\r
217 -            * substring of one of the email addresses.\r
218 +           /*\r
219 +            * Recombine domain and tld and look for it among the\r
220 +            * configured email addresses. This time we have a known\r
221 +            * domain name and nothing else - so the test is the other\r
222 +            * way around: we check if this is a substring of one of\r
223 +            * the email addresses.\r
224              */\r
225 -           *(tld-1) = '.';\r
226 +           *(tld - 1) = '.';\r
227  \r
228             addr = string_in_user_address (domain, config);\r
229             if (addr) {\r
230 @@ -482,6 +450,63 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message\r
231      return NULL;\r
232  }\r
233  \r
234 +/*\r
235 + * Get the concatenated Received: headers and search from the front\r
236 + * (last Received: header added) and try to extract from them\r
237 + * indications to which email address this message was delivered.\r
238 + *\r
239 + * The Received: header is special in our get_header function and is\r
240 + * always concatenated.\r
241 + *\r
242 + * Return the address that was found, if any, and NULL otherwise.\r
243 + */\r
244 +static const char *\r
245 +guess_from_in_received_headers (notmuch_config_t *config,\r
246 +                               notmuch_message_t *message)\r
247 +{\r
248 +    const char *received, *addr;\r
249 +\r
250 +    received = notmuch_message_get_header (message, "received");\r
251 +    if (! received)\r
252 +       return NULL;\r
253 +\r
254 +    addr = guess_from_in_received_for (config, received);\r
255 +    if (! addr)\r
256 +       addr = guess_from_in_received_by (config, received);\r
257 +\r
258 +    return addr;\r
259 +}\r
260 +\r
261 +/*\r
262 + * Try to find user's email address in one of the extra To-like\r
263 + * headers: Envelope-To, X-Original-To, and Delivered-To (searched in\r
264 + * that order).\r
265 + *\r
266 + * Return the address that was found, if any, and NULL otherwise.\r
267 + */\r
268 +static const char *\r
269 +get_from_in_to_headers (notmuch_config_t *config, notmuch_message_t *message)\r
270 +{\r
271 +    size_t i;\r
272 +    const char *tohdr, *addr;\r
273 +    const char *to_headers[] = {\r
274 +       "Envelope-to",\r
275 +       "X-Original-To",\r
276 +       "Delivered-To",\r
277 +    };\r
278 +\r
279 +    for (i = 0; i < ARRAY_SIZE (to_headers); i++) {\r
280 +       tohdr = notmuch_message_get_header (message, to_headers[i]);\r
281 +\r
282 +       /* Note: tohdr potentially contains a list of email addresses. */\r
283 +       addr = user_address_in_string (tohdr, config);\r
284 +       if (addr)\r
285 +           return addr;\r
286 +    }\r
287 +\r
288 +    return NULL;\r
289 +}\r
290 +\r
291  static GMimeMessage *\r
292  create_reply_message(void *ctx,\r
293                      notmuch_config_t *config,\r
294 @@ -508,9 +533,30 @@ create_reply_message(void *ctx,\r
295      from_addr = add_recipients_from_message (reply, config,\r
296                                              message, reply_all);\r
297  \r
298 +    /*\r
299 +     * Sadly, there is no standard way to find out to which email\r
300 +     * address a mail was delivered - what is in the headers depends\r
301 +     * on the MTAs used along the way.\r
302 +     *\r
303 +     * If none of the user's email addresses are in the To: or Cc:\r
304 +     * headers, we try a number of heuristics which hopefully will\r
305 +     * answer this question.\r
306 +     *\r
307 +     * First, check for Envelope-To:, X-Original-To:, and\r
308 +     * Delivered-To: headers.\r
309 +     */\r
310 +    if (from_addr == NULL)\r
311 +       from_addr = get_from_in_to_headers (config, message);\r
312 +\r
313 +    /*\r
314 +     * Check for a (for <email@add.res>) clause in Received: headers,\r
315 +     * and the domain part of known email addresses in the 'by' part\r
316 +     * of Received: headers\r
317 +     */\r
318      if (from_addr == NULL)\r
319 -       from_addr = guess_from_received_header (config, message);\r
320 +       from_addr = guess_from_in_received_headers (config, message);\r
321  \r
322 +    /* Default to user's primary address. */\r
323      if (from_addr == NULL)\r
324         from_addr = notmuch_config_get_user_primary_email (config);\r
325  \r
326 -- \r
327 1.8.5.2\r
328 \r