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