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