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
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
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
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
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
68 Signed-off-by: Dirk Hohndel <hohndel@infradead.org>
\r
70 notmuch-reply.c | 125 +++++++++++++++++++++++++++++++++++++++++-------------
\r
71 1 files changed, 95 insertions(+), 30 deletions(-)
\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
79 guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message)
\r
81 - const char *received,*primary;
\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
89 const char *delim=". \t";
\r
92 + const char *to_headers[] = {"Envelope-to", "X-Original-To"};
\r
94 + primary = notmuch_config_get_user_primary_email (config);
\r
95 + other = notmuch_config_get_user_other_email (config, &other_len);
\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
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
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
117 + if (strcasestr(tohdr, primary)) {
\r
121 + for (i = 0; i < other_len; i++)
\r
122 + if (strcasestr (tohdr, other[i])) {
\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
134 + * The Received: header is special in our get_header function
\r
135 + * and is always concated.
\r
137 received = notmuch_message_get_header (message, "received");
\r
138 if (received == NULL)
\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
153 + ptr = strstr (received, " for ");
\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
159 - mta = strdup (by+4);
\r
162 + if (strcasestr(ptr, primary)) {
\r
165 + for (i = 0; i < other_len; i++)
\r
166 + if (strcasestr (ptr, other[i])) {
\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
180 + while((by = strstr (by, " by ")) != NULL) {
\r
184 + mta = xstrdup (by);
\r
185 token = strtok(mta," \t");
\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
193 while ((ptr = strsep (&token, delim)) != NULL) {
\r
195 @@ -350,23 +414,24 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message
\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
208 - primary = notmuch_config_get_user_primary_email (config);
\r
209 - if (strcasestr (primary, domain)) {
\r
213 + if (strcasestr(primary, domain)) {
\r
217 + for (i = 0; i < other_len; i++)
\r
218 + if (strcasestr (other[i],domain)) {
\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