summaryrefslogtreecommitdiff
path: root/alpine
diff options
context:
space:
mode:
authorEduardo Chappa <chappa@washington.edu>2013-05-31 17:08:22 -0600
committerEduardo Chappa <chappa@washington.edu>2013-05-31 17:08:22 -0600
commit81e994d7907f850506ddc248f84761a54995e58c (patch)
tree3bc4993b48ddeec45dee51323437200ab975887c /alpine
parent077522d7e058133f9de99d0d74481566b21c5a98 (diff)
downloadalpine-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')
-rw-r--r--alpine/Makefile.am1
-rw-r--r--alpine/Makefile.in1
-rw-r--r--alpine/adrbkcmd.c3
-rw-r--r--alpine/alpine.c56
-rw-r--r--alpine/arg.c31
-rw-r--r--alpine/arg.h1
-rw-r--r--alpine/busy.c14
-rw-r--r--alpine/confscroll.c132
-rw-r--r--alpine/confscroll.h2
-rw-r--r--alpine/dispfilt.c73
-rw-r--r--alpine/dispfilt.h2
-rw-r--r--alpine/folder.c34
-rw-r--r--alpine/imap.c79
-rw-r--r--alpine/imap.h3
-rw-r--r--alpine/keymenu.c47
-rw-r--r--alpine/keymenu.h13
-rw-r--r--alpine/mailcmd.c513
-rw-r--r--alpine/mailcmd.h13
-rw-r--r--alpine/mailindx.c130
-rw-r--r--alpine/mailindx.h2
-rw-r--r--alpine/mailpart.c7
-rw-r--r--alpine/mailview.c151
-rw-r--r--alpine/osdep/debuging.c3
-rw-r--r--alpine/osdep/execview.c2
-rw-r--r--alpine/osdep/termin.gen.c62
-rw-r--r--alpine/osdep/termin.gen.h1
-rw-r--r--alpine/osdep/termin.unx.c8
-rw-r--r--alpine/osdep/termout.unx.c8
-rw-r--r--alpine/radio.c2
-rw-r--r--alpine/reply.c280
-rw-r--r--alpine/reply.h2
-rw-r--r--alpine/roleconf.c20
-rw-r--r--alpine/send.c118
-rw-r--r--alpine/setup.c61
-rw-r--r--alpine/status.c6
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();