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