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