mutt stable branch with some hacks
at jcs 2339 lines 62 kB view raw
1/* 2 * Copyright (C) 1996-2002,2004,2010,2012-2013 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_curses.h" 25#include "rfc2047.h" 26#include "keymap.h" 27#include "mime.h" 28#include "mailbox.h" 29#include "copy.h" 30#include "mutt_crypt.h" 31#include "mutt_idna.h" 32#include "url.h" 33#include "rfc3676.h" 34#include "attach.h" 35 36#ifdef USE_AUTOCRYPT 37#include "autocrypt.h" 38#endif 39 40#include <ctype.h> 41#include <stdlib.h> 42#include <locale.h> 43#include <unistd.h> 44#include <string.h> 45#include <errno.h> 46#include <sys/stat.h> 47#include <sys/wait.h> 48#include <dirent.h> 49#include <time.h> 50#include <sys/types.h> 51#include <utime.h> 52 53#ifdef MIXMASTER 54#include "remailer.h" 55#endif 56 57 58static void append_signature (FILE *f) 59{ 60 FILE *tmpfp; 61 pid_t thepid; 62 63 if (Signature && (tmpfp = mutt_open_read (Signature, &thepid))) 64 { 65 if (option (OPTSIGDASHES)) 66 fputs ("\n-- \n", f); 67 mutt_copy_stream (tmpfp, f); 68 safe_fclose (&tmpfp); 69 if (thepid != -1) 70 mutt_wait_filter (thepid); 71 } 72} 73 74/* compare two e-mail addresses and return 1 if they are equivalent */ 75static int mutt_addrcmp (ADDRESS *a, ADDRESS *b) 76{ 77 if (!a || !b) 78 return 0; 79 if (!a->mailbox || !b->mailbox) 80 return 0; 81 if (ascii_strcasecmp (a->mailbox, b->mailbox)) 82 return 0; 83 return 1; 84} 85 86/* search an e-mail address in a list */ 87static int mutt_addrsrc (ADDRESS *a, ADDRESS *lst) 88{ 89 for (; lst; lst = lst->next) 90 { 91 if (mutt_addrcmp (a, lst)) 92 return (1); 93 } 94 return (0); 95} 96 97/* removes addresses from "b" which are contained in "a" */ 98ADDRESS *mutt_remove_xrefs (ADDRESS *a, ADDRESS *b) 99{ 100 ADDRESS *top, *p, *prev = NULL; 101 102 top = b; 103 while (b) 104 { 105 for (p = a; p; p = p->next) 106 { 107 if (mutt_addrcmp (p, b)) 108 break; 109 } 110 if (p) 111 { 112 if (prev) 113 { 114 prev->next = b->next; 115 b->next = NULL; 116 rfc822_free_address (&b); 117 b = prev; 118 } 119 else 120 { 121 top = top->next; 122 b->next = NULL; 123 rfc822_free_address (&b); 124 b = top; 125 } 126 } 127 else 128 { 129 prev = b; 130 b = b->next; 131 } 132 } 133 return top; 134} 135 136/* remove any address which matches the current user. if `leave_only' is 137 * nonzero, don't remove the user's address if it is the only one in the list 138 */ 139static ADDRESS *remove_user (ADDRESS *a, int leave_only) 140{ 141 ADDRESS *top = NULL, *last = NULL; 142 143 while (a) 144 { 145 if (!mutt_addr_is_user (a)) 146 { 147 if (top) 148 { 149 last->next = a; 150 last = last->next; 151 } 152 else 153 last = top = a; 154 a = a->next; 155 last->next = NULL; 156 } 157 else 158 { 159 ADDRESS *tmp = a; 160 161 a = a->next; 162 if (!leave_only || a || last) 163 { 164 tmp->next = NULL; 165 rfc822_free_address (&tmp); 166 } 167 else 168 last = top = tmp; 169 } 170 } 171 return top; 172} 173 174static ADDRESS *find_mailing_lists (ADDRESS *t, ADDRESS *c) 175{ 176 ADDRESS *top = NULL, *ptr = NULL; 177 178 for (; t || c; t = c, c = NULL) 179 { 180 for (; t; t = t->next) 181 { 182 if (mutt_is_mail_list (t) && !t->group) 183 { 184 if (top) 185 { 186 ptr->next = rfc822_cpy_adr_real (t); 187 ptr = ptr->next; 188 } 189 else 190 ptr = top = rfc822_cpy_adr_real (t); 191 } 192 } 193 } 194 return top; 195} 196 197int mutt_edit_address (ADDRESS **a, const char *field, int expand_aliases) 198{ 199 char buf[HUGE_STRING]; 200 char *err = NULL; 201 int idna_ok = 0; 202 203 do 204 { 205 buf[0] = 0; 206 mutt_addrlist_to_local (*a); 207 rfc822_write_address (buf, sizeof (buf), *a, 0); 208 if (mutt_get_field (field, buf, sizeof (buf), MUTT_ALIAS) != 0) 209 return (-1); 210 rfc822_free_address (a); 211 *a = mutt_parse_adrlist (NULL, buf); 212 if (expand_aliases) 213 *a = mutt_expand_aliases (*a); 214 if ((idna_ok = mutt_addrlist_to_intl (*a, &err)) != 0) 215 { 216 mutt_error (_("Error: '%s' is a bad IDN."), err); 217 mutt_refresh (); 218 mutt_sleep (2); 219 FREE (&err); 220 } 221 } 222 while (idna_ok != 0); 223 return 0; 224} 225 226static int edit_envelope (ENVELOPE *en) 227{ 228 char buf[HUGE_STRING]; 229 LIST *uh = UserHeader; 230 231 if (mutt_edit_address (&en->to, _("To: "), 1) == -1 || en->to == NULL) 232 return (-1); 233 if (option (OPTASKCC) && mutt_edit_address (&en->cc, _("Cc: "), 1) == -1) 234 return (-1); 235 if (option (OPTASKBCC) && mutt_edit_address (&en->bcc, _("Bcc: "), 1) == -1) 236 return (-1); 237 238 if (en->subject) 239 { 240 if (option (OPTFASTREPLY)) 241 return (0); 242 else 243 strfcpy (buf, en->subject, sizeof (buf)); 244 } 245 else 246 { 247 const char *p; 248 249 buf[0] = 0; 250 for (; uh; uh = uh->next) 251 { 252 if (ascii_strncasecmp ("subject:", uh->data, 8) == 0) 253 { 254 p = skip_email_wsp(uh->data + 8); 255 strncpy (buf, p, sizeof (buf)); 256 } 257 } 258 } 259 260 if (mutt_get_field (_("Subject: "), buf, sizeof (buf), 0) != 0 || 261 (!buf[0] && query_quadoption (OPT_SUBJECT, _("No subject, abort?")) != MUTT_NO)) 262 { 263 mutt_message _("No subject, aborting."); 264 return (-1); 265 } 266 mutt_str_replace (&en->subject, buf); 267 268 return 0; 269} 270 271static void process_user_recips (ENVELOPE *env) 272{ 273 LIST *uh = UserHeader; 274 275 for (; uh; uh = uh->next) 276 { 277 if (ascii_strncasecmp ("to:", uh->data, 3) == 0) 278 env->to = rfc822_parse_adrlist (env->to, uh->data + 3); 279 else if (ascii_strncasecmp ("cc:", uh->data, 3) == 0) 280 env->cc = rfc822_parse_adrlist (env->cc, uh->data + 3); 281 else if (ascii_strncasecmp ("bcc:", uh->data, 4) == 0) 282 env->bcc = rfc822_parse_adrlist (env->bcc, uh->data + 4); 283 } 284} 285 286static void process_user_header (ENVELOPE *env) 287{ 288 LIST *uh = UserHeader; 289 LIST *last = env->userhdrs; 290 291 if (last) 292 while (last->next) 293 last = last->next; 294 295 for (; uh; uh = uh->next) 296 { 297 if (ascii_strncasecmp ("from:", uh->data, 5) == 0) 298 { 299 /* User has specified a default From: address. Remove default address */ 300 rfc822_free_address (&env->from); 301 env->from = rfc822_parse_adrlist (env->from, uh->data + 5); 302 } 303 else if (ascii_strncasecmp ("reply-to:", uh->data, 9) == 0) 304 { 305 rfc822_free_address (&env->reply_to); 306 env->reply_to = rfc822_parse_adrlist (env->reply_to, uh->data + 9); 307 } 308 else if (ascii_strncasecmp ("message-id:", uh->data, 11) == 0) 309 { 310 char *tmp = mutt_extract_message_id (uh->data + 11, NULL); 311 if (rfc822_valid_msgid (tmp) >= 0) 312 { 313 FREE(&env->message_id); 314 env->message_id = tmp; 315 } 316 else 317 FREE(&tmp); 318 } 319 else if (ascii_strncasecmp ("to:", uh->data, 3) != 0 && 320 ascii_strncasecmp ("cc:", uh->data, 3) != 0 && 321 ascii_strncasecmp ("bcc:", uh->data, 4) != 0 && 322 ascii_strncasecmp ("subject:", uh->data, 8) != 0 && 323 ascii_strncasecmp ("return-path:", uh->data, 12) != 0) 324 { 325 if (last) 326 { 327 last->next = mutt_new_list (); 328 last = last->next; 329 } 330 else 331 last = env->userhdrs = mutt_new_list (); 332 last->data = safe_strdup (uh->data); 333 } 334 } 335} 336 337void mutt_forward_intro (CONTEXT *ctx, HEADER *cur, FILE *fp) 338{ 339 char buffer[LONG_STRING]; 340 341 if (ForwardAttrIntro) 342 { 343 setlocale (LC_TIME, NONULL (AttributionLocale)); 344 mutt_make_string (buffer, sizeof (buffer), ForwardAttrIntro, ctx, cur); 345 setlocale (LC_TIME, ""); 346 fputs (buffer, fp); 347 fputs ("\n\n", fp); 348 } 349} 350 351void mutt_forward_trailer (CONTEXT *ctx, HEADER *cur, FILE *fp) 352{ 353 char buffer[LONG_STRING]; 354 355 if (ForwardAttrTrailer) 356 { 357 setlocale (LC_TIME, NONULL (AttributionLocale)); 358 mutt_make_string (buffer, sizeof (buffer), ForwardAttrTrailer, ctx, cur); 359 setlocale (LC_TIME, ""); 360 fputc ('\n', fp); 361 fputs (buffer, fp); 362 fputc ('\n', fp); 363 } 364} 365 366 367static int include_forward (CONTEXT *ctx, HEADER *cur, FILE *out) 368{ 369 int chflags = CH_DECODE, cmflags = 0; 370 371 mutt_parse_mime_message (ctx, cur); 372 mutt_message_hook (ctx, cur, MUTT_MESSAGEHOOK); 373 374 if (WithCrypto && (cur->security & ENCRYPT) && option (OPTFORWDECODE)) 375 { 376 /* make sure we have the user's passphrase before proceeding... */ 377 crypt_valid_passphrase (cur->security); 378 } 379 380 mutt_forward_intro (ctx, cur, out); 381 382 if (option (OPTFORWDECODE)) 383 { 384 cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV; 385 if (option (OPTWEED)) 386 { 387 chflags |= CH_WEED | CH_REORDER; 388 cmflags |= MUTT_CM_WEED; 389 } 390 } 391 if (option (OPTFORWQUOTE)) 392 cmflags |= MUTT_CM_PREFIX; 393 394 /* wrapping headers for forwarding is considered a display 395 * rather than send action */ 396 chflags |= CH_DISPLAY; 397 398 mutt_copy_message (out, ctx, cur, cmflags, chflags); 399 mutt_forward_trailer (ctx, cur, out); 400 return 0; 401} 402 403static int inline_forward_attachments (CONTEXT *ctx, HEADER *cur, 404 BODY ***plast, int *forwardq) 405{ 406 BODY **last = *plast, *body; 407 MESSAGE *msg = NULL; 408 ATTACH_CONTEXT *actx = NULL; 409 int rc = 0, i; 410 411 mutt_parse_mime_message (ctx, cur); 412 mutt_message_hook (ctx, cur, MUTT_MESSAGEHOOK); 413 414 if ((msg = mx_open_message (ctx, cur->msgno)) == NULL) 415 return -1; 416 417 actx = safe_calloc (sizeof(ATTACH_CONTEXT), 1); 418 actx->hdr = cur; 419 actx->root_fp = msg->fp; 420 421 mutt_generate_recvattach_list (actx, actx->hdr, actx->hdr->content, 422 actx->root_fp, -1, 0, 0); 423 424 for (i = 0; i < actx->idxlen; i++) 425 { 426 body = actx->idx[i]->content; 427 if ((body->type != TYPEMULTIPART) && 428 (!mutt_can_decode (body) || 429 (option (OPTHONORDISP) && body->disposition == DISPATTACH)) && 430 !(body->type == TYPEAPPLICATION && 431 (!ascii_strcasecmp (body->subtype, "pgp-signature") || 432 !ascii_strcasecmp (body->subtype, "x-pkcs7-signature") || 433 !ascii_strcasecmp (body->subtype, "pkcs7-signature")))) 434 { 435 /* Ask the quadoption only once */ 436 if (*forwardq == -1) 437 { 438 *forwardq = query_quadoption (OPT_FORWATTS, 439 /* L10N: 440 This is the prompt for $forward_attachments. 441 When inline forwarding ($mime_forward answered "no"), this prompts 442 whether to add non-decodable attachments from the original email. 443 Text/plain parts and the like will already be included in the 444 message contents, but other attachment, such as PDF files, will also 445 be added as attachments to the new mail, if this is answered yes. 446 */ 447 _("Forward attachments?")); 448 if (*forwardq != MUTT_YES) 449 { 450 if (*forwardq == -1) 451 rc = -1; 452 goto cleanup; 453 } 454 } 455 if (mutt_copy_body (actx->idx[i]->fp, last, body) == -1) 456 { 457 rc = -1; 458 goto cleanup; 459 } 460 last = &((*last)->next); 461 } 462 } 463 464cleanup: 465 *plast = last; 466 mx_close_message (ctx, &msg); 467 mutt_free_attach_context (&actx); 468 return rc; 469} 470 471int mutt_inline_forward (CONTEXT *ctx, HEADER *msg, HEADER *cur, FILE *out) 472{ 473 int i, forwardq = -1; 474 BODY **last; 475 476 if (cur) 477 include_forward (ctx, cur, out); 478 else 479 for (i = 0; i < ctx->vcount; i++) 480 if (ctx->hdrs[ctx->v2r[i]]->tagged) 481 include_forward (ctx, ctx->hdrs[ctx->v2r[i]], out); 482 483 if (option (OPTFORWDECODE) && (quadoption (OPT_FORWATTS) != MUTT_NO)) 484 { 485 last = &msg->content; 486 while (*last) 487 last = &((*last)->next); 488 489 if (cur) 490 { 491 if (inline_forward_attachments (ctx, cur, &last, &forwardq) != 0) 492 return -1; 493 } 494 else 495 for (i = 0; i < ctx->vcount; i++) 496 if (ctx->hdrs[ctx->v2r[i]]->tagged) 497 { 498 if (inline_forward_attachments (ctx, ctx->hdrs[ctx->v2r[i]], 499 &last, &forwardq) != 0) 500 return -1; 501 if (forwardq == MUTT_NO) 502 break; 503 } 504 } 505 506 return 0; 507} 508 509 510void mutt_make_attribution (CONTEXT *ctx, HEADER *cur, FILE *out) 511{ 512 char buffer[LONG_STRING]; 513 if (Attribution) 514 { 515 setlocale (LC_TIME, NONULL (AttributionLocale)); 516 mutt_make_string (buffer, sizeof (buffer), Attribution, ctx, cur); 517 setlocale (LC_TIME, ""); 518 fputs (buffer, out); 519 fputc ('\n', out); 520 } 521} 522 523void mutt_make_post_indent (CONTEXT *ctx, HEADER *cur, FILE *out) 524{ 525 char buffer[STRING]; 526 if (PostIndentString) 527 { 528 mutt_make_string (buffer, sizeof (buffer), PostIndentString, ctx, cur); 529 fputs (buffer, out); 530 fputc ('\n', out); 531 } 532} 533 534static int include_reply (CONTEXT *ctx, HEADER *cur, FILE *out) 535{ 536 int cmflags = MUTT_CM_PREFIX | MUTT_CM_DECODE | MUTT_CM_CHARCONV | MUTT_CM_REPLYING; 537 int chflags = CH_DECODE; 538 539 if (WithCrypto && (cur->security & ENCRYPT)) 540 { 541 /* make sure we have the user's passphrase before proceeding... */ 542 crypt_valid_passphrase (cur->security); 543 } 544 545 mutt_parse_mime_message (ctx, cur); 546 mutt_message_hook (ctx, cur, MUTT_MESSAGEHOOK); 547 548 mutt_make_attribution (ctx, cur, out); 549 550 if (!option (OPTHEADER)) 551 cmflags |= MUTT_CM_NOHEADER; 552 if (option (OPTWEED)) 553 { 554 chflags |= CH_WEED | CH_REORDER; 555 cmflags |= MUTT_CM_WEED; 556 } 557 558 mutt_copy_message (out, ctx, cur, cmflags, chflags); 559 560 mutt_make_post_indent (ctx, cur, out); 561 562 return 0; 563} 564 565static int default_to (ADDRESS **to, ENVELOPE *env, int flags, int hmfupto) 566{ 567 char prompt[STRING]; 568 569 if (flags && env->mail_followup_to && hmfupto == MUTT_YES) 570 { 571 rfc822_append (to, env->mail_followup_to, 1); 572 return 0; 573 } 574 575 /* Exit now if we're setting up the default Cc list for list-reply 576 * (only set if Mail-Followup-To is present and honoured). 577 */ 578 if (flags & SENDLISTREPLY) 579 return 0; 580 581 if (!option(OPTREPLYSELF) && mutt_addr_is_user (env->from)) 582 { 583 /* mail is from the user, assume replying to recipients */ 584 rfc822_append (to, env->to, 1); 585 } 586 else if (env->reply_to) 587 { 588 if ((mutt_addrcmp (env->from, env->reply_to) && !env->reply_to->next && 589 !env->reply_to->personal) || 590 (option (OPTIGNORELISTREPLYTO) && 591 mutt_is_mail_list (env->reply_to) && 592 (mutt_addrsrc (env->reply_to, env->to) || 593 mutt_addrsrc (env->reply_to, env->cc)))) 594 { 595 /* If the Reply-To: address is a mailing list, assume that it was 596 * put there by the mailing list, and use the From: address 597 * 598 * We also take the from header if our correspondent has a reply-to 599 * header which is identical to the electronic mail address given 600 * in his From header, and the reply-to has no display-name. 601 * 602 */ 603 rfc822_append (to, env->from, 0); 604 } 605 else if (!(mutt_addrcmp (env->from, env->reply_to) && 606 !env->reply_to->next) && 607 quadoption (OPT_REPLYTO) != MUTT_YES) 608 { 609 /* There are quite a few mailing lists which set the Reply-To: 610 * header field to the list address, which makes it quite impossible 611 * to send a message to only the sender of the message. This 612 * provides a way to do that. 613 */ 614 /* L10N: 615 Asks whether the user respects the reply-to header. 616 If she says no, mutt will reply to the from header's address instead. */ 617 snprintf (prompt, sizeof (prompt), _("Reply to %s%s?"), 618 env->reply_to->mailbox, 619 env->reply_to->next?",...":""); 620 switch (query_quadoption (OPT_REPLYTO, prompt)) 621 { 622 case MUTT_YES: 623 rfc822_append (to, env->reply_to, 0); 624 break; 625 626 case MUTT_NO: 627 rfc822_append (to, env->from, 0); 628 break; 629 630 default: 631 return (-1); /* abort */ 632 } 633 } 634 else 635 rfc822_append (to, env->reply_to, 0); 636 } 637 else 638 rfc822_append (to, env->from, 0); 639 640 return (0); 641} 642 643int mutt_fetch_recips (ENVELOPE *out, ENVELOPE *in, int flags) 644{ 645 char prompt[STRING]; 646 ADDRESS *tmp; 647 int hmfupto = -1; 648 649 if ((flags & (SENDLISTREPLY|SENDGROUPREPLY|SENDGROUPCHATREPLY)) && 650 in->mail_followup_to) 651 { 652 snprintf (prompt, sizeof (prompt), _("Follow-up to %s%s?"), 653 in->mail_followup_to->mailbox, 654 in->mail_followup_to->next ? ",..." : ""); 655 656 if ((hmfupto = query_quadoption (OPT_MFUPTO, prompt)) == -1) 657 return -1; 658 } 659 660 if (flags & SENDLISTREPLY) 661 { 662 tmp = find_mailing_lists (in->to, in->cc); 663 rfc822_append (&out->to, tmp, 0); 664 rfc822_free_address (&tmp); 665 666 if (in->mail_followup_to && hmfupto == MUTT_YES && 667 default_to (&out->cc, in, flags & SENDLISTREPLY, hmfupto) == -1) 668 return (-1); /* abort */ 669 } 670 else if (flags & SENDTOSENDER) 671 rfc822_append (&out->to, in->from, 0); 672 else 673 { 674 if (default_to (&out->to, in, flags & (SENDGROUPREPLY|SENDGROUPCHATREPLY), 675 hmfupto) == -1) 676 return (-1); /* abort */ 677 678 if ((flags & (SENDGROUPREPLY|SENDGROUPCHATREPLY)) && 679 (!in->mail_followup_to || hmfupto != MUTT_YES)) 680 { 681 /* if (!mutt_addr_is_user(in->to)) */ 682 if (flags & SENDGROUPREPLY) 683 rfc822_append (&out->cc, in->to, 1); 684 else 685 rfc822_append (&out->to, in->to, 1); 686 rfc822_append (&out->cc, in->cc, 1); 687 } 688 } 689 return 0; 690} 691 692LIST *mutt_make_references(ENVELOPE *e) 693{ 694 LIST *t = NULL, *l = NULL; 695 696 if (e->references) 697 l = mutt_copy_list (e->references); 698 else 699 l = mutt_copy_list (e->in_reply_to); 700 701 if (e->message_id) 702 { 703 t = mutt_new_list(); 704 t->data = safe_strdup(e->message_id); 705 t->next = l; 706 l = t; 707 } 708 709 return l; 710} 711 712void mutt_fix_reply_recipients (ENVELOPE *env) 713{ 714 if (! option (OPTMETOO)) 715 { 716 /* the order is important here. do the CC: first so that if the 717 * the user is the only recipient, it ends up on the TO: field 718 */ 719 env->cc = remove_user (env->cc, (env->to == NULL)); 720 env->to = remove_user (env->to, (env->cc == NULL) || option (OPTREPLYSELF)); 721 } 722 723 /* the CC field can get cluttered, especially with lists */ 724 env->to = mutt_remove_duplicates (env->to); 725 env->cc = mutt_remove_duplicates (env->cc); 726 env->cc = mutt_remove_xrefs (env->to, env->cc); 727 728 if (env->cc && !env->to) 729 { 730 env->to = env->cc; 731 env->cc = NULL; 732 } 733} 734 735void mutt_make_forward_subject (ENVELOPE *env, CONTEXT *ctx, HEADER *cur) 736{ 737 char buffer[STRING]; 738 739 /* set the default subject for the message. */ 740 mutt_make_string (buffer, sizeof (buffer), NONULL(ForwFmt), ctx, cur); 741 mutt_str_replace (&env->subject, buffer); 742} 743 744void mutt_make_misc_reply_headers (ENVELOPE *env, CONTEXT *ctx, 745 HEADER *cur, ENVELOPE *curenv) 746{ 747 /* This takes precedence over a subject that might have 748 * been taken from a List-Post header. Is that correct? 749 */ 750 if (curenv->real_subj) 751 { 752 FREE (&env->subject); 753 env->subject = safe_malloc (mutt_strlen (curenv->real_subj) + 5); 754 sprintf (env->subject, "Re: %s", curenv->real_subj); /* __SPRINTF_CHECKED__ */ 755 } 756 else if (!env->subject) 757 env->subject = safe_strdup ("Re:"); 758} 759 760void mutt_add_to_reference_headers (ENVELOPE *env, ENVELOPE *curenv, LIST ***pp, LIST ***qq) 761{ 762 LIST **p = NULL, **q = NULL; 763 764 if (pp) p = *pp; 765 if (qq) q = *qq; 766 767 if (!p) p = &env->references; 768 if (!q) q = &env->in_reply_to; 769 770 while (*p) p = &(*p)->next; 771 while (*q) q = &(*q)->next; 772 773 *p = mutt_make_references (curenv); 774 775 if (curenv->message_id) 776 { 777 *q = mutt_new_list(); 778 (*q)->data = safe_strdup (curenv->message_id); 779 } 780 781 if (pp) *pp = p; 782 if (qq) *qq = q; 783 784} 785 786static void 787mutt_make_reference_headers (ENVELOPE *curenv, ENVELOPE *env, CONTEXT *ctx) 788{ 789 env->references = NULL; 790 env->in_reply_to = NULL; 791 792 if (!curenv) 793 { 794 HEADER *h; 795 LIST **p = NULL, **q = NULL; 796 int i; 797 798 for (i = 0; i < ctx->vcount; i++) 799 { 800 h = ctx->hdrs[ctx->v2r[i]]; 801 if (h->tagged) 802 mutt_add_to_reference_headers (env, h->env, &p, &q); 803 } 804 } 805 else 806 mutt_add_to_reference_headers (env, curenv, NULL, NULL); 807 808 /* if there's more than entry in In-Reply-To (i.e. message has 809 multiple parents), don't generate a References: header as it's 810 discouraged by RfC2822, sect. 3.6.4 */ 811 if (ctx->tagged > 0 && env->in_reply_to && env->in_reply_to->next) 812 mutt_free_list (&env->references); 813} 814 815static int 816envelope_defaults (ENVELOPE *env, CONTEXT *ctx, HEADER *cur, int flags) 817{ 818 ENVELOPE *curenv = NULL; 819 int i = 0, tag = 0; 820 821 if (!cur) 822 { 823 tag = 1; 824 for (i = 0; i < ctx->vcount; i++) 825 if (ctx->hdrs[ctx->v2r[i]]->tagged) 826 { 827 cur = ctx->hdrs[ctx->v2r[i]]; 828 curenv = cur->env; 829 break; 830 } 831 832 if (!cur) 833 { 834 /* This could happen if the user tagged some messages and then did 835 * a limit such that none of the tagged message are visible. 836 */ 837 mutt_error _("No tagged messages are visible!"); 838 return (-1); 839 } 840 } 841 else 842 curenv = cur->env; 843 844 if (flags & (SENDREPLY|SENDTOSENDER)) 845 { 846 if (tag) 847 { 848 HEADER *h; 849 850 for (i = 0; i < ctx->vcount; i++) 851 { 852 h = ctx->hdrs[ctx->v2r[i]]; 853 if (h->tagged && mutt_fetch_recips (env, h->env, flags) == -1) 854 return -1; 855 } 856 } 857 else if (mutt_fetch_recips (env, curenv, flags) == -1) 858 return -1; 859 860 if ((flags & SENDLISTREPLY) && !env->to) 861 { 862 mutt_error _("No mailing lists found!"); 863 return (-1); 864 } 865 866 if (flags & SENDREPLY) 867 { 868 mutt_make_misc_reply_headers (env, ctx, cur, curenv); 869 mutt_make_reference_headers (tag ? NULL : curenv, env, ctx); 870 } 871 } 872 else if (flags & SENDFORWARD) 873 mutt_make_forward_subject (env, ctx, cur); 874 875 return (0); 876} 877 878static int 879generate_body (FILE *tempfp, /* stream for outgoing message */ 880 HEADER *msg, /* header for outgoing message */ 881 int flags, /* compose mode */ 882 CONTEXT *ctx, /* current mailbox */ 883 HEADER *cur) /* current message */ 884{ 885 int i; 886 HEADER *h; 887 BODY *tmp; 888 889 if (flags & SENDREPLY) 890 { 891 if ((i = query_quadoption (OPT_INCLUDE, _("Include message in reply?"))) == -1) 892 return (-1); 893 894 if (i == MUTT_YES) 895 { 896 mutt_message _("Including quoted message..."); 897 if (!cur) 898 { 899 for (i = 0; i < ctx->vcount; i++) 900 { 901 h = ctx->hdrs[ctx->v2r[i]]; 902 if (h->tagged) 903 { 904 if (include_reply (ctx, h, tempfp) == -1) 905 { 906 mutt_error _("Could not include all requested messages!"); 907 return (-1); 908 } 909 fputc ('\n', tempfp); 910 } 911 } 912 } 913 else 914 include_reply (ctx, cur, tempfp); 915 916 } 917 } 918 else if (flags & SENDFORWARD) 919 { 920 if ((i = query_quadoption (OPT_MIMEFWD, _("Forward as attachment?"))) == MUTT_YES) 921 { 922 BODY *last = msg->content; 923 924 mutt_message _("Preparing forwarded message..."); 925 926 while (last && last->next) 927 last = last->next; 928 929 if (cur) 930 { 931 tmp = mutt_make_message_attach (ctx, cur, 0); 932 if (last) 933 last->next = tmp; 934 else 935 msg->content = tmp; 936 } 937 else 938 { 939 for (i = 0; i < ctx->vcount; i++) 940 { 941 if (ctx->hdrs[ctx->v2r[i]]->tagged) 942 { 943 tmp = mutt_make_message_attach (ctx, ctx->hdrs[ctx->v2r[i]], 0); 944 if (last) 945 { 946 last->next = tmp; 947 last = tmp; 948 } 949 else 950 last = msg->content = tmp; 951 } 952 } 953 } 954 } 955 else if (i != -1) 956 { 957 if (mutt_inline_forward (ctx, msg, cur, tempfp) != 0) 958 return -1; 959 } 960 else if (i == -1) 961 return -1; 962 } 963 /* if (WithCrypto && (flags & SENDKEY)) */ 964 else if ((WithCrypto & APPLICATION_PGP) && (flags & SENDKEY)) 965 { 966 BODY *tmp; 967 968 if ((WithCrypto & APPLICATION_PGP) 969 && (tmp = crypt_pgp_make_key_attachment ()) == NULL) 970 return -1; 971 972 tmp->next = msg->content; 973 msg->content = tmp; 974 } 975 976 mutt_clear_error (); 977 978 return (0); 979} 980 981void mutt_set_followup_to (ENVELOPE *e) 982{ 983 ADDRESS *t = NULL; 984 ADDRESS *from; 985 986 /* 987 * Only generate the Mail-Followup-To if the user has requested it, and 988 * it hasn't already been set 989 */ 990 991 if (option (OPTFOLLOWUPTO) && !e->mail_followup_to) 992 { 993 if (mutt_is_list_cc (0, e->to, e->cc)) 994 { 995 /* 996 * this message goes to known mailing lists, so create a proper 997 * mail-followup-to header 998 */ 999 1000 t = rfc822_append (&e->mail_followup_to, e->to, 0); 1001 rfc822_append (&t, e->cc, 1); 1002 } 1003 1004 /* remove ourselves from the mail-followup-to header */ 1005 e->mail_followup_to = remove_user (e->mail_followup_to, 0); 1006 1007 /* 1008 * If we are not subscribed to any of the lists in question, 1009 * re-add ourselves to the mail-followup-to header. The 1010 * mail-followup-to header generated is a no-op with group-reply, 1011 * but makes sure list-reply has the desired effect. 1012 */ 1013 1014 if (e->mail_followup_to && !mutt_is_list_recipient (0, e->to, e->cc)) 1015 { 1016 if (e->reply_to) 1017 from = rfc822_cpy_adr (e->reply_to, 0); 1018 else if (e->from) 1019 from = rfc822_cpy_adr (e->from, 0); 1020 else 1021 from = mutt_default_from (); 1022 1023 if (from) 1024 { 1025 /* Normally, this loop will not even be entered. */ 1026 for (t = from; t && t->next; t = t->next) 1027 ; 1028 1029 t->next = e->mail_followup_to; /* t cannot be NULL at this point. */ 1030 e->mail_followup_to = from; 1031 } 1032 } 1033 1034 e->mail_followup_to = mutt_remove_duplicates (e->mail_followup_to); 1035 1036 } 1037} 1038 1039 1040/* look through the recipients of the message we are replying to, and if 1041 we find an address that matches $alternates, we use that as the default 1042 from field */ 1043static ADDRESS *set_reverse_name (ENVELOPE *env) 1044{ 1045 ADDRESS *tmp; 1046 1047 for (tmp = env->to; tmp; tmp = tmp->next) 1048 { 1049 if (mutt_addr_is_user (tmp)) 1050 break; 1051 } 1052 if (!tmp) 1053 { 1054 for (tmp = env->cc; tmp; tmp = tmp->next) 1055 { 1056 if (mutt_addr_is_user (tmp)) 1057 break; 1058 } 1059 } 1060 if (!tmp && mutt_addr_is_user (env->from)) 1061 tmp = env->from; 1062 if (tmp) 1063 { 1064 tmp = rfc822_cpy_adr_real (tmp); 1065 /* when $reverse_realname is not set, clear the personal name so that it 1066 * may be set vi a reply- or send-hook. 1067 */ 1068 if (!option (OPTREVREAL)) 1069 FREE (&tmp->personal); 1070 } 1071 return (tmp); 1072} 1073 1074ADDRESS *mutt_default_from (void) 1075{ 1076 ADDRESS *adr; 1077 const char *fqdn = mutt_fqdn(1); 1078 1079 /* 1080 * Note: We let $from override $realname here. Is this the right 1081 * thing to do? 1082 */ 1083 1084 if (From) 1085 adr = rfc822_cpy_adr_real (From); 1086 else if (option (OPTUSEDOMAIN)) 1087 { 1088 adr = rfc822_new_address (); 1089 adr->mailbox = safe_malloc (mutt_strlen (Username) + mutt_strlen (fqdn) + 2); 1090 sprintf (adr->mailbox, "%s@%s", NONULL(Username), NONULL(fqdn)); /* __SPRINTF_CHECKED__ */ 1091 } 1092 else 1093 { 1094 adr = rfc822_new_address (); 1095 adr->mailbox = safe_strdup (NONULL(Username)); 1096 } 1097 1098 return (adr); 1099} 1100 1101static int generate_multipart_alternative (HEADER *msg, int flags) 1102{ 1103 BODY *alternative; 1104 1105 if (!SendMultipartAltFilter) 1106 return 0; 1107 1108 /* In batch mode, only run if the quadoption is yes or ask-yes */ 1109 if (flags & SENDBATCH) 1110 { 1111 if (!(quadoption (OPT_SENDMULTIPARTALT) & 0x1)) 1112 return 0; 1113 } 1114 else 1115 { 1116 if (query_quadoption (OPT_SENDMULTIPARTALT, 1117 /* L10N: 1118 This is the query for the $send_multipart_alternative quadoption. 1119 Answering yes generates an alternative content using 1120 $send_multipart_alternative_filter 1121 */ 1122 _("Generate multipart/alternative content?")) != MUTT_YES) 1123 return 0; 1124 } 1125 1126 1127 alternative = mutt_run_send_alternative_filter (msg->content); 1128 if (!alternative) 1129 return -1; 1130 1131 msg->content = mutt_make_multipart_alternative (msg->content, alternative); 1132 1133 return 0; 1134} 1135 1136static int send_message (HEADER *msg) 1137{ 1138 BUFFER *tempfile = NULL; 1139 FILE *tempfp = NULL; 1140 int i = -1; 1141#ifdef USE_SMTP 1142 short old_write_bcc; 1143#endif 1144 1145 /* Write out the message in MIME form. */ 1146 tempfile = mutt_buffer_pool_get (); 1147 mutt_buffer_mktemp (tempfile); 1148 if ((tempfp = safe_fopen (mutt_b2s (tempfile), "w")) == NULL) 1149 goto cleanup; 1150 1151#ifdef USE_SMTP 1152 old_write_bcc = option (OPTWRITEBCC); 1153 if (SmtpUrl) 1154 unset_option (OPTWRITEBCC); 1155#endif 1156#ifdef MIXMASTER 1157 mutt_write_rfc822_header (tempfp, msg->env, msg->content, 1158 MUTT_WRITE_HEADER_NORMAL, msg->chain ? 1 : 0, 1159 mutt_should_hide_protected_subject (msg)); 1160#endif 1161#ifndef MIXMASTER 1162 mutt_write_rfc822_header (tempfp, msg->env, msg->content, 1163 MUTT_WRITE_HEADER_NORMAL, 0, 1164 mutt_should_hide_protected_subject (msg)); 1165#endif 1166#ifdef USE_SMTP 1167 if (old_write_bcc) 1168 set_option (OPTWRITEBCC); 1169#endif 1170 1171 fputc ('\n', tempfp); /* tie off the header. */ 1172 1173 if ((mutt_write_mime_body (msg->content, tempfp) == -1)) 1174 goto cleanup; 1175 1176 if (safe_fclose (&tempfp) != 0) 1177 { 1178 mutt_perror (mutt_b2s (tempfile)); 1179 unlink (mutt_b2s (tempfile)); 1180 goto cleanup; 1181 } 1182 1183#ifdef MIXMASTER 1184 if (msg->chain) 1185 i = mix_send_message (msg->chain, mutt_b2s (tempfile)); 1186 else 1187#endif 1188 1189#if USE_SMTP 1190 if (SmtpUrl) 1191 i = mutt_smtp_send (msg->env->from, msg->env->to, msg->env->cc, 1192 msg->env->bcc, mutt_b2s (tempfile), 1193 (msg->content->encoding == ENC8BIT)); 1194 else 1195#endif /* USE_SMTP */ 1196 1197 i = mutt_invoke_sendmail (msg->env->from, msg->env->to, msg->env->cc, 1198 msg->env->bcc, mutt_b2s (tempfile), 1199 (msg->content->encoding == ENC8BIT)); 1200 1201cleanup: 1202 if (tempfp) 1203 { 1204 safe_fclose (&tempfp); 1205 unlink (mutt_b2s (tempfile)); 1206 } 1207 mutt_buffer_pool_release (&tempfile); 1208 return (i); 1209} 1210 1211static int save_fcc (HEADER *msg, BUFFER *fcc, 1212 BODY *clear_content, char *pgpkeylist, 1213 int flags) 1214{ 1215 int rc = 0; 1216 BODY *tmpbody = msg->content; 1217 BODY *save_content = NULL; 1218 BODY *save_sig = NULL; 1219 BODY *save_parts = NULL; 1220 int choice, save_atts; 1221 1222 mutt_buffer_expand_path (fcc); 1223 1224 /* Don't save a copy when we are in batch-mode, and the FCC 1225 * folder is on an IMAP server: This would involve possibly lots 1226 * of user interaction, which is not available in batch mode. 1227 * 1228 * Note: A patch to fix the problems with the use of IMAP servers 1229 * from non-curses mode is available from Brendan Cully. However, 1230 * I'd like to think a bit more about this before including it. 1231 */ 1232 1233#ifdef USE_IMAP 1234 if ((flags & SENDBATCH) && 1235 mutt_buffer_len (fcc) && 1236 mx_is_imap (mutt_b2s (fcc))) 1237 { 1238 mutt_error _ ("Fcc to an IMAP mailbox is not supported in batch mode"); 1239 return rc; 1240 } 1241#endif 1242 1243 if (!(mutt_buffer_len (fcc) && 1244 mutt_strcmp ("/dev/null", mutt_b2s (fcc)))) 1245 return rc; 1246 1247 /* Before sending, we don't allow message manipulation because it 1248 * will break message signatures. This is especially complicated by 1249 * Protected Headers. */ 1250 if (!option (OPTFCCBEFORESEND)) 1251 { 1252 if (WithCrypto && 1253 (msg->security & (ENCRYPT | SIGN | AUTOCRYPT)) 1254 && option (OPTFCCCLEAR)) 1255 { 1256 msg->content = clear_content; 1257 msg->security &= ~(ENCRYPT | SIGN | AUTOCRYPT); 1258 mutt_free_envelope (&msg->content->mime_headers); 1259 } 1260 1261 /* check to see if the user wants copies of all attachments */ 1262 save_atts = 1; 1263 if (msg->content->type == TYPEMULTIPART) 1264 { 1265 /* In batch mode, save attachments if the quadoption is yes or ask-yes */ 1266 if (flags & SENDBATCH) 1267 { 1268 if (!(quadoption (OPT_FCCATTACH) & 0x1)) 1269 save_atts = 0; 1270 } 1271 else if (query_quadoption (OPT_FCCATTACH, _("Save attachments in Fcc?")) != MUTT_YES) 1272 save_atts = 0; 1273 } 1274 if (!save_atts) 1275 { 1276 if (WithCrypto 1277 && (msg->security & (ENCRYPT | SIGN | AUTOCRYPT)) 1278 && (mutt_strcmp (msg->content->subtype, "encrypted") == 0 || 1279 mutt_strcmp (msg->content->subtype, "signed") == 0)) 1280 { 1281 if ((clear_content->type == TYPEMULTIPART) && 1282 !ascii_strcasecmp (clear_content->subtype, "mixed")) 1283 { 1284 if (!(msg->security & ENCRYPT) && (msg->security & SIGN)) 1285 { 1286 /* save initial signature and attachments */ 1287 save_sig = msg->content->parts->next; 1288 save_parts = clear_content->parts->next; 1289 } 1290 1291 /* this means writing only the main part */ 1292 msg->content = clear_content->parts; 1293 1294 if (mutt_protect (msg, pgpkeylist, 0) == -1) 1295 { 1296 /* we can't do much about it at this point, so 1297 * fallback to saving the whole thing to fcc 1298 */ 1299 msg->content = tmpbody; 1300 save_sig = NULL; 1301 goto full_fcc; 1302 } 1303 1304 save_content = msg->content; 1305 } 1306 } 1307 else if (!ascii_strcasecmp (msg->content->subtype, "mixed")) 1308 msg->content = msg->content->parts; 1309 } 1310 } 1311 1312full_fcc: 1313 if (msg->content) 1314 { 1315 /* update received time so that when storing to a mbox-style folder 1316 * the From_ line contains the current time instead of when the 1317 * message was first postponed. 1318 */ 1319 msg->received = time (NULL); 1320 rc = mutt_write_fcc (mutt_b2s (fcc), msg, NULL, 0, NULL); 1321 while (rc && !(flags & SENDBATCH)) 1322 { 1323 mutt_clear_error (); 1324 choice = mutt_multi_choice ( 1325 /* L10N: 1326 Called when saving to $record or Fcc failed after sending. 1327 (r)etry tries the same mailbox again. 1328 alternate (m)ailbox prompts for a different mailbox to try. 1329 (s)kip aborts saving. 1330 */ 1331 _("Fcc failed. (r)etry, alternate (m)ailbox, or (s)kip? "), 1332 /* L10N: 1333 These correspond to the "Fcc failed" multi-choice prompt 1334 (r)etry, alternate (m)ailbox, or (s)kip. 1335 Any similarity to famous leaders of the FSF is coincidental. 1336 */ 1337 _("rms")); 1338 switch (choice) 1339 { 1340 case 2: /* alternate (m)ailbox */ 1341 /* L10N: 1342 This is the prompt to enter an "alternate (m)ailbox" when the 1343 initial Fcc fails. 1344 */ 1345 rc = mutt_buffer_enter_fname (_("Fcc mailbox"), fcc, 1); 1346 if ((rc == -1) || !mutt_buffer_len (fcc)) 1347 { 1348 rc = 0; 1349 break; 1350 } 1351 /* fall through */ 1352 1353 case 1: /* (r)etry */ 1354 rc = mutt_write_fcc (mutt_b2s (fcc), msg, NULL, 0, NULL); 1355 break; 1356 1357 case -1: /* abort */ 1358 case 3: /* (s)kip */ 1359 rc = 0; 1360 break; 1361 } 1362 } 1363 } 1364 1365 if (!option (OPTFCCBEFORESEND)) 1366 { 1367 msg->content = tmpbody; 1368 1369 if (WithCrypto && save_sig) 1370 { 1371 /* cleanup the second signature structures */ 1372 if (save_content->parts) 1373 { 1374 mutt_free_body (&save_content->parts->next); 1375 save_content->parts = NULL; 1376 } 1377 mutt_free_body (&save_content); 1378 1379 /* restore old signature and attachments */ 1380 msg->content->parts->next = save_sig; 1381 msg->content->parts->parts->next = save_parts; 1382 } 1383 else if (WithCrypto && save_content) 1384 { 1385 /* destroy the new encrypted body. */ 1386 mutt_free_body (&save_content); 1387 } 1388 } 1389 1390 return rc; 1391} 1392 1393/* rfc2047 encode the content-descriptions */ 1394void mutt_encode_descriptions (BODY *b, short recurse) 1395{ 1396 BODY *t; 1397 1398 for (t = b; t; t = t->next) 1399 { 1400 if (t->description) 1401 { 1402 rfc2047_encode_string (&t->description); 1403 } 1404 if (recurse && t->parts) 1405 mutt_encode_descriptions (t->parts, recurse); 1406 } 1407} 1408 1409/* rfc2047 decode them in case of an error */ 1410static void decode_descriptions (BODY *b) 1411{ 1412 BODY *t; 1413 1414 for (t = b; t; t = t->next) 1415 { 1416 if (t->description) 1417 { 1418 rfc2047_decode (&t->description); 1419 } 1420 if (t->parts) 1421 decode_descriptions (t->parts); 1422 } 1423} 1424 1425static void fix_end_of_file (const char *data) 1426{ 1427 FILE *fp; 1428 int c; 1429 1430 if ((fp = safe_fopen (data, "a+")) == NULL) 1431 return; 1432 fseek (fp,-1,SEEK_END); 1433 if ((c = fgetc(fp)) != '\n') 1434 fputc ('\n', fp); 1435 safe_fclose (&fp); 1436} 1437 1438int mutt_resend_message (FILE *fp, CONTEXT *ctx, HEADER *cur) 1439{ 1440 HEADER *msg = mutt_new_header (); 1441 1442 if (mutt_prepare_template (fp, ctx, msg, cur, 1) < 0) 1443 return -1; 1444 1445 if (WithCrypto) 1446 { 1447 /* mutt_prepare_template doesn't always flip on an application bit. 1448 * so fix that here */ 1449 if (!(msg->security & (APPLICATION_SMIME | APPLICATION_PGP))) 1450 { 1451 if ((WithCrypto & APPLICATION_SMIME) && option (OPTSMIMEISDEFAULT)) 1452 msg->security |= APPLICATION_SMIME; 1453 else if (WithCrypto & APPLICATION_PGP) 1454 msg->security |= APPLICATION_PGP; 1455 else 1456 msg->security |= APPLICATION_SMIME; 1457 } 1458 1459 if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) 1460 { 1461 msg->security |= OPPENCRYPT; 1462 crypt_opportunistic_encrypt(msg); 1463 } 1464 } 1465 1466 return ci_send_message (SENDRESEND, msg, NULL, ctx, cur); 1467} 1468 1469static int is_reply (HEADER *reply, HEADER *orig) 1470{ 1471 return mutt_find_list (orig->env->references, reply->env->message_id) || 1472 mutt_find_list (orig->env->in_reply_to, reply->env->message_id); 1473} 1474 1475static int has_recips (ADDRESS *a) 1476{ 1477 int c = 0; 1478 1479 for ( ; a; a = a->next) 1480 { 1481 if (!a->mailbox || a->group) 1482 continue; 1483 c++; 1484 } 1485 return c; 1486} 1487 1488static int has_attach_keyword (char *filename) 1489{ 1490 int match = 0; 1491 char *buf = NULL; 1492 size_t blen = 0; 1493 FILE *fp; 1494 1495 if ((fp = safe_fopen (filename, "r")) == NULL) 1496 { 1497 mutt_perror (filename); 1498 return 0; 1499 } 1500 1501 while ((buf = mutt_read_line (buf, &blen, fp, NULL, 0)) != NULL) 1502 { 1503 if (!mutt_is_quote_line (buf, NULL) && 1504 regexec (AbortNoattachRegexp.rx, buf, 0, NULL, 0) == 0) 1505 { 1506 match = 1; 1507 break; 1508 } 1509 } 1510 safe_fclose (&fp); 1511 FREE (&buf); 1512 1513 return match; 1514} 1515 1516static int postpone_message (HEADER *msg, HEADER *cur, const char *fcc, int flags) 1517{ 1518 char *pgpkeylist = NULL; 1519 char *encrypt_as = NULL; 1520 BODY *clear_content = NULL; 1521 1522 if (!Postponed) 1523 { 1524 mutt_error _("Cannot postpone. $postponed is unset"); 1525 return -1; 1526 } 1527 1528 if (msg->content->next) 1529 msg->content = mutt_make_multipart_mixed (msg->content); 1530 1531 mutt_encode_descriptions (msg->content, 1); 1532 1533 if (WithCrypto && option (OPTPOSTPONEENCRYPT) && 1534 (msg->security & (ENCRYPT | AUTOCRYPT))) 1535 { 1536 if ((WithCrypto & APPLICATION_PGP) && (msg->security & APPLICATION_PGP)) 1537 encrypt_as = PgpDefaultKey; 1538 else if ((WithCrypto & APPLICATION_SMIME) && (msg->security & APPLICATION_SMIME)) 1539 encrypt_as = SmimeDefaultKey; 1540 if (!encrypt_as) 1541 encrypt_as = PostponeEncryptAs; 1542 1543#ifdef USE_AUTOCRYPT 1544 if (msg->security & AUTOCRYPT) 1545 { 1546 if (mutt_autocrypt_set_sign_as_default_key (msg)) 1547 { 1548 msg->content = mutt_remove_multipart_mixed (msg->content); 1549 decode_descriptions (msg->content); 1550 return -1; 1551 } 1552 encrypt_as = AutocryptDefaultKey; 1553 } 1554#endif 1555 1556 if (encrypt_as) 1557 { 1558 pgpkeylist = safe_strdup (encrypt_as); 1559 clear_content = msg->content; 1560 if (mutt_protect (msg, pgpkeylist, 1) == -1) 1561 { 1562 FREE (&pgpkeylist); 1563 msg->content = mutt_remove_multipart_mixed (msg->content); 1564 decode_descriptions (msg->content); 1565 return -1; 1566 } 1567 1568 FREE (&pgpkeylist); 1569 mutt_encode_descriptions (msg->content, 0); 1570 } 1571 } 1572 1573 /* 1574 * make sure the message is written to the right part of a maildir 1575 * postponed folder. 1576 */ 1577 msg->read = 0; msg->old = 0; 1578 1579 mutt_prepare_envelope (msg->env, 0); 1580 mutt_env_to_intl (msg->env, NULL, NULL); /* Handle bad IDNAs the next time. */ 1581 1582 if (mutt_write_fcc (NONULL (Postponed), msg, 1583 (cur && (flags & SENDREPLY)) ? cur->env->message_id : NULL, 1584 1, fcc) < 0) 1585 { 1586 if (clear_content) 1587 { 1588 mutt_free_body (&msg->content); 1589 msg->content = clear_content; 1590 } 1591 mutt_free_envelope (&msg->content->mime_headers); /* protected headers */ 1592 msg->content = mutt_remove_multipart_mixed (msg->content); 1593 decode_descriptions (msg->content); 1594 mutt_unprepare_envelope (msg->env); 1595 return -1; 1596 } 1597 1598 mutt_update_num_postponed (); 1599 1600 if (clear_content) 1601 mutt_free_body (&clear_content); 1602 1603 return 0; 1604} 1605 1606/* 1607 * Returns 0 if the message was successfully sent 1608 * -1 if the message was aborted or an error occurred 1609 * 1 if the message was postponed 1610 */ 1611int 1612ci_send_message (int flags, /* send mode */ 1613 HEADER *msg, /* template to use for new message */ 1614 const char *tempfile, /* file specified by -i or -H */ 1615 CONTEXT *ctx, /* current mailbox */ 1616 HEADER *cur) /* current message */ 1617{ 1618 char buffer[LONG_STRING]; 1619 BUFFER *fcc; /* where to copy this message */ 1620 FILE *tempfp = NULL; 1621 BODY *pbody; 1622 int i, killfrom = 0; 1623 int free_clear_content = 0; 1624 1625 BODY *clear_content = NULL; 1626 char *pgpkeylist = NULL; 1627 /* save current value of "pgp_sign_as" and "smime_default_key" */ 1628 char *pgp_signas = NULL; 1629 char *smime_signas = NULL; 1630 char *tag = NULL, *err = NULL; 1631 char *ctype; 1632 1633 int rv = -1; 1634 1635 if (!flags && !msg && quadoption (OPT_RECALL) != MUTT_NO && 1636 mutt_num_postponed (1)) 1637 { 1638 /* If the user is composing a new message, check to see if there 1639 * are any postponed messages first. 1640 */ 1641 if ((i = query_quadoption (OPT_RECALL, _("Recall postponed message?"))) == -1) 1642 return rv; 1643 1644 if (i == MUTT_YES) 1645 flags |= SENDPOSTPONED; 1646 } 1647 1648 /* Allocate the buffer due to the long lifetime, but 1649 * pre-resize it to ensure there are no NULL data field issues */ 1650 fcc = mutt_buffer_new (); 1651 mutt_buffer_increase_size (fcc, LONG_STRING); 1652 1653 if (flags & SENDPOSTPONED) 1654 { 1655 if (WithCrypto & APPLICATION_PGP) 1656 pgp_signas = safe_strdup(PgpSignAs); 1657 if (WithCrypto & APPLICATION_SMIME) 1658 smime_signas = safe_strdup(SmimeSignAs); 1659 } 1660 1661 /* Delay expansion of aliases until absolutely necessary--shouldn't 1662 * be necessary unless we are prompting the user or about to execute a 1663 * send-hook. 1664 */ 1665 1666 if (!msg) 1667 { 1668 msg = mutt_new_header (); 1669 1670 if (flags == SENDPOSTPONED) 1671 { 1672 if ((flags = mutt_get_postponed (ctx, msg, &cur, fcc)) < 0) 1673 { 1674 flags = SENDPOSTPONED; 1675 goto cleanup; 1676 } 1677 } 1678 1679 if (flags & (SENDPOSTPONED|SENDRESEND)) 1680 { 1681 if ((tempfp = safe_fopen (msg->content->filename, "a+")) == NULL) 1682 { 1683 mutt_perror (msg->content->filename); 1684 goto cleanup; 1685 } 1686 } 1687 1688 if (!msg->env) 1689 msg->env = mutt_new_envelope (); 1690 } 1691 1692 /* Parse and use an eventual list-post header */ 1693 if ((flags & SENDLISTREPLY) 1694 && cur && cur->env && cur->env->list_post) 1695 { 1696 /* Use any list-post header as a template */ 1697 url_parse_mailto (msg->env, NULL, cur->env->list_post); 1698 /* We don't let them set the sender's address. */ 1699 rfc822_free_address (&msg->env->from); 1700 } 1701 1702 if (! (flags & (SENDKEY | SENDPOSTPONED | SENDRESEND))) 1703 { 1704 /* When SENDDRAFTFILE is set, the caller has already 1705 * created the "parent" body structure. 1706 */ 1707 if (! (flags & SENDDRAFTFILE)) 1708 { 1709 pbody = mutt_new_body (); 1710 pbody->next = msg->content; /* don't kill command-line attachments */ 1711 msg->content = pbody; 1712 1713 if (!(ctype = safe_strdup (ContentType))) 1714 ctype = safe_strdup ("text/plain"); 1715 mutt_parse_content_type (ctype, msg->content); 1716 FREE (&ctype); 1717 msg->content->unlink = 1; 1718 msg->content->use_disp = 0; 1719 msg->content->disposition = DISPINLINE; 1720 1721 if (!tempfile) 1722 { 1723 mutt_mktemp (buffer, sizeof (buffer)); 1724 tempfp = safe_fopen (buffer, "w+"); 1725 msg->content->filename = safe_strdup (buffer); 1726 } 1727 else 1728 { 1729 tempfp = safe_fopen (tempfile, "a+"); 1730 msg->content->filename = safe_strdup (tempfile); 1731 } 1732 } 1733 else 1734 tempfp = safe_fopen (msg->content->filename, "a+"); 1735 1736 if (!tempfp) 1737 { 1738 dprint(1,(debugfile, "newsend_message: can't create tempfile %s (errno=%d)\n", msg->content->filename, errno)); 1739 mutt_perror (msg->content->filename); 1740 goto cleanup; 1741 } 1742 } 1743 1744 /* this is handled here so that the user can match ~f in send-hook */ 1745 if (cur && option (OPTREVNAME) && !(flags & (SENDPOSTPONED|SENDRESEND))) 1746 { 1747 /* we shouldn't have to worry about freeing `msg->env->from' before 1748 * setting it here since this code will only execute when doing some 1749 * sort of reply. the pointer will only be set when using the -H command 1750 * line option. 1751 * 1752 * We shouldn't have to worry about alias expansion here since we are 1753 * either replying to a real or postponed message, therefore no aliases 1754 * should exist since the user has not had the opportunity to add 1755 * addresses to the list. We just have to ensure the postponed messages 1756 * have their aliases expanded. 1757 */ 1758 1759 msg->env->from = set_reverse_name (cur->env); 1760 } 1761 1762 if (! (flags & (SENDPOSTPONED|SENDRESEND)) && 1763 ! ((flags & SENDDRAFTFILE) && option (OPTRESUMEDRAFTFILES))) 1764 { 1765 if ((flags & (SENDREPLY | SENDFORWARD | SENDTOSENDER)) && ctx && 1766 envelope_defaults (msg->env, ctx, cur, flags) == -1) 1767 goto cleanup; 1768 1769 if (option (OPTHDRS)) 1770 process_user_recips (msg->env); 1771 1772 /* Expand aliases and remove duplicates/crossrefs */ 1773 mutt_expand_aliases_env (msg->env); 1774 1775 if (flags & SENDREPLY) 1776 mutt_fix_reply_recipients (msg->env); 1777 1778 if (! (flags & (SENDMAILX|SENDBATCH)) && 1779 ! (option (OPTAUTOEDIT) && option (OPTEDITHDRS)) && 1780 ! ((flags & SENDREPLY) && option (OPTFASTREPLY))) 1781 { 1782 if (edit_envelope (msg->env) == -1) 1783 goto cleanup; 1784 } 1785 1786 /* the from address must be set here regardless of whether or not 1787 * $use_from is set so that the `~P' (from you) operator in send-hook 1788 * patterns will work. if $use_from is unset, the from address is killed 1789 * after send-hooks are evaluated */ 1790 1791 if (!msg->env->from) 1792 { 1793 msg->env->from = mutt_default_from (); 1794 killfrom = 1; 1795 } 1796 1797 if ((flags & SENDREPLY) && cur) 1798 { 1799 /* change setting based upon message we are replying to */ 1800 mutt_message_hook (ctx, cur, MUTT_REPLYHOOK); 1801 1802 /* 1803 * set the replied flag for the message we are generating so that the 1804 * user can use ~Q in a send-hook to know when reply-hook's are also 1805 * being used. 1806 */ 1807 msg->replied = 1; 1808 } 1809 1810 /* change settings based upon recipients */ 1811 1812 mutt_message_hook (NULL, msg, MUTT_SENDHOOK); 1813 1814 /* 1815 * Unset the replied flag from the message we are composing since it is 1816 * no longer required. This is done here because the FCC'd copy of 1817 * this message was erroneously get the 'R'eplied flag when stored in 1818 * a maildir-style mailbox. 1819 */ 1820 msg->replied = 0; 1821 1822 /* $use_from and/or $from might have changed in a send-hook */ 1823 if (killfrom) 1824 { 1825 rfc822_free_address (&msg->env->from); 1826 if (option (OPTUSEFROM) && !(flags & (SENDPOSTPONED|SENDRESEND))) 1827 msg->env->from = mutt_default_from (); 1828 killfrom = 0; 1829 } 1830 1831 if (option (OPTHDRS)) 1832 process_user_header (msg->env); 1833 1834 if (flags & SENDBATCH) 1835 mutt_copy_stream (stdin, tempfp); 1836 1837 if (option (OPTSIGONTOP) && ! (flags & (SENDMAILX|SENDKEY|SENDBATCH)) 1838 && Editor && mutt_strcmp (Editor, "builtin") != 0) { 1839 append_signature (tempfp); 1840 fputs ("\n", tempfp); 1841 } 1842 1843 /* include replies/forwarded messages, unless we are given a template */ 1844 if (!tempfile && (ctx || !(flags & (SENDREPLY|SENDFORWARD))) 1845 && generate_body (tempfp, msg, flags, ctx, cur) == -1) 1846 goto cleanup; 1847 1848 if (!option (OPTSIGONTOP) && ! (flags & (SENDMAILX|SENDKEY|SENDBATCH)) 1849 && Editor && mutt_strcmp (Editor, "builtin") != 0) 1850 append_signature (tempfp); 1851 } 1852 1853 /* Only set format=flowed for new messages. Postponed/resent/draftfiles 1854 * should respect the original email. 1855 * 1856 * This is set here so that send-hook can be used to turn the option on. 1857 */ 1858 if (!(flags & (SENDKEY | SENDPOSTPONED | SENDRESEND | SENDDRAFTFILE))) 1859 { 1860 if (option (OPTTEXTFLOWED) && 1861 msg->content->type == TYPETEXT && 1862 !ascii_strcasecmp (msg->content->subtype, "plain")) 1863 mutt_set_parameter ("format", "flowed", &msg->content->parameter); 1864 } 1865 1866 /* 1867 * This hook is even called for postponed messages, and can, e.g., be 1868 * used for setting the editor, the sendmail path, or the 1869 * envelope sender. 1870 */ 1871 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 1872 1873 /* wait until now to set the real name portion of our return address so 1874 that $realname can be set in a send-hook */ 1875 if (msg->env->from && !msg->env->from->personal 1876 && !(flags & (SENDRESEND|SENDPOSTPONED))) 1877 msg->env->from->personal = safe_strdup (Realname); 1878 1879 if (!((WithCrypto & APPLICATION_PGP) && (flags & SENDKEY))) 1880 safe_fclose (&tempfp); 1881 1882 if (flags & SENDMAILX) 1883 { 1884 if (mutt_builtin_editor (msg->content->filename, msg, cur) == -1) 1885 goto cleanup; 1886 } 1887 else if (! (flags & SENDBATCH)) 1888 { 1889 struct stat st; 1890 time_t mtime = mutt_decrease_mtime (msg->content->filename, NULL); 1891 1892 mutt_update_encoding (msg->content); 1893 1894 /* 1895 * Select whether or not the user's editor should be called now. We 1896 * don't want to do this when: 1897 * 1) we are sending a key/cert 1898 * 2) we are forwarding a message and the user doesn't want to edit it. 1899 * This is controlled by the quadoption $forward_edit. However, if 1900 * both $edit_headers and $autoedit are set, we want to ignore the 1901 * setting of $forward_edit because the user probably needs to add the 1902 * recipients. 1903 */ 1904 if (! (flags & SENDKEY) && 1905 ((flags & SENDFORWARD) == 0 || 1906 (option (OPTEDITHDRS) && option (OPTAUTOEDIT)) || 1907 query_quadoption (OPT_FORWEDIT, _("Edit forwarded message?")) == MUTT_YES)) 1908 { 1909 /* If the this isn't a text message, look for a mailcap edit command */ 1910 if (mutt_needs_mailcap (msg->content)) 1911 { 1912 if (!mutt_edit_attachment (msg->content)) 1913 goto cleanup; 1914 } 1915 else if (!Editor || mutt_strcmp ("builtin", Editor) == 0) 1916 mutt_builtin_editor (msg->content->filename, msg, cur); 1917 else if (option (OPTEDITHDRS)) 1918 { 1919 mutt_env_to_local (msg->env); 1920 mutt_edit_headers (Editor, msg->content->filename, msg, fcc); 1921 mutt_env_to_intl (msg->env, NULL, NULL); 1922 } 1923 else 1924 { 1925 mutt_edit_file (Editor, msg->content->filename); 1926 if (stat (msg->content->filename, &st) == 0) 1927 { 1928 if (mtime != st.st_mtime) 1929 fix_end_of_file (msg->content->filename); 1930 } 1931 else 1932 mutt_perror (msg->content->filename); 1933 } 1934 1935 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK); 1936 } 1937 1938 if (! (flags & (SENDPOSTPONED | SENDFORWARD | SENDKEY | SENDRESEND | SENDDRAFTFILE))) 1939 { 1940 if (stat (msg->content->filename, &st) == 0) 1941 { 1942 /* if the file was not modified, bail out now */ 1943 if (mtime == st.st_mtime && !msg->content->next && 1944 query_quadoption (OPT_ABORT, _("Abort unmodified message?")) == MUTT_YES) 1945 { 1946 mutt_message _("Aborted unmodified message."); 1947 goto cleanup; 1948 } 1949 } 1950 else 1951 mutt_perror (msg->content->filename); 1952 } 1953 } 1954 1955 /* 1956 * Set the message security unless: 1957 * 1) crypto support is not enabled (WithCrypto==0) 1958 * 2) pgp: header field was present during message editing with $edit_headers (msg->security != 0) 1959 * 3) we are resending a message 1960 * 4) we are recalling a postponed message (don't override the user's saved settings) 1961 * 5) we are in mailx mode 1962 * 6) we are in batch mode 1963 * 1964 * This is done after allowing the user to edit the message so that security 1965 * settings can be configured with send2-hook and $edit_headers. 1966 */ 1967 if (WithCrypto && (msg->security == 0) && !(flags & (SENDBATCH | SENDMAILX | SENDPOSTPONED | SENDRESEND))) 1968 { 1969 if ( 1970#ifdef USE_AUTOCRYPT 1971 option (OPTAUTOCRYPT) && option (OPTAUTOCRYPTREPLY) 1972#else 1973 0 1974#endif 1975 && cur && (cur->security & AUTOCRYPT)) 1976 { 1977 msg->security |= (AUTOCRYPT | AUTOCRYPT_OVERRIDE | APPLICATION_PGP); 1978 } 1979 else 1980 { 1981 if (option (OPTCRYPTAUTOSIGN)) 1982 msg->security |= SIGN; 1983 if (option (OPTCRYPTAUTOENCRYPT)) 1984 msg->security |= ENCRYPT; 1985 if (option (OPTCRYPTREPLYENCRYPT) && cur && (cur->security & ENCRYPT)) 1986 msg->security |= ENCRYPT; 1987 if (option (OPTCRYPTREPLYSIGN) && cur && (cur->security & SIGN)) 1988 msg->security |= SIGN; 1989 if (option (OPTCRYPTREPLYSIGNENCRYPTED) && cur && (cur->security & ENCRYPT)) 1990 msg->security |= SIGN; 1991 if ((WithCrypto & APPLICATION_PGP) && 1992 ((msg->security & (ENCRYPT | SIGN)) || option (OPTCRYPTOPPORTUNISTICENCRYPT))) 1993 { 1994 if (option (OPTPGPAUTOINLINE)) 1995 msg->security |= INLINE; 1996 if (option (OPTPGPREPLYINLINE) && cur && (cur->security & INLINE)) 1997 msg->security |= INLINE; 1998 } 1999 } 2000 2001 if (msg->security || option (OPTCRYPTOPPORTUNISTICENCRYPT)) 2002 { 2003 /* 2004 * When replying / forwarding, use the original message's 2005 * crypto system. According to the documentation, 2006 * smime_is_default should be disregarded here. 2007 * 2008 * Problem: At least with forwarding, this doesn't really 2009 * make much sense. Should we have an option to completely 2010 * disable individual mechanisms at run-time? 2011 */ 2012 if (cur) 2013 { 2014 if ((WithCrypto & APPLICATION_PGP) && option (OPTCRYPTAUTOPGP) 2015 && (cur->security & APPLICATION_PGP)) 2016 msg->security |= APPLICATION_PGP; 2017 else if ((WithCrypto & APPLICATION_SMIME) && option (OPTCRYPTAUTOSMIME) 2018 && (cur->security & APPLICATION_SMIME)) 2019 msg->security |= APPLICATION_SMIME; 2020 } 2021 2022 /* 2023 * No crypto mechanism selected? Use availability + smime_is_default 2024 * for the decision. 2025 */ 2026 if (!(msg->security & (APPLICATION_SMIME | APPLICATION_PGP))) 2027 { 2028 if ((WithCrypto & APPLICATION_SMIME) && option (OPTCRYPTAUTOSMIME) 2029 && option (OPTSMIMEISDEFAULT)) 2030 msg->security |= APPLICATION_SMIME; 2031 else if ((WithCrypto & APPLICATION_PGP) && option (OPTCRYPTAUTOPGP)) 2032 msg->security |= APPLICATION_PGP; 2033 else if ((WithCrypto & APPLICATION_SMIME) && option (OPTCRYPTAUTOSMIME)) 2034 msg->security |= APPLICATION_SMIME; 2035 } 2036 } 2037 2038 /* opportunistic encrypt relies on SMIME or PGP already being selected */ 2039 if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) 2040 { 2041 /* If something has already enabled encryption, e.g. OPTCRYPTAUTOENCRYPT 2042 * or OPTCRYPTREPLYENCRYPT, then don't enable opportunistic encrypt for 2043 * the message. 2044 */ 2045 if (! (msg->security & (ENCRYPT|AUTOCRYPT))) 2046 { 2047 msg->security |= OPPENCRYPT; 2048 crypt_opportunistic_encrypt(msg); 2049 } 2050 } 2051 2052 /* No permissible mechanisms found. Don't sign or encrypt. */ 2053 if (!(msg->security & (APPLICATION_SMIME|APPLICATION_PGP))) 2054 msg->security = 0; 2055 } 2056 2057 /* Deal with the corner case where the crypto module backend is not available. 2058 * This can happen if configured without pgp/smime and with gpgme, but 2059 * $crypt_use_gpgme is unset. 2060 */ 2061 if (msg->security && 2062 !crypt_has_module_backend (msg->security)) 2063 { 2064 mutt_error _("No crypto backend configured. Disabling message security setting."); 2065 mutt_sleep (1); 2066 msg->security = 0; 2067 } 2068 2069 /* specify a default fcc. if we are in batchmode, only save a copy of 2070 * the message if the value of $copy is yes or ask-yes */ 2071 2072 if (!mutt_buffer_len (fcc) && 2073 !(flags & (SENDPOSTPONEDFCC)) && 2074 (!(flags & SENDBATCH) || (quadoption (OPT_COPY) & 0x1))) 2075 { 2076 /* set the default FCC */ 2077 if (!msg->env->from) 2078 { 2079 msg->env->from = mutt_default_from (); 2080 killfrom = 1; /* no need to check $use_from because if the user specified 2081 a from address it would have already been set by now */ 2082 } 2083 mutt_select_fcc (fcc, msg); 2084 if (killfrom) 2085 { 2086 rfc822_free_address (&msg->env->from); 2087 killfrom = 0; 2088 } 2089 } 2090 2091 2092 mutt_rfc3676_space_stuff (msg); 2093 2094 mutt_update_encoding (msg->content); 2095 2096 if (! (flags & (SENDMAILX | SENDBATCH))) 2097 { 2098main_loop: 2099 2100 mutt_buffer_pretty_mailbox (fcc); 2101 i = mutt_compose_menu (msg, fcc, cur, 2102 (flags & SENDNOFREEHEADER ? MUTT_COMPOSE_NOFREEHEADER : 0)); 2103 if (i == -1) 2104 { 2105 /* abort */ 2106 mutt_message _("Mail not sent."); 2107 goto cleanup; 2108 } 2109 else if (i == 1) 2110 { 2111 if (postpone_message (msg, cur, mutt_b2s (fcc), flags) != 0) 2112 goto main_loop; 2113 mutt_message _("Message postponed."); 2114 rv = 1; 2115 goto cleanup; 2116 } 2117 } 2118 2119 if (!has_recips (msg->env->to) && !has_recips (msg->env->cc) && 2120 !has_recips (msg->env->bcc)) 2121 { 2122 if (! (flags & SENDBATCH)) 2123 { 2124 mutt_error _("No recipients are specified!"); 2125 goto main_loop; 2126 } 2127 else 2128 { 2129 puts _("No recipients were specified."); 2130 goto cleanup; 2131 } 2132 } 2133 2134 if (mutt_env_to_intl (msg->env, &tag, &err)) 2135 { 2136 mutt_error (_("Bad IDN in \"%s\": '%s'"), tag, err); 2137 FREE (&err); 2138 if (!(flags & SENDBATCH)) 2139 goto main_loop; 2140 else 2141 goto cleanup; 2142 } 2143 2144 if (!msg->env->subject && ! (flags & SENDBATCH) && 2145 (i = query_quadoption (OPT_SUBJECT, _("No subject, abort sending?"))) != MUTT_NO) 2146 { 2147 /* if the abort is automatic, print an error message */ 2148 if (quadoption (OPT_SUBJECT) == MUTT_YES) 2149 mutt_error _("No subject specified."); 2150 goto main_loop; 2151 } 2152 2153 /* Scan for a mention of an attachment in the message body and 2154 * prompt if there is none. */ 2155 if (!(flags & SENDBATCH) && 2156 (quadoption (OPT_ABORTNOATTACH) != MUTT_NO) && 2157 AbortNoattachRegexp.pattern && 2158 !msg->content->next && 2159 (msg->content->type == TYPETEXT) && 2160 !ascii_strcasecmp (msg->content->subtype, "plain") && 2161 has_attach_keyword (msg->content->filename)) 2162 { 2163 if (query_quadoption (OPT_ABORTNOATTACH, _("No attachments, abort sending?")) != MUTT_NO) 2164 { 2165 if (quadoption (OPT_ABORTNOATTACH) == MUTT_YES) 2166 mutt_error _("Attachment referenced in message is missing"); 2167 goto main_loop; 2168 } 2169 } 2170 2171 if (generate_multipart_alternative (msg, flags)) 2172 { 2173 if (!(flags & SENDBATCH)) 2174 goto main_loop; 2175 else 2176 goto cleanup; 2177 } 2178 2179 if (msg->content->next) 2180 msg->content = mutt_make_multipart_mixed (msg->content); 2181 2182 /* 2183 * Ok, we need to do it this way instead of handling all fcc stuff in 2184 * one place in order to avoid going to main_loop with encoded "env" 2185 * in case of error. Ugh. 2186 */ 2187 2188 mutt_encode_descriptions (msg->content, 1); 2189 2190 /* 2191 * Make sure that clear_content and free_clear_content are 2192 * properly initialized -- we may visit this particular place in 2193 * the code multiple times, including after a failed call to 2194 * mutt_protect(). 2195 */ 2196 2197 clear_content = NULL; 2198 free_clear_content = 0; 2199 2200 if (WithCrypto) 2201 { 2202 if (msg->security & (ENCRYPT | SIGN | AUTOCRYPT)) 2203 { 2204 /* save the decrypted attachments */ 2205 clear_content = msg->content; 2206 2207 if ((crypt_get_keys (msg, &pgpkeylist, 0) == -1) || 2208 mutt_protect (msg, pgpkeylist, 0) == -1) 2209 { 2210 msg->content = mutt_remove_multipart_mixed (msg->content); 2211 msg->content = mutt_remove_multipart_alternative (msg->content); 2212 2213 FREE (&pgpkeylist); 2214 2215 decode_descriptions (msg->content); 2216 goto main_loop; 2217 } 2218 mutt_encode_descriptions (msg->content, 0); 2219 } 2220 2221 /* 2222 * at this point, msg->content is one of the following three things: 2223 * - multipart/signed. In this case, clear_content is a child. 2224 * - multipart/encrypted. In this case, clear_content exists 2225 * independently 2226 * - application/pgp. In this case, clear_content exists independently. 2227 * - something else. In this case, it's the same as clear_content. 2228 */ 2229 2230 /* This is ugly -- lack of "reporting back" from mutt_protect(). */ 2231 2232 if (clear_content && (msg->content != clear_content) 2233 && (msg->content->parts != clear_content)) 2234 free_clear_content = 1; 2235 } 2236 2237 if (!option (OPTNOCURSES) && !(flags & SENDMAILX)) 2238 mutt_message _("Sending message..."); 2239 2240 mutt_prepare_envelope (msg->env, 1); 2241 2242 if (option (OPTFCCBEFORESEND)) 2243 save_fcc (msg, fcc, clear_content, pgpkeylist, flags); 2244 2245 if ((i = send_message (msg)) < 0) 2246 { 2247 if (!(flags & SENDBATCH)) 2248 { 2249 if (!WithCrypto) 2250 ; 2251 else if ((msg->security & (ENCRYPT | AUTOCRYPT)) || 2252 ((msg->security & SIGN) 2253 && msg->content->type == TYPEAPPLICATION)) 2254 { 2255 mutt_free_body (&msg->content); /* destroy PGP data */ 2256 msg->content = clear_content; /* restore clear text. */ 2257 } 2258 else if ((msg->security & SIGN) && 2259 msg->content->type == TYPEMULTIPART && 2260 !ascii_strcasecmp (msg->content->subtype, "signed")) 2261 { 2262 mutt_free_body (&msg->content->parts->next); /* destroy sig */ 2263 msg->content = mutt_remove_multipart (msg->content); 2264 } 2265 2266 FREE (&pgpkeylist); 2267 mutt_free_envelope (&msg->content->mime_headers); /* protected headers */ 2268 msg->content = mutt_remove_multipart_mixed (msg->content); 2269 msg->content = mutt_remove_multipart_alternative (msg->content); 2270 decode_descriptions (msg->content); 2271 mutt_unprepare_envelope (msg->env); 2272 goto main_loop; 2273 } 2274 else 2275 { 2276 puts _("Could not send the message."); 2277 goto cleanup; 2278 } 2279 } 2280 2281 if (!option (OPTFCCBEFORESEND)) 2282 save_fcc (msg, fcc, clear_content, pgpkeylist, flags); 2283 2284 if (!option (OPTNOCURSES) && ! (flags & SENDMAILX)) 2285 { 2286 mutt_message (i == 0 ? _("Mail sent.") : _("Sending in background.")); 2287 mutt_sleep (0); 2288 } 2289 2290 2291 if (WithCrypto) 2292 FREE (&pgpkeylist); 2293 2294 if (WithCrypto && free_clear_content) 2295 mutt_free_body (&clear_content); 2296 2297 /* set 'replied' flag only if the user didn't change/remove 2298 In-Reply-To: and References: headers during edit */ 2299 if (flags & SENDREPLY) 2300 { 2301 if (cur && ctx) 2302 mutt_set_flag (ctx, cur, MUTT_REPLIED, is_reply (cur, msg)); 2303 else if (!(flags & SENDPOSTPONED) && ctx && ctx->tagged) 2304 { 2305 for (i = 0; i < ctx->vcount; i++) 2306 if (ctx->hdrs[ctx->v2r[i]]->tagged) 2307 mutt_set_flag (ctx, ctx->hdrs[ctx->v2r[i]], MUTT_REPLIED, 2308 is_reply (ctx->hdrs[ctx->v2r[i]], msg)); 2309 } 2310 } 2311 2312 2313 rv = 0; 2314 2315cleanup: 2316 mutt_buffer_free (&fcc); 2317 2318 if (flags & SENDPOSTPONED) 2319 { 2320 if (WithCrypto & APPLICATION_PGP) 2321 { 2322 FREE (&PgpSignAs); 2323 PgpSignAs = pgp_signas; 2324 } 2325 if (WithCrypto & APPLICATION_SMIME) 2326 { 2327 FREE (&SmimeSignAs); 2328 SmimeSignAs = smime_signas; 2329 } 2330 } 2331 2332 safe_fclose (&tempfp); 2333 if (! (flags & SENDNOFREEHEADER)) 2334 mutt_free_header (&msg); 2335 2336 return rv; 2337} 2338 2339/* vim: set sw=2: */