📄 recvattach.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_curses.h"#include "mutt_menu.h"#include "rfc1524.h"#include "mime.h"#include "mailbox.h"#include "attach.h"#include "mapping.h"#include "mx.h"#include "copy.h"#include "mutt_crypt.h"#include <ctype.h>#include <stdlib.h>#include <unistd.h>#include <sys/wait.h>#include <sys/stat.h>#include <string.h>#include <errno.h>static const char *Mailbox_is_read_only = N_("Mailbox is read-only.");#define CHECK_READONLY if (Context->readonly) \{\ mutt_flushinp (); \ mutt_error _(Mailbox_is_read_only); \ break; \}static struct mapping_t AttachHelp[] = { { N_("Exit"), OP_EXIT }, { N_("Save"), OP_SAVE }, { N_("Pipe"), OP_PIPE }, { N_("Print"), OP_PRINT }, { N_("Help"), OP_HELP }, { NULL }};void mutt_update_tree (ATTACHPTR **idx, short idxlen){ char buf[STRING]; char *s; int x; for (x = 0; x < idxlen; x++) { idx[x]->num = x; if (2 * (idx[x]->level + 2) < sizeof (buf)) { if (idx[x]->level) { s = buf + 2 * (idx[x]->level - 1); *s++ = (idx[x]->content->next) ? M_TREE_LTEE : M_TREE_LLCORNER; *s++ = M_TREE_HLINE; *s++ = M_TREE_RARROW; } else s = buf; *s = 0; } if (idx[x]->tree) { if (mutt_strcmp (idx[x]->tree, buf) != 0) mutt_str_replace (&idx[x]->tree, buf); } else idx[x]->tree = safe_strdup (buf); if (2 * (idx[x]->level + 2) < sizeof (buf) && idx[x]->level) { s = buf + 2 * (idx[x]->level - 1); *s++ = (idx[x]->content->next) ? '\005' : '\006'; *s++ = '\006'; } }}ATTACHPTR **mutt_gen_attach_list (BODY *m, int parent_type, ATTACHPTR **idx, short *idxlen, short *idxmax, int level, int compose){ ATTACHPTR *new; int i; for (; m; m = m->next) { if (*idxlen == *idxmax) { safe_realloc (&idx, sizeof (ATTACHPTR *) * ((*idxmax) += 5)); for (i = *idxlen; i < *idxmax; i++) idx[i] = NULL; } if (m->type == TYPEMULTIPART && m->parts && (compose || (parent_type == -1 && ascii_strcasecmp ("alternative", m->subtype))) && (!(WithCrypto & APPLICATION_PGP) || !mutt_is_multipart_encrypted(m)) ) { idx = mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax, level, compose); } else { if (!idx[*idxlen]) idx[*idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR)); new = idx[(*idxlen)++]; new->content = m; m->aptr = new; new->parent_type = parent_type; new->level = level; /* We don't support multipart messages in the compose menu yet */ if (!compose && !m->collapsed && ((m->type == TYPEMULTIPART && (!(WithCrypto & APPLICATION_PGP) || !mutt_is_multipart_encrypted (m)) ) || mutt_is_message_type(m->type, m->subtype))) { idx = mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax, level + 1, compose); } } } if (level == 0) mutt_update_tree (idx, *idxlen); return (idx);}/* %c = character set: convert? * %C = character set * %D = deleted flag * %d = description * %e = MIME content-transfer-encoding * %f = filename * %I = content-disposition, either I (inline) or A (attachment) * %t = tagged flag * %T = tree chars * %m = major MIME type * %M = MIME subtype * %n = attachment number * %s = size * %u = unlink */const char *mutt_attach_fmt (char *dest, size_t destlen, char op, const char *src, const char *prefix, const char *ifstring, const char *elsestring, unsigned long data, format_flag flags){ char fmt[16]; char tmp[SHORT_STRING]; char charset[SHORT_STRING]; ATTACHPTR *aptr = (ATTACHPTR *) data; int optional = (flags & M_FORMAT_OPTIONAL); size_t l; switch (op) { case 'C': if (!optional) { if (mutt_is_text_part (aptr->content) && mutt_get_body_charset (charset, sizeof (charset), aptr->content)) mutt_format_s (dest, destlen, prefix, charset); else mutt_format_s (dest, destlen, prefix, ""); } else if (!mutt_is_text_part (aptr->content) || !mutt_get_body_charset (charset, sizeof (charset), aptr->content)) optional = 0; break; case 'c': /* XXX */ if (!optional) { snprintf (fmt, sizeof (fmt), "%%%sc", prefix); snprintf (dest, destlen, fmt, aptr->content->type != TYPETEXT || aptr->content->noconv ? 'n' : 'c'); } else if (aptr->content->type != TYPETEXT || aptr->content->noconv) optional = 0; break; case 'd': if(!optional) { if (aptr->content->description) { mutt_format_s (dest, destlen, prefix, aptr->content->description); break; } if (mutt_is_message_type(aptr->content->type, aptr->content->subtype) && MsgFmt && aptr->content->hdr) { char s[SHORT_STRING]; _mutt_make_string (s, sizeof (s), MsgFmt, NULL, aptr->content->hdr, M_FORMAT_FORCESUBJ | M_FORMAT_MAKEPRINT | M_FORMAT_ARROWCURSOR); if (*s) { mutt_format_s (dest, destlen, prefix, s); break; } } if (!aptr->content->filename) { mutt_format_s (dest, destlen, prefix, "<no description>"); break; } } else if(aptr->content->description || (mutt_is_message_type (aptr->content->type, aptr->content->subtype) && MsgFmt && aptr->content->hdr)) break; /* FALLS THROUGH TO 'f' */ case 'f': if(!optional) { if (aptr->content->filename && *aptr->content->filename == '/') { char path[_POSIX_PATH_MAX]; strfcpy (path, aptr->content->filename, sizeof (path)); mutt_pretty_mailbox (path); mutt_format_s (dest, destlen, prefix, path); } else mutt_format_s (dest, destlen, prefix, NONULL (aptr->content->filename)); } else if(!aptr->content->filename) optional = 0; break; case 'D': if(!optional) snprintf (dest, destlen, "%c", aptr->content->deleted ? 'D' : ' '); else if(!aptr->content->deleted) optional = 0; break; case 'e': if(!optional) mutt_format_s (dest, destlen, prefix, ENCODING (aptr->content->encoding)); break; case 'I': if (!optional) { snprintf (dest, destlen, "%c", (aptr->content->disposition == DISPINLINE) ? 'I' : 'A'); } break; case 'm': if(!optional) mutt_format_s (dest, destlen, prefix, TYPE (aptr->content)); break; case 'M': if(!optional) mutt_format_s (dest, destlen, prefix, aptr->content->subtype); else if(!aptr->content->subtype) optional = 0; break; case 'n': if(!optional) { snprintf (fmt, sizeof (fmt), "%%%sd", prefix); snprintf (dest, destlen, fmt, aptr->num + 1); } break; case 'Q': if (optional) optional = aptr->content->attach_qualifies; else { snprintf (fmt, sizeof (fmt), "%%%sc", prefix); mutt_format_s (dest, destlen, fmt, "Q"); } break; case 's': if (flags & M_FORMAT_STAT_FILE) { struct stat st; stat (aptr->content->filename, &st); l = st.st_size; } else l = aptr->content->length; if(!optional) { mutt_pretty_size (tmp, sizeof(tmp), l); mutt_format_s (dest, destlen, prefix, tmp); } else if (l == 0) optional = 0; break; case 't': if(!optional) snprintf (dest, destlen, "%c", aptr->content->tagged ? '*' : ' '); else if(!aptr->content->tagged) optional = 0; break; case 'T': if(!optional) mutt_format_s_tree (dest, destlen, prefix, NONULL (aptr->tree)); else if (!aptr->tree) optional = 0; break; case 'u': if(!optional) snprintf (dest, destlen, "%c", aptr->content->unlink ? '-' : ' '); else if (!aptr->content->unlink) optional = 0; break; case 'X': if (optional) optional = (aptr->content->attach_count + aptr->content->attach_qualifies) != 0; else { snprintf (fmt, sizeof (fmt), "%%%sd", prefix); snprintf (dest, destlen, fmt, aptr->content->attach_count + aptr->content->attach_qualifies); } break; default: *dest = 0; } if (optional) mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0); else if (flags & M_FORMAT_OPTIONAL) mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0); return (src);}void attach_entry (char *b, size_t blen, MUTTMENU *menu, int num){ mutt_FormatString (b, blen, NONULL (AttachFormat), mutt_attach_fmt, (unsigned long) (((ATTACHPTR **)menu->data)[num]), M_FORMAT_ARROWCURSOR);}int mutt_tag_attach (MUTTMENU *menu, int n, int m){ BODY *cur = ((ATTACHPTR **) menu->data)[n]->content; int ot = cur->tagged; cur->tagged = (m >= 0 ? m : !cur->tagged); return cur->tagged - ot;}int mutt_is_message_type (int type, const char *subtype){ if (type != TYPEMESSAGE) return 0; subtype = NONULL(subtype); return (ascii_strcasecmp (subtype, "rfc822") == 0 || ascii_strcasecmp (subtype, "news") == 0);}static int mutt_query_save_attachment (FILE *fp, BODY *body, HEADER *hdr, char **directory){ char *prompt; char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX]; int is_message; int append = 0; int rc; if (body->filename) { if (directory && *directory) mutt_concat_path (buf, *directory, mutt_basename (body->filename), sizeof (buf)); else strfcpy (buf, body->filename, sizeof (buf)); } else if(body->hdr && body->encoding != ENCBASE64 && body->encoding != ENCQUOTEDPRINTABLE && mutt_is_message_type(body->type, body->subtype)) mutt_default_save(buf, sizeof(buf), body->hdr); else buf[0] = 0; prompt = _("Save to file: "); while (prompt) { if (mutt_get_field (prompt, buf, sizeof (buf), M_FILE | M_CLEAR) != 0 || !buf[0]) return -1; prompt = NULL; mutt_expand_path (buf, sizeof (buf)); is_message = (fp && body->hdr && body->encoding != ENCBASE64 && body->encoding != ENCQUOTEDPRINTABLE && mutt_is_message_type (body->type, body->subtype)); if (is_message) { struct stat st; /* check to make sure that this file is really the one the user wants */ if ((rc = mutt_save_confirm (buf, &st)) == 1) { prompt = _("Save to file: "); continue; } else if (rc == -1) return -1; strfcpy(tfile, buf, sizeof(tfile)); } else { if ((rc = mutt_check_overwrite (body->filename, buf, tfile, sizeof (tfile), &append, directory)) == -1) return -1; else if (rc == 1) { prompt = _("Save to file: "); continue; } } mutt_message _("Saving..."); if (mutt_save_attachment (fp, body, tfile, append, (hdr || !is_message) ? hdr : body->hdr) == 0) { mutt_message _("Attachment saved."); return 0; } else { prompt = _("Save to file: "); continue; } } return 0;} void mutt_save_attachment_list (FILE *fp, int tag, BODY *top, HEADER *hdr, MUTTMENU *menu){ char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX]; char *directory = NULL; int rc = 1; int last = menu ? menu->current : -1; FILE *fpout; buf[0] = 0; for (; top; top = top->next) { if (!tag || top->tagged) { if (!option (OPTATTACHSPLIT)) { if (!buf[0]) { int append = 0; strfcpy (buf, mutt_basename (NONULL (top->filename)), sizeof (buf)); if (mutt_get_field (_("Save to file: "), buf, sizeof (buf), M_FILE | M_CLEAR) != 0 || !buf[0]) return; mutt_expand_path (buf, sizeof (buf)); if (mutt_check_overwrite (top->filename, buf, tfile, sizeof (tfile), &append, NULL)) return; rc = mutt_save_attachment (fp, top, tfile, append, hdr); if (rc == 0 && AttachSep && (fpout = fopen (tfile,"a")) != NULL) { fprintf(fpout, "%s", AttachSep); fclose (fpout); } } else { rc = mutt_save_attachment (fp, top, tfile, M_SAVE_APPEND, hdr); if (rc == 0 && AttachSep && (fpout = fopen (tfile,"a")) != NULL) { fprintf(fpout, "%s", AttachSep); fclose (fpout); } } } else { if (tag && menu && top->aptr) { menu->oldcurrent = menu->current; menu->current = top->aptr->num; menu_check_recenter (menu); menu->redraw |= REDRAW_MOTION; menu_redraw (menu); } if (mutt_query_save_attachment (fp, top, hdr, &directory) == -1) break; } } else if (top->parts) mutt_save_attachment_list (fp, 1, top->parts, hdr, menu); if (!tag) break; } FREE (&directory); if (tag && menu) { menu->oldcurrent = menu->current; menu->current = last; menu_check_recenter (menu); menu->redraw |= REDRAW_MOTION; } if (!option (OPTATTACHSPLIT) && (rc == 0)) mutt_message _("Attachment saved.");}static voidmutt_query_pipe_attachment (char *command, FILE *fp, BODY *body, int filter){ char tfile[_POSIX_PATH_MAX]; char warning[STRING+_POSIX_PATH_MAX]; if (filter) { snprintf (warning, sizeof (warning), _("WARNING! You are about to overwrite %s, continue?"), body->filename); if (mutt_yesorno (warning, M_NO) != M_YES) { CLEARLINE (LINES-1); return; } mutt_mktemp (tfile); } else tfile[0] = 0; if (mutt_pipe_attachment (fp, body, command, tfile)) { if (filter) { mutt_unlink (body->filename); mutt_rename_file (tfile, body->filename); mutt_update_encoding (body); mutt_message _("Attachment filtered."); } } else { if (filter && tfile[0]) mutt_unlink (tfile); }}static void pipe_attachment (FILE *fp, BODY *b, STATE *state){ FILE *ifp; if (fp) { state->fpin = fp; mutt_decode_attachment (b, state); if (AttachSep) state_puts (AttachSep, state); } else { if ((ifp = fopen (b->filename, "r")) == NULL) { mutt_perror ("fopen"); return; } mutt_copy_stream (ifp, state->fpout); fclose (ifp); if (AttachSep) state_puts (AttachSep, state); }}static voidpipe_attachment_list (char *command, FILE *fp, int tag, BODY *top, int filter, STATE *state){ for (; top; top = top->next) { if (!tag || top->tagged) { if (!filter && !option (OPTATTACHSPLIT)) pipe_attachment (fp, top, state);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -