📄 attach.c
字号:
/* * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org> * Copyright (C) 1999-2000 Thomas Roessler <roessler@does-not-exist.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #if HAVE_CONFIG_H# include "config.h"#endif#include "mutt.h"#include "mutt_menu.h"#include "attach.h"#include "mutt_curses.h"#include "keymap.h"#include "rfc1524.h"#include "mime.h"#include "pager.h"#include "mailbox.h"#include "copy.h"#include "mx.h"#include "mutt_crypt.h"#include <ctype.h>#include <stdlib.h>#include <unistd.h>#include <sys/wait.h>#include <sys/stat.h>#include <fcntl.h>#include <string.h>#include <errno.h>int mutt_get_tmp_attachment (BODY *a){ char type[STRING]; char tempfile[_POSIX_PATH_MAX]; rfc1524_entry *entry = rfc1524_new_entry(); FILE *fpin = NULL, *fpout = NULL; struct stat st; if(a->unlink) return 0; snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype); rfc1524_mailcap_lookup(a, type, entry, 0); rfc1524_expand_filename(entry->nametemplate, a->filename, tempfile, sizeof(tempfile)); rfc1524_free_entry(&entry); if(stat(a->filename, &st) == -1) return -1; if((fpin = fopen(a->filename, "r")) && (fpout = safe_fopen(tempfile, "w"))) /* __FOPEN_CHECKED__ */ { mutt_copy_stream (fpin, fpout); mutt_str_replace (&a->filename, tempfile); a->unlink = 1; if(a->stamp >= st.st_mtime) mutt_stamp_attachment(a); } else mutt_perror(fpin ? tempfile : a->filename); if(fpin) fclose(fpin); if(fpout) fclose(fpout); return a->unlink ? 0 : -1;}/* return 1 if require full screen redraw, 0 otherwise */int mutt_compose_attachment (BODY *a){ char type[STRING]; char command[STRING]; char newfile[_POSIX_PATH_MAX] = ""; rfc1524_entry *entry = rfc1524_new_entry (); short unlink_newfile = 0; int rc = 0; snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype); if (rfc1524_mailcap_lookup (a, type, entry, M_COMPOSE)) { if (entry->composecommand || entry->composetypecommand) { if (entry->composetypecommand) strfcpy (command, entry->composetypecommand, sizeof (command)); else strfcpy (command, entry->composecommand, sizeof (command)); if (rfc1524_expand_filename (entry->nametemplate, a->filename, newfile, sizeof (newfile))) { dprint(1, (debugfile, "oldfile: %s\t newfile: %s\n", a->filename, newfile)); if (safe_symlink (a->filename, newfile) == -1) { if (mutt_yesorno (_("Can't match nametemplate, continue?"), M_YES) != M_YES) goto bailout; } else unlink_newfile = 1; } else strfcpy(newfile, a->filename, sizeof(newfile)); if (rfc1524_expand_command (a, newfile, type, command, sizeof (command))) { /* For now, editing requires a file, no piping */ mutt_error _("Mailcap compose entry requires %%s"); } else { int r; mutt_endwin (NULL); if ((r = mutt_system (command)) == -1) mutt_error (_("Error running \"%s\"!"), command); if (r != -1 && entry->composetypecommand) { BODY *b; FILE *fp, *tfp; char tempfile[_POSIX_PATH_MAX]; if ((fp = safe_fopen (a->filename, "r")) == NULL) { mutt_perror _("Failure to open file to parse headers."); goto bailout; } b = mutt_read_mime_header (fp, 0); if (b) { if (b->parameter) { mutt_free_parameter (&a->parameter); a->parameter = b->parameter; b->parameter = NULL; } if (b->description) { FREE (&a->description); a->description = b->description; b->description = NULL; } if (b->form_name) { FREE (&a->form_name); a->form_name = b->form_name; b->form_name = NULL; } /* Remove headers by copying out data to another file, then * copying the file back */ fseeko (fp, b->offset, 0); mutt_mktemp (tempfile); if ((tfp = safe_fopen (tempfile, "w")) == NULL) { mutt_perror _("Failure to open file to strip headers."); goto bailout; } mutt_copy_stream (fp, tfp); fclose (fp); fclose (tfp); mutt_unlink (a->filename); if (mutt_rename_file (tempfile, a->filename) != 0) { mutt_perror _("Failure to rename file."); goto bailout; } mutt_free_body (&b); } } } } } else { rfc1524_free_entry (&entry); mutt_message (_("No mailcap compose entry for %s, creating empty file."), type); return 1; } rc = 1; bailout: if(unlink_newfile) unlink(newfile); rfc1524_free_entry (&entry); return rc;}/* * Currently, this only works for send mode, as it assumes that the * BODY->filename actually contains the information. I'm not sure * we want to deal with editing attachments we've already received, * so this should be ok. * * Returns 1 if editor found, 0 if not (useful to tell calling menu to * redraw) */int mutt_edit_attachment (BODY *a){ char type[STRING]; char command[STRING]; char newfile[_POSIX_PATH_MAX] = ""; rfc1524_entry *entry = rfc1524_new_entry (); short unlink_newfile = 0; int rc = 0; snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype); if (rfc1524_mailcap_lookup (a, type, entry, M_EDIT)) { if (entry->editcommand) { strfcpy (command, entry->editcommand, sizeof (command)); if (rfc1524_expand_filename (entry->nametemplate, a->filename, newfile, sizeof (newfile))) { dprint(1, (debugfile, "oldfile: %s\t newfile: %s\n", a->filename, newfile)); if (safe_symlink (a->filename, newfile) == -1) { if (mutt_yesorno (_("Can't match nametemplate, continue?"), M_YES) != M_YES) goto bailout; } else unlink_newfile = 1; } else strfcpy(newfile, a->filename, sizeof(newfile)); if (rfc1524_expand_command (a, newfile, type, command, sizeof (command))) { /* For now, editing requires a file, no piping */ mutt_error _("Mailcap Edit entry requires %%s"); goto bailout; } else { mutt_endwin (NULL); if (mutt_system (command) == -1) { mutt_error (_("Error running \"%s\"!"), command); goto bailout; } } } } else if (a->type == TYPETEXT) { /* On text, default to editor */ mutt_edit_file (NONULL (Editor), a->filename); } else { rfc1524_free_entry (&entry); mutt_error (_("No mailcap edit entry for %s"),type); return 0; } rc = 1; bailout: if(unlink_newfile) unlink(newfile); rfc1524_free_entry (&entry); return rc;}/* for compatibility with metamail */static int is_mmnoask (const char *buf){ char tmp[LONG_STRING], *p, *q; int lng; if ((p = getenv ("MM_NOASK")) != NULL && *p) { if (mutt_strcmp (p, "1") == 0) return (1); strfcpy (tmp, p, sizeof (tmp)); p = tmp; while ((p = strtok (p, ",")) != NULL) { if ((q = strrchr (p, '/')) != NULL) { if (*(q+1) == '*') { if (ascii_strncasecmp (buf, p, q-p) == 0) return (1); } else { if (ascii_strcasecmp (buf, p) == 0) return (1); } } else { lng = mutt_strlen (p); if (buf[lng] == '/' && mutt_strncasecmp (buf, p, lng) == 0) return (1); } p = NULL; } } return (0);}void mutt_check_lookup_list (BODY *b, char *type, int len){ LIST *t = MimeLookupList; int i; for (; t; t = t->next) { i = mutt_strlen (t->data) - 1; if ((i > 0 && t->data[i-1] == '/' && t->data[i] == '*' && ascii_strncasecmp (type, t->data, i) == 0) || ascii_strcasecmp (type, t->data) == 0) { BODY tmp = {0}; int n; if ((n = mutt_lookup_mime_type (&tmp, b->filename)) != TYPEOTHER) { snprintf (type, len, "%s/%s", n == TYPEAUDIO ? "audio" : n == TYPEAPPLICATION ? "application" : n == TYPEIMAGE ? "image" : n == TYPEMESSAGE ? "message" : n == TYPEMODEL ? "model" : n == TYPEMULTIPART ? "multipart" : n == TYPETEXT ? "text" : n == TYPEVIDEO ? "video" : "other", tmp.subtype); dprint(1, (debugfile, "mutt_check_lookup_list: \"%s\" -> %s\n", b->filename, type)); } if (tmp.subtype) FREE (&tmp.subtype); if (tmp.xtype) FREE (&tmp.xtype); } }}int mutt_is_autoview (BODY *b, const char *type){ LIST *t = AutoViewList; char _type[SHORT_STRING]; int i; if (!type) snprintf (_type, sizeof (_type), "%s/%s", TYPE (b), b->subtype); else strncpy (_type, type, sizeof(_type)); mutt_check_lookup_list (b, _type, sizeof(_type)); type = _type; if (mutt_needs_mailcap (b)) { if (option (OPTIMPLICITAUTOVIEW)) return 1; if (is_mmnoask (type)) return 1; } for (; t; t = t->next) { i = mutt_strlen (t->data) - 1; if ((i > 0 && t->data[i-1] == '/' && t->data[i] == '*' && ascii_strncasecmp (type, t->data, i) == 0) || ascii_strcasecmp (type, t->data) == 0) return 1; } return 0;}/* returns -1 on error, 0 or the return code from mutt_do_pager() on success */int mutt_view_attachment (FILE *fp, BODY *a, int flag, HEADER *hdr, ATTACHPTR **idx, short idxlen){ char tempfile[_POSIX_PATH_MAX] = ""; char pagerfile[_POSIX_PATH_MAX] = ""; int is_message; int use_mailcap; int use_pipe = 0; int use_pager = 1; char type[STRING]; char command[STRING]; char descrip[STRING]; char *fname; rfc1524_entry *entry = NULL; int rc = -1; int unlink_tempfile = 0; is_message = mutt_is_message_type(a->type, a->subtype); if (WithCrypto && is_message && a->hdr && (a->hdr->security & ENCRYPT) && !crypt_valid_passphrase(a->hdr->security)) return (rc); use_mailcap = (flag == M_MAILCAP || (flag == M_REGULAR && mutt_needs_mailcap (a))); snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype); if (use_mailcap) { entry = rfc1524_new_entry (); if (!rfc1524_mailcap_lookup (a, type, entry, 0)) { if (flag == M_REGULAR) { /* fallback to view as text */ rfc1524_free_entry (&entry); mutt_error _("No matching mailcap entry found. Viewing as text."); flag = M_AS_TEXT; use_mailcap = 0; } else goto return_error; } } if (use_mailcap) { if (!entry->command) { mutt_error _("MIME type not defined. Cannot view attachment."); goto return_error; } strfcpy (command, entry->command, sizeof (command)); if (fp) { fname = safe_strdup (a->filename); mutt_sanitize_filename (fname, 1); } else fname = a->filename; if (rfc1524_expand_filename (entry->nametemplate, fname, tempfile, sizeof (tempfile))) { if (fp == NULL && mutt_strcmp(tempfile, a->filename)) { /* send case: the file is already there */ if (safe_symlink (a->filename, tempfile) == -1) { if (mutt_yesorno (_("Can't match nametemplate, continue?"), M_YES) == M_YES) strfcpy (tempfile, a->filename, sizeof (tempfile)); else goto return_error; } else unlink_tempfile = 1; } } else if (fp == NULL) /* send case */ strfcpy (tempfile, a->filename, sizeof (tempfile)); if (fp) { /* recv case: we need to save the attachment to a file */ FREE (&fname); if (mutt_save_attachment (fp, a, tempfile, 0, NULL) == -1) goto return_error; } use_pipe = rfc1524_expand_command (a, tempfile, type, command, sizeof (command)); use_pager = entry->copiousoutput; } if (use_pager) { if (fp && !use_mailcap && a->filename) { /* recv case */ strfcpy (pagerfile, a->filename, sizeof (pagerfile)); mutt_adv_mktemp (pagerfile, sizeof(pagerfile)); } else mutt_mktemp (pagerfile); } if (use_mailcap) { pid_t thepid = 0; int tempfd = -1, pagerfd = -1; if (!use_pager) mutt_endwin (NULL); if (use_pager || use_pipe) { if (use_pager && ((pagerfd = safe_open (pagerfile, O_CREAT | O_EXCL | O_WRONLY)) == -1)) { mutt_perror ("open"); goto return_error; } if (use_pipe && ((tempfd = open (tempfile, 0)) == -1)) { if(pagerfd != -1) close(pagerfd); mutt_perror ("open"); goto return_error; } if ((thepid = mutt_create_filter_fd (command, NULL, NULL, NULL, use_pipe ? tempfd : -1, use_pager ? pagerfd : -1, -1)) == -1) { if(pagerfd != -1) close(pagerfd); if(tempfd != -1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -