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