diff options
author | Eduardo Chappa <chappa@washington.edu> | 2013-05-31 17:08:22 -0600 |
---|---|---|
committer | Eduardo Chappa <chappa@washington.edu> | 2013-05-31 17:08:22 -0600 |
commit | 81e994d7907f850506ddc248f84761a54995e58c (patch) | |
tree | 3bc4993b48ddeec45dee51323437200ab975887c /alpine | |
parent | 077522d7e058133f9de99d0d74481566b21c5a98 (diff) | |
download | alpine-81e994d7907f850506ddc248f84761a54995e58c.tar.xz |
* Fix not allow remote execution by adding PIPE_NOSHELL to the opening of a url by
a browser.
Diffstat (limited to 'alpine')
35 files changed, 1712 insertions, 169 deletions
diff --git a/alpine/Makefile.am b/alpine/Makefile.am index c80a97ff..76bef8e3 100644 --- a/alpine/Makefile.am +++ b/alpine/Makefile.am @@ -46,3 +46,4 @@ CLEANFILES = date.c date.c: echo "char datestamp[]="\"`date`\"";" > date.c echo "char hoststamp[]="\"`hostname`\"";" >> date.c + cat ../patchlevel >> date.c diff --git a/alpine/Makefile.in b/alpine/Makefile.in index 4bb886ec..09719265 100644 --- a/alpine/Makefile.in +++ b/alpine/Makefile.in @@ -817,6 +817,7 @@ uninstall-am: uninstall-binPROGRAMS date.c: echo "char datestamp[]="\"`date`\"";" > date.c echo "char hoststamp[]="\"`hostname`\"";" >> date.c + cat ../patchlevel >> date.c # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/alpine/adrbkcmd.c b/alpine/adrbkcmd.c index 9320160d..ab3c981b 100644 --- a/alpine/adrbkcmd.c +++ b/alpine/adrbkcmd.c @@ -4128,6 +4128,8 @@ ab_compose_internal(BuildTo bldto, int allow_role) * won't do anything, but will cause compose_mail to think there's * already a role so that it won't try to confirm the default. */ + if (ps_global->role) + fs_give((void **)&ps_global->role); if(role) role = copy_action(role); else{ @@ -4135,6 +4137,7 @@ ab_compose_internal(BuildTo bldto, int allow_role) memset((void *)role, 0, sizeof(*role)); role->nick = cpystr("Default Role"); } + ps_global->role = cpystr(role->nick); } compose_mail(addr, fcc, role, NULL, NULL); diff --git a/alpine/alpine.c b/alpine/alpine.c index 9e7298f2..838473ec 100644 --- a/alpine/alpine.c +++ b/alpine/alpine.c @@ -308,6 +308,7 @@ main(int argc, char **argv) mail_parameters(NULL, SET_SENDCOMMAND, (void *) pine_imap_cmd_happened); mail_parameters(NULL, SET_FREESTREAMSPAREP, (void *) sp_free_callback); mail_parameters(NULL, SET_FREEELTSPAREP, (void *) free_pine_elt); + mail_parameters(NULL, SET_ERASEPASSWORD, (void *) pine_delete_pwd); #ifdef SMIME mail_parameters(NULL, SET_FREEBODYSPAREP, (void *) free_smime_body_sparep); #endif @@ -459,6 +460,11 @@ main(int argc, char **argv) convert_args_to_utf8(pine_state, &args); + if (args.action == aaFolder && !args.data.folder && + ps_global->send_immediately){ + printf(_("No value for To: field specified\n")); + exit(-1); + } if(args.action == aaFolder){ pine_state->beginning_of_month = first_run_of_month(); pine_state->beginning_of_year = first_run_of_year(); @@ -467,6 +473,7 @@ main(int argc, char **argv) /* Set up optional for user-defined display filtering */ pine_state->tools.display_filter = dfilter; pine_state->tools.display_filter_trigger = dfilter_trigger; + pine_state->tools.exec_rule = exec_function_rule; #ifdef _WINDOWS if(ps_global->install_flag){ @@ -558,6 +565,11 @@ main(int argc, char **argv) if(F_ON(F_MAILDROPS_PRESERVE_STATE, ps_global)) mail_parameters(NULL, SET_SNARFPRESERVE, (void *) TRUE); +#ifndef _WINDOWS + mail_parameters(NULL,SET_COURIERSTYLE, + (void *)(F_ON(F_COURIER_FOLDER_LIST, ps_global) ? 1 : 0)); +#endif + rvl = 0L; if(pine_state->VAR_NNTPRANGE){ if(!SVAR_NNTPRANGE(pine_state, rvl, tmp_20k_buf, SIZEOF_20KBUF)) @@ -677,6 +689,7 @@ main(int argc, char **argv) /*--- output side ---*/ + if (!ps_global->send_immediately){ rv = config_screen(&(pine_state->ttyo)); #ifndef _WINDOWS /* always succeeds under _WINDOWS */ if(rv){ @@ -717,12 +730,6 @@ main(int argc, char **argv) /* initialize titlebar in case we use it */ set_titlebar("", NULL, NULL, NULL, NULL, 0, FolderName, 0, 0, NULL); - /* - * Prep storage object driver for PicoText - */ - so_register_external_driver(pine_pico_get, pine_pico_give, pine_pico_writec, pine_pico_readc, - pine_pico_puts, pine_pico_seek, NULL, NULL); - #ifdef DEBUG if(ps_global->debug_imap > 4 || debug > 9){ q_status_message(SM_ORDER | SM_DING, 5, 9, @@ -730,6 +737,19 @@ main(int argc, char **argv) flush_status_messages(0); } #endif + } + else{ + fake_config_screen(&(pine_state->ttyo)); + init_folders(pine_state); /* digest folder spec's */ + } + + /* + * Prep storage object driver for PicoText + */ + so_register_external_driver(pine_pico_get, pine_pico_give, + (args.noutf8 == 0 ? pine_pico_writec : pine_pico_writec_noucs), + (args.noutf8 == 0 ? pine_pico_readc : pine_pico_readc_noucs), + (args.noutf8 == 0 ? pine_pico_puts : pine_pico_puts_noucs), pine_pico_seek, NULL, NULL); if(args.action == aaPrcCopy || args.action == aaAbookCopy){ int exit_val = -1; @@ -905,6 +925,12 @@ main(int argc, char **argv) int len, good_addr = 1; int exit_val = 0; BUILDER_ARG fcc; + ACTION_S *role = NULL; + + if (pine_state->in_init_seq && pine_state->send_immediately + && (char) *pine_state->initial_cmds++ == '#' + && ++pine_state->initial_cmds_offset) + role_select_screen(pine_state, &role, 1); if(pine_state->in_init_seq){ pine_state->in_init_seq = pine_state->save_in_init_seq = 0; @@ -943,7 +969,7 @@ main(int argc, char **argv) memset(&fcc, 0, sizeof(fcc)); if(good_addr){ - compose_mail(addr, fcc.tptr, NULL, + compose_mail(addr, fcc.tptr, role, args.data.mail.attachlist, stdin_getc); } else{ @@ -977,6 +1003,7 @@ main(int argc, char **argv) pine_state->mail_stream = NULL; pine_state->mangled_screen = 1; + pine_state->subject = NULL; if(args.action == aaURL){ url_tool_t f; @@ -1092,6 +1119,7 @@ main(int argc, char **argv) } } + if (!pine_state->send_immediately) fflush(stdout); #if !defined(_WINDOWS) && !defined(LEAVEOUTFIFO) @@ -2980,10 +3008,15 @@ process_init_cmds(struct pine *ps, char **list) if(i > 0){ ps->initial_cmds = (int *)fs_get((i+1) * sizeof(int)); ps->free_initial_cmds = ps->initial_cmds; + ps->initial_cmds_backup = (int *)fs_get((i+1) * sizeof(int)); + ps->free_initial_cmds_backup = ps->initial_cmds_backup; for(j = 0; j < i; j++) - ps->initial_cmds[j] = i_cmds[j]; - - ps->initial_cmds[i] = 0; + ps->initial_cmds[j] = ps->initial_cmds_backup[j] = i_cmds[j]; +#define ctrl_x 24 + if (i > 1) + ps->send_immediately = i_cmds[i - 2] == ctrl_x + && ((i_cmds[i - 1] == 'y') || (i_cmds[i-1] == 'Y')); + ps->initial_cmds[i] = ps->initial_cmds_backup[i] = 0; ps->in_init_seq = ps->save_in_init_seq = 1; } } @@ -3139,6 +3172,9 @@ goodnight_gracey(struct pine *pine_state, int exit_val) extern KBESC_T *kbesc; dprint((2, "goodnight_gracey:\n")); + strncpy(pine_state->cur_folder, pine_state->inbox_name, + sizeof(pine_state->cur_folder)); + pine_state->cur_folder[sizeof(pine_state->cur_folder) - 1] = '\0'; /* We want to do this here before we close up the streams */ trim_remote_adrbks(); diff --git a/alpine/arg.c b/alpine/arg.c index e23853c4..315649ba 100644 --- a/alpine/arg.c +++ b/alpine/arg.c @@ -60,6 +60,7 @@ static char args_err_missing_passfile[] = N_("missing argument for option \"-pas static char args_err_non_abs_passfile[] = N_("argument to \"-passfile\" should be fully-qualified"); #endif static char args_err_missing_sort[] = N_("missing argument for option \"-sort\""); +static char args_err_missing_thread_sort[] = N_("missing argument for option \"-threadsort\""); static char args_err_missing_flag_arg[] = N_("missing argument for flag \"%c\""); static char args_err_missing_flag_num[] = N_("Non numeric argument for flag \"%c\""); static char args_err_missing_debug_num[] = N_("Non numeric argument for \"%s\""); @@ -103,11 +104,13 @@ N_(" -k \t\tKeys - Force use of function keys"), N_(" -z \t\tSuspend - allow use of ^Z suspension"), N_(" -r \t\tRestricted - can only send mail to oneself"), N_(" -sort <sort>\tSort - Specify sort order of folder:"), +N_(" -threadsort <sort>\tSort - Specify sort order of thread index screen:"), N_("\t\t\tarrival, subject, threaded, orderedsubject, date,"), N_("\t\t\tfrom, size, score, to, cc, /reverse"), N_(" -i\t\tIndex - Go directly to index, bypassing main menu"), N_(" -I <keystroke_list> Initial keystrokes to be executed"), N_(" -n <number>\tEntry in index to begin on"), +N_(" -noutf8\t Warns Alpine that piped input is not encoded in utf-8"), N_(" -o \t\tReadOnly - Open first folder read-only"), N_(" -conf\t\tConfiguration - Print out fresh global configuration. The"), N_("\t\tvalues of your global configuration affect all Alpine users"), @@ -192,6 +195,7 @@ pine_args(struct pine *pine_state, int argc, char **argv, ARGDATA_S *args) char *cmd_list = NULL; char *debug_str = NULL; char *sort = NULL; + char *threadsort = NULL; char *pinerc_file = NULL; char *lc = NULL; int do_help = 0; @@ -363,6 +367,17 @@ Loop: while(--ac > 0) goto Loop; } + else if(strcmp(*av, "threadsort") == 0){ + if(--ac){ + threadsort = *++av; + COM_THREAD_SORT_KEY = cpystr(threadsort); + } + else{ + display_args_err(_(args_err_missing_thread_sort), NULL, 1); + ++usage; + } + goto Loop; + } else if(strcmp(*av, "url") == 0){ if(args->action == aaFolder && !args->data.folder){ args->action = aaURL; @@ -469,6 +484,10 @@ Loop: while(--ac > 0) goto Loop; } + else if(strcmp(*av, "noutf8") == 0){ + args->noutf8++; + goto Loop; + } else if(strcmp(*av, "bail") == 0){ pine_state->exit_if_no_pinerc = 1; goto Loop; @@ -477,6 +496,12 @@ Loop: while(--ac > 0) do_version = 1; goto Loop; } + else if(strcmp(*av, "subject") == 0){ + if(--ac){ + pine_state->subject = cpystr(*++av); + } + goto Loop; + } #ifdef _WINDOWS else if(strcmp(*av, "install") == 0){ pine_state->install_flag = 1; @@ -827,14 +852,14 @@ Loop: while(--ac > 0) exit(-1); if(do_version){ - extern char datestamp[], hoststamp[]; + extern char datestamp[], hoststamp[], plevstamp[]; char rev[128]; - snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Alpine %s (%s %s) built %s on %s", + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Alpine %s (%s %s) built %s on %s, using patchlevel %s.", ALPINE_VERSION, SYSTYPE ? SYSTYPE : "?", get_alpine_revision_string(rev, sizeof(rev)), - datestamp, hoststamp); + datestamp, hoststamp, plevstamp); tmp_20k_buf[SIZEOF_20KBUF-1] = '\0'; display_args_err(tmp_20k_buf, NULL, 0); exit(0); diff --git a/alpine/arg.h b/alpine/arg.h index 339e793b..4faddfe9 100644 --- a/alpine/arg.h +++ b/alpine/arg.h @@ -27,6 +27,7 @@ typedef struct argdata { enum {aaFolder = 0, aaMore, aaURL, aaMail, aaPrcCopy, aaAbookCopy} action; + int noutf8; union { char *folder; char *file; diff --git a/alpine/busy.c b/alpine/busy.c index a0c71ab0..b2fd1869 100644 --- a/alpine/busy.c +++ b/alpine/busy.c @@ -226,7 +226,7 @@ busy_cue(char *msg, percent_done_t pc_f, int delay) add_review_message(buf, -1); } - else{ + else if (!ps_global->send_immediately){ q_status_message(SM_ORDER, 0, 1, progress); /* @@ -238,8 +238,8 @@ busy_cue(char *msg, percent_done_t pc_f, int delay) */ display_message('x'); } - - fflush(stdout); + if (!ps_global->send_immediately) + fflush(stdout); } /* @@ -287,7 +287,8 @@ busy_cue(char *msg, percent_done_t pc_f, int delay) (*ap)->cf = done_busy_cue; ap = &(*ap)->next; - start_after(a); /* launch cue handler */ + if(!ps_global->send_immediately) + start_after(a); /* launch cue handler */ #ifdef _WINDOWS mswin_setcursor(MSWIN_CURSOR_BUSY); @@ -436,6 +437,11 @@ done_busy_cue(void *data) { int space_left, slots_used; + if (ps_global->send_immediately){ + mark_status_dirty(); + return; + } + if(final_message && final_message_pri >= 0){ char progress[MAX_SCREEN_COLS+1]; diff --git a/alpine/confscroll.c b/alpine/confscroll.c index b4aa3218..11473d27 100644 --- a/alpine/confscroll.c +++ b/alpine/confscroll.c @@ -51,6 +51,7 @@ static char rcsid[] = "$Id: confscroll.c 1169 2008-08-27 06:42:06Z hubert@u.wash #include "../pith/tempfile.h" #include "../pith/pattern.h" #include "../pith/charconv/utf8.h" +#include "../pith/rules.h" #define CONFIG_SCREEN_HELP_TITLE _("HELP FOR SETUP CONFIGURATION") @@ -139,7 +140,7 @@ char *yesno_pretty_value(struct pine *, CONF_S *); char *radio_pretty_value(struct pine *, CONF_S *); char *sigfile_pretty_value(struct pine *, CONF_S *); char *color_pretty_value(struct pine *, CONF_S *); -char *sort_pretty_value(struct pine *, CONF_S *); +char *sort_pretty_value(struct pine *, CONF_S *, int); int longest_feature_name(void); COLOR_PAIR *sample_color(struct pine *, struct variable *); COLOR_PAIR *sampleexc_color(struct pine *, struct variable *); @@ -287,7 +288,8 @@ set_radio_pretty_vals(struct pine *ps, CONF_S **cl) CONF_S *ctmp; if(!(cl && *cl && - ((*cl)->var == &ps->vars[V_SORT_KEY] || + (((*cl)->var == &ps->vars[V_SORT_KEY]) || + ((*cl)->var == &ps->vars[V_THREAD_SORT_KEY]) || standard_radio_var(ps, (*cl)->var) || (*cl)->var == startup_ptr))) return; @@ -463,7 +465,7 @@ conf_scroll_screen(struct pine *ps, OPT_SCREEN_S *screen, CONF_S *start_line, ch char tmp[MAXPATH+1]; char *utf8str; UCS ch = 'x'; - int cmd, i, j, done = 0, changes = 0; + int cmd, i, j, k = 1, done = 0, changes = 0; int retval = 0; int km_popped = 0, stay_in_col = 0; struct key_menu *km = NULL; @@ -512,6 +514,7 @@ conf_scroll_screen(struct pine *ps, OPT_SCREEN_S *screen, CONF_S *start_line, ch } /*----------- Check for new mail -----------*/ + if (!ps->send_immediately){ if(new_mail(0, NM_TIMING(ch), NM_STATUS_MSG | NM_DEFER_SORT) >= 0) ps->mangled_header = 1; @@ -541,6 +544,7 @@ conf_scroll_screen(struct pine *ps, OPT_SCREEN_S *screen, CONF_S *start_line, ch mark_status_unknown(); } + } /* send_immediately */ if(ps->mangled_footer || km != screen->current->keymenu){ bitmap_t bitmap; @@ -612,6 +616,7 @@ conf_scroll_screen(struct pine *ps, OPT_SCREEN_S *screen, CONF_S *start_line, ch } } + if(!ps_global->send_immediately){ MoveCursor(cursor_pos.row, cursor_pos.col); #ifdef MOUSE mouse_in_content(KEY_MOUSE, -1, -1, 0, 0); /* prime the handler */ @@ -630,6 +635,14 @@ conf_scroll_screen(struct pine *ps, OPT_SCREEN_S *screen, CONF_S *start_line, ch #ifdef _WINDOWS mswin_setscrollcallback(NULL); #endif + } /* send_immediately */ + + if (ps->send_immediately){ + ps_global->dont_use_init_cmds = 0; + process_config_input(&ch); + if (ch == '\030') /* ^X, bye */ + goto end; + } cmd = menu_command(ch, km); @@ -1383,7 +1396,7 @@ no_down: break; } } - +end: screen->current = first_confline(screen->current); free_conflines(&screen->current); return(retval); @@ -1552,6 +1565,10 @@ text_toolit(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags, int look_ lowrange = 1; hirange = MAX_FILLCOL; } + else if((*cl)->var == &ps->vars[V_SLEEP]){ + lowrange = 0; + hirange = 120; + } else if((*cl)->var == &ps->vars[V_OVERLAP] || (*cl)->var == &ps->vars[V_MARGIN]){ lowrange = 0; @@ -2427,6 +2444,9 @@ delete: * Now go and set the current_val based on user_val changes * above. Turn off command line settings... */ + set_current_val((*cl)->var, + (strcmp((*cl)->var->name,"key-definition-rules") ? TRUE : FALSE), + FALSE); set_current_val((*cl)->var, TRUE, FALSE); fix_side_effects(ps, (*cl)->var, 0); @@ -2923,7 +2943,7 @@ radiobutton_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) } set_current_val((*cl)->var, TRUE, TRUE); - if(decode_sort(ps->VAR_SORT_KEY, &def_sort, &def_sort_rev) != -1){ + if(decode_sort(ps->VAR_SORT_KEY, &def_sort, &def_sort_rev,0) != -1){ ps->def_sort = def_sort; ps->def_sort_rev = def_sort_rev; } @@ -2932,6 +2952,37 @@ radiobutton_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) ps->mangled_body = 1; /* BUG: redraw it all for now? */ rv = 1; } + else if((*cl)->var == &ps->vars[V_THREAD_SORT_KEY]){ + SortOrder thread_def_sort; + int thread_def_sort_rev; + + thread_def_sort_rev = (*cl)->varmem >= (short) EndofList; + thread_def_sort = (SortOrder) ((*cl)->varmem - (thread_def_sort_rev + * EndofList)); + sprintf(tmp_20k_buf, "%s%s", sort_name(thread_def_sort), + (thread_def_sort_rev) ? "/Reverse" : ""); + + if((*cl)->var->cmdline_val.p) + fs_give((void **)&(*cl)->var->cmdline_val.p); + + if(apval){ + if(*apval) + fs_give((void **)apval); + + *apval = cpystr(tmp_20k_buf); + } + + set_current_val((*cl)->var, TRUE, TRUE); + if(decode_sort(ps->VAR_THREAD_SORT_KEY, &thread_def_sort, + &thread_def_sort_rev, 1) != -1){ + ps->thread_def_sort = thread_def_sort; + ps->thread_def_sort_rev = thread_def_sort_rev; + } + + set_radio_pretty_vals(ps, cl); + ps->mangled_body = 1; /* BUG: redraw it all for now? */ + rv = 1; + } else q_status_message(SM_ORDER | SM_DING, 3, 6, "Programmer botch! Unknown radiobutton type."); @@ -3794,7 +3845,9 @@ pretty_value(struct pine *ps, CONF_S *cl) else if(standard_radio_var(ps, v) || v == startup_ptr) return(radio_pretty_value(ps, cl)); else if(v == &ps->vars[V_SORT_KEY]) - return(sort_pretty_value(ps, cl)); + return(sort_pretty_value(ps, cl, 0)); + else if(v == &ps->vars[V_THREAD_SORT_KEY]) + return(sort_pretty_value(ps, cl, 1)); else if(v == &ps->vars[V_SIGNATURE_FILE]) return(sigfile_pretty_value(ps, cl)); else if(v == &ps->vars[V_USE_ONLY_DOMAIN_NAME]) @@ -4325,14 +4378,14 @@ color_pretty_value(struct pine *ps, CONF_S *cl) char * -sort_pretty_value(struct pine *ps, CONF_S *cl) +sort_pretty_value(struct pine *ps, CONF_S *cl, int thread) { - return(generalized_sort_pretty_value(ps, cl, 1)); + return(generalized_sort_pretty_value(ps, cl, 1, thread)); } char * -generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok) +generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok, int thread) { char tmp[6*MAXPATH]; char *pvalnorm, *pvalexc, *pval; @@ -4382,7 +4435,7 @@ generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok) } else if(fixed){ pval = v->fixed_val.p; - decode_sort(pval, &var_sort, &var_sort_rev); + decode_sort(pval, &var_sort, &var_sort_rev, thread); is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort); utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s", @@ -4393,9 +4446,9 @@ generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok) is_the_one ? " (value is fixed)" : ""); } else if(is_set_for_this_level){ - decode_sort(pval, &var_sort, &var_sort_rev); + decode_sort(pval, &var_sort, &var_sort_rev, thread); is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort); - decode_sort(pvalexc, &exc_sort, &exc_sort_rev); + decode_sort(pvalexc, &exc_sort, &exc_sort_rev, thread); the_exc_one = (editing_normal_which_isnt_except && pvalexc && exc_sort_rev == line_sort_rev && exc_sort == line_sort); utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s", @@ -4413,7 +4466,7 @@ generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok) } else{ if(pvalexc){ - decode_sort(pvalexc, &exc_sort, &exc_sort_rev); + decode_sort(pvalexc, &exc_sort, &exc_sort_rev, thread); is_the_one = (exc_sort_rev == line_sort_rev && exc_sort == line_sort); utf8_snprintf(tmp, sizeof(tmp), "( ) %s%-*w%*s%s", @@ -4424,7 +4477,7 @@ generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok) } else{ pval = v->current_val.p; - decode_sort(pval, &var_sort, &var_sort_rev); + decode_sort(pval, &var_sort, &var_sort_rev, thread); is_the_one = ((pval || default_ok) && var_sort_rev == line_sort_rev && var_sort == line_sort); @@ -5161,6 +5214,30 @@ fix_side_effects(struct pine *ps, struct variable *var, int revert) var == &ps->vars[V_ABOOK_FORMATS]){ addrbook_reset(); } + else if(var == &ps->vars[V_INDEX_RULES]){ + if(ps_global->rule_list) + free_parsed_rule_list(&ps_global->rule_list); + create_rule_list(ps->vars); + reset_index_format(); + clear_index_cache(ps->mail_stream, 0); + } + else if(var == &ps->vars[V_COMPOSE_RULES] || + var == &ps->vars[V_FORWARD_RULES] || + var == &ps->vars[V_KEY_RULES] || + var == &ps->vars[V_REPLACE_RULES] || + var == &ps->vars[V_REPLY_INDENT_RULES] || + var == &ps->vars[V_REPLY_LEADIN_RULES] || + var == &ps->vars[V_RESUB_RULES] || + var == &ps->vars[V_SAVE_RULES] || + var == &ps->vars[V_SMTP_RULES] || + var == &ps->vars[V_SORT_RULES] || + var == &ps->vars[V_STARTUP_RULES] || + var == &ps->vars[V_THREAD_DISP_STYLE_RULES] || + var == &ps->vars[V_THREAD_INDEX_STYLE_RULES]){ + if(ps_global->rule_list) + free_parsed_rule_list(&ps_global->rule_list); + create_rule_list(ps->vars); + } else if(var == &ps->vars[V_INDEX_FORMAT]){ reset_index_format(); clear_index_cache(ps->mail_stream, 0); @@ -5183,6 +5260,9 @@ fix_side_effects(struct pine *ps, struct variable *var, int revert) clear_index_cache(ps->mail_stream, 0); } + else if(var == &ps->vars[V_SPECIAL_TEXT]){ + regex_pattern(ps->VAR_SPECIAL_TEXT); + } else if(var == &ps->vars[V_INIT_CMD_LIST]){ if(!revert) q_status_message(SM_ASYNC, 0, 3, @@ -5215,6 +5295,16 @@ fix_side_effects(struct pine *ps, struct variable *var, int revert) else ps->viewer_overlap = old_value; } + else if(var == &ps->vars[V_SLEEP]){ + int old_value = ps->sleep; + + if(SVAR_SLEEP(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){ + if(!revert) + q_status_message(SM_ORDER, 3, 5, tmp_20k_buf); + } + else + ps->sleep = old_value; + } #ifdef SMIME else if(smime_related_var(ps, var)){ smime_deinit(); @@ -5496,6 +5586,12 @@ fix_side_effects(struct pine *ps, struct variable *var, int revert) (void *)var->current_val.p); } #endif +#ifndef _WINDOWS + else if(var == &ps->vars[V_MAILDIR_LOCATION]){ + if(var->current_val.p && var->current_val.p[0]) + mail_parameters(NULL, SET_MDINBOXPATH, (void *)var->current_val.p); + } +#endif else if(revert && standard_radio_var(ps, var)){ cur_rule_value(var, TRUE, FALSE); @@ -5545,9 +5641,15 @@ fix_side_effects(struct pine *ps, struct variable *var, int revert) else if(revert && var == &ps->vars[V_SORT_KEY]){ int def_sort_rev; - decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev); + decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev, 0); ps->def_sort_rev = def_sort_rev; } + else if(revert && var == &ps->vars[V_THREAD_SORT_KEY]){ + int thread_def_sort_rev; + + decode_sort(VAR_THREAD_SORT_KEY, &ps->thread_def_sort, &thread_def_sort_rev, 1); + ps->thread_def_sort_rev = thread_def_sort_rev; + } else if(var == &ps->vars[V_THREAD_MORE_CHAR] || var == &ps->vars[V_THREAD_EXP_CHAR] || var == &ps->vars[V_THREAD_LASTREPLY_CHAR]){ diff --git a/alpine/confscroll.h b/alpine/confscroll.h index 4315c8e1..95925cc2 100644 --- a/alpine/confscroll.h +++ b/alpine/confscroll.h @@ -95,7 +95,7 @@ int checkbox_tool(struct pine *, int, CONF_S **, unsigned); int radiobutton_tool(struct pine *, int, CONF_S **, unsigned); int yesno_tool(struct pine *, int, CONF_S **, unsigned); int text_toolit(struct pine *, int, CONF_S **, unsigned, int); -char *generalized_sort_pretty_value(struct pine *, CONF_S *, int); +char *generalized_sort_pretty_value(struct pine *, CONF_S *, int, int); int exclude_config_var(struct pine *, struct variable *, int); int config_exit_cmd(unsigned); int simple_exit_cmd(unsigned); diff --git a/alpine/dispfilt.c b/alpine/dispfilt.c index 7c93938b..7a386a1c 100644 --- a/alpine/dispfilt.c +++ b/alpine/dispfilt.c @@ -243,6 +243,19 @@ expand_filter_tokens(char *filter, ENVELOPE *env, char **tmpf, char **resultf, fs_give((void **)q); *q = rl ? rl : cpystr(""); } + else if(!strcmp(*q, "_ADDRESS_")){ + char *r = NULL; + + if(env && env->from && env->from->mailbox && env->from->host){ + size_t l; + l = strlen(env->from->mailbox) + strlen(env->from->host) + 1; + r = (char *) fs_get((l+1) * sizeof(char)); + snprintf(r, l+1, "%s@%s", env->from->mailbox, env->from->host); + } + + fs_give((void **)q); + *q = r ? r : cpystr(""); + } else if(!strcmp(*q, "_TMPFILE_")){ if(!tfn){ tfn = temp_nam(NULL, "sf"); /* send filter file */ @@ -461,3 +474,63 @@ df_valid_test(struct mail_bodystruct *body, char *test) return(passed); } + +char * +exec_function_rule(char *rawcmd, gf_io_t input_gc, gf_io_t output_pc) +{ + char *status = NULL, *cmd, *tmpfile = NULL; + + if((cmd = expand_filter_tokens(rawcmd,NULL,&tmpfile,NULL,NULL,NULL,NULL, NULL)) != NULL){ + suspend_busy_cue(); + ps_global->mangled_screen = 1; + if(tmpfile){ + PIPE_S *filter_pipe; + FILE *fp; + gf_io_t gc, pc; + STORE_S *tmpf_so; + + /* write the tmp file */ + if((tmpf_so = so_get(FileStar, tmpfile, WRITE_ACCESS|OWNER_ONLY|WRITE_TO_LOCALE)) != NULL){ + /* copy input to tmp file */ + gf_set_so_writec(&pc, tmpf_so); + gf_filter_init(); + status = gf_pipe(input_gc, pc); + gf_clear_so_writec(tmpf_so); + if(so_give(&tmpf_so) != 0 && status == NULL) + status = error_description(errno); + + /* prepare the terminal in case the filter uses it */ + if(status == NULL){ + if((filter_pipe = open_system_pipe(cmd, NULL, NULL, + PIPE_USER|PIPE_PROT|PIPE_NOSHELL|PIPE_SILENT, + 0, pipe_callback, NULL)) != NULL){ + if(close_system_pipe(&filter_pipe, NULL, pipe_callback) == 0){ + /* pull result out of tmp file */ + if((fp = our_fopen(tmpfile, "rb")) != NULL){ + gf_set_readc(&gc, fp, 0L, FileStar, READ_FROM_LOCALE); + gf_filter_init(); + status = gf_pipe(gc, output_pc); + fclose(fp); + } + else + status = "Can't read result of EXEC command"; + } + else + status = "EXEC command command returned error."; + } + else + status = "Can't open pipe for EXEC command"; + } + + our_unlink(tmpfile); + } + else + status = "Can't open EXEC command tmp file"; + } + + resume_busy_cue(0); + fs_give((void **)&cmd); + } + + return(status); +} diff --git a/alpine/dispfilt.h b/alpine/dispfilt.h index 0b42010d..a890b19c 100644 --- a/alpine/dispfilt.h +++ b/alpine/dispfilt.h @@ -24,7 +24,7 @@ char *dfilter_trigger(BODY *, char *, size_t); char *expand_filter_tokens(char *, ENVELOPE *, char **, char **, char **, int *, int *, int *); char *filter_session_key(void); char *filter_data_file(int); - +char *exec_function_rule(char *, gf_io_t, gf_io_t); #endif /* PINE_DISPFILT_INCLUDED */ diff --git a/alpine/folder.c b/alpine/folder.c index 31d2031e..59589011 100644 --- a/alpine/folder.c +++ b/alpine/folder.c @@ -247,7 +247,7 @@ folder_screen(struct pine *ps) dprint((1, "=== folder_screen called ====\n")); mailcap_free(); /* free resources we won't be using for a while */ ps->next_screen = SCREEN_FUN_NULL; - + strcpy(ps->screen_name, "folder"); /* Initialize folder state and dispatches */ memset(&fs, 0, sizeof(FSTATE_S)); fs.context = cntxt; @@ -344,6 +344,7 @@ folder_screen(struct pine *ps) pine_mail_close(*fs.cache_streamp); ps->prev_screen = folder_screen; + strcpy(ps->screen_name, "unknown"); } @@ -6342,11 +6343,17 @@ folder_delimiter(char *folder) char * next_folder(MAILSTREAM **streamp, char *next, size_t nextlen, char *current, CONTEXT_S *cntxt, long int *find_recent, int *did_cancel) { - int index, recent = 0, failed_status = 0, try_fast; + int index, recent = 0, failed_status = 0, try_fast, done = 0; char prompt[128]; FOLDER_S *f = NULL; char tmp[MAILTMPLEN]; - + char *test_current = cpystr(current); + int cur_indx = folder_index(ps_global->cur_folder, cntxt, FI_FOLDER); + int loop = !strcmp(next, ps_global->cur_folder) ? 0 : + (folder_index(test_current, cntxt, FI_FOLDER) <= cur_indx + ? 1 : 0); + int last = !strcmp(ps_global->cur_folder, ps_global->inbox_name) + ? 1 : cur_indx; /* note: find_folders may assign "stream" */ build_folder_list(streamp, cntxt, NULL, NULL, @@ -6357,7 +6364,9 @@ next_folder(MAILSTREAM **streamp, char *next, size_t nextlen, char *current, CON if(find_recent) *find_recent = 0L; - for(index = folder_index(current, cntxt, FI_FOLDER) + 1; + +find_new_message: + for(index = folder_index(test_current, cntxt, FI_FOLDER) + 1; index > 0 && index < folder_total(FOLDERS(cntxt)) && (f = folder_entry(index, FOLDERS(cntxt))) @@ -6368,6 +6377,11 @@ next_folder(MAILSTREAM **streamp, char *next, size_t nextlen, char *current, CON int rv, we_cancel = 0, match; char msg_buf[MAX_BM+1]; + if (loop && (index == last)){ + done++; + break; + } + /* must be a folder and it can't be the current one */ if(ps_global->context_current == ps_global->context_list && !strcmp(ps_global->cur_folder, FLDR_NAME(f))) @@ -6535,12 +6549,24 @@ next_folder(MAILSTREAM **streamp, char *next, size_t nextlen, char *current, CON if(f && (!find_recent || recent)){ strncpy(next, FLDR_NAME(f), nextlen); next[nextlen-1] = '\0'; + done++; } else if(nextlen > 0) *next = '\0'; + if (!done && F_ON(F_AUTO_CIRCULAR_TAB,ps_global) + && strcmp(test_current,ps_global->inbox_name)){ + done++; loop++; + if (test_current) + fs_give((void **)&test_current); + test_current = cpystr(ps_global->inbox_name); + goto find_new_message; + } + /* BUG: how can this be made smarter so we cache the list? */ free_folder_list(cntxt); + if (test_current) + fs_give((void **)&test_current); return((*next) ? next : NULL); } diff --git a/alpine/imap.c b/alpine/imap.c index 074b9f6d..e43d3e2e 100644 --- a/alpine/imap.c +++ b/alpine/imap.c @@ -2040,6 +2040,83 @@ passfile_name(char *pinerc, char *path, size_t len) #endif /* PASSFILE */ +void +pine_delete_pwd(NETMBX *mb, char *user) +{ + char hostlist0[MAILTMPLEN], hostlist1[MAILTMPLEN]; + char port[20], non_def_port[20], insecure[20]; + STRLIST_S hostlist[2]; + MMLOGIN_S *l; + struct servent *sv; + + + dprint((9, "pine_delete_pwd\n")); + + /* do not invalidate password on cancel */ + if(ps_global->user_says_cancel != 0) + return; + + /* setup hostlist */ + non_def_port[0] = '\0'; + if(mb->port && mb->service && + (sv = getservbyname(mb->service, "tcp")) && + (mb->port != ntohs(sv->s_port))){ + snprintf(non_def_port, sizeof(non_def_port), ":%lu", mb->port); + non_def_port[sizeof(non_def_port)-1] = '\0'; + dprint((9, "mm_login: using non-default port=%s\n", + non_def_port ? non_def_port : "?")); + } + + if(*non_def_port){ + strncpy(hostlist0, mb->host, sizeof(hostlist0)-1); + hostlist0[sizeof(hostlist0)-1] = '\0'; + strncat(hostlist0, non_def_port, sizeof(hostlist0)-strlen(hostlist0)-1); + hostlist0[sizeof(hostlist0)-1] = '\0'; + hostlist[0].name = hostlist0; + if(mb->orighost && mb->orighost[0] && strucmp(mb->host, mb->orighost)){ + strncpy(hostlist1, mb->orighost, sizeof(hostlist1)-1); + hostlist1[sizeof(hostlist1)-1] = '\0'; + strncat(hostlist1, non_def_port, sizeof(hostlist1)-strlen(hostlist1)-1); + hostlist1[sizeof(hostlist1)-1] = '\0'; + hostlist[0].next = &hostlist[1]; + hostlist[1].name = hostlist1; + hostlist[1].next = NULL; + } + else + hostlist[0].next = NULL; + } + else{ + hostlist[0].name = mb->host; + if(mb->orighost && mb->orighost[0] && strucmp(mb->host, mb->orighost)){ + hostlist[0].next = &hostlist[1]; + hostlist[1].name = mb->orighost; + hostlist[1].next = NULL; + } + else + hostlist[0].next = NULL; + } + + /* delete it from all lists */ + + for(l = mm_login_list; l; l = l->next) + if(imap_same_host(l->hosts, hostlist) + && !strcmp(l->user, user ? user : "") + && l->passwd){ + l->invalidpwd = 1; + break; + } + +#ifdef LOCAL_PASSWD_CACHE + for(l = passfile_cache; l; l = l->next) + if(imap_same_host(l->hosts, hostlist) + && !strcmp(l->user, user ? user : "") + && l->passwd){ + l->invalidpwd = 1; + break; + } + write_passfile(ps_global->pinerc, passfile_cache); /* blast it from passfile */ +#endif +} #ifdef LOCAL_PASSWD_CACHE @@ -2602,6 +2679,8 @@ write_passfile(pinerc, l) #endif /* SMIME */ for(n = 0; l; l = l->next, n++){ + if(l->invalidpwd == 1) /* if password is invalid, do not save it */ + continue; /*** do any necessary ENcryption here ***/ snprintf(tmp, sizeof(tmp), "%s\t%s\t%s\t%d%s%s\n", l->passwd, l->user, l->hosts->name, l->altflag, diff --git a/alpine/imap.h b/alpine/imap.h index b254fb53..378e687a 100644 --- a/alpine/imap.h +++ b/alpine/imap.h @@ -31,7 +31,8 @@ char *pine_newsrcquery(MAILSTREAM *, char *, char *); int url_local_certdetails(char *); void pine_sslfailure(char *, char *, unsigned long); void mm_expunged_current(long unsigned int); - +void pine_delete_pwd(NETMBX *mb, char *user); + #ifdef LOCAL_PASSWD_CACHE int get_passfile_passwd(char *, char *, char *, STRLIST_S *, int); int is_using_passfile(); diff --git a/alpine/keymenu.c b/alpine/keymenu.c index 195ae73c..a37304f9 100644 --- a/alpine/keymenu.c +++ b/alpine/keymenu.c @@ -650,10 +650,25 @@ struct key index_keys[] = RCOMPOSE_MENU, HOMEKEY_MENU, ENDKEY_MENU, - NULL_MENU, + {"K","Sort Thread",{MC_SORTHREAD,1,{'k'}},KS_NONE}, /* TRANSLATORS: toggles a collapsed view or an expanded view of a message thread on and off */ {"/",N_("Collapse/Expand"),{MC_COLLAPSE,1,{'/'}},KS_NONE}, + /* TRANSLATORS: Collapse all threads */ + {"{",N_("Collapse All"),{MC_KOLAPSE,1,{'{'}},KS_NONE}, + /* TRANSLATORS: Expand all threads */ + {"}",N_("Expand All"), {MC_EXPTHREAD,1,{'}'}},KS_NONE}, + + HELP_MENU, + OTHER_MENU, + {")","Next Threa",{MC_NEXTHREAD,1,{')'}},KS_NONE}, + {"(","Prev Threa",{MC_PRETHREAD,1,{'('}},KS_NONE}, + {"^R","Remove Thr",{MC_DELTHREAD,1,{ctrl('r')}},KS_NONE}, + {"^U","Undel Thre",{MC_UNDTHREAD,1,{ctrl('u')}},KS_NONE}, + {"^T","Select Thr",{MC_SELTHREAD,1,{ctrl('t')}},KS_NONE}, + NULL_MENU, + {"[","Close Thre",{MC_CTHREAD,1,{'['}},KS_NONE}, + {"]","Open Threa",{MC_OTHREAD,1,{']'}},KS_NONE}, {"@", N_("Quota"), {MC_QUOTA,1,{'@'}}, KS_NONE}, NULL_MENU}; INST_KEY_MENU(index_keymenu, index_keys); @@ -728,9 +743,22 @@ struct key thread_keys[] = RCOMPOSE_MENU, HOMEKEY_MENU, ENDKEY_MENU, - NULL_MENU, + {"]",N_("Open Thread"),{MC_OTHREAD,1,{']'}},KS_NONE}, {"/",N_("Collapse/Expand"),{MC_COLLAPSE,1,{'/'}},KS_NONE}, + {")",N_("Next Thread"),{MC_NEXTHREAD,1,{')'}},KS_NONE}, + {"(",N_("Prev Thread"),{MC_PRETHREAD,1,{'('}},KS_NONE}, + + HELP_MENU, + OTHER_MENU, {"@", N_("Quota"), {MC_QUOTA,1,{'@'}}, KS_NONE}, + NULL_MENU, + {"^R",N_("Remove Thread"),{MC_DELTHREAD,1,{ctrl('r')}},KS_NONE}, + {"^U",N_("Undelete Thread"),{MC_UNDTHREAD,1,{ctrl('u')}},KS_NONE}, + {"^T",N_("SelecT Thread"),{MC_SELTHREAD,1,{ctrl('t')}},KS_NONE}, + NULL_MENU, + NULL_MENU, + NULL_MENU, + {"K","Sort Thread",{MC_SORTHREAD,1,{'k'}},KS_NONE}, NULL_MENU}; INST_KEY_MENU(thread_keymenu, thread_keys); @@ -880,7 +908,20 @@ struct key view_keys[] = NULL_MENU, NULL_MENU, NULL_MENU, - NULL_MENU}; + NULL_MENU, + + HELP_MENU, + OTHER_MENU, + NULL_MENU, + NULL_MENU, + NULL_MENU, + NULL_MENU, + NULL_MENU, + {"(",N_("Prev Thread"),{MC_PRETHREAD,1,{'('}},KS_NONE}, + {")",N_("Next Thread"),{MC_NEXTHREAD,1,{')'}},KS_NONE}, + {"^R",N_("Remove Thread"),{MC_DELTHREAD,1,{ctrl('r')}},KS_NONE}, + {"^U",N_("Undelete Thread"),{MC_UNDTHREAD,1,{ctrl('u')}},KS_NONE}, + {"^T",N_("selecT Thread"),{MC_SELTHREAD,1,{ctrl('t')}},KS_NONE}}; INST_KEY_MENU(view_keymenu, view_keys); diff --git a/alpine/keymenu.h b/alpine/keymenu.h index 0e1f7618..84fc0422 100644 --- a/alpine/keymenu.h +++ b/alpine/keymenu.h @@ -215,6 +215,19 @@ struct key_menu { #define MC_DECRYPT 802 #define MC_QUOTA 803 #define MC_ADDHEADER 804 +#define MC_DELTHREAD 805 +#define MC_UNDTHREAD 806 +#define MC_SELTHREAD 807 +#define MC_SSUTHREAD 808 +#define MC_DSUTHREAD 809 +#define MC_USUTHREAD 810 +#define MC_SORTHREAD 811 +#define MC_NEXTHREAD 812 +#define MC_KOLAPSE 813 +#define MC_EXPTHREAD 814 +#define MC_PRETHREAD 815 +#define MC_CTHREAD 816 +#define MC_OTHREAD 817 /* * Some standard Key/Command Bindings diff --git a/alpine/mailcmd.c b/alpine/mailcmd.c index 7388005c..fc25795d 100644 --- a/alpine/mailcmd.c +++ b/alpine/mailcmd.c @@ -73,6 +73,7 @@ static char rcsid[] = "$Id: mailcmd.c 1266 2009-07-14 18:39:12Z hubert@u.washing #include "../pith/tempfile.h" #include "../pith/search.h" #include "../pith/margin.h" +#include "../pith/rules.h" #ifdef _WINDOWS #include "../pico/osdep/mswin.h" #endif @@ -113,7 +114,7 @@ int select_by_thread(MAILSTREAM *, MSGNO_S *, SEARCHSET **); char *choose_a_rule(int); int select_by_keyword(MAILSTREAM *, SEARCHSET **); char *choose_a_keyword(void); -int select_sort(struct pine *, int, SortOrder *, int *); +int select_sort(struct pine *, int, SortOrder *, int *, int); int print_index(struct pine *, MSGNO_S *, int); @@ -974,7 +975,7 @@ nfolder: state->context_current, &recent_cnt, F_ON(F_TAB_NO_CONFIRM,state) ? NULL : &did_cancel))){ - if(!in_inbox){ + if(!in_inbox && F_OFF(F_AUTO_CIRCULAR_TAB,state)){ static ESCKEY_S inbox_opt[] = { {'y', 'y', "Y", N_("Yes")}, {'n', 'n', "N", N_("No")}, @@ -1335,7 +1336,7 @@ get_out: if(any_messages(msgmap, NULL, NULL)){ if(any_lflagged(msgmap, MN_SLCT) > 0L){ if(apply_command(state, stream, msgmap, 0, - AC_NONE, question_line)){ + AC_NONE, question_line, 1)){ if(F_ON(F_AUTO_UNSELECT, state)){ agg_select_all(stream, msgmap, NULL, 0); unzoom_index(state, stream, msgmap); @@ -1353,23 +1354,35 @@ get_out: /*-------- Sort command -------*/ case MC_SORT : + case MC_SORTHREAD: { int were_threading = THREADING(); SortOrder sort = mn_get_sort(msgmap); int rev = mn_get_revsort(msgmap); + int thread = (command == MC_SORT) ? 0 : 1; dprint((1,"MAIL_CMD: sort\n")); - if(select_sort(state, question_line, &sort, &rev)){ + if(sort == SortThread) + sort = ps_global->thread_cur_sort; + if(select_sort(state, question_line, &sort, &rev, thread)){ /* $ command reinitializes threading collapsed/expanded info */ if(SORT_IS_THREADED(msgmap) && !SEP_THRDINDX()) erase_threading_info(stream, msgmap); + if(command == MC_SORTHREAD){ + ps_global->thread_cur_sort = sort; + sort = SortThread; + } + else if(sort == SortThread) /* command = MC_SORT */ + ps_global->thread_cur_sort = F_ON(F_THREAD_SORTS_BY_ARRIVAL, ps_global) + ? SortArrival : ps_global->thread_def_sort; + if(ps_global && ps_global->ttyo){ blank_keymenu(ps_global->ttyo->screen_rows - 2, 0); ps_global->mangled_footer = 1; } - sort_folder(stream, msgmap, sort, rev, SRT_VRB|SRT_MAN); + sort_folder(stream, msgmap, sort, rev, SRT_VRB|SRT_MAN, 1); } state->mangled_footer = 1; @@ -2594,6 +2607,9 @@ role_compose(struct pine *state) role->nick = cpystr("Default Role"); } + if(state->role) + fs_give((void **)&state->role); + state->role = cpystr(role->nick); /* remember the role */ state->redrawer = NULL; switch(action){ case 'c': @@ -2644,12 +2660,12 @@ save_prompt(struct pine *state, CONTEXT_S **cntxt, char *nfldr, size_t len_nfldr char *nmsgs, ENVELOPE *env, long int rawmsgno, char *section, SaveDel *dela, SavePreserveOrder *prea) { - int rc, ku = -1, n, flags, last_rc = 0, saveable_count = 0, done = 0; + int rc, ku = -1, n = 0, flags, last_rc = 0, saveable_count = 0, done = 0; int delindex, preindex, r; char prompt[6*MAX_SCREEN_COLS+1], *p, expanded[MAILTMPLEN]; char *buf = tmp_20k_buf; char shortbuf[200]; - char *folder; + char *folder, folder2[MAXPATH]; HelpType help; SaveDel del = DontAsk; SavePreserveOrder pre = DontAskPreserve; @@ -2657,6 +2673,7 @@ save_prompt(struct pine *state, CONTEXT_S **cntxt, char *nfldr, size_t len_nfldr static HISTORY_S *history = NULL; CONTEXT_S *tc; ESCKEY_S ekey[10]; + RULE_RESULT *rule; if(!cntxt) panic("no context ptr in save_prompt"); @@ -2666,6 +2683,15 @@ save_prompt(struct pine *state, CONTEXT_S **cntxt, char *nfldr, size_t len_nfldr if(!(folder = save_get_default(state, env, rawmsgno, section, cntxt))) return(0); /* message expunged! */ + if (rule = get_result_rule(V_SAVE_RULES, FOR_SAVE, env)){ + strncpy(folder2,rule->result,sizeof(folder2)-1); + folder2[sizeof(folder2)-1] = '\0'; + folder = folder2; + if (rule->result) + fs_give((void **)&rule->result); + fs_give((void **)&rule); + } + /* how many context's can be saved to... */ for(tc = state->context_list; tc; tc = tc->next) if(!NEWS_TEST(tc)) @@ -3174,6 +3200,10 @@ cmd_expunge(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap) if(SORT_IS_THREADED(msgmap)) refresh_sort(stream, msgmap, SRT_NON); + if (msgmap->nmsgs + && F_ON(F_ENHANCED_THREAD, state) && COLL_THRDS()) + kolapse_thread(state, stream, msgmap, '[', 0); + state->mangled_body = 1; state->mangled_header = 1; q_status_message2(SM_ORDER, 0, 4, @@ -3268,6 +3298,9 @@ cmd_expunge(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap) */ if(SORT_IS_THREADED(msgmap)) refresh_sort(stream, msgmap, SRT_NON); + if (msgmap->nmsgs + && F_ON(F_ENHANCED_THREAD, state) && COLL_THRDS()) + kolapse_thread(state, stream, msgmap, '[', 0); } else{ if(del_count) @@ -3349,6 +3382,9 @@ save_size_changed_prompt(long msgno, int flags) {-1, 0, NULL, NULL} }; + if(F_ON(F_IGNORE_SIZE, ps_global)) + return 'y'; + if(flags & SSCP_INIT || flags & SSCP_END){ if(flags & SSCP_END && possible_corruption) q_status_message(SM_ORDER, 3, 3, "There is possible data corruption, check the results"); @@ -6945,7 +6981,7 @@ select_by_current(struct pine *state, MSGNO_S *msgmap, CmdWhere in_index) * Maybe it makes sense to zoom after a select but not after a colon * command even though they are very similar. */ - thread_command(state, state->mail_stream, msgmap, ':', -FOOTER_ROWS(state)); + thread_command(state, state->mail_stream, msgmap, ':', -FOOTER_ROWS(state), 1); } else{ if((all_selected = @@ -7001,7 +7037,7 @@ select_by_current(struct pine *state, MSGNO_S *msgmap, CmdWhere in_index) ----*/ int apply_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, - UCS preloadkeystroke, int flags, int q_line) + UCS preloadkeystroke, int flags, int q_line, int display) { int i = 8, /* number of static entries in sel_opts3 */ rv = 0, @@ -7153,9 +7189,19 @@ apply_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, collapse_or_expand(state, stream, msgmap, F_ON(F_SLASH_COLL_ENTIRE, ps_global) ? 0L - : mn_get_cur(msgmap)); + : mn_get_cur(msgmap), + display); break; + case '[' : + collapse_this_thread(state, stream, msgmap, display, 0); + break; + + case ']' : + expand_this_thread(state, stream, msgmap, display, 0); + break; + + case ':' : select_thread_stmp(state, stream, msgmap); break; @@ -7189,7 +7235,7 @@ apply_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, int select_by_number(MAILSTREAM *stream, MSGNO_S *msgmap, SEARCHSET **limitsrch) { - int r, end; + int r, end, cur; long n1, n2, raw; char number1[16], number2[16], numbers[80], *p, *t; HelpType help; @@ -7236,7 +7282,7 @@ select_by_number(MAILSTREAM *stream, MSGNO_S *msgmap, SEARCHSET **limitsrch) *t = '\0'; - end = 0; + end = cur = 0; if(number1[0] == '\0'){ if(*p == '-'){ q_status_message1(SM_ORDER | SM_DING, 0, 2, @@ -7248,6 +7294,14 @@ select_by_number(MAILSTREAM *stream, MSGNO_S *msgmap, SEARCHSET **limitsrch) end = 1; p += strlen("end"); } + else if(!strucmp(p, "$")){ + end = 1; + p++; + } + else if(!struncmp(p, ".",1)){ + cur = 1; + p++; + } else{ q_status_message1(SM_ORDER | SM_DING, 0, 2, _("Invalid message number: %s"), numbers); @@ -7257,6 +7311,8 @@ select_by_number(MAILSTREAM *stream, MSGNO_S *msgmap, SEARCHSET **limitsrch) if(end) n1 = mn_get_total(msgmap); + else if(cur) + n1 = mn_get_cur(msgmap); else if((n1 = atol(number1)) < 1L || n1 > mn_get_total(msgmap)){ q_status_message1(SM_ORDER | SM_DING, 0, 2, _("\"%s\" out of message number range"), @@ -7271,12 +7327,20 @@ select_by_number(MAILSTREAM *stream, MSGNO_S *msgmap, SEARCHSET **limitsrch) *t = '\0'; - end = 0; + end = cur = 0; if(number2[0] == '\0'){ if(!strucmp("end", p)){ end = 1; p += strlen("end"); } + else if(!strucmp(p, "$")){ + end = 1; + p++; + } + else if(!struncmp(p, ".",1)){ + cur = 1; + p++; + } else{ q_status_message1(SM_ORDER | SM_DING, 0, 2, _("Invalid number range, missing number after \"-\": %s"), @@ -7287,6 +7351,8 @@ select_by_number(MAILSTREAM *stream, MSGNO_S *msgmap, SEARCHSET **limitsrch) if(end) n2 = mn_get_total(msgmap); + else if(cur) + n2 = mn_get_cur(msgmap); else if((n2 = atol(number2)) < 1L || n2 > mn_get_total(msgmap)){ q_status_message1(SM_ORDER | SM_DING, 0, 2, _("\"%s\" out of message number range"), @@ -9014,10 +9080,10 @@ Args: state -- pine state pointer Returns 0 if it was cancelled, 1 otherwise. ----*/ int -select_sort(struct pine *state, int ql, SortOrder *sort, int *rev) +select_sort(struct pine *state, int ql, SortOrder *sort, int *rev, int thread) { char prompt[200], tmp[3], *p; - int s, i; + int s, i, j; int deefault = 'a', retval = 1; HelpType help; ESCKEY_S sorts[14]; @@ -9050,17 +9116,26 @@ select_sort(struct pine *state, int ql, SortOrder *sort, int *rev) strncpy(prompt, _("Choose type of sort, or 'R' to reverse current sort : "), sizeof(prompt)); - for(i = 0; state->sort_types[i] != EndofList; i++) { - sorts[i].rval = i; - p = sorts[i].label = sort_name(state->sort_types[i]); - while(*(p+1) && islower((unsigned char)*p)) - p++; - - sorts[i].ch = tolower((unsigned char)(tmp[0] = *p)); - sorts[i].name = cpystr(tmp); - - if(mn_get_sort(state->msgmap) == state->sort_types[i]) - deefault = sorts[i].rval; + for(i = 0, j = 0; state->sort_types[i] != EndofList; i++) { + sorts[i].rval = i; + sorts[i].name = cpystr(""); + sorts[i].label = ""; + sorts[i].ch = -2; + if (!thread || allowed_thread_key(state->sort_types[i])){ + p = sorts[j].label = sort_name(state->sort_types[i]); + while(*(p+1) && islower((unsigned char)*p)) + p++; + sorts[j].ch = tolower((unsigned char)(tmp[0] = *p)); + sorts[j++].name = cpystr(tmp); + } + + if (thread){ + if (state->thread_def_sort == state->sort_types[i]) + deefault = sorts[j-1].rval; + } + else + if(mn_get_sort(state->msgmap) == state->sort_types[i]) + deefault = sorts[i].rval; } sorts[i].ch = 'r'; @@ -9084,8 +9159,17 @@ select_sort(struct pine *state, int ql, SortOrder *sort, int *rev) state->mangled_body = 1; /* signal screen's changed */ if(s == 'r') *rev = !mn_get_revsort(state->msgmap); - else + else{ + if(thread){ + for(i = 0; state->sort_types[i] != EndofList; i++){ + if(struncmp(sort_name(state->sort_types[i]), + sorts[s].label, strlen(sorts[s].label)) == 0) + break; + } + s = i; + } *sort = state->sort_types[s]; + } if(F_ON(F_SHOW_SORT, ps_global)) ps_global->mangled_header = 1; @@ -9470,3 +9554,378 @@ flag_submenu(mc) } #endif /* _WINDOWS */ + +void +cmd_delete_this_thread(state, stream, msgmap) + struct pine *state; + MAILSTREAM *stream; + MSGNO_S *msgmap; +{ + unsigned long rawno, top, save_kolapsed; + PINETHRD_S *thrd = NULL, *nxthrd; + + if(!stream) + return; + + rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + move_top_this_thread(stream, msgmap, rawno); + top = mn_m2raw(msgmap, mn_get_cur(msgmap)); + if(top) + thrd = fetch_thread(stream, top); + + if(!thrd) + return; + + save_kolapsed = this_thread_is_kolapsed(state, stream, msgmap, top); + collapse_this_thread(state, stream, msgmap, 0, 0); + thread_command(state, stream, msgmap, 'd', -FOOTER_ROWS(state), 1); + if (!save_kolapsed) + expand_this_thread(state, stream, msgmap, 0, 0); +} + +void +cmd_delete_thread(state, stream, msgmap) + struct pine *state; + MAILSTREAM *stream; + MSGNO_S *msgmap; +{ + unsigned long rawno, top, orig_top, topnxt, save_kolapsed; + PINETHRD_S *thrd = NULL, *nxthrd; + int done = 0, count; + + if(!stream) + return; + + rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + move_top_thread(stream, msgmap, rawno); + top = orig_top = mn_m2raw(msgmap, mn_get_cur(msgmap)); + if(top) + thrd = fetch_thread(stream, top); + + if(!thrd) + return; + + while (!done){ + cmd_delete_this_thread(state, stream, msgmap); + if (F_OFF(F_ENHANCED_THREAD, state) + || (move_next_this_thread(state, stream, msgmap, 0) <= 0) + || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap))) + || (orig_top != top_thread(stream, top))) + done++; + } + mn_set_cur(msgmap,mn_raw2m(msgmap, rawno)); + cmd_delete(state, msgmap, MCMD_NONE, cmd_delete_index); + count = count_thread(state, stream, msgmap, rawno); + q_status_message2(SM_ORDER, 0, 1, "%s message%s marked deleted", + int2string(count), plural(count)); +} + +int +collapse_this_thread(state, stream, msgmap, display, special) + struct pine *state; + MAILSTREAM *stream; + MSGNO_S *msgmap; + int display; + int special; +{ + int collapsed, rv = 1, done = 0; + PINETHRD_S *thrd = NULL, *nthrd; + unsigned long rawno, orig, msgno; + + if(!stream) + return 0; + + rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + + if(rawno) + thrd = fetch_thread(stream, rawno); + + if(!thrd) + return rv; + + collapsed = this_thread_is_kolapsed(state, stream, msgmap, rawno); + + if (special && collapsed){ + expand_this_thread(state, stream, msgmap, 0, 0); + collapsed = 0; + } + + clear_index_cache_ent(stream, rawno, 0); + + if (!collapsed && thrd->next){ + if (thrd->rawno == top_thread(stream, thrd->rawno)) + collapse_or_expand(state, stream, msgmap, mn_get_cur(msgmap), display); + else{ + set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno), MN_COLL, 1); + set_thread_subtree(stream, thrd, msgmap, 1, MN_CHID); + } + } + else{ + if (!collapsed && special + && ((F_OFF(F_ENHANCED_THREAD, state) && !thrd->next) + || F_ON(F_ENHANCED_THREAD, state))){ + if (thrd->toploose){ + if (thrd->rawno != thrd->toploose) + set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno),MN_CHID, + 1); + else + set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno),MN_COLL, + 1); + } + } + else{ + rv = 0; + if (display) + q_status_message(SM_ORDER, 0, 1, "Thread already collapsed"); + } + } + return rv; +} + +void +collapse_thread(state, stream, msgmap, display) + struct pine *state; + MAILSTREAM *stream; + MSGNO_S *msgmap; + int display; +{ + int collapsed, rv = 1, done = 0; + PINETHRD_S *thrd = NULL; + unsigned long orig, orig_top, top; + + if(!stream) + return; + + expand_this_thread(state, stream, msgmap, display, 1); + orig = mn_m2raw(msgmap, mn_get_cur(msgmap)); + move_top_thread(stream, msgmap,orig); + top = orig_top = mn_m2raw(msgmap, mn_get_cur(msgmap)); + + if(top) + thrd = fetch_thread(stream, top); + + if(!thrd) + return; + + while (!done){ + collapse_this_thread(state, stream, msgmap, display, 1); + if (F_OFF(F_ENHANCED_THREAD, state) + || (move_next_this_thread(state, stream, msgmap, 0) <= 0) + || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap))) + || (orig_top != top_thread(stream, top))) + done++; + } + mn_set_cur(msgmap,mn_raw2m(msgmap, orig_top)); +} + +int +expand_this_thread(state, stream, msgmap, display, special) + struct pine *state; + MAILSTREAM *stream; + MSGNO_S *msgmap; + int display; + int special; +{ + int collapsed, rv = 1, done = 0; + PINETHRD_S *thrd = NULL, *nthrd; + unsigned long rawno, orig, msgno; + + if(!stream) + return 0; + + orig = mn_m2raw(msgmap, mn_get_cur(msgmap)); + move_top_this_thread(stream, msgmap,orig); + rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + + if(rawno) + thrd = fetch_thread(stream, rawno); + + if(!thrd) + return rv; + + collapsed = this_thread_is_kolapsed(state, stream, msgmap, rawno); + + if (special && !collapsed){ + collapse_this_thread(state, stream, msgmap, 0, 0); + collapsed = 1; + } + + clear_index_cache_ent(stream, rawno, 0); + + if (collapsed && thrd->next){ + if (thrd->rawno == top_thread(stream, thrd->rawno)) + collapse_or_expand(state, stream, msgmap, mn_get_cur(msgmap), display); + else{ + set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno), MN_COLL, 0); + set_thread_subtree(stream, thrd, msgmap, 0, MN_CHID); + } + } + else{ + if (collapsed && special + && ((F_OFF(F_ENHANCED_THREAD, state) && !thrd->next) + || F_ON(F_ENHANCED_THREAD, state))){ + if (thrd->toploose) + if (thrd->rawno != thrd->toploose) + set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno),MN_CHID, 0); + else + set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno),MN_COLL, 0); + } + else{ + rv = 0; + if (display) + q_status_message(SM_ORDER, 0, 1, "Thread already expanded"); + } + } + return rv; +} + +void +expand_thread(state, stream, msgmap, display) + struct pine *state; + MAILSTREAM *stream; + MSGNO_S *msgmap; + int display; +{ + int collapsed, rv = 1, done = 0; + PINETHRD_S *thrd = NULL; + unsigned long orig, orig_top, top; + + if(!stream) + return; + + orig = mn_m2raw(msgmap, mn_get_cur(msgmap)); + top = orig_top = mn_m2raw(msgmap, mn_get_cur(msgmap)); + + if(top) + thrd = fetch_thread(stream, top); + + if(!thrd) + return; + + while (!done){ + expand_this_thread(state, stream, msgmap, display, 1); + if (F_OFF(F_ENHANCED_THREAD, state) + || (move_next_this_thread(state, stream, msgmap, 0) <= 0) + || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap))) + || (orig_top != top_thread(stream, top))) + done++; + } + mn_set_cur(msgmap,mn_raw2m(msgmap, orig_top)); +} + + +void +cmd_undelete_this_thread(state, stream, msgmap) + struct pine *state; + MAILSTREAM *stream; + MSGNO_S *msgmap; +{ + unsigned long rawno; + int save_kolapsed; + + rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + save_kolapsed = this_thread_is_kolapsed(state, stream, msgmap, rawno); + collapse_this_thread(state, stream, msgmap, 0, 0); + thread_command(state, stream, msgmap, 'u', -FOOTER_ROWS(state), 1); + if (!save_kolapsed) + expand_this_thread(state, stream, msgmap, 0, 0); +} + +void +cmd_undelete_thread(state, stream, msgmap) + struct pine *state; + MAILSTREAM *stream; + MSGNO_S *msgmap; +{ + PINETHRD_S *thrd = NULL; + unsigned long rawno, top, orig_top; + int done = 0, count; + + rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + move_top_thread(stream, msgmap, rawno); + top = orig_top = mn_m2raw(msgmap, mn_get_cur(msgmap)); + if(top) + thrd = fetch_thread(stream, top); + + if(!thrd) + return; + + while (!done){ + cmd_undelete_this_thread(state, stream, msgmap); + if (F_OFF(F_ENHANCED_THREAD, state) + || (move_next_this_thread(state, stream, msgmap, 0) <= 0) + || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap))) + || (orig_top != top_thread(stream, top))) + done++; + } + mn_set_cur(msgmap,mn_raw2m(msgmap, rawno)); + count = count_thread(state, stream, msgmap, rawno); + q_status_message2(SM_ORDER, 0, 1, "Deletion mark removed from %s message%s", + int2string(count), plural(count)); +} + +void +kolapse_thread(state, stream, msgmap, ch, display) + struct pine *state; + MAILSTREAM *stream; + MSGNO_S *msgmap; + char ch; + int display; +{ + PINETHRD_S *thrd = NULL; + unsigned long rawno; + int rv = 1, done = 0; + + if(!stream) + return; + + rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + if(rawno) + thrd = fetch_thread(stream, rawno); + + if(!thrd) + return; + + clear_index_cache(stream, 0); + mn_set_cur(msgmap,1); /* go to the first message */ + while (!done){ + if (ch == '[') + collapse_thread(state, stream, msgmap, display); + else + expand_thread(state, stream, msgmap, display); + if ((rv = move_next_thread(state, stream, msgmap, 0)) <= 0) + done++; + } + + if (rv < 0){ + if (display) + q_status_message(SM_ORDER, 0, 1, (ch == '[') + ? "Error while collapsing thread" + : "Error while expanding thread"); + } + else + if(display) + q_status_message(SM_ORDER, 0, 1, (ch == '[') + ? "All threads collapsed. Use \"}\" to expand them" + : "All threads expanded. Use \"{\" to collapse them"); + + mn_set_cur(msgmap,mn_raw2m(msgmap, top_thread(stream,rawno))); +} + +void +cmd_select_thread(state, stream, msgmap) + struct pine *state; + MAILSTREAM *stream; + MSGNO_S *msgmap; +{ + unsigned long rawno; + int save_kolapsed; + + rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + save_kolapsed = thread_is_kolapsed(state, stream, msgmap, rawno); + collapse_thread(state, stream, msgmap, 0); + thread_command(state, stream, msgmap, ':', -FOOTER_ROWS(state), 1); + if (!save_kolapsed) + expand_thread(state, stream, msgmap, 0); +} + diff --git a/alpine/mailcmd.h b/alpine/mailcmd.h index c86ef7cd..2be89e40 100644 --- a/alpine/mailcmd.h +++ b/alpine/mailcmd.h @@ -84,7 +84,7 @@ char *broach_folder(int, int, int *, CONTEXT_S **); int ask_mailbox_reopen(struct pine *, int *); void visit_folder(struct pine *, char *, CONTEXT_S *, MAILSTREAM *, unsigned long); int select_by_current(struct pine *, MSGNO_S *, CmdWhere); -int apply_command(struct pine *, MAILSTREAM *, MSGNO_S *, UCS, int, int); +int apply_command(struct pine *, MAILSTREAM *, MSGNO_S *, UCS, int, int, int); char **choose_list_of_keywords(void); char *choose_a_charset(int); char **choose_list_of_charsets(void); @@ -102,6 +102,15 @@ int any_selected_callback(int, long); int flag_callback(int, long); MPopup *flag_submenu(MESSAGECACHE *); #endif - +void cmd_delete_thread(struct pine *, MAILSTREAM *, MSGNO_S *); +void cmd_delete_this_thread(struct pine *, MAILSTREAM *, MSGNO_S *); +void cmd_undelete_this_thread(struct pine *, MAILSTREAM *, MSGNO_S *); +void cmd_undelete_thread(struct pine *, MAILSTREAM *, MSGNO_S *); +void cmd_select_thread(struct pine *, MAILSTREAM *, MSGNO_S *); +void kolapse_thread(struct pine *, MAILSTREAM *, MSGNO_S *, char, int); +void collapse_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int); +void expand_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int); +int collapse_this_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int, int); +int expand_this_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int, int); #endif /* PINE_MAILCMD_INCLUDED */ diff --git a/alpine/mailindx.c b/alpine/mailindx.c index 01e01558..263825d2 100644 --- a/alpine/mailindx.c +++ b/alpine/mailindx.c @@ -229,6 +229,8 @@ mail_index_screen(struct pine *state) state->prev_screen = mail_index_screen; state->next_screen = SCREEN_FUN_NULL; + setup_threading_display_style(); + if(THRD_AUTO_VIEW() && sp_viewing_a_thread(state->mail_stream) && state->view_skipped_index @@ -240,10 +242,14 @@ mail_index_screen(struct pine *state) adjust_cur_to_visible(state->mail_stream, state->msgmap); + strcpy(state->screen_name,"index"); + if(THRD_INDX()) thread_index_screen(state); else index_index_screen(state); + + strcpy(state->screen_name,"unknown"); } @@ -561,6 +567,7 @@ index_lister(struct pine *state, CONTEXT_S *cntxt, char *folder, MAILSTREAM *str /*---------- Scroll line up ----------*/ case MC_CHARUP : +previtem: (void) process_cmd(state, stream, msgmap, MC_PREVITEM, (style == MsgIndex || style == MultiMsgIndex @@ -578,6 +585,7 @@ index_lister(struct pine *state, CONTEXT_S *cntxt, char *folder, MAILSTREAM *str /*---------- Scroll line down ----------*/ case MC_CHARDOWN : +nextitem: /* * Special Page framing handling here. If we * did something that should scroll-by-a-line, frame @@ -795,6 +803,7 @@ view_a_thread: case MC_THRDINDX : +mc_thrdindx: msgmap->top = msgmap->top_after_thrd; if(unview_thread(state, stream, msgmap)){ state->next_screen = mail_index_screen; @@ -845,7 +854,7 @@ view_a_thread: && mp.col == id.plus_col && style != ThreadIndex){ collapse_or_expand(state, stream, msgmap, - mn_get_cur(msgmap)); + mn_get_cur(msgmap), 1); } else if (mp.doubleclick){ if(mp.button == M_BUTTON_LEFT){ @@ -954,9 +963,105 @@ view_a_thread: case MC_COLLAPSE : - thread_command(state, stream, msgmap, ch, -FOOTER_ROWS(state)); + thread_command(state, stream, msgmap, ch, -FOOTER_ROWS(state), 1); break; + case MC_CTHREAD : + if (SEP_THRDINDX()) + goto mc_thrdindx; + else + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, + "to collapse a thread")) + collapse_thread(state, stream,msgmap, 1); + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; + + case MC_OTHREAD : + if (SEP_THRDINDX()) + goto view_a_thread; + else + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, "to expand a thread")) + expand_thread(state, stream,msgmap, 1); + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; + + case MC_NEXTHREAD: + case MC_PRETHREAD: + if (THRD_INDX()){ + if (cmd == MC_NEXTHREAD) + goto nextitem; + else + goto previtem; + } + else + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, + "to move to other thread")) + move_thread(state, stream, msgmap, + cmd == MC_NEXTHREAD ? 1 : -1); + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; + + case MC_KOLAPSE: + case MC_EXPTHREAD: + if (SEP_THRDINDX()){ + q_status_message(SM_ORDER, 0, 1, + "Command not available in this screen"); + } + else{ + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, + cmd == MC_KOLAPSE ? "to collapse" : "to expand")) + kolapse_thread(state, stream, msgmap, + (cmd == MC_KOLAPSE) ? '[' : ']', 1); + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + } + break; + + case MC_DELTHREAD: + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, "to delete")) + cmd_delete_thread(state, stream, msgmap); + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; + + case MC_UNDTHREAD: + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, "to undelete")) + cmd_undelete_thread(state, stream, msgmap); + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; + + case MC_SELTHREAD: + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, "to undelete")) + cmd_select_thread(state, stream, msgmap); + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; + case MC_DELETE : case MC_UNDELETE : case MC_REPLY : @@ -977,13 +1082,12 @@ view_a_thread: if(rawno) thrd = fetch_thread(stream, rawno); - collapsed = thrd && thrd->next - && get_lflag(stream, NULL, rawno, MN_COLL); + collapsed = thread_is_kolapsed(ps_global, stream, msgmap, rawno); } if(collapsed){ thread_command(state, stream, msgmap, - ch, -FOOTER_ROWS(state)); + ch, -FOOTER_ROWS(state),1); /* increment current */ if(cmd == MC_DELETE){ advance_cur_after_delete(state, stream, msgmap, @@ -2675,6 +2779,7 @@ top_ent_calc(MAILSTREAM *stream, MSGNO_S *msgs, long int at_top, long int lines_ n = mn_raw2m(msgs, thrd->rawno); while(thrd){ + unsigned long branch; if(!msgline_hidden(stream, msgs, n, 0) && (++m % lines_per_page) == 1L) t = n; @@ -2743,11 +2848,12 @@ top_ent_calc(MAILSTREAM *stream, MSGNO_S *msgs, long int at_top, long int lines_ /* n is the end of this thread */ while(thrd){ + unsigned long next = 0L, branch = 0L; n = mn_raw2m(msgs, thrd->rawno); - if(thrd->branch) - thrd = fetch_thread(stream, thrd->branch); - else if(thrd->next) - thrd = fetch_thread(stream, thrd->next); + if(branch = get_branch(stream,thrd)) + thrd = fetch_thread(stream, branch); + else if(next = get_next(stream,thrd)) + thrd = fetch_thread(stream, next); else thrd = NULL; } @@ -2855,7 +2961,7 @@ warn_other_cmds(void) void thread_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, - UCS preloadkeystroke, int q_line) + UCS preloadkeystroke, int q_line, int display) { PINETHRD_S *thrd = NULL; unsigned long rawno, save_branch; @@ -2904,7 +3010,7 @@ thread_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, cancel_busy_cue(0); (void ) apply_command(state, stream, msgmap, preloadkeystroke, flags, - q_line); + q_line, display); /* restore the original flags */ copy_lflags(stream, msgmap, MN_STMP, MN_SLCT); @@ -3398,7 +3504,7 @@ index_sort_callback(set, order) if(set){ sort_folder(ps_global->mail_stream, ps_global->msgmap, order & 0x000000ff, - (order & 0x00000100) != 0, SRT_VRB); + (order & 0x00000100) != 0, SRT_VRB, 1); mswin_beginupdate(); update_titlebar_message(); update_titlebar_status(); diff --git a/alpine/mailindx.h b/alpine/mailindx.h index 3b4291c2..a1627c2f 100644 --- a/alpine/mailindx.h +++ b/alpine/mailindx.h @@ -103,7 +103,7 @@ int truncate_subj_and_from_strings(void); void paint_index_hline(MAILSTREAM *, long, ICE_S *); void setup_index_state(int); void warn_other_cmds(void); -void thread_command(struct pine *, MAILSTREAM *, MSGNO_S *, UCS, int); +void thread_command(struct pine *, MAILSTREAM *, MSGNO_S *, UCS, int, int); COLOR_PAIR *apply_rev_color(COLOR_PAIR *, int); #ifdef _WINDOWS int index_sort_callback(int, long); diff --git a/alpine/mailpart.c b/alpine/mailpart.c index 8286d79d..63427744 100644 --- a/alpine/mailpart.c +++ b/alpine/mailpart.c @@ -2146,6 +2146,11 @@ display_attachment(long int msgno, ATTACH_S *a, int flags) return(1); } + /* ok, we have a filename. Now check if there is a template, and if + * so, rename the file accordingly + */ + filename = mc_template(filename, a->body, a->can_display & MCD_EXT_PROMPT); + 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"), @@ -3308,7 +3313,7 @@ reply_msg_att(MAILSTREAM *stream, long int msgno, ATTACH_S *a) /* * For consistency, the first question is always "include text?" */ - if((include_text = reply_text_query(ps_global, 1, &prefix)) >= 0 + if((include_text = reply_text_query(ps_global, 1, NULL, &prefix)) >= 0 && reply_news_test(a->body->nested.msg->env, outgoing) > 0 && reply_harvest(ps_global, msgno, a->number, a->body->nested.msg->env, &saved_from, diff --git a/alpine/mailview.c b/alpine/mailview.c index 5193118f..41aeea5a 100644 --- a/alpine/mailview.c +++ b/alpine/mailview.c @@ -45,6 +45,7 @@ static char rcsid[] = "$Id: mailview.c 1266 2009-07-14 18:39:12Z hubert@u.washin #include "dispfilt.h" #include "busy.h" #include "smime.h" +#include "roleconf.h" #include "../pith/conf.h" #include "../pith/filter.h" #include "../pith/msgno.h" @@ -130,6 +131,7 @@ struct view_write_s { #define SS_CUR 2 #define SS_FREE 3 +static ACTION_S *role_chosen = NULL; /* * Handle hints. @@ -204,7 +206,15 @@ char *pcpine_help_scroll(char *); int pcpine_view_cursor(int, long); #endif +static char *prefix; +#define NO_FLOWED 0x0000 +#define IS_FLOWED 0x0001 +#define DELETEQUO 0x0010 +#define COLORAQUO 0x0100 +#define RAWSTRING 0x1000 +int is_word (char *, int, int); +int is_mailbox(char *, int, int); /*---------------------------------------------------------------------- Format a buffer with the text of the current message for browser @@ -243,6 +253,8 @@ mail_view_screen(struct pine *ps) ps->prev_screen = mail_view_screen; ps->force_prefer_plain = ps->force_no_prefer_plain = 0; + strcpy(ps->screen_name, "text"); + if(ps->ttyo->screen_rows - HEADER_ROWS(ps) - FOOTER_ROWS(ps) < 1){ q_status_message(SM_ORDER | SM_DING, 0, 3, _("Screen too small to view message")); @@ -295,6 +307,17 @@ mail_view_screen(struct pine *ps) else ps->unseen_in_view = !mc->seen; + prefix = reply_quote_str(env); + /* Make sure the prefix is not only made of spaces, so that we do not + * paint the screen incorrectly + */ + if (prefix && *prefix){ + int i; + for (i = 0; isspace((unsigned char) prefix[i]); i++); + if (i == strlen(prefix)) + fs_give((void **)&prefix); + } + init_handles(&handles); store = so_get(src, NULL, EDIT_ACCESS); @@ -479,6 +502,10 @@ mail_view_screen(struct pine *ps) } while(ps->next_screen == SCREEN_FUN_NULL); + strcpy(ps->screen_name, "unknown"); + + if (prefix && *prefix) + fs_give((void **)&prefix); if(we_cancel) cancel_busy_cue(-1); @@ -733,6 +760,8 @@ scroll_handle_prompt(HANDLE_S *handle, int force) {0, 'a', "A", N_("editApp")}, {-1, 0, NULL, NULL}}; + if (role_chosen) + free_action(&role_chosen); if(handle->type == URL){ launch_opts[4].ch = 'u'; @@ -847,12 +876,42 @@ scroll_handle_prompt(HANDLE_S *handle, int force) * sense if you just say View selected URL ... */ if(handle->type == URL && - !struncmp(handle->h.url.path, "mailto:", 7)) - snprintf(prompt, sizeof(prompt), "Compose mail to \"%.*s%s\" ? ", - 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 ? ", + !struncmp(handle->h.url.path, "mailto:", 7)){ + int rolenick = role_chosen ? strlen(role_chosen->nick) : 0; + int offset = 25 + (role_chosen ? 20 : 0); + int offset2 = max(0, sc - offset) - strlen(handle->h.url.path+7); + int offset3 = sc - strlen(handle->h.url.path+7) - rolenick - offset; + int laddress = min(max(0,sc - offset), sizeof(prompt)-50); + int lrole = rolenick; + + if (offset3 < 0){ + lrole = rolenick; + laddress = sc - offset - lrole; + offset3 = laddress - 20; /* redefine offset3 */ + if (offset3 < 0){ + laddress = 20; + lrole = sc - offset - laddress; + } + } + launch_opts[2].ch = 'r'; + launch_opts[2].rval = 'r'; + launch_opts[2].name = "R"; + launch_opts[2].label = N_("Set Role"); + snprintf(prompt, sizeof(prompt), "Compose mail to \"%.*s%s\" %s%.*s%s%s? ", + laddress, handle->h.url.path+7, + (offset2 < 0 ? "..." : ""), + (role_chosen ? "using role \"" : ""), + (role_chosen ? lrole : 0), + (role_chosen ? role_chosen->nick : ""), + (role_chosen ? (rolenick > lrole ? "..." : "") : ""), + (role_chosen ? "\" " : "")); + } + else{ + launch_opts[2].ch = -2; + launch_opts[2].rval = 0; + launch_opts[2].name = NULL; + launch_opts[2].label = NULL; + snprintf(prompt, sizeof(prompt), "View selected %s %s%.*s%s ? ", (handle->type == URL) ? "URL" : "Attachment", (handle->type == URL) ? "\"" : "", MIN(MAX(0,sc-27), sizeof(prompt)-50), @@ -860,6 +919,7 @@ scroll_handle_prompt(HANDLE_S *handle, int force) (handle->type == URL) ? ((strlen(handle->h.url.path) > MAX(0,sc-27)) ? "...\"" : "\"") : ""); + } prompt[sizeof(prompt)-1] = '\0'; @@ -868,6 +928,29 @@ scroll_handle_prompt(HANDLE_S *handle, int force) case 'y' : return(1); + case 'r': + { + void (*prev_screen)(struct pine *) = ps_global->prev_screen, + (*redraw)(void) = ps_global->redrawer; + ps_global->redrawer = NULL; + ps_global->next_screen = SCREEN_FUN_NULL; + if(role_select_screen(ps_global, &role_chosen, 1) < 0){ + cmd_cancelled("Compose"); + ps_global->next_screen = prev_screen; + ps_global->redrawer = redraw; + if(ps_global->redrawer) + (*ps_global->redrawer)(); + return 0; + } + ps_global->next_screen = prev_screen; + ps_global->redrawer = redraw; + if(role_chosen) + role_chosen = combine_inherited_role(role_chosen); + if(ps_global->redrawer) + (*ps_global->redrawer)(); + break; + } + case 'u' : strncpy(tmp, handle->h.url.path, sizeof(tmp)-1); tmp[sizeof(tmp)-1] = '\0'; @@ -1432,7 +1515,7 @@ url_launch(HANDLE_S *handle) else #endif /* quote shell specials */ - if(strpbrk(handle->h.url.path, "&*!;<>?[]|~$(){}'\"") != NULL){ + if(strpbrk(handle->h.url.path, "&*;<>?[]|~$(){}'\"") != NULL){ escape_single_quotes++; if((p = strstr(toolp, "_URL_")) != NULL){ /* explicit arg? */ int in_quote = 0; @@ -1510,8 +1593,7 @@ url_launch(HANDLE_S *handle) *cmdp++ = '\''; /* closing quote */ *cmdp++ = '\\'; *cmdp++ = '\''; /* opening quote comes from p below */ - } else if (strchr("&*!;<>?[]|~$(){}\"", *p) != NULL) - *cmdp++ = '\\'; + } *cmdp++ = *p; } @@ -1539,7 +1621,7 @@ url_launch(HANDLE_S *handle) if(cmdp-cmd >= URL_MAX_LAUNCH) return(url_launch_too_long(rv)); - mode = PIPE_RESET | PIPE_USER | PIPE_RUNNOW ; + mode = PIPE_RESET | PIPE_USER | PIPE_RUNNOW | PIPE_NOSHELL; if((syspipe = open_system_pipe(cmd, NULL, NULL, mode, 0, pipe_callback, pipe_report_error)) != NULL){ close_system_pipe(&syspipe, NULL, pipe_callback); q_status_message(SM_ORDER, 0, 4, _("VIEWER command completed")); @@ -1817,7 +1899,7 @@ url_local_mailto_and_atts(char *url, PATMT *attachlist) fs_give((void **) &urlp); rflags = ROLE_COMPOSE; - if(nonempty_patterns(rflags, &dummy)){ + if(!(role = copy_action(role_chosen)) && nonempty_patterns(rflags, &dummy)){ role = set_role_from_msg(ps_global, rflags, -1L, NULL); if(confirm_role(rflags, &role)) role = combine_inherited_role(role); @@ -1893,6 +1975,7 @@ outta_here: free_redraft_pos(&redraft_pos); free_action(&role); + free_action(&role_chosen); return(rv); } @@ -3463,6 +3546,52 @@ scrolltool(SCROLL_S *sparms) print_to_printer(sparms); break; + case MC_NEXTHREAD: + case MC_PRETHREAD: + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, + "to move to other thread")) + move_thread(ps_global, ps_global->mail_stream, ps_global->msgmap, + cmd == MC_NEXTHREAD ? 1 : -1); + done = 1; + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; + + case MC_DELTHREAD: + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, "to delete")) + cmd_delete_thread(ps_global, ps_global->mail_stream, ps_global->msgmap); + done = 1; + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; + + case MC_UNDTHREAD: + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, "to undelete")) + cmd_undelete_thread(ps_global, ps_global->mail_stream, ps_global->msgmap); + done = 1; + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; + + case MC_SELTHREAD: + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, "to undelete")) + cmd_select_thread(ps_global, ps_global->mail_stream, ps_global->msgmap); + done = 1; + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; /* ------- First handle on Line ------ */ case MC_GOTOBOL : diff --git a/alpine/osdep/debuging.c b/alpine/osdep/debuging.c index 0310f5b5..4767ca57 100644 --- a/alpine/osdep/debuging.c +++ b/alpine/osdep/debuging.c @@ -105,6 +105,7 @@ init_debug(void) if(debugfile != NULL){ char rev[128]; + extern char plevstamp[]; time_t now = time((time_t *)0); if(ps_global->debug_flush) setvbuf(debugfile, (char *)NULL, _IOLBF, BUFSIZ); @@ -127,6 +128,8 @@ init_debug(void) get_alpine_revision_string(rev, sizeof(rev)), ctime(&now))); + dprint((0, "This version uses all.patch:\n%s\n\n", plevstamp)); + dprint((0, "Starting after the reading_pinerc calls, the data in this file should\nbe encoded as UTF-8. Before that it will be in the user's native charset.\n")); if(dfile && (debug > DEFAULT_DEBUG || ps_global->debug_imap > 0 || diff --git a/alpine/osdep/execview.c b/alpine/osdep/execview.c index da7310df..d7087caa 100644 --- a/alpine/osdep/execview.c +++ b/alpine/osdep/execview.c @@ -261,7 +261,7 @@ exec_mailcap_cmd(MCAP_CMD_S *mc_cmd, char *image_file, int needsterminal) p = command = (char *)fs_get((l+1) * sizeof(char)); if(!needsterminal) /* put in background if it doesn't need terminal */ *p++ = '('; - snprintf(p, l+1-(p-command), "%s ; rm -f %s", cmd, image_file); + snprintf(p, l+1-(p-command), "%s ; sleep %d ; rm -f %s", cmd, ps_global->sleep, image_file); command[l] = '\0'; p += strlen(p); if(!needsterminal && (p-command)+5 < l){ diff --git a/alpine/osdep/termin.gen.c b/alpine/osdep/termin.gen.c index fb106be1..74d2a37f 100644 --- a/alpine/osdep/termin.gen.c +++ b/alpine/osdep/termin.gen.c @@ -33,6 +33,8 @@ static char rcsid[] = "$Id: termin.gen.c 1025 2008-04-08 22:59:38Z hubert@u.wash #include "../../pith/newmail.h" #include "../../pith/conf.h" #include "../../pith/busy.h" +#include "../../pith/list.h" +#include "../../pith/rules.h" #include "../../pico/estruct.h" #include "../../pico/pico.h" @@ -67,12 +69,30 @@ static int g_mc_row, g_mc_col; int pcpine_oe_cursor(int, long); #endif +void +fake_config_screen(tt) + struct ttyo **tt; +{ + struct ttyo *ttyo; + + ttyo = (struct ttyo *)fs_get(sizeof (struct ttyo)); + + ttyo->header_rows = 2; + ttyo->footer_rows = 3; + ttyo->screen_rows = 24; + ttyo->screen_cols = 80; + + *tt = ttyo; + +} + /* * Generic tty input routines */ - +void process_init_cmds(struct pine *, char **); +void queue_init_errors(struct pine *); /*---------------------------------------------------------------------- Read a character from keyboard with timeout Input: none @@ -114,6 +134,41 @@ read_command(char **utf8str) *utf8str = NULL; ucs = read_char(tm); + if(!ps_global->initial_cmds){ + RULE_RESULT *rule; + char **list = NULL, *error = NULL; + int commas = 0, k; /* From args.c */ + + ps_global->pressed_key = cpystr(pretty_command(ucs)); + rule = (RULE_RESULT *)get_result_rule(V_KEY_RULES, FOR_KEY, NULL); + if(ps_global->pressed_key) + fs_give((void **)&ps_global->pressed_key); + if (rule){ + for(k = 0; rule->result[k]; k++) + if(rule->result[k] == ',') commas++; + list = parse_list(rule->result, commas+1, 0, &error); + if(error) + sprintf(tmp_20k_buf, "Error in parsing command list: %s, %s", + rule->result, error); + if (rule->result) + fs_give((void **)&rule->result); + fs_give((void **)&rule); + if(error){ + q_status_message(SM_ORDER | SM_DING, 0, 2, tmp_20k_buf); + return (NO_OP_COMMAND); + } + process_init_cmds(ps_global, list); + if(ps_global->init_errs){ + queue_init_errors(ps_global); + return (NO_OP_COMMAND); + } + ucs = read_char(tm); + ps_global->in_init_seq = 1; /* no output please */ + for(k = 0; k < commas; k++) + if(list[k]) fs_give((void **)&list[k]); + if (list) fs_give((void **)list); + } + } if(ucs != NO_OP_COMMAND && ucs != NO_OP_IDLE && ucs != KEY_RESIZE) zero_new_mail_count(); @@ -307,7 +362,7 @@ optionally_enter(char *utf8string, int y_base, int x_base, int utf8string_size, (escape_list && escape_list[0].ch != -1 && escape_list[0].label) ? escape_list[0].label: "")); - if(!ps_global->ttyo) + if(!ps_global->ttyo || ps_global->send_immediately) return(pre_screen_config_opt_enter(utf8string, utf8string_size, utf8prompt, escape_list, help, flags)); @@ -1154,10 +1209,11 @@ process_config_input(UCS *ch) } } } - + ps_global->initial_cmds_offset++; if(!*ps_global->initial_cmds && ps_global->free_initial_cmds){ fs_give((void **) &ps_global->free_initial_cmds); ps_global->initial_cmds = NULL; + firsttime = (char) 1; } return(ret); diff --git a/alpine/osdep/termin.gen.h b/alpine/osdep/termin.gen.h index 18c7c0de..5309eba2 100644 --- a/alpine/osdep/termin.gen.h +++ b/alpine/osdep/termin.gen.h @@ -33,6 +33,7 @@ int process_config_input(UCS *); int key_recorder(int); int key_playback(int); int recent_keystroke(int *, char *, size_t); +void fake_config_screen(struct ttyo **); int init_tty_driver(struct pine *); void end_tty_driver(struct pine *); int PineRaw(int); diff --git a/alpine/osdep/termin.unx.c b/alpine/osdep/termin.unx.c index 451d18c2..b23c6f22 100644 --- a/alpine/osdep/termin.unx.c +++ b/alpine/osdep/termin.unx.c @@ -111,6 +111,8 @@ open_mailer for details. int init_tty_driver(struct pine *ps) { + if(ps->send_immediately) + return 0; #ifdef MOUSE if(F_ON(F_ENABLE_MOUSE, ps_global)) init_mouse(); @@ -677,6 +679,9 @@ a lot of at UW void init_keyboard(int use_fkeys) { + if (ps_global->send_immediately) + return; + if(use_fkeys && (!strucmp(term_name,"vt102") || !strucmp(term_name,"vt100"))) printf("\033\133\071\071\150"); @@ -694,6 +699,9 @@ init_keyboard(int use_fkeys) void end_keyboard(int use_fkeys) { + if(ps_global->send_immediately) + return; + if(use_fkeys && (!strcmp(term_name, "vt102") || !strcmp(term_name, "vt100"))){ printf("\033\133\071\071\154"); diff --git a/alpine/osdep/termout.unx.c b/alpine/osdep/termout.unx.c index faf8c7f9..88df57ea 100644 --- a/alpine/osdep/termout.unx.c +++ b/alpine/osdep/termout.unx.c @@ -206,6 +206,9 @@ config_screen(struct ttyo **tt) void init_screen(void) { + if(ps_global->send_immediately) + return; + if(_termcap_init) /* init using termcap's rule */ tputs(_termcap_init, 1, outchar); @@ -313,6 +316,9 @@ end_screen(char *message, int exit_val) { int footer_rows_was_one = 0; + if(ps_global->send_immediately) + return; + if(!panicking()){ dprint((9, "end_screen called\n")); @@ -367,7 +373,7 @@ ClearScreen(void) _line = 0; /* clear leaves us at top... */ _col = 0; - if(ps_global->in_init_seq) + if(ps_global->in_init_seq || ps_global->send_immediately) return; mark_status_unknown(); diff --git a/alpine/radio.c b/alpine/radio.c index fc5c9ab9..436be052 100644 --- a/alpine/radio.c +++ b/alpine/radio.c @@ -122,7 +122,7 @@ want_to(char *question, int dflt, int on_ctrl_C, HelpType help, int flags) int rv, width; size_t len; - if(!ps_global->ttyo) + if(!ps_global->ttyo || ps_global->send_immediately) return(pre_screen_config_want_to(question, dflt, on_ctrl_C)); #ifdef _WINDOWS if (mswin_usedialog ()) { diff --git a/alpine/reply.c b/alpine/reply.c index f0a40651..e72268c0 100644 --- a/alpine/reply.c +++ b/alpine/reply.c @@ -62,7 +62,8 @@ The evolution continues... #include "../pith/tempfile.h" #include "../pith/busy.h" #include "../pith/ablookup.h" - +#include "../pith/copyaddr.h" +#include "../pith/rules.h" /* * Internal Prototypes @@ -109,11 +110,12 @@ reply(struct pine *pine_state, ACTION_S *role_arg) long msgno, j, totalm, rflags, *seq = NULL; int i, include_text = 0, times = -1, warned = 0, rv = 0, flags = RSF_QUERY_REPLY_ALL, reply_raw_body = 0; - int rolemsg = 0, copytomsg = 0; + int rolemsg = 0, copytomsg = 0, do_role_early = 0; gf_io_t pc; PAT_STATE dummy; REDRAFT_POS_S *redraft_pos = NULL; ACTION_S *role = NULL, *nrole; + RULE_RESULT *rule; #if defined(DOS) && !defined(_WINDOWS) char *reserve; #endif @@ -139,6 +141,69 @@ reply(struct pine *pine_state, ACTION_S *role_arg) && F_ON(F_ENABLE_FULL_HDR_AND_TEXT, ps_global)) reply_raw_body = 1; + /* Setup possible role */ + if(role_arg) + role = copy_action(role_arg); + + if(!role && F_ON(F_ENABLE_EDIT_REPLY_INDENT, pine_state)){ + for(msgno = mn_first_cur(pine_state->msgmap); + msgno > 0L; msgno = mn_next_cur(pine_state->msgmap)){ + + env = pine_mail_fetchstructure(pine_state->mail_stream, + mn_m2raw(pine_state->msgmap, msgno), + NULL); + if(!env) { + q_status_message1(SM_ORDER,3,4, + _("Error fetching message %s. Can't reply to it."), + long2string(msgno)); + goto done_early; + } + + if(rule = get_result_rule(V_REPLY_INDENT_RULES, FOR_COMPOSE , env)){ + RULELIST *list = get_rulelist_from_code(V_REPLY_INDENT_RULES, + ps_global->rule_list); + RULE_S *prule = get_rule(list, rule->number); + if(condition_contains_token(prule->condition, ROLE_TOKEN)) + do_role_early++; + if(rule->result) + fs_give((void **)&rule->result); + fs_give((void **)&rule); + } + } + } + + if(do_role_early){ + rflags = ROLE_REPLY; + if(nonempty_patterns(rflags, &dummy)){ + /* setup default role */ + nrole = NULL; + j = mn_first_cur(pine_state->msgmap); + do { + role = nrole; + nrole = set_role_from_msg(pine_state, rflags, + mn_m2raw(pine_state->msgmap, j), + NULL); + } while(nrole && (!role || nrole == role) + && (j=mn_next_cur(pine_state->msgmap)) > 0L); + + if(!role || nrole == role) + role = nrole; + else + role = NULL; + + if(confirm_role(rflags, &role)) + role = combine_inherited_role(role); + else{ /* cancel reply */ + role = NULL; + cmd_cancelled("Reply"); + goto done_early; + } + } + } + + if (role) + ps_global->role = cpystr(role->nick); /* remember the role */ + /* * We may have to loop through first to figure out what default * reply-indent-string to offer... @@ -230,7 +295,7 @@ reply(struct pine *pine_state, ACTION_S *role_arg) if(!times){ /* only first time */ char *p = cpystr(prefix); - if((include_text=reply_text_query(pine_state,totalm,&prefix)) < 0) + if((include_text=reply_text_query(pine_state,totalm,env,&prefix)) < 0) goto done_early; /* edited prefix? */ @@ -286,8 +351,18 @@ reply(struct pine *pine_state, ACTION_S *role_arg) outgoing->subject = cpystr("Re: several messages"); } } - else - outgoing->subject = reply_subject(env->subject, NULL, 0); + else{ + RULE_RESULT *rule; + rule = get_result_rule(V_RESUB_RULES,FOR_RESUB|FOR_TRIM , env); + if (rule){ + outgoing->subject = reply_subject(rule->result, NULL, 0); + if (rule->result) + fs_give((void **)&rule->result); + fs_give((void **)&rule); + } + else + outgoing->subject = reply_subject(env->subject, NULL, 0); + } } /* fill reply header */ @@ -306,13 +381,15 @@ reply(struct pine *pine_state, ACTION_S *role_arg) if(sp_expunge_count(pine_state->mail_stream)) /* cur msg expunged */ goto done_early; - /* Setup possible role */ - if(role_arg) - role = copy_action(role_arg); + if (ps_global->reply.role_chosen){ + if(role_arg) + free_action(&role); + role = ps_global->reply.role_chosen; + } - if(!role){ + if(!do_role_early){ rflags = ROLE_REPLY; - if(nonempty_patterns(rflags, &dummy)){ + if(!ps_global->reply.role_chosen && nonempty_patterns(rflags, &dummy)){ /* setup default role */ nrole = NULL; j = mn_first_cur(pine_state->msgmap); @@ -548,7 +625,7 @@ reply(struct pine *pine_state, ACTION_S *role_arg) if(orig_body == NULL || orig_body->type == TYPETEXT || reply_raw_body) { reply_delimiter(env, role, pc); - if(F_ON(F_INCLUDE_HEADER, pine_state)) + if(ps_global->reply.inchdr) reply_forward_header(pine_state->mail_stream, mn_m2raw(pine_state->msgmap,msgno), NULL, env, pc, prefix); @@ -567,7 +644,7 @@ reply(struct pine *pine_state, ACTION_S *role_arg) && orig_body->nested.part->body.type == TYPETEXT) { /*---- First part of the message is text -----*/ reply_delimiter(env, role, pc); - if(F_ON(F_INCLUDE_HEADER, pine_state)) + if(ps_global->reply.inchdr) reply_forward_header(pine_state->mail_stream, mn_m2raw(pine_state->msgmap, msgno), @@ -721,6 +798,9 @@ reply(struct pine *pine_state, ACTION_S *role_arg) if(prefix) fs_give((void **)&prefix); + if (ps_global->role) + fs_give((void **)&ps_global->role); + if(fcc) fs_give((void **) &fcc); @@ -876,7 +956,8 @@ confirm_role(long int rflags, ACTION_S **role) prompt[sizeof(prompt)-1] = '\0'; - cmd = radio_buttons(prompt, -FOOTER_ROWS(ps_global), ekey, + cmd = ps_global->send_immediately ? 'n' : + radio_buttons(prompt, -FOOTER_ROWS(ps_global), ekey, 'y', 'x', help, RB_NORM); switch(cmd){ @@ -1003,48 +1084,113 @@ reply_using_replyto_query(void) * 0 if we're NOT to include the text * -1 on cancel or error */ +#define MAX_REPLY_OPTIONS 8 int -reply_text_query(struct pine *ps, long int many, char **prefix) +reply_text_query(struct pine *ps, long int many, ENVELOPE *env, char **prefix) { int ret, edited = 0; - static ESCKEY_S rtq_opts[] = { - {'y', 'y', "Y", N_("Yes")}, - {'n', 'n', "N", N_("No")}, - {-1, 0, NULL, NULL}, /* may be overridden below */ - {-1, 0, NULL, NULL} - }; + static ESCKEY_S compose_style[MAX_REPLY_OPTIONS]; + int ekey_num; + int orig_sf; + + orig_sf = *prefix && **prefix ? (F_OFF(F_QUELL_FLOWED_TEXT, ps) + && F_OFF(F_STRIP_WS_BEFORE_SEND, ps) + && (strcmp(*prefix, "> ") == 0 + || strcmp(*prefix, ">") == 0)) : 0; + + ps_global->reply.no_send_flowed = !orig_sf; + ps_global->reply.role_chosen = NULL; + ps_global->reply.strip = ps->full_header == 0 + && (F_ON(F_ENABLE_STRIP_SIGDASHES, ps) + || F_ON(F_ENABLE_SIGDASHES, ps)); + ps_global->reply.attach = F_ON(F_ATTACHMENTS_IN_REPLY, ps); + ps_global->reply.inchdr = F_ON(F_INCLUDE_HEADER, ps); if(F_ON(F_AUTO_INCLUDE_IN_REPLY, ps) - && F_OFF(F_ENABLE_EDIT_REPLY_INDENT, ps)) + && F_OFF(F_ENABLE_EDIT_REPLY_INDENT, ps) && F_OFF(F_ALT_REPLY_MENU,ps)) return(1); - while(1){ - if(many > 1L) - /* TRANSLATORS: The final three %s's can probably be safely ignored */ - snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Include %s original messages in Reply%s%s%s? "), - comatose(many), - F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? " (using \"" : "", - F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? *prefix : "", - F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? "\")" : ""); - else - snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Include original message in Reply%s%s%s? "), + while(1){ + /* TRANSLATORS: The final five %s's can probably be safely ignored */ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Include %s%soriginal message%s in Reply%s%s%s%s%s%s? "), + (many > 1L) ? comatose(many) : "", + (many > 1L) ? " " : "", + (many > 1L) ? "s" : "", + (many > 1L) ? "s" : "", F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? " (using \"" : "", F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? *prefix : "", + ps_global->reply.role_chosen ? "\" and role \"" : "", + ps_global->reply.role_chosen ? ps_global->reply.role_chosen->nick : "", F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? "\")" : ""); - if(F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps)){ - rtq_opts[2].ch = ctrl('R'); - rtq_opts[2].rval = 'r'; - rtq_opts[2].name = "^R"; - rtq_opts[2].label = N_("Edit Indent String"); + ekey_num = 0; + compose_style[ekey_num].ch = 'y'; + compose_style[ekey_num].rval = 'y'; + compose_style[ekey_num].name = "Y"; + compose_style[ekey_num++].label = N_("Yes"); + + compose_style[ekey_num].ch = 'n'; + compose_style[ekey_num].rval = 'n'; + compose_style[ekey_num].name = "N"; + compose_style[ekey_num++].label = N_("No"); + + if (F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps)){ + compose_style[ekey_num].ch = ctrl('R'); + compose_style[ekey_num].rval = 'r'; + compose_style[ekey_num].name = "^R"; + compose_style[ekey_num++].label = N_("Edit Indent String"); } - else - rtq_opts[2].ch = -1; + + /***** Alternate Reply Menu ********/ + + if (F_ON(F_ALT_REPLY_MENU, ps)){ + unsigned which_help; + + if (F_ON(F_ENABLE_STRIP_SIGDASHES, ps) || + F_ON(F_ENABLE_SIGDASHES, ps)){ + compose_style[ekey_num].ch = 's'; + compose_style[ekey_num].rval = 'S'; + compose_style[ekey_num].name = "S"; + compose_style[ekey_num++].label = ps_global->reply.strip + ? N_("No Strip"): N_("Strip Sig"); + } + + compose_style[ekey_num].ch = 'r'; + compose_style[ekey_num].rval = 'R'; + compose_style[ekey_num].name = "R"; + compose_style[ekey_num++].label = N_("Set Role"); + + if(orig_sf){ + compose_style[ekey_num].ch = 'f'; + compose_style[ekey_num].rval = 'F'; + compose_style[ekey_num].name = "F"; + compose_style[ekey_num++].label = ps_global->reply.no_send_flowed + ? N_("Quell Flow") : N_("Send Flowd"); + } + + compose_style[ekey_num].ch = 'a'; + compose_style[ekey_num].rval = 'A'; + compose_style[ekey_num].name = "A"; + compose_style[ekey_num++].label = ps_global->reply.attach + ? N_("No Attach"): N_("Inc Attac"); + + compose_style[ekey_num].ch = 'h'; + compose_style[ekey_num].rval = 'H'; + compose_style[ekey_num].name = "H"; + compose_style[ekey_num++].label = ps_global->reply.inchdr + ? N_("No Header") : N_("Inc Head"); + + } + compose_style[ekey_num].ch = -1; + compose_style[ekey_num].name = NULL; + compose_style[ekey_num].label = NULL; + + /***** End Alt Reply Menu *********/ switch(ret = radio_buttons(tmp_20k_buf, ps->ttyo->screen_rows > 4 ? -FOOTER_ROWS(ps_global) : -1, - rtq_opts, + compose_style, (edited || F_ON(F_AUTO_INCLUDE_IN_REPLY, ps)) ? 'y' : 'n', 'x', NO_HELP, RB_SEQ_SENSITIVE)){ @@ -1052,6 +1198,46 @@ reply_text_query(struct pine *ps, long int many, char **prefix) cmd_cancelled("Reply"); return(-1); + case 'F': + ps_global->reply.no_send_flowed = (ps_global->reply.no_send_flowed + 1) % 2; + break; + + case 'S': + ps_global->reply.strip = (ps_global->reply.strip + 1) % 2; + break; + + case 'A': + ps_global->reply.attach = (ps_global->reply.attach + 1) % 2; + break; + + case 'H': + ps_global->reply.inchdr = (ps_global->reply.inchdr + 1) % 2; + break; + + + case 'R': + { + void (*prev_screen)(struct pine *) = ps->prev_screen, + (*redraw)(void) = ps->redrawer; + ps->redrawer = NULL; + ps->next_screen = SCREEN_FUN_NULL; + if(role_select_screen(ps, &ps_global->reply.role_chosen, 1) < 0){ + cmd_cancelled("Reply"); + ps->next_screen = prev_screen; + ps->redrawer = redraw; + if (ps->redrawer) + (*ps->redrawer)(); + continue; + } + ps->next_screen = prev_screen; + ps->redrawer = redraw; + if(ps_global->reply.role_chosen) + ps_global->reply.role_chosen = combine_inherited_role(ps_global->reply.role_chosen); + } + if (ps->redrawer) + (*ps->redrawer)(); + break; + case 'r': if(prefix && *prefix){ int done = 0; @@ -1075,6 +1261,12 @@ reply_text_query(struct pine *ps, long int many, char **prefix) if(flags & OE_USER_MODIFIED){ fs_give((void **)prefix); *prefix = removing_quotes(cpystr(buf)); + orig_sf = *prefix && **prefix ? + (F_OFF(F_QUELL_FLOWED_TEXT, ps) + && F_OFF(F_STRIP_WS_BEFORE_SEND, ps) + && (strcmp(*prefix, "> ") == 0 + || strcmp(*prefix, ">") == 0)) : 0; + ps_global->reply.no_send_flowed = !orig_sf; edited = 1; } @@ -1471,9 +1663,14 @@ forward(struct pine *ps, ACTION_S *role_arg) } } - if(role) + if (ps_global->role) + fs_give((void **)&ps_global->role); + + if(role){ q_status_message1(SM_ORDER, 3, 4, _("Forwarding using role \"%s\""), role->nick); + ps_global->role = cpystr(role->nick); + } if(role && role->template){ char *filtered; @@ -1705,6 +1902,7 @@ forward(struct pine *ps, ACTION_S *role_arg) #if defined(DOS) && !defined(_WINDOWS) free((void *)reserve); #endif + outgoing->sparep = env && env->from ? copyaddr(env->from) : NULL; pine_send(outgoing, &body, "FORWARD MESSAGE", role, NULL, &reply, redraft_pos, NULL, NULL, 0); @@ -2457,6 +2655,8 @@ display_message_for_pico(int x) { int rv; + if(ps_global->send_immediately) + return 0; clear_cursor_pos(); /* can't know where cursor is */ mark_status_dirty(); /* don't count on cached text */ fix_windsize(ps_global); diff --git a/alpine/reply.h b/alpine/reply.h index 2c239071..134f8fc2 100644 --- a/alpine/reply.h +++ b/alpine/reply.h @@ -28,7 +28,7 @@ int reply(struct pine *, ACTION_S *); int confirm_role(long, ACTION_S **); int reply_to_all_query(int *); int reply_using_replyto_query(void); -int reply_text_query(struct pine *, long, char **); +int reply_text_query(struct pine *, long, ENVELOPE *, char **); int reply_news_test(ENVELOPE *, ENVELOPE *); char *get_signature_file(char *, int, int, int); int forward(struct pine *, ACTION_S *); diff --git a/alpine/roleconf.c b/alpine/roleconf.c index fad1e661..be046acf 100644 --- a/alpine/roleconf.c +++ b/alpine/roleconf.c @@ -140,8 +140,13 @@ role_select_screen(struct pine *ps, ACTION_S **role, int alt_compose) if(!(nonempty_patterns(rflags, &pstate) && first_pattern(&pstate))){ + if(!ps->send_immediately) q_status_message(SM_ORDER, 3, 3, _("No roles available. Use Setup/Rules to add roles.")); + else{ + printf( _("No roles available. Use Setup/Rules to add roles.")); + exit(-1); + } return(ret); } @@ -4478,11 +4483,11 @@ role_config_edit_screen(struct pine *ps, PAT_S *def, char *title, long int rflag ctmp->tool = role_sort_tool; ctmp->valoffset = rindent; ctmp->flags |= CF_NOSELECT; - ctmp->value = cpystr(set_choose); \ + ctmp->value = cpystr(set_choose); pval = PVAL(&sort_act_var, ew); if(pval) - decode_sort(pval, &def_sort, &def_sort_rev); + decode_sort(pval, &def_sort, &def_sort_rev, 0); /* allow user to set their default sort order */ new_confline(&ctmp)->var = &sort_act_var; @@ -4492,7 +4497,7 @@ role_config_edit_screen(struct pine *ps, PAT_S *def, char *title, long int rflag ctmp->tool = role_sort_tool; ctmp->valoffset = rindent; ctmp->varmem = -1; - ctmp->value = generalized_sort_pretty_value(ps, ctmp, 0); + ctmp->value = generalized_sort_pretty_value(ps, ctmp, 0, 0); for(j = 0; j < 2; j++){ for(i = 0; ps->sort_types[i] != EndofList; i++){ @@ -4504,7 +4509,7 @@ role_config_edit_screen(struct pine *ps, PAT_S *def, char *title, long int rflag ctmp->valoffset = rindent; ctmp->varmem = i + (j * EndofList); ctmp->value = generalized_sort_pretty_value(ps, ctmp, - 0); + 0, 0); } } @@ -5437,7 +5442,7 @@ role_config_edit_screen(struct pine *ps, PAT_S *def, char *title, long int rflag (*result)->patgrp->stat_boy = PAT_STAT_EITHER; if(sort_act){ - decode_sort(sort_act, &def_sort, &def_sort_rev); + decode_sort(sort_act, &def_sort, &def_sort_rev, 0); (*result)->action->sort_is_set = 1; (*result)->action->sortorder = def_sort; (*result)->action->revsort = (def_sort_rev ? 1 : 0); @@ -7706,6 +7711,11 @@ role_text_tool_inick(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) if(apval) *apval = (role && role->nick) ? cpystr(role->nick) : NULL; + if (ps_global->role) + fs_give((void **)&ps_global->role); + if (role && role->nick) + ps_global->role = cpystr(role->nick); + if((*cl)->value) fs_give((void **)&((*cl)->value)); diff --git a/alpine/send.c b/alpine/send.c index 852b611c..06c43b65 100644 --- a/alpine/send.c +++ b/alpine/send.c @@ -63,7 +63,7 @@ static char rcsid[] = "$Id: send.c 1142 2008-08-13 17:22:21Z hubert@u.washington #include "../pith/mimetype.h" #include "../pith/send.h" #include "../pith/smime.h" - +#include "../pith/rules.h" typedef struct body_particulars { unsigned short type, encoding, had_csp; @@ -239,6 +239,11 @@ alt_compose_screen(struct pine *pine_state) role->nick = cpystr("Default Role"); } + if (ps_global->role) + fs_give((void **)&ps_global->role); + + ps_global->role = cpystr(role->nick); + pine_state->redrawer = NULL; compose_mail(NULL, NULL, role, NULL, NULL); free_action(&role); @@ -448,8 +453,12 @@ compose_mail(char *given_to, char *fcc_arg, ACTION_S *role_arg, ps_global->next_screen = prev_screen; ps_global->redrawer = redraw; - if(role) + if (ps_global->role) + fs_give((void **)&ps_global->role); + if(role){ role = combine_inherited_role(role); + ps_global->role = cpystr(role->nick); + } } break; @@ -614,6 +623,7 @@ compose_mail(char *given_to, char *fcc_arg, ACTION_S *role_arg, if(given_to) rfc822_parse_adrlist(&outgoing->to, given_to, ps_global->maildomain); + outgoing->subject = cpystr(ps_global->subject); outgoing->message_id = generate_message_id(); /* @@ -644,9 +654,14 @@ compose_mail(char *given_to, char *fcc_arg, ACTION_S *role_arg, } } - if(role) + if (ps_global->role) + fs_give((void **)&ps_global->role); + + if(role){ q_status_message1(SM_ORDER, 3, 4, _("Composing using role \"%s\""), role->nick); + ps_global->role = cpystr(role->nick); + } /* * The type of storage object allocated below is vitally @@ -912,7 +927,7 @@ static struct headerentry he_template[]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE}, {"From : ", "From", h_composer_from, 10, 0, NULL, build_address, NULL, NULL, addr_book_compose, "To AddrBk", NULL, abook_nickname_complete, - 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK}, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK}, {"Reply-To: ", "Reply To", h_composer_reply_to, 10, 0, NULL, build_address, NULL, NULL, addr_book_compose, "To AddrBk", NULL, abook_nickname_complete, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK}, @@ -1782,6 +1797,9 @@ pine_send(ENVELOPE *outgoing, struct mail_bodystruct **body, pbf = &pbuf1; standard_picobuf_setup(pbf); + pbf->auto_cmds = ps_global->initial_cmds_backup + + ps_global->initial_cmds_offset; + /* * Cancel any pending initial commands since pico uses a different * input routine. If we didn't cancel them, they would happen after @@ -2305,6 +2323,11 @@ pine_send(ENVELOPE *outgoing, struct mail_bodystruct **body, he->rich_header = 0; } } + if (F_ON(F_ALLOW_CHANGING_FROM, ps_global) && + !ps_global->never_allow_changing_from){ + he->display_it = 1; /* show it */ + he->rich_header = 0; + } he_from = he; break; @@ -2414,6 +2437,26 @@ pine_send(ENVELOPE *outgoing, struct mail_bodystruct **body, removing_trailing_white_space(pf->textbuf); (void)removing_double_quotes(pf->textbuf); build_address(pf->textbuf, &addr, NULL, NULL, NULL); + if (!strncmp(pf->name,"Lcc",3) && addr && *addr){ + RULE_RESULT *rule; + + outgoing->date = (unsigned char *) cpystr(addr); + ps_global->procid = cpystr("fwd-lcc"); + rule = get_result_rule(V_FORWARD_RULES, + FOR_COMPOSE|FOR_TRIM, outgoing); + if (rule){ + addr = cpystr(rule->result); + removing_trailing_white_space(addr); + (void)removing_extra_stuff(addr); + if (rule->result) + fs_give((void **)&rule->result); + fs_give((void **)&rule); + } + fs_give((void **)&ps_global->procid); + if (outgoing->date) + fs_give((void **)&outgoing->date); + } + rfc822_parse_adrlist(pf->addr, addr, ps_global->maildomain); fs_give((void **)&addr); @@ -2983,7 +3026,12 @@ pine_send(ENVELOPE *outgoing, struct mail_bodystruct **body, #ifdef _WINDOWS mswin_setwindowmenu (MENU_DEFAULT); #endif - fix_windsize(ps_global); + if (ps_global->send_immediately){ + if(ps_global->free_initial_cmds_backup) + fs_give((void **)&ps_global->free_initial_cmds_backup); + } + else + fix_windsize(ps_global); /* * Only reinitialize signals if we didn't receive an interesting @@ -3042,7 +3090,9 @@ pine_send(ENVELOPE *outgoing, struct mail_bodystruct **body, if(outgoing->return_path) mail_free_address(&outgoing->return_path); - outgoing->return_path = rfc822_cpy_adr(outgoing->from); + outgoing->return_path = F_ON(F_USE_DOMAIN_NAME,ps_global) + ? rfc822_cpy_adr(generate_from()) + : rfc822_cpy_adr(outgoing->from); /* * Don't ever believe the sender that is there. @@ -3719,10 +3769,16 @@ pine_send(ENVELOPE *outgoing, struct mail_bodystruct **body, if(sending_filter_requested && !filter_message_text(sending_filter_requested, outgoing, *body, &orig_so, &header)){ - q_status_message1(SM_ORDER, 3, 3, + if (!ps_global->send_immediately){ + q_status_message1(SM_ORDER, 3, 3, _("Problem filtering! Nothing sent%s."), fcc ? " or saved to fcc" : ""); - continue; + continue; + } + else{ + fprintf(stderr, _("Problem filtering! Nothing sent or saved to Fcc\n")); + exit(-1); + } } /*------ Actually post -------*/ @@ -3966,6 +4022,8 @@ pine_send(ENVELOPE *outgoing, struct mail_bodystruct **body, /*----- Mail Post FAILED, back to composer -----*/ if(result & (P_MAIL_LOSE | P_FCC_LOSE)){ dprint((1, "Send failed, continuing\n")); + if (ps_global->send_immediately) + exit(1); if(result & P_FCC_LOSE){ /* @@ -4000,6 +4058,7 @@ pine_send(ENVELOPE *outgoing, struct mail_bodystruct **body, update_answered_flags(reply); /*----- Signed, sealed, delivered! ------*/ + if (!ps_global->send_immediately) q_status_message(SM_ORDER, 0, 3, pine_send_status(result, fcc, tmp_20k_buf, SIZEOF_20KBUF, NULL)); @@ -4466,7 +4525,7 @@ send_exit_for_pico(struct headerentry *he, void (*redraw_pico)(void), int allow_ return(1); } - if(F_ON(F_SEND_WO_CONFIRM, ps_global)){ + if(!ps_global->send_immediately && F_ON(F_SEND_WO_CONFIRM, ps_global)){ if(result) *result = NULL; @@ -4646,7 +4705,8 @@ send_exit_for_pico(struct headerentry *he, void (*redraw_pico)(void), int allow_ opts[i].ch = -1; - fix_windsize(ps_global); + if (!ps_global->send_immediately) + fix_windsize(ps_global); while(1){ if(filters && filters->filter && (p = strindex(filters->filter, ' '))) @@ -4828,7 +4888,8 @@ send_exit_for_pico(struct headerentry *he, void (*redraw_pico)(void), int allow_ if(double_rad + ((call_mailer_flags & CM_DSN_SHOW) ? 4 : F_ON(F_DSN, ps_global) ? 1 : 0) > 11) - rv = double_radio_buttons(tmp_20k_buf, -FOOTER_ROWS(ps_global), opts, + rv = ps_global->send_immediately ? 'y' : + double_radio_buttons(tmp_20k_buf, -FOOTER_ROWS(ps_global), opts, 'y', 'z', (F_ON(F_DSN, ps_global) && allow_flowed) ? h_send_prompt_dsn_flowed : @@ -4837,7 +4898,8 @@ send_exit_for_pico(struct headerentry *he, void (*redraw_pico)(void), int allow_ h_send_prompt, RB_NORM); else - rv = radio_buttons(tmp_20k_buf, -FOOTER_ROWS(ps_global), opts, + rv = ps_global->send_immediately ? 'y' : + radio_buttons(tmp_20k_buf, -FOOTER_ROWS(ps_global), opts, 'y', 'z', (double_rad + ((call_mailer_flags & CM_DSN_SHOW) @@ -5174,11 +5236,13 @@ cancel_for_pico(void (*redraw_pico)(void)) {'c', 'c', "C", N_("Confirm")}, {'n', 'n', "N", N_("No")}, {'y', 'y', "", ""}, + {'t', 't', "T", N_("CounT")}, {-1, 0, NULL, NULL} }; ps_global->redrawer = redraw_pico; fix_windsize(ps_global); + pbf->curpos[0] = '\0'; while(1){ rv = radio_buttons(prompt, -FOOTER_ROWS(ps_global), opts, @@ -5191,12 +5255,16 @@ cancel_for_pico(void (*redraw_pico)(void)) q_status_message(SM_INFO, 1, 3, _(" Type \"C\" to cancel message ")); display_message('x'); } + else if(rv == 't'){ + showcpos(1,0); + break; + } else break; } ps_global->redrawer = redraw; - return(rstr); + return(pbf->curpos[0] ? pbf->curpos : rstr); } @@ -5300,9 +5368,11 @@ filter_message_text(char *fcmd, ENVELOPE *outgoing, struct mail_bodystruct *body if((tmp_so = so_get(PicoText, NULL, EDIT_ACCESS)) != NULL){ gf_set_so_writec(&pc, tmp_so); ps_global->mangled_screen = 1; - suspend_busy_cue(); - ClearScreen(); - fflush(stdout); + if (!ps_global->send_immediately){ + suspend_busy_cue(); + ClearScreen(); + fflush(stdout); + } if(tmpf){ PIPE_S *fpipe; @@ -5414,8 +5484,10 @@ filter_message_text(char *fcmd, ENVELOPE *outgoing, struct mail_bodystruct *body set_mime_type_by_grope(b); } - ClearScreen(); - resume_busy_cue(0); + if (!ps_global->send_immediately){ + ClearScreen(); + resume_busy_cue(0); + } } else errstr = "Can't create space for filtered text."; @@ -5446,10 +5518,16 @@ filter_message_text(char *fcmd, ENVELOPE *outgoing, struct mail_bodystruct *body if(tmp_so) so_give(&tmp_so); - q_status_message1(SM_ORDER | SM_DING, 3, 6, _("Problem filtering: %s"), + if (!ps_global->send_immediately){ + q_status_message1(SM_ORDER | SM_DING, 3, 6, _("Problem filtering: %s"), errstr); - dprint((1, "Filter FAILED: %s\n", + dprint((1, "Filter FAILED: %s\n", errstr ? errstr : "?")); + } + else{ + fprintf(stderr, _("Filter FAILED: %s\n"), errstr ? errstr : "?"); + exit(-1); + } } return(errstr == NULL); diff --git a/alpine/setup.c b/alpine/setup.c index 3ac90f21..4a30bec9 100644 --- a/alpine/setup.c +++ b/alpine/setup.c @@ -258,7 +258,7 @@ option_screen(struct pine *ps, int edit_exceptions) ctmpa->flags |= CF_NOSELECT; ctmpa->value = cpystr("--- ----------------------"); - decode_sort(pval, &def_sort, &def_sort_rev); + decode_sort(pval, &def_sort, &def_sort_rev, 0); for(j = 0; j < 2; j++){ for(i = 0; ps->sort_types[i] != EndofList; i++){ @@ -273,6 +273,55 @@ option_screen(struct pine *ps, int edit_exceptions) } } } + else if(vtmp == &ps->vars[V_THREAD_SORT_KEY]){ /* radio case */ + SortOrder thread_def_sort; + int thread_def_sort_rev, lv; + + ctmpa->flags |= CF_NOSELECT; + ctmpa->keymenu = &config_radiobutton_keymenu; + ctmpa->tool = NULL; + + /* put a nice delimiter before list */ + new_confline(&ctmpa)->var = NULL; + ctmpa->varnamep = ctmpb; + ctmpa->keymenu = &config_radiobutton_keymenu; + ctmpa->help = NO_HELP; + ctmpa->tool = radiobutton_tool; + ctmpa->valoffset = 12; + ctmpa->flags |= CF_NOSELECT; + ctmpa->value = cpystr("Set Thread Sort Options"); + + new_confline(&ctmpa)->var = NULL; + ctmpa->varnamep = ctmpb; + ctmpa->keymenu = &config_radiobutton_keymenu; + ctmpa->help = NO_HELP; + ctmpa->tool = radiobutton_tool; + ctmpa->valoffset = 12; + ctmpa->flags |= CF_NOSELECT; + ctmpa->value = cpystr("--- ----------------------"); + + /* find longest value's name */ + for(lv = 0, i = 0; ps->sort_types[i] != EndofList; i++) + if(lv < (j = strlen(sort_name(ps->sort_types[i])))) + lv = j; + + decode_sort(pval, &thread_def_sort, &thread_def_sort_rev, 1); + + for(j = 0; j < 2; j++){ + for(i = 0; ps->sort_types[i] != EndofList; i++){ + if (allowed_thread_key(ps->sort_types[i])){ + new_confline(&ctmpa)->var = vtmp; + ctmpa->varnamep = ctmpb; + ctmpa->keymenu = &config_radiobutton_keymenu; + ctmpa->help = config_help(vtmp - ps->vars, 0); + ctmpa->tool = radiobutton_tool; + ctmpa->valoffset = 12; + ctmpa->varmem = i + (j * EndofList); + ctmpa->value = pretty_value(ps, ctmpa); + } + } + } + } else if(vtmp == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){ /* yesno case */ ctmpa->keymenu = &config_yesno_keymenu; ctmpa->tool = yesno_tool; @@ -335,6 +384,7 @@ option_screen(struct pine *ps, int edit_exceptions) } else{ if(vtmp == &ps->vars[V_FILLCOL] + || vtmp == &ps->vars[V_SLEEP] || vtmp == &ps->vars[V_QUOTE_SUPPRESSION] || vtmp == &ps->vars[V_OVERLAP] || vtmp == &ps->vars[V_MAXREMSTREAM] @@ -464,6 +514,15 @@ option_screen(struct pine *ps, int edit_exceptions) } } + pval = PVAL(&ps->vars[V_THREAD_SORT_KEY], ew); + if(vsave[V_THREAD_SORT_KEY].saved_user_val.p && pval + && strcmp(vsave[V_THREAD_SORT_KEY].saved_user_val.p, pval)){ + if(!mn_get_mansort(ps_global->msgmap)){ + clear_index_cache(ps_global->mail_stream, 0); + reset_sort_order(SRT_VRB); + } + } + treat_color_vars_as_text = 0; free_saved_config(ps, &vsave, expose_hidden_config); #ifdef _WINDOWS diff --git a/alpine/status.c b/alpine/status.c index b51c640f..4dd44817 100644 --- a/alpine/status.c +++ b/alpine/status.c @@ -111,6 +111,9 @@ q_status_message(int flags, int min_time, int max_time, char *message) char *clean_msg; size_t mlen; + if (ps_global->send_immediately) + return; + status_message_lock(); /* @@ -605,6 +608,9 @@ flush_status_messages(int skip_last_pause) SMQ_T *q, *copy_of_q; int ding; + if(ps_global->send_immediately) + return; + start_over: status_message_lock(); |