📄 commands.c
字号:
/* * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org> * Copyright (C) 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 "mime.h"#include "sort.h"#include "mailbox.h"#include "copy.h"#include "mx.h"#include "pager.h"#include "mutt_crypt.h"#include "mutt_idna.h"#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#ifdef USE_IMAP#include "imap.h"#endif#ifdef BUFFY_SIZE#include "buffy.h"#endif#include <errno.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <sys/wait.h>#include <sys/stat.h>#include <sys/types.h>#include <utime.h>/* The folder the user last saved to. Used by ci_save_message() */static char LastSaveFolder[_POSIX_PATH_MAX] = "";int mutt_display_message (HEADER *cur){ char tempfile[_POSIX_PATH_MAX], buf[LONG_STRING]; int rc = 0, builtin = 0; int cmflags = M_CM_DECODE | M_CM_DISPLAY | M_CM_CHARCONV; FILE *fpout = NULL; FILE *fpfilterout = NULL; pid_t filterpid = -1; int res; snprintf (buf, sizeof (buf), "%s/%s", TYPE (cur->content), cur->content->subtype); mutt_parse_mime_message (Context, cur); mutt_message_hook (Context, cur, M_MESSAGEHOOK); /* see if crytpo is needed for this message. if so, we should exit curses */ if (WithCrypto && cur->security) { if (cur->security & ENCRYPT) { if (cur->security & APPLICATION_SMIME) crypt_smime_getkeys (cur->env); if(!crypt_valid_passphrase(cur->security)) return 0; cmflags |= M_CM_VERIFY; } else if (cur->security & SIGN) { /* find out whether or not the verify signature */ if (query_quadoption (OPT_VERIFYSIG, _("Verify PGP signature?")) == M_YES) { cmflags |= M_CM_VERIFY; } } } if (cmflags & M_CM_VERIFY || cur->security & ENCRYPT) { if (cur->security & APPLICATION_PGP) { if (cur->env->from) crypt_pgp_invoke_getkeys (cur->env->from); crypt_invoke_message (APPLICATION_PGP); } if (cur->security & APPLICATION_SMIME) crypt_invoke_message (APPLICATION_SMIME); } mutt_mktemp (tempfile); if ((fpout = safe_fopen (tempfile, "w")) == NULL) { mutt_error _("Could not create temporary file!"); return (0); } if (DisplayFilter && *DisplayFilter) { fpfilterout = fpout; fpout = NULL; /* mutt_endwin (NULL); */ filterpid = mutt_create_filter_fd (DisplayFilter, &fpout, NULL, NULL, -1, fileno(fpfilterout), -1); if (filterpid < 0) { mutt_error (_("Cannot create display filter")); safe_fclose (&fpfilterout); unlink (tempfile); return 0; } } if (!Pager || mutt_strcmp (Pager, "builtin") == 0) builtin = 1; else { mutt_make_string (buf, sizeof (buf), NONULL(PagerFmt), Context, cur); fputs (buf, fpout); fputs ("\n\n", fpout); } res = mutt_copy_message (fpout, Context, cur, cmflags, (option (OPTWEED) ? (CH_WEED | CH_REORDER) : 0) | CH_DECODE | CH_FROM); if ((safe_fclose (&fpout) != 0 && errno != EPIPE) || res == -1) { mutt_error (_("Could not copy message")); if (fpfilterout != NULL) { mutt_wait_filter (filterpid); safe_fclose (&fpfilterout); } mutt_unlink (tempfile); return 0; } if (fpfilterout != NULL && mutt_wait_filter (filterpid) != 0) mutt_any_key_to_continue (NULL); safe_fclose (&fpfilterout); /* XXX - check result? */ if (WithCrypto) { /* update crypto information for this message */ cur->security &= ~(GOODSIGN|BADSIGN); cur->security |= crypt_query (cur->content); /* Remove color cache for this message, in case there are color patterns for both ~g and ~V */ cur->pair = 0; } if (builtin) { pager_t info; if (WithCrypto && (cur->security & APPLICATION_SMIME) && (cmflags & M_CM_VERIFY)) { if (cur->security & GOODSIGN) { if (!crypt_smime_verify_sender(cur)) mutt_message ( _("S/MIME signature successfully verified.")); else mutt_error ( _("S/MIME certificate owner does not match sender.")); } else if (cur->security & PARTSIGN) mutt_message (_("Warning: Part of this message has not been signed.")); else if (cur->security & SIGN || cur->security & BADSIGN) mutt_error ( _("S/MIME signature could NOT be verified.")); } if (WithCrypto && (cur->security & APPLICATION_PGP) && (cmflags & M_CM_VERIFY)) { if (cur->security & GOODSIGN) mutt_message (_("PGP signature successfully verified.")); else if (cur->security & PARTSIGN) mutt_message (_("Warning: Part of this message has not been signed.")); else if (cur->security & SIGN) mutt_message (_("PGP signature could NOT be verified.")); } /* Invoke the builtin pager */ memset (&info, 0, sizeof (pager_t)); info.hdr = cur; info.ctx = Context; rc = mutt_pager (NULL, tempfile, M_PAGER_MESSAGE, &info); } else { int r; mutt_endwin (NULL); snprintf (buf, sizeof (buf), "%s %s", NONULL(Pager), tempfile); if ((r = mutt_system (buf)) == -1) mutt_error (_("Error running \"%s\"!"), buf); unlink (tempfile); keypad (stdscr, TRUE); if (r != -1) mutt_set_flag (Context, cur, M_READ, 1); if (r != -1 && option (OPTPROMPTAFTER)) { mutt_ungetch (mutt_any_key_to_continue _("Command: "), 0); rc = km_dokey (MENU_PAGER); } else rc = 0; } return rc;}void ci_bounce_message (HEADER *h, int *redraw){ char prompt[SHORT_STRING]; char buf[HUGE_STRING] = { 0 }; ADDRESS *adr = NULL; char *err = NULL; int rc; if(h) strfcpy(prompt, _("Bounce message to: "), sizeof(prompt)); else strfcpy(prompt, _("Bounce tagged messages to: "), sizeof(prompt)); rc = mutt_get_field (prompt, buf, sizeof (buf), M_ALIAS); if (option (OPTNEEDREDRAW)) { unset_option (OPTNEEDREDRAW); *redraw = REDRAW_FULL; } if (rc || !buf[0]) return; if (!(adr = rfc822_parse_adrlist (adr, buf))) { mutt_error _("Error parsing address!"); return; } adr = mutt_expand_aliases (adr); if (mutt_addrlist_to_idna (adr, &err) < 0) { mutt_error (_("Bad IDN: '%s'"), err); FREE (&err); rfc822_free_address (&adr); return; } buf[0] = 0; rfc822_write_address (buf, sizeof (buf), adr, 1);#define extra_space (15 + 7 + 2) snprintf (prompt, sizeof (prompt), (h ? _("Bounce message to %s") : _("Bounce messages to %s")), buf); if (mutt_strwidth (prompt) > COLS - extra_space) { mutt_format_string (prompt, sizeof (prompt), 0, COLS-extra_space, 0, 0, prompt, sizeof (prompt), 0); safe_strcat (prompt, sizeof (prompt), "...?"); } else safe_strcat (prompt, sizeof (prompt), "?"); if (query_quadoption (OPT_BOUNCE, prompt) != M_YES) { rfc822_free_address (&adr); CLEARLINE (LINES - 1); mutt_message (h ? _("Message not bounced.") : _("Messages not bounced.")); return; } CLEARLINE (LINES - 1); rc = mutt_bounce_message (NULL, h, adr); rfc822_free_address (&adr); /* If no error, or background, display message. */ if ((rc == 0) || (rc == S_BKG)) mutt_message (h ? _("Message bounced.") : _("Messages bounced."));}static void pipe_set_flags (int decode, int print, int *cmflags, int *chflags){ if (decode) { *cmflags |= M_CM_DECODE | M_CM_CHARCONV; *chflags |= CH_DECODE | CH_REORDER; if (option (OPTWEED)) { *chflags |= CH_WEED; *cmflags |= M_CM_WEED; } } if (print) *cmflags |= M_CM_PRINTING; }static void pipe_msg (HEADER *h, FILE *fp, int decode, int print){ int cmflags = 0; int chflags = CH_FROM; pipe_set_flags (decode, print, &cmflags, &chflags); if (WithCrypto && decode && h->security & ENCRYPT) { if(!crypt_valid_passphrase(h->security)) return; endwin (); } if (decode) mutt_parse_mime_message (Context, h); mutt_copy_message (fp, Context, h, cmflags, chflags);}/* the following code is shared between printing and piping */static int _mutt_pipe_message (HEADER *h, char *cmd, int decode, int print, int split, char *sep){ int i, rc = 0; pid_t thepid; FILE *fpout; /* mutt_endwin (NULL); is this really needed here ? it makes the screen flicker on pgp and s/mime messages, before asking for a passphrase... Oliver Ehli */ if (h) { mutt_message_hook (Context, h, M_MESSAGEHOOK); if (WithCrypto && decode) { mutt_parse_mime_message (Context, h); if(h->security & ENCRYPT && !crypt_valid_passphrase(h->security)) return 1; } mutt_endwin (NULL); if ((thepid = mutt_create_filter (cmd, &fpout, NULL, NULL)) < 0) { mutt_perror _("Can't create filter process"); return 1; } pipe_msg (h, fpout, decode, print); fclose (fpout); rc = mutt_wait_filter (thepid); } else { /* handle tagged messages */ if (WithCrypto && decode) { for (i = 0; i < Context->vcount; i++) if(Context->hdrs[Context->v2r[i]]->tagged) { mutt_message_hook (Context, Context->hdrs[Context->v2r[i]], M_MESSAGEHOOK); mutt_parse_mime_message(Context, Context->hdrs[Context->v2r[i]]); if (Context->hdrs[Context->v2r[i]]->security & ENCRYPT && !crypt_valid_passphrase(Context->hdrs[Context->v2r[i]]->security)) return 1; } } if (split) { for (i = 0; i < Context->vcount; i++) { if (Context->hdrs[Context->v2r[i]]->tagged) { mutt_message_hook (Context, Context->hdrs[Context->v2r[i]], M_MESSAGEHOOK); mutt_endwin (NULL); if ((thepid = mutt_create_filter (cmd, &fpout, NULL, NULL)) < 0) { mutt_perror _("Can't create filter process"); return 1; } pipe_msg (Context->hdrs[Context->v2r[i]], fpout, decode, print); /* add the message separator */ if (sep) fputs (sep, fpout); safe_fclose (&fpout); if (mutt_wait_filter (thepid) != 0) rc = 1; } } } else { mutt_endwin (NULL); if ((thepid = mutt_create_filter (cmd, &fpout, NULL, NULL)) < 0) { mutt_perror _("Can't create filter process"); return 1; } for (i = 0; i < Context->vcount; i++) { if (Context->hdrs[Context->v2r[i]]->tagged) { mutt_message_hook (Context, Context->hdrs[Context->v2r[i]], M_MESSAGEHOOK); pipe_msg (Context->hdrs[Context->v2r[i]], fpout, decode, print); /* add the message separator */ if (sep) fputs (sep, fpout); } } safe_fclose (&fpout); if (mutt_wait_filter (thepid) != 0) rc = 1; } } if (rc || option (OPTWAITKEY)) mutt_any_key_to_continue (NULL); return rc;}void mutt_pipe_message (HEADER *h){ char buffer[LONG_STRING]; buffer[0] = 0; if (mutt_get_field (_("Pipe to command: "), buffer, sizeof (buffer), M_CMD) != 0 || !buffer[0]) return; mutt_expand_path (buffer, sizeof (buffer)); _mutt_pipe_message (h, buffer, option (OPTPIPEDECODE), 0, option (OPTPIPESPLIT), PipeSep);}void mutt_print_message (HEADER *h){ if (quadoption (OPT_PRINT) && (!PrintCmd || !*PrintCmd)) { mutt_message (_("No printing command has been defined.")); return; } if (query_quadoption (OPT_PRINT, h ? _("Print message?") : _("Print tagged messages?")) != M_YES) return; if (_mutt_pipe_message (h, PrintCmd, option (OPTPRINTDECODE), 1, option (OPTPRINTSPLIT), "\f") == 0) mutt_message (h ? _("Message printed") : _("Messages printed")); else mutt_message (h ? _("Message could not be printed") : _("Messages could not be printed"));}int mutt_select_sort (int reverse){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -