safe_fclose -> m_fclose, and is now inlined.
[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
547   fclose (tmpfp);
548   tmpfp = NULL;
549
550   /* now that we have the template, send it. */
551   ci_send_message (flags, tmphdr, tmpbody, NULL, parent);
552   return;
553
554 bail:
555
556   if (tmpfp) {
557     fclose (tmpfp);
558     mutt_unlink (tmpbody);
559   }
560
561   header_delete(&tmphdr);
562 }
563
564
565 /* 
566  * Forward one or several message-type attachments. This 
567  * is different from the previous function
568  * since we want to mimic the index menu's behaviour.
569  *
570  * Code reuse from ci_send_message is not possible here -
571  * ci_send_message relies on a context structure to find messages,
572  * while, on the attachment menu, messages are referenced through
573  * the attachment index. 
574  */
575
576 static void attach_forward_msgs (FILE * fp, HEADER * hdr __attribute__ ((unused)),
577                                  ATTACHPTR ** idx, short idxlen, BODY * cur,
578                                  int flags)
579 {
580   HEADER *curhdr = NULL;
581   HEADER *tmphdr;
582   short i;
583   int rc;
584
585   BODY **last;
586   char tmpbody[_POSIX_PATH_MAX];
587   FILE *tmpfp = NULL;
588
589   int cmflags = 0;
590   int chflags = CH_XMIT;
591
592   if (cur)
593     curhdr = cur->hdr;
594   else {
595     for (i = 0; i < idxlen; i++)
596       if (idx[i]->content->tagged) {
597         curhdr = idx[i]->content->hdr;
598         break;
599       }
600   }
601
602   tmphdr = header_new();
603   tmphdr->env = envelope_new();
604   mutt_make_forward_subject (tmphdr->env, Context, curhdr);
605
606
607   tmpbody[0] = '\0';
608
609   if ((rc = query_quadoption (OPT_MIMEFWD,
610                               _("Forward MIME encapsulated?"))) == M_NO) {
611
612     /* no MIME encapsulation */
613
614     tmpfp = m_tempfile(tmpbody, sizeof(tmpbody), NONULL(Tempdir), NULL);
615     if (!tmpfp) {
616       mutt_error(_("Could not create temporary file"));
617       header_delete(&tmphdr);
618       return;
619     }
620
621     if (option (OPTFORWQUOTE)) {
622       chflags |= CH_PREFIX;
623       cmflags |= M_CM_PREFIX;
624     }
625
626     if (option (OPTFORWDECODE)) {
627       cmflags |= M_CM_DECODE | M_CM_CHARCONV;
628       if (option (OPTWEED)) {
629         chflags |= CH_WEED | CH_REORDER;
630         cmflags |= M_CM_WEED;
631       }
632     }
633
634
635     if (cur) {
636       /* mutt_message_hook (cur->hdr, M_MESSAGEHOOK); */
637       mutt_forward_intro (tmpfp, cur->hdr);
638       _mutt_copy_message (tmpfp, fp, cur->hdr, cur->hdr->content, cmflags,
639                           chflags);
640       mutt_forward_trailer (tmpfp);
641     }
642     else {
643       for (i = 0; i < idxlen; i++) {
644         if (idx[i]->content->tagged) {
645           /* mutt_message_hook (idx[i]->content->hdr, M_MESSAGEHOOK); */
646           mutt_forward_intro (tmpfp, idx[i]->content->hdr);
647           _mutt_copy_message (tmpfp, fp, idx[i]->content->hdr,
648                               idx[i]->content->hdr->content, cmflags,
649                               chflags);
650           mutt_forward_trailer (tmpfp);
651         }
652       }
653     }
654     fclose (tmpfp);
655   }
656   else if (rc == M_YES) {       /* do MIME encapsulation - we don't need to do much here */
657     last = &tmphdr->content;
658     if (cur)
659       mutt_copy_body (fp, last, cur);
660     else {
661       for (i = 0; i < idxlen; i++)
662         if (idx[i]->content->tagged) {
663           mutt_copy_body (fp, last, idx[i]->content);
664           last = &((*last)->next);
665         }
666     }
667   }
668   else
669     header_delete(&tmphdr);
670
671   ci_send_message (flags, tmphdr, *tmpbody ? tmpbody : NULL, NULL, curhdr);
672
673 }
674
675 void mutt_attach_forward (FILE * fp, HEADER * hdr,
676                           ATTACHPTR ** idx, short idxlen, BODY * cur,
677                           int flags)
678 {
679   short nattach;
680
681
682   if (check_all_msg (idx, idxlen, cur, 0) == 0)
683     attach_forward_msgs (fp, hdr, idx, idxlen, cur, flags);
684   else {
685     nattach = count_tagged (idx, idxlen);
686     attach_forward_bodies (fp, hdr, idx, idxlen, cur, nattach, flags);
687   }
688 }
689 \f
690
691
692 /**
693  ** the various reply functions, from the attachment menu
694  **/
695
696 /* Create the envelope defaults for a reply.
697  *
698  * This function can be invoked in two ways.
699  * 
700  * Either, parent is NULL.  In this case, all tagged bodies are of a message type,
701  * and the header information is fetched from them.
702  * 
703  * Or, parent is non-NULL.  In this case, cur is the common parent of all the
704  * tagged attachments.
705  * 
706  * Note that this code is horribly similar to envelope_defaults () from send.c.
707  */
708
709 static int
710 attach_reply_envelope_defaults (ENVELOPE * env, ATTACHPTR ** idx,
711                                 short idxlen, HEADER * parent, int flags)
712 {
713   ENVELOPE *curenv = NULL;
714   HEADER *curhdr = NULL;
715   short i;
716
717   if (!parent) {
718     for (i = 0; i < idxlen; i++) {
719       if (idx[i]->content->tagged) {
720         curhdr = idx[i]->content->hdr;
721         curenv = curhdr->env;
722         break;
723       }
724     }
725   }
726   else {
727     curenv = parent->env;
728     curhdr = parent;
729   }
730
731   if (curenv == NULL || curhdr == NULL) {
732     mutt_error _("Can't find any tagged messages.");
733
734     return -1;
735   }
736
737 #ifdef USE_NNTP
738   if ((flags & SENDNEWS)) {
739     /* in case followup set Newsgroups: with Followup-To: if it present */
740     if (!env->newsgroups && curenv &&
741         m_strcasecmp(curenv->followup_to, "poster"))
742       env->newsgroups = m_strdup(curenv->followup_to);
743   }
744   else
745 #endif
746   {
747     if (parent) {
748       if (mutt_fetch_recips (env, curenv, flags) == -1)
749         return -1;
750     }
751     else {
752       for (i = 0; i < idxlen; i++) {
753         if (idx[i]->content->tagged
754             && mutt_fetch_recips (env, idx[i]->content->hdr->env,
755                                   flags) == -1)
756           return -1;
757       }
758     }
759
760     if ((flags & SENDLISTREPLY) && !env->to) {
761       mutt_error _("No mailing lists found!");
762
763       return (-1);
764     }
765
766     mutt_fix_reply_recipients (env);
767   }
768   mutt_make_misc_reply_headers (env, Context, curhdr, curenv);
769
770   if (parent)
771     mutt_add_to_reference_headers (env, curenv, NULL, NULL);
772   else {
773     string_list_t **p = NULL, **q = NULL;
774
775     for (i = 0; i < idxlen; i++) {
776       if (idx[i]->content->tagged)
777         mutt_add_to_reference_headers (env, idx[i]->content->hdr->env, &p,
778                                        &q);
779     }
780   }
781
782   return 0;
783 }
784
785
786 /*  This is _very_ similar to send.c's include_reply(). */
787
788 static void attach_include_reply (FILE * fp, FILE * tmpfp, HEADER * cur,
789                                   int flags __attribute__ ((unused)))
790 {
791   int cmflags = M_CM_PREFIX | M_CM_DECODE | M_CM_CHARCONV;
792   int chflags = CH_DECODE;
793
794   /* mutt_message_hook (cur, M_MESSAGEHOOK); */
795
796   mutt_make_attribution (Context, cur, tmpfp);
797
798   if (!option (OPTHEADER))
799     cmflags |= M_CM_NOHEADER;
800   if (option (OPTWEED)) {
801     chflags |= CH_WEED;
802     cmflags |= M_CM_WEED;
803   }
804
805   _mutt_copy_message (tmpfp, fp, cur, cur->content, cmflags, chflags);
806   mutt_make_post_indent (Context, cur, tmpfp);
807 }
808
809 void mutt_attach_reply (FILE * fp, HEADER * hdr,
810                         ATTACHPTR ** idx, short idxlen, BODY * cur, int flags)
811 {
812   short mime_reply_any = 0;
813
814   short nattach = 0;
815   HEADER *parent = NULL;
816   HEADER *tmphdr = NULL;
817   short i;
818
819   STATE st;
820   char tmpbody[_POSIX_PATH_MAX];
821   FILE *tmpfp;
822
823   char prefix[SHORT_STRING];
824   int rc;
825
826 #ifdef USE_NNTP
827   if (flags & SENDNEWS)
828     set_option (OPTNEWSSEND);
829   else
830     unset_option (OPTNEWSSEND);
831 #endif
832
833   if (check_all_msg (idx, idxlen, cur, 0) == -1) {
834     nattach = count_tagged (idx, idxlen);
835     if ((parent = find_parent (idx, idxlen, cur, nattach)) == NULL)
836       parent = hdr;
837   }
838
839   if (nattach > 1 && !check_can_decode (idx, idxlen, cur)) {
840     if ((rc = query_quadoption (OPT_MIMEFWDREST,
841                                 _
842                                 ("Can't decode all tagged attachments.  MIME-encapsulate the others?")))
843         == -1)
844       return;
845     else if (rc == M_YES)
846       mime_reply_any = 1;
847   }
848   else if (nattach == 1)
849     mime_reply_any = 1;
850
851   tmphdr = header_new();
852   tmphdr->env = envelope_new();
853
854   if (attach_reply_envelope_defaults (tmphdr->env, idx, idxlen,
855                                       parent ? parent : (cur ? cur->
856                                                          hdr : NULL),
857                                       flags) == -1) {
858     header_delete(&tmphdr);
859     return;
860   }
861
862   tmpfp = m_tempfile(tmpbody, sizeof(tmpbody), NONULL(Tempdir), NULL);
863   if (!tmpfp) {
864     mutt_error(_("Could not create temporary file"));
865     header_delete(&tmphdr);
866     return;
867   }
868
869   if (!parent) {
870     if (cur)
871       attach_include_reply (fp, tmpfp, cur->hdr, flags);
872     else {
873       for (i = 0; i < idxlen; i++) {
874         if (idx[i]->content->tagged)
875           attach_include_reply (fp, tmpfp, idx[i]->content->hdr, flags);
876       }
877     }
878   }
879   else {
880     mutt_make_attribution (Context, parent, tmpfp);
881
882     p_clear(&st, 1);
883     st.fpin = fp;
884     st.fpout = tmpfp;
885
886     if (!option (OPTTEXTFLOWED))
887       _mutt_make_string (prefix, sizeof (prefix), NONULL (Prefix),
888                          Context, parent, 0);
889     else
890       m_strcpy(prefix, sizeof(prefix), ">");
891
892     st.prefix = prefix;
893     st.flags = M_CHARCONV;
894
895     if (option (OPTWEED))
896       st.flags |= M_WEED;
897
898     if (option (OPTHEADER))
899       include_header (1, fp, parent, tmpfp, prefix);
900
901     if (cur) {
902       if (mutt_can_decode (cur)) {
903         mutt_body_handler (cur, &st);
904         state_putc ('\n', &st);
905       }
906       else
907         mutt_copy_body (fp, &tmphdr->content, cur);
908     }
909     else {
910       for (i = 0; i < idxlen; i++) {
911         if (idx[i]->content->tagged && mutt_can_decode (idx[i]->content)) {
912           mutt_body_handler (idx[i]->content, &st);
913           state_putc ('\n', &st);
914         }
915       }
916     }
917
918     mutt_make_post_indent (Context, parent, tmpfp);
919
920     if (mime_reply_any && !cur &&
921         copy_problematic_attachments (fp, &tmphdr->content, idx, idxlen,
922                                       0) == NULL) {
923       header_delete(&tmphdr);
924       fclose (tmpfp);
925       return;
926     }
927   }
928
929   fclose (tmpfp);
930
931   if (ci_send_message (flags, tmphdr, tmpbody, NULL, parent) == 0)
932     mutt_set_flag (Context, hdr, M_REPLIED, 1);
933 }