More string and buffer functions.
[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-mx/mx.h>
17
18 #include "alias.h"
19 #include "keymap.h"
20 #include "copy.h"
21 #include "crypt.h"
22 #include "mutt_idna.h"
23 #include "attach.h"
24
25 int url_parse_mailto(ENVELOPE *e, char **body, const char *src)
26 {
27     char *t;
28     char *tmp;
29     char *headers;
30     char *tag, *value;
31     char scratch[HUGE_STRING];
32
33     int taglen;
34
35     string_list_t **last = &e->userhdrs;
36
37     if (!(t = strchr (src, ':')))
38         return -1;
39
40     if ((tmp = m_strdup(t + 1)) == NULL)
41         return -1;
42
43     if ((headers = strchr (tmp, '?')))
44         *headers++ = '\0';
45
46     url_decode(tmp);
47     e->to = rfc822_parse_adrlist(e->to, tmp);
48
49     tag = headers ? strtok (headers, "&") : NULL;
50
51     for (; tag; tag = strtok(NULL, "&")) {
52         if ((value = strchr (tag, '=')))
53             *value++ = '\0';
54         if (!value || !*value)
55             continue;
56
57         url_decode (tag);
58         url_decode (value);
59
60         if (mime_which_token(tag, -1) == MIME_BODY) {
61             if (body)
62                 m_strreplace(body, value);
63         } else {
64 #define SAFEPFX (option(OPTSTRICTMAILTO) ? "" : "X-Mailto-")
65             taglen = m_strlen(tag) + strlen(SAFEPFX);
66             /* mutt_parse_rfc822_line makes some assumptions */
67             snprintf(scratch, sizeof(scratch), "%s%s: %s", SAFEPFX, tag, value);
68 #undef SAVEPFX
69             scratch[taglen] = '\0';
70             value = vskipspaces(&scratch[taglen + 1]);
71             last  = mutt_parse_rfc822_line (e, NULL, scratch, value, 0, 0, last);
72             /* if $strict_mailto is set, force editing headers to let
73              * users have a look at what we got */
74             if (!option (OPTSTRICTMAILTO)) {
75                 set_option (OPTXMAILTO);
76                 set_option (OPTEDITHDRS);
77             }
78         }
79     }
80
81     p_delete(&tmp);
82     return 0;
83 }
84 static void append_signature (FILE * f)
85 {
86   FILE *tmpfp;
87   pid_t thepid;
88
89   if (SignOffString) {
90     fprintf (f, "\n%s", SignOffString);
91   }
92
93   if ((tmpfp = mutt_open_read(NONULL(MAlias.signature), &thepid))) {
94     if (option (OPTSIGDASHES))
95       fputs ("\n-- \n", f);
96     else if (SignOffString)
97       fputs ("\n", f);
98     mutt_copy_stream (tmpfp, f);
99     m_fclose(&tmpfp);
100     if (thepid != -1)
101       mutt_wait_filter (thepid);
102   }
103 }
104
105 /* compare two e-mail addresses and return 1 if they are equivalent */
106 static int mutt_addrcmp (address_t * a, address_t * b)
107 {
108   if (!a->mailbox || !b->mailbox)
109     return 0;
110   if (ascii_strcasecmp (a->mailbox, b->mailbox))
111     return 0;
112   return 1;
113 }
114
115 /* search an e-mail address in a list */
116 static int mutt_addrsrc (address_t * a, address_t * lst)
117 {
118   for (; lst; lst = lst->next) {
119     if (mutt_addrcmp (a, lst))
120       return 1;
121   }
122   return 0;
123 }
124
125 /* removes addresses from "b" which are contained in "a" */
126 static address_t *mutt_remove_xrefs (address_t * a, address_t * b)
127 {
128   address_t *top, *p, *prev = NULL;
129
130   top = b;
131   while (b) {
132     for (p = a; p; p = p->next) {
133       if (mutt_addrcmp (p, b))
134         break;
135     }
136     if (p) {
137       if (prev) {
138         prev->next = b->next;
139         b->next = NULL;
140         address_list_wipe(&b);
141         b = prev;
142       }
143       else {
144         top = top->next;
145         b->next = NULL;
146         address_list_wipe(&b);
147         b = top;
148       }
149     }
150     else {
151       prev = b;
152       b = b->next;
153     }
154   }
155   return top;
156 }
157
158 /* remove any address which matches the current user.  if `leave_only' is
159  * nonzero, don't remove the user's address if it is the only one in the list
160  */
161 static address_t *remove_user (address_t * a, int leave_only)
162 {
163   address_t *top = NULL, *last = NULL;
164
165   while (a) {
166     if (!mutt_addr_is_user (a)) {
167       if (top) {
168         last->next = a;
169         last = last->next;
170       }
171       else
172         last = top = a;
173       a = a->next;
174       last->next = NULL;
175     }
176     else {
177       address_t *tmp = a;
178
179       a = a->next;
180       if (!leave_only || a || last) {
181         tmp->next = NULL;
182         address_list_wipe(&tmp);
183       }
184       else
185         last = top = tmp;
186     }
187   }
188   return top;
189 }
190
191 static address_t *find_mailing_lists (address_t * t, address_t * c)
192 {
193   address_t *top = NULL, *ptr = NULL;
194
195   for (; t || c; t = c, c = NULL) {
196     for (; t; t = t->next) {
197       if (mutt_is_mail_list (t) && !t->group) {
198         if (top) {
199           ptr->next = address_dup (t);
200           ptr = ptr->next;
201         }
202         else
203           ptr = top = address_dup (t);
204       }
205     }
206   }
207   return top;
208 }
209
210 static int edit_address (address_t ** a, const char *field)
211 {
212   char buf[HUGE_STRING];
213   char *err = NULL;
214   int idna_ok = 0;
215
216   do {
217     buf[0] = 0;
218     mutt_addrlist_to_local (*a);
219     rfc822_addrcat(buf, sizeof(buf), *a, 0);
220     if (mutt_get_field (field, buf, sizeof (buf), M_ALIAS) != 0)
221       return -1;
222     address_list_wipe(a);
223     *a = mutt_expand_aliases (mutt_parse_adrlist (NULL, buf));
224     if ((idna_ok = mutt_addrlist_to_idna (*a, &err)) != 0) {
225       mutt_error (_("Error: '%s' is a bad IDN."), err);
226       mutt_refresh ();
227       mutt_sleep (2);
228       p_delete(&err);
229     }
230   }
231   while (idna_ok != 0);
232   return 0;
233 }
234
235 static int edit_envelope (ENVELOPE * en, int flags)
236 {
237   char buf[HUGE_STRING];
238   string_list_t *uh = UserHeader;
239   regmatch_t pat_match[1];
240
241   if (edit_address (&en->to, "To: ") == -1 || en->to == NULL)
242     return -1;
243   if (option (OPTASKCC) && edit_address (&en->cc, "Cc: ") == -1)
244     return -1;
245   if (option (OPTASKBCC) && edit_address (&en->bcc, "Bcc: ") == -1)
246     return -1;
247
248   if (en->subject) {
249     if (option (OPTFASTREPLY))
250       return 0;
251     else
252       m_strcpy(buf, sizeof(buf), en->subject);
253   }
254   else {
255     char *p;
256
257     buf[0] = 0;
258     for (; uh; uh = uh->next) {
259       if (ascii_strncasecmp ("subject:", uh->data, 8) == 0) {
260         p = vskipspaces(uh->data + 8);
261         m_strcpy(buf, sizeof(buf), p);
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       mutt_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   m_strreplace(&en->subject, buf);
292
293   return 0;
294 }
295
296 static void process_user_recips (ENVELOPE * env)
297 {
298     string_list_t *uh = UserHeader;
299
300     for (; uh; uh = uh->next) {
301         const char *p = strchr(uh->data, ':');
302         if (!p)
303             continue;
304
305         switch (mime_which_token(uh->data, p++ - uh->data)) {
306           case MIME_TO:
307             env->to = rfc822_parse_adrlist(env->to, p);
308             break;
309           case MIME_CC:
310             env->cc = rfc822_parse_adrlist(env->cc, p);
311             break;
312           case MIME_BCC:
313             env->bcc = rfc822_parse_adrlist(env->bcc, p);
314             break;
315           default: break;
316         }
317     }
318 }
319
320 static void process_user_header(ENVELOPE * env)
321 {
322     string_list_t *uh;
323     string_list_t **last = string_list_last(&env->userhdrs);
324
325     for (uh = UserHeader; uh; uh = uh->next) {
326         const char *p = strchr(uh->data, ':');
327         if (!p)
328           continue;
329
330         switch (mime_which_token(uh->data, p++ - uh->data)) {
331           case MIME_FROM:
332             /* User has specified a default From: address.  Remove default address */
333             address_list_wipe(&env->from);
334             env->from = rfc822_parse_adrlist(env->from, p);
335             break;
336
337           case MIME_REPLY_TO:
338             address_list_wipe(&env->reply_to);
339             env->reply_to = rfc822_parse_adrlist (env->reply_to, p);
340             break;
341
342           case MIME_MESSAGE_ID:
343             m_strreplace(&env->message_id, p);
344             break;
345
346           case MIME_TO:
347           case MIME_CC:
348           case MIME_BCC:
349           case MIME_SUPERSEDES:
350           case MIME_SUPERCEDES:
351           case MIME_SUBJECT:
352             break;
353
354           default:
355             *last = string_item_new();
356             (*last)->data = m_strdup(uh->data);
357             last = &(*last)->next;
358             break;
359         }
360     }
361 }
362
363 void mutt_forward_intro (FILE * fp, HEADER * cur)
364 {
365   char buffer[STRING];
366
367   fputs ("----- Forwarded message from ", fp);
368   buffer[0] = 0;
369   rfc822_addrcat(buffer, sizeof(buffer), cur->env->from, 1);
370   fputs (buffer, fp);
371   fputs (" -----\n\n", fp);
372 }
373
374 void mutt_forward_trailer (FILE * fp)
375 {
376   fputs ("\n----- End forwarded message -----\n", fp);
377 }
378
379
380 static int include_forward (CONTEXT * ctx, HEADER * cur, FILE * out)
381 {
382   int chflags = CH_DECODE, cmflags = 0;
383
384   mutt_parse_mime_message (ctx, cur);
385   mutt_message_hook (ctx, cur, M_MESSAGEHOOK);
386
387   mutt_forward_intro (out, cur);
388
389   if (option (OPTFORWDECODE)) {
390     cmflags |= M_CM_DECODE | M_CM_CHARCONV;
391     if (option (OPTWEED)) {
392       chflags |= CH_WEED | CH_REORDER;
393       cmflags |= M_CM_WEED;
394     }
395   }
396   if (option (OPTFORWQUOTE))
397     cmflags |= M_CM_PREFIX;
398
399   mutt_copy_message (out, ctx, cur, cmflags, chflags);
400   mutt_forward_trailer (out);
401   return 0;
402 }
403
404 void mutt_make_attribution (CONTEXT * ctx, HEADER * cur, FILE * out)
405 {
406   char buffer[STRING];
407
408   if (Attribution) {
409     mutt_make_string (buffer, sizeof (buffer), Attribution, ctx, cur);
410     fputs (buffer, out);
411     fputc ('\n', out);
412   }
413 }
414
415 static int include_reply (CONTEXT * ctx, HEADER * cur, FILE * out)
416 {
417   int cmflags = M_CM_PREFIX | M_CM_DECODE | M_CM_CHARCONV | M_CM_REPLYING;
418   int chflags = CH_DECODE;
419
420   mutt_parse_mime_message (ctx, cur);
421   mutt_message_hook (ctx, cur, M_MESSAGEHOOK);
422   mutt_make_attribution (ctx, cur, out);
423
424   if (!option (OPTHEADER))
425     cmflags |= M_CM_NOHEADER;
426   if (option (OPTWEED)) {
427     chflags |= CH_WEED | CH_REORDER;
428     cmflags |= M_CM_WEED;
429   }
430
431   mutt_copy_message (out, ctx, cur, cmflags, chflags);
432   return 0;
433 }
434
435 static int default_to (address_t ** to, ENVELOPE * env, int flags, int hmfupto)
436 {
437   char prompt[STRING];
438
439   if (flags && env->mail_followup_to && hmfupto == M_YES) {
440     address_list_append(to, address_list_dup(env->mail_followup_to));
441     return 0;
442   }
443
444   /* Exit now if we're setting up the default Cc list for list-reply
445    * (only set if Mail-Followup-To is present and honoured).
446    */
447   if (flags & SENDLISTREPLY)
448     return 0;
449
450   /* If this message came from a mailing list, ask the user if he really
451    * intended to reply to the author only.
452    */
453   if (!(flags & SENDGROUPREPLY) && mutt_is_list_cc (0, env->to, env->cc)) {
454     switch (query_quadoption (OPT_LISTREPLY,
455                               _("Message came from a mailing list. List-reply to mailing list?")))
456     {
457     case M_YES:
458       address_list_append(to, find_mailing_lists (env->to, env->cc));
459       return 0;
460     case -1:
461       return -1;                /* abort */
462     }
463   }
464
465   if (mutt_addr_is_user(env->from)) {
466     /* mail is from the user, assume replying to recipients */
467     address_list_append(to, address_list_dup(env->to));
468   }
469   else if (env->reply_to) {
470     if ((mutt_addrcmp (env->from, env->reply_to) && !env->reply_to->next) ||
471         (option (OPTIGNORELISTREPLYTO) &&
472          mutt_is_mail_list (env->reply_to) &&
473          (mutt_addrsrc (env->reply_to, env->to) ||
474           mutt_addrsrc (env->reply_to, env->cc)))) {
475       /* If the Reply-To: address is a mailing list, assume that it was
476        * put there by the mailing list, and use the From: address
477        * 
478        * We also take the from header if our correspondant has a reply-to
479        * header which is identical to the electronic mail address given
480        * in his From header.
481        * 
482        */
483       address_list_append(to, address_list_dup(env->from));
484     }
485     else if (!(mutt_addrcmp (env->from, env->reply_to) &&
486                !env->reply_to->next) && quadoption (OPT_REPLYTO) != M_YES) {
487       /* There are quite a few mailing lists which set the Reply-To:
488        * header field to the list address, which makes it quite impossible
489        * to send a message to only the sender of the message.  This
490        * provides a way to do that.
491        */
492       snprintf (prompt, sizeof (prompt), _("Reply to %s%s?"),
493                 env->reply_to->mailbox, env->reply_to->next ? ",..." : "");
494       switch (query_quadoption (OPT_REPLYTO, prompt)) {
495       case M_YES:
496         address_list_append(to, address_list_dup(env->reply_to));
497         break;
498
499       case M_NO:
500         address_list_append(to, address_list_dup(env->from));
501         break;
502
503       default:
504         return -1;            /* abort */
505       }
506     }
507     else
508       address_list_append(to, address_list_dup(env->reply_to));
509   }
510   else
511     address_list_append(to, address_list_dup(env->from));
512
513   return 0;
514 }
515
516 int mutt_fetch_recips (ENVELOPE * out, ENVELOPE * in, int flags)
517 {
518   char prompt[STRING];
519   int hmfupto = -1;
520
521   if ((flags & (SENDLISTREPLY | SENDGROUPREPLY)) && in->mail_followup_to) {
522     snprintf (prompt, sizeof (prompt), _("Follow-up to %s%s?"),
523               in->mail_followup_to->mailbox,
524               in->mail_followup_to->next ? ",..." : "");
525
526     if ((hmfupto = query_quadoption (OPT_MFUPTO, prompt)) == -1)
527       return -1;
528   }
529
530   if (flags & SENDLISTREPLY) {
531     address_list_append(&out->to, find_mailing_lists(in->to, in->cc));
532
533     if (in->mail_followup_to && hmfupto == M_YES &&
534         default_to (&out->cc, in, flags & SENDLISTREPLY, hmfupto) == -1)
535       return -1;              /* abort */
536   }
537   else {
538     if (default_to (&out->to, in, flags & SENDGROUPREPLY, hmfupto) == -1)
539       return -1;              /* abort */
540
541     if ((flags & SENDGROUPREPLY)
542         && (!in->mail_followup_to || hmfupto != M_YES))
543     {
544       address_t **tmp = address_list_append(&out->cc, address_list_dup(in->to));
545       address_list_append(tmp, address_list_dup(in->cc));
546     }
547   }
548   return 0;
549 }
550
551 void mutt_fix_reply_recipients (ENVELOPE * env)
552 {
553   mutt_expand_aliases_env (env);
554
555   if (!option (OPTMETOO)) {
556     /* the order is important here.  do the CC: first so that if the
557      * the user is the only recipient, it ends up on the TO: field
558      */
559     env->cc = remove_user (env->cc, (env->to == NULL));
560     env->to = remove_user (env->to, (env->cc == NULL));
561   }
562
563   /* the CC field can get cluttered, especially with lists */
564   address_list_uniq(env->to);
565   address_list_uniq(env->cc);
566   env->cc = mutt_remove_xrefs (env->to, env->cc);
567
568   if (env->cc && !env->to) {
569     env->to = env->cc;
570     env->cc = NULL;
571   }
572 }
573
574 void mutt_make_forward_subject (ENVELOPE * env, CONTEXT * ctx, HEADER * cur)
575 {
576   char buffer[STRING];
577
578   /* set the default subject for the message. */
579   mutt_make_string (buffer, sizeof (buffer), NONULL (ForwFmt), ctx, cur);
580   m_strreplace(&env->subject, buffer);
581 }
582
583 void mutt_make_misc_reply_headers (ENVELOPE * env,
584                                    CONTEXT * ctx __attribute__ ((unused)),
585                                    HEADER * cur __attribute__ ((unused)),
586                                    ENVELOPE * curenv)
587 {
588   /* This takes precedence over a subject that might have
589    * been taken from a List-Post header.  Is that correct?
590    */
591   if (curenv->real_subj) {
592     p_delete(&env->subject);
593     env->subject = p_new(char, m_strlen(curenv->real_subj) + 5);
594     sprintf (env->subject, "Re: %s", curenv->real_subj);
595   }
596   else if (!env->subject)
597     env->subject = m_strdup("Re: your mail");
598 }
599
600 static string_list_t *mutt_make_references (ENVELOPE * e)
601 {
602   string_list_t *t = NULL, *l = NULL;
603
604   if (e->references)
605     l = string_list_dup(e->references);
606   else
607     l = string_list_dup(e->in_reply_to);
608
609   if (e->message_id) {
610     t = string_item_new();
611     t->data = m_strdup(e->message_id);
612     t->next = l;
613     l = t;
614   }
615
616   return l;
617 }
618
619 void mutt_add_to_reference_headers (ENVELOPE * env, ENVELOPE * curenv,
620                                     string_list_t *** pp, string_list_t *** qq)
621 {
622   string_list_t **p = NULL, **q = NULL;
623
624   if (pp)
625     p = *pp;
626   if (qq)
627     q = *qq;
628
629   if (!p)
630     p = &env->references;
631   if (!q)
632     q = &env->in_reply_to;
633
634   while (*p)
635     p = &(*p)->next;
636   while (*q)
637     q = &(*q)->next;
638
639   *p = mutt_make_references (curenv);
640
641   if (curenv->message_id) {
642     *q = string_item_new();
643     (*q)->data = m_strdup(curenv->message_id);
644   }
645
646   if (pp)
647     *pp = p;
648   if (qq)
649     *qq = q;
650
651 }
652
653 static void
654 mutt_make_reference_headers (ENVELOPE * curenv, ENVELOPE * env, CONTEXT * ctx)
655 {
656   env->references = NULL;
657   env->in_reply_to = NULL;
658
659   if (!curenv) {
660     HEADER *h;
661     string_list_t **p = NULL, **q = NULL;
662     int i;
663
664     for (i = 0; i < ctx->vcount; i++) {
665       h = ctx->hdrs[ctx->v2r[i]];
666       if (h->tagged)
667         mutt_add_to_reference_headers (env, h->env, &p, &q);
668     }
669   }
670   else
671     mutt_add_to_reference_headers (env, curenv, NULL, NULL);
672 }
673
674 static int
675 envelope_defaults (ENVELOPE * env, CONTEXT * ctx, HEADER * cur, int flags)
676 {
677   ENVELOPE *curenv = NULL;
678   int i = 0, tag = 0;
679
680   if (!cur) {
681     tag = 1;
682     for (i = 0; i < ctx->vcount; i++)
683       if (ctx->hdrs[ctx->v2r[i]]->tagged) {
684         cur = ctx->hdrs[ctx->v2r[i]];
685         curenv = cur->env;
686         break;
687       }
688
689     if (!cur) {
690       /* This could happen if the user tagged some messages and then did
691        * a limit such that none of the tagged message are visible.
692        */
693       mutt_error _("No tagged messages are visible!");
694
695       return -1;
696     }
697   }
698   else
699     curenv = cur->env;
700
701   if (flags & SENDREPLY) {
702     if (tag) {
703       HEADER *h;
704
705       for (i = 0; i < ctx->vcount; i++) {
706         h = ctx->hdrs[ctx->v2r[i]];
707         if (h->tagged && mutt_fetch_recips (env, h->env, flags) == -1)
708           return -1;
709       }
710     }
711     else if (mutt_fetch_recips (env, curenv, flags) == -1)
712       return -1;
713
714     if ((flags & SENDLISTREPLY) && !env->to) {
715       mutt_error _("No mailing lists found!");
716
717       return -1;
718     }
719
720     mutt_make_misc_reply_headers (env, ctx, cur, curenv);
721     mutt_make_reference_headers (tag ? NULL : curenv, env, ctx);
722   }
723   else if (flags & SENDFORWARD)
724     mutt_make_forward_subject (env, ctx, cur);
725
726   return 0;
727 }
728
729 static int generate_body (FILE * tempfp,        /* stream for outgoing message */
730                           HEADER * msg, /* header for outgoing message */
731                           int flags,    /* compose mode */
732                           CONTEXT * ctx,        /* current mailbox */
733                           HEADER * cur)
734 {                               /* current message */
735   int i;
736   HEADER *h;
737   BODY *tmp;
738
739   if (flags & SENDREPLY) {
740     if ((i =
741          query_quadoption (OPT_INCLUDE,
742                            _("Include message in reply?"))) == -1)
743       return -1;
744
745     if (i == M_YES) {
746       mutt_message _("Including quoted message...");
747
748       if (!cur) {
749         for (i = 0; i < ctx->vcount; i++) {
750           h = ctx->hdrs[ctx->v2r[i]];
751           if (h->tagged) {
752             if (include_reply (ctx, h, tempfp) == -1) {
753               mutt_error _("Could not include all requested messages!");
754
755               return -1;
756             }
757             fputc ('\n', tempfp);
758           }
759         }
760       }
761       else
762         include_reply (ctx, cur, tempfp);
763
764     }
765   }
766   else if (flags & SENDFORWARD) {
767     if ((i =
768          query_quadoption (OPT_MIMEFWD,
769                            _("Forward as attachment?"))) == M_YES) {
770       BODY *last = msg->content;
771
772       mutt_message _("Preparing forwarded message...");
773
774       while (last && last->next)
775         last = last->next;
776
777       if (cur) {
778         tmp = mutt_make_message_attach (ctx, cur, 0);
779         if (last)
780           last->next = tmp;
781         else
782           msg->content = tmp;
783       }
784       else {
785         for (i = 0; i < ctx->vcount; i++) {
786           if (ctx->hdrs[ctx->v2r[i]]->tagged) {
787             tmp = mutt_make_message_attach (ctx, ctx->hdrs[ctx->v2r[i]], 0);
788             if (last) {
789               last->next = tmp;
790               last = tmp;
791             }
792             else
793               last = msg->content = tmp;
794           }
795         }
796       }
797     }
798     else if (i != -1) {
799       if (cur)
800         include_forward (ctx, cur, tempfp);
801       else
802         for (i = 0; i < ctx->vcount; i++)
803           if (ctx->hdrs[ctx->v2r[i]]->tagged)
804             include_forward (ctx, ctx->hdrs[ctx->v2r[i]], tempfp);
805     }
806     else if (i == -1)
807       return -1;
808   }
809
810   mutt_clear_error ();
811
812   return 0;
813 }
814
815 void mutt_set_followup_to (ENVELOPE * e)
816 {
817     /*
818      * Only generate the Mail-Followup-To if the user has requested it, and
819      * it hasn't already been set
820      */
821     if (!option(OPTFOLLOWUPTO))
822         return;
823
824     if (e->mail_followup_to)
825         return;
826
827     if (mutt_is_list_cc (0, e->to, e->cc)) {
828         address_t **tmp;
829
830         /*
831          * this message goes to known mailing lists, so create a proper
832          * mail-followup-to header
833          */
834         tmp = address_list_append(&e->mail_followup_to, address_list_dup(e->to));
835         address_list_append(tmp, address_list_dup(e->cc));
836     }
837
838     /* remove ourselves from the mail-followup-to header */
839     e->mail_followup_to = remove_user(e->mail_followup_to, 0);
840
841     /*
842      * If we are not subscribed to any of the lists in question,
843      * re-add ourselves to the mail-followup-to header.  The
844      * mail-followup-to header generated is a no-op with group-reply,
845      * but makes sure list-reply has the desired effect.
846      */
847     if (e->mail_followup_to && !mutt_is_list_recipient(0, e->to, e->cc)) {
848         address_t *from;
849
850         if (e->reply_to)
851             from = address_list_dup(e->reply_to);
852         else if (e->from)
853             from = address_list_dup(e->from);
854         else
855             from = mutt_default_from();
856
857         address_list_append(&from, e->mail_followup_to);
858         e->mail_followup_to = from;
859     }
860
861     address_list_uniq(e->mail_followup_to);
862 }
863
864
865 /* look through the recipients of the message we are replying to, and if
866    we find an address that matches $alternates, we use that as the default
867    from field */
868 static address_t *set_reverse_name (ENVELOPE * env)
869 {
870     address_t *tmp = NULL;
871
872     for (tmp = env->to; tmp; tmp = tmp->next) {
873         if (mutt_addr_is_user(tmp))
874             goto found;
875     }
876     for (tmp = env->cc; tmp; tmp = tmp->next) {
877         if (mutt_addr_is_user(tmp))
878             goto found;
879     }
880
881     if (!mutt_addr_is_user(env->from))
882         return NULL;
883
884     tmp = env->from;
885
886   found:
887     tmp = address_dup(tmp);
888     if (!option(OPTREVREAL) || !tmp->personal) {
889         p_delete(&tmp->personal);
890         tmp->personal = m_strdup(Realname);
891     }
892     return tmp;
893 }
894
895 address_t *mutt_default_from (void)
896 {
897   address_t *adr;
898
899   /*
900    * Note: We let $from override $realname here.
901    * Is this the right thing to do?
902    */
903
904   if (MAlias.from)
905     adr = address_dup(MAlias.from);
906   else if (mod_core.use_domain) {
907     const char *fqdn = mutt_fqdn (1);
908     adr = address_new();
909     adr->mailbox = p_new(char, m_strlen(mod_core.username) + m_strlen(fqdn) + 2);
910     sprintf(adr->mailbox, "%s@%s", NONULL(mod_core.username), NONULL(fqdn));
911   } else {
912     adr = address_new ();
913     adr->mailbox = m_strdup(NONULL(mod_core.username));
914   }
915
916   return adr;
917 }
918
919 static int send_message (HEADER * msg)
920 {
921   char tempfile[_POSIX_PATH_MAX];
922   FILE *tempfp;
923   int i;
924
925   /* Write out the message in MIME form. */
926   tempfp = m_tempfile(tempfile, sizeof(tempfile), NONULL(mod_core.tmpdir), NULL);
927   if (!tempfp)
928     return -1;
929
930   mutt_write_rfc822_header (tempfp, msg->env, msg->content, 0);
931   fputc ('\n', tempfp);         /* tie off the header. */
932
933   if ((mutt_write_mime_body (msg->content, tempfp) == -1)) {
934     m_fclose(&tempfp);
935     unlink (tempfile);
936     return -1;
937   }
938
939   if (m_fclose(&tempfp) != 0) {
940     mutt_perror (_("Can't create temporary file"));
941     unlink (tempfile);
942     return -1;
943   }
944
945   i = mutt_invoke_mta (msg->env->from, msg->env->to, msg->env->cc,
946                        msg->env->bcc, tempfile,
947                        (msg->content->encoding == ENC8BIT));
948   return i;
949 }
950
951 /* rfc2047 encode the content-descriptions */
952 static void encode_descriptions (BODY * b, short recurse)
953 {
954   BODY *t;
955
956   for (t = b; t; t = t->next) {
957     if (t->description) {
958       rfc2047_encode_string (&t->description);
959     }
960     if (recurse && t->parts)
961       encode_descriptions (t->parts, recurse);
962   }
963 }
964
965 /* rfc2047 decode them in case of an error */
966 static void decode_descriptions (BODY * b)
967 {
968   BODY *t;
969
970   for (t = b; t; t = t->next) {
971     if (t->description) {
972       rfc2047_decode (&t->description);
973     }
974     if (t->parts)
975       decode_descriptions (t->parts);
976   }
977 }
978
979 static void fix_end_of_file (const char *data)
980 {
981   FILE *fp;
982   int c;
983
984   if ((fp = safe_fopen (data, "a+")) == NULL)
985     return;
986   fseeko (fp, -1, SEEK_END);
987   if ((c = fgetc (fp)) != '\n')
988     fputc ('\n', fp);
989   m_fclose(&fp);
990 }
991
992 int mutt_resend_message (FILE * fp, CONTEXT * ctx, HEADER * cur)
993 {
994   HEADER *msg = header_new();
995
996   if (mutt_prepare_template (fp, ctx, msg, cur, option(OPTWEED)) < 0)
997     return -1;
998
999   return ci_send_message (SENDRESEND, msg, NULL, ctx, cur);
1000 }
1001
1002 int ci_send_message (int flags, /* send mode */
1003                      HEADER * msg,      /* template to use for new message */
1004                      char *tempfile,    /* file specified by -i or -H */
1005                      CONTEXT * ctx,     /* current mailbox */
1006                      HEADER * cur)
1007 {                               /* current message */
1008   char fcc[_POSIX_PATH_MAX] = "";       /* where to copy this message */
1009   FILE *tempfp = NULL;
1010   BODY *pbody;
1011   int i, killfrom = 0;
1012   int fcc_error = 0;
1013   int free_clear_content = 0;
1014
1015   BODY *save_content = NULL;
1016   BODY *clear_content = NULL;
1017   char *pgpkeylist = NULL;
1018
1019   /* save current value of "pgp_sign_as" */
1020   char *signas = NULL, *err = NULL;
1021   const char *tag = NULL;
1022   char *ctype;
1023
1024   int rv = -1;
1025
1026   if (!flags && !msg && quadoption (OPT_RECALL) != M_NO &&
1027       mutt_num_postponed (1)) {
1028     /* If the user is composing a new message, check to see if there
1029      * are any postponed messages first.
1030      */
1031     if ((i =
1032          query_quadoption (OPT_RECALL, _("Recall postponed message?"))) == -1)
1033       return rv;
1034
1035     if (i == M_YES)
1036       flags |= SENDPOSTPONED;
1037   }
1038
1039
1040   if (flags & SENDPOSTPONED)
1041     signas = m_strdup(PgpSignAs);
1042
1043   /* Delay expansion of aliases until absolutely necessary--shouldn't
1044    * be necessary unless we are prompting the user or about to execute a
1045    * send-hook.
1046    */
1047
1048   if (!msg) {
1049     msg = header_new();
1050
1051     if (flags == SENDPOSTPONED) {
1052       if ((flags =
1053            mutt_get_postponed (ctx, msg, &cur, fcc, sizeof (fcc))) < 0)
1054         goto cleanup;
1055     }
1056
1057     if (flags & (SENDPOSTPONED | SENDRESEND)) {
1058       if ((tempfp = safe_fopen (msg->content->filename, "a+")) == NULL) {
1059         mutt_perror (msg->content->filename);
1060         goto cleanup;
1061       }
1062     }
1063
1064     if (!msg->env)
1065       msg->env = envelope_new();
1066   }
1067
1068   /* Parse and use an eventual list-post header */
1069   if ((flags & SENDLISTREPLY)
1070       && cur && cur->env && cur->env->list_post) {
1071     /* Use any list-post header as a template */
1072     url_parse_mailto (msg->env, NULL, cur->env->list_post);
1073     /* We don't let them set the sender's address. */
1074     address_list_wipe(&msg->env->from);
1075   }
1076
1077   if (!(flags & (SENDPOSTPONED | SENDRESEND))) {
1078     pbody = body_new();
1079     pbody->next = msg->content; /* don't kill command-line attachments */
1080     msg->content = pbody;
1081
1082     if (!(ctype = m_strdup(ContentType)))
1083       ctype = m_strdup("text/plain");
1084     mutt_parse_content_type (ctype, msg->content);
1085     p_delete(&ctype);
1086
1087     msg->content->unlink = 1;
1088     msg->content->use_disp = 0;
1089     msg->content->disposition = DISPINLINE;
1090     if (option (OPTTEXTFLOWED) && msg->content->type == TYPETEXT
1091         && !ascii_strcasecmp (msg->content->subtype, "plain")) {
1092       parameter_setval(&msg->content->parameter, "format", "flowed");
1093       if (option (OPTDELSP))
1094         parameter_setval(&msg->content->parameter, "delsp", "yes");
1095     }
1096
1097     if (!tempfile) {
1098       char buffer[_POSIX_PATH_MAX];
1099       tempfp = m_tempfile(buffer, sizeof(buffer), NONULL(mod_core.tmpdir), NULL);
1100       msg->content->filename = m_strdup(buffer);
1101     } else {
1102       tempfp = safe_fopen(tempfile, "a+");
1103       msg->content->filename = m_strdup(tempfile);
1104     }
1105
1106     if (!tempfp) {
1107       mutt_perror (msg->content->filename);
1108       goto cleanup;
1109     }
1110   }
1111
1112   /* this is handled here so that the user can match ~f in send-hook */
1113   if (cur && option (OPTREVNAME) && !(flags & (SENDPOSTPONED | SENDRESEND))) {
1114     /* we shouldn't have to worry about freeing `msg->env->from' before
1115      * setting it here since this code will only execute when doing some
1116      * sort of reply.  the pointer will only be set when using the -H command
1117      * line option.
1118      *
1119      * We shouldn't have to worry about alias expansion here since we are
1120      * either replying to a real or postponed message, therefore no aliases
1121      * should exist since the user has not had the opportunity to add
1122      * addresses to the list.  We just have to ensure the postponed messages
1123      * have their aliases expanded.
1124      */
1125
1126     msg->env->from = set_reverse_name (cur->env);
1127   }
1128
1129   if (!msg->env->from && option (OPTUSEFROM)
1130       && !(flags & (SENDPOSTPONED | SENDRESEND)))
1131     msg->env->from = mutt_default_from ();
1132
1133   if (flags & SENDBATCH) {
1134     mutt_copy_stream (stdin, tempfp);
1135     process_user_recips (msg->env);
1136     process_user_header (msg->env);
1137     mutt_expand_aliases_env (msg->env);
1138   }
1139   else if (!(flags & (SENDPOSTPONED | SENDRESEND))) {
1140     if ((flags & (SENDREPLY | SENDFORWARD)) && ctx &&
1141         envelope_defaults (msg->env, ctx, cur, flags) == -1)
1142       goto cleanup;
1143
1144     process_user_recips (msg->env);
1145
1146     /* Expand aliases and remove duplicates/crossrefs */
1147     mutt_fix_reply_recipients (msg->env);
1148
1149     if (!(option (OPTAUTOEDIT) && option (OPTEDITHDRS)) &&
1150         !((flags & SENDREPLY) && option (OPTFASTREPLY))) {
1151       if (edit_envelope (msg->env, flags) == -1)
1152         goto cleanup;
1153     }
1154
1155     /* the from address must be set here regardless of whether or not
1156      * $use_from is set so that the `~P' (from you) operator in send-hook
1157      * patterns will work.  if $use_from is unset, the from address is killed
1158      * after send-hooks are evaulated */
1159
1160     if (!msg->env->from) {
1161       msg->env->from = mutt_default_from ();
1162       killfrom = 1;
1163     }
1164
1165     if ((flags & SENDREPLY) && cur) {
1166       /* change setting based upon message we are replying to */
1167       mutt_message_hook (ctx, cur, M_REPLYHOOK);
1168
1169       /*
1170        * set the replied flag for the message we are generating so that the
1171        * user can use ~Q in a send-hook to know when reply-hook's are also
1172        * being used.
1173        */
1174       msg->replied = 1;
1175     }
1176
1177     /* change settings based upon recipients */
1178
1179     mutt_message_hook (NULL, msg, M_SENDHOOK);
1180
1181     /*
1182      * Unset the replied flag from the message we are composing since it is
1183      * no longer required.  This is done here because the FCC'd copy of
1184      * this message was erroneously get the 'R'eplied flag when stored in
1185      * a maildir-style mailbox.
1186      */
1187     msg->replied = 0;
1188
1189     if (killfrom) {
1190       address_list_wipe(&msg->env->from);
1191       killfrom = 0;
1192     }
1193
1194     process_user_header (msg->env);
1195
1196     /* include replies/forwarded messages, unless we are given a template */
1197     if (!tempfile && (ctx || !(flags & (SENDREPLY | SENDFORWARD)))
1198         && generate_body (tempfp, msg, flags, ctx, cur) == -1)
1199       goto cleanup;
1200
1201     append_signature (tempfp);
1202
1203     /* 
1204      * this wants to be done _after_ generate_body, so message-hooks
1205      * can take effect.
1206      */
1207
1208     if (mod_crypt.autosign)
1209       msg->security |= SIGN;
1210     if (mod_crypt.autoencrypt)
1211       msg->security |= ENCRYPT;
1212     if (mod_crypt.replyencrypt && cur && (cur->security & ENCRYPT))
1213       msg->security |= ENCRYPT;
1214     if (mod_crypt.replysign && cur && (cur->security & SIGN))
1215       msg->security |= SIGN;
1216     if (mod_crypt.replysignencrypted && cur && (cur->security & ENCRYPT))
1217       msg->security |= SIGN;
1218
1219     if (msg->security) {
1220       /* 
1221        * When reypling / forwarding, use the original message's
1222        * crypto system.  According to the documentation,
1223        * smime_is_default should be disregarded here.
1224        * 
1225        * Problem: At least with forwarding, this doesn't really
1226        * make much sense. Should we have an option to completely
1227        * disable individual mechanisms at run-time?
1228        */
1229       if (cur) {
1230         if (mod_crypt.autopgp && (cur->security & APPLICATION_PGP))
1231           msg->security |= APPLICATION_PGP;
1232         else if (mod_crypt.autosmime && (cur->security & APPLICATION_SMIME))
1233           msg->security |= APPLICATION_SMIME;
1234       }
1235
1236       /*
1237        * No crypto mechanism selected? Use availability + smime_is_default
1238        * for the decision. 
1239        */
1240       if (!(msg->security & (APPLICATION_SMIME | APPLICATION_PGP))) {
1241         if (mod_crypt.autosmime && mod_crypt.smime_is_default)
1242           msg->security |= APPLICATION_SMIME;
1243         else if (mod_crypt.autopgp)
1244           msg->security |= APPLICATION_PGP;
1245         else if (mod_crypt.autosmime)
1246           msg->security |= APPLICATION_SMIME;
1247       }
1248     }
1249
1250     /* No permissible mechanisms found.  Don't sign or encrypt. */
1251     if (!(msg->security & (APPLICATION_SMIME | APPLICATION_PGP)))
1252       msg->security = 0;
1253   }
1254
1255   /* 
1256    * This hook is even called for postponed messages, and can, e.g., be
1257    * used for setting the editor, the sendmail path, or the
1258    * envelope sender.
1259    */
1260   mutt_message_hook (NULL, msg, M_SEND2HOOK);
1261
1262   /* wait until now to set the real name portion of our return address so
1263      that $realname can be set in a send-hook */
1264   if (msg->env->from && !msg->env->from->personal
1265       && !(flags & (SENDRESEND | SENDPOSTPONED)))
1266     msg->env->from->personal = m_strdup(Realname);
1267
1268   m_fclose(&tempfp);
1269
1270   if (!(flags & SENDBATCH)) {
1271     struct stat st;
1272     time_t mtime = m_decrease_mtime(msg->content->filename, NULL);
1273
1274     mutt_update_encoding (msg->content);
1275
1276     /*
1277      * Select whether or not the user's editor should be called now.  We
1278      * don't want to do this when:
1279      * 1) we are sending a key/cert
1280      * 2) we are forwarding a message and the user doesn't want to edit it.
1281      *    This is controled by the quadoption $forward_edit.  However, if
1282      *    both $edit_headers and $autoedit are set, we want to ignore the
1283      *    setting of $forward_edit because the user probably needs to add the
1284      *    recipients.
1285      */
1286     if (((flags & SENDFORWARD) == 0 ||
1287          (option (OPTEDITHDRS) && option (OPTAUTOEDIT)) ||
1288          query_quadoption (OPT_FORWEDIT,
1289                            _("Edit forwarded message?")) == M_YES))
1290     {
1291       /* If the this isn't a text message, look for a mailcap edit command */
1292       if (rfc1524_mailcap_isneeded(msg->content)) {
1293         if (!mutt_edit_attachment (msg->content))
1294           goto cleanup;
1295       } else if (option (OPTEDITHDRS)) {
1296         mutt_env_to_local (msg->env);
1297         mutt_edit_headers(msg->content->filename, msg, fcc, sizeof (fcc));
1298         mutt_env_to_idna (msg->env, NULL, NULL);
1299       }
1300       else {
1301         mutt_edit_file(msg->content->filename);
1302
1303         if (stat (msg->content->filename, &st) == 0) {
1304           if (mtime != st.st_mtime)
1305             fix_end_of_file (msg->content->filename);
1306         } else
1307           mutt_perror (msg->content->filename);
1308       }
1309
1310       if (option (OPTTEXTFLOWED))
1311         rfc3676_space_stuff (msg);
1312
1313       mutt_message_hook (NULL, msg, M_SEND2HOOK);
1314     }
1315
1316     if (!(flags & (SENDPOSTPONED | SENDFORWARD | SENDRESEND))) {
1317       if (stat (msg->content->filename, &st) == 0) {
1318         /* if the file was not modified, bail out now */
1319         if (mtime == st.st_mtime && !msg->content->next &&
1320             query_quadoption (OPT_ABORT,
1321                               _("Abort unmodified message?")) == M_YES) {
1322           mutt_message _("Aborted unmodified message.");
1323
1324           goto cleanup;
1325         }
1326       }
1327       else
1328         mutt_perror (msg->content->filename);
1329     }
1330   }
1331
1332   /* specify a default fcc.  if we are in batchmode, only save a copy of
1333    * the message if the value of $copy is yes or ask-yes */
1334
1335   if (!fcc[0] && !(flags & (SENDPOSTPONED))
1336       && (!(flags & SENDBATCH) || (quadoption (OPT_COPY) & 0x1))) {
1337     /* set the default FCC */
1338     if (!msg->env->from) {
1339       msg->env->from = mutt_default_from ();
1340       killfrom = 1;             /* no need to check $use_from because if the user specified
1341                                    a from address it would have already been set by now */
1342     }
1343     m_strcpy(fcc, sizeof(fcc), NONULL(MAlias.record));
1344     mutt_pretty_mailbox(fcc);
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       mutt_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: */