mutt stable branch with some hacks
at jcs 1154 lines 28 kB view raw
1/* 2 * Copyright (C) 1996-2000,2002,2013 Michael R. Elkins <me@mutt.org> 3 * Copyright (C) 1999-2004,2006 Thomas Roessler <roessler@does-not-exist.org> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 */ 19 20#if HAVE_CONFIG_H 21# include "config.h" 22#endif 23 24#include "mutt.h" 25#include "mutt_menu.h" 26#include "attach.h" 27#include "mutt_curses.h" 28#include "keymap.h" 29#include "rfc1524.h" 30#include "mime.h" 31#include "pager.h" 32#include "mailbox.h" 33#include "copy.h" 34#include "mx.h" 35#include "mutt_crypt.h" 36 37#include <ctype.h> 38#include <stdlib.h> 39#include <unistd.h> 40#include <sys/wait.h> 41#include <sys/stat.h> 42#include <fcntl.h> 43#include <string.h> 44#include <errno.h> 45 46int mutt_get_tmp_attachment (BODY *a) 47{ 48 char type[STRING]; 49 BUFFER *tempfile = NULL; 50 rfc1524_entry *entry = NULL; 51 FILE *fpin = NULL, *fpout = NULL; 52 struct stat st; 53 54 if (a->unlink) 55 return 0; 56 57 tempfile = mutt_buffer_pool_get (); 58 entry = rfc1524_new_entry(); 59 60 snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype); 61 rfc1524_mailcap_lookup(a, type, sizeof(type), entry, 0); 62 mutt_rfc1524_expand_filename (entry->nametemplate, a->filename, tempfile); 63 64 rfc1524_free_entry(&entry); 65 66 if (stat(a->filename, &st) == -1) 67 { 68 mutt_buffer_pool_release (&tempfile); 69 return -1; 70 } 71 72 if ((fpin = fopen(a->filename, "r")) && /* __FOPEN_CHECKED__ */ 73 (fpout = safe_fopen(mutt_b2s (tempfile), "w"))) 74 { 75 mutt_copy_stream (fpin, fpout); 76 mutt_str_replace (&a->filename, mutt_b2s (tempfile)); 77 a->unlink = 1; 78 79 if (a->stamp >= st.st_mtime) 80 mutt_stamp_attachment(a); 81 } 82 else 83 mutt_perror(fpin ? mutt_b2s (tempfile) : a->filename); 84 85 if (fpin) safe_fclose (&fpin); 86 if (fpout) safe_fclose (&fpout); 87 88 mutt_buffer_pool_release (&tempfile); 89 90 return a->unlink ? 0 : -1; 91} 92 93 94/* return 1 if require full screen redraw, 0 otherwise */ 95int mutt_compose_attachment (BODY *a) 96{ 97 char type[STRING]; 98 BUFFER *command = mutt_buffer_pool_get (); 99 BUFFER *newfile = mutt_buffer_pool_get (); 100 BUFFER *tempfile = mutt_buffer_pool_get (); 101 rfc1524_entry *entry = rfc1524_new_entry (); 102 short unlink_newfile = 0; 103 int rc = 0; 104 105 snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype); 106 if (rfc1524_mailcap_lookup (a, type, sizeof(type), entry, MUTT_COMPOSE)) 107 { 108 if (entry->composecommand || entry->composetypecommand) 109 { 110 if (entry->composetypecommand) 111 mutt_buffer_strcpy (command, entry->composetypecommand); 112 else 113 mutt_buffer_strcpy (command, entry->composecommand); 114 115 mutt_rfc1524_expand_filename (entry->nametemplate, 116 a->filename, newfile); 117 dprint(1, (debugfile, "oldfile: %s\t newfile: %s\n", 118 a->filename, mutt_b2s (newfile))); 119 120 if (safe_symlink (a->filename, mutt_b2s (newfile)) == -1) 121 { 122 if (mutt_yesorno (_("Can't match nametemplate, continue?"), MUTT_YES) != MUTT_YES) 123 goto bailout; 124 mutt_buffer_strcpy (newfile, a->filename); 125 } 126 else 127 unlink_newfile = 1; 128 129 if (mutt_rfc1524_expand_command (a, mutt_b2s (newfile), type, command)) 130 { 131 /* For now, editing requires a file, no piping */ 132 mutt_error _("Mailcap compose entry requires %%s"); 133 } 134 else 135 { 136 int r; 137 138 mutt_endwin (NULL); 139 if ((r = mutt_system (mutt_b2s (command))) == -1) 140 mutt_error (_("Error running \"%s\"!"), mutt_b2s (command)); 141 142 if (r != -1 && entry->composetypecommand) 143 { 144 BODY *b; 145 FILE *fp, *tfp; 146 147 if ((fp = safe_fopen (a->filename, "r")) == NULL) 148 { 149 mutt_perror _("Failure to open file to parse headers."); 150 goto bailout; 151 } 152 153 b = mutt_read_mime_header (fp, 0); 154 if (b) 155 { 156 if (b->parameter) 157 { 158 mutt_free_parameter (&a->parameter); 159 a->parameter = b->parameter; 160 b->parameter = NULL; 161 } 162 if (b->description) 163 { 164 FREE (&a->description); 165 a->description = b->description; 166 b->description = NULL; 167 } 168 if (b->form_name) 169 { 170 FREE (&a->form_name); 171 a->form_name = b->form_name; 172 b->form_name = NULL; 173 } 174 175 /* Remove headers by copying out data to another file, then 176 * copying the file back */ 177 fseeko (fp, b->offset, 0); 178 mutt_buffer_mktemp (tempfile); 179 if ((tfp = safe_fopen (mutt_b2s (tempfile), "w")) == NULL) 180 { 181 mutt_perror _("Failure to open file to strip headers."); 182 goto bailout; 183 } 184 mutt_copy_stream (fp, tfp); 185 safe_fclose (&fp); 186 safe_fclose (&tfp); 187 mutt_unlink (a->filename); 188 if (mutt_rename_file (mutt_b2s (tempfile), a->filename) != 0) 189 { 190 mutt_perror _("Failure to rename file."); 191 goto bailout; 192 } 193 194 mutt_free_body (&b); 195 } 196 } 197 } 198 } 199 } 200 else 201 { 202 mutt_message (_("No mailcap compose entry for %s, creating empty file."), 203 type); 204 rc = 1; 205 goto bailout; 206 } 207 208 rc = 1; 209 210bailout: 211 212 if (unlink_newfile) 213 unlink(mutt_b2s (newfile)); 214 215 mutt_buffer_pool_release (&command); 216 mutt_buffer_pool_release (&newfile); 217 mutt_buffer_pool_release (&tempfile); 218 219 rfc1524_free_entry (&entry); 220 return rc; 221} 222 223/* 224 * Currently, this only works for send mode, as it assumes that the 225 * BODY->filename actually contains the information. I'm not sure 226 * we want to deal with editing attachments we've already received, 227 * so this should be ok. 228 * 229 * Returns 1 if editor found, 0 if not (useful to tell calling menu to 230 * redraw) 231 */ 232int mutt_edit_attachment (BODY *a) 233{ 234 char type[STRING]; 235 BUFFER *command = mutt_buffer_pool_get (); 236 BUFFER *newfile = mutt_buffer_pool_get (); 237 rfc1524_entry *entry = rfc1524_new_entry (); 238 short unlink_newfile = 0; 239 int rc = 0; 240 241 snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype); 242 if (rfc1524_mailcap_lookup (a, type, sizeof(type), entry, MUTT_EDIT)) 243 { 244 if (entry->editcommand) 245 { 246 247 mutt_buffer_strcpy (command, entry->editcommand); 248 mutt_rfc1524_expand_filename (entry->nametemplate, 249 a->filename, newfile); 250 dprint(1, (debugfile, "oldfile: %s\t newfile: %s\n", 251 a->filename, mutt_b2s (newfile))); 252 253 if (safe_symlink (a->filename, mutt_b2s (newfile)) == -1) 254 { 255 if (mutt_yesorno (_("Can't match nametemplate, continue?"), MUTT_YES) != MUTT_YES) 256 goto bailout; 257 mutt_buffer_strcpy (newfile, a->filename); 258 } 259 else 260 unlink_newfile = 1; 261 262 if (mutt_rfc1524_expand_command (a, mutt_b2s (newfile), type, command)) 263 { 264 /* For now, editing requires a file, no piping */ 265 mutt_error _("Mailcap Edit entry requires %%s"); 266 goto bailout; 267 } 268 else 269 { 270 mutt_endwin (NULL); 271 if (mutt_system (mutt_b2s (command)) == -1) 272 { 273 mutt_error (_("Error running \"%s\"!"), mutt_b2s (command)); 274 goto bailout; 275 } 276 } 277 } 278 } 279 else if (a->type == TYPETEXT) 280 { 281 /* On text, default to editor */ 282 mutt_edit_file (NONULL (Editor), a->filename); 283 } 284 else 285 { 286 mutt_error (_("No mailcap edit entry for %s"),type); 287 rc = 0; 288 goto bailout; 289 } 290 291 rc = 1; 292 293bailout: 294 295 if (unlink_newfile) 296 unlink(mutt_b2s (newfile)); 297 298 mutt_buffer_pool_release (&command); 299 mutt_buffer_pool_release (&newfile); 300 301 rfc1524_free_entry (&entry); 302 return rc; 303} 304 305 306void mutt_check_lookup_list (BODY *b, char *type, size_t len) 307{ 308 LIST *t = MimeLookupList; 309 int i; 310 311 for (; t; t = t->next) 312 { 313 i = mutt_strlen (t->data) - 1; 314 if ((i > 0 && t->data[i-1] == '/' && t->data[i] == '*' && 315 ascii_strncasecmp (type, t->data, i) == 0) || 316 ascii_strcasecmp (type, t->data) == 0) 317 { 318 BODY tmp = {0}; 319 int n; 320 if ((n = mutt_lookup_mime_type (&tmp, b->filename)) != TYPEOTHER) 321 { 322 snprintf (type, len, "%s/%s", 323 n == TYPEAUDIO ? "audio" : 324 n == TYPEAPPLICATION ? "application" : 325 n == TYPEIMAGE ? "image" : 326 n == TYPEMESSAGE ? "message" : 327 n == TYPEMODEL ? "model" : 328 n == TYPEMULTIPART ? "multipart" : 329 n == TYPETEXT ? "text" : 330 n == TYPEVIDEO ? "video" : "other", 331 tmp.subtype); 332 dprint(1, (debugfile, "mutt_check_lookup_list: \"%s\" -> %s\n", 333 b->filename, type)); 334 } 335 if (tmp.subtype) 336 FREE (&tmp.subtype); 337 if (tmp.xtype) 338 FREE (&tmp.xtype); 339 } 340 } 341} 342 343/* returns -1 on error, 0 or the return code from mutt_do_pager() on success */ 344int mutt_view_attachment (FILE *fp, BODY *a, int flag, HEADER *hdr, 345 ATTACH_CONTEXT *actx) 346{ 347 BUFFER *tempfile = NULL; 348 BUFFER *pagerfile = NULL; 349 BUFFER *command = NULL; 350 int is_message; 351 int use_mailcap; 352 int use_pipe = 0; 353 int use_pager = 1; 354 char type[STRING]; 355 char descrip[STRING]; 356 char *fname; 357 rfc1524_entry *entry = NULL; 358 int rc = -1; 359 int unlink_tempfile = 0; 360 361 is_message = mutt_is_message_type(a->type, a->subtype); 362 if (WithCrypto && is_message && a->hdr && (a->hdr->security & ENCRYPT) && 363 !crypt_valid_passphrase(a->hdr->security)) 364 return (rc); 365 366 tempfile = mutt_buffer_pool_get (); 367 pagerfile = mutt_buffer_pool_get (); 368 command = mutt_buffer_pool_get (); 369 370 use_mailcap = (flag == MUTT_MAILCAP || 371 (flag == MUTT_REGULAR && mutt_needs_mailcap (a))); 372 snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype); 373 374 if (use_mailcap) 375 { 376 entry = rfc1524_new_entry (); 377 if (!rfc1524_mailcap_lookup (a, type, sizeof(type), entry, 0)) 378 { 379 if (flag == MUTT_REGULAR) 380 { 381 /* fallback to view as text */ 382 rfc1524_free_entry (&entry); 383 mutt_error _("No matching mailcap entry found. Viewing as text."); 384 flag = MUTT_AS_TEXT; 385 use_mailcap = 0; 386 } 387 else 388 goto return_error; 389 } 390 } 391 392 if (use_mailcap) 393 { 394 if (!entry->command) 395 { 396 mutt_error _("MIME type not defined. Cannot view attachment."); 397 goto return_error; 398 } 399 mutt_buffer_strcpy (command, entry->command); 400 401 if (fp) 402 { 403 fname = safe_strdup (a->filename); 404 mutt_sanitize_filename (fname, 1); 405 } 406 else 407 fname = a->filename; 408 409 mutt_rfc1524_expand_filename (entry->nametemplate, fname, 410 tempfile); 411 412 /* send case: the file is already there; symlink to it */ 413 if (fp == NULL) 414 { 415 if (safe_symlink (a->filename, mutt_b2s (tempfile)) == -1) 416 { 417 if (mutt_yesorno (_("Can't match nametemplate, continue?"), MUTT_YES) != MUTT_YES) 418 goto return_error; 419 mutt_buffer_strcpy (tempfile, a->filename); 420 } 421 else 422 unlink_tempfile = 1; 423 } 424 /* recv case: we need to save the attachment to a file */ 425 else 426 { 427 FREE (&fname); 428 if (mutt_save_attachment (fp, a, mutt_b2s (tempfile), 0, NULL) == -1) 429 goto return_error; 430 } 431 432 use_pipe = mutt_rfc1524_expand_command (a, mutt_b2s (tempfile), type, 433 command); 434 use_pager = entry->copiousoutput; 435 } 436 437 if (use_pager) 438 { 439 if (fp && !use_mailcap && a->filename) 440 { 441 /* recv case */ 442 mutt_buffer_strcpy (pagerfile, a->filename); 443 mutt_adv_mktemp (pagerfile); 444 } 445 else 446 mutt_buffer_mktemp (pagerfile); 447 } 448 449 if (use_mailcap) 450 { 451 pid_t thepid = 0; 452 int tempfd = -1, pagerfd = -1; 453 454 if (!use_pager) 455 mutt_endwin (NULL); 456 457 if (use_pager || use_pipe) 458 { 459 if (use_pager && ((pagerfd = safe_open (mutt_b2s (pagerfile), O_CREAT | O_EXCL | O_WRONLY)) == -1)) 460 { 461 mutt_perror ("open"); 462 goto return_error; 463 } 464 if (use_pipe && ((tempfd = open (mutt_b2s (tempfile), 0)) == -1)) 465 { 466 if (pagerfd != -1) 467 close(pagerfd); 468 mutt_perror ("open"); 469 goto return_error; 470 } 471 472 if ((thepid = mutt_create_filter_fd (mutt_b2s (command), NULL, NULL, NULL, 473 use_pipe ? tempfd : -1, use_pager ? pagerfd : -1, -1)) == -1) 474 { 475 if (pagerfd != -1) 476 close(pagerfd); 477 478 if (tempfd != -1) 479 close(tempfd); 480 481 mutt_error _("Cannot create filter"); 482 goto return_error; 483 } 484 485 if (use_pager) 486 { 487 if (a->description) 488 snprintf (descrip, sizeof (descrip), 489 _("---Command: %-20.20s Description: %s"), 490 mutt_b2s (command), a->description); 491 else 492 snprintf (descrip, sizeof (descrip), 493 _("---Command: %-30.30s Attachment: %s"), mutt_b2s (command), type); 494 495 mutt_wait_filter (thepid); 496 } 497 else 498 { 499 if (mutt_wait_interactive_filter (thepid) || 500 (entry->needsterminal && option (OPTWAITKEY))) 501 mutt_any_key_to_continue (NULL); 502 } 503 504 if (tempfd != -1) 505 close (tempfd); 506 if (pagerfd != -1) 507 close (pagerfd); 508 } 509 else 510 { 511 /* interactive command */ 512 if (mutt_system (mutt_b2s (command)) || 513 (entry->needsterminal && option (OPTWAITKEY))) 514 mutt_any_key_to_continue (NULL); 515 } 516 } 517 else 518 { 519 /* Don't use mailcap; the attachment is viewed in the pager */ 520 521 if (flag == MUTT_AS_TEXT) 522 { 523 /* just let me see the raw data */ 524 if (fp) 525 { 526 /* Viewing from a received message. 527 * 528 * Don't use mutt_save_attachment() because we want to perform charset 529 * conversion since this will be displayed by the internal pager. 530 */ 531 STATE decode_state; 532 533 memset(&decode_state, 0, sizeof(decode_state)); 534 decode_state.fpout = safe_fopen(mutt_b2s (pagerfile), "w"); 535 if (!decode_state.fpout) 536 { 537 dprint(1, (debugfile, "mutt_view_attachment:%d safe_fopen(%s) errno=%d %s\n", 538 __LINE__, mutt_b2s (pagerfile), errno, strerror(errno))); 539 mutt_perror(mutt_b2s (pagerfile)); 540 mutt_sleep(1); 541 goto return_error; 542 } 543 decode_state.fpin = fp; 544 decode_state.flags = MUTT_CHARCONV; 545 mutt_decode_attachment(a, &decode_state); 546 if (fclose(decode_state.fpout) == EOF) 547 dprint(1, (debugfile, "mutt_view_attachment:%d fclose errno=%d %s\n", 548 __LINE__, mutt_b2s (pagerfile), errno, strerror(errno))); 549 } 550 else 551 { 552 /* in compose mode, just copy the file. we can't use 553 * mutt_decode_attachment() since it assumes the content-encoding has 554 * already been applied 555 */ 556 if (mutt_save_attachment(fp, a, mutt_b2s (pagerfile), 0, NULL)) 557 goto return_error; 558 } 559 } 560 else 561 { 562 /* Use built-in handler */ 563 set_option (OPTVIEWATTACH); /* disable the "use 'v' to view this part" 564 * message in case of error */ 565 if (mutt_decode_save_attachment (fp, a, mutt_b2s (pagerfile), MUTT_DISPLAY, 0)) 566 { 567 unset_option (OPTVIEWATTACH); 568 goto return_error; 569 } 570 unset_option (OPTVIEWATTACH); 571 } 572 573 if (a->description) 574 strfcpy (descrip, a->description, sizeof (descrip)); 575 else if (a->filename) 576 snprintf (descrip, sizeof (descrip), _("---Attachment: %s: %s"), 577 a->filename, type); 578 else 579 snprintf (descrip, sizeof (descrip), _("---Attachment: %s"), type); 580 } 581 582 /* We only reach this point if there have been no errors */ 583 584 if (use_pager) 585 { 586 pager_t info; 587 588 memset (&info, 0, sizeof (info)); 589 info.fp = fp; 590 info.bdy = a; 591 info.ctx = Context; 592 info.actx = actx; 593 info.hdr = hdr; 594 595 rc = mutt_do_pager (descrip, mutt_b2s (pagerfile), 596 MUTT_PAGER_ATTACHMENT | (is_message ? MUTT_PAGER_MESSAGE : 0), &info); 597 mutt_buffer_clear (pagerfile); 598 } 599 else 600 rc = 0; 601 602return_error: 603 604 rfc1524_free_entry (&entry); 605 if (fp && (mutt_b2s (tempfile))[0]) 606 mutt_unlink (mutt_b2s (tempfile)); 607 else if (unlink_tempfile) 608 unlink (mutt_b2s (tempfile)); 609 610 if ((mutt_b2s (pagerfile))[0]) 611 mutt_unlink (mutt_b2s (pagerfile)); 612 613 mutt_buffer_pool_release (&tempfile); 614 mutt_buffer_pool_release (&pagerfile); 615 mutt_buffer_pool_release (&command); 616 617 return rc; 618} 619 620/* returns 1 on success, 0 on error */ 621int mutt_pipe_attachment (FILE *fp, BODY *b, const char *path, const char *outfile) 622{ 623 pid_t thepid; 624 int out = -1; 625 int rv = 0; 626 627 if (outfile && *outfile) 628 if ((out = safe_open (outfile, O_CREAT | O_EXCL | O_WRONLY)) < 0) 629 { 630 mutt_perror ("open"); 631 return 0; 632 } 633 634 mutt_endwin (NULL); 635 636 if (fp) 637 { 638 /* recv case */ 639 640 STATE s; 641 642 memset (&s, 0, sizeof (STATE)); 643 /* perform charset conversion on text attachments when piping */ 644 s.flags = MUTT_CHARCONV; 645 646 if (outfile && *outfile) 647 thepid = mutt_create_filter_fd (path, &s.fpout, NULL, NULL, -1, out, -1); 648 else 649 thepid = mutt_create_filter (path, &s.fpout, NULL, NULL); 650 651 if (thepid < 0) 652 { 653 mutt_perror _("Can't create filter"); 654 goto bail; 655 } 656 657 s.fpin = fp; 658 mutt_decode_attachment (b, &s); 659 safe_fclose (&s.fpout); 660 } 661 else 662 { 663 /* send case */ 664 665 FILE *ifp, *ofp; 666 667 if ((ifp = fopen (b->filename, "r")) == NULL) 668 { 669 mutt_perror ("fopen"); 670 if (outfile && *outfile) 671 { 672 close (out); 673 unlink (outfile); 674 } 675 return 0; 676 } 677 678 if (outfile && *outfile) 679 thepid = mutt_create_filter_fd (path, &ofp, NULL, NULL, -1, out, -1); 680 else 681 thepid = mutt_create_filter (path, &ofp, NULL, NULL); 682 683 if (thepid < 0) 684 { 685 mutt_perror _("Can't create filter"); 686 safe_fclose (&ifp); 687 goto bail; 688 } 689 690 mutt_copy_stream (ifp, ofp); 691 safe_fclose (&ofp); 692 safe_fclose (&ifp); 693 } 694 695 rv = 1; 696 697bail: 698 699 if (outfile && *outfile) 700 close (out); 701 702 /* 703 * check for error exit from child process 704 */ 705 if (mutt_wait_filter (thepid) != 0) 706 rv = 0; 707 708 if (rv == 0 || option (OPTWAITKEY)) 709 mutt_any_key_to_continue (NULL); 710 return rv; 711} 712 713static FILE * 714mutt_save_attachment_open (const char *path, int flags) 715{ 716 if (flags == MUTT_SAVE_APPEND) 717 return fopen (path, "a"); 718 if (flags == MUTT_SAVE_OVERWRITE) 719 return fopen (path, "w"); /* __FOPEN_CHECKED__ */ 720 721 return safe_fopen (path, "w"); 722} 723 724/* returns 0 on success, -1 on error */ 725int mutt_save_attachment (FILE *fp, BODY *m, const char *path, int flags, HEADER *hdr) 726{ 727 if (fp) 728 { 729 730 /* recv mode */ 731 732 if (hdr && 733 m->hdr && 734 m->encoding != ENCBASE64 && 735 m->encoding != ENCQUOTEDPRINTABLE && 736 mutt_is_message_type(m->type, m->subtype)) 737 { 738 /* message type attachments are written to mail folders. */ 739 740 char buf[HUGE_STRING]; 741 HEADER *hn; 742 CONTEXT ctx; 743 MESSAGE *msg; 744 int chflags = 0; 745 int r = -1; 746 747 hn = m->hdr; 748 hn->msgno = hdr->msgno; /* required for MH/maildir */ 749 hn->read = 1; 750 751 fseeko (fp, m->offset, 0); 752 if (fgets (buf, sizeof (buf), fp) == NULL) 753 return -1; 754 if (mx_open_mailbox(path, MUTT_APPEND | MUTT_QUIET, &ctx) == NULL) 755 return -1; 756 if ((msg = mx_open_new_message (&ctx, hn, is_from (buf, NULL, 0, NULL) ? 0 : MUTT_ADD_FROM)) == NULL) 757 { 758 mx_close_mailbox(&ctx, NULL); 759 return -1; 760 } 761 if (ctx.magic == MUTT_MBOX || ctx.magic == MUTT_MMDF) 762 chflags = CH_FROM | CH_UPDATE_LEN; 763 chflags |= (ctx.magic == MUTT_MAILDIR ? CH_NOSTATUS : CH_UPDATE); 764 if (_mutt_copy_message (msg->fp, fp, hn, hn->content, 0, chflags) == 0 765 && mx_commit_message (msg, &ctx) == 0) 766 r = 0; 767 else 768 r = -1; 769 770 mx_close_message (&ctx, &msg); 771 mx_close_mailbox (&ctx, NULL); 772 return r; 773 } 774 else 775 { 776 /* In recv mode, extract from folder and decode */ 777 778 STATE s; 779 780 memset (&s, 0, sizeof (s)); 781 if ((s.fpout = mutt_save_attachment_open (path, flags)) == NULL) 782 { 783 mutt_perror ("fopen"); 784 mutt_sleep (2); 785 return (-1); 786 } 787 fseeko ((s.fpin = fp), m->offset, 0); 788 mutt_decode_attachment (m, &s); 789 790 if (fclose (s.fpout) != 0) 791 { 792 mutt_perror ("fclose"); 793 mutt_sleep (2); 794 return (-1); 795 } 796 } 797 } 798 else 799 { 800 /* In send mode, just copy file */ 801 802 FILE *ofp, *nfp; 803 804 if ((ofp = fopen (m->filename, "r")) == NULL) 805 { 806 mutt_perror ("fopen"); 807 return (-1); 808 } 809 810 if ((nfp = mutt_save_attachment_open (path, flags)) == NULL) 811 { 812 mutt_perror ("fopen"); 813 safe_fclose (&ofp); 814 return (-1); 815 } 816 817 if (mutt_copy_stream (ofp, nfp) == -1) 818 { 819 mutt_error _("Write fault!"); 820 safe_fclose (&ofp); 821 safe_fclose (&nfp); 822 return (-1); 823 } 824 safe_fclose (&ofp); 825 safe_fclose (&nfp); 826 } 827 828 return 0; 829} 830 831/* returns 0 on success, -1 on error */ 832int mutt_decode_save_attachment (FILE *fp, BODY *m, const char *path, 833 int displaying, int flags) 834{ 835 STATE s; 836 unsigned int saved_encoding = 0; 837 BODY *saved_parts = NULL; 838 HEADER *saved_hdr = NULL; 839 840 memset (&s, 0, sizeof (s)); 841 s.flags = displaying; 842 843 if (flags == MUTT_SAVE_APPEND) 844 s.fpout = fopen (path, "a"); 845 else if (flags == MUTT_SAVE_OVERWRITE) 846 s.fpout = fopen (path, "w"); /* __FOPEN_CHECKED__ */ 847 else 848 s.fpout = safe_fopen (path, "w"); 849 850 if (s.fpout == NULL) 851 { 852 mutt_perror ("fopen"); 853 return (-1); 854 } 855 856 if (fp == NULL) 857 { 858 /* When called from the compose menu, the attachment isn't parsed, 859 * so we need to do it here. */ 860 struct stat st; 861 862 if (stat (m->filename, &st) == -1) 863 { 864 mutt_perror ("stat"); 865 safe_fclose (&s.fpout); 866 return (-1); 867 } 868 869 if ((s.fpin = fopen (m->filename, "r")) == NULL) 870 { 871 mutt_perror ("fopen"); 872 return (-1); 873 } 874 875 saved_encoding = m->encoding; 876 if (!is_multipart (m)) 877 m->encoding = ENC8BIT; 878 879 m->length = st.st_size; 880 m->offset = 0; 881 saved_parts = m->parts; 882 saved_hdr = m->hdr; 883 mutt_parse_part (s.fpin, m); 884 885 if (m->noconv || is_multipart (m)) 886 s.flags |= MUTT_CHARCONV; 887 } 888 else 889 { 890 s.fpin = fp; 891 s.flags |= MUTT_CHARCONV; 892 } 893 894 mutt_body_handler (m, &s); 895 896 safe_fclose (&s.fpout); 897 if (fp == NULL) 898 { 899 m->length = 0; 900 m->encoding = saved_encoding; 901 if (saved_parts) 902 { 903 mutt_free_header (&m->hdr); 904 m->parts = saved_parts; 905 m->hdr = saved_hdr; 906 } 907 safe_fclose (&s.fpin); 908 } 909 910 return (0); 911} 912 913/* Ok, the difference between send and receive: 914 * recv: BODY->filename is a suggested name, and Context|HEADER points 915 * to the attachment in mailbox which is encoded 916 * send: BODY->filename points to the un-encoded file which contains the 917 * attachment 918 */ 919 920int mutt_print_attachment (FILE *fp, BODY *a) 921{ 922 BUFFER *newfile = mutt_buffer_pool_get (); 923 BUFFER *command = mutt_buffer_pool_get (); 924 char type[STRING]; 925 pid_t thepid; 926 FILE *ifp, *fpout; 927 short unlink_newfile = 0; 928 int rc = 0; 929 930 snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype); 931 932 if (rfc1524_mailcap_lookup (a, type, sizeof(type), NULL, MUTT_PRINT)) 933 { 934 rfc1524_entry *entry = NULL; 935 int piped = FALSE; 936 937 dprint (2, (debugfile, "Using mailcap...\n")); 938 939 entry = rfc1524_new_entry (); 940 rfc1524_mailcap_lookup (a, type, sizeof(type), entry, MUTT_PRINT); 941 mutt_rfc1524_expand_filename (entry->nametemplate, a->filename, 942 newfile); 943 944 /* send mode: symlink from existing file to the newfile */ 945 if (!fp) 946 { 947 if (safe_symlink (a->filename, mutt_b2s (newfile)) == -1) 948 { 949 if (mutt_yesorno (_("Can't match nametemplate, continue?"), MUTT_YES) != MUTT_YES) 950 goto mailcap_cleanup; 951 mutt_buffer_strcpy (newfile, a->filename); 952 } 953 else 954 unlink_newfile = 1; 955 } 956 /* in recv mode, save file to newfile first */ 957 else 958 { 959 if (mutt_save_attachment (fp, a, mutt_b2s (newfile), 0, NULL) == -1) 960 goto mailcap_cleanup; 961 } 962 963 mutt_buffer_strcpy (command, entry->printcommand); 964 piped = mutt_rfc1524_expand_command (a, mutt_b2s (newfile), type, command); 965 966 mutt_endwin (NULL); 967 968 /* interactive program */ 969 if (piped) 970 { 971 if ((ifp = fopen (mutt_b2s (newfile), "r")) == NULL) 972 { 973 mutt_perror ("fopen"); 974 goto mailcap_cleanup; 975 } 976 977 if ((thepid = mutt_create_filter (mutt_b2s (command), &fpout, NULL, NULL)) < 0) 978 { 979 mutt_perror _("Can't create filter"); 980 safe_fclose (&ifp); 981 goto mailcap_cleanup; 982 } 983 mutt_copy_stream (ifp, fpout); 984 safe_fclose (&fpout); 985 safe_fclose (&ifp); 986 if (mutt_wait_filter (thepid) || option (OPTWAITKEY)) 987 mutt_any_key_to_continue (NULL); 988 } 989 else 990 { 991 if (mutt_system (mutt_b2s (command)) || option (OPTWAITKEY)) 992 mutt_any_key_to_continue (NULL); 993 } 994 995 rc = 1; 996 997 mailcap_cleanup: 998 if (fp) 999 mutt_unlink (mutt_b2s (newfile)); 1000 else if (unlink_newfile) 1001 unlink(mutt_b2s (newfile)); 1002 1003 rfc1524_free_entry (&entry); 1004 goto out; 1005 } 1006 1007 if (!ascii_strcasecmp ("text/plain", type) || 1008 !ascii_strcasecmp ("application/postscript", type)) 1009 { 1010 rc = mutt_pipe_attachment (fp, a, NONULL(PrintCmd), NULL); 1011 goto out; 1012 } 1013 else if (mutt_can_decode (a)) 1014 { 1015 /* decode and print */ 1016 1017 ifp = NULL; 1018 fpout = NULL; 1019 1020 mutt_buffer_mktemp (newfile); 1021 if (mutt_decode_save_attachment (fp, a, mutt_b2s (newfile), MUTT_PRINTING, 0) == 0) 1022 { 1023 1024 dprint (2, (debugfile, "successfully decoded %s type attachment to %s\n", 1025 type, mutt_b2s (newfile))); 1026 1027 if ((ifp = fopen (mutt_b2s (newfile), "r")) == NULL) 1028 { 1029 mutt_perror ("fopen"); 1030 goto decode_cleanup; 1031 } 1032 1033 dprint (2, (debugfile, "successfully opened %s read-only\n", mutt_b2s (newfile))); 1034 1035 mutt_endwin (NULL); 1036 if ((thepid = mutt_create_filter (NONULL(PrintCmd), &fpout, NULL, NULL)) < 0) 1037 { 1038 mutt_perror _("Can't create filter"); 1039 goto decode_cleanup; 1040 } 1041 1042 dprint (2, (debugfile, "Filter created.\n")); 1043 1044 mutt_copy_stream (ifp, fpout); 1045 1046 safe_fclose (&fpout); 1047 safe_fclose (&ifp); 1048 1049 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY)) 1050 mutt_any_key_to_continue (NULL); 1051 rc = 1; 1052 } 1053 decode_cleanup: 1054 safe_fclose (&ifp); 1055 safe_fclose (&fpout); 1056 mutt_unlink (mutt_b2s (newfile)); 1057 } 1058 else 1059 { 1060 mutt_error _("I don't know how to print that!"); 1061 rc = 0; 1062 } 1063 1064out: 1065 mutt_buffer_pool_release (&newfile); 1066 mutt_buffer_pool_release (&command); 1067 1068 return rc; 1069} 1070 1071void mutt_actx_add_attach (ATTACH_CONTEXT *actx, ATTACHPTR *attach) 1072{ 1073 int i; 1074 1075 if (actx->idxlen == actx->idxmax) 1076 { 1077 actx->idxmax += 5; 1078 safe_realloc (&actx->idx, sizeof (ATTACHPTR *) * actx->idxmax); 1079 safe_realloc (&actx->v2r, sizeof (short) * actx->idxmax); 1080 for (i = actx->idxlen; i < actx->idxmax; i++) 1081 actx->idx[i] = NULL; 1082 } 1083 1084 actx->idx[actx->idxlen++] = attach; 1085} 1086 1087void mutt_actx_add_fp (ATTACH_CONTEXT *actx, FILE *new_fp) 1088{ 1089 int i; 1090 1091 if (actx->fp_len == actx->fp_max) 1092 { 1093 actx->fp_max += 5; 1094 safe_realloc (&actx->fp_idx, sizeof (FILE *) * actx->fp_max); 1095 for (i = actx->fp_len; i < actx->fp_max; i++) 1096 actx->fp_idx[i] = NULL; 1097 } 1098 1099 actx->fp_idx[actx->fp_len++] = new_fp; 1100} 1101 1102void mutt_actx_add_body (ATTACH_CONTEXT *actx, BODY *new_body) 1103{ 1104 int i; 1105 1106 if (actx->body_len == actx->body_max) 1107 { 1108 actx->body_max += 5; 1109 safe_realloc (&actx->body_idx, sizeof (BODY *) * actx->body_max); 1110 for (i = actx->body_len; i < actx->body_max; i++) 1111 actx->body_idx[i] = NULL; 1112 } 1113 1114 actx->body_idx[actx->body_len++] = new_body; 1115} 1116 1117void mutt_actx_free_entries (ATTACH_CONTEXT *actx) 1118{ 1119 int i; 1120 1121 for (i = 0; i < actx->idxlen; i++) 1122 { 1123 if (actx->idx[i]->content) 1124 actx->idx[i]->content->aptr = NULL; 1125 FREE (&actx->idx[i]->tree); 1126 FREE (&actx->idx[i]); 1127 } 1128 actx->idxlen = 0; 1129 actx->vcount = 0; 1130 1131 for (i = 0; i < actx->fp_len; i++) 1132 safe_fclose (&actx->fp_idx[i]); 1133 actx->fp_len = 0; 1134 1135 for (i = 0; i < actx->body_len; i++) 1136 mutt_free_body (&actx->body_idx[i]); 1137 actx->body_len = 0; 1138} 1139 1140void mutt_free_attach_context (ATTACH_CONTEXT **pactx) 1141{ 1142 ATTACH_CONTEXT *actx; 1143 1144 if (!pactx || !*pactx) 1145 return; 1146 1147 actx = *pactx; 1148 mutt_actx_free_entries (actx); 1149 FREE (&actx->idx); 1150 FREE (&actx->v2r); 1151 FREE (&actx->fp_idx); 1152 FREE (&actx->body_idx); 1153 FREE (pactx); /* __FREE_CHECKED__ */ 1154}