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