]> git.llucax.com Git - software/mutt-debian.git/blob - recvcmd.c
adding a missing bug number
[software/mutt-debian.git] / recvcmd.c
1 /*
2  * Copyright (C) 1999-2004 Thomas Roessler <roessler@does-not-exist.org>
3  * 
4  *     This program is free software; you can redistribute it
5  *     and/or modify it under the terms of the GNU General Public
6  *     License as published by the Free Software Foundation; either
7  *     version 2 of the License, or (at your option) any later
8  *     version.
9  * 
10  *     This program is distributed in the hope that it will be
11  *     useful, but WITHOUT ANY WARRANTY; without even the implied
12  *     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13  *     PURPOSE.  See the GNU General Public License for more
14  *     details.
15  * 
16  *     You should have received a copy of the GNU General Public
17  *     License along with this program; if not, write to the Free
18  *     Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *     Boston, MA  02110-1301, USA. 
20  */
21
22 #if HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25
26 #include "mutt.h"
27 #include "mutt_curses.h"
28 #include "mutt_menu.h"
29 #include "attach.h"
30 #include "mapping.h"
31 #include "copy.h"
32 #include "mutt_idna.h"
33
34 /* some helper functions to verify that we are exclusively operating
35  * on message/rfc822 attachments
36  */
37
38 static short check_msg (BODY * b, short err)
39 {
40   if (!mutt_is_message_type (b->type, b->subtype))
41   {
42     if (err)
43       mutt_error _("You may only bounce message/rfc822 parts.");
44     return -1;
45   }
46   return 0;
47 }
48
49 static short check_all_msg (ATTACHPTR ** idx, short idxlen,
50                             BODY * cur, short err)
51 {
52   short i;
53
54   if (cur && check_msg (cur, err) == -1)
55     return -1;
56   else if (!cur)
57   {
58     for (i = 0; i < idxlen; i++)
59     {
60       if (idx[i]->content->tagged)
61       {
62         if (check_msg (idx[i]->content, err) == -1)
63           return -1;
64       }
65     }
66   }
67   return 0;
68 }
69
70
71 /* can we decode all tagged attachments? */
72
73 static short check_can_decode (ATTACHPTR ** idx, short idxlen, 
74                               BODY * cur)
75 {
76   short i;
77
78   if (cur)
79     return mutt_can_decode (cur);
80
81   for (i = 0; i < idxlen; i++)
82     if (idx[i]->content->tagged && !mutt_can_decode (idx[i]->content))
83       return 0;
84
85   return 1;
86 }
87
88 static short count_tagged (ATTACHPTR **idx, short idxlen)
89 {
90   short count = 0;
91   short i;
92   
93   for (i = 0; i < idxlen; i++)
94     if (idx[i]->content->tagged)
95       count++;
96   
97   return count;
98 }
99
100 /* count the number of tagged children below a multipart or message
101  * attachment.
102  */
103
104 static short count_tagged_children (ATTACHPTR ** idx, 
105                                     short idxlen, short i)
106 {
107   short level = idx[i]->level;
108   short count = 0;
109
110   while ((++i < idxlen) && (level < idx[i]->level))
111     if (idx[i]->content->tagged)
112       count++;
113
114   return count;
115 }
116
117
118 \f
119 /**
120  **
121  ** The bounce function, from the attachment menu
122  **
123  **/
124
125 void mutt_attach_bounce (FILE * fp, HEADER * hdr, 
126            ATTACHPTR ** idx, short idxlen, BODY * cur)
127 {
128   short i;
129   char prompt[STRING];
130   char buf[HUGE_STRING];
131   char *err = NULL;
132   ADDRESS *adr = NULL;
133   int ret = 0;
134   int p   = 0;
135
136   if (check_all_msg (idx, idxlen, cur, 1) == -1)
137     return;
138
139   /* one or more messages? */
140   p = (cur || count_tagged (idx, idxlen) == 1);
141
142   /* RfC 5322 mandates a From: header, so warn before bouncing
143    * messages without one */
144   if (cur)
145   {
146     if (!cur->hdr->env->from)
147     {
148       mutt_error _("Warning: message contains no From: header");
149       mutt_sleep (2);
150       mutt_clear_error ();
151     }
152   }
153   else
154   {
155     for (i = 0; i < idxlen; i++)
156     {
157       if (idx[i]->content->tagged)
158       {
159         if (!idx[i]->content->hdr->env->from)
160         {
161           mutt_error _("Warning: message contains no From: header");
162           mutt_sleep (2);
163           mutt_clear_error ();
164           break;
165         }
166       }
167     }
168   }
169
170   if (p)
171     strfcpy (prompt, _("Bounce message to: "), sizeof (prompt));
172   else
173     strfcpy (prompt, _("Bounce tagged messages to: "), sizeof (prompt));
174
175   buf[0] = '\0';
176   if (mutt_get_field (prompt, buf, sizeof (buf), M_ALIAS) 
177       || buf[0] == '\0')
178     return;
179
180   if (!(adr = rfc822_parse_adrlist (adr, buf)))
181   {
182     mutt_error _("Error parsing address!");
183     return;
184   }
185
186   adr = mutt_expand_aliases (adr);
187   
188   if (mutt_addrlist_to_idna (adr, &err) < 0)
189   {
190     mutt_error (_("Bad IDN: '%s'"), err);
191     FREE (&err);
192     rfc822_free_address (&adr);
193     return;
194   }
195   
196   buf[0] = 0;
197   rfc822_write_address (buf, sizeof (buf), adr, 1);
198
199 #define extra_space (15+7+2)
200   /*
201    * See commands.c.
202    */
203   snprintf (prompt, sizeof (prompt) - 4, 
204    (p ? _("Bounce message to %s") : _("Bounce messages to %s")), buf);
205   
206   if (mutt_strwidth (prompt) > COLS - extra_space)
207   {
208     mutt_format_string (prompt, sizeof (prompt) - 4,
209                         0, COLS-extra_space, FMT_LEFT, 0,
210                         prompt, sizeof (prompt), 0);
211     safe_strcat (prompt, sizeof (prompt), "...?");
212   }
213   else
214     safe_strcat (prompt, sizeof (prompt), "?");
215
216   if (query_quadoption (OPT_BOUNCE, prompt) != M_YES)
217   {
218     rfc822_free_address (&adr);
219     CLEARLINE (LINES - 1);
220     mutt_message (p ? _("Message not bounced.") : _("Messages not bounced."));
221     return;
222   }
223   
224   CLEARLINE (LINES - 1);
225   
226   if (cur)
227     ret = mutt_bounce_message (fp, cur->hdr, adr);
228   else
229   {
230     for (i = 0; i < idxlen; i++)
231     {
232       if (idx[i]->content->tagged)
233         if (mutt_bounce_message (fp, idx[i]->content->hdr, adr))
234           ret = 1;
235     }
236   }
237
238   if (!ret)
239     mutt_message (p ? _("Message bounced.") : _("Messages bounced."));
240   else
241     mutt_error (p ? _("Error bouncing message!") : _("Error bouncing messages!"));
242 }
243
244
245 \f
246 /**
247  **
248  ** resend-message, from the attachment menu 
249  **
250  **
251  **/
252
253 void mutt_attach_resend (FILE * fp, HEADER * hdr, ATTACHPTR ** idx, 
254                          short idxlen, BODY * cur)
255 {
256   short i;
257
258   if (check_all_msg (idx, idxlen, cur, 1) == -1)
259     return;
260
261   if (cur)
262     mutt_resend_message (fp, Context, cur->hdr);
263   else
264   {
265     for (i = 0; i < idxlen; i++)
266       if (idx[i]->content->tagged)
267         mutt_resend_message (fp, Context, idx[i]->content->hdr);
268   }
269 }
270
271 \f
272 /**
273  **
274  ** forward-message, from the attachment menu 
275  **
276  **/
277   
278 /* try to find a common parent message for the tagged attachments. */
279
280 static HEADER *find_common_parent (ATTACHPTR ** idx, short idxlen,
281                                    short nattach)
282 {
283   short i;
284   short nchildren;
285
286   for (i = 0; i < idxlen; i++)
287     if (idx[i]->content->tagged)
288       break;
289   
290   while (--i >= 0)
291   {
292     if (mutt_is_message_type (idx[i]->content->type, idx[i]->content->subtype))
293     {
294       nchildren = count_tagged_children (idx, idxlen, i);
295       if (nchildren == nattach)
296         return idx[i]->content->hdr;
297     }
298   }
299
300   return NULL;
301 }
302
303 /* 
304  * check whether attachment #i is a parent of the attachment
305  * pointed to by cur
306  * 
307  * Note: This and the calling procedure could be optimized quite a 
308  * bit.  For now, it's not worth the effort.
309  */
310
311 static int is_parent (short i, ATTACHPTR **idx, short idxlen, BODY *cur)
312 {
313   short level = idx[i]->level;
314
315   while ((++i < idxlen) && idx[i]->level > level)
316   {
317     if (idx[i]->content == cur)
318       return 1;
319   }
320
321   return 0;
322 }
323
324 static HEADER *find_parent (ATTACHPTR **idx, short idxlen, BODY *cur, short nattach)
325 {
326   short i;
327   HEADER *parent = NULL;
328   
329   if (cur)
330   {
331     for (i = 0; i < idxlen; i++)
332     {
333       if (mutt_is_message_type (idx[i]->content->type, idx[i]->content->subtype) 
334           && is_parent (i, idx, idxlen, cur))
335         parent = idx[i]->content->hdr;
336       if (idx[i]->content == cur)
337         break;
338     }
339   }
340   else if (nattach)
341     parent = find_common_parent (idx, idxlen, nattach);
342   
343   return parent;
344 }
345
346 static void include_header (int quote, FILE * ifp,
347                             HEADER * hdr, FILE * ofp,
348                             char *_prefix)
349 {
350   int chflags = CH_DECODE;
351   char prefix[SHORT_STRING];
352   
353   if (option (OPTWEED))
354     chflags |= CH_WEED | CH_REORDER;
355
356   if (quote)
357   {
358     if (_prefix)
359       strfcpy (prefix, _prefix, sizeof (prefix));
360     else if (!option (OPTTEXTFLOWED))
361       _mutt_make_string (prefix, sizeof (prefix), NONULL (Prefix), 
362                          Context, hdr, 0);
363     else
364       strfcpy (prefix, ">", sizeof (prefix));
365
366     chflags |= CH_PREFIX;
367   }
368   
369   mutt_copy_header (ifp, hdr, ofp, chflags, quote ? prefix : NULL);
370 }
371
372 /* Attach all the body parts which can't be decoded. 
373  * This code is shared by forwarding and replying. */
374
375 static BODY ** copy_problematic_attachments (FILE *fp,
376                                              BODY **last, 
377                                              ATTACHPTR **idx, 
378                                              short idxlen,
379                                              short force)
380 {
381   short i;
382   
383   for (i = 0; i < idxlen; i++)
384   {
385     if (idx[i]->content->tagged && 
386         (force || !mutt_can_decode (idx[i]->content)))
387     {
388       if (mutt_copy_body (fp, last, idx[i]->content) == -1)
389         return NULL;            /* XXXXX - may lead to crashes */
390       last = &((*last)->next);
391     }
392   }
393   return last;
394 }
395
396 /* 
397  * forward one or several MIME bodies 
398  * (non-message types)
399  */
400
401 static void attach_forward_bodies (FILE * fp, HEADER * hdr,
402                                    ATTACHPTR ** idx, short idxlen,
403                                    BODY * cur,
404                                    short nattach)
405 {
406   short i;
407   short mime_fwd_all = 0;
408   short mime_fwd_any = 1;
409   HEADER *parent = NULL;
410   HEADER *tmphdr = NULL;
411   BODY **last;
412   char tmpbody[_POSIX_PATH_MAX];
413   FILE *tmpfp = NULL;
414
415   char prefix[STRING];
416
417   int rc = 0;
418
419   STATE st;
420
421   /* 
422    * First, find the parent message.
423    * Note: This could be made an option by just
424    * putting the following lines into an if block.
425    */
426
427
428   parent = find_parent (idx, idxlen, cur, nattach);
429   
430   if (parent == NULL)
431     parent = hdr;
432
433
434   tmphdr = mutt_new_header ();
435   tmphdr->env = mutt_new_envelope ();
436   mutt_make_forward_subject (tmphdr->env, Context, parent);
437
438   mutt_mktemp (tmpbody);
439   if ((tmpfp = safe_fopen (tmpbody, "w")) == NULL)
440   {
441     mutt_error (_("Can't open temporary file %s."), tmpbody);
442     return;
443   }
444
445   mutt_forward_intro (tmpfp, parent);
446
447   /* prepare the prefix here since we'll need it later. */
448
449   if (option (OPTFORWQUOTE))
450   {
451     if (!option (OPTTEXTFLOWED))
452       _mutt_make_string (prefix, sizeof (prefix), NONULL (Prefix), Context,
453                          parent, 0);
454     else
455       strfcpy (prefix, ">", sizeof (prefix));
456   }
457     
458   include_header (option (OPTFORWQUOTE), fp, parent,
459                   tmpfp, prefix);
460
461
462   /* 
463    * Now, we have prepared the first part of the message body: The
464    * original message's header. 
465    *
466    * The next part is more interesting: either include the message bodies,
467    * or attach them.
468    */
469
470   if ((!cur || mutt_can_decode (cur)) &&
471       (rc = query_quadoption (OPT_MIMEFWD, 
472                               _("Forward as attachments?"))) == M_YES)
473     mime_fwd_all = 1;
474   else if (rc == -1)
475     goto bail;
476
477   /* 
478    * shortcut MIMEFWDREST when there is only one attachment.  Is 
479    * this intuitive?
480    */
481
482   if (!mime_fwd_all && !cur && (nattach > 1) 
483       && !check_can_decode (idx, idxlen, cur))
484   {
485     if ((rc = query_quadoption (OPT_MIMEFWDREST,
486 _("Can't decode all tagged attachments.  MIME-forward the others?"))) == -1)
487       goto bail;
488     else if (rc == M_NO)
489       mime_fwd_any = 0;
490   }
491
492   /* initialize a state structure */
493   
494   memset (&st, 0, sizeof (st));
495   
496   if (option (OPTFORWQUOTE))
497     st.prefix = prefix;
498   st.flags = M_CHARCONV;
499   if (option (OPTWEED))
500     st.flags |= M_WEED;
501   st.fpin = fp;
502   st.fpout = tmpfp;
503
504   /* where do we append new MIME parts? */
505   last = &tmphdr->content;
506
507   if (cur)
508   {
509     /* single body case */
510
511     if (!mime_fwd_all && mutt_can_decode (cur))
512     {
513       mutt_body_handler (cur, &st);
514       state_putc ('\n', &st);
515     }
516     else
517     {
518       if (mutt_copy_body (fp, last, cur) == -1)
519         goto bail;
520       last = &((*last)->next);
521     }
522   }
523   else
524   {
525     /* multiple body case */
526
527     if (!mime_fwd_all)
528     {
529       for (i = 0; i < idxlen; i++)
530       {
531         if (idx[i]->content->tagged && mutt_can_decode (idx[i]->content))
532         {
533           mutt_body_handler (idx[i]->content, &st);
534           state_putc ('\n', &st);
535         }
536       }
537     }
538
539     if (mime_fwd_any && 
540         copy_problematic_attachments (fp, last, idx, idxlen, mime_fwd_all) == NULL)
541       goto bail;
542   }
543   
544   mutt_forward_trailer (tmpfp);
545   
546   safe_fclose (&tmpfp);
547   tmpfp = NULL;
548
549   /* now that we have the template, send it. */
550   ci_send_message (0, tmphdr, tmpbody, NULL, parent);
551   return;
552   
553   bail:
554   
555   if (tmpfp)
556   {
557     safe_fclose (&tmpfp);
558     mutt_unlink (tmpbody);
559   }
560
561   mutt_free_header (&tmphdr);
562 }
563
564
565 /* 
566  * Forward one or several message-type attachments. This 
567  * is different from the previous function
568  * since we want to mimic the index menu's behaviour.
569  *
570  * Code reuse from ci_send_message is not possible here -
571  * ci_send_message relies on a context structure to find messages,
572  * while, on the attachment menu, messages are referenced through
573  * the attachment index. 
574  */
575
576 static void attach_forward_msgs (FILE * fp, HEADER * hdr, 
577                ATTACHPTR ** idx, short idxlen, BODY * cur)
578 {
579   HEADER *curhdr = NULL;
580   HEADER *tmphdr;
581   short i;
582   int rc;
583
584   BODY **last;
585   char tmpbody[_POSIX_PATH_MAX];
586   FILE *tmpfp = NULL;
587
588   int cmflags = 0;
589   int chflags = CH_XMIT;
590   
591   if (cur)
592     curhdr = cur->hdr;
593   else
594   {
595     for (i = 0; i < idxlen; i++)
596       if (idx[i]->content->tagged)
597       {
598         curhdr = idx[i]->content->hdr;
599         break;
600       }
601   }
602
603   tmphdr = mutt_new_header ();
604   tmphdr->env = mutt_new_envelope ();
605   mutt_make_forward_subject (tmphdr->env, Context, curhdr);
606
607
608   tmpbody[0] = '\0';
609
610   if ((rc = query_quadoption (OPT_MIMEFWD, 
611                  _("Forward MIME encapsulated?"))) == M_NO)
612   {
613     
614     /* no MIME encapsulation */
615     
616     mutt_mktemp (tmpbody);
617     if (!(tmpfp = safe_fopen (tmpbody, "w")))
618     {
619       mutt_error (_("Can't create %s."), tmpbody);
620       mutt_free_header (&tmphdr);
621       return;
622     }
623
624     if (option (OPTFORWQUOTE))
625     {
626       chflags |= CH_PREFIX;
627       cmflags |= M_CM_PREFIX;
628     }
629
630     if (option (OPTFORWDECODE))
631     {
632       cmflags |= M_CM_DECODE | M_CM_CHARCONV;
633       if (option (OPTWEED))
634       {
635         chflags |= CH_WEED | CH_REORDER;
636         cmflags |= M_CM_WEED;
637       }
638     }
639     
640     
641     if (cur)
642     {
643       /* mutt_message_hook (cur->hdr, M_MESSAGEHOOK); */ 
644       mutt_forward_intro (tmpfp, cur->hdr);
645       _mutt_copy_message (tmpfp, fp, cur->hdr, cur->hdr->content, cmflags, chflags);
646       mutt_forward_trailer (tmpfp);
647     }
648     else
649     {
650       for (i = 0; i < idxlen; i++)
651       {
652         if (idx[i]->content->tagged)
653         {
654           /* mutt_message_hook (idx[i]->content->hdr, M_MESSAGEHOOK); */ 
655           mutt_forward_intro (tmpfp, idx[i]->content->hdr);
656           _mutt_copy_message (tmpfp, fp, idx[i]->content->hdr,
657                               idx[i]->content->hdr->content, cmflags, chflags);
658           mutt_forward_trailer (tmpfp);
659         }
660       }
661     }
662     safe_fclose (&tmpfp);
663   }
664   else if (rc == M_YES) /* do MIME encapsulation - we don't need to do much here */
665   {
666     last = &tmphdr->content;
667     if (cur)
668       mutt_copy_body (fp, last, cur);
669     else
670     {
671       for (i = 0; i < idxlen; i++)
672         if (idx[i]->content->tagged)
673         {
674           mutt_copy_body (fp, last, idx[i]->content);
675           last = &((*last)->next);
676         }
677     }
678   }
679   else
680     mutt_free_header (&tmphdr);
681
682   ci_send_message (0, tmphdr, *tmpbody ? tmpbody : NULL, 
683                    NULL, curhdr);
684
685 }
686
687 void mutt_attach_forward (FILE * fp, HEADER * hdr, 
688                           ATTACHPTR ** idx, short idxlen, BODY * cur)
689 {
690   short nattach;
691   
692
693   if (check_all_msg (idx, idxlen, cur, 0) == 0)
694     attach_forward_msgs (fp, hdr, idx, idxlen, cur);
695   else
696   {
697     nattach = count_tagged (idx, idxlen);
698     attach_forward_bodies (fp, hdr, idx, idxlen, cur, nattach);
699   }
700 }
701
702
703 \f
704 /**
705  ** 
706  ** the various reply functions, from the attachment menu
707  **
708  **
709  **/
710
711 /* Create the envelope defaults for a reply.
712  *
713  * This function can be invoked in two ways.
714  * 
715  * Either, parent is NULL.  In this case, all tagged bodies are of a message type,
716  * and the header information is fetched from them.
717  * 
718  * Or, parent is non-NULL.  In this case, cur is the common parent of all the
719  * tagged attachments.
720  * 
721  * Note that this code is horribly similar to envelope_defaults () from send.c.
722  */
723   
724 static int
725 attach_reply_envelope_defaults (ENVELOPE *env, ATTACHPTR **idx, short idxlen,
726                                 HEADER *parent, int flags)
727 {
728   ENVELOPE *curenv = NULL;
729   HEADER *curhdr = NULL;
730   short i;
731   
732   if (!parent)
733   {
734     for (i = 0; i < idxlen; i++)
735     {
736       if (idx[i]->content->tagged)
737       {
738         curhdr = idx[i]->content->hdr;
739         curenv = curhdr->env;
740         break;
741       }
742     }
743   }
744   else
745   {
746     curenv = parent->env;
747     curhdr = parent;
748   }
749
750   if (curenv == NULL  ||  curhdr == NULL)
751   {
752     mutt_error _("Can't find any tagged messages.");
753     return -1;
754   }
755
756   if (parent)
757   {
758     if (mutt_fetch_recips (env, curenv, flags) == -1)
759       return -1;
760   }
761   else
762   {
763     for (i = 0; i < idxlen; i++)
764     {
765       if (idx[i]->content->tagged
766           && mutt_fetch_recips (env, idx[i]->content->hdr->env, flags) == -1)
767         return -1;
768     }
769   }
770   
771   if ((flags & SENDLISTREPLY) && !env->to)
772   {
773     mutt_error _("No mailing lists found!");
774     return (-1);
775   }
776   
777   mutt_fix_reply_recipients (env);
778   mutt_make_misc_reply_headers (env, Context, curhdr, curenv);
779
780   if (parent)
781     mutt_add_to_reference_headers (env, curenv, NULL, NULL);
782   else
783   {
784     LIST **p = NULL, **q = NULL;
785     
786     for (i = 0; i < idxlen; i++)
787     {
788       if (idx[i]->content->tagged)
789         mutt_add_to_reference_headers (env, idx[i]->content->hdr->env, &p, &q);
790     }
791   }
792   
793   return 0;
794 }
795
796
797 /*  This is _very_ similar to send.c's include_reply(). */
798
799 static void attach_include_reply (FILE *fp, FILE *tmpfp, HEADER *cur, int flags)
800 {
801   int cmflags = M_CM_PREFIX | M_CM_DECODE | M_CM_CHARCONV;
802   int chflags = CH_DECODE;
803
804   /* mutt_message_hook (cur, M_MESSAGEHOOK); */ 
805   
806   mutt_make_attribution (Context, cur, tmpfp);
807   
808   if (!option (OPTHEADER))
809     cmflags |= M_CM_NOHEADER;
810   if (option (OPTWEED))
811   {
812     chflags |= CH_WEED;
813     cmflags |= M_CM_WEED;
814   }
815
816   _mutt_copy_message (tmpfp, fp, cur, cur->content, cmflags, chflags);
817   mutt_make_post_indent (Context, cur, tmpfp);
818 }
819   
820 void mutt_attach_reply (FILE * fp, HEADER * hdr, 
821                         ATTACHPTR ** idx, short idxlen, BODY * cur, 
822                         int flags)
823 {
824   short mime_reply_any = 0;
825   
826   short nattach = 0;
827   HEADER *parent = NULL;
828   HEADER *tmphdr = NULL;
829   short i;
830
831   STATE st;
832   char tmpbody[_POSIX_PATH_MAX];
833   FILE *tmpfp;
834   
835   char prefix[SHORT_STRING];
836   int rc;
837   
838   if (check_all_msg (idx, idxlen, cur, 0) == -1)
839   {
840     nattach = count_tagged (idx, idxlen);
841     if ((parent = find_parent (idx, idxlen, cur, nattach)) == NULL)
842       parent = hdr;
843   }
844
845   if (nattach > 1 && !check_can_decode (idx, idxlen, cur))
846   {
847     if ((rc = query_quadoption (OPT_MIMEFWDREST,
848       _("Can't decode all tagged attachments.  MIME-encapsulate the others?"))) == -1)
849       return;
850     else if (rc == M_YES)
851       mime_reply_any = 1;
852   }
853   else if (nattach == 1)
854     mime_reply_any = 1;
855
856   tmphdr = mutt_new_header ();
857   tmphdr->env = mutt_new_envelope ();
858
859   if (attach_reply_envelope_defaults (tmphdr->env, idx, idxlen, 
860                                       parent ? parent : (cur ? cur->hdr : NULL), flags) == -1)
861   {
862     mutt_free_header (&tmphdr);
863     return;
864   }
865   
866   mutt_mktemp (tmpbody);
867   if ((tmpfp = safe_fopen (tmpbody, "w")) == NULL)
868   {
869     mutt_error (_("Can't create %s."), tmpbody);
870     mutt_free_header (&tmphdr);
871     return;
872   }
873
874   if (!parent)
875   {
876     if (cur)
877       attach_include_reply (fp, tmpfp, cur->hdr, flags);
878     else
879     {
880       for (i = 0; i < idxlen; i++)
881       {
882         if (idx[i]->content->tagged)
883           attach_include_reply (fp, tmpfp, idx[i]->content->hdr, flags);
884       }
885     }
886   }
887   else
888   {
889     mutt_make_attribution (Context, parent, tmpfp);
890     
891     memset (&st, 0, sizeof (STATE));
892     st.fpin = fp;
893     st.fpout = tmpfp;
894
895     if (!option (OPTTEXTFLOWED))
896       _mutt_make_string (prefix, sizeof (prefix), NONULL (Prefix), 
897                          Context, parent, 0);
898     else
899       strfcpy (prefix, ">", sizeof (prefix));
900
901     st.prefix = prefix;
902     st.flags  = M_CHARCONV;
903     
904     if (option (OPTWEED)) 
905       st.flags |= M_WEED;
906
907     if (option (OPTHEADER))
908       include_header (1, fp, parent, tmpfp, prefix);
909
910     if (cur)
911     {
912       if (mutt_can_decode (cur))
913       {
914         mutt_body_handler (cur, &st);
915         state_putc ('\n', &st);
916       }
917       else
918         mutt_copy_body (fp, &tmphdr->content, cur);
919     }
920     else
921     {
922       for (i = 0; i < idxlen; i++)
923       {
924         if (idx[i]->content->tagged && mutt_can_decode (idx[i]->content))
925         {
926           mutt_body_handler (idx[i]->content, &st);
927           state_putc ('\n', &st);
928         }
929       }
930     }
931
932     mutt_make_post_indent (Context, parent, tmpfp);
933
934     if (mime_reply_any && !cur && 
935         copy_problematic_attachments (fp, &tmphdr->content, idx, idxlen, 0) == NULL)
936     {
937       mutt_free_header (&tmphdr);
938       safe_fclose (&tmpfp);
939       return;
940     }
941   }
942
943   safe_fclose (&tmpfp);
944   
945   if (ci_send_message (flags, tmphdr, tmpbody, NULL, parent) == 0)
946     mutt_set_flag (Context, hdr, M_REPLIED, 1);
947 }
948