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