From 1a5381e07e97fe482c2b3a7c75f99938f0b105d4 Mon Sep 17 00:00:00 2001 From: Thomas Roessler Date: Mon, 8 Jun 1998 09:16:03 +0000 Subject: Initial revision --- commands.c | 751 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 751 insertions(+) create mode 100644 commands.c (limited to 'commands.c') diff --git a/commands.c b/commands.c new file mode 100644 index 00000000..4de052a3 --- /dev/null +++ b/commands.c @@ -0,0 +1,751 @@ +/* + * Copyright (C) 1996-8 Michael R. Elkins + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#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" + +#ifdef BUFFY_SIZE +#include "buffy.h" +#endif + + + +#ifdef _PGPPATH +#include "pgp.h" +#endif + + + + + + + + + + + +#include +#include +#include +#include +#include +#include +#include +#include + +extern char *ReleaseDate; + +/* The folder the user last saved to. Used by ci_save_message() */ +static char LastSaveFolder[_POSIX_PATH_MAX] = ""; + +/* 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 (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 (strncasecmp (buf, p, q-p) == 0) + return (1); + } + else + { + if (strcasecmp (buf, p) == 0) + return (1); + } + } + else + { + lng = strlen (p); + if (buf[lng] == '/' && strncasecmp (buf, p, lng) == 0) + return (1); + } + + p = NULL; + } + } + + return (0); +} + +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; + FILE *fpout; + + snprintf (buf, sizeof (buf), "%s/%s", TYPE (cur->content->type), + cur->content->subtype); + + if (cur->mailcap && !mutt_is_autoview (buf)) + { + if (is_mmnoask (buf)) + rc = M_YES; + else + rc = query_quadoption (OPT_USEMAILCAP, "Display message using mailcap?"); + if (rc < 0) + return 0; + else if (rc == M_YES) + { + MESSAGE *msg; + + if ((msg = mx_open_message (Context, cur->msgno)) != NULL) + { + mutt_view_attachment (msg->fp, cur->content, M_REGULAR); + mx_close_message (&msg); + mutt_set_flag (Context, cur, M_READ, 1); + } + return 0; + } + } + + mutt_parse_mime_message (Context, cur); + + + +#ifdef _PGPPATH + /* see if PGP is needed for this message. if so, we should exit curses */ + if (cur->pgp) + { + if (cur->pgp & PGPENCRYPT) + { + if (!pgp_valid_passphrase ()) + return 0; + + cmflags |= M_CM_VERIFY; + mutt_message ("Invoking PGP..."); + } + else if (cur->pgp & PGPSIGN) + { + /* find out whether or not the verify signature */ + if (query_quadoption (OPT_VERIFYSIG, "Verify PGP signature?") == M_YES) + { + cmflags |= M_CM_VERIFY; + mutt_message ("Invoking PGP..."); + } + } + } +#endif + + + + + + + + mutt_mktemp (tempfile); + if ((fpout = safe_fopen (tempfile, "w")) == NULL) + { + mutt_error ("Could not create temporary file!"); + return (0); + } + + if (strcmp (Pager, "builtin") == 0) + builtin = 1; + else + { + mutt_make_string (buf, sizeof (buf), PagerFmt, cur); + fputs (buf, fpout); + fputs ("\n\n", fpout); + } + + if (mutt_copy_message (fpout, Context, cur, cmflags, + (option (OPTWEED) ? (CH_WEED | CH_REORDER) : 0) | CH_DECODE | CH_FROM) == -1) + { + fclose (fpout); + unlink (tempfile); + return 0; + } + + if (fclose (fpout) != 0 && errno != EPIPE) + { + mutt_perror ("fclose"); + mutt_unlink (tempfile); + return (0); + } + + if (builtin) + { + pager_t info; + + /* Invoke the builtin pager */ + memset (&info, 0, sizeof (pager_t)); + info.hdr = cur; + info.ctx = Context; + rc = mutt_pager (NULL, tempfile, 1, &info); + } + else + { + endwin (); + snprintf (buf, sizeof (buf), "%s %s", Pager, tempfile); + mutt_system (buf); + unlink (tempfile); + keypad (stdscr, TRUE); + mutt_set_flag (Context, cur, M_READ, 1); + if (option (OPTPROMPTAFTER)) + { + mutt_ungetch (mutt_any_key_to_continue ("Command: ")); + 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; + int rc; + + snprintf (prompt, sizeof(prompt), "Bounce %smessage%s to: ", + h ? "" : "tagged ", h ? "" : "s"); + 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); + + buf[0] = 0; + rfc822_write_address (buf, sizeof (buf), adr); + + snprintf (prompt, (COLS > sizeof(prompt) ? sizeof(prompt) : COLS) - 13, + "Bounce message%s to %s", (h ? "" : "s"), buf); + strcat(prompt, "...?"); + if (mutt_yesorno (prompt, 1) != 1) + { + rfc822_free_address (&adr); + CLEARLINE (LINES-1); + return; + } + + mutt_bounce_message (h, adr); + rfc822_free_address (&adr); + mutt_message ("Message%s bounced.", h ? "" : "s"); +} + +void mutt_pipe_message_to_state (HEADER *h, STATE *s) +{ + if (option (OPTPIPEDECODE)) + mutt_parse_mime_message (Context, h); + mutt_copy_message (s->fpout, Context, h, + option (OPTPIPEDECODE) ? M_CM_DECODE : 0, + option (OPTPIPEDECODE) ? CH_FROM | CH_WEED | CH_DECODE : CH_FROM); +} + +int mutt_pipe_message (HEADER *h) +{ + STATE s; + char buffer[LONG_STRING]; + int i, rc = 0; + pid_t thepid; + + buffer[0] = 0; + if (mutt_get_field ("Pipe to command: ", buffer, sizeof (buffer), 0) != 0 || + !buffer[0]) + return 0; + mutt_expand_path (buffer, sizeof (buffer)); + + memset (&s, 0, sizeof (s)); + + endwin (); + if (h) + { + + + +#ifdef _PGPPATH + if (option (OPTPIPEDECODE)) + { + mutt_parse_mime_message (Context, h); + if(h->pgp & PGPENCRYPT && !pgp_valid_passphrase()) + return 1; + } + endwin (); +#endif + + + + thepid = mutt_create_filter (buffer, &s.fpout, NULL, NULL); + mutt_pipe_message_to_state (h, &s); + fclose (s.fpout); + rc = mutt_wait_filter (thepid); + } + else + { /* handle tagged messages */ + + + +#ifdef _PGPPATH + + if(option(OPTPIPEDECODE)) + { + for (i = 0; i < Context->vcount; i++) + if(Context->hdrs[Context->v2r[i]]->tagged) + { + mutt_parse_mime_message(Context, Context->hdrs[Context->v2r[i]]); + if (Context->hdrs[Context->v2r[i]]->pgp & PGPENCRYPT && + !pgp_valid_passphrase()) + return 1; + } + } +#endif + + + + if (option (OPTPIPESPLIT)) + { + for (i = 0; i < Context->vcount; i++) + { + if (Context->hdrs[Context->v2r[i]]->tagged) + { + endwin (); + thepid = mutt_create_filter (buffer, &(s.fpout), NULL, NULL); + mutt_pipe_message_to_state (Context->hdrs[Context->v2r[i]], &s); + /* add the message separator */ + if (PipeSep) + state_puts (PipeSep, &s); + fclose (s.fpout); + if (mutt_wait_filter (thepid) != 0) + rc = 1; + } + } + } + else + { + endwin (); + thepid = mutt_create_filter (buffer, &(s.fpout), NULL, NULL); + for (i = 0; i < Context->vcount; i++) + { + if (Context->hdrs[Context->v2r[i]]->tagged) + { + mutt_pipe_message_to_state (Context->hdrs[Context->v2r[i]], &s); + /* add the message separator */ + if (PipeSep) + state_puts (PipeSep, &s); + } + } + fclose (s.fpout); + if (mutt_wait_filter (thepid) != 0) + rc = 1; + } + } + + if (rc || option (OPTWAITKEY)) + mutt_any_key_to_continue (NULL); + return 1; +} + +int mutt_select_sort (int reverse) +{ + int method = Sort; /* save the current method in case of abort */ + int ch; + + Sort = 0; + while (!Sort) + { + mvprintw (LINES - 1, 0, +"%sSort (d)ate/(f)rm/(r)ecv/(s)ubj/t(o)/(t)hread/(u)nsort/si(z)e/s(c)ore?: ", + reverse ? "Rev-" : ""); + ch = mutt_getch (); + if (ch == ERR || CI_is_return (ch)) + { + Sort = method; + CLEARLINE (LINES-1); + return (-1); + } + switch (ch) + { + case 'c': + Sort = SORT_SCORE; + break; + case 'd': + Sort = SORT_DATE; + break; + case 'f': + Sort = SORT_FROM; + break; + case 'o': + Sort = SORT_TO; + break; + case 'r': + Sort = SORT_RECEIVED; + break; + case 's': + Sort = SORT_SUBJECT; + break; + case 't': + Sort = SORT_THREADS; + break; + case 'u': + Sort = SORT_ORDER; + break; + case 'z': + Sort = SORT_SIZE; + break; + default: + BEEP (); + break; + } + } + CLEARLINE (LINES-1); + if (reverse) + Sort |= SORT_REVERSE; + + return (Sort != method ? 0 : -1); /* no need to resort if it's the same */ +} + +/* invoke a command in a subshell */ +void mutt_shell_escape (void) +{ + char buf[LONG_STRING]; + + buf[0] = 0; + if (mutt_get_field ("Shell command: ", buf, sizeof (buf), M_CMD) == 0) + { + if (!buf[0]) + strfcpy (buf, Shell, sizeof (buf)); + CLEARLINE (LINES-1); + endwin (); + fflush (stdout); + if (mutt_system (buf) != 0 || option (OPTWAITKEY)) + mutt_any_key_to_continue (NULL); + } +} + +/* enter a mutt command */ +void mutt_enter_command (void) +{ + BUFFER err, token; + char buffer[LONG_STRING], errbuf[SHORT_STRING]; + int r; + int old_strictthreads = option (OPTSTRICTTHREADS); + int old_sortre = option (OPTSORTRE); + + buffer[0] = 0; + if (mutt_get_field (":", buffer, sizeof (buffer), 0) != 0 || !buffer[0]) + return; + err.data = errbuf; + err.dsize = sizeof (errbuf); + memset (&token, 0, sizeof (token)); + r = mutt_parse_rc_line (buffer, &token, &err); + FREE (&token.data); + if (errbuf[0]) + { + /* since errbuf could potentially contain printf() sequences in it, + we must call mutt_error() in this fashion so that vsprintf() + doesn't expect more arguments that we passed */ + if (r == 0) + mutt_message ("%s", errbuf); + else + mutt_error ("%s", errbuf); + } + if (option (OPTSTRICTTHREADS) != old_strictthreads || + option (OPTSORTRE) != old_sortre) + set_option (OPTNEEDRESORT); +} + +void mutt_display_address (ADDRESS *adr) +{ + char buf[SHORT_STRING]; + + buf[0] = 0; + rfc822_write_address (buf, sizeof (buf), adr); + mutt_message ("%s", buf); +} + +/* returns 1 if OK to proceed, 0 to abort */ +static int save_confirm_func (const char *s, struct stat *st) +{ + char tmp[_POSIX_PATH_MAX]; + int ret = 1; + + if (stat (s, st) != -1) + { + if (mx_get_magic (s) == -1) + { + mutt_error ("%s is not a mailbox!", s); + return 0; + } + + if (option (OPTCONFIRMAPPEND)) + { + snprintf (tmp, sizeof (tmp), "Append messages to %s?", s); + if (mutt_yesorno (tmp, 1) < 1) + ret = 0; + } + } + else + { + st->st_mtime = 0; + st->st_atime = 0; + + if (errno == ENOENT) + { + if (option (OPTCONFIRMCREATE)) + { + snprintf (tmp, sizeof (tmp), "Create %s?", s); + if (mutt_yesorno (tmp, 1) < 1) + ret = 0; + } + } + else + { + mutt_perror (s); + return 0; + } + } + + CLEARLINE (LINES-1); + return (ret); +} + +/* returns 0 if the copy/save was successful, or -1 on error/abort */ +int mutt_save_message (HEADER *h, int delete, int decode, int *redraw) +{ + int i, need_buffy_cleanup; + int cmflags = decode ? M_CM_DECODE : 0; + int chflags = decode ? CH_XMIT | CH_MIME : CH_UPDATE_LEN; + char prompt[SHORT_STRING], buf[_POSIX_PATH_MAX]; + CONTEXT ctx; + struct stat st; +#ifdef BUFFY_SIZE + BUFFY *tmp = NULL; +#else + struct utimbuf ut; +#endif + + *redraw = 0; + + snprintf (prompt, sizeof (prompt), "%s%s to mailbox", + decode ? (delete ? "Decode-save" : "Decode-copy") : + (delete ? "Save" : "Copy"), h ? "" : " tagged"); + + if (h) + mutt_default_save (buf, sizeof (buf), h); + else + { + /* look for the first tagged message */ + + for (i = 0; i < Context->vcount; i++) + { + if (Context->hdrs[Context->v2r[i]]->tagged) + { + h = Context->hdrs[Context->v2r[i]]; + break; + } + } + + if (h) + { + mutt_default_save (buf, sizeof (buf), h); + h = NULL; + } + } + + mutt_pretty_mailbox (buf); + if (mutt_enter_fname (prompt, buf, sizeof (buf), redraw, 0) == -1) + return (-1); + + if (*redraw != REDRAW_FULL) + { + if (!h) + *redraw = REDRAW_INDEX | REDRAW_STATUS; + else + *redraw = REDRAW_STATUS; + } + + if (!buf[0]) + return (-1); + + /* This is an undocumented feature of ELM pointed out to me by Felix von + * Leitner + */ + if (strcmp (buf, ".") == 0) + strfcpy (buf, LastSaveFolder, sizeof (buf)); + else + strfcpy (LastSaveFolder, buf, sizeof (LastSaveFolder)); + + mutt_expand_path (buf, sizeof (buf)); + + /* check to make sure that this file is really the one the user wants */ + if (!save_confirm_func (buf, &st)) + { + CLEARLINE (LINES-1); + return (-1); + } + + mutt_message ("Copying to %s...", buf); + + if (mx_open_mailbox (buf, M_APPEND, &ctx) != NULL) + { + if (h) + { + if (decode) + mutt_parse_mime_message (Context, h); + if (mutt_append_message (&ctx, Context, h, cmflags, chflags) == 0 && delete) + { + mutt_set_flag (Context, h, M_DELETE, 1); + mutt_set_flag (Context, h, M_TAG, 0); + } + } + else + { + for (i = 0; i < Context->vcount; i++) + { + if (Context->hdrs[Context->v2r[i]]->tagged) + { + h = Context->hdrs[Context->v2r[i]]; + if (decode) + mutt_parse_mime_message (Context, h); + mutt_append_message (&ctx, Context, h, cmflags, chflags); + if (delete) + { + mutt_set_flag (Context, h, M_DELETE, 1); + mutt_set_flag (Context, h, M_TAG, 0); + } + } + } + } + + need_buffy_cleanup = (ctx.magic == M_MBOX || ctx.magic == M_MMDF); + + mx_close_mailbox (&ctx); + + if (need_buffy_cleanup) + { +#ifdef BUFFY_SIZE + tmp = mutt_find_mailbox (buf); + if (tmp && !tmp->new) + mutt_update_mailbox (tmp); +#else + /* fix up the times so buffy won't get confused */ + if (st.st_mtime > st.st_atime) + { + ut.actime = st.st_atime; + ut.modtime = time (NULL); + utime (buf, &ut); + } + else + utime (buf, NULL); +#endif + } + + mutt_clear_error (); + } + + return (0); +} + +static void print_msg (FILE *fp, CONTEXT *ctx, HEADER *h) +{ + + + +#ifdef _PGPPATH + if (h->pgp & PGPENCRYPT) + { + if (!pgp_valid_passphrase ()) + return; + endwin (); + } +#endif + + + + mutt_parse_mime_message (ctx, h); + mutt_copy_message (fp, ctx, h, M_CM_DECODE, CH_WEED | CH_DECODE); +} + +void mutt_print_message (HEADER *h) +{ + int i, count = 0; + pid_t thepid; + FILE *fp; + + if (query_quadoption (OPT_PRINT, + h ? "Print message?" : "Print tagged messages?") != M_YES) + return; + endwin (); + if ((thepid = mutt_create_filter (PrintCmd, &fp, NULL, NULL)) == -1) + return; + if (h) + { + print_msg (fp, Context, h); + count++; + } + else + { + for (i = 0 ; i < Context->vcount ; i++) + { + if (Context->hdrs[Context->v2r[i]]->tagged) + { + print_msg (fp, Context, Context->hdrs[Context->v2r[i]]); + /* add a formfeed */ + fputc ('\f', fp); + count++; + } + } + } + fclose (fp); + if (mutt_wait_filter (thepid) || option (OPTWAITKEY)) + mutt_any_key_to_continue (NULL); + mutt_message ("Message%s printed", (count > 1) ? "s" : ""); +} + +void mutt_version (void) +{ + mutt_message ("Mutt %s (%s)", VERSION, ReleaseDate); +} -- cgit v1.2.3