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