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