diff options
author | Eduardo Chappa <chappa@washington.edu> | 2020-06-07 21:14:19 -0600 |
---|---|---|
committer | Eduardo Chappa <chappa@washington.edu> | 2020-06-07 21:14:19 -0600 |
commit | d1300c95499f3b422c2299432eb4acc93cf4618a (patch) | |
tree | f516d0630fbb085ac689c2010e07cbbe6c281ca5 /alpine | |
parent | 6c702a26f10f04bf225aa914b2eae5b89e3d0b4a (diff) | |
download | alpine-d1300c95499f3b422c2299432eb4acc93cf4618a.tar.xz |
* Experimental: Alpine can pass an HTML message to an external web browser, by using
the "External" command in the ATTACHMENT INDEX screen.
* Experimental: New configuration variable "External Command Loads Inline Images Only"
that controls if Alpine will pass to an external browser a link to all the images in
the HTML message, or will only pass a link to inline images included in the message.
For your privacy and security this feature is enabled by default.
Diffstat (limited to 'alpine')
-rw-r--r-- | alpine/alpine.c | 1 | ||||
-rw-r--r-- | alpine/confscroll.c | 1 | ||||
-rw-r--r-- | alpine/keymenu.c | 2 | ||||
-rw-r--r-- | alpine/keymenu.h | 1 | ||||
-rw-r--r-- | alpine/mailpart.c | 162 | ||||
-rw-r--r-- | alpine/mailpart.h | 2 | ||||
-rw-r--r-- | alpine/mailview.c | 65 |
7 files changed, 219 insertions, 15 deletions
diff --git a/alpine/alpine.c b/alpine/alpine.c index 98814787..d6e5e44e 100644 --- a/alpine/alpine.c +++ b/alpine/alpine.c @@ -3393,6 +3393,7 @@ goodnight_gracey(struct pine *pine_state, int exit_val) free_saved_query_parameters(); #endif + html_dir_clean(1); /* force remove of remaining files */ free_pine_struct(&pine_state); free_histlist(); diff --git a/alpine/confscroll.c b/alpine/confscroll.c index 44c02ca5..ee182b21 100644 --- a/alpine/confscroll.c +++ b/alpine/confscroll.c @@ -330,6 +330,7 @@ exclude_config_var(struct pine *ps, struct variable *var, int allow_hard_to_conf return(!(var->is_user && var->is_used && !var->is_obsolete)); switch(var - ps->vars){ + case V_HTML_DIRECTORY : case V_MAIL_DIRECTORY : case V_INCOMING_FOLDERS : case V_FOLDER_SPEC : diff --git a/alpine/keymenu.c b/alpine/keymenu.c index 529d79f6..65ba6f88 100644 --- a/alpine/keymenu.c +++ b/alpine/keymenu.c @@ -787,7 +787,7 @@ struct key att_index_keys[] = HELP_MENU, OTHER_MENU, HDRMODE_MENU, - NULL_MENU, + {"X",N_("eXternal"),{MC_EXTERNAL,1,{'x'}},KS_NONE}, NULL_MENU, NULL_MENU, NULL_MENU, diff --git a/alpine/keymenu.h b/alpine/keymenu.h index 21315e6a..e29ec201 100644 --- a/alpine/keymenu.h +++ b/alpine/keymenu.h @@ -216,6 +216,7 @@ struct key_menu { #define MC_QUOTA 803 #define MC_ADDHEADER 804 #define MC_XOAUTH2 805 +#define MC_EXTERNAL 806 /* Commands for S/MIME screens */ diff --git a/alpine/mailpart.c b/alpine/mailpart.c index df1de5d6..0e742fc7 100644 --- a/alpine/mailpart.c +++ b/alpine/mailpart.c @@ -69,6 +69,7 @@ static char rcsid[] = "$Id: mailpart.c 1074 2008-06-04 00:08:43Z hubert@u.washin #include "../pith/smime.h" #include "../pith/ical.h" #include "../pith/body.h" +#include "../pith/init.h" /* * Information used to paint and maintain a line on the attachment @@ -146,6 +147,7 @@ int format_msg_att(long, ATTACH_S **, HANDLE_S **, gf_io_t, int); void display_vcard_att(long, ATTACH_S *, int); void display_vcalendar_att(long, ATTACH_S *, int); void display_attach_info(long, ATTACH_S *); +int display_html_external_attachment(long int, ATTACH_S *, int); void forward_attachment(MAILSTREAM *, long, ATTACH_S *); void forward_msg_att(MAILSTREAM *, long, ATTACH_S *); void reply_msg_att(MAILSTREAM *, long, ATTACH_S *); @@ -540,6 +542,11 @@ attachment_screen(struct pine *ps) break; + case MC_EXTERNAL: + display_html_external_attachment(msgno, current->attp, + DA_EXTERNAL | DA_SAVE | (F_OFF(F_EXTERNAL_INLINE_IMAGES, ps_global) ? DA_ALLIMAGES : 0)); + break; + case MC_EXIT : /* exit attachment screen */ ps->next_screen = mail_view_screen; break; @@ -1989,6 +1996,158 @@ print_digest_att(long int msgno, ATTACH_S *a) } } +int +display_html_external_attachment(long int msgno, ATTACH_S *a, int flags) +{ + char dir_path[MAXPATH+1]; + char *filename = NULL; + char *file_path; /* file:///some/path/ */ + STORE_S *store; + gf_io_t pc; + char *err; + int we_cancel = 0, saved, errs; + char *tool; + ATTACH_S *att; + unsigned long rawno; + + if(a->body == NULL){ + q_status_message(SM_ORDER | SM_DING, 3, 5, _("Attachment has no body!")); + return 1; + } else if (a->body->type != TYPETEXT + || a->body->subtype == NULL + || strucmp(a->body->subtype, "HTML")){ + q_status_message(SM_ORDER | SM_DING, 3, 5, _("Not a TEXT/HTML attachment")); + return 1; + } + + /* zero these variables, just in case. Do not try freeing them. They have short lives */ + for(att = ps_global->atmts; att->description != NULL; att++){ + att->cid_tmpfile = NULL; + att->tmpdir = NULL; + } + + /* setup the environment first */ + if(!ps_global->html_dir){ + if(!html_directory_path(ps_global->VAR_HTML_DIRECTORY, dir_path, MAXPATH)){ + q_status_message1(SM_ORDER | SM_DING, 3, 5, + _("Error creating full path for %s"), ps_global->VAR_HTML_DIRECTORY); + return 1; + } else if (init_html_directory(dir_path) < 0){ + q_status_message1(SM_ORDER | SM_DING, 3, 5, _("Error initializing %s"), dir_path); + return 1; + } + ps_global->html_dir = cpystr(dir_path); + } + else{ + strncpy(dir_path, ps_global->html_dir, sizeof(dir_path)); + dir_path[sizeof(dir_path)-1] = '\0'; + } + + if(create_random_dir(dir_path, sizeof(dir_path)) < 0){ + q_status_message1(SM_ORDER | SM_DING, 3, 5, _("Error creating temp dir in %s"), dir_path); + return 1; + } + + a->tmpdir = cpystr(dir_path); + add_html_log(&ps_global->html_dir_list, a->tmpdir); + + /* Process the text/html part */ + filename = temp_nam_ext(a->tmpdir, "tmp-html-", HTML_EXT); + + if(!filename){ + q_status_message1(SM_ORDER | SM_DING, 3, 5, + _("Error \"%s\", Can't create temporary file"), + error_description(errno)); + return(1); + } + + if((store = so_get(FileStar, filename, WRITE_ACCESS|OWNER_ONLY)) == NULL){ + q_status_message2(SM_ORDER | SM_DING, 3, 5, + _("Error \"%s\", Can't write file %s"), + error_description(errno), filename); + if(filename){ + our_unlink(filename); + fs_give((void **)&filename); + } + return(1); + } + + if(a->body->size.bytes){ + char msg_buf[128]; + + snprintf(msg_buf, sizeof(msg_buf), "Decoding %s%s%s%s", + a->description ? "\"" : "", + a->description ? a->description : "attachment number ", + a->description ? "" : a->number, + a->description ? "\"" : ""); + msg_buf[sizeof(msg_buf)-1] = '\0'; + we_cancel = init_att_progress(msg_buf, ps_global->mail_stream, a->body); + } + + gf_set_so_writec(&pc, store); + + err = detach(ps_global->mail_stream, msgno, a->number, 0L, NULL, pc, NULL, + DT_EXTERNAL | ((flags & DA_ALLIMAGES) ? DT_ALLIMAGES : 0)); + + gf_clear_so_writec(store); + + if(we_cancel) + cancel_busy_cue(0); + + so_give(&store); + + /*----- Download all needed inline attachments ------*/ + saved = errs = 0; + rawno = mn_m2raw(ps_global->msgmap, msgno); + for (att = ps_global->atmts; rawno > 0 && att->description != NULL; att++){ + if(att->cid_tmpfile){ + if(write_attachment_to_file(ps_global->mail_stream, rawno, + att, GER_NONE, att->cid_tmpfile) == 1) + saved++; + else + errs++; + fs_give((void **) &att->cid_tmpfile); + } + if(att->tmpdir) + fs_give((void **) &att->tmpdir); + } + + if(err){ + q_status_message2(SM_ORDER | SM_DING, 3, 5, + "%s: Error saving image to temp file %s", + err, filename); + if(filename){ + our_unlink(filename); + fs_give((void **)&filename); + } + return(1); + } + + tool = get_url_external_handler("http://", 1); + if(tool == NULL) tool = get_url_external_handler("http://", 0); + if(tool == NULL) tool = get_url_external_handler("https://", 1); + if(tool == NULL) tool = get_url_external_handler("https://", 0); + + file_path = fs_get((strlen(filename) + strlen("file://") + 1)*sizeof(char)); + sprintf(file_path, "file://%s", filename); + + /*----- Run the viewer process ----*/ + if(do_url_launch(tool, file_path) == 0) + q_status_message(SM_ORDER, 3, 3, "Opened message in external browser"); + else + q_status_message(SM_ORDER|SM_DING, 3, 5, "Failed to open message in external browser"); + + if(filename) + fs_give((void **)&filename); + + if(file_path) + fs_give((void **)&file_path); + + ps_global->mangled_screen = 1; + + return(0); +} + /*---------------------------------------------------------------------- Unpack and display the given attachment associated with given message no. @@ -2012,6 +2171,9 @@ display_attachment(long int msgno, ATTACH_S *a, int flags) char ext[32]; char mtype[128]; + if(flags & DA_EXTERNAL) + return display_html_external_attachment(msgno, a, flags); + /*------- Display the attachment -------*/ if(dispatch_attachment(a) == MCD_NONE){ /*----- Can't display this type ------*/ diff --git a/alpine/mailpart.h b/alpine/mailpart.h index 6f1c0023..ecc1c59e 100644 --- a/alpine/mailpart.h +++ b/alpine/mailpart.h @@ -27,6 +27,8 @@ #define DA_FROM_VIEW 0x02 /* see mailpart.c */ #define DA_RESIZE 0x04 #define DA_DIDPROMPT 0x08 /* Already prompted to view att */ +#define DA_EXTERNAL 0x10 /* use external viewer operations */ +#define DA_ALLIMAGES 0x20 /* external browser displays all images */ /* exported prototypes */ diff --git a/alpine/mailview.c b/alpine/mailview.c index eec5805e..dbc009ed 100644 --- a/alpine/mailview.c +++ b/alpine/mailview.c @@ -720,15 +720,15 @@ int scroll_handle_prompt(HANDLE_S *handle, int force) { char prompt[256], tmp[MAILTMPLEN]; - int rc, flags, local_h; + int rc, flags, local_h, external, images; static ESCKEY_S launch_opts[] = { /* TRANSLATORS: command names, editURL means user gets to edit a URL if they want, editApp is edit application where they edit the application used to view a URL */ {'y', 'y', "Y", N_("Yes")}, {'n', 'n', "N", N_("No")}, - {-2, 0, NULL, NULL}, - {-2, 0, NULL, NULL}, + {0, 'x', "X", ""}, + {0, 'i', "I", ""}, {0, 'u', "U", N_("editURL")}, {0, 'a', "A", N_("editApp")}, {-1, 0, NULL, NULL}}; @@ -833,6 +833,25 @@ scroll_handle_prompt(HANDLE_S *handle, int force) else launch_opts[4].ch = -1; + if(handle->type == Attach + && handle->h.attach + && handle->h.attach->body + && handle->h.attach->body->type == TYPETEXT + && !strucmp(handle->h.attach->body->subtype, "HTML")){ + images = F_OFF(F_EXTERNAL_INLINE_IMAGES, ps_global) ? 1 : 0; + external = 0; /* default to not using external viewer, set to 1 to make it default */ + force = 0; /* do not open automatically */ + launch_opts[2].ch = 'x'; + launch_opts[2].label = external > 0 ? N_("No eXternal") : N_("External"); + launch_opts[3].ch = external > 0 ? 'i' : -2; + launch_opts[3].label = images ? N_("Inline imgs") : N_("All images"); + } + else { + launch_opts[2].ch = -2; /* skip */ + launch_opts[3].ch = -2; /* skip */ + external = images = -1; + } + if(force || (handle->type == URL && (!struncmp(handle->h.url.path, "x-alpine-", 9) @@ -852,13 +871,15 @@ scroll_handle_prompt(HANDLE_S *handle, int force) (int) MIN(MAX(0,sc - 25), sizeof(prompt)-50), handle->h.url.path+7, (strlen(handle->h.url.path+7) > MAX(0,sc-25)) ? "..." : ""); else - snprintf(prompt, sizeof(prompt), "View selected %s %s%.*s%s ? ", + snprintf(prompt, sizeof(prompt), "View selected %s %s%s%s%.*s%s ? ", (handle->type == URL) ? "URL" : "Attachment", + external > 0 ? "using external viewer " : "", + external > 0 ? (images > 0 ? "including all images" : "including inline images only") : "", (handle->type == URL) ? "\"" : "", - (int) MIN(MAX(0,sc-27), sizeof(prompt)-50), + (int) MIN(MAX(0,sc-27-(external ? (images ? 41 : 50) : 0)), sizeof(prompt)-50), (handle->type == URL) ? handle->h.url.path : "", (handle->type == URL) - ? ((strlen(handle->h.url.path) > MAX(0,sc-27)) + ? ((strlen(handle->h.url.path) > MAX(0,sc-27 - (external ? (images > 0 ? 41 : 50) : 0))) ? "...\"" : "\"") : ""); prompt[sizeof(prompt)-1] = '\0'; @@ -866,7 +887,20 @@ scroll_handle_prompt(HANDLE_S *handle, int force) switch(radio_buttons(prompt, -FOOTER_ROWS(ps_global), launch_opts, 'y', 'n', NO_HELP, RB_SEQ_SENSITIVE)){ case 'y' : - return(1); + return(external > 0 ? (images > 0 ? -2 : -1) : 1); + + case 'x' : + external = 1 - external; + images = F_OFF(F_EXTERNAL_INLINE_IMAGES, ps_global) ? 1 : 0; + launch_opts[2].label = external > 0 ? N_("No eXternal") : N_("External"); + launch_opts[3].ch = external > 0 ? 'i' : -2; + launch_opts[3].label = images ? N_("Inline imgs") : N_("All images"); + break; + + case 'i' : + images = 1 - images; + launch_opts[3].label = images ? N_("Inline imgs") : N_("All images"); + break; case 'u' : strncpy(tmp, handle->h.url.path, sizeof(tmp)-1); @@ -950,6 +984,7 @@ scroll_handle_prompt(HANDLE_S *handle, int force) int scroll_handle_launch(HANDLE_S *handle, int force) { + int flags; switch(handle->type){ case URL : if(handle->h.url.path){ @@ -965,13 +1000,15 @@ scroll_handle_launch(HANDLE_S *handle, int force) break; case Attach : - if(scroll_handle_prompt(handle, force)) - display_attachment(mn_m2raw(ps_global->msgmap, - mn_get_cur(ps_global->msgmap)), - handle->h.attach, DA_FROM_VIEW | DA_DIDPROMPT); - else - return(-1); - + flags = DA_FROM_VIEW | DA_DIDPROMPT; + switch(scroll_handle_prompt(handle, force)){ + case 1 : break; + case -2 : flags |= DA_ALLIMAGES; + case -1 : flags |= DA_EXTERNAL; break; + default : return -1; + } + display_attachment(mn_m2raw(ps_global->msgmap, + mn_get_cur(ps_global->msgmap)), handle->h.attach, flags); break; case Folder : |