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