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 (ATTACH_CONTEXT *actx,
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 < actx->idxlen; i++)
59 {
60 if (actx->idx[i]->content->tagged)
61 {
62 if (check_msg (actx->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 (ATTACH_CONTEXT *actx, BODY * cur)
74{
75 short i;
76
77 if (cur)
78 return mutt_can_decode (cur);
79
80 for (i = 0; i < actx->idxlen; i++)
81 if (actx->idx[i]->content->tagged && !mutt_can_decode (actx->idx[i]->content))
82 return 0;
83
84 return 1;
85}
86
87static short count_tagged (ATTACH_CONTEXT *actx)
88{
89 short count = 0;
90 short i;
91
92 for (i = 0; i < actx->idxlen; i++)
93 if (actx->idx[i]->content->tagged)
94 count++;
95
96 return count;
97}
98
99/* count the number of tagged children below a multipart or message
100 * attachment.
101 */
102
103static short count_tagged_children (ATTACH_CONTEXT *actx, short i)
104{
105 short level = actx->idx[i]->level;
106 short count = 0;
107
108 while ((++i < actx->idxlen) && (level < actx->idx[i]->level))
109 if (actx->idx[i]->content->tagged)
110 count++;
111
112 return count;
113}
114
115
116
117/**
118 **
119 ** The bounce function, from the attachment menu
120 **
121 **/
122
123void mutt_attach_bounce (FILE * fp, HEADER * hdr,
124 ATTACH_CONTEXT *actx, BODY * cur)
125{
126 short i;
127 char prompt[STRING];
128 char buf[HUGE_STRING];
129 char *err = NULL;
130 ADDRESS *adr = NULL;
131 int ret = 0;
132 int p = 0;
133
134 if (check_all_msg (actx, cur, 1) == -1)
135 return;
136
137 /* one or more messages? */
138 p = (cur || count_tagged (actx) == 1);
139
140 /* RfC 5322 mandates a From: header, so warn before bouncing
141 * messages without one */
142 if (cur)
143 {
144 if (!cur->hdr->env->from)
145 {
146 mutt_error _("Warning: message contains no From: header");
147 mutt_sleep (2);
148 mutt_clear_error ();
149 }
150 }
151 else
152 {
153 for (i = 0; i < actx->idxlen; i++)
154 {
155 if (actx->idx[i]->content->tagged)
156 {
157 if (!actx->idx[i]->content->hdr->env->from)
158 {
159 mutt_error _("Warning: message contains no From: header");
160 mutt_sleep (2);
161 mutt_clear_error ();
162 break;
163 }
164 }
165 }
166 }
167
168 if (p)
169 strfcpy (prompt, _("Bounce message to: "), sizeof (prompt));
170 else
171 strfcpy (prompt, _("Bounce tagged messages to: "), sizeof (prompt));
172
173 buf[0] = '\0';
174 if (mutt_get_field (prompt, buf, sizeof (buf), MUTT_ALIAS)
175 || buf[0] == '\0')
176 return;
177
178 if (!(adr = rfc822_parse_adrlist (adr, buf)))
179 {
180 mutt_error _("Error parsing address!");
181 return;
182 }
183
184 adr = mutt_expand_aliases (adr);
185
186 if (mutt_addrlist_to_intl (adr, &err) < 0)
187 {
188 mutt_error (_("Bad IDN: '%s'"), err);
189 FREE (&err);
190 rfc822_free_address (&adr);
191 return;
192 }
193
194 buf[0] = 0;
195 rfc822_write_address (buf, sizeof (buf), adr, 1);
196
197#define extra_space (15+7+2)
198 /*
199 * See commands.c.
200 */
201 snprintf (prompt, sizeof (prompt) - 4,
202 (p ? _("Bounce message to %s") : _("Bounce messages to %s")), buf);
203
204 if (mutt_strwidth (prompt) > MuttMessageWindow->cols - extra_space)
205 {
206 mutt_format_string (prompt, sizeof (prompt) - 4,
207 0, MuttMessageWindow->cols-extra_space, FMT_LEFT, 0,
208 prompt, sizeof (prompt), 0);
209 safe_strcat (prompt, sizeof (prompt), "...?");
210 }
211 else
212 safe_strcat (prompt, sizeof (prompt), "?");
213
214 if (query_quadoption (OPT_BOUNCE, prompt) != MUTT_YES)
215 {
216 rfc822_free_address (&adr);
217 mutt_window_clearline (MuttMessageWindow, 0);
218 mutt_message (p ? _("Message not bounced.") : _("Messages not bounced."));
219 return;
220 }
221
222 mutt_window_clearline (MuttMessageWindow, 0);
223
224 if (cur)
225 ret = mutt_bounce_message (fp, cur->hdr, adr);
226 else
227 {
228 for (i = 0; i < actx->idxlen; i++)
229 {
230 if (actx->idx[i]->content->tagged)
231 if (mutt_bounce_message (actx->idx[i]->fp, actx->idx[i]->content->hdr, adr))
232 ret = 1;
233 }
234 }
235
236 if (!ret)
237 mutt_message (p ? _("Message bounced.") : _("Messages bounced."));
238 else
239 mutt_error (p ? _("Error bouncing message!") : _("Error bouncing messages!"));
240
241 rfc822_free_address (&adr);
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, ATTACH_CONTEXT *actx,
254 BODY * cur)
255{
256 short i;
257
258 if (check_all_msg (actx, 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 < actx->idxlen; i++)
266 if (actx->idx[i]->content->tagged)
267 mutt_resend_message (actx->idx[i]->fp, Context, actx->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 ATTACHPTR *find_common_parent (ATTACH_CONTEXT *actx, short nattach)
281{
282 short i;
283 short nchildren;
284
285 for (i = 0; i < actx->idxlen; i++)
286 if (actx->idx[i]->content->tagged)
287 break;
288
289 while (--i >= 0)
290 {
291 if (mutt_is_message_type (actx->idx[i]->content->type, actx->idx[i]->content->subtype))
292 {
293 nchildren = count_tagged_children (actx, i);
294 if (nchildren == nattach)
295 return actx->idx[i];
296 }
297 }
298
299 return NULL;
300}
301
302/*
303 * check whether attachment #i is a parent of the attachment
304 * pointed to by cur
305 *
306 * Note: This and the calling procedure could be optimized quite a
307 * bit. For now, it's not worth the effort.
308 */
309
310static int is_parent (short i, ATTACH_CONTEXT *actx, BODY *cur)
311{
312 short level = actx->idx[i]->level;
313
314 while ((++i < actx->idxlen) && actx->idx[i]->level > level)
315 {
316 if (actx->idx[i]->content == cur)
317 return 1;
318 }
319
320 return 0;
321}
322
323static ATTACHPTR *find_parent (ATTACH_CONTEXT *actx, BODY *cur, short nattach)
324{
325 short i;
326 ATTACHPTR *parent = NULL;
327
328 if (cur)
329 {
330 for (i = 0; i < actx->idxlen; i++)
331 {
332 if (mutt_is_message_type (actx->idx[i]->content->type, actx->idx[i]->content->subtype)
333 && is_parent (i, actx, cur))
334 parent = actx->idx[i];
335 if (actx->idx[i]->content == cur)
336 break;
337 }
338 }
339 else if (nattach)
340 parent = find_common_parent (actx, nattach);
341
342 return parent;
343}
344
345static void include_header (int quote, FILE * ifp,
346 HEADER * hdr, FILE * ofp,
347 char *_prefix)
348{
349 int chflags = CH_DECODE;
350 char prefix[SHORT_STRING];
351
352 if (option (OPTWEED))
353 chflags |= CH_WEED | CH_REORDER;
354
355 if (quote)
356 {
357 if (_prefix)
358 strfcpy (prefix, _prefix, sizeof (prefix));
359 else if (!option (OPTTEXTFLOWED))
360 _mutt_make_string (prefix, sizeof (prefix), NONULL (Prefix),
361 Context, hdr, 0);
362 else
363 strfcpy (prefix, ">", sizeof (prefix));
364
365 chflags |= CH_PREFIX;
366 }
367
368 mutt_copy_header (ifp, hdr, ofp, chflags, quote ? prefix : NULL);
369}
370
371/* Attach all the body parts which can't be decoded.
372 * This code is shared by forwarding and replying. */
373
374static BODY ** copy_problematic_attachments (BODY **last,
375 ATTACH_CONTEXT *actx,
376 short force)
377{
378 short i;
379
380 for (i = 0; i < actx->idxlen; i++)
381 {
382 if (actx->idx[i]->content->tagged &&
383 (force || !mutt_can_decode (actx->idx[i]->content)))
384 {
385 if (mutt_copy_body (actx->idx[i]->fp, last, actx->idx[i]->content) == -1)
386 return NULL; /* XXXXX - may lead to crashes */
387 last = &((*last)->next);
388 }
389 }
390 return last;
391}
392
393/*
394 * forward one or several MIME bodies
395 * (non-message types)
396 */
397
398static void attach_forward_bodies (FILE * fp, HEADER * hdr,
399 ATTACH_CONTEXT *actx,
400 BODY * cur,
401 short nattach)
402{
403 short i;
404 short mime_fwd_all = 0;
405 short mime_fwd_any = 1;
406 ATTACHPTR *parent = NULL;
407 HEADER *parent_hdr;
408 FILE *parent_fp;
409 HEADER *tmphdr = NULL;
410 BODY **last;
411 BUFFER *tmpbody = NULL;
412 FILE *tmpfp = NULL;
413
414 char prefix[STRING];
415
416 int rc = 0;
417
418 STATE st;
419
420 /*
421 * First, find the parent message.
422 * Note: This could be made an option by just
423 * putting the following lines into an if block.
424 */
425
426
427 parent = find_parent (actx, cur, nattach);
428 if (parent)
429 {
430 parent_hdr = parent->content->hdr;
431 parent_fp = parent->fp;
432 }
433 else
434 {
435 parent_hdr = hdr;
436 parent_fp = actx->root_fp;
437 }
438
439
440 tmphdr = mutt_new_header ();
441 tmphdr->env = mutt_new_envelope ();
442 mutt_make_forward_subject (tmphdr->env, Context, parent_hdr);
443
444 tmpbody = mutt_buffer_pool_get ();
445 mutt_buffer_mktemp (tmpbody);
446 if ((tmpfp = safe_fopen (mutt_b2s (tmpbody), "w")) == NULL)
447 {
448 mutt_error (_("Can't open temporary file %s."), mutt_b2s (tmpbody));
449 goto bail;
450 }
451
452 mutt_forward_intro (Context, parent_hdr, tmpfp);
453
454 /* prepare the prefix here since we'll need it later. */
455
456 if (option (OPTFORWQUOTE))
457 {
458 if (!option (OPTTEXTFLOWED))
459 _mutt_make_string (prefix, sizeof (prefix), NONULL (Prefix), Context,
460 parent_hdr, 0);
461 else
462 strfcpy (prefix, ">", sizeof (prefix));
463 }
464
465 include_header (option (OPTFORWQUOTE), parent_fp, parent_hdr,
466 tmpfp, prefix);
467
468
469 /*
470 * Now, we have prepared the first part of the message body: The
471 * original message's header.
472 *
473 * The next part is more interesting: either include the message bodies,
474 * or attach them.
475 */
476
477 if ((!cur || mutt_can_decode (cur)) &&
478 (rc = query_quadoption (OPT_MIMEFWD,
479 _("Forward as attachments?"))) == MUTT_YES)
480 mime_fwd_all = 1;
481 else if (rc == -1)
482 goto bail;
483
484 /*
485 * shortcut MIMEFWDREST when there is only one attachment. Is
486 * this intuitive?
487 */
488
489 if (!mime_fwd_all && !cur && (nattach > 1)
490 && !check_can_decode (actx, cur))
491 {
492 if ((rc = query_quadoption (OPT_MIMEFWDREST,
493 _("Can't decode all tagged attachments. MIME-forward the others?"))) == -1)
494 goto bail;
495 else if (rc == MUTT_NO)
496 mime_fwd_any = 0;
497 }
498
499 /* initialize a state structure */
500
501 memset (&st, 0, sizeof (st));
502
503 if (option (OPTFORWQUOTE))
504 st.prefix = prefix;
505 st.flags = MUTT_CHARCONV;
506 if (option (OPTWEED))
507 st.flags |= MUTT_WEED;
508 st.fpout = tmpfp;
509
510 /* where do we append new MIME parts? */
511 last = &tmphdr->content;
512
513 if (cur)
514 {
515 /* single body case */
516
517 if (!mime_fwd_all && mutt_can_decode (cur))
518 {
519 st.fpin = fp;
520 mutt_body_handler (cur, &st);
521 state_putc ('\n', &st);
522 }
523 else
524 {
525 if (mutt_copy_body (fp, last, cur) == -1)
526 goto bail;
527 last = &((*last)->next);
528 }
529 }
530 else
531 {
532 /* multiple body case */
533
534 if (!mime_fwd_all)
535 {
536 for (i = 0; i < actx->idxlen; i++)
537 {
538 if (actx->idx[i]->content->tagged && mutt_can_decode (actx->idx[i]->content))
539 {
540 st.fpin = actx->idx[i]->fp;
541 mutt_body_handler (actx->idx[i]->content, &st);
542 state_putc ('\n', &st);
543 }
544 }
545 }
546
547 if (mime_fwd_any &&
548 copy_problematic_attachments (last, actx, mime_fwd_all) == NULL)
549 goto bail;
550 }
551
552 mutt_forward_trailer (Context, parent_hdr, tmpfp);
553
554 safe_fclose (&tmpfp);
555 tmpfp = NULL;
556
557 /* now that we have the template, send it. */
558 ci_send_message (0, tmphdr, mutt_b2s (tmpbody), NULL, parent_hdr);
559
560 mutt_buffer_pool_release (&tmpbody);
561 return;
562
563bail:
564 if (tmpfp)
565 {
566 safe_fclose (&tmpfp);
567 mutt_unlink (mutt_b2s (tmpbody));
568 }
569 mutt_buffer_pool_release (&tmpbody);
570
571 mutt_free_header (&tmphdr);
572}
573
574
575/*
576 * Forward one or several message-type attachments. This
577 * is different from the previous function
578 * since we want to mimic the index menu's behavior.
579 *
580 * Code reuse from ci_send_message is not possible here -
581 * ci_send_message relies on a context structure to find messages,
582 * while, on the attachment menu, messages are referenced through
583 * the attachment index.
584 */
585
586static void attach_forward_msgs (FILE * fp, HEADER * hdr,
587 ATTACH_CONTEXT *actx, BODY * cur)
588{
589 HEADER *curhdr = NULL;
590 HEADER *tmphdr = NULL;
591 short i;
592 int rc;
593
594 BODY **last;
595 BUFFER *tmpbody = NULL;
596 FILE *tmpfp = NULL;
597
598 int cmflags = 0;
599 int chflags = CH_XMIT;
600
601 if (cur)
602 curhdr = cur->hdr;
603 else
604 {
605 for (i = 0; i < actx->idxlen; i++)
606 if (actx->idx[i]->content->tagged)
607 {
608 curhdr = actx->idx[i]->content->hdr;
609 break;
610 }
611 }
612
613 tmphdr = mutt_new_header ();
614 tmphdr->env = mutt_new_envelope ();
615 mutt_make_forward_subject (tmphdr->env, Context, curhdr);
616
617
618 tmpbody = mutt_buffer_pool_get ();
619
620 if ((rc = query_quadoption (OPT_MIMEFWD,
621 _("Forward MIME encapsulated?"))) == MUTT_NO)
622 {
623
624 /* no MIME encapsulation */
625
626 mutt_buffer_mktemp (tmpbody);
627 if (!(tmpfp = safe_fopen (mutt_b2s (tmpbody), "w")))
628 {
629 mutt_error (_("Can't create %s."), mutt_b2s (tmpbody));
630 goto cleanup;
631 }
632
633 if (option (OPTFORWQUOTE))
634 {
635 chflags |= CH_PREFIX;
636 cmflags |= MUTT_CM_PREFIX;
637 }
638
639 if (option (OPTFORWDECODE))
640 {
641 cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
642 if (option (OPTWEED))
643 {
644 chflags |= CH_WEED | CH_REORDER;
645 cmflags |= MUTT_CM_WEED;
646 }
647 }
648
649
650 if (cur)
651 {
652 /* mutt_message_hook (cur->hdr, MUTT_MESSAGEHOOK); */
653 mutt_forward_intro (Context, cur->hdr, tmpfp);
654 _mutt_copy_message (tmpfp, fp, cur->hdr, cur->hdr->content, cmflags, chflags);
655 mutt_forward_trailer (Context, cur->hdr, tmpfp);
656 }
657 else
658 {
659 for (i = 0; i < actx->idxlen; i++)
660 {
661 if (actx->idx[i]->content->tagged)
662 {
663 /* mutt_message_hook (idx[i]->content->hdr, MUTT_MESSAGEHOOK); */
664 mutt_forward_intro (Context, actx->idx[i]->content->hdr, tmpfp);
665 _mutt_copy_message (tmpfp, actx->idx[i]->fp, actx->idx[i]->content->hdr,
666 actx->idx[i]->content->hdr->content, cmflags, chflags);
667 mutt_forward_trailer (Context, actx->idx[i]->content->hdr, tmpfp);
668 }
669 }
670 }
671 safe_fclose (&tmpfp);
672 }
673 else if (rc == MUTT_YES) /* do MIME encapsulation - we don't need to do much here */
674 {
675 last = &tmphdr->content;
676 if (cur)
677 mutt_copy_body (fp, last, cur);
678 else
679 {
680 for (i = 0; i < actx->idxlen; i++)
681 if (actx->idx[i]->content->tagged)
682 {
683 mutt_copy_body (actx->idx[i]->fp, last, actx->idx[i]->content);
684 last = &((*last)->next);
685 }
686 }
687 }
688 else
689 mutt_free_header (&tmphdr);
690
691 ci_send_message (0, tmphdr,
692 mutt_buffer_len (tmpbody) ? mutt_b2s (tmpbody) : NULL,
693 NULL, curhdr);
694 tmphdr = NULL; /* ci_send_message frees this */
695
696cleanup:
697 mutt_free_header (&tmphdr);
698 mutt_buffer_pool_release (&tmpbody);
699}
700
701void mutt_attach_forward (FILE * fp, HEADER * hdr,
702 ATTACH_CONTEXT *actx, BODY * cur)
703{
704 short nattach;
705
706
707 if (check_all_msg (actx, cur, 0) == 0)
708 attach_forward_msgs (fp, hdr, actx, cur);
709 else
710 {
711 nattach = count_tagged (actx);
712 attach_forward_bodies (fp, hdr, actx, cur, nattach);
713 }
714}
715
716void mutt_attach_mail_sender (FILE *fp, HEADER *hdr, ATTACH_CONTEXT *actx,
717 BODY *cur)
718{
719 HEADER *tmphdr = NULL;
720 short i;
721
722 if (check_all_msg (actx, cur, 0) == -1)
723 {
724 /* L10N: You will see this error message if you invoke <compose-to-sender>
725 when you are on a normal attachment.
726 */
727 mutt_error _("You may only compose to sender with message/rfc822 parts.");
728 return;
729 }
730
731 tmphdr = mutt_new_header ();
732 tmphdr->env = mutt_new_envelope ();
733
734 if (cur)
735 {
736 if (mutt_fetch_recips (tmphdr->env, cur->hdr->env, SENDTOSENDER) == -1)
737 return;
738 }
739 else
740 {
741 for (i = 0; i < actx->idxlen; i++)
742 {
743 if (actx->idx[i]->content->tagged &&
744 mutt_fetch_recips (tmphdr->env, actx->idx[i]->content->hdr->env,
745 SENDTOSENDER) == -1)
746 return;
747 }
748 }
749 ci_send_message (0, tmphdr, NULL, NULL, NULL);
750}
751
752
753/**
754 **
755 ** the various reply functions, from the attachment menu
756 **
757 **
758 **/
759
760/* Create the envelope defaults for a reply.
761 *
762 * This function can be invoked in two ways.
763 *
764 * Either, parent is NULL. In this case, all tagged bodies are of a message type,
765 * and the header information is fetched from them.
766 *
767 * Or, parent is non-NULL. In this case, cur is the common parent of all the
768 * tagged attachments.
769 *
770 * Note that this code is horribly similar to envelope_defaults () from send.c.
771 */
772
773static int
774attach_reply_envelope_defaults (ENVELOPE *env, ATTACH_CONTEXT *actx,
775 HEADER *parent, int flags)
776{
777 ENVELOPE *curenv = NULL;
778 HEADER *curhdr = NULL;
779 short i;
780
781 if (!parent)
782 {
783 for (i = 0; i < actx->idxlen; i++)
784 {
785 if (actx->idx[i]->content->tagged)
786 {
787 curhdr = actx->idx[i]->content->hdr;
788 curenv = curhdr->env;
789 break;
790 }
791 }
792 }
793 else
794 {
795 curenv = parent->env;
796 curhdr = parent;
797 }
798
799 if (curenv == NULL || curhdr == NULL)
800 {
801 mutt_error _("Can't find any tagged messages.");
802 return -1;
803 }
804
805 if (parent)
806 {
807 if (mutt_fetch_recips (env, curenv, flags) == -1)
808 return -1;
809 }
810 else
811 {
812 for (i = 0; i < actx->idxlen; i++)
813 {
814 if (actx->idx[i]->content->tagged
815 && mutt_fetch_recips (env, actx->idx[i]->content->hdr->env, flags) == -1)
816 return -1;
817 }
818 }
819
820 if ((flags & SENDLISTREPLY) && !env->to)
821 {
822 mutt_error _("No mailing lists found!");
823 return (-1);
824 }
825
826 mutt_fix_reply_recipients (env);
827 mutt_make_misc_reply_headers (env, Context, curhdr, curenv);
828
829 if (parent)
830 mutt_add_to_reference_headers (env, curenv, NULL, NULL);
831 else
832 {
833 LIST **p = NULL, **q = NULL;
834
835 for (i = 0; i < actx->idxlen; i++)
836 {
837 if (actx->idx[i]->content->tagged)
838 mutt_add_to_reference_headers (env, actx->idx[i]->content->hdr->env, &p, &q);
839 }
840 }
841
842 return 0;
843}
844
845
846/* This is _very_ similar to send.c's include_reply(). */
847
848static void attach_include_reply (FILE *fp, FILE *tmpfp, HEADER *cur, int flags)
849{
850 int cmflags = MUTT_CM_PREFIX | MUTT_CM_DECODE | MUTT_CM_CHARCONV;
851 int chflags = CH_DECODE;
852
853 /* mutt_message_hook (cur, MUTT_MESSAGEHOOK); */
854
855 mutt_make_attribution (Context, cur, tmpfp);
856
857 if (!option (OPTHEADER))
858 cmflags |= MUTT_CM_NOHEADER;
859 if (option (OPTWEED))
860 {
861 chflags |= CH_WEED;
862 cmflags |= MUTT_CM_WEED;
863 }
864
865 _mutt_copy_message (tmpfp, fp, cur, cur->content, cmflags, chflags);
866 mutt_make_post_indent (Context, cur, tmpfp);
867}
868
869void mutt_attach_reply (FILE * fp, HEADER * hdr,
870 ATTACH_CONTEXT *actx, BODY * cur,
871 int flags)
872{
873 short mime_reply_any = 0;
874
875 short nattach = 0;
876 ATTACHPTR *parent = NULL;
877 HEADER *parent_hdr = NULL;
878 FILE *parent_fp = NULL;
879 HEADER *tmphdr = NULL;
880 short i;
881
882 STATE st;
883 BUFFER *tmpbody = NULL;
884 FILE *tmpfp = NULL;
885
886 char prefix[SHORT_STRING];
887 int rc;
888
889 if (check_all_msg (actx, cur, 0) == -1)
890 {
891 nattach = count_tagged (actx);
892 if ((parent = find_parent (actx, cur, nattach)) != NULL)
893 {
894 parent_hdr = parent->content->hdr;
895 parent_fp = parent->fp;
896 }
897 else
898 {
899 parent_hdr = hdr;
900 parent_fp = actx->root_fp;
901 }
902 }
903
904 if (nattach > 1 && !check_can_decode (actx, cur))
905 {
906 if ((rc = query_quadoption (OPT_MIMEFWDREST,
907 _("Can't decode all tagged attachments. MIME-encapsulate the others?"))) == -1)
908 return;
909 else if (rc == MUTT_YES)
910 mime_reply_any = 1;
911 }
912 else if (nattach == 1)
913 mime_reply_any = 1;
914
915 tmphdr = mutt_new_header ();
916 tmphdr->env = mutt_new_envelope ();
917
918 if (attach_reply_envelope_defaults (tmphdr->env, actx,
919 parent_hdr ? parent_hdr : (cur ? cur->hdr : NULL), flags) == -1)
920 goto cleanup;
921
922 tmpbody = mutt_buffer_pool_get ();
923 mutt_buffer_mktemp (tmpbody);
924 if ((tmpfp = safe_fopen (mutt_b2s (tmpbody), "w")) == NULL)
925 {
926 mutt_error (_("Can't create %s."), mutt_b2s (tmpbody));
927 goto cleanup;
928 }
929
930 if (!parent_hdr)
931 {
932 if (cur)
933 attach_include_reply (fp, tmpfp, cur->hdr, flags);
934 else
935 {
936 for (i = 0; i < actx->idxlen; i++)
937 {
938 if (actx->idx[i]->content->tagged)
939 attach_include_reply (actx->idx[i]->fp, tmpfp, actx->idx[i]->content->hdr, flags);
940 }
941 }
942 }
943 else
944 {
945 mutt_make_attribution (Context, parent_hdr, tmpfp);
946
947 memset (&st, 0, sizeof (STATE));
948 st.fpout = tmpfp;
949
950 if (!option (OPTTEXTFLOWED))
951 _mutt_make_string (prefix, sizeof (prefix), NONULL (Prefix),
952 Context, parent_hdr, 0);
953 else
954 strfcpy (prefix, ">", sizeof (prefix));
955
956 st.prefix = prefix;
957 st.flags = MUTT_CHARCONV;
958
959 if (option (OPTWEED))
960 st.flags |= MUTT_WEED;
961
962 if (option (OPTHEADER))
963 include_header (1, parent_fp, parent_hdr, tmpfp, prefix);
964
965 if (cur)
966 {
967 if (mutt_can_decode (cur))
968 {
969 st.fpin = fp;
970 mutt_body_handler (cur, &st);
971 state_putc ('\n', &st);
972 }
973 else
974 mutt_copy_body (fp, &tmphdr->content, cur);
975 }
976 else
977 {
978 for (i = 0; i < actx->idxlen; i++)
979 {
980 if (actx->idx[i]->content->tagged && mutt_can_decode (actx->idx[i]->content))
981 {
982 st.fpin = actx->idx[i]->fp;
983 mutt_body_handler (actx->idx[i]->content, &st);
984 state_putc ('\n', &st);
985 }
986 }
987 }
988
989 mutt_make_post_indent (Context, parent_hdr, tmpfp);
990
991 if (mime_reply_any && !cur &&
992 copy_problematic_attachments (&tmphdr->content, actx, 0) == NULL)
993 {
994 goto cleanup;
995 }
996 }
997
998 safe_fclose (&tmpfp);
999
1000 if (ci_send_message (flags, tmphdr, mutt_b2s (tmpbody), NULL,
1001 parent_hdr ? parent_hdr : (cur ? cur->hdr : NULL)) == 0)
1002 mutt_set_flag (Context, hdr, MUTT_REPLIED, 1);
1003
1004 tmphdr = NULL; /* ci_send_message frees this */
1005
1006cleanup:
1007 if (tmpfp)
1008 {
1009 safe_fclose (&tmpfp);
1010 mutt_unlink (mutt_b2s (tmpbody));
1011 }
1012 mutt_buffer_pool_release (&tmpbody);
1013 mutt_free_header (&tmphdr);
1014}