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