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