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