mutt stable branch with some hacks
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: */