From 50a851fdc29309b8693a8f9a1ae001cec63bb6c5 Mon Sep 17 00:00:00 2001 From: Thomas Roessler Date: Sat, 4 Oct 2003 20:34:59 +0000 Subject: [PATCH] This patch fixes various aspects of the attachment-saving user interface. Changes include: * When tagging and saving multiple attachments, you can now use the same target directory for multiple attachments. * When you can't save an attachment, you get an opportunity to enter a new file name. * The menu cursor will highlight the attachment that you are currently discussing with mutt. * Various bug fixes. This does, in particular, address #1619 (Debian#208430). --- attach.h | 2 +- commands.c | 2 +- compose.c | 24 +++------ keymap.h | 2 + lib.c | 7 +++ lib.h | 1 + menu.c | 52 +++++++++++-------- mutt.h | 2 + mutt_menu.h | 1 + muttlib.c | 59 +++++++++++++++------ pager.c | 2 +- protos.h | 2 +- recvattach.c | 141 +++++++++++++++++++++++++++++++++++---------------- 13 files changed, 195 insertions(+), 102 deletions(-) diff --git a/attach.h b/attach.h index 2147b744..2e17a449 100644 --- a/attach.h +++ b/attach.h @@ -24,7 +24,7 @@ int mutt_attach_display_loop (MUTTMENU *menu, int op, FILE *fp, HEADER *hdr, int recv); -void mutt_save_attachment_list (FILE *fp, int tag, BODY *top, HEADER *hdr); +void mutt_save_attachment_list (FILE *fp, int tag, BODY *top, HEADER *hdr, MUTTMENU *menu); void mutt_pipe_attachment_list (FILE *fp, int tag, BODY *top, int filter); void mutt_print_attachment_list (FILE *fp, int tag, BODY *top); diff --git a/commands.c b/commands.c index fe623fd4..3761926d 100644 --- a/commands.c +++ b/commands.c @@ -761,7 +761,7 @@ int mutt_save_message (HEADER *h, int delete, mutt_expand_path (buf, sizeof (buf)); /* check to make sure that this file is really the one the user wants */ - if (!mutt_save_confirm (buf, &st)) + if (mutt_save_confirm (buf, &st) != 0) return -1; if (WithCrypto && need_passphrase && (decode || decrypt) diff --git a/compose.c b/compose.c index 22ebc23c..a77667c8 100644 --- a/compose.c +++ b/compose.c @@ -483,6 +483,7 @@ static void update_idx (MUTTMENU *menu, ATTACHPTR **idx, short idxlen) idx[idxlen]->level = (idxlen > 0) ? idx[idxlen-1]->level : 0; if (idxlen) idx[idxlen - 1]->content->next = idx[idxlen]->content; + idx[idxlen]->content->aptr = idx[idxlen]; menu->current = idxlen++; mutt_update_tree (idx, idxlen); menu->max = idxlen; @@ -760,14 +761,7 @@ int mutt_compose_menu (HEADER *msg, /* structure for new message */ idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR)); if ((idx[idxlen]->content = crypt_pgp_make_key_attachment(NULL)) != NULL) { - idx[idxlen]->level = (idxlen > 0) ? idx[idxlen-1]->level : 0; - - if(idxlen) - idx[idxlen - 1]->content->next = idx[idxlen]->content; - - menu->current = idxlen++; - mutt_update_tree (idx, idxlen); - menu->max = idxlen; + update_idx (menu, idx, idxlen++); menu->redraw |= REDRAW_INDEX; } else @@ -1187,14 +1181,7 @@ int mutt_compose_menu (HEADER *msg, /* structure for new message */ mutt_error _("What we have here is a failure to make an attachment"); continue; } - - idx[idxlen]->level = (idxlen > 0) ? idx[idxlen-1]->level : 0; - if (idxlen) - idx[idxlen - 1]->content->next = idx[idxlen]->content; - - menu->current = idxlen++; - mutt_update_tree (idx, idxlen); - menu->max = idxlen; + update_idx (menu, idx, idxlen++); idx[menu->current]->content->type = itype; mutt_str_replace (&idx[menu->current]->content->subtype, p); @@ -1227,7 +1214,7 @@ int mutt_compose_menu (HEADER *msg, /* structure for new message */ case OP_SAVE: CHECK_COUNT; - mutt_save_attachment_list (NULL, menu->tagprefix, menu->tagprefix ? msg->content : idx[menu->current]->content, NULL); + mutt_save_attachment_list (NULL, menu->tagprefix, menu->tagprefix ? msg->content : idx[menu->current]->content, NULL, menu); MAYBE_REDRAW (menu->redraw); break; @@ -1392,7 +1379,10 @@ int mutt_compose_menu (HEADER *msg, /* structure for new message */ { msg->content = idx[0]->content; for (i = 0; i < idxlen; i++) + { + idx[i]->content->aptr = NULL; FREE (&idx[i]); + } } else msg->content = NULL; diff --git a/keymap.h b/keymap.h index bdbafae6..a88bbf46 100644 --- a/keymap.h +++ b/keymap.h @@ -19,6 +19,8 @@ #ifndef KEYMAP_H #define KEYMAP_H +#include "mapping.h" + /* maximal length of a key binding sequence used for buffer in km_bindkey */ #define MAX_SEQ 8 diff --git a/lib.c b/lib.c index 97879c98..4c6a4b5b 100644 --- a/lib.c +++ b/lib.c @@ -646,3 +646,10 @@ char *mutt_concat_path (char *d, const char *dir, const char *fname, size_t l) snprintf (d, l, fmt, dir, fname); return d; } + +const char *mutt_basename (const char *f) +{ + const char *p = strrchr (f, '/'); + if (p) ++p; + return p; +} diff --git a/lib.h b/lib.h index 6e006836..2bda25d2 100644 --- a/lib.h +++ b/lib.h @@ -118,6 +118,7 @@ char *mutt_substrdup (const char *, const char *); char *safe_strdup (const char *); const char *mutt_stristr (const char *, const char *); +const char *mutt_basename (const char *); int mutt_copy_stream (FILE *, FILE *); int mutt_copy_bytes (FILE *, FILE *, size_t); diff --git a/menu.c b/menu.c index f64d918c..11d8faa1 100644 --- a/menu.c +++ b/menu.c @@ -800,6 +800,34 @@ static int menu_dialog_dokey (MUTTMENU *menu, int *ip) } } +int menu_redraw (MUTTMENU *menu) +{ + /* See if all or part of the screen needs to be updated. */ + if (menu->redraw & REDRAW_FULL) + { + menu_redraw_full (menu); + /* allow the caller to do any local configuration */ + return (OP_REDRAW); + } + + if (!menu->dialog) + menu_check_recenter (menu); + + if (menu->redraw & REDRAW_STATUS) + menu_redraw_status (menu); + if (menu->redraw & REDRAW_INDEX) + menu_redraw_index (menu); + else if (menu->redraw & (REDRAW_MOTION | REDRAW_MOTION_RESYNCH)) + menu_redraw_motion (menu); + else if (menu->redraw == REDRAW_CURRENT) + menu_redraw_current (menu); + + if (menu->dialog) + menu_redraw_prompt (menu); + + return OP_NULL; +} + int mutt_menuLoop (MUTTMENU *menu) { int i = OP_NULL; @@ -819,28 +847,8 @@ int mutt_menuLoop (MUTTMENU *menu) imap_keepalive (); #endif - /* See if all or part of the screen needs to be updated. */ - if (menu->redraw & REDRAW_FULL) - { - menu_redraw_full (menu); - /* allow the caller to do any local configuration */ - return (OP_REDRAW); - } - - if (!menu->dialog) - menu_check_recenter (menu); - - if (menu->redraw & REDRAW_STATUS) - menu_redraw_status (menu); - if (menu->redraw & REDRAW_INDEX) - menu_redraw_index (menu); - else if (menu->redraw & (REDRAW_MOTION | REDRAW_MOTION_RESYNCH)) - menu_redraw_motion (menu); - else if (menu->redraw == REDRAW_CURRENT) - menu_redraw_current (menu); - - if (menu->dialog) - menu_redraw_prompt (menu); + if (menu_redraw (menu) == OP_REDRAW) + return OP_REDRAW; menu->oldcurrent = menu->current; diff --git a/mutt.h b/mutt.h index f708d091..cc0d1b19 100644 --- a/mutt.h +++ b/mutt.h @@ -598,6 +598,8 @@ typedef struct body struct body *parts; /* parts of a multipart or message/rfc822 */ struct header *hdr; /* header information for message/rfc822 */ + struct attachptr *aptr; /* Menu information, used in recvattach.c */ + time_t stamp; /* time stamp of last * encoding update. */ diff --git a/mutt_menu.h b/mutt_menu.h index 83b83cdb..9ed85bba 100644 --- a/mutt_menu.h +++ b/mutt_menu.h @@ -83,6 +83,7 @@ void menu_redraw_index (MUTTMENU *); void menu_redraw_status (MUTTMENU *); void menu_redraw_motion (MUTTMENU *); void menu_redraw_current (MUTTMENU *); +int menu_redraw (MUTTMENU *); void menu_first_entry (MUTTMENU *); void menu_last_entry (MUTTMENU *); void menu_top_page (MUTTMENU *); diff --git a/muttlib.c b/muttlib.c index 9b75b834..7d412089 100644 --- a/muttlib.c +++ b/muttlib.c @@ -814,10 +814,11 @@ void mutt_expand_fmt (char *dest, size_t destlen, const char *fmt, const char *s } -/* return 0 on success, -1 on error */ +/* return 0 on success, -1 on abort, 1 on error */ int mutt_check_overwrite (const char *attname, const char *path, - char *fname, size_t flen, int *append) + char *fname, size_t flen, int *append, char **directory) { + int rc = 0; char tmp[_POSIX_PATH_MAX]; struct stat st; @@ -828,18 +829,38 @@ int mutt_check_overwrite (const char *attname, const char *path, return -1; if (S_ISDIR (st.st_mode)) { - if (mutt_yesorno (_("File is a directory, save under it?"), M_YES) != M_YES) - return (-1); + if (directory) + { + switch (mutt_multi_choice + (_("File is a directory, save under it? [(y)es, (n)o, (a)ll]"), _("yna"))) + { + case 3: /* all */ + mutt_str_replace (directory, fname); + break; + case 1: /* yes */ + FREE (directory); + break; + case -1: /* abort */ + FREE (directory); + return -1; + case 2: /* no */ + FREE (directory); + return 1; + } + } + else if ((rc = mutt_yesorno (_("File is a directory, save under it?"), M_YES)) != M_YES) + return (rc == M_NO) ? 1 : -1; + if (!attname || !attname[0]) { tmp[0] = 0; if (mutt_get_field (_("File under directory: "), tmp, sizeof (tmp), M_FILE | M_CLEAR) != 0 || !tmp[0]) return (-1); - snprintf (fname, flen, "%s/%s", path, tmp); + mutt_concat_path (fname, path, tmp, flen); } else - snprintf (fname, flen, "%s/%s", path, attname); + mutt_concat_path (fname, path, mutt_basename (attname), flen); } if (*append == 0 && access (fname, F_OK) == 0) @@ -848,8 +869,9 @@ int mutt_check_overwrite (const char *attname, const char *path, (_("File exists, (o)verwrite, (a)ppend, or (c)ancel?"), _("oac"))) { case -1: /* abort */ + return -1; case 3: /* cancel */ - return -1; + return 1; case 2: /* append */ *append = M_SAVE_APPEND; @@ -1133,11 +1155,12 @@ FILE *mutt_open_read (const char *path, pid_t *thepid) return (f); } -/* returns 1 if OK to proceed, 0 to abort */ +/* returns 0 if OK to proceed, -1 to abort, 1 to retry */ int mutt_save_confirm (const char *s, struct stat *st) { char tmp[_POSIX_PATH_MAX]; - int ret = 1; + int ret = 0; + int rc; int magic = 0; magic = mx_get_magic (s); @@ -1146,7 +1169,7 @@ int mutt_save_confirm (const char *s, struct stat *st) if (magic == M_POP) { mutt_error _("Can't save message to POP mailbox."); - return 0; + return 1; } #endif @@ -1155,14 +1178,16 @@ int mutt_save_confirm (const char *s, struct stat *st) if (magic == -1) { mutt_error (_("%s is not a mailbox!"), s); - return 0; + return 1; } if (option (OPTCONFIRMAPPEND)) { snprintf (tmp, sizeof (tmp), _("Append messages to %s?"), s); - if (mutt_yesorno (tmp, M_YES) != M_YES) - ret = 0; + if ((rc = mutt_yesorno (tmp, M_YES)) == M_NO) + ret = 1; + else if (rc == -1) + ret = -1; } } else @@ -1179,14 +1204,16 @@ int mutt_save_confirm (const char *s, struct stat *st) if (option (OPTCONFIRMCREATE)) { snprintf (tmp, sizeof (tmp), _("Create %s?"), s); - if (mutt_yesorno (tmp, M_YES) != M_YES) - ret = 0; + if ((rc = mutt_yesorno (tmp, M_YES)) == M_NO) + ret = 1; + else if (rc == -1) + ret = -1; } } else { mutt_perror (s); - return 0; + return 1; } } } diff --git a/pager.c b/pager.c index 26fcf07e..dd84c4f8 100644 --- a/pager.c +++ b/pager.c @@ -2438,7 +2438,7 @@ CHECK_IMAP_ACL(IMAP_ACL_WRITE); case OP_SAVE: if (IsAttach (extra)) { - mutt_save_attachment_list (extra->fp, 0, extra->bdy, extra->hdr); + mutt_save_attachment_list (extra->fp, 0, extra->bdy, extra->hdr, NULL); break; } /* fall through */ diff --git a/protos.h b/protos.h index 5a0d97f3..8a4722cd 100644 --- a/protos.h +++ b/protos.h @@ -248,7 +248,7 @@ int mutt_check_key (const char *); int mutt_check_menu (const char *); int mutt_check_mime_type (const char *); int mutt_check_month (const char *); -int mutt_check_overwrite (const char *, const char *, char *, size_t, int *); +int mutt_check_overwrite (const char *, const char *, char *, size_t, int *, char **); int mutt_check_traditional_pgp (HEADER *, int *); int mutt_command_complete (char *, size_t, int, int); int mutt_var_value_complete (char *, size_t, int); diff --git a/recvattach.c b/recvattach.c index 09abea2d..aa1ce274 100644 --- a/recvattach.c +++ b/recvattach.c @@ -129,6 +129,7 @@ ATTACHPTR **mutt_gen_attach_list (BODY *m, new = idx[(*idxlen)++]; new->content = m; + m->aptr = new; new->parent_type = parent_type; new->level = level; @@ -363,14 +364,21 @@ int mutt_is_message_type (int type, const char *subtype) return (ascii_strcasecmp (subtype, "rfc822") == 0 || ascii_strcasecmp (subtype, "news") == 0); } -static int mutt_query_save_attachment (FILE *fp, BODY *body, HEADER *hdr) +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; - - if (body->filename) - strfcpy (buf, body->filename, sizeof (buf)); + 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 && @@ -379,45 +387,68 @@ static int mutt_query_save_attachment (FILE *fp, BODY *body, HEADER *hdr) else buf[0] = 0; - if (mutt_get_field (_("Save to file: "), buf, sizeof (buf), M_FILE | M_CLEAR) != 0 - || !buf[0]) - return -1; - - 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) + prompt = _("Save to file: "); + while (prompt) { - struct stat st; - - /* check to make sure that this file is really the one the user wants */ - if (!mutt_save_confirm (buf, &st)) - return -1; - strfcpy(tfile, buf, sizeof(tfile)); - } - else - if (mutt_check_overwrite (body->filename, buf, tfile, sizeof (tfile), &append)) + if (mutt_get_field (prompt, buf, sizeof (buf), M_FILE | M_CLEAR) != 0 + || !buf[0]) return -1; - - mutt_message _("Saving..."); - if (mutt_save_attachment (fp, body, tfile, append, (hdr || !is_message) ? hdr : body->hdr) == 0) - { - mutt_message _("Attachment saved."); - return 0; + + 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; + } } - else - return -1; + return 0; } - -void mutt_save_attachment_list (FILE *fp, int tag, BODY *top, HEADER *hdr) + +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; @@ -438,7 +469,7 @@ void mutt_save_attachment_list (FILE *fp, int tag, BODY *top, HEADER *hdr) return; mutt_expand_path (buf, sizeof (buf)); if (mutt_check_overwrite (top->filename, buf, tfile, - sizeof (tfile), &append)) + sizeof (tfile), &append, NULL)) return; rc = mutt_save_attachment (fp, top, tfile, append, hdr); if (rc == 0 && AttachSep && (fpout = fopen (tfile,"a")) != NULL) @@ -457,15 +488,37 @@ void mutt_save_attachment_list (FILE *fp, int tag, BODY *top, HEADER *hdr) } } } - else - mutt_query_save_attachment (fp, top, hdr); + 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); + mutt_save_attachment_list (fp, 1, top->parts, hdr, menu); if (!tag) - return; + 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."); } @@ -977,9 +1030,9 @@ void mutt_view_attachments (HEADER *hdr) case OP_SAVE: mutt_save_attachment_list (fp, menu->tagprefix, - menu->tagprefix ? cur : idx[menu->current]->content, hdr); + menu->tagprefix ? cur : idx[menu->current]->content, hdr, menu); - if (option (OPTRESOLVE) && menu->current < menu->max - 1) + if (!menu->tagprefix && option (OPTRESOLVE) && menu->current < menu->max - 1) menu->current++; menu->redraw = REDRAW_MOTION_RESYNCH | REDRAW_FULL; @@ -1120,6 +1173,8 @@ void mutt_view_attachments (HEADER *hdr) continue; if (idx[idxmax]->content && idx[idxmax]->content->deleted) hdr->attach_del = 1; + if (idx[idxmax]->content) + idx[idxmax]->content->aptr = NULL; FREE (&idx[idxmax]->tree); FREE (&idx[idxmax]); } -- 2.40.0