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