mutt stable branch with some hacks
at jcs 1014 lines 23 kB view raw
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}