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 9FFA5431FC1
\r
6 for <notmuch@notmuchmail.org>; Fri, 16 Apr 2010 13:52:02 -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 WemCDZ5ZSTyw for <notmuch@notmuchmail.org>;
\r
16 Fri, 16 Apr 2010 13:52:00 -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 501724196F4
\r
19 for <notmuch@notmuchmail.org>; Fri, 16 Apr 2010 13:51:57 -0700 (PDT)
\r
20 Received: by mail.hohndel.org (Postfix, from userid 112)
\r
21 id 0DAC0340FC; Fri, 16 Apr 2010 16:51:57 -0400 (EDT)
\r
22 Received: from x200.gr8dns.org (unknown [65.23.157.147])
\r
23 by mail.hohndel.org (Postfix) with ESMTP id 1E634340FA;
\r
24 Fri, 16 Apr 2010 16:51:53 -0400 (EDT)
\r
25 Received: by x200.gr8dns.org (Postfix, from userid 500)
\r
26 id B8CD3C0162; Fri, 16 Apr 2010 13:51:52 -0700 (PDT)
\r
27 From: Dirk Hohndel <hohndel@infradead.org>
\r
28 To: <notmuch@notmuchmail.org>
\r
29 Subject: [PATCH 1/2] Add interface to obtain the concatenation of all
\r
30 instances of a specified header
\r
31 Date: Fri, 16 Apr 2010 13:51:41 -0700
\r
32 Message-Id: <1271451102-11336-2-git-send-email-hohndel@infradead.org>
\r
33 X-Mailer: git-send-email 1.6.6.1
\r
34 In-Reply-To: <1271451102-11336-1-git-send-email-hohndel@infradead.org>
\r
35 References: <1271451102-11336-1-git-send-email-hohndel@infradead.org>
\r
36 X-BeenThere: notmuch@notmuchmail.org
\r
37 X-Mailman-Version: 2.1.13
\r
39 List-Id: "Use and development of the notmuch mail system."
\r
40 <notmuch.notmuchmail.org>
\r
41 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
\r
42 <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
\r
43 List-Archive: <http://notmuchmail.org/pipermail/notmuch>
\r
44 List-Post: <mailto:notmuch@notmuchmail.org>
\r
45 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
\r
46 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
\r
47 <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
\r
48 X-List-Received-Date: Fri, 16 Apr 2010 20:52:02 -0000
\r
50 notmuch_message_get_header only returns the first instance of the specified
\r
51 header in a message.
\r
52 notmuch_message_get_concat_header concatenates the values from ALL instances
\r
53 of that header in a message. This is useful for example to get the full
\r
54 delivery path as captured in all of the Received: headers.
\r
56 Signed-off-by: Dirk Hohndel <hohndel@infradead.org>
\r
58 lib/database.cc | 14 +++++++-------
\r
59 lib/message-file.c | 49 +++++++++++++++++++++++++++++++++++--------------
\r
60 lib/message.cc | 12 +++++++++++-
\r
61 lib/notmuch-private.h | 2 +-
\r
62 lib/notmuch.h | 16 ++++++++++++++++
\r
63 5 files changed, 70 insertions(+), 23 deletions(-)
\r
65 diff --git a/lib/database.cc b/lib/database.cc
\r
66 index 6842faf..d706263 100644
\r
67 --- a/lib/database.cc
\r
68 +++ b/lib/database.cc
\r
69 @@ -1289,11 +1289,11 @@ _notmuch_database_link_message_to_parents (notmuch_database_t *notmuch,
\r
70 parents = g_hash_table_new_full (g_str_hash, g_str_equal,
\r
71 _my_talloc_free_for_g_hash, NULL);
\r
73 - refs = notmuch_message_file_get_header (message_file, "references");
\r
74 + refs = notmuch_message_file_get_header (message_file, "references", 0);
\r
75 parse_references (message, notmuch_message_get_message_id (message),
\r
78 - in_reply_to = notmuch_message_file_get_header (message_file, "in-reply-to");
\r
79 + in_reply_to = notmuch_message_file_get_header (message_file, "in-reply-to", 0);
\r
80 parse_references (message, notmuch_message_get_message_id (message),
\r
81 parents, in_reply_to);
\r
83 @@ -1506,9 +1506,9 @@ notmuch_database_add_message (notmuch_database_t *notmuch,
\r
84 * let's make sure that what we're looking at looks like an
\r
85 * actual email message.
\r
87 - from = notmuch_message_file_get_header (message_file, "from");
\r
88 - subject = notmuch_message_file_get_header (message_file, "subject");
\r
89 - to = notmuch_message_file_get_header (message_file, "to");
\r
90 + from = notmuch_message_file_get_header (message_file, "from", 0);
\r
91 + subject = notmuch_message_file_get_header (message_file, "subject", 0);
\r
92 + to = notmuch_message_file_get_header (message_file, "to", 0);
\r
94 if ((from == NULL || *from == '\0') &&
\r
95 (subject == NULL || *subject == '\0') &&
\r
96 @@ -1521,7 +1521,7 @@ notmuch_database_add_message (notmuch_database_t *notmuch,
\r
97 /* Now that we're sure it's mail, the first order of business
\r
98 * is to find a message ID (or else create one ourselves). */
\r
100 - header = notmuch_message_file_get_header (message_file, "message-id");
\r
101 + header = notmuch_message_file_get_header (message_file, "message-id", 0);
\r
102 if (header && *header != '\0') {
\r
103 message_id = _parse_message_id (message_file, header, NULL);
\r
105 @@ -1580,7 +1580,7 @@ notmuch_database_add_message (notmuch_database_t *notmuch,
\r
109 - date = notmuch_message_file_get_header (message_file, "date");
\r
110 + date = notmuch_message_file_get_header (message_file, "date", 0);
\r
111 _notmuch_message_set_date (message, date);
\r
113 _notmuch_message_index_file (message, filename);
\r
114 diff --git a/lib/message-file.c b/lib/message-file.c
\r
115 index 0c152a3..a01adbb 100644
\r
116 --- a/lib/message-file.c
\r
117 +++ b/lib/message-file.c
\r
118 @@ -209,15 +209,21 @@ copy_header_unfolding (header_value_closure_t *value,
\r
120 /* As a special-case, a value of NULL for header_desired will force
\r
121 * the entire header to be parsed if it is not parsed already. This is
\r
122 - * used by the _notmuch_message_file_get_headers_end function. */
\r
123 + * used by the _notmuch_message_file_get_headers_end function.
\r
124 + * If concat is 'true' then it parses the whole message and
\r
125 + * concatenates all instances of the header in question. This is
\r
126 + * currently used to get a complete Received: header when analyzing
\r
127 + * the path the mail has taken from sender to recipient.
\r
130 notmuch_message_file_get_header (notmuch_message_file_t *message,
\r
131 - const char *header_desired)
\r
132 + const char *header_desired,
\r
136 - char *header, *decoded_value;
\r
137 + char *header, *decoded_value, *header_sofar, *combined_header;
\r
138 const char *s, *colon;
\r
140 + int match, newhdr, hdrsofar;
\r
141 static int initialized = 0;
\r
143 if (! initialized) {
\r
144 @@ -227,7 +233,7 @@ notmuch_message_file_get_header (notmuch_message_file_t *message,
\r
146 message->parsing_started = 1;
\r
148 - if (header_desired == NULL)
\r
149 + if (concat || header_desired == NULL)
\r
152 contains = g_hash_table_lookup_extended (message->headers,
\r
153 @@ -237,6 +243,9 @@ notmuch_message_file_get_header (notmuch_message_file_t *message,
\r
154 if (contains && decoded_value)
\r
155 return decoded_value;
\r
158 + message->parsing_finished = 0;
\r
160 if (message->parsing_finished)
\r
163 @@ -312,20 +321,32 @@ notmuch_message_file_get_header (notmuch_message_file_t *message,
\r
165 NEXT_HEADER_LINE (&message->value);
\r
167 - if (header_desired == 0)
\r
168 + if (concat || header_desired == NULL)
\r
171 match = (strcasecmp (header, header_desired) == 0);
\r
173 decoded_value = g_mime_utils_header_decode_text (message->value.str);
\r
174 - if (g_hash_table_lookup (message->headers, header) == NULL) {
\r
175 - /* Only insert if we don't have a value for this header, yet.
\r
176 - * This way we always return the FIRST instance of any header
\r
178 - * FIXME: we should be returning ALL instances of a header
\r
179 - * or at least provide a way to iterate over them
\r
181 - g_hash_table_insert (message->headers, header, decoded_value);
\r
182 + header_sofar = (char *)g_hash_table_lookup (message->headers, header);
\r
184 + if (header_sofar == NULL) {
\r
185 + /* Only insert if we don't have a value for this header, yet. */
\r
186 + g_hash_table_insert (message->headers, header, decoded_value);
\r
188 + /* the caller wants them all concatenated */
\r
189 + newhdr = strlen(decoded_value);
\r
190 + hdrsofar = strlen(header_sofar);
\r
191 + combined_header = xmalloc(hdrsofar + newhdr + 2);
\r
192 + strncpy(combined_header,header_sofar,hdrsofar);
\r
193 + *(combined_header+hdrsofar) = ' ';
\r
194 + strncpy(combined_header+hdrsofar+1,decoded_value,newhdr+1);
\r
195 + g_hash_table_insert (message->headers, header, combined_header);
\r
198 + if (header_sofar == NULL) {
\r
199 + /* Only insert if we don't have a value for this header, yet. */
\r
200 + g_hash_table_insert (message->headers, header, decoded_value);
\r
204 return decoded_value;
\r
205 diff --git a/lib/message.cc b/lib/message.cc
\r
206 index 721c9a6..fb8fe95 100644
\r
207 --- a/lib/message.cc
\r
208 +++ b/lib/message.cc
\r
209 @@ -264,7 +264,17 @@ notmuch_message_get_header (notmuch_message_t *message, const char *header)
\r
210 if (message->message_file == NULL)
\r
213 - return notmuch_message_file_get_header (message->message_file, header);
\r
214 + return notmuch_message_file_get_header (message->message_file, header, 0);
\r
218 +notmuch_message_get_concat_header (notmuch_message_t *message, const char *header)
\r
220 + _notmuch_message_ensure_message_file (message);
\r
221 + if (message->message_file == NULL)
\r
224 + return notmuch_message_file_get_header (message->message_file, header, 1);
\r
227 /* Return the message ID from the In-Reply-To header of 'message'.
\r
228 diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h
\r
229 index d52d84d..9f8a10a 100644
\r
230 --- a/lib/notmuch-private.h
\r
231 +++ b/lib/notmuch-private.h
\r
232 @@ -342,7 +342,7 @@ notmuch_message_file_restrict_headersv (notmuch_message_file_t *message,
\r
235 notmuch_message_file_get_header (notmuch_message_file_t *message,
\r
236 - const char *header);
\r
237 + const char *header, int concat);
\r
241 diff --git a/lib/notmuch.h b/lib/notmuch.h
\r
242 index a7e66dd..d77eb5c 100644
\r
243 --- a/lib/notmuch.h
\r
244 +++ b/lib/notmuch.h
\r
245 @@ -787,6 +787,22 @@ notmuch_message_get_date (notmuch_message_t *message);
\r
247 notmuch_message_get_header (notmuch_message_t *message, const char *header);
\r
249 +/* Get the concatenated value of all instances of the specified header
\r
250 + * from 'message'.
\r
252 + * The value will be read from the actual message file, not from the
\r
253 + * notmuch database. The header name is case insensitive.
\r
255 + * The returned string belongs to the message so should not be
\r
256 + * modified or freed by the caller (nor should it be referenced after
\r
257 + * the message is destroyed).
\r
259 + * Returns an empty string ("") if the message does not contain a
\r
260 + * header line matching 'header'. Returns NULL if any error occurs.
\r
263 +notmuch_message_get_concat_header (notmuch_message_t *message, const char *header);
\r
265 /* Get the tags for 'message', returning a notmuch_tags_t object which
\r
266 * can be used to iterate over all tags.
\r