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