mutt stable branch with some hacks
1/*
2 * Copyright (C) 1996-2009,2012 Michael R. Elkins <me@mutt.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19#if HAVE_CONFIG_H
20# include "config.h"
21#endif
22
23#include "mutt.h"
24#include "mutt_crypt.h"
25#include "mutt_idna.h"
26
27#include <sys/stat.h>
28#include <string.h>
29#include <ctype.h>
30#include <stdint.h>
31
32void mutt_edit_headers (const char *editor,
33 const char *body,
34 HEADER *msg,
35 BUFFER *fcc)
36{
37 BUFFER *path = NULL; /* tempfile used to edit headers + body */
38 char buffer[LONG_STRING];
39 const char *p;
40 FILE *ifp, *ofp;
41 int i, keep;
42 ENVELOPE *n;
43 time_t mtime;
44 struct stat st;
45 LIST *cur, **last = NULL, *tmp;
46
47 path = mutt_buffer_pool_get ();
48 mutt_buffer_mktemp (path);
49 if ((ofp = safe_fopen (mutt_b2s (path), "w")) == NULL)
50 {
51 mutt_perror (mutt_b2s (path));
52 goto cleanup;
53 }
54
55 mutt_env_to_local (msg->env);
56 mutt_write_rfc822_header (ofp, msg->env, NULL, MUTT_WRITE_HEADER_EDITHDRS, 0, 0);
57 fputc ('\n', ofp); /* tie off the header. */
58
59 /* now copy the body of the message. */
60 if ((ifp = fopen (body, "r")) == NULL)
61 {
62 mutt_perror (body);
63 goto cleanup;
64 }
65
66 mutt_copy_stream (ifp, ofp);
67
68 safe_fclose (&ifp);
69 safe_fclose (&ofp);
70
71 if (stat (mutt_b2s (path), &st) == -1)
72 {
73 mutt_perror (mutt_b2s (path));
74 goto cleanup;
75 }
76
77 mtime = mutt_decrease_mtime (mutt_b2s (path), &st);
78
79 mutt_edit_file (editor, mutt_b2s (path));
80 stat (mutt_b2s (path), &st);
81 if (mtime == st.st_mtime)
82 {
83 dprint (1, (debugfile, "ci_edit_headers(): temp file was not modified.\n"));
84 /* the file has not changed! */
85 mutt_unlink (mutt_b2s (path));
86 goto cleanup;
87 }
88
89 mutt_unlink (body);
90 mutt_free_list (&msg->env->userhdrs);
91
92 /* Read the temp file back in */
93 if ((ifp = fopen (mutt_b2s (path), "r")) == NULL)
94 {
95 mutt_perror (mutt_b2s (path));
96 goto cleanup;
97 }
98
99 if ((ofp = safe_fopen (body, "w")) == NULL)
100 {
101 /* intentionally leak a possible temporary file here */
102 safe_fclose (&ifp);
103 mutt_perror (body);
104 goto cleanup;
105 }
106
107 n = mutt_read_rfc822_header (ifp, NULL, 1, 0);
108 while ((i = fread (buffer, 1, sizeof (buffer), ifp)) > 0)
109 fwrite (buffer, 1, i, ofp);
110 safe_fclose (&ofp);
111 safe_fclose (&ifp);
112 mutt_unlink (mutt_b2s (path));
113
114 /* in case the user modifies/removes the In-Reply-To header with
115 $edit_headers set, we remove References: as they're likely invalid;
116 we can simply compare strings as we don't generate References for
117 multiple Message-Ids in IRT anyways */
118 if (msg->env->in_reply_to &&
119 (!n->in_reply_to || mutt_strcmp (n->in_reply_to->data,
120 msg->env->in_reply_to->data) != 0))
121 mutt_free_list (&msg->env->references);
122
123 /* restore old info. */
124 mutt_free_list (&n->references);
125 n->references = msg->env->references;
126 msg->env->references = NULL;
127
128 mutt_free_envelope (&msg->env);
129 msg->env = n; n = NULL;
130
131 mutt_expand_aliases_env (msg->env);
132
133 /* search through the user defined headers added to see if
134 * fcc: or attach: or pgp: was specified
135 */
136
137 cur = msg->env->userhdrs;
138 last = &msg->env->userhdrs;
139 while (cur)
140 {
141 keep = 1;
142
143 if (fcc && ascii_strncasecmp ("fcc:", cur->data, 4) == 0)
144 {
145 p = skip_email_wsp(cur->data + 4);
146 if (*p)
147 {
148 mutt_buffer_strcpy (fcc, p);
149 mutt_buffer_pretty_mailbox (fcc);
150 }
151 keep = 0;
152 }
153 else if (ascii_strncasecmp ("attach:", cur->data, 7) == 0)
154 {
155 BODY *body;
156 BODY *parts;
157
158 p = skip_email_wsp(cur->data + 7);
159 if (*p)
160 {
161 mutt_buffer_clear (path);
162 for ( ; *p && *p != ' ' && *p != '\t'; p++)
163 {
164 if (*p == '\\')
165 {
166 if (!*(p+1))
167 break;
168 p++;
169 }
170 mutt_buffer_addch (path, *p);
171 }
172 p = skip_email_wsp(p);
173
174 mutt_buffer_expand_path (path);
175 if ((body = mutt_make_file_attach (mutt_b2s (path))))
176 {
177 body->description = safe_strdup (p);
178 for (parts = msg->content; parts->next; parts = parts->next) ;
179 parts->next = body;
180 }
181 else
182 {
183 mutt_buffer_pretty_mailbox (path);
184 mutt_error (_("%s: unable to attach file"), mutt_b2s (path));
185 }
186 }
187 keep = 0;
188 }
189 else if ((WithCrypto & APPLICATION_PGP)
190 && ascii_strncasecmp ("pgp:", cur->data, 4) == 0)
191 {
192 msg->security = mutt_parse_crypt_hdr (cur->data + 4, 0, APPLICATION_PGP);
193 if (msg->security)
194 msg->security |= APPLICATION_PGP;
195 keep = 0;
196 }
197
198 if (keep)
199 {
200 last = &cur->next;
201 cur = cur->next;
202 }
203 else
204 {
205 tmp = cur;
206 *last = cur->next;
207 cur = cur->next;
208 tmp->next = NULL;
209 mutt_free_list (&tmp);
210 }
211 }
212
213cleanup:
214 mutt_buffer_pool_release (&path);
215}
216
217static void label_ref_dec(CONTEXT *ctx, char *label)
218{
219 struct hash_elem *elem;
220 uintptr_t count;
221
222 elem = hash_find_elem (ctx->label_hash, label);
223 if (!elem)
224 return;
225
226 count = (uintptr_t)elem->data;
227 if (count <= 1)
228 {
229 hash_delete(ctx->label_hash, label, NULL, NULL);
230 return;
231 }
232
233 count--;
234 elem->data = (void *)count;
235}
236
237static void label_ref_inc(CONTEXT *ctx, char *label)
238{
239 struct hash_elem *elem;
240 uintptr_t count;
241
242 elem = hash_find_elem (ctx->label_hash, label);
243 if (!elem)
244 {
245 count = 1;
246 hash_insert(ctx->label_hash, label, (void *)count);
247 return;
248 }
249
250 count = (uintptr_t)elem->data;
251 count++;
252 elem->data = (void *)count;
253}
254
255/*
256 * add an X-Label: field.
257 */
258static int label_message(CONTEXT *ctx, HEADER *hdr, char *new)
259{
260 if (hdr == NULL)
261 return 0;
262 if (mutt_strcmp (hdr->env->x_label, new) == 0)
263 return 0;
264
265 if (hdr->env->x_label != NULL)
266 label_ref_dec(ctx, hdr->env->x_label);
267 mutt_str_replace (&hdr->env->x_label, new);
268 if (hdr->env->x_label != NULL)
269 label_ref_inc(ctx, hdr->env->x_label);
270
271 hdr->changed = 1;
272 hdr->env->changed |= MUTT_ENV_CHANGED_XLABEL;
273 return 1;
274}
275
276int mutt_label_message(HEADER *hdr)
277{
278 char buf[LONG_STRING], *new;
279 int i;
280 int changed;
281
282 if (!Context || !Context->label_hash)
283 return 0;
284
285 *buf = '\0';
286 if (hdr != NULL && hdr->env->x_label != NULL)
287 {
288 strncpy(buf, hdr->env->x_label, LONG_STRING);
289 }
290
291 if (mutt_get_field("Label: ", buf, sizeof(buf), MUTT_LABEL /* | MUTT_CLEAR */) != 0)
292 return 0;
293
294 new = buf;
295 SKIPWS(new);
296 if (*new == '\0')
297 new = NULL;
298
299 changed = 0;
300 if (hdr != NULL)
301 {
302 if (label_message(Context, hdr, new))
303 {
304 ++changed;
305 mutt_set_header_color (Context, hdr);
306 }
307 }
308 else
309 {
310#define HDR_OF(index) Context->hdrs[Context->v2r[(index)]]
311 for (i = 0; i < Context->vcount; ++i)
312 {
313 if (HDR_OF(i)->tagged)
314 if (label_message(Context, HDR_OF(i), new))
315 {
316 ++changed;
317 mutt_set_flag(Context, HDR_OF(i),
318 MUTT_TAG, 0);
319 /* mutt_set_flag re-evals the header color */
320 }
321 }
322 }
323
324 return changed;
325}
326
327void mutt_make_label_hash (CONTEXT *ctx)
328{
329 /* 131 is just a rough prime estimate of how many distinct
330 * labels someone might have in a mailbox.
331 */
332 ctx->label_hash = hash_create(131, MUTT_HASH_STRDUP_KEYS);
333}
334
335void mutt_label_hash_add (CONTEXT *ctx, HEADER *hdr)
336{
337 if (!ctx || !ctx->label_hash)
338 return;
339 if (hdr->env->x_label)
340 label_ref_inc (ctx, hdr->env->x_label);
341}
342
343void mutt_label_hash_remove (CONTEXT *ctx, HEADER *hdr)
344{
345 if (!ctx || !ctx->label_hash)
346 return;
347 if (hdr->env->x_label)
348 label_ref_dec (ctx, hdr->env->x_label);
349}