Fix dereferencing for the mutt_hcache_close calls. Use hcache_t* instead of evil...
[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(main_w, LINES - 1);
165     mutt_message (p ? _("Message not bounced.") : _("Messages not bounced."));
166     return;
167   }
168
169   CLEARLINE(main_w, 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 #ifdef USE_NNTP
713   if ((flags & SENDNEWS)) {
714     /* in case followup set Newsgroups: with Followup-To: if it present */
715     if (!env->newsgroups && curenv &&
716         m_strcasecmp(curenv->followup_to, "poster"))
717       env->newsgroups = m_strdup(curenv->followup_to);
718   }
719   else
720 #endif
721   {
722     if (parent) {
723       if (mutt_fetch_recips (env, curenv, flags) == -1)
724         return -1;
725     }
726     else {
727       for (i = 0; i < idxlen; i++) {
728         if (idx[i]->content->tagged
729             && mutt_fetch_recips (env, idx[i]->content->hdr->env,
730                                   flags) == -1)
731           return -1;
732       }
733     }
734
735     if ((flags & SENDLISTREPLY) && !env->to) {
736       mutt_error _("No mailing lists found!");
737
738       return (-1);
739     }
740
741     mutt_fix_reply_recipients (env);
742   }
743   mutt_make_misc_reply_headers (env, Context, curhdr, curenv);
744
745   if (parent)
746     mutt_add_to_reference_headers (env, curenv, NULL, NULL);
747   else {
748     string_list_t **p = NULL, **q = NULL;
749
750     for (i = 0; i < idxlen; i++) {
751       if (idx[i]->content->tagged)
752         mutt_add_to_reference_headers (env, idx[i]->content->hdr->env, &p,
753                                        &q);
754     }
755   }
756
757   return 0;
758 }
759
760
761 /*  This is _very_ similar to send.c's include_reply(). */
762
763 static void attach_include_reply (FILE * fp, FILE * tmpfp, HEADER * cur,
764                                   int flags __attribute__ ((unused)))
765 {
766   int cmflags = M_CM_PREFIX | M_CM_DECODE | M_CM_CHARCONV;
767   int chflags = CH_DECODE;
768
769   /* mutt_message_hook (cur, M_MESSAGEHOOK); */
770
771   mutt_make_attribution (Context, cur, tmpfp);
772
773   if (!option (OPTHEADER))
774     cmflags |= M_CM_NOHEADER;
775   if (option (OPTWEED)) {
776     chflags |= CH_WEED;
777     cmflags |= M_CM_WEED;
778   }
779
780   _mutt_copy_message (tmpfp, fp, cur, cur->content, cmflags, chflags);
781 }
782
783 void mutt_attach_reply (FILE * fp, HEADER * hdr,
784                         ATTACHPTR ** idx, short idxlen, BODY * cur, int flags)
785 {
786   short mime_reply_any = 0;
787
788   short nattach = 0;
789   HEADER *parent = NULL;
790   HEADER *tmphdr = NULL;
791   short i;
792
793   STATE st;
794   char tmpbody[_POSIX_PATH_MAX];
795   FILE *tmpfp;
796
797   char prefix[STRING];
798   int rc;
799
800 #ifdef USE_NNTP
801   if (flags & SENDNEWS)
802     set_option (OPTNEWSSEND);
803   else
804     unset_option (OPTNEWSSEND);
805 #endif
806
807   if (check_all_msg (idx, idxlen, cur, 0) == -1) {
808     nattach = count_tagged (idx, idxlen);
809     if ((parent = find_parent (idx, idxlen, cur, nattach)) == NULL)
810       parent = hdr;
811   }
812
813   if (nattach > 1 && !check_can_decode (idx, idxlen, cur)) {
814     if ((rc = query_quadoption (OPT_MIMEFWDREST,
815                                 _
816                                 ("Can't decode all tagged attachments.  MIME-encapsulate the others?")))
817         == -1)
818       return;
819     else if (rc == M_YES)
820       mime_reply_any = 1;
821   }
822   else if (nattach == 1)
823     mime_reply_any = 1;
824
825   tmphdr = header_new();
826   tmphdr->env = envelope_new();
827
828   if (attach_reply_envelope_defaults (tmphdr->env, idx, idxlen,
829                                       parent ? parent : (cur ? cur->
830                                                          hdr : NULL),
831                                       flags) == -1) {
832     header_delete(&tmphdr);
833     return;
834   }
835
836   tmpfp = m_tempfile(tmpbody, sizeof(tmpbody), NONULL(mod_core.tmpdir), NULL);
837   if (!tmpfp) {
838     mutt_error(_("Could not create temporary file"));
839     header_delete(&tmphdr);
840     return;
841   }
842
843   if (!parent) {
844     if (cur)
845       attach_include_reply (fp, tmpfp, cur->hdr, flags);
846     else {
847       for (i = 0; i < idxlen; i++) {
848         if (idx[i]->content->tagged)
849           attach_include_reply (fp, tmpfp, idx[i]->content->hdr, flags);
850       }
851     }
852   }
853   else {
854     mutt_make_attribution (Context, parent, tmpfp);
855
856     p_clear(&st, 1);
857     st.fpin = fp;
858     st.fpout = tmpfp;
859
860     if (!option (OPTTEXTFLOWED))
861       _mutt_make_string (prefix, sizeof (prefix), NONULL (Prefix),
862                          Context, parent, 0);
863     else
864       m_strcpy(prefix, sizeof(prefix), ">");
865
866     st.prefix = prefix;
867     st.flags = M_CHARCONV;
868
869     if (option (OPTWEED))
870       st.flags |= M_WEED;
871
872     if (option (OPTHEADER))
873       include_header (1, fp, parent, tmpfp, prefix);
874
875     if (cur) {
876       if (mutt_can_decode (cur)) {
877         mutt_body_handler (cur, &st);
878         state_putc ('\n', &st);
879       }
880       else
881         mutt_copy_body (fp, &tmphdr->content, cur);
882     }
883     else {
884       for (i = 0; i < idxlen; i++) {
885         if (idx[i]->content->tagged && mutt_can_decode (idx[i]->content)) {
886           mutt_body_handler (idx[i]->content, &st);
887           state_putc ('\n', &st);
888         }
889       }
890     }
891
892     if (mime_reply_any && !cur &&
893         copy_problematic_attachments (fp, &tmphdr->content, idx, idxlen,
894                                       0) == NULL) {
895       header_delete(&tmphdr);
896       m_fclose(&tmpfp);
897       return;
898     }
899   }
900
901   m_fclose(&tmpfp);
902
903   if (ci_send_message (flags, tmphdr, tmpbody, NULL, parent) == 0)
904     mutt_set_flag (Context, hdr, M_REPLIED, 1);
905 }