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