mutt stable branch with some hacks
at jcs 349 lines 8.1 kB view raw
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}