summaryrefslogtreecommitdiffstats
path: root/main/alpine
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2011-02-25 11:17:55 +0000
committerNatanael Copa <ncopa@alpinelinux.org>2011-02-25 11:17:55 +0000
commitba489c5e19754da1c71031b7c462b9614518d2ef (patch)
tree95a0334d0a6ccaf0f23bb67d62b886621f75a7e2 /main/alpine
parenta5b85e4e288c38fd11f1b3b3ee7922548a21cba7 (diff)
downloadaports-ba489c5e19754da1c71031b7c462b9614518d2ef.tar.bz2
aports-ba489c5e19754da1c71031b7c462b9614518d2ef.tar.xz
main/alpine: upgrade to 2.00_p84
Diffstat (limited to 'main/alpine')
-rw-r--r--main/alpine/APKBUILD7
-rw-r--r--main/alpine/all_p84.patch26592
2 files changed, 26595 insertions, 4 deletions
diff --git a/main/alpine/APKBUILD b/main/alpine/APKBUILD
index 435866f73..cc2204a35 100644
--- a/main/alpine/APKBUILD
+++ b/main/alpine/APKBUILD
@@ -1,6 +1,6 @@
# Maintainer: Natanael Copa <ncopa@alpinelinux.org>
pkgname=alpine
-pkgver=2.00_p73
+pkgver=2.00_p84
_ver=${pkgver%_p*}
_pver=${pkgver##*_p}
pkgrel=1
@@ -12,13 +12,12 @@ depends=""
makedepends="openldap-dev heimdal-dev ncurses-dev openssl-dev"
subpackages="$pkgname-doc"
source="ftp://ftp.cac.washington.edu/alpine/alpine.tar.bz2
- http://staff.washington.edu/chappa/alpine/patches/alpine-${_ver}/all_${_pver}.patch.gz
+ all_p84.patch
CVE-2008-5514.patch"
_builddir="$srcdir"/$pkgname-$_ver
prepare() {
cd "$_builddir"
- gunzip -c "$srcdir"/all_$_pver.patch.gz | patch -p1 || return 1
for i in $source; do
case $i in
*.patch)
@@ -46,5 +45,5 @@ package() {
}
md5sums="84e44cbf71ed674800a5d57eed9c1c52 alpine.tar.bz2
-12fa93aa8bf008f40bf8cc9326a8751f all_73.patch.gz
+785cea92b11d6655c183f3379468a643 all_p84.patch
1b52a54a656979116c09fb1d948a4325 CVE-2008-5514.patch"
diff --git a/main/alpine/all_p84.patch b/main/alpine/all_p84.patch
new file mode 100644
index 000000000..c025fc435
--- /dev/null
+++ b/main/alpine/all_p84.patch
@@ -0,0 +1,26592 @@
+diff -rc alpine-2.00/alpine/adrbkcmd.c alpine-2.00.I.USE/alpine/adrbkcmd.c
+*** alpine-2.00/alpine/adrbkcmd.c 2008-05-30 09:52:41.000000000 -0700
+--- alpine-2.00.I.USE/alpine/adrbkcmd.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 57,62 ****
+--- 57,64 ----
+ #include "../pith/send.h"
+ #include "../pith/list.h"
+ #include "../pith/busy.h"
++ #include "../pith/icache.h"
++ #include "../pith/osdep/color.h"
+
+
+ /* internal prototypes */
+***************
+*** 1146,1151 ****
+--- 1148,1155 ----
+ q_status_message1(SM_INFO, 0, 2, _("Address book %s cancelled"), cmd);
+ }
+ else if(editor_result & COMP_EXIT){
++ if(pico_usingcolor())
++ clear_index_cache(ps_global->mail_stream, 0);
+ removing_leading_and_trailing_white_space(nick);
+ removing_leading_and_trailing_white_space(full);
+ removing_leading_and_trailing_white_space(fcc);
+***************
+*** 4123,4128 ****
+--- 4127,4134 ----
+ * 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{
+***************
+*** 4130,4135 ****
+--- 4136,4142 ----
+ 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 -rc alpine-2.00/alpine/alpine.c alpine-2.00.I.USE/alpine/alpine.c
+*** alpine-2.00/alpine/alpine.c 2008-06-03 15:31:05.000000000 -0700
+--- alpine-2.00.I.USE/alpine/alpine.c 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 193,198 ****
+--- 193,199 ----
+ #endif
+
+ status_message_lock_init();
++ inverse_itokens();
+
+ #if HAVE_SRANDOM
+ /*
+***************
+*** 293,298 ****
+--- 294,300 ----
+ exit(-1);
+ }
+
++ mail_parameters(NULL, SET_QUOTA, (void *) pine_parse_quota);
+ /* set some default timeouts in case pinerc is remote */
+ mail_parameters(NULL, SET_OPENTIMEOUT, (void *)(long)30);
+ mail_parameters(NULL, SET_READTIMEOUT, (void *)(long)15);
+***************
+*** 303,308 ****
+--- 305,311 ----
+ 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
+***************
+*** 454,459 ****
+--- 457,467 ----
+
+ 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();
+***************
+*** 462,467 ****
+--- 470,476 ----
+ /* 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){
+***************
+*** 553,558 ****
+--- 562,572 ----
+ 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))
+***************
+*** 672,677 ****
+--- 686,692 ----
+
+
+ /*--- output side ---*/
++ if (!ps_global->send_immediately){
+ rv = config_screen(&(pine_state->ttyo));
+ #ifndef _WINDOWS /* always succeeds under _WINDOWS */
+ if(rv){
+***************
+*** 712,723 ****
+ /* 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,
+--- 727,732 ----
+***************
+*** 725,730 ****
+--- 734,752 ----
+ 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;
+***************
+*** 900,905 ****
+--- 922,933 ----
+ 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;
+***************
+*** 938,944 ****
+ memset(&fcc, 0, sizeof(fcc));
+
+ if(good_addr){
+! compose_mail(addr, fcc.tptr, NULL,
+ args.data.mail.attachlist, stdin_getc);
+ }
+ else{
+--- 966,972 ----
+ memset(&fcc, 0, sizeof(fcc));
+
+ if(good_addr){
+! compose_mail(addr, fcc.tptr, role,
+ args.data.mail.attachlist, stdin_getc);
+ }
+ else{
+***************
+*** 972,977 ****
+--- 1000,1006 ----
+
+ pine_state->mail_stream = NULL;
+ pine_state->mangled_screen = 1;
++ pine_state->subject = NULL;
+
+ if(args.action == aaURL){
+ url_tool_t f;
+***************
+*** 1087,1092 ****
+--- 1116,1122 ----
+ }
+ }
+
++ if (!pine_state->send_immediately)
+ fflush(stdout);
+
+ #if !defined(_WINDOWS) && !defined(LEAVEOUTFIFO)
+***************
+*** 2975,2984 ****
+ if(i > 0){
+ ps->initial_cmds = (int *)fs_get((i+1) * sizeof(int));
+ ps->free_initial_cmds = ps->initial_cmds;
+ for(j = 0; j < i; j++)
+! ps->initial_cmds[j] = i_cmds[j];
+!
+! ps->initial_cmds[i] = 0;
+ ps->in_init_seq = ps->save_in_init_seq = 1;
+ }
+ }
+--- 3005,3019 ----
+ 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] = 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;
+ }
+ }
+***************
+*** 3134,3139 ****
+--- 3169,3177 ----
+ 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 -rc alpine-2.00/alpine/arg.c alpine-2.00.I.USE/alpine/arg.c
+*** alpine-2.00/alpine/arg.c 2008-01-04 14:49:15.000000000 -0800
+--- alpine-2.00.I.USE/alpine/arg.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 59,64 ****
+--- 59,65 ----
+ 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\"");
+***************
+*** 102,112 ****
+--- 103,115 ----
+ 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"),
+***************
+*** 191,196 ****
+--- 194,200 ----
+ 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;
+***************
+*** 362,367 ****
+--- 366,382 ----
+
+ 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;
+***************
+*** 468,473 ****
+--- 483,492 ----
+
+ 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;
+***************
+*** 476,481 ****
+--- 495,506 ----
+ 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;
+***************
+*** 826,839 ****
+ exit(-1);
+
+ if(do_version){
+! extern char datestamp[], hoststamp[];
+ char rev[128];
+
+! snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Alpine %s (%s %s) built %s on %s",
+ ALPINE_VERSION,
+ SYSTYPE ? SYSTYPE : "?",
+ get_alpine_revision_string(rev, sizeof(rev)),
+! datestamp, hoststamp);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 0);
+ exit(0);
+--- 851,864 ----
+ exit(-1);
+
+ if(do_version){
+! extern char datestamp[], hoststamp[], plevstamp[];
+ char rev[128];
+
+! 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, plevstamp);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 0);
+ exit(0);
+diff -rc alpine-2.00/alpine/arg.h alpine-2.00.I.USE/alpine/arg.h
+*** alpine-2.00/alpine/arg.h 2006-09-22 13:06:05.000000000 -0700
+--- alpine-2.00.I.USE/alpine/arg.h 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 27,32 ****
+--- 27,33 ----
+ typedef struct argdata {
+ enum {aaFolder = 0, aaMore, aaURL, aaMail,
+ aaPrcCopy, aaAbookCopy} action;
++ int noutf8;
+ union {
+ char *folder;
+ char *file;
+diff -rc alpine-2.00/alpine/busy.c alpine-2.00.I.USE/alpine/busy.c
+*** alpine-2.00/alpine/busy.c 2007-10-15 14:02:56.000000000 -0700
+--- alpine-2.00.I.USE/alpine/busy.c 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 194,200 ****
+
+ add_review_message(buf, -1);
+ }
+! else{
+ q_status_message(SM_ORDER, 0, 1, progress);
+
+ /*
+--- 194,200 ----
+
+ add_review_message(buf, -1);
+ }
+! else if (!ps_global->send_immediately){
+ q_status_message(SM_ORDER, 0, 1, progress);
+
+ /*
+***************
+*** 206,213 ****
+ */
+ display_message('x');
+ }
+!
+! fflush(stdout);
+ }
+
+ /*
+--- 206,213 ----
+ */
+ display_message('x');
+ }
+! if (!ps_global->send_immediately)
+! fflush(stdout);
+ }
+
+ /*
+***************
+*** 255,261 ****
+ (*ap)->cf = done_busy_cue;
+ ap = &(*ap)->next;
+
+! start_after(a); /* launch cue handler */
+
+ #ifdef _WINDOWS
+ mswin_setcursor(MSWIN_CURSOR_BUSY);
+--- 255,262 ----
+ (*ap)->cf = done_busy_cue;
+ ap = &(*ap)->next;
+
+! if(!ps_global->send_immediately)
+! start_after(a); /* launch cue handler */
+
+ #ifdef _WINDOWS
+ mswin_setcursor(MSWIN_CURSOR_BUSY);
+***************
+*** 404,409 ****
+--- 405,415 ----
+ {
+ 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 -rc alpine-2.00/alpine/colorconf.c alpine-2.00.I.USE/alpine/colorconf.c
+*** alpine-2.00/alpine/colorconf.c 2008-02-08 10:39:55.000000000 -0800
+--- alpine-2.00.I.USE/alpine/colorconf.c 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 28,33 ****
+--- 28,34 ----
+ #include "../pith/color.h"
+ #include "../pith/icache.h"
+ #include "../pith/mailcmd.h"
++ #include "../pith/mailindx.h"
+ #include "../pith/list.h"
+
+
+***************
+*** 39,45 ****
+ SAVED_CONFIG_S *save_color_config_vars(struct pine *);
+ void free_saved_color_config(struct pine *, SAVED_CONFIG_S **);
+ void color_config_init_display(struct pine *, CONF_S **, CONF_S **);
+! void add_header_color_line(struct pine *, CONF_S **, char *, int);
+ int is_rgb_color(char *);
+ char *new_color_line(char *, int, int, int);
+ int color_text_tool(struct pine *, int, CONF_S **, unsigned);
+--- 40,46 ----
+ SAVED_CONFIG_S *save_color_config_vars(struct pine *);
+ void free_saved_color_config(struct pine *, SAVED_CONFIG_S **);
+ void color_config_init_display(struct pine *, CONF_S **, CONF_S **);
+! void add_header_color_line(struct pine *, CONF_S **, char *, int, int);
+ int is_rgb_color(char *);
+ char *new_color_line(char *, int, int, int);
+ int color_text_tool(struct pine *, int, CONF_S **, unsigned);
+***************
+*** 141,147 ****
+ if((v && v->name &&
+ srchstr(v->name, "-foreground-color") &&
+ pvalfg && pvalfg[0] && pvalbg && pvalbg[0]) ||
+! (v == &ps->vars[V_VIEW_HDR_COLORS] || v == &ps->vars[V_KW_COLORS]))
+ ret = SAMP1;
+
+ return(ret);
+--- 142,149 ----
+ if((v && v->name &&
+ srchstr(v->name, "-foreground-color") &&
+ pvalfg && pvalfg[0] && pvalbg && pvalbg[0]) ||
+! (v == &ps->vars[V_INDEX_TOKEN_COLORS] ||
+! v == &ps->vars[V_VIEW_HDR_COLORS] || v == &ps->vars[V_KW_COLORS]))
+ ret = SAMP1;
+
+ return(ret);
+***************
+*** 486,491 ****
+--- 488,513 ----
+ }
+
+ /*
++ * custom index tokens colors
++ */
++ vtmp = &ps->vars[V_INDEX_TOKEN_COLORS];
++ lval = LVAL(vtmp, ew);
++
++ if(lval && lval[0] && lval[0][0]){
++ for(i = 0; lval && lval[i]; i++)
++ add_header_color_line(ps, ctmp, lval[i], i, V_INDEX_TOKEN_COLORS);
++ }
++ else{
++ new_confline(ctmp); /* Blank line */
++ (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
++ new_confline(ctmp);
++ (*ctmp)->help = NO_HELP;
++ (*ctmp)->flags |= CF_NOSELECT;
++ (*ctmp)->value = cpystr(_(ADDINDEXTOKEN_COMMENT));
++ (*ctmp)->valoffset = COLOR_INDENT;
++ }
++
++ /*
+ * custom header colors
+ */
+ new_confline(ctmp); /* Blank line */
+***************
+*** 497,503 ****
+ new_confline(ctmp);
+ (*ctmp)->help = NO_HELP;
+ (*ctmp)->flags |= CF_NOSELECT;
+! (*ctmp)->value = cpystr(_("HEADER COLORS"));
+ new_confline(ctmp);
+ (*ctmp)->help = NO_HELP;
+ (*ctmp)->flags |= CF_NOSELECT;
+--- 519,525 ----
+ new_confline(ctmp);
+ (*ctmp)->help = NO_HELP;
+ (*ctmp)->flags |= CF_NOSELECT;
+! (*ctmp)->value = cpystr(_(HDR_COLORS));
+ new_confline(ctmp);
+ (*ctmp)->help = NO_HELP;
+ (*ctmp)->flags |= CF_NOSELECT;
+***************
+*** 526,532 ****
+
+ if(lval && lval[0] && lval[0][0]){
+ for(i = 0; lval && lval[i]; i++)
+! add_header_color_line(ps, ctmp, lval[i], i);
+ }
+ else{
+ new_confline(ctmp); /* Blank line */
+--- 548,554 ----
+
+ if(lval && lval[0] && lval[0][0]){
+ for(i = 0; lval && lval[i]; i++)
+! add_header_color_line(ps, ctmp, lval[i], i, V_VIEW_HDR_COLORS);
+ }
+ else{
+ new_confline(ctmp); /* Blank line */
+***************
+*** 696,701 ****
+--- 718,724 ----
+ char **lval, *ret = "";
+
+ if(var == &ps_global->vars[V_VIEW_HDR_COLORS]
++ || var == &ps_global->vars[V_INDEX_TOKEN_COLORS]
+ || var == &ps_global->vars[V_KW_COLORS]){
+ norm = (LVAL(var, Main) != NULL);
+ exc = (LVAL(var, ps_global->ew_for_except_vars) != NULL);
+***************
+*** 722,736 ****
+
+
+ void
+! add_header_color_line(struct pine *ps, CONF_S **ctmp, char *val, int which)
+ {
+ struct variable *vtmp;
+ SPEC_COLOR_S *hc;
+ char tmp[100+1];
+ int l;
+
+! vtmp = &ps->vars[V_VIEW_HDR_COLORS];
+! l = strlen(HEADER_WORD);
+
+ /* Blank line */
+ new_confline(ctmp);
+--- 745,765 ----
+
+
+ void
+! add_header_color_line(struct pine *ps, CONF_S **ctmp, char *val, int which, int varnum)
+ {
+ struct variable *vtmp;
+ SPEC_COLOR_S *hc;
+ char tmp[100+1];
+ int l;
+
+! hc = spec_color_from_var(val, 0);
+! if(varnum == V_INDEX_TOKEN_COLORS){
+! if(hc == NULL || hc->spec == NULL
+! || itoktype(hc->spec, FOR_INDEX) == NULL)
+! return;
+! }
+! vtmp = &ps->vars[varnum];
+! l = strlen(varnum == V_VIEW_HDR_COLORS ? HEADER_WORD : TOKEN_WORD);
+
+ /* Blank line */
+ new_confline(ctmp);
+***************
+*** 748,754 ****
+ /* which is an index into the variable list */
+ (*ctmp)->varmem = CFC_SET_COLOR(which, 0);
+
+- hc = spec_color_from_var(val, 0);
+ if(hc && hc->inherit)
+ (*ctmp)->flags = (CF_NOSELECT | CF_INHERIT);
+ else{
+--- 777,782 ----
+***************
+*** 759,765 ****
+ * with all this. It probably doesn't happen in real life.
+ */
+ utf8_snprintf(tmp, sizeof(tmp), "%s%c%.*w Color%*w %s%s",
+! HEADER_WORD,
+ (hc && hc->spec) ? (islower((unsigned char)hc->spec[0])
+ ? toupper((unsigned char)hc->spec[0])
+ : hc->spec[0]) : '?',
+--- 787,793 ----
+ * with all this. It probably doesn't happen in real life.
+ */
+ utf8_snprintf(tmp, sizeof(tmp), "%s%c%.*w Color%*w %s%s",
+! (varnum == V_VIEW_HDR_COLORS ? HEADER_WORD : TOKEN_WORD),
+ (hc && hc->spec) ? (islower((unsigned char)hc->spec[0])
+ ? toupper((unsigned char)hc->spec[0])
+ : hc->spec[0]) : '?',
+***************
+*** 1139,1144 ****
+--- 1167,1173 ----
+ return(var && var->name &&
+ (srchstr(var->name, "-foreground-color") ||
+ srchstr(var->name, "-background-color") ||
++ var == &ps->vars[V_INDEX_TOKEN_COLORS] ||
+ var == &ps->vars[V_VIEW_HDR_COLORS] ||
+ var == &ps->vars[V_KW_COLORS]));
+ }
+***************
+*** 1395,1400 ****
+--- 1424,1430 ----
+ if(hcolors)
+ free_spec_colors(&hcolors);
+
++ fix_side_effects(ps, (*cl)->var, 0);
+ set_current_color_vals(ps);
+ ClearScreen();
+ rv = ps->mangled_screen = 1;
+***************
+*** 1803,1808 ****
+--- 1833,1839 ----
+ /* get rid of all user set colors */
+ for(v = ps->vars; v->name; v++){
+ if(!color_holding_var(ps, v)
++ || v == &ps->vars[V_INDEX_TOKEN_COLORS]
+ || v == &ps->vars[V_VIEW_HDR_COLORS]
+ || v == &ps->vars[V_KW_COLORS])
+ continue;
+***************
+*** 1856,1861 ****
+--- 1887,1930 ----
+ free_spec_colors(&hcolors);
+ }
+
++ /* same for index token colors */
++ alval = ALVAL(&ps->vars[V_INDEX_TOKEN_COLORS], ew);
++ if(alval && *alval){
++ SPEC_COLOR_S *global_hcolors = NULL, *hcg;
++
++ v = &ps->vars[V_INDEX_TOKEN_COLORS];
++ if(v->global_val.l && v->global_val.l[0])
++ global_hcolors = spec_colors_from_varlist(v->global_val.l, 0);
++
++ hcolors = spec_colors_from_varlist(*alval, 0);
++ for(hc = hcolors; hc; hc = hc->next){
++ if(hc->fg)
++ fs_give((void **)&hc->fg);
++ if(hc->bg)
++ fs_give((void **)&hc->bg);
++
++ for(hcg = global_hcolors; hcg; hcg = hcg->next){
++ if(hc->spec && hcg->spec && !strucmp(hc->spec, hcg->spec)){
++ hc->fg = hcg->fg;
++ hcg->fg = NULL;
++ hc->bg = hcg->bg;
++ hcg->bg = NULL;
++ if(hc->val && !hcg->val)
++ fs_give((void **) &hc->val);
++ }
++ }
++
++ if(global_hcolors)
++ free_spec_colors(&global_hcolors);
++ }
++
++ free_list_array(alval);
++ *alval = varlist_from_spec_colors(hcolors);
++
++ if(hcolors)
++ free_spec_colors(&hcolors);
++ }
++
+ /*
+ * Same for keyword colors.
+ */
+***************
+*** 1898,1912 ****
+ rv = 1;
+ break;
+
+ case MC_ADD : /* add custom header color */
+ /* get header field name */
+ help = NO_HELP;
+ while(1){
+ i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, sizeof(sval),
+! _("Enter the name of the header field to be added: "),
+ NULL, help, NULL);
+! if(i == 0)
+ break;
+ else if(i == 1){
+ cmd_cancelled("Add");
+ cancel = 1;
+--- 1967,1989 ----
+ rv = 1;
+ break;
+
++ case MC_ADDHEADER: /* add custom index token color */
+ case MC_ADD : /* add custom header color */
+ /* get header field name */
+ help = NO_HELP;
+ while(1){
+ i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, sizeof(sval),
+! (cmd == MC_ADD ? _("Enter the name of the header field to be added: ")
+! : _("Enter the name of the index token to be added: ")),
+ NULL, help, NULL);
+! if(i == 0){
+! if(cmd == MC_ADDHEADER && itoktype(sval, FOR_INDEX) == NULL){
+! q_status_message1(SM_ORDER, 1, 3,
+! _("token \"%s\" not recognized"), sval);
+! continue;
+! }
+ break;
++ }
+ else if(i == 1){
+ cmd_cancelled("Add");
+ cancel = 1;
+***************
+*** 1937,1943 ****
+ confline = var_from_spec_color(new_hcolor);
+
+ /* add it to end of list */
+! alval = ALVAL(&ps->vars[V_VIEW_HDR_COLORS], ew);
+ if(alval){
+ /* get rid of possible empty value first */
+ if((t = *alval) && t[0] && !t[0][0] && !(t+1)[0])
+--- 2014,2020 ----
+ confline = var_from_spec_color(new_hcolor);
+
+ /* add it to end of list */
+! alval = ALVAL(&ps->vars[(cmd == MC_ADD ? V_VIEW_HDR_COLORS : V_INDEX_TOKEN_COLORS)], ew);
+ if(alval){
+ /* get rid of possible empty value first */
+ if((t = *alval) && t[0] && !t[0][0] && !(t+1)[0])
+***************
+*** 1962,1968 ****
+ ;
+
+ /* back up to the KEYWORD COLORS title line */
+! for(; ctmp && (!ctmp->value || strcmp(ctmp->value, KW_COLORS_HDR))
+ && ctmp->prev;
+ ctmp = prev_confline(ctmp))
+ ;
+--- 2039,2045 ----
+ ;
+
+ /* back up to the KEYWORD COLORS title line */
+! for(; ctmp && (!ctmp->value || strcmp(ctmp->value, (cmd == MC_ADD ? KW_COLORS_HDR : HDR_COLORS)))
+ && ctmp->prev;
+ ctmp = prev_confline(ctmp))
+ ;
+***************
+*** 2000,2006 ****
+ free_conflines(&beg);
+ }
+
+! add_header_color_line(ps, cl, confline, i);
+
+ /* be sure current is on selectable line */
+ for(; *cl && ((*cl)->flags & CF_NOSELECT); *cl = next_confline(*cl))
+--- 2077,2084 ----
+ free_conflines(&beg);
+ }
+
+! add_header_color_line(ps, cl, confline, i, cmd == MC_ADD
+! ? V_VIEW_HDR_COLORS : V_INDEX_TOKEN_COLORS);
+
+ /* be sure current is on selectable line */
+ for(; *cl && ((*cl)->flags & CF_NOSELECT); *cl = next_confline(*cl))
+***************
+*** 2012,2024 ****
+ break;
+
+ case MC_DELETE : /* delete custom header color */
+! if((*cl)->var != &ps->vars[V_VIEW_HDR_COLORS]){
+ q_status_message(SM_ORDER, 0, 2,
+ _("Can't delete this color setting"));
+ break;
+ }
+
+! if(want_to(_("Really delete header color from config"),
+ 'y', 'n', NO_HELP, WT_NORM) != 'y'){
+ cmd_cancelled("Delete");
+ return(rv);
+--- 2090,2105 ----
+ break;
+
+ case MC_DELETE : /* delete custom header color */
+! if((*cl)->var != &ps->vars[V_VIEW_HDR_COLORS]
+! && (*cl)->var != &ps->vars[V_INDEX_TOKEN_COLORS]){
+ q_status_message(SM_ORDER, 0, 2,
+ _("Can't delete this color setting"));
+ break;
+ }
+
+! if(want_to(((*cl)->var == &ps->vars[V_VIEW_HDR_COLORS]
+! ? _("Really delete header color from config")
+! : _("Really delete index token color from config")),
+ 'y', 'n', NO_HELP, WT_NORM) != 'y'){
+ cmd_cancelled("Delete");
+ return(rv);
+***************
+*** 2054,2072 ****
+ another = 0;
+ /* reset current line */
+ if(end && end->next && end->next->next &&
+! end->next->next->var == &ps->vars[V_VIEW_HDR_COLORS]){
+ *cl = end->next->next; /* next Header Color */
+ another++;
+ }
+ else if(beg && beg->prev &&
+! beg->prev->var == &ps->vars[V_VIEW_HDR_COLORS]){
+ *cl = beg->prev; /* prev Header Color */
+ another++;
+ }
+
+ /* adjust SPEC_COLOR_S index (varmem) values */
+ for(ctmp = end; ctmp; ctmp = next_confline(ctmp))
+! if(ctmp->var == &ps->vars[V_VIEW_HDR_COLORS])
+ ctmp->varmem = CFC_ICUST_DEC(ctmp);
+
+ /*
+--- 2135,2156 ----
+ another = 0;
+ /* reset current line */
+ if(end && end->next && end->next->next &&
+! end->next->next->var == &ps->vars[(*cl)->var == &ps->vars[V_VIEW_HDR_COLORS]
+! ? V_VIEW_HDR_COLORS : V_INDEX_TOKEN_COLORS]){
+ *cl = end->next->next; /* next Header Color */
+ another++;
+ }
+ else if(beg && beg->prev &&
+! beg->prev->var == &ps->vars[(*cl)->var == &ps->vars[V_VIEW_HDR_COLORS]
+! ? V_VIEW_HDR_COLORS : V_INDEX_TOKEN_COLORS]){
+ *cl = beg->prev; /* prev Header Color */
+ another++;
+ }
+
+ /* adjust SPEC_COLOR_S index (varmem) values */
+ for(ctmp = end; ctmp; ctmp = next_confline(ctmp))
+! if(ctmp->var == &ps->vars[(*cl)->var == &ps->vars[V_VIEW_HDR_COLORS]
+! ? V_VIEW_HDR_COLORS : V_INDEX_TOKEN_COLORS])
+ ctmp->varmem = CFC_ICUST_DEC(ctmp);
+
+ /*
+***************
+*** 2098,2104 ****
+
+ end->flags = CF_NOSELECT;
+ end->help = NO_HELP;
+! end->value = cpystr(_(ADDHEADER_COMMENT));
+ end->valoffset = COLOR_INDENT;
+ end->varnamep = NULL;
+ end->varmem = 0;
+--- 2182,2189 ----
+
+ end->flags = CF_NOSELECT;
+ end->help = NO_HELP;
+! end->value = cpystr((*cl)->var == &ps->vars[V_VIEW_HDR_COLORS]
+! ? _(ADDHEADER_COMMENT) : _(ADDINDEXTOKEN_COMMENT));
+ end->valoffset = COLOR_INDENT;
+ end->varnamep = NULL;
+ end->varmem = 0;
+***************
+*** 2556,2562 ****
+ OPT_SCREEN_S screen, *saved_screen;
+ CONF_S *ctmp = NULL, *first_line = NULL, *ctmpb;
+ int rv, is_index = 0, is_hdrcolor = 0, indent = 12;
+! int is_general = 0, is_keywordcol = 0;
+ char tmp[1200+1], name[1200], *p;
+ struct variable *vtmp, v;
+ int i, def;
+--- 2641,2647 ----
+ OPT_SCREEN_S screen, *saved_screen;
+ CONF_S *ctmp = NULL, *first_line = NULL, *ctmpb;
+ int rv, is_index = 0, is_hdrcolor = 0, indent = 12;
+! int is_general = 0, is_keywordcol = 0, is_idxtokcol = 0;
+ char tmp[1200+1], name[1200], *p;
+ struct variable *vtmp, v;
+ int i, def;
+***************
+*** 2567,2572 ****
+--- 2652,2659 ----
+ vtmp = (*cl)->var;
+ if(vtmp == &ps->vars[V_VIEW_HDR_COLORS])
+ is_hdrcolor++;
++ else if(vtmp == &ps->vars[V_INDEX_TOKEN_COLORS])
++ is_idxtokcol++;
+ else if(vtmp == &ps->vars[V_KW_COLORS])
+ is_keywordcol++;
+ else if(color_holding_var(ps, vtmp)){
+***************
+*** 2618,2623 ****
+--- 2705,2728 ----
+ name[i] = toupper((unsigned char) name[i]);
+ }
+ }
++ else if(is_idxtokcol){
++ char **lval;
++
++ lval = LVAL(vtmp, ew);
++ hcolors = spec_colors_from_varlist(lval, 0);
++
++ for(hc = hcolors, i = 0; hc; hc = hc->next, i++)
++ if(CFC_ICUST(*cl) == i)
++ break;
++
++ if(hc){
++ snprintf(name, sizeof(name), "%s%s", TOKEN_WORD, hc->spec);
++ name[sizeof(name)-1] = '\0';
++ i = sizeof(TOKEN_WORD) - 1;
++ if(islower((unsigned char) name[i]))
++ name[i] = toupper((unsigned char) name[i]);
++ }
++ }
+ else if(is_keywordcol){
+ char **lval;
+
+***************
+*** 2663,2669 ****
+ ctmp->flags |= (CF_STARTITEM | CF_NOSELECT);
+ ctmp->keymenu = &color_changing_keymenu;
+
+! if(is_hdrcolor){
+ char **apval;
+
+ def = !(hc && hc->fg && hc->fg[0] && hc->bg && hc->bg[0]);
+--- 2768,2774 ----
+ ctmp->flags |= (CF_STARTITEM | CF_NOSELECT);
+ ctmp->keymenu = &color_changing_keymenu;
+
+! if(is_hdrcolor || is_idxtokcol){
+ char **apval;
+
+ def = !(hc && hc->fg && hc->fg[0] && hc->bg && hc->bg[0]);
+diff -rc alpine-2.00/alpine/colorconf.h alpine-2.00.I.USE/alpine/colorconf.h
+*** alpine-2.00/alpine/colorconf.h 2007-08-16 15:25:10.000000000 -0700
+--- alpine-2.00.I.USE/alpine/colorconf.h 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 23,30 ****
+--- 23,33 ----
+
+
+ #define HEADER_WORD "Header "
++ #define TOKEN_WORD "Index Token "
+ #define KW_COLORS_HDR "KEYWORD COLORS"
++ #define HDR_COLORS "HEADER COLORS"
+ #define ADDHEADER_COMMENT N_("[ Use the AddHeader command to add colored headers in MESSAGE TEXT screen ]")
++ #define ADDINDEXTOKEN_COMMENT N_("[ Use the IndxHdr command to add colored tokens in MESSAGE INDEX screen ]")
+ #define EQ_COL 37
+
+ #define SPACE_BETWEEN_DOUBLEVARS 3
+diff -rc alpine-2.00/alpine/confscroll.c alpine-2.00.I.USE/alpine/confscroll.c
+*** alpine-2.00/alpine/confscroll.c 2008-08-21 15:14:45.000000000 -0700
+--- alpine-2.00.I.USE/alpine/confscroll.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 50,55 ****
+--- 50,56 ----
+ #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")
+***************
+*** 138,144 ****
+ 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 *);
+ int longest_feature_name(void);
+ COLOR_PAIR *sample_color(struct pine *, struct variable *);
+ COLOR_PAIR *sampleexc_color(struct pine *, struct variable *);
+--- 139,145 ----
+ 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 *, int);
+ int longest_feature_name(void);
+ COLOR_PAIR *sample_color(struct pine *, struct variable *);
+ COLOR_PAIR *sampleexc_color(struct pine *, struct variable *);
+***************
+*** 286,292 ****
+ CONF_S *ctmp;
+
+ if(!(cl && *cl &&
+! ((*cl)->var == &ps->vars[V_SORT_KEY] ||
+ standard_radio_var(ps, (*cl)->var) ||
+ (*cl)->var == startup_ptr)))
+ return;
+--- 287,294 ----
+ CONF_S *ctmp;
+
+ if(!(cl && *cl &&
+! (((*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;
+***************
+*** 462,468 ****
+ char tmp[MAXPATH+1];
+ char *utf8str;
+ UCS ch = 'x';
+! int cmd, i, j, done = 0, changes = 0;
+ int retval = 0;
+ int km_popped = 0, stay_in_col = 0;
+ struct key_menu *km = NULL;
+--- 464,470 ----
+ char tmp[MAXPATH+1];
+ char *utf8str;
+ UCS ch = 'x';
+! 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;
+***************
+*** 491,499 ****
+--- 493,504 ----
+
+ opt_screen = screen;
+ ps->mangled_screen = 1;
++ ps->resize_for_pico= 0;
+ ps->redrawer = option_screen_redrawer;
+
+ while(!done){
++ if(ps->resize_for_pico)
++ ps->mangled_screen = ps->resize_for_pico;
+ ps->user_says_cancel = 0;
+ if(km_popped){
+ km_popped--;
+***************
+*** 507,516 ****
+ ps->mangled_header = 1;
+ ps->mangled_footer = 1;
+ ps->mangled_body = 1;
+! ps->mangled_screen = 0;
+ }
+
+ /*----------- Check for new mail -----------*/
+ if(new_mail(0, NM_TIMING(ch), NM_STATUS_MSG | NM_DEFER_SORT) >= 0)
+ ps->mangled_header = 1;
+
+--- 512,522 ----
+ ps->mangled_header = 1;
+ ps->mangled_footer = 1;
+ ps->mangled_body = 1;
+! ps->mangled_screen = ps->resize_for_pico = 0;
+ }
+
+ /*----------- 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;
+
+***************
+*** 540,545 ****
+--- 546,552 ----
+ mark_status_unknown();
+ }
+
++ } /* send_immediately */
+ if(ps->mangled_footer || km != screen->current->keymenu){
+ bitmap_t bitmap;
+
+***************
+*** 611,616 ****
+--- 618,624 ----
+ }
+ }
+
++ 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 */
+***************
+*** 629,634 ****
+--- 637,650 ----
+ #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);
+
+***************
+*** 1382,1388 ****
+ break;
+ }
+ }
+!
+ screen->current = first_confline(screen->current);
+ free_conflines(&screen->current);
+ return(retval);
+--- 1398,1404 ----
+ break;
+ }
+ }
+! end:
+ screen->current = first_confline(screen->current);
+ free_conflines(&screen->current);
+ return(retval);
+***************
+*** 2426,2431 ****
+--- 2442,2450 ----
+ * 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);
+
+***************
+*** 2922,2928 ****
+ }
+
+ set_current_val((*cl)->var, TRUE, TRUE);
+! if(decode_sort(ps->VAR_SORT_KEY, &def_sort, &def_sort_rev) != -1){
+ ps->def_sort = def_sort;
+ ps->def_sort_rev = def_sort_rev;
+ }
+--- 2941,2947 ----
+ }
+
+ set_current_val((*cl)->var, TRUE, TRUE);
+! 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;
+ }
+***************
+*** 2931,2936 ****
+--- 2950,2986 ----
+ 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.");
+***************
+*** 3369,3375 ****
+ ptr = sample;
+
+ /* then the color sample */
+! if(ctmp->var == &ps->vars[V_VIEW_HDR_COLORS]){
+ SPEC_COLOR_S *hc, *hcolors;
+
+ lastc = newc = NULL;
+--- 3419,3426 ----
+ ptr = sample;
+
+ /* then the color sample */
+! if(ctmp->var == &ps->vars[V_VIEW_HDR_COLORS]
+! || ctmp->var == &ps->vars[V_INDEX_TOKEN_COLORS]){
+ SPEC_COLOR_S *hc, *hcolors;
+
+ lastc = newc = NULL;
+***************
+*** 3787,3793 ****
+ 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));
+ else if(v == &ps->vars[V_SIGNATURE_FILE])
+ return(sigfile_pretty_value(ps, cl));
+ else if(v == &ps->vars[V_USE_ONLY_DOMAIN_NAME])
+--- 3838,3846 ----
+ 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, 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])
+***************
+*** 4318,4331 ****
+
+
+ char *
+! sort_pretty_value(struct pine *ps, CONF_S *cl)
+ {
+! return(generalized_sort_pretty_value(ps, cl, 1));
+ }
+
+
+ char *
+! generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok)
+ {
+ char tmp[6*MAXPATH];
+ char *pvalnorm, *pvalexc, *pval;
+--- 4371,4384 ----
+
+
+ char *
+! sort_pretty_value(struct pine *ps, CONF_S *cl, int thread)
+ {
+! return(generalized_sort_pretty_value(ps, cl, 1, thread));
+ }
+
+
+ char *
+! generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok, int thread)
+ {
+ char tmp[6*MAXPATH];
+ char *pvalnorm, *pvalexc, *pval;
+***************
+*** 4375,4381 ****
+ }
+ else if(fixed){
+ pval = v->fixed_val.p;
+! decode_sort(pval, &var_sort, &var_sort_rev);
+ is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
+
+ utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s",
+--- 4428,4434 ----
+ }
+ else if(fixed){
+ pval = v->fixed_val.p;
+! 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",
+***************
+*** 4386,4394 ****
+ is_the_one ? " (value is fixed)" : "");
+ }
+ else if(is_set_for_this_level){
+! decode_sort(pval, &var_sort, &var_sort_rev);
+ is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
+! decode_sort(pvalexc, &exc_sort, &exc_sort_rev);
+ 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",
+--- 4439,4447 ----
+ is_the_one ? " (value is fixed)" : "");
+ }
+ else if(is_set_for_this_level){
+! 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, 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",
+***************
+*** 4406,4412 ****
+ }
+ else{
+ if(pvalexc){
+! decode_sort(pvalexc, &exc_sort, &exc_sort_rev);
+ is_the_one = (exc_sort_rev == line_sort_rev &&
+ exc_sort == line_sort);
+ utf8_snprintf(tmp, sizeof(tmp), "( ) %s%-*w%*s%s",
+--- 4459,4465 ----
+ }
+ else{
+ if(pvalexc){
+! 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",
+***************
+*** 4417,4423 ****
+ }
+ else{
+ pval = v->current_val.p;
+! decode_sort(pval, &var_sort, &var_sort_rev);
+ is_the_one = ((pval || default_ok) &&
+ var_sort_rev == line_sort_rev &&
+ var_sort == line_sort);
+--- 4470,4476 ----
+ }
+ else{
+ pval = v->current_val.p;
+! 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);
+***************
+*** 5154,5159 ****
+--- 5207,5236 ----
+ 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);
+***************
+*** 5176,5181 ****
+--- 5253,5261 ----
+
+ 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,
+***************
+*** 5489,5494 ****
+--- 5569,5580 ----
+ (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);
+***************
+*** 5538,5546 ****
+ else if(revert && var == &ps->vars[V_SORT_KEY]){
+ int def_sort_rev;
+
+! decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev);
+ ps->def_sort_rev = 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]){
+--- 5624,5638 ----
+ else if(revert && var == &ps->vars[V_SORT_KEY]){
+ int 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]){
+***************
+*** 5607,5612 ****
+--- 5699,5705 ----
+ }
+ }
+ else if(var == &ps->vars[V_KW_COLORS] ||
++ var == &ps->vars[V_INDEX_TOKEN_COLORS] ||
+ var == &ps->vars[V_IND_PLUS_FORE_COLOR] ||
+ var == &ps->vars[V_IND_IMP_FORE_COLOR] ||
+ var == &ps->vars[V_IND_DEL_FORE_COLOR] ||
+diff -rc alpine-2.00/alpine/confscroll.h alpine-2.00.I.USE/alpine/confscroll.h
+*** alpine-2.00/alpine/confscroll.h 2007-11-09 13:13:47.000000000 -0800
+--- alpine-2.00.I.USE/alpine/confscroll.h 2011-02-07 20:33:41.000000000 -0800
+***************
+*** 94,100 ****
+ 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);
+ int exclude_config_var(struct pine *, struct variable *, int);
+ int config_exit_cmd(unsigned);
+ int simple_exit_cmd(unsigned);
+--- 94,100 ----
+ 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, int);
+ int exclude_config_var(struct pine *, struct variable *, int);
+ int config_exit_cmd(unsigned);
+ int simple_exit_cmd(unsigned);
+diff -rc alpine-2.00/alpine/dispfilt.c alpine-2.00.I.USE/alpine/dispfilt.c
+*** alpine-2.00/alpine/dispfilt.c 2008-03-18 10:24:31.000000000 -0700
+--- alpine-2.00.I.USE/alpine/dispfilt.c 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 56,68 ****
+ dfilter(char *rawcmd, STORE_S *input_so, gf_io_t output_pc, FILTLIST_S *aux_filters)
+ {
+ char *status = NULL, *cmd, *resultf = NULL, *tmpfile = NULL;
+! int key = 0;
+
+! if((cmd = expand_filter_tokens(rawcmd,NULL,&tmpfile,&resultf,NULL,&key,NULL)) != NULL){
+ suspend_busy_cue();
+ #ifndef _WINDOWS
+! ps_global->mangled_screen = 1;
+! ClearScreen();
+ fflush(stdout);
+ #endif
+
+--- 56,70 ----
+ dfilter(char *rawcmd, STORE_S *input_so, gf_io_t output_pc, FILTLIST_S *aux_filters)
+ {
+ char *status = NULL, *cmd, *resultf = NULL, *tmpfile = NULL;
+! int key = 0, silent = 0;
+
+! if((cmd = expand_filter_tokens(rawcmd,NULL,&tmpfile,&resultf,NULL,&key,NULL, &silent)) != NULL){
+ suspend_busy_cue();
+ #ifndef _WINDOWS
+! if(!silent){
+! ps_global->mangled_screen = 1;
+! ClearScreen();
+! }
+ fflush(stdout);
+ #endif
+
+***************
+*** 99,105 ****
+ /* prepare the terminal in case the filter uses it */
+ if(status == NULL){
+ if((filter_pipe = open_system_pipe(cmd, NULL, NULL,
+! PIPE_USER | PIPE_RESET,
+ 0, pipe_callback, NULL)) != NULL){
+ if(close_system_pipe(&filter_pipe, NULL, pipe_callback) == 0){
+ /* pull result out of tmp file */
+--- 101,108 ----
+ /* prepare the terminal in case the filter uses it */
+ if(status == NULL){
+ if((filter_pipe = open_system_pipe(cmd, NULL, NULL,
+! PIPE_USER | (silent ? PIPE_SILENT :
+! (F_ON(F_DISABLE_TERM_RESET_DISP, ps_global) ? 0 : PIPE_RESET)),
+ 0, pipe_callback, NULL)) != NULL){
+ if(close_system_pipe(&filter_pipe, NULL, pipe_callback) == 0){
+ /* pull result out of tmp file */
+***************
+*** 130,136 ****
+ status = "Can't open display filter tmp file";
+ }
+ else if((status = gf_filter(cmd, key ? filter_session_key() : NULL,
+! input_so, output_pc, aux_filters,
+ F_ON(F_DISABLE_TERM_RESET_DISP, ps_global),
+ pipe_callback)) != NULL){
+ unsigned long ch;
+--- 133,139 ----
+ status = "Can't open display filter tmp file";
+ }
+ else if((status = gf_filter(cmd, key ? filter_session_key() : NULL,
+! input_so, output_pc, aux_filters, silent,
+ F_ON(F_DISABLE_TERM_RESET_DISP, ps_global),
+ pipe_callback)) != NULL){
+ unsigned long ch;
+***************
+*** 150,156 ****
+
+ resume_busy_cue(0);
+ #ifndef _WINDOWS
+! ClearScreen();
+ #endif
+ fs_give((void **)&cmd);
+ }
+--- 153,160 ----
+
+ resume_busy_cue(0);
+ #ifndef _WINDOWS
+! if(!silent)
+! ClearScreen();
+ #endif
+ fs_give((void **)&cmd);
+ }
+***************
+*** 165,171 ****
+ */
+ char *
+ expand_filter_tokens(char *filter, ENVELOPE *env, char **tmpf, char **resultf,
+! char **mtypef, int *key, int *hdrs)
+ {
+ char **array, **q;
+ char *bp, *cmd = NULL, *p = NULL,
+--- 169,175 ----
+ */
+ char *
+ expand_filter_tokens(char *filter, ENVELOPE *env, char **tmpf, char **resultf,
+! char **mtypef, int *key, int *hdrs, int *silent)
+ {
+ char **array, **q;
+ char *bp, *cmd = NULL, *p = NULL,
+***************
+*** 238,243 ****
+--- 242,260 ----
+ 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 */
+***************
+*** 312,317 ****
+--- 329,339 ----
+ if(hdrs)
+ *hdrs = 1;
+ }
++ else if(!strcmp(*q, "_SILENT_")){
++ (*q)[0] = '\0';
++ if(silent)
++ *silent = 1;
++ }
+ }
+
+ /* count up required length */
+***************
+*** 451,453 ****
+--- 473,535 ----
+
+ 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 -rc alpine-2.00/alpine/dispfilt.h alpine-2.00.I.USE/alpine/dispfilt.h
+*** alpine-2.00/alpine/dispfilt.h 2006-09-26 12:30:49.000000000 -0700
+--- alpine-2.00.I.USE/alpine/dispfilt.h 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 21,30 ****
+ /* exported protoypes */
+ char *dfilter(char *, STORE_S *, gf_io_t, FILTLIST_S *);
+ char *dfilter_trigger(BODY *, char *, size_t);
+! char *expand_filter_tokens(char *, ENVELOPE *, char **, char **, char **, int *, int *);
+ char *filter_session_key(void);
+ char *filter_data_file(int);
+!
+
+
+ #endif /* PINE_DISPFILT_INCLUDED */
+--- 21,30 ----
+ /* exported protoypes */
+ char *dfilter(char *, STORE_S *, gf_io_t, FILTLIST_S *);
+ 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 -rc alpine-2.00/alpine/folder.c alpine-2.00.I.USE/alpine/folder.c
+*** alpine-2.00/alpine/folder.c 2008-08-13 17:51:47.000000000 -0700
+--- alpine-2.00.I.USE/alpine/folder.c 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 77,83 ****
+ #define FLW_LIST 0x04 /* Allow for ListMode for subscribing */
+ #define FLW_UNSEEN 0x08 /* Add (unseen) */
+
+!
+
+ /*----------------------------------------------------------------------
+ The data needed to redraw the folders screen, including the case where the
+--- 77,88 ----
+ #define FLW_LIST 0x04 /* Allow for ListMode for subscribing */
+ #define FLW_UNSEEN 0x08 /* Add (unseen) */
+
+! /* folder colors */
+! #define CLR_UNSEEN 0x01 /* color folder with unseen/new messages */
+! #define CLR_FOLDER 0x02 /* color a name of folder or directory */
+! #define CLR_DIRECT 0x04 /* color a separator of a directory */
+! #define CLR_FLDRLT 0x08 /* color of explanatory text in list scrn*/
+! #define CLR_NORMAL 0x10 /* use normal color */
+
+ /*----------------------------------------------------------------------
+ The data needed to redraw the folders screen, including the case where the
+***************
+*** 173,179 ****
+ int folder_list_write_prefix(FOLDER_S *, int, gf_io_t);
+ int folder_list_write_middle(FOLDER_S *fp, CONTEXT_S *ctxt, gf_io_t pc, HANDLE_S *);
+ int folder_list_write_suffix(FOLDER_S *, int, gf_io_t);
+! int color_monitored_unseen(FOLDER_S *, int);
+ int folder_list_ith(int, CONTEXT_S *);
+ char *folder_list_center_space(char *, int);
+ HANDLE_S *folder_list_handle(FSTATE_S *, HANDLE_S *);
+--- 178,187 ----
+ int folder_list_write_prefix(FOLDER_S *, int, gf_io_t);
+ int folder_list_write_middle(FOLDER_S *fp, CONTEXT_S *ctxt, gf_io_t pc, HANDLE_S *);
+ int folder_list_write_suffix(FOLDER_S *, int, gf_io_t);
+! int color_monitored(FOLDER_S *, int, int);
+! int color_test_for_folder(char *, char *);
+! int color_write_for_folder(gf_io_t pc, int testtype);
+! int use_color_for_folder(FOLDER_S *fp);
+ int folder_list_ith(int, CONTEXT_S *);
+ char *folder_list_center_space(char *, int);
+ HANDLE_S *folder_list_handle(FSTATE_S *, HANDLE_S *);
+***************
+*** 238,244 ****
+ dprint((1, "=== folder_screen called ====\n"));
+ mailcap_free(); /* free resources we won't be using for a while */
+ ps->next_screen = SCREEN_FUN_NULL;
+!
+ /* Initialize folder state and dispatches */
+ memset(&fs, 0, sizeof(FSTATE_S));
+ fs.context = cntxt;
+--- 246,252 ----
+ 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;
+***************
+*** 335,340 ****
+--- 343,349 ----
+ pine_mail_close(*fs.cache_streamp);
+
+ ps->prev_screen = folder_screen;
++ strcpy(ps->screen_name, "unknown");
+ }
+
+
+***************
+*** 1615,1622 ****
+--- 1624,1633 ----
+ if(c_list->prev)
+ gf_puts("\n", pc); /* blank line */
+
++ color_write_for_folder(pc, CLR_FLDRLT);
+ gf_puts(repeat_char(cols, '-'), pc);
+ gf_puts("\n", pc);
++ color_write_for_folder(pc, CLR_NORMAL);
+ }
+
+ /* nickname or description */
+***************
+*** 1625,1630 ****
+--- 1636,1642 ----
+ || F_ON(F_CMBND_SUBDIR_DISP, ps_global))){
+ char buf[6*MAX_SCREEN_COLS + 1];
+
++ color_write_for_folder(pc, CLR_FLDRLT);
+ if(cols < 40){
+ snprintf(buf, sizeof(buf), "%.*s", cols,
+ strsquish(tmp_20k_buf, SIZEOF_20KBUF,
+***************
+*** 1651,1656 ****
+--- 1663,1669 ----
+
+ gf_puts(buf, pc);
+ gf_puts("\n", pc);
++ color_write_for_folder(pc, CLR_NORMAL);
+ }
+ else if(c_list->label){
+ if(utf8_width(c_list->label) > ps_global->ttyo->screen_cols)
+***************
+*** 1660,1668 ****
+--- 1673,1683 ----
+
+ lbuf[sizeof(lbuf)-1] = '\0';
+
++ color_write_for_folder(pc, CLR_FLDRLT);
+ gf_puts(folder_list_center_space(lbuf, cols), pc);
+ gf_puts(lbuf, pc);
+ gf_puts("\n", pc);
++ color_write_for_folder(pc, CLR_NORMAL);
+ }
+
+ if(c_list->comment){
+***************
+*** 1673,1681 ****
+--- 1688,1698 ----
+
+ lbuf[sizeof(lbuf)-1] = '\0';
+
++ color_write_for_folder(pc, CLR_FLDRLT);
+ gf_puts(folder_list_center_space(lbuf, cols), pc);
+ gf_puts(lbuf, pc);
+ gf_puts("\n", pc);
++ color_write_for_folder(pc, CLR_NORMAL);
+ }
+
+ if(c_list->dir->desc){
+***************
+*** 1684,1692 ****
+--- 1701,1711 ----
+ strncpy(buf, strsquish(tmp_20k_buf,SIZEOF_20KBUF,c_list->dir->desc,cols),
+ sizeof(buf)-1);
+ buf[sizeof(buf)-1] = '\0';
++ color_write_for_folder(pc, CLR_FLDRLT);
+ gf_puts(folder_list_center_space(buf, cols), pc);
+ gf_puts(buf, pc);
+ gf_puts("\n", pc);
++ color_write_for_folder(pc, CLR_NORMAL);
+ }
+
+ if(c_list->use & CNTXT_ZOOM){
+***************
+*** 1703,1720 ****
+--- 1722,1744 ----
+
+ lbuf[sizeof(lbuf)-1] = '\0';
+
++ color_write_for_folder(pc, CLR_FLDRLT);
+ gf_puts(folder_list_center_space(lbuf, cols), pc);
+ gf_puts(lbuf, pc);
+ gf_puts("\n", pc);
++ color_write_for_folder(pc, CLR_NORMAL);
+ }
+
++ color_write_for_folder(pc, CLR_FLDRLT);
+ gf_puts(repeat_char(cols, '-'), pc);
+ gf_puts("\n\n", pc);
++ color_write_for_folder(pc, CLR_NORMAL);
+ }
+
+ if(shown){
+ /* Run thru list formatting as necessary */
+ if((ftotal = folder_total(FOLDERS(c_list))) != 0){
++ int use_color;
+ /* If previously selected, mark members of new list */
+ selected = selected_folders(c_list);
+
+***************
+*** 1729,1738 ****
+ continue;
+
+ fcount++;
+!
+ width = utf8_width(FLDR_NAME(f));
+ if(f->isdir)
+! width += (f->isfolder) ? 3 : 1;
+
+ if(NEWS_TEST(c_list) && (c_list->use & CNTXT_FINDALL))
+ /* assume listmode so we don't have to reformat */
+--- 1753,1762 ----
+ continue;
+
+ fcount++;
+! use_color = use_color_for_folder(f);
+ width = utf8_width(FLDR_NAME(f));
+ if(f->isdir)
+! width += (f->isfolder) ? (use_color ? 1 : 3) : (use_color ? 0 : 1);
+
+ if(NEWS_TEST(c_list) && (c_list->use & CNTXT_FINDALL))
+ /* assume listmode so we don't have to reformat */
+***************
+*** 1866,1874 ****
+--- 1890,1900 ----
+
+ lbuf[sizeof(lbuf)-1] = '\0';
+
++ color_write_for_folder(pc, CLR_FLDRLT);
+ gf_puts(folder_list_center_space(lbuf, cols), pc);
+ (void) folder_list_write(pc, handlesp, c_list, -1, lbuf,
+ (handlesp) ? FLW_LUNK : FLW_NONE);
++ color_write_for_folder(pc, CLR_NORMAL);
+ }
+ }
+ else if(fp->fs->combined_view
+***************
+*** 1883,1891 ****
+--- 1909,1919 ----
+
+ lbuf[sizeof(lbuf)-1] = '\0';
+
++ color_write_for_folder(pc, CLR_FLDRLT);
+ gf_puts(folder_list_center_space(lbuf, cols), pc);
+ (void) folder_list_write(pc, handlesp, c_list, -1, lbuf,
+ (handlesp) ? FLW_LUNK : FLW_NONE);
++ color_write_for_folder(pc, CLR_NORMAL);
+ }
+
+ gf_puts("\n", pc); /* blank line */
+***************
+*** 1932,1948 ****
+
+ if(h1){
+ /* color unseen? */
+! if(color_monitored_unseen(fp, flags)){
+ h1->color_unseen = 1;
+ if(h2)
+ h2->color_unseen = 1;
+ }
+ }
+
+ /* embed handle pointer */
+! if(((h1 && h1->color_unseen) ?
+! gf_puts(color_embed(ps_global->VAR_INCUNSEEN_FORE_COLOR,
+! ps_global->VAR_INCUNSEEN_BACK_COLOR), pc) : 1)
+ && (h1 ? ((*pc)(TAG_EMBED) && (*pc)(TAG_HANDLE)
+ && (*pc)(strlen(buf)) && gf_puts(buf, pc)) : 1)
+ && (fp ? ((lprefix = folder_list_write_prefix(fp, flags, pc)) >= 0
+--- 1960,1983 ----
+
+ if(h1){
+ /* color unseen? */
+! if(color_monitored(fp, flags, CLR_UNSEEN)){
+ h1->color_unseen = 1;
+ if(h2)
+ h2->color_unseen = 1;
+ }
++ /* color folder? */
++ if(color_monitored(fp, flags, CLR_FOLDER)){
++ h1->color_folder = 1;
++ if(h2)
++ h2->color_folder = 1;
++ }
+ }
+
+ /* embed handle pointer */
+! if(((h1 && h1->color_unseen) ? color_write_for_folder(pc, CLR_UNSEEN)
+! : ((h1 && h1->color_folder)
+! ? color_write_for_folder(pc, fp->isfolder ? CLR_FOLDER : CLR_DIRECT)
+! : 1))
+ && (h1 ? ((*pc)(TAG_EMBED) && (*pc)(TAG_HANDLE)
+ && (*pc)(strlen(buf)) && gf_puts(buf, pc)) : 1)
+ && (fp ? ((lprefix = folder_list_write_prefix(fp, flags, pc)) >= 0
+***************
+*** 1951,1959 ****
+ : (alt_name ? gf_puts(alt_name, pc) : 0))
+ && (h1 ? ((*pc)(TAG_EMBED) && (*pc)(TAG_BOLDOFF)
+ && (*pc)(TAG_EMBED) && (*pc)(TAG_INVOFF)) : 1)
+! && ((h1 && h1->color_unseen) ?
+! gf_puts(color_embed(ps_global->VAR_NORM_FORE_COLOR,
+! ps_global->VAR_NORM_BACK_COLOR), pc) : 1)){
+ if(fp)
+ width = lprefix + lmiddle + lsuffix;
+ else if(alt_name)
+--- 1986,1993 ----
+ : (alt_name ? gf_puts(alt_name, pc) : 0))
+ && (h1 ? ((*pc)(TAG_EMBED) && (*pc)(TAG_BOLDOFF)
+ && (*pc)(TAG_EMBED) && (*pc)(TAG_INVOFF)) : 1)
+! && ((h1 && (h1->color_unseen || h1->color_folder)) ?
+! color_write_for_folder(pc, CLR_NORMAL): 1)){
+ if(fp)
+ width = lprefix + lmiddle + lsuffix;
+ else if(alt_name)
+***************
+*** 1992,2002 ****
+ return(rv);
+ }
+
+-
+ int
+ folder_list_write_middle(FOLDER_S *fp, CONTEXT_S *ctxt, gf_io_t pc, HANDLE_S *h2)
+ {
+! int rv = -1;
+ char buf[256];
+
+ if(h2){
+--- 2026,2035 ----
+ return(rv);
+ }
+
+ int
+ folder_list_write_middle(FOLDER_S *fp, CONTEXT_S *ctxt, gf_io_t pc, HANDLE_S *h2)
+ {
+! int rv = -1, use_color;
+ char buf[256];
+
+ if(h2){
+***************
+*** 2007,2023 ****
+ if(!fp)
+ return(rv);
+
+ if(gf_puts(FLDR_NAME(fp), pc)
+ && (h2 ? ((*pc)(TAG_EMBED) && (*pc)(TAG_BOLDOFF) /* tie off handle 1 */
+ && (*pc)(TAG_EMBED) && (*pc)(TAG_INVOFF)) : 1)
+ && (h2 ? ((*pc)(TAG_EMBED) && (*pc)(TAG_HANDLE) /* start handle 2 */
+ && (*pc)(strlen(buf)) && gf_puts(buf, pc)) : 1)
+! && ((fp->isdir && fp->isfolder) ? (*pc)('[') : 1)
+! && ((fp->isdir) ? (*pc)(ctxt->dir->delim) : 1)
+! && ((fp->isdir && fp->isfolder) ? (*pc)(']') : 1)){
+ rv = utf8_width(FLDR_NAME(fp));
+ if(fp->isdir)
+! rv += (fp->isfolder) ? 3 : 1;
+ }
+
+ return(rv);
+--- 2040,2062 ----
+ if(!fp)
+ return(rv);
+
++ use_color = use_color_for_folder(fp);
++
+ if(gf_puts(FLDR_NAME(fp), pc)
+ && (h2 ? ((*pc)(TAG_EMBED) && (*pc)(TAG_BOLDOFF) /* tie off handle 1 */
+ && (*pc)(TAG_EMBED) && (*pc)(TAG_INVOFF)) : 1)
++ && ((use_color && fp->isdir && fp->isfolder)
++ ? color_write_for_folder(pc, CLR_DIRECT) : 1)
+ && (h2 ? ((*pc)(TAG_EMBED) && (*pc)(TAG_HANDLE) /* start handle 2 */
+ && (*pc)(strlen(buf)) && gf_puts(buf, pc)) : 1)
+! && use_color
+! ? (fp->isdir && fp->isfolder ? (*pc)(ctxt->dir->delim) : 1)
+! : (((fp->isdir && fp->isfolder) ? (*pc)('[') : 1)
+! && ((fp->isdir) ? (*pc)(ctxt->dir->delim) : 1)
+! && ((fp->isdir && fp->isfolder) ? (*pc)(']') : 1))){
+ rv = utf8_width(FLDR_NAME(fp));
+ if(fp->isdir)
+! rv += (fp->isfolder) ? (use_color ? 1 : 3) : (use_color ? 0 : 1);
+ }
+
+ return(rv);
+***************
+*** 2065,2084 ****
+ return(rv);
+ }
+
+
+ int
+! color_monitored_unseen(FOLDER_S *f, int flags)
+ {
+! return((flags & FLW_UNSEEN) && f && f->unseen_valid
+ && ((F_ON(F_INCOMING_CHECKING_RECENT, ps_global) && f->new > 0L)
+ || (F_OFF(F_INCOMING_CHECKING_RECENT, ps_global) && f->unseen > 0L))
+! && pico_usingcolor()
+! && pico_is_good_color(ps_global->VAR_INCUNSEEN_FORE_COLOR)
+! && pico_is_good_color(ps_global->VAR_INCUNSEEN_BACK_COLOR)
+! && (colorcmp(ps_global->VAR_INCUNSEEN_FORE_COLOR,
+! ps_global->VAR_NORM_FORE_COLOR)
+! || colorcmp(ps_global->VAR_INCUNSEEN_BACK_COLOR,
+! ps_global->VAR_NORM_BACK_COLOR)));
+ }
+
+
+--- 2104,2188 ----
+ return(rv);
+ }
+
++ int
++ color_write_for_folder(gf_io_t pc, int testtype)
++ {
++ int rv;
++ if(!pico_usingcolor())
++ return 1;
++ switch (testtype){
++ case CLR_UNSEEN:
++ rv = gf_puts(color_embed(ps_global->VAR_INCUNSEEN_FORE_COLOR,
++ ps_global->VAR_INCUNSEEN_BACK_COLOR), pc);
++ break;
++ case CLR_FOLDER:
++ rv = gf_puts(color_embed(ps_global->VAR_FOLDER_FORE_COLOR,
++ ps_global->VAR_FOLDER_BACK_COLOR ), pc);
++ break;
++ case CLR_FLDRLT:
++ rv = gf_puts(color_embed(ps_global->VAR_FOLDER_LIST_FORE_COLOR,
++ ps_global->VAR_FOLDER_LIST_BACK_COLOR ), pc);
++ break;
++ case CLR_DIRECT:
++ rv = gf_puts(color_embed(ps_global->VAR_DIRECTORY_FORE_COLOR,
++ ps_global->VAR_DIRECTORY_BACK_COLOR), pc);
++ break;
++ case CLR_NORMAL:
++ rv = gf_puts(color_embed(ps_global->VAR_NORM_FORE_COLOR,
++ ps_global->VAR_NORM_BACK_COLOR), pc);
++ break;
++ default:
++ rv = 0; /* fail */
++ break;
++ }
++ return rv;
++ }
++
+
+ int
+! color_test_for_folder(char *color_fore, char *color_back)
+ {
+! return pico_usingcolor()
+! && pico_is_good_color(color_fore)
+! && pico_is_good_color(color_back)
+! && (colorcmp(color_fore, ps_global->VAR_NORM_FORE_COLOR)
+! || colorcmp(color_back,
+! ps_global->VAR_NORM_BACK_COLOR)) ? 1 : 0;
+!
+! }
+!
+!
+! int
+! use_color_for_folder(FOLDER_S *fp)
+! {
+! int test1, test2;
+! if(fp->isdir)
+! test1 = color_test_for_folder(ps_global->VAR_DIRECTORY_FORE_COLOR,
+! ps_global->VAR_DIRECTORY_BACK_COLOR);
+! if(fp->isfolder)
+! test2 = color_test_for_folder(ps_global->VAR_FOLDER_FORE_COLOR,
+! ps_global->VAR_FOLDER_BACK_COLOR);
+! return (fp->isdir && fp->isfolder) ? test1 + test2
+! : (fp->isdir ? test1 : (fp->isfolder? test2 : 0));
+! }
+!
+!
+! int
+! color_monitored(FOLDER_S *f, int flags, int testtype)
+! {
+! int rv;
+! switch(testtype){
+! case CLR_UNSEEN: rv = (flags & FLW_UNSEEN) && f && f->unseen_valid
+ && ((F_ON(F_INCOMING_CHECKING_RECENT, ps_global) && f->new > 0L)
+ || (F_OFF(F_INCOMING_CHECKING_RECENT, ps_global) && f->unseen > 0L))
+! && color_test_for_folder(ps_global->VAR_INCUNSEEN_FORE_COLOR,
+! ps_global->VAR_INCUNSEEN_BACK_COLOR) ? 1 : 0;
+! break;
+! case CLR_FOLDER: rv = f ? use_color_for_folder(f) : 0;
+! break;
+! default: rv = 0;
+! }
+! return rv;
+ }
+
+
+***************
+*** 6223,6233 ****
+ 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;
+ char prompt[128];
+ FOLDER_S *f = NULL;
+ char tmp[MAILTMPLEN];
+!
+
+ /* note: find_folders may assign "stream" */
+ build_folder_list(streamp, cntxt, NULL, NULL,
+--- 6327,6343 ----
+ 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, 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,
+***************
+*** 6238,6244 ****
+ if(find_recent)
+ *find_recent = 0L;
+
+! for(index = folder_index(current, cntxt, FI_FOLDER) + 1;
+ index > 0
+ && index < folder_total(FOLDERS(cntxt))
+ && (f = folder_entry(index, FOLDERS(cntxt)))
+--- 6348,6356 ----
+ if(find_recent)
+ *find_recent = 0L;
+
+!
+! 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)))
+***************
+*** 6249,6254 ****
+--- 6361,6371 ----
+ 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)))
+***************
+*** 6416,6427 ****
+--- 6533,6556 ----
+ 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 -rc alpine-2.00/alpine/help.c alpine-2.00.I.USE/alpine/help.c
+*** alpine-2.00/alpine/help.c 2008-04-10 09:50:54.000000000 -0700
+--- alpine-2.00.I.USE/alpine/help.c 2011-02-07 20:33:44.000000000 -0800
+***************
+*** 390,395 ****
+--- 390,396 ----
+ {
+ int rv = 0;
+ char message[64];
++ struct help_texts *t;
+
+ switch(cmd){
+ /*----------- Print all the help ------------*/
+***************
+*** 407,412 ****
+--- 408,430 ----
+
+ break;
+
++ case MC_EXPORT: /* reuse old definition, so as not to patch pine.h */
++ {char help_name[40];
++ help_name[0] = '\0';
++ for(t = h_texts; t->help_text != NO_HELP; t++)
++ if(t->help_text == ((HELP_SCROLL_S *)sparms->proc.data.p)->help_source){
++ strcpy(help_name,t->tag);
++ break;
++ }
++ if(help_name[0])
++ q_status_message1(SM_ORDER, 0, 2,
++ "Internal Name: x-alpine-help:%s", help_name);
++ else
++ q_status_message(SM_ORDER|SM_DING, 1, 2,
++ "Can not find link for text help");
++ }
++ break;
++
+ case MC_FINISH :
+ rv = 1;
+ break;
+***************
+*** 572,578 ****
+ int
+ url_local_helper(char *url)
+ {
+! if(!struncmp(url, "x-alpine-help:", 14) && *(url += 14)){
+ char *frag;
+ HelpType newhelp;
+
+--- 590,597 ----
+ int
+ url_local_helper(char *url)
+ {
+! if((!struncmp(url, "x-alpine-help:", 14) && *(url += 14))
+! || (!struncmp(url, "x-pine-help:", 12) && *(url += 12))){
+ char *frag;
+ HelpType newhelp;
+
+diff -rc alpine-2.00/alpine/imap.c alpine-2.00.I.USE/alpine/imap.c
+*** alpine-2.00/alpine/imap.c 2008-04-10 14:26:20.000000000 -0700
+--- alpine-2.00.I.USE/alpine/imap.c 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 94,100 ****
+ * Internal prototypes
+ */
+ void mm_login_alt_cue(NETMBX *);
+! long pine_tcptimeout_noscreen(long, long);
+ int answer_cert_failure(int, MSGNO_S *, SCROLL_S *);
+
+ #ifdef LOCAL_PASSWD_CACHE
+--- 94,100 ----
+ * Internal prototypes
+ */
+ void mm_login_alt_cue(NETMBX *);
+! long pine_tcptimeout_noscreen(long, long, char *);
+ int answer_cert_failure(int, MSGNO_S *, SCROLL_S *);
+
+ #ifdef LOCAL_PASSWD_CACHE
+***************
+*** 350,355 ****
+--- 350,356 ----
+ HelpType help ;
+ int len, rc, q_line, flags;
+ int oespace, avail, need, save_dont_use;
++ int save_in_init;
+ struct servent *sv;
+ #if defined(_WINDOWS) || defined(LOCAL_PASSWD_CACHE)
+ int preserve_password = -1;
+***************
+*** 364,369 ****
+--- 365,372 ----
+ altuserforcache ? altuserforcache : ""));
+ q_line = -(ps_global->ttyo ? ps_global->ttyo->footer_rows : 3);
+
++ save_in_init = ps_global->in_init_seq;
++ ps_global->in_init_seq = 0;
+ ps_global->no_newmail_check_from_optionally_enter = 1;
+
+ /* make sure errors are seen */
+***************
+*** 440,448 ****
+
+ /* try last working password associated with this host. */
+ if(imap_get_passwd(mm_login_list, pwd, user, hostlist,
+! (mb->sslflag||mb->tlsflag))){
+ dprint((9, "mm_login: found a password to try\n"));
+ ps_global->no_newmail_check_from_optionally_enter = 0;
+ return;
+ }
+
+--- 443,452 ----
+
+ /* try last working password associated with this host. */
+ if(imap_get_passwd(mm_login_list, pwd, user, hostlist,
+! (mb->sslflag||mb->tlsflag)) && pwd[0] != '\0'){
+ dprint((9, "mm_login: found a password to try\n"));
+ ps_global->no_newmail_check_from_optionally_enter = 0;
++ ps_global->in_init_seq = save_in_init;
+ return;
+ }
+
+***************
+*** 456,461 ****
+--- 460,466 ----
+ (mb->sslflag||mb->tlsflag));
+ dprint((9, "mm_login: found a password in passfile to try\n"));
+ ps_global->no_newmail_check_from_optionally_enter = 0;
++ ps_global->in_init_seq = save_in_init;
+ return;
+ }
+ #endif /* LOCAL_PASSWD_CACHE */
+***************
+*** 484,489 ****
+--- 489,495 ----
+ "mm_login: found a password for user=%s to try\n",
+ user ? user : "?"));
+ ps_global->no_newmail_check_from_optionally_enter = 0;
++ ps_global->in_init_seq = save_in_init;
+ return;
+ }
+
+***************
+*** 499,504 ****
+--- 505,511 ----
+ "mm_login: found a password for user=%s in passfile to try\n",
+ user ? user : "?"));
+ ps_global->no_newmail_check_from_optionally_enter = 0;
++ ps_global->in_init_seq = save_in_init;
+ return;
+ }
+ #endif /* LOCAL_PASSWD_CACHE */
+***************
+*** 519,524 ****
+--- 526,532 ----
+ (mb->sslflag||mb->tlsflag))){
+ dprint((9, "mm_login:ui: found a password to try\n"));
+ ps_global->no_newmail_check_from_optionally_enter = 0;
++ ps_global->in_init_seq = save_in_init;
+ return;
+ }
+
+***************
+*** 532,537 ****
+--- 540,546 ----
+ (mb->sslflag||mb->tlsflag));
+ dprint((9, "mm_login:ui: found a password in passfile to try\n"));
+ ps_global->no_newmail_check_from_optionally_enter = 0;
++ ps_global->in_init_seq = save_in_init;
+ return;
+ }
+ #endif /* LOCAL_PASSWD_CACHE */
+***************
+*** 750,755 ****
+--- 759,765 ----
+
+ if(!(user[0] || altuserforcache)){
+ ps_global->no_newmail_check_from_optionally_enter = 0;
++ ps_global->in_init_seq = save_in_init;
+ return;
+ }
+
+***************
+*** 762,767 ****
+--- 772,778 ----
+ if(imap_get_passwd(mm_login_list, pwd, user, hostlist,
+ (mb->sslflag||mb->tlsflag))){
+ ps_global->no_newmail_check_from_optionally_enter = 0;
++ ps_global->in_init_seq = save_in_init;
+ return;
+ }
+
+***************
+*** 771,776 ****
+--- 782,788 ----
+ imap_set_passwd(&mm_login_list, pwd, user,
+ hostlist, (mb->sslflag||mb->tlsflag), 0, 0);
+ ps_global->no_newmail_check_from_optionally_enter = 0;
++ ps_global->in_init_seq = save_in_init;
+ return;
+ }
+ #endif /* LOCAL_PASSWD_CACHE */
+***************
+*** 779,784 ****
+--- 791,797 ----
+ if(imap_get_passwd(mm_login_list, pwd, altuserforcache, hostlist,
+ (mb->sslflag||mb->tlsflag))){
+ ps_global->no_newmail_check_from_optionally_enter = 0;
++ ps_global->in_init_seq = save_in_init;
+ return;
+ }
+
+***************
+*** 788,793 ****
+--- 801,807 ----
+ imap_set_passwd(&mm_login_list, pwd, altuserforcache,
+ hostlist, (mb->sslflag||mb->tlsflag), 0, 0);
+ ps_global->no_newmail_check_from_optionally_enter = 0;
++ ps_global->in_init_seq = save_in_init;
+ return;
+ }
+ #endif /* LOCAL_PASSWD_CACHE */
+***************
+*** 976,981 ****
+--- 990,996 ----
+ ps_global->user_says_cancel = (rc == 1);
+ user[0] = pwd[0] = '\0';
+ ps_global->no_newmail_check_from_optionally_enter = 0;
++ ps_global->in_init_seq = save_in_init;
+ return;
+ }
+
+***************
+*** 1181,1187 ****
+
+
+ long
+! pine_tcptimeout_noscreen(long int elapsed, long int sincelast)
+ {
+ long rv = 1L;
+ char pmt[128];
+--- 1196,1202 ----
+
+
+ long
+! pine_tcptimeout_noscreen(long int elapsed, long int sincelast, char *host)
+ {
+ long rv = 1L;
+ char pmt[128];
+***************
+*** 1192,1199 ****
+
+ if(elapsed >= (long)ps_global->tcp_query_timeout){
+ snprintf(pmt, sizeof(pmt),
+! _("Waited %s seconds for server reply. Break connection to server"),
+! long2string(elapsed));
+ pmt[sizeof(pmt)-1] = '\0';
+ if(want_to(pmt, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
+ ps_global->user_says_cancel = 1;
+--- 1207,1214 ----
+
+ if(elapsed >= (long)ps_global->tcp_query_timeout){
+ snprintf(pmt, sizeof(pmt),
+! _("No reply in %s seconds from server %s. Break connection"),
+! long2string(elapsed), host);
+ pmt[sizeof(pmt)-1] = '\0';
+ if(want_to(pmt, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
+ ps_global->user_says_cancel = 1;
+***************
+*** 1216,1222 ****
+ * pine_tcptimeout - C-client callback to handle tcp-related timeouts.
+ */
+ long
+! pine_tcptimeout(long int elapsed, long int sincelast)
+ {
+ long rv = 1L; /* keep trying by default */
+ unsigned long ch;
+--- 1231,1237 ----
+ * pine_tcptimeout - C-client callback to handle tcp-related timeouts.
+ */
+ long
+! pine_tcptimeout(long int elapsed, long int sincelast, char *host)
+ {
+ long rv = 1L; /* keep trying by default */
+ unsigned long ch;
+***************
+*** 1236,1242 ****
+ return(rv);
+
+ if(!ps_global->ttyo)
+! return(pine_tcptimeout_noscreen(elapsed, sincelast));
+
+ suspend_busy_cue();
+
+--- 1251,1257 ----
+ return(rv);
+
+ if(!ps_global->ttyo)
+! return(pine_tcptimeout_noscreen(elapsed, sincelast, host));
+
+ suspend_busy_cue();
+
+***************
+*** 1253,1261 ****
+
+ Writechar(BELL, 0);
+
+! PutLine1(ps_global->ttyo->screen_rows - FOOTER_ROWS(ps_global), 0,
+! _("Waited %s seconds for server reply. Break connection to server? "),
+! long2string(elapsed));
+ CleartoEOLN();
+ fflush(stdout);
+ flush_input();
+--- 1268,1276 ----
+
+ Writechar(BELL, 0);
+
+! PutLine2(ps_global->ttyo->screen_rows - FOOTER_ROWS(ps_global), 0,
+! _("No reply in %s seconds from server %s. Break connection?"),
+! long2string(elapsed), host);
+ CleartoEOLN();
+ fflush(stdout);
+ flush_input();
+***************
+*** 1272,1280 ****
+ }
+
+ if(rv == 1L){ /* just warn 'em something's up */
+! q_status_message1(SM_ORDER, 0, 0,
+! _("Waited %s seconds for server reply. Still Waiting..."),
+! long2string(elapsed));
+ flush_status_messages(0); /* make sure it's seen */
+ }
+
+--- 1287,1295 ----
+ }
+
+ if(rv == 1L){ /* just warn 'em something's up */
+! q_status_message2(SM_ORDER, 0, 0,
+! _("No reply in %s seconds from server %s. Still Waiting..."),
+! long2string(elapsed), host);
+ flush_status_messages(0); /* make sure it's seen */
+ }
+
+***************
+*** 1285,1290 ****
+--- 1300,1335 ----
+ return(rv);
+ }
+
++ QUOTALIST *pine_quotalist_copy (pquota)
++ QUOTALIST *pquota;
++ {
++ QUOTALIST *cquota = NULL;
++
++ if(pquota){
++ cquota = mail_newquotalist();
++ if (pquota->name && *pquota->name){
++ cquota->name = (char *) fs_get((strlen(pquota->name) + 1)*sizeof(char));
++ cquota->name = cpystr(pquota->name);
++ }
++ cquota->usage = pquota->usage;
++ cquota->limit = pquota->limit;
++ if (pquota->next)
++ cquota->next = pine_quotalist_copy(pquota->next);
++ }
++ return cquota;
++ }
++
++
++ /* C-client callback to handle quota */
++
++ void
++ pine_parse_quota (stream, msg, pquota)
++ MAILSTREAM *stream;
++ unsigned char *msg;
++ QUOTALIST *pquota;
++ {
++ ps_global->quota = pine_quotalist_copy (pquota);
++ }
+
+ /*
+ * C-client callback to handle SSL/TLS certificate validation failures
+diff -rc alpine-2.00/alpine/imap.h alpine-2.00.I.USE/alpine/imap.h
+*** alpine-2.00/alpine/imap.h 2008-04-23 19:00:26.000000000 -0700
+--- alpine-2.00.I.USE/alpine/imap.h 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 21,28 ****
+
+
+ /* exported protoypes */
+ void *pine_block_notify(int, void *);
+! long pine_tcptimeout(long, long);
+ long pine_sslcertquery(char *, char *, char *);
+ char *pine_newsrcquery(MAILSTREAM *, char *, char *);
+ int url_local_certdetails(char *);
+--- 21,30 ----
+
+
+ /* exported protoypes */
++ void pine_parse_quota (MAILSTREAM *, unsigned char *, QUOTALIST *);
++ QUOTALIST *pine_quotalist_copy (QUOTALIST *);
+ void *pine_block_notify(int, void *);
+! long pine_tcptimeout(long, long, char *);
+ long pine_sslcertquery(char *, char *, char *);
+ char *pine_newsrcquery(MAILSTREAM *, char *, char *);
+ int url_local_certdetails(char *);
+diff -rc alpine-2.00/alpine/keymenu.c alpine-2.00.I.USE/alpine/keymenu.c
+*** alpine-2.00/alpine/keymenu.c 2008-06-03 08:54:15.000000000 -0700
+--- alpine-2.00.I.USE/alpine/keymenu.c 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 314,319 ****
+--- 314,333 ----
+ WHEREIS_MENU};
+ INST_KEY_MENU(c_fcc_km, context_fcc_keys);
+
++ static struct key quota_keys[] =
++ {HELP_MENU,
++ NULL_MENU,
++ {"E","Exit",{MC_EXIT,3,{'e','i',ctrl('C')}},KS_EXITMODE},
++ NULL_MENU,
++ NULL_MENU,
++ NULL_MENU,
++ NULL_MENU,
++ NULL_MENU,
++ NULL_MENU,
++ NULL_MENU,
++ NULL_MENU,
++ NULL_MENU};
++ INST_KEY_MENU(pine_quota_keymenu, quota_keys);
+
+ struct key folder_keys[] =
+ {HELP_MENU,
+***************
+*** 482,488 ****
+ NEXTPAGE_MENU,
+ PRYNTMSG_MENU,
+ {"Z",N_("Print All"),{MC_PRINTALL,1,{'z'}},KS_NONE},
+! NULL_MENU,
+ WHEREIS_MENU,
+
+ HELP_MENU,
+--- 496,502 ----
+ NEXTPAGE_MENU,
+ PRYNTMSG_MENU,
+ {"Z",N_("Print All"),{MC_PRINTALL,1,{'z'}},KS_NONE},
+! {"N",N_("Name"),{MC_EXPORT,1,{'n'}},KS_NONE},
+ WHEREIS_MENU,
+
+ HELP_MENU,
+***************
+*** 650,661 ****
+ RCOMPOSE_MENU,
+ HOMEKEY_MENU,
+ ENDKEY_MENU,
+! NULL_MENU,
+ /* TRANSLATORS: toggles a collapsed view or an expanded view
+ of a message thread on and off */
+ {"/",N_("Collapse/Expand"),{MC_COLLAPSE,1,{'/'}},KS_NONE},
+! NULL_MENU,
+ NULL_MENU};
+ INST_KEY_MENU(index_keymenu, index_keys);
+
+
+--- 664,691 ----
+ RCOMPOSE_MENU,
+ HOMEKEY_MENU,
+ ENDKEY_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},
+! {"^D","Delete Thr",{MC_DELTHREAD,1,{ctrl('D')}},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,736 ****
+ RCOMPOSE_MENU,
+ HOMEKEY_MENU,
+ ENDKEY_MENU,
+! NULL_MENU,
+ {"/",N_("Collapse/Expand"),{MC_COLLAPSE,1,{'/'}},KS_NONE},
+ NULL_MENU,
+ NULL_MENU};
+ INST_KEY_MENU(thread_keymenu, thread_keys);
+
+--- 758,779 ----
+ RCOMPOSE_MENU,
+ HOMEKEY_MENU,
+ ENDKEY_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,
++ {"^D",N_("Delete Thread"),{MC_DELTHREAD,1,{ctrl('D')}},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,886 ****
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+! NULL_MENU};
+ INST_KEY_MENU(view_keymenu, view_keys);
+
+
+--- 923,942 ----
+ 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},
+! {"^D",N_("Delete Thread"),{MC_DELTHREAD,1,{ctrl('D')}},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);
+
+
+***************
+*** 2452,2458 ****
+
+ HELP_MENU,
+ OTHER_MENU,
+! NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+--- 2508,2514 ----
+
+ HELP_MENU,
+ OTHER_MENU,
+! {"I", N_("IndxHdr"), {MC_ADDHEADER,1,{'i'}}, KS_NONE},
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+***************
+*** 2481,2487 ****
+
+ HELP_MENU,
+ OTHER_MENU,
+! NULL_MENU,
+ NULL_MENU,
+ {"D", N_("DeleteHdr"), {MC_DELETE,1,{'d'}}, KS_NONE},
+ /* TRANSLATORS: shuffle headers (change the order of headers) */
+--- 2537,2543 ----
+
+ HELP_MENU,
+ OTHER_MENU,
+! {"I", N_("IndxHdr"), {MC_ADDHEADER,1,{'i'}}, KS_NONE},
+ NULL_MENU,
+ {"D", N_("DeleteHdr"), {MC_DELETE,1,{'d'}}, KS_NONE},
+ /* TRANSLATORS: shuffle headers (change the order of headers) */
+***************
+*** 2527,2533 ****
+
+ HELP_MENU,
+ OTHER_MENU,
+! NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+--- 2583,2589 ----
+
+ HELP_MENU,
+ OTHER_MENU,
+! {"I", N_("IndxHdr"), {MC_ADDHEADER,1,{'i'}}, KS_NONE},
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+diff -rc alpine-2.00/alpine/keymenu.h alpine-2.00.I.USE/alpine/keymenu.h
+*** alpine-2.00/alpine/keymenu.h 2008-06-03 08:54:15.000000000 -0700
+--- alpine-2.00.I.USE/alpine/keymenu.h 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 212,218 ****
+ #define MC_COLLAPSE 800
+ #define MC_CHK_RECENT 801
+ #define MC_DECRYPT 802
+!
+
+ /*
+ * Some standard Key/Command Bindings
+--- 212,232 ----
+ #define MC_COLLAPSE 800
+ #define MC_CHK_RECENT 801
+ #define MC_DECRYPT 802
+! #define MC_CTHREAD 803
+! #define MC_OTHREAD 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_QUOTA 816
+! #define MC_ADDHEADER 817
+
+ /*
+ * Some standard Key/Command Bindings
+***************
+*** 559,564 ****
+--- 573,579 ----
+ c_cfg_km,
+ c_sel_km,
+ c_fcc_km,
++ pine_quota_keymenu,
+ folder_km,
+ folder_sel_km,
+ folder_sela_km,
+diff -rc alpine-2.00/alpine/mailcmd.c alpine-2.00.I.USE/alpine/mailcmd.c
+*** alpine-2.00/alpine/mailcmd.c 2008-08-21 15:14:45.000000000 -0700
+--- alpine-2.00.I.USE/alpine/mailcmd.c 2011-02-07 20:33:44.000000000 -0800
+***************
+*** 72,77 ****
+--- 72,78 ----
+ #include "../pith/tempfile.h"
+ #include "../pith/search.h"
+ #include "../pith/margin.h"
++ #include "../pith/rules.h"
+ #ifdef _WINDOWS
+ #include "../pico/osdep/mswin.h"
+ #endif
+***************
+*** 112,118 ****
+ 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 print_index(struct pine *, MSGNO_S *, int);
+
+
+--- 113,119 ----
+ 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);
+ int print_index(struct pine *, MSGNO_S *, int);
+
+
+***************
+*** 253,258 ****
+--- 254,260 ----
+ {'r', 'r', "R", N_("Recipient")},
+ {'p', 'p', "P", N_("Participant")},
+ {'b', 'b', "B", N_("Body")},
++ {'h', 'h', "H", N_("Header")},
+ {-1, 0, NULL, NULL}
+ };
+
+***************
+*** 972,978 ****
+ state->context_current, &recent_cnt,
+ F_ON(F_TAB_NO_CONFIRM,state)
+ ? NULL : &did_cancel))){
+! if(!in_inbox){
+ static ESCKEY_S inbox_opt[] = {
+ {'y', 'y', "Y", N_("Yes")},
+ {'n', 'n', "N", N_("No")},
+--- 974,980 ----
+ state->context_current, &recent_cnt,
+ F_ON(F_TAB_NO_CONFIRM,state)
+ ? NULL : &did_cancel))){
+! 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")},
+***************
+*** 1333,1339 ****
+ if(any_messages(msgmap, NULL, NULL)){
+ if(any_lflagged(msgmap, MN_SLCT) > 0L){
+ if(apply_command(state, stream, msgmap, 0,
+! AC_NONE, question_line)){
+ if(F_ON(F_AUTO_UNSELECT, state)){
+ agg_select_all(stream, msgmap, NULL, 0);
+ unzoom_index(state, stream, msgmap);
+--- 1335,1341 ----
+ if(any_messages(msgmap, NULL, NULL)){
+ if(any_lflagged(msgmap, MN_SLCT) > 0L){
+ if(apply_command(state, stream, msgmap, 0,
+! AC_NONE, question_line, 1)){
+ if(F_ON(F_AUTO_UNSELECT, state)){
+ agg_select_all(stream, msgmap, NULL, 0);
+ unzoom_index(state, stream, msgmap);
+***************
+*** 1351,1373 ****
+
+ /*-------- Sort command -------*/
+ case MC_SORT :
+ {
+ int were_threading = THREADING();
+ SortOrder sort = mn_get_sort(msgmap);
+ int rev = mn_get_revsort(msgmap);
+
+ dprint((1,"MAIL_CMD: sort\n"));
+! if(select_sort(state, question_line, &sort, &rev)){
+ /* $ command reinitializes threading collapsed/expanded info */
+ if(SORT_IS_THREADED(msgmap) && !SEP_THRDINDX())
+ erase_threading_info(stream, msgmap);
+
+ 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);
+ }
+
+ state->mangled_footer = 1;
+--- 1353,1387 ----
+
+ /*-------- 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(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, 1);
+ }
+
+ state->mangled_footer = 1;
+***************
+*** 2368,2373 ****
+--- 2382,2388 ----
+
+ dprint((4, "\n - saving message -\n"));
+
++ saved_stream = stream; /* ugly hack! */
+ state->ugly_consider_advancing_bit = 0;
+ if(F_OFF(F_SAVE_PARTIAL_WO_CONFIRM, state)
+ && msgno_any_deletedparts(stream, msgmap)
+***************
+*** 2592,2597 ****
+--- 2607,2615 ----
+ 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':
+***************
+*** 2642,2653 ****
+ 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 delindex, preindex, r;
+ char prompt[6*MAX_SCREEN_COLS+1], *p, expanded[MAILTMPLEN];
+ char *buf = tmp_20k_buf;
+ char shortbuf[200];
+! char *folder;
+ HelpType help;
+ SaveDel del = DontAsk;
+ SavePreserveOrder pre = DontAskPreserve;
+--- 2660,2671 ----
+ char *nmsgs, ENVELOPE *env, long int rawmsgno, char *section,
+ SaveDel *dela, SavePreserveOrder *prea)
+ {
+! 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, folder2[MAXPATH];
+ HelpType help;
+ SaveDel del = DontAsk;
+ SavePreserveOrder pre = DontAskPreserve;
+***************
+*** 2655,2660 ****
+--- 2673,2681 ----
+ static HISTORY_S *history = NULL;
+ CONTEXT_S *tc;
+ ESCKEY_S ekey[10];
++ RULE_RESULT *rule;
++
++ saved_stream = state->mail_stream;
+
+ if(!cntxt)
+ panic("no context ptr in save_prompt");
+***************
+*** 2664,2669 ****
+--- 2685,2699 ----
+ 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))
+***************
+*** 3172,3177 ****
+--- 3202,3211 ----
+ 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,
+***************
+*** 3266,3271 ****
+--- 3300,3308 ----
+ */
+ 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)
+***************
+*** 3347,3352 ****
+--- 3384,3392 ----
+ {-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");
+***************
+*** 6933,6939 ****
+ * 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));
+ }
+ else{
+ if((all_selected =
+--- 6973,6979 ----
+ * 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), 1);
+ }
+ else{
+ if((all_selected =
+***************
+*** 6989,6995 ****
+ ----*/
+ int
+ apply_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap,
+! UCS preloadkeystroke, int flags, int q_line)
+ {
+ int i = 8, /* number of static entries in sel_opts3 */
+ rv = 0,
+--- 7029,7035 ----
+ ----*/
+ int
+ apply_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap,
+! UCS preloadkeystroke, int flags, int q_line, int display)
+ {
+ int i = 8, /* number of static entries in sel_opts3 */
+ rv = 0,
+***************
+*** 7141,7149 ****
+ collapse_or_expand(state, stream, msgmap,
+ F_ON(F_SLASH_COLL_ENTIRE, ps_global)
+ ? 0L
+! : mn_get_cur(msgmap));
+ break;
+
+ case ':' :
+ select_thread_stmp(state, stream, msgmap);
+ break;
+--- 7181,7199 ----
+ collapse_or_expand(state, stream, msgmap,
+ F_ON(F_SLASH_COLL_ENTIRE, ps_global)
+ ? 0L
+! : 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;
+***************
+*** 7670,7676 ****
+ int not = 0, me = 0;
+ char sstring[80], savedsstring[80], tmp[128];
+ char *p, *sval = NULL;
+! char buftmp[MAILTMPLEN];
+ ESCKEY_S ekey[8];
+ ENVELOPE *env = NULL;
+ HelpType help;
+--- 7720,7726 ----
+ int not = 0, me = 0;
+ char sstring[80], savedsstring[80], tmp[128];
+ char *p, *sval = NULL;
+! char buftmp[MAILTMPLEN], namehdr[80];
+ ESCKEY_S ekey[8];
+ ENVELOPE *env = NULL;
+ HelpType help;
+***************
+*** 7757,7762 ****
+--- 7807,7846 ----
+ sval = "BODYTEXT";
+ break;
+
++ case 'h' :
++ strcpy(tmp, "Name of HEADER to match : ");
++ flags = OE_APPEND_CURRENT;
++ namehdr[0] = '\0';
++ r = 'x';
++ while (r == 'x'){
++ int done = 0;
++
++ r = optionally_enter(namehdr, -FOOTER_ROWS(ps_global), 0,
++ sizeof(namehdr), tmp, ekey, NO_HELP, &flags);
++ if (r == 1){
++ cmd_cancelled("Selection by text");
++ return(1);
++ }
++ removing_leading_white_space(namehdr);
++ while(!done){
++ while ((namehdr[0] != '\0') && /* remove trailing ":" */
++ (namehdr[strlen(namehdr) - 1] == ':'))
++ namehdr[strlen(namehdr) - 1] = '\0';
++ if ((namehdr[0] != '\0')
++ && isspace((unsigned char) namehdr[strlen(namehdr) - 1]))
++ removing_trailing_white_space(namehdr);
++ else
++ done++;
++ }
++ if (strchr(namehdr,' ') || strchr(namehdr,'\t') ||
++ strchr(namehdr,':'))
++ namehdr[0] = '\0';
++ if (namehdr[0] == '\0')
++ r = 'x';
++ }
++ sval = namehdr;
++ break;
++
+ case 'x':
+ break;
+
+***************
+*** 7953,7959 ****
+ flagsforhist = (not ? 0x1 : 0) + (me ? 0x2 : 0);
+ save_hist(history, sstring, flagsforhist, NULL);
+
+! rv = agg_text_select(stream, msgmap, type, not, me, sstring, "utf-8", limitsrch);
+ if(we_cancel)
+ cancel_busy_cue(0);
+
+--- 8037,8043 ----
+ flagsforhist = (not ? 0x1 : 0) + (me ? 0x2 : 0);
+ save_hist(history, sstring, flagsforhist, NULL);
+
+! rv = agg_text_select(stream, msgmap, type, namehdr, not, me, sstring, "utf-8", limitsrch);
+ if(we_cancel)
+ cancel_busy_cue(0);
+
+***************
+*** 8874,8879 ****
+--- 8958,9102 ----
+ return(ret);
+ }
+
++ int process_quota_cmd(int cmd, MSGNO_S *msgmap, SCROLL_S *sparms)
++ {
++ return cmd;
++ }
++
++ void cmd_quota (struct pine *state)
++ {
++ QUOTALIST *imapquota;
++ NETMBX mb;
++ unsigned long len, storageuse, storagelim, messageuse, messagelim;
++ STORE_S *store;
++ SCROLL_S sargs;
++ char *linedata, *storageq = NULL, *messageq = NULL;
++ int storage=0, message=0, other=0, storagelen = 0, messagelen = 0;
++
++ if(!state->mail_stream || !is_imap_stream(state->mail_stream)){
++ q_status_message(SM_ORDER, 1, 5, "Quota only available for IMAP folders");
++ return;
++ }
++
++ if (state->mail_stream
++ && !sp_dead_stream(state->mail_stream)
++ && state->mail_stream->mailbox
++ && *state->mail_stream->mailbox
++ && mail_valid_net_parse(state->mail_stream->mailbox, &mb))
++ imap_getquotaroot(state->mail_stream, mb.mailbox);
++
++ if(!state->quota) /* failed ? */
++ return; /* go back... */
++
++ if(!(store = so_get(CharStar, NULL, EDIT_ACCESS))){
++ q_status_message(SM_ORDER | SM_DING, 3, 3, "Error allocating space.");
++ return;
++ }
++
++ if (state->mail_stream && state->mail_stream->original_mailbox){
++ len = strlen(state->mail_stream->original_mailbox) + 19;
++ linedata = (char *) fs_get(len*sizeof(char));
++ sprintf(linedata,"Quota Report for %s\n",
++ state->mail_stream->original_mailbox);
++ so_puts(store,linedata);
++ if (linedata)
++ fs_give((void **)&linedata);
++ }
++ else
++ so_puts(store,"Quota Report:\n");
++ so_puts(store,"\n");
++
++ for (imapquota = state->quota; imapquota; imapquota = imapquota->next){
++ if(!strucmp(imapquota->name,"STORAGE")){
++ storage++;
++ storagelen = strlen(long2string(imapquota->limit)) + 1+3;
++ storageuse = imapquota->usage;
++ storagelim = imapquota->limit;
++ }
++ if(!strucmp(imapquota->name,"MESSAGE")){
++ message++;
++ messagelen = strlen(long2string(imapquota->limit)) + 1+9;
++ messageuse = imapquota->usage;
++ messagelim = imapquota->limit;
++ }
++ other += strucmp(imapquota->name,"STORAGE") &&
++ strucmp(imapquota->name,"MESSAGE") ? 0 : 1;
++ }
++
++ storageq = (char *) fs_get(storagelen*sizeof(char));
++ if (storage)
++ sprintf(storageq, "%lu KB", storageuse);
++ messageq = (char *) fs_get(messagelen*sizeof(char));
++ if (message)
++ sprintf(messageq, "%lu message%s", messageuse, plural(messageuse));
++ len = strlen("Usage: ") + storagelen + messagelen + 9;
++ linedata = (char *) fs_get(len*sizeof(char));
++ sprintf(linedata,"Usage: %s%s%s%s\n", (storage ? storageq : ""),
++ (message ? (storage ? " (" : "") : ""),
++ (message ? messageq : ""),
++ (message ? (storage ? ")" : "") : ""));
++ so_puts(store, linedata);
++ if (storageq)
++ fs_give((void **)&storageq);
++ if (messageq)
++ fs_give((void **)&messageq);
++ if (linedata)
++ fs_give((void **)&linedata);
++
++ storageq = (char *) fs_get(storagelen*sizeof(char));
++ if (storage)
++ sprintf(storageq, "%lu KB", storagelim);
++ messageq = (char *) fs_get(messagelen*sizeof(char));
++ if (message)
++ sprintf(messageq, "%lu message%s", messagelim, plural(messagelim));
++ len = strlen("Limit: ") + storagelen + messagelen + 9;
++ linedata = (char *) fs_get(len*sizeof(char));
++ sprintf(linedata,"Limit: %s%s%s%s", (storage ? storageq : ""),
++ (message ? (storage ? " (" : "") : ""),
++ (message ? messageq : ""),
++ (message ? (storage ? ")" : "") : ""));
++ so_puts(store, linedata);
++ if (storageq)
++ fs_give((void **)&storageq);
++ if (messageq)
++ fs_give((void **)&messageq);
++ if (linedata)
++ fs_give((void **)&linedata);
++
++ for (imapquota = state->quota; other && imapquota;
++ imapquota = imapquota->next){
++ if (strucmp(imapquota->name,"STORAGE") &&
++ strucmp(imapquota->name,"MESSAGE")){
++ len = (imapquota->name ? strlen(imapquota->name) : strlen("No Name"));
++ linedata = (char *) fs_get(len*sizeof(char));
++ sprintf(linedata,
++ "Resource : %s\nUsage : %lu (%lu%%)\nLimit : %lu\n\n",
++ (imapquota->name ? imapquota->name : "No Name"),
++ imapquota->usage, 100*imapquota->usage/imapquota->limit,
++ imapquota->limit);
++ so_puts(store,linedata);
++ if (linedata)
++ fs_give((void **)&linedata);
++ }
++ }
++
++ memset(&sargs, 0, sizeof(SCROLL_S));
++ sargs.text.text = so_text(store);
++ sargs.text.src = CharStar;
++ sargs.text.desc = _("Quota Resources Summary");
++ sargs.bar.title = _("QUOTA SUMMARY");
++ sargs.proc.tool = process_quota_cmd;
++ sargs.help.text = NO_HELP;
++ sargs.help.title = NULL;
++ sargs.keys.menu = &pine_quota_keymenu;
++ setbitmap(sargs.keys.bitmap);
++
++ scrolltool(&sargs);
++ so_give(&store);
++
++ if (state->quota)
++ mail_free_quotalist(&(state->quota));
++ }
+
+ /*----------------------------------------------------------------------
+ Prompt the user for the type of sort he desires
+***************
+*** 8884,8893 ****
+ Returns 0 if it was cancelled, 1 otherwise.
+ ----*/
+ int
+! select_sort(struct pine *state, int ql, SortOrder *sort, int *rev)
+ {
+ char prompt[200], tmp[3], *p;
+! int s, i;
+ int deefault = 'a', retval = 1;
+ HelpType help;
+ ESCKEY_S sorts[14];
+--- 9107,9116 ----
+ Returns 0 if it was cancelled, 1 otherwise.
+ ----*/
+ int
+! select_sort(struct pine *state, int ql, SortOrder *sort, int *rev, int thread)
+ {
+ char prompt[200], tmp[3], *p;
+! int s, i, j;
+ int deefault = 'a', retval = 1;
+ HelpType help;
+ ESCKEY_S sorts[14];
+***************
+*** 8920,8936 ****
+ 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;
+ }
+
+ sorts[i].ch = 'r';
+--- 9143,9168 ----
+ strncpy(prompt, _("Choose type of sort, or 'R' to reverse current sort : "),
+ sizeof(prompt));
+
+! 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';
+***************
+*** 8954,8961 ****
+ state->mangled_body = 1; /* signal screen's changed */
+ if(s == 'r')
+ *rev = !mn_get_revsort(state->msgmap);
+! else
+ *sort = state->sort_types[s];
+
+ if(F_ON(F_SHOW_SORT, ps_global))
+ ps_global->mangled_header = 1;
+--- 9186,9202 ----
+ state->mangled_body = 1; /* signal screen's changed */
+ if(s == 'r')
+ *rev = !mn_get_revsort(state->msgmap);
+! 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;
+***************
+*** 9340,9342 ****
+--- 9581,9958 ----
+ }
+
+ #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 -rc alpine-2.00/alpine/mailcmd.h alpine-2.00.I.USE/alpine/mailcmd.h
+*** alpine-2.00/alpine/mailcmd.h 2008-03-19 12:43:03.000000000 -0700
+--- alpine-2.00.I.USE/alpine/mailcmd.h 2011-02-07 20:33:41.000000000 -0800
+***************
+*** 83,89 ****
+ 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);
+ char **choose_list_of_keywords(void);
+ char *choose_a_charset(int);
+ char **choose_list_of_charsets(void);
+--- 83,89 ----
+ 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);
+ char **choose_list_of_keywords(void);
+ char *choose_a_charset(int);
+ char **choose_list_of_charsets(void);
+***************
+*** 101,106 ****
+ int flag_callback(int, long);
+ MPopup *flag_submenu(MESSAGECACHE *);
+ #endif
+!
+
+ #endif /* PINE_MAILCMD_INCLUDED */
+--- 101,115 ----
+ 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 -rc alpine-2.00/alpine/mailindx.c alpine-2.00.I.USE/alpine/mailindx.c
+*** alpine-2.00/alpine/mailindx.c 2008-07-09 22:01:13.000000000 -0700
+--- alpine-2.00.I.USE/alpine/mailindx.c 2011-02-07 20:33:44.000000000 -0800
+***************
+*** 228,233 ****
+--- 228,235 ----
+ 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
+***************
+*** 239,248 ****
+--- 241,254 ----
+
+ 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");
+ }
+
+
+***************
+*** 560,565 ****
+--- 566,572 ----
+
+ /*---------- Scroll line up ----------*/
+ case MC_CHARUP :
++ previtem:
+ (void) process_cmd(state, stream, msgmap, MC_PREVITEM,
+ (style == MsgIndex
+ || style == MultiMsgIndex
+***************
+*** 577,582 ****
+--- 584,590 ----
+
+ /*---------- Scroll line down ----------*/
+ case MC_CHARDOWN :
++ nextitem:
+ /*
+ * Special Page framing handling here. If we
+ * did something that should scroll-by-a-line, frame
+***************
+*** 794,799 ****
+--- 802,808 ----
+
+
+ case MC_THRDINDX :
++ mc_thrdindx:
+ msgmap->top = msgmap->top_after_thrd;
+ if(unview_thread(state, stream, msgmap)){
+ state->next_screen = mail_index_screen;
+***************
+*** 844,850 ****
+ && mp.col == id.plus_col
+ && style != ThreadIndex){
+ collapse_or_expand(state, stream, msgmap,
+! mn_get_cur(msgmap));
+ }
+ else if (mp.doubleclick){
+ if(mp.button == M_BUTTON_LEFT){
+--- 853,859 ----
+ && mp.col == id.plus_col
+ && style != ThreadIndex){
+ collapse_or_expand(state, stream, msgmap,
+! mn_get_cur(msgmap), 1);
+ }
+ else if (mp.doubleclick){
+ if(mp.button == M_BUTTON_LEFT){
+***************
+*** 923,928 ****
+--- 932,939 ----
+ reset_index_border();
+ break;
+
++ case MC_QUOTA:
++ cmd_quota(state);
+
+ /*---------- Redraw ----------*/
+ case MC_REPAINT :
+***************
+*** 951,959 ****
+
+
+ case MC_COLLAPSE :
+! thread_command(state, stream, msgmap, ch, -FOOTER_ROWS(state));
+ break;
+
+ case MC_DELETE :
+ case MC_UNDELETE :
+ case MC_REPLY :
+--- 962,1066 ----
+
+
+ case MC_COLLAPSE :
+! 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 :
+***************
+*** 974,986 ****
+ if(rawno)
+ thrd = fetch_thread(stream, rawno);
+
+! collapsed = thrd && thrd->next
+! && get_lflag(stream, NULL, rawno, MN_COLL);
+ }
+
+ if(collapsed){
+ thread_command(state, stream, msgmap,
+! ch, -FOOTER_ROWS(state));
+ /* increment current */
+ if(cmd == MC_DELETE){
+ advance_cur_after_delete(state, stream, msgmap,
+--- 1081,1092 ----
+ if(rawno)
+ thrd = fetch_thread(stream, rawno);
+
+! collapsed = thread_is_kolapsed(ps_global, stream, msgmap, rawno);
+ }
+
+ if(collapsed){
+ thread_command(state, stream, msgmap,
+! ch, -FOOTER_ROWS(state),1);
+ /* increment current */
+ if(cmd == MC_DELETE){
+ advance_cur_after_delete(state, stream, msgmap,
+***************
+*** 2672,2677 ****
+--- 2778,2784 ----
+ 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;
+***************
+*** 2740,2750 ****
+
+ /* n is the end of this thread */
+ while(thrd){
+ 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);
+ else
+ thrd = NULL;
+ }
+--- 2847,2858 ----
+
+ /* n is the end of this thread */
+ while(thrd){
++ unsigned long next = 0L, branch = 0L;
+ n = mn_raw2m(msgs, thrd->rawno);
+! 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;
+ }
+***************
+*** 2852,2858 ****
+
+ void
+ thread_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap,
+! UCS preloadkeystroke, int q_line)
+ {
+ PINETHRD_S *thrd = NULL;
+ unsigned long rawno, save_branch;
+--- 2960,2966 ----
+
+ void
+ thread_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap,
+! UCS preloadkeystroke, int q_line, int display)
+ {
+ PINETHRD_S *thrd = NULL;
+ unsigned long rawno, save_branch;
+***************
+*** 2901,2907 ****
+ cancel_busy_cue(0);
+
+ (void ) apply_command(state, stream, msgmap, preloadkeystroke, flags,
+! q_line);
+
+ /* restore the original flags */
+ copy_lflags(stream, msgmap, MN_STMP, MN_SLCT);
+--- 3009,3015 ----
+ cancel_busy_cue(0);
+
+ (void ) apply_command(state, stream, msgmap, preloadkeystroke, flags,
+! q_line, display);
+
+ /* restore the original flags */
+ copy_lflags(stream, msgmap, MN_STMP, MN_SLCT);
+***************
+*** 3395,3401 ****
+ if(set){
+ sort_folder(ps_global->mail_stream, ps_global->msgmap,
+ order & 0x000000ff,
+! (order & 0x00000100) != 0, SRT_VRB);
+ mswin_beginupdate();
+ update_titlebar_message();
+ update_titlebar_status();
+--- 3503,3509 ----
+ if(set){
+ sort_folder(ps_global->mail_stream, ps_global->msgmap,
+ order & 0x000000ff,
+! (order & 0x00000100) != 0, SRT_VRB, 1);
+ mswin_beginupdate();
+ update_titlebar_message();
+ update_titlebar_status();
+diff -rc alpine-2.00/alpine/mailindx.h alpine-2.00.I.USE/alpine/mailindx.h
+*** alpine-2.00/alpine/mailindx.h 2007-10-15 14:02:56.000000000 -0700
+--- alpine-2.00.I.USE/alpine/mailindx.h 2011-02-07 20:33:41.000000000 -0800
+***************
+*** 102,108 ****
+ 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);
+ COLOR_PAIR *apply_rev_color(COLOR_PAIR *, int);
+ #ifdef _WINDOWS
+ int index_sort_callback(int, long);
+--- 102,108 ----
+ 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, int);
+ COLOR_PAIR *apply_rev_color(COLOR_PAIR *, int);
+ #ifdef _WINDOWS
+ int index_sort_callback(int, long);
+diff -rc alpine-2.00/alpine/mailpart.c alpine-2.00.I.USE/alpine/mailpart.c
+*** alpine-2.00/alpine/mailpart.c 2008-06-03 08:54:15.000000000 -0700
+--- alpine-2.00.I.USE/alpine/mailpart.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 2145,2150 ****
+--- 2145,2155 ----
+ 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"),
+***************
+*** 3307,3313 ****
+ /*
+ * For consistency, the first question is always "include text?"
+ */
+! if((include_text = reply_text_query(ps_global, 1, &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,
+--- 3312,3318 ----
+ /*
+ * For consistency, the first question is always "include text?"
+ */
+! 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 -rc alpine-2.00/alpine/mailview.c alpine-2.00.I.USE/alpine/mailview.c
+*** alpine-2.00/alpine/mailview.c 2008-08-01 17:32:26.000000000 -0700
+--- alpine-2.00.I.USE/alpine/mailview.c 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 44,49 ****
+--- 44,50 ----
+ #include "dispfilt.h"
+ #include "busy.h"
+ #include "smime.h"
++ #include "roleconf.h"
+ #include "../pith/conf.h"
+ #include "../pith/filter.h"
+ #include "../pith/msgno.h"
+***************
+*** 129,134 ****
+--- 130,136 ----
+ #define SS_CUR 2
+ #define SS_FREE 3
+
++ static ACTION_S *role_chosen = NULL;
+
+ /*
+ * Handle hints.
+***************
+*** 203,209 ****
+--- 205,219 ----
+ 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
+***************
+*** 242,247 ****
+--- 252,259 ----
+ 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"));
+***************
+*** 294,299 ****
+--- 306,322 ----
+ 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);
+***************
+*** 478,483 ****
+--- 501,510 ----
+ }
+ 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);
+
+***************
+*** 732,741 ****
+ {0, 'a', "A", N_("editApp")},
+ {-1, 0, NULL, NULL}};
+
+ if(handle->type == URL){
+ launch_opts[4].ch = 'u';
+
+! if(!(local_h = !struncmp(handle->h.url.path, "x-alpine-", 9))
+ && (handle->h.url.tool
+ || ((local_h = url_local_handler(handle->h.url.path) != NULL)
+ && (handle->h.url.tool = url_external_handler(handle,1)))
+--- 759,771 ----
+ {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';
+
+! if((!(local_h = !struncmp(handle->h.url.path, "x-alpine-", 9))
+! || !(local_h = !struncmp(handle->h.url.path, "x-pine-help", 11)))
+ && (handle->h.url.tool
+ || ((local_h = url_local_handler(handle->h.url.path) != NULL)
+ && (handle->h.url.tool = url_external_handler(handle,1)))
+***************
+*** 833,839 ****
+
+ if(force
+ || (handle->type == URL
+! && !struncmp(handle->h.url.path, "x-alpine-", 9)))
+ return(1);
+
+ while(1){
+--- 863,870 ----
+
+ if(force
+ || (handle->type == URL
+! && !struncmp(handle->h.url.path, "x-alpine-", 9)
+! || !struncmp(handle->h.url.path, "x-pine-help", 11)))
+ return(1);
+
+ while(1){
+***************
+*** 844,855 ****
+ * 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 ? ",
+ (handle->type == URL) ? "URL" : "Attachment",
+ (handle->type == URL) ? "\"" : "",
+ MIN(MAX(0,sc-27), sizeof(prompt)-50),
+--- 875,916 ----
+ * sense if you just say View selected URL ...
+ */
+ if(handle->type == URL &&
+! !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),
+***************
+*** 857,862 ****
+--- 918,924 ----
+ (handle->type == URL)
+ ? ((strlen(handle->h.url.path) > MAX(0,sc-27))
+ ? "...\"" : "\"") : "");
++ }
+
+ prompt[sizeof(prompt)-1] = '\0';
+
+***************
+*** 865,870 ****
+--- 927,955 ----
+ 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';
+***************
+*** 1697,1702 ****
+--- 1782,1788 ----
+ {"news:", 5, url_local_news},
+ {"x-alpine-gripe:", 15, gripe_gripe_to},
+ {"x-alpine-help:", 14, url_local_helper},
++ {"x-pine-help:", 12, url_local_helper},
+ {"x-alpine-phone-home:", 20, url_local_phone_home},
+ {"x-alpine-config:", 16, url_local_config},
+ {"x-alpine-cert:", 14, url_local_certdetails},
+***************
+*** 1812,1818 ****
+ fs_give((void **) &urlp);
+
+ rflags = ROLE_COMPOSE;
+! if(nonempty_patterns(rflags, &dummy)){
+ role = set_role_from_msg(ps_global, rflags, -1L, NULL);
+ if(confirm_role(rflags, &role))
+ role = combine_inherited_role(role);
+--- 1898,1904 ----
+ fs_give((void **) &urlp);
+
+ rflags = ROLE_COMPOSE;
+! 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);
+***************
+*** 1888,1893 ****
+--- 1974,1980 ----
+
+ free_redraft_pos(&redraft_pos);
+ free_action(&role);
++ free_action(&role_chosen);
+
+ return(rv);
+ }
+***************
+*** 2603,2608 ****
+--- 2690,2696 ----
+ }
+
+ if(ps_global->noticed_change_in_unseen){
++ ps_global->noticed_change_in_unseen = 0; /* redraw only once */
+ cmd = MC_RESIZE; /* causes cursor to be saved in folder_lister */
+ done = 1;
+ continue;
+***************
+*** 3449,3454 ****
+--- 3537,3588 ----
+ 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 -rc alpine-2.00/alpine/Makefile.am alpine-2.00.I.USE/alpine/Makefile.am
+*** alpine-2.00/alpine/Makefile.am 2008-06-03 08:54:15.000000000 -0700
+--- alpine-2.00.I.USE/alpine/Makefile.am 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 46,48 ****
+--- 46,49 ----
+ date.c:
+ echo "char datestamp[]="\"`date`\"";" > date.c
+ echo "char hoststamp[]="\"`hostname`\"";" >> date.c
++ cat ../patchlevel >> date.c
+diff -rc alpine-2.00/alpine/Makefile.in alpine-2.00.I.USE/alpine/Makefile.in
+*** alpine-2.00/alpine/Makefile.in 2008-06-03 08:54:15.000000000 -0700
+--- alpine-2.00.I.USE/alpine/Makefile.in 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 724,729 ****
+--- 724,730 ----
+ 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.
+ .NOEXPORT:
+diff -rc alpine-2.00/alpine/osdep/debuging.c alpine-2.00.I.USE/alpine/osdep/debuging.c
+*** alpine-2.00/alpine/osdep/debuging.c 2008-01-04 14:49:15.000000000 -0800
+--- alpine-2.00.I.USE/alpine/osdep/debuging.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 104,109 ****
+--- 104,110 ----
+
+ 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);
+***************
+*** 126,131 ****
+--- 127,134 ----
+ 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 -rc alpine-2.00/alpine/osdep/termin.gen.c alpine-2.00.I.USE/alpine/osdep/termin.gen.c
+*** alpine-2.00/alpine/osdep/termin.gen.c 2008-03-26 10:27:45.000000000 -0700
+--- alpine-2.00.I.USE/alpine/osdep/termin.gen.c 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 32,37 ****
+--- 32,39 ----
+ #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"
+***************
+*** 66,77 ****
+ int pcpine_oe_cursor(int, long);
+ #endif
+
+
+ /*
+ * Generic tty input routines
+ */
+
+!
+ /*----------------------------------------------------------------------
+ Read a character from keyboard with timeout
+ Input: none
+--- 68,97 ----
+ 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
+***************
+*** 113,118 ****
+--- 133,173 ----
+ *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();
+
+***************
+*** 306,312 ****
+ (escape_list && escape_list[0].ch != -1 && escape_list[0].label)
+ ? escape_list[0].label: ""));
+
+! if(!ps_global->ttyo)
+ return(pre_screen_config_opt_enter(utf8string, utf8string_size, utf8prompt,
+ escape_list, help, flags));
+
+--- 361,367 ----
+ (escape_list && escape_list[0].ch != -1 && escape_list[0].label)
+ ? escape_list[0].label: ""));
+
+! if(!ps_global->ttyo || ps_global->send_immediately)
+ return(pre_screen_config_opt_enter(utf8string, utf8string_size, utf8prompt,
+ escape_list, help, flags));
+
+***************
+*** 1153,1162 ****
+ }
+ }
+ }
+!
+ if(!*ps_global->initial_cmds && ps_global->free_initial_cmds){
+ fs_give((void **) &ps_global->free_initial_cmds);
+ ps_global->initial_cmds = NULL;
+ }
+
+ return(ret);
+--- 1208,1218 ----
+ }
+ }
+ }
+! 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 -rc alpine-2.00/alpine/osdep/termin.gen.h alpine-2.00.I.USE/alpine/osdep/termin.gen.h
+*** alpine-2.00/alpine/osdep/termin.gen.h 2007-12-18 10:29:24.000000000 -0800
+--- alpine-2.00.I.USE/alpine/osdep/termin.gen.h 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 32,37 ****
+--- 32,38 ----
+ 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 -rc alpine-2.00/alpine/osdep/termin.unx.c alpine-2.00.I.USE/alpine/osdep/termin.unx.c
+*** alpine-2.00/alpine/osdep/termin.unx.c 2008-03-26 10:27:45.000000000 -0700
+--- alpine-2.00.I.USE/alpine/osdep/termin.unx.c 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 110,115 ****
+--- 110,117 ----
+ 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();
+***************
+*** 676,681 ****
+--- 678,686 ----
+ 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");
+***************
+*** 693,698 ****
+--- 698,706 ----
+ 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 -rc alpine-2.00/alpine/osdep/termout.unx.c alpine-2.00.I.USE/alpine/osdep/termout.unx.c
+*** alpine-2.00/alpine/osdep/termout.unx.c 2008-03-04 12:41:47.000000000 -0800
+--- alpine-2.00.I.USE/alpine/osdep/termout.unx.c 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 205,210 ****
+--- 205,213 ----
+ void
+ init_screen(void)
+ {
++ if(ps_global->send_immediately)
++ return;
++
+ if(_termcap_init) /* init using termcap's rule */
+ tputs(_termcap_init, 1, outchar);
+
+***************
+*** 312,317 ****
+--- 315,323 ----
+ {
+ int footer_rows_was_one = 0;
+
++ if(ps_global->send_immediately)
++ return;
++
+ if(!panicking()){
+
+ dprint((9, "end_screen called\n"));
+***************
+*** 366,372 ****
+ _line = 0; /* clear leaves us at top... */
+ _col = 0;
+
+! if(ps_global->in_init_seq)
+ return;
+
+ mark_status_unknown();
+--- 372,378 ----
+ _line = 0; /* clear leaves us at top... */
+ _col = 0;
+
+! if(ps_global->in_init_seq || ps_global->send_immediately)
+ return;
+
+ mark_status_unknown();
+diff -rc alpine-2.00/alpine/radio.c alpine-2.00.I.USE/alpine/radio.c
+*** alpine-2.00/alpine/radio.c 2007-08-16 15:25:10.000000000 -0700
+--- alpine-2.00.I.USE/alpine/radio.c 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 121,127 ****
+ int rv, width;
+ size_t len;
+
+! if(!ps_global->ttyo)
+ return(pre_screen_config_want_to(question, dflt, on_ctrl_C));
+ #ifdef _WINDOWS
+ if (mswin_usedialog ()) {
+--- 121,127 ----
+ int rv, width;
+ size_t len;
+
+! 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 -rc alpine-2.00/alpine/reply.c alpine-2.00.I.USE/alpine/reply.c
+*** alpine-2.00/alpine/reply.c 2008-06-03 08:54:15.000000000 -0700
+--- alpine-2.00.I.USE/alpine/reply.c 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 61,67 ****
+ #include "../pith/tempfile.h"
+ #include "../pith/busy.h"
+ #include "../pith/ablookup.h"
+!
+
+ /*
+ * Internal Prototypes
+--- 61,68 ----
+ #include "../pith/tempfile.h"
+ #include "../pith/busy.h"
+ #include "../pith/ablookup.h"
+! #include "../pith/copyaddr.h"
+! #include "../pith/rules.h"
+
+ /*
+ * Internal Prototypes
+***************
+*** 108,118 ****
+ 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;
+ gf_io_t pc;
+ PAT_STATE dummy;
+ REDRAFT_POS_S *redraft_pos = NULL;
+ ACTION_S *role = NULL, *nrole;
+ #if defined(DOS) && !defined(_WINDOWS)
+ char *reserve;
+ #endif
+--- 109,120 ----
+ 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, 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
+***************
+*** 138,143 ****
+--- 140,208 ----
+ && 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(!role && 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...
+***************
+*** 229,235 ****
+ if(!times){ /* only first time */
+ char *p = cpystr(prefix);
+
+! if((include_text=reply_text_query(pine_state,totalm,&prefix)) < 0)
+ goto done_early;
+
+ /* edited prefix? */
+--- 294,300 ----
+ if(!times){ /* only first time */
+ char *p = cpystr(prefix);
+
+! if((include_text=reply_text_query(pine_state,totalm,env,&prefix)) < 0)
+ goto done_early;
+
+ /* edited prefix? */
+***************
+*** 285,292 ****
+ outgoing->subject = cpystr("Re: several messages");
+ }
+ }
+! else
+! outgoing->subject = reply_subject(env->subject, NULL, 0);
+ }
+
+ /* fill reply header */
+--- 350,367 ----
+ outgoing->subject = cpystr("Re: several messages");
+ }
+ }
+! 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 */
+***************
+*** 305,315 ****
+ 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(!role){
+ rflags = ROLE_REPLY;
+ if(nonempty_patterns(rflags, &dummy)){
+ /* setup default role */
+--- 380,392 ----
+ if(sp_expunge_count(pine_state->mail_stream)) /* cur msg expunged */
+ goto done_early;
+
+! if (ps_global->reply.role_chosen){
+! if(role_arg)
+! free_action(&role);
+! role = ps_global->reply.role_chosen;
+! }
+
+! if(!role && !do_role_early){
+ rflags = ROLE_REPLY;
+ if(nonempty_patterns(rflags, &dummy)){
+ /* setup default role */
+***************
+*** 545,553 ****
+ goto done_early;
+ }
+
+! if(orig_body == NULL || orig_body->type == TYPETEXT || reply_raw_body) {
+ reply_delimiter(env, role, pc);
+! if(F_ON(F_INCLUDE_HEADER, pine_state))
+ reply_forward_header(pine_state->mail_stream,
+ mn_m2raw(pine_state->msgmap,msgno),
+ NULL, env, pc, prefix);
+--- 622,631 ----
+ goto done_early;
+ }
+
+! if(orig_body == NULL || orig_body->type == TYPETEXT || reply_raw_body
+! || !ps_global->reply.attach) {
+ reply_delimiter(env, role, pc);
+! if(ps_global->reply.inchdr)
+ reply_forward_header(pine_state->mail_stream,
+ mn_m2raw(pine_state->msgmap,msgno),
+ NULL, env, pc, prefix);
+***************
+*** 566,572 ****
+ && 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))
+ reply_forward_header(pine_state->mail_stream,
+ mn_m2raw(pine_state->msgmap,
+ msgno),
+--- 644,650 ----
+ && orig_body->nested.part->body.type == TYPETEXT) {
+ /*---- First part of the message is text -----*/
+ reply_delimiter(env, role, pc);
+! if(ps_global->reply.inchdr)
+ reply_forward_header(pine_state->mail_stream,
+ mn_m2raw(pine_state->msgmap,
+ msgno),
+***************
+*** 720,725 ****
+--- 798,806 ----
+ if(prefix)
+ fs_give((void **)&prefix);
+
++ if (ps_global->role)
++ fs_give((void **)&ps_global->role);
++
+ if(fcc)
+ fs_give((void **) &fcc);
+
+***************
+*** 875,881 ****
+
+ prompt[sizeof(prompt)-1] = '\0';
+
+! cmd = radio_buttons(prompt, -FOOTER_ROWS(ps_global), ekey,
+ 'y', 'x', help, RB_NORM);
+
+ switch(cmd){
+--- 956,963 ----
+
+ prompt[sizeof(prompt)-1] = '\0';
+
+! cmd = ps_global->send_immediately ? 'n' :
+! radio_buttons(prompt, -FOOTER_ROWS(ps_global), ekey,
+ 'y', 'x', help, RB_NORM);
+
+ switch(cmd){
+***************
+*** 930,937 ****
+ int
+ reply_to_all_query(int *flagp)
+ {
+! switch(want_to("Reply to all recipients",
+! 'n', 'x', NO_HELP, WT_SEQ_SENSITIVE)){
+ case 'x' :
+ return(-1);
+
+--- 1012,1047 ----
+ int
+ reply_to_all_query(int *flagp)
+ {
+! char prompt[80];
+! ESCKEY_S ekey[4];
+! char cmd;
+!
+! ekey[0].name = "Y";
+! ekey[0].ch = 'y';
+! ekey[0].rval = 'y';
+! ekey[0].label = N_("Yes");
+! ekey[1].name = "N";
+! ekey[1].ch = 'n';
+! ekey[1].rval = 'n';
+! ekey[1].label = N_("No");
+! ekey[2].name = "P";
+! ekey[2].ch = 'p';
+! ekey[2].rval = 'p';
+! ekey[3].ch = -1;
+!
+! ps_global->preserve = F_ON(F_PRESERVE_ORIGINAL_FIELD, ps_global);
+!
+!
+! loop:
+! ekey[2].label = ps_global->preserve ? N_("Not Preserve") : N_("Preserve");
+! snprintf(prompt, sizeof(prompt), _("Reply to all recipients%s"),
+! ps_global->preserve ? _(" (preserving fields)? ") : "? ");
+!
+! prompt[sizeof(prompt)-1] = '\0';
+!
+! switch(cmd = radio_buttons(prompt, -FOOTER_ROWS(ps_global), ekey,
+! 'n', 'x', h_preserve_field, RB_NORM)){
+!
+ case 'x' :
+ return(-1);
+
+***************
+*** 942,947 ****
+--- 1052,1062 ----
+ case 'n' : /* clear reply-all bit */
+ (*flagp) &= ~RSF_FORCE_REPLY_ALL;
+ break;
++
++ case 'p' :
++ ps_global->preserve = !ps_global->preserve;
++ goto loop; /* ugly, but saves me a variable */
++ break;
+ }
+
+ return(0);
+***************
+*** 969,1016 ****
+ * 0 if we're NOT to include the text
+ * -1 on cancel or error
+ */
+ int
+! reply_text_query(struct pine *ps, long int many, 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}
+! };
+
+ if(F_ON(F_AUTO_INCLUDE_IN_REPLY, ps)
+! && F_OFF(F_ENABLE_EDIT_REPLY_INDENT, 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? "),
+ 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) ? "\")" : "");
+
+! 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");
+! }
+! else
+! rtq_opts[2].ch = -1;
+
+ switch(ret = radio_buttons(tmp_20k_buf,
+ ps->ttyo->screen_rows > 4
+ ? -FOOTER_ROWS(ps_global) : -1,
+! rtq_opts,
+ (edited || F_ON(F_AUTO_INCLUDE_IN_REPLY, ps))
+ ? 'y' : 'n',
+ 'x', NO_HELP, RB_SEQ_SENSITIVE)){
+--- 1084,1195 ----
+ * 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, ENVELOPE *env, char **prefix)
+ {
+ int ret, edited = 0;
+! 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_ALT_REPLY_MENU,ps))
+ return(1);
+
+! while(1){
+! /* TRANSLATORS: The final five %s's can probably be safely ignored */
+! snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Include %s original messages in Reply%s%s%s%s%s%s%s? "),
+! (many > 1L) ? comatose(many) : "",
+! (many > 1L) ? " " : "",
+! (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) ? "\")" : "");
+
+! 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");
+! }
+!
+! /***** 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,
+! compose_style,
+ (edited || F_ON(F_AUTO_INCLUDE_IN_REPLY, ps))
+ ? 'y' : 'n',
+ 'x', NO_HELP, RB_SEQ_SENSITIVE)){
+***************
+*** 1018,1023 ****
+--- 1197,1242 ----
+ 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;
+***************
+*** 1041,1046 ****
+--- 1260,1271 ----
+ 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;
+ }
+
+***************
+*** 1164,1172 ****
+ }
+ else if(!outgoing->newsgroups)
+ outgoing->newsgroups = cpystr(env->newsgroups);
+- if(!IS_NEWS(ps_global->mail_stream))
+- q_status_message(SM_ORDER, 2, 3,
+- _("Replying to message that MAY or MAY NOT have been posted to newsgroup"));
+ }
+
+ return(ret);
+--- 1389,1394 ----
+***************
+*** 1440,1448 ****
+ }
+ }
+
+! if(role)
+ q_status_message1(SM_ORDER, 3, 4,
+ _("Forwarding using role \"%s\""), role->nick);
+
+ if(role && role->template){
+ char *filtered;
+--- 1662,1675 ----
+ }
+ }
+
+! 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;
+***************
+*** 1674,1679 ****
+--- 1901,1907 ----
+ #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);
+***************
+*** 2426,2431 ****
+--- 2654,2661 ----
+ {
+ 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);
+***************
+*** 2485,2490 ****
+--- 2715,2721 ----
+ resize_for_pico(void)
+ {
+ fix_windsize(ps_global);
++ ps_global->resize_for_pico = 1;
+ }
+
+
+diff -rc alpine-2.00/alpine/reply.h alpine-2.00.I.USE/alpine/reply.h
+*** alpine-2.00/alpine/reply.h 2006-11-15 20:08:15.000000000 -0800
+--- alpine-2.00.I.USE/alpine/reply.h 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 28,34 ****
+ 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_news_test(ENVELOPE *, ENVELOPE *);
+ char *get_signature_file(char *, int, int, int);
+ int forward(struct pine *, ACTION_S *);
+--- 28,34 ----
+ 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, ENVELOPE *, char **);
+ int reply_news_test(ENVELOPE *, ENVELOPE *);
+ char *get_signature_file(char *, int, int, int);
+ int forward(struct pine *, ACTION_S *);
+diff -rc alpine-2.00/alpine/roleconf.c alpine-2.00.I.USE/alpine/roleconf.c
+*** alpine-2.00/alpine/roleconf.c 2008-02-27 17:04:46.000000000 -0800
+--- alpine-2.00.I.USE/alpine/roleconf.c 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 139,146 ****
+--- 139,151 ----
+
+ if(!(nonempty_patterns(rflags, &pstate) &&
+ first_pattern(&pstate))){
++ if (!ps->send_immediately)
+ q_status_message(SM_ORDER, 0, 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);
+ }
+
+***************
+*** 4477,4487 ****
+ ctmp->tool = role_sort_tool;
+ ctmp->valoffset = rindent;
+ ctmp->flags |= CF_NOSELECT;
+! ctmp->value = cpystr(set_choose); \
+
+ pval = PVAL(&sort_act_var, ew);
+ if(pval)
+! decode_sort(pval, &def_sort, &def_sort_rev);
+
+ /* allow user to set their default sort order */
+ new_confline(&ctmp)->var = &sort_act_var;
+--- 4482,4492 ----
+ ctmp->tool = role_sort_tool;
+ ctmp->valoffset = rindent;
+ ctmp->flags |= CF_NOSELECT;
+! ctmp->value = cpystr(set_choose);
+
+ pval = PVAL(&sort_act_var, ew);
+ if(pval)
+! decode_sort(pval, &def_sort, &def_sort_rev, 0);
+
+ /* allow user to set their default sort order */
+ new_confline(&ctmp)->var = &sort_act_var;
+***************
+*** 4491,4497 ****
+ ctmp->tool = role_sort_tool;
+ ctmp->valoffset = rindent;
+ ctmp->varmem = -1;
+! ctmp->value = generalized_sort_pretty_value(ps, ctmp, 0);
+
+ for(j = 0; j < 2; j++){
+ for(i = 0; ps->sort_types[i] != EndofList; i++){
+--- 4496,4502 ----
+ ctmp->tool = role_sort_tool;
+ ctmp->valoffset = rindent;
+ ctmp->varmem = -1;
+! 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++){
+***************
+*** 4503,4509 ****
+ ctmp->valoffset = rindent;
+ ctmp->varmem = i + (j * EndofList);
+ ctmp->value = generalized_sort_pretty_value(ps, ctmp,
+! 0);
+ }
+ }
+
+--- 4508,4514 ----
+ ctmp->valoffset = rindent;
+ ctmp->varmem = i + (j * EndofList);
+ ctmp->value = generalized_sort_pretty_value(ps, ctmp,
+! 0, 0);
+ }
+ }
+
+***************
+*** 5436,5442 ****
+ (*result)->patgrp->stat_boy = PAT_STAT_EITHER;
+
+ if(sort_act){
+! decode_sort(sort_act, &def_sort, &def_sort_rev);
+ (*result)->action->sort_is_set = 1;
+ (*result)->action->sortorder = def_sort;
+ (*result)->action->revsort = (def_sort_rev ? 1 : 0);
+--- 5441,5447 ----
+ (*result)->patgrp->stat_boy = PAT_STAT_EITHER;
+
+ if(sort_act){
+! 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);
+***************
+*** 7705,7710 ****
+--- 7710,7720 ----
+ 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 -rc alpine-2.00/alpine/send.c alpine-2.00.I.USE/alpine/send.c
+*** alpine-2.00/alpine/send.c 2008-06-30 15:03:35.000000000 -0700
+--- alpine-2.00.I.USE/alpine/send.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 62,68 ****
+ #include "../pith/mimetype.h"
+ #include "../pith/send.h"
+ #include "../pith/smime.h"
+!
+
+ typedef struct body_particulars {
+ unsigned short type, encoding, had_csp;
+--- 62,68 ----
+ #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;
+***************
+*** 98,103 ****
+--- 98,104 ----
+ void free_body_particulars(BODY_PARTICULARS_S *);
+ long message_format_for_pico(long, int (*)(int));
+ int send_exit_for_pico(struct headerentry *, void (*)(void), int, char **);
++ void new_thread_on_blank_subject(void);
+ char *choose_a_priority(char *);
+ int dont_flow_this_time(void);
+ int mime_type_for_pico(char *);
+***************
+*** 237,242 ****
+--- 238,248 ----
+ 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);
+***************
+*** 446,453 ****
+
+ ps_global->next_screen = prev_screen;
+ ps_global->redrawer = redraw;
+! if(role)
+ role = combine_inherited_role(role);
+ }
+ break;
+
+--- 452,463 ----
+
+ ps_global->next_screen = prev_screen;
+ ps_global->redrawer = redraw;
+! if (ps_global->role)
+! fs_give((void **)&ps_global->role);
+! if(role){
+ role = combine_inherited_role(role);
++ ps_global->role = cpystr(role->nick);
++ }
+ }
+ break;
+
+***************
+*** 612,617 ****
+--- 622,628 ----
+ 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();
+
+ /*
+***************
+*** 642,650 ****
+ }
+ }
+
+! if(role)
+ q_status_message1(SM_ORDER, 3, 4, _("Composing using role \"%s\""),
+ role->nick);
+
+ /*
+ * The type of storage object allocated below is vitally
+--- 653,666 ----
+ }
+ }
+
+! 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
+***************
+*** 910,916 ****
+ 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},
+ {"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},
+--- 926,932 ----
+ 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, 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},
+***************
+*** 1780,1785 ****
+--- 1796,1804 ----
+ 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
+***************
+*** 1816,1821 ****
+--- 1835,1842 ----
+ pbf->mimetype = mime_type_for_pico;
+ pbf->exittest = send_exit_for_pico;
+ pbf->user_says_noflow = dont_flow_this_time;
++ pbf->newthread = new_thread_on_blank_subject;
++ ps_global->newthread = 0; /* reset this value */
+ if(F_OFF(F_CANCEL_CONFIRM, ps_global))
+ pbf->canceltest = cancel_for_pico;
+
+***************
+*** 2301,2306 ****
+--- 2322,2332 ----
+ 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;
+***************
+*** 2410,2415 ****
+--- 2436,2461 ----
+ 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);
+***************
+*** 2979,2985 ****
+ #ifdef _WINDOWS
+ mswin_setwindowmenu (MENU_DEFAULT);
+ #endif
+! fix_windsize(ps_global);
+
+ /*
+ * Only reinitialize signals if we didn't receive an interesting
+--- 3025,3036 ----
+ #ifdef _WINDOWS
+ mswin_setwindowmenu (MENU_DEFAULT);
+ #endif
+! 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
+***************
+*** 3038,3044 ****
+ if(outgoing->return_path)
+ mail_free_address(&outgoing->return_path);
+
+! outgoing->return_path = rfc822_cpy_adr(outgoing->from);
+
+ /*
+ * Don't ever believe the sender that is there.
+--- 3089,3097 ----
+ if(outgoing->return_path)
+ mail_free_address(&outgoing->return_path);
+
+! 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.
+***************
+*** 3068,3073 ****
+--- 3121,3131 ----
+ outgoing->sender->host = cpystr(ps_global->hostname);
+ }
+
++ if(ps_global->newthread){
++ if(outgoing->in_reply_to) fs_give((void **)&outgoing->in_reply_to);
++ if(outgoing->references) fs_give((void **)&outgoing->references);
++ }
++
+ /*----- Message is edited, now decide what to do with it ----*/
+ if(editor_result & (COMP_SUSPEND | COMP_GOTHUP | COMP_CANCEL)){
+ /*=========== Postpone or Interrupted message ============*/
+***************
+*** 3710,3719 ****
+ if(sending_filter_requested
+ && !filter_message_text(sending_filter_requested, outgoing,
+ *body, &orig_so, &header)){
+! q_status_message1(SM_ORDER, 3, 3,
+ _("Problem filtering! Nothing sent%s."),
+ fcc ? " or saved to fcc" : "");
+! continue;
+ }
+
+ /*------ Actually post -------*/
+--- 3768,3783 ----
+ if(sending_filter_requested
+ && !filter_message_text(sending_filter_requested, outgoing,
+ *body, &orig_so, &header)){
+! if (!ps_global->send_immediately){
+! q_status_message1(SM_ORDER, 3, 3,
+ _("Problem filtering! Nothing sent%s."),
+ fcc ? " or saved to fcc" : "");
+! continue;
+! }
+! else{
+! fprintf(stderr, _("Problem filtering! Nothing sent or saved to Fcc\n"));
+! exit(-1);
+! }
+ }
+
+ /*------ Actually post -------*/
+***************
+*** 3957,3962 ****
+--- 4021,4028 ----
+ /*----- 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){
+ /*
+***************
+*** 3991,3996 ****
+--- 4057,4063 ----
+ 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));
+
+***************
+*** 4360,4365 ****
+--- 4427,4442 ----
+ return(buf);
+ }
+
++ /* Callback from Pico to set the conditions for Alpine to start a new thread
++ */
++
++ void
++ new_thread_on_blank_subject(void)
++ {
++ ps_global->newthread = F_ON(F_NEW_THREAD_ON_BLANK_SUBJECT, ps_global);
++ }
++
++
+
+ /*----------------------------------------------------------------------
+ Call back for pico to insert the specified message's text
+***************
+*** 4447,4453 ****
+ return(1);
+ }
+
+! if(F_ON(F_SEND_WO_CONFIRM, ps_global)){
+ if(result)
+ *result = NULL;
+
+--- 4524,4530 ----
+ return(1);
+ }
+
+! if(!ps_global->send_immediately && F_ON(F_SEND_WO_CONFIRM, ps_global)){
+ if(result)
+ *result = NULL;
+
+***************
+*** 4627,4633 ****
+
+ opts[i].ch = -1;
+
+! fix_windsize(ps_global);
+
+ while(1){
+ if(filters && filters->filter && (p = strindex(filters->filter, ' ')))
+--- 4704,4711 ----
+
+ opts[i].ch = -1;
+
+! if (!ps_global->send_immediately)
+! fix_windsize(ps_global);
+
+ while(1){
+ if(filters && filters->filter && (p = strindex(filters->filter, ' ')))
+***************
+*** 4809,4815 ****
+ 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,
+ 'y', 'z',
+ (F_ON(F_DSN, ps_global) && allow_flowed)
+ ? h_send_prompt_dsn_flowed :
+--- 4887,4894 ----
+ if(double_rad +
+ ((call_mailer_flags & CM_DSN_SHOW)
+ ? 4 : F_ON(F_DSN, ps_global) ? 1 : 0) > 11)
+! 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 :
+***************
+*** 4818,4824 ****
+ h_send_prompt,
+ RB_NORM);
+ else
+! rv = radio_buttons(tmp_20k_buf, -FOOTER_ROWS(ps_global), opts,
+ 'y', 'z',
+ (double_rad +
+ ((call_mailer_flags & CM_DSN_SHOW)
+--- 4897,4904 ----
+ h_send_prompt,
+ RB_NORM);
+ else
+! 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)
+***************
+*** 5155,5165 ****
+--- 5235,5247 ----
+ {'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,
+***************
+*** 5172,5183 ****
+ q_status_message(SM_INFO, 1, 3, _(" Type \"C\" to cancel message "));
+ display_message('x');
+ }
+ else
+ break;
+ }
+
+ ps_global->redrawer = redraw;
+! return(rstr);
+ }
+
+
+--- 5254,5269 ----
+ 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(pbf->curpos[0] ? pbf->curpos : rstr);
+ }
+
+
+***************
+*** 5204,5210 ****
+
+ if(fcmd
+ && (cmd=expand_filter_tokens(fcmd, outgoing, &tmpf, &resultf, &mtf,
+! &key, &include_hdrs))){
+ if(tmpf){
+ /*
+ * We need WRITE_TO_LOCALE here because the user is going to
+--- 5290,5296 ----
+
+ if(fcmd
+ && (cmd=expand_filter_tokens(fcmd, outgoing, &tmpf, &resultf, &mtf,
+! &key, &include_hdrs, NULL))){
+ if(tmpf){
+ /*
+ * We need WRITE_TO_LOCALE here because the user is going to
+***************
+*** 5281,5289 ****
+ 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(tmpf){
+ PIPE_S *fpipe;
+
+--- 5367,5377 ----
+ if((tmp_so = so_get(PicoText, NULL, EDIT_ACCESS)) != NULL){
+ gf_set_so_writec(&pc, tmp_so);
+ ps_global->mangled_screen = 1;
+! if (!ps_global->send_immediately){
+! suspend_busy_cue();
+! ClearScreen();
+! fflush(stdout);
+! }
+ if(tmpf){
+ PIPE_S *fpipe;
+
+***************
+*** 5311,5317 ****
+ }
+ else
+ errstr = gf_filter(cmd, key ? filter_session_key() : NULL,
+! readthis_so, pc, NULL, 0,
+ pipe_callback);
+
+ if(our_tmpf_so)
+--- 5399,5405 ----
+ }
+ else
+ errstr = gf_filter(cmd, key ? filter_session_key() : NULL,
+! readthis_so, pc, NULL, 0, 0,
+ pipe_callback);
+
+ if(our_tmpf_so)
+***************
+*** 5395,5402 ****
+ set_mime_type_by_grope(b);
+ }
+
+! ClearScreen();
+! resume_busy_cue(0);
+ }
+ else
+ errstr = "Can't create space for filtered text.";
+--- 5483,5492 ----
+ set_mime_type_by_grope(b);
+ }
+
+! if (!ps_global->send_immediately){
+! ClearScreen();
+! resume_busy_cue(0);
+! }
+ }
+ else
+ errstr = "Can't create space for filtered text.";
+***************
+*** 5427,5436 ****
+ if(tmp_so)
+ so_give(&tmp_so);
+
+! q_status_message1(SM_ORDER | SM_DING, 3, 6, _("Problem filtering: %s"),
+ errstr);
+! dprint((1, "Filter FAILED: %s\n",
+ errstr ? errstr : "?"));
+ }
+
+ return(errstr == NULL);
+--- 5517,5532 ----
+ if(tmp_so)
+ so_give(&tmp_so);
+
+! if (!ps_global->send_immediately){
+! q_status_message1(SM_ORDER | SM_DING, 3, 6, _("Problem filtering: %s"),
+ errstr);
+! dprint((1, "Filter FAILED: %s\n",
+ errstr ? errstr : "?"));
++ }
++ else{
++ fprintf(stderr, _("Filter FAILED: %s\n"), errstr ? errstr : "?");
++ exit(-1);
++ }
+ }
+
+ return(errstr == NULL);
+diff -rc alpine-2.00/alpine/setup.c alpine-2.00.I.USE/alpine/setup.c
+*** alpine-2.00/alpine/setup.c 2008-01-23 11:15:36.000000000 -0800
+--- alpine-2.00.I.USE/alpine/setup.c 2011-02-07 20:33:41.000000000 -0800
+***************
+*** 257,263 ****
+ ctmpa->flags |= CF_NOSELECT;
+ ctmpa->value = cpystr("--- ----------------------");
+
+! decode_sort(pval, &def_sort, &def_sort_rev);
+
+ for(j = 0; j < 2; j++){
+ for(i = 0; ps->sort_types[i] != EndofList; i++){
+--- 257,263 ----
+ ctmpa->flags |= CF_NOSELECT;
+ ctmpa->value = cpystr("--- ----------------------");
+
+! decode_sort(pval, &def_sort, &def_sort_rev, 0);
+
+ for(j = 0; j < 2; j++){
+ for(i = 0; ps->sort_types[i] != EndofList; i++){
+***************
+*** 272,277 ****
+--- 272,326 ----
+ }
+ }
+ }
++ 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;
+***************
+*** 463,468 ****
+--- 512,526 ----
+ }
+ }
+
++ 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 -rc alpine-2.00/alpine/signal.c alpine-2.00.I.USE/alpine/signal.c
+*** alpine-2.00/alpine/signal.c 2008-04-07 15:58:40.000000000 -0700
+--- alpine-2.00.I.USE/alpine/signal.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 819,826 ****
+ #else
+ if(F_ON(F_SUSPEND_SPAWNS, ps_global)){
+ PIPE_S *syspipe;
+
+! if((syspipe = open_system_pipe(NULL, NULL, NULL, PIPE_USER|PIPE_RESET,
+ 0, pipe_callback, pipe_report_error)) != NULL){
+ suspend_notice("exit");
+ #ifndef SIGCHLD
+--- 819,828 ----
+ #else
+ if(F_ON(F_SUSPEND_SPAWNS, ps_global)){
+ PIPE_S *syspipe;
++ int flag = some_stream_is_locked() ? PIPE_NONEWMAIL : 0;
+
+! flag |= PIPE_USER|PIPE_RESET;
+! if((syspipe = open_system_pipe(NULL, NULL, NULL, flag,
+ 0, pipe_callback, pipe_report_error)) != NULL){
+ suspend_notice("exit");
+ #ifndef SIGCHLD
+***************
+*** 867,873 ****
+ _("Error loading \"%s\""), shell);
+ #endif
+
+! if(isremote && !pine_mail_ping(ps_global->mail_stream))
+ q_status_message(SM_ORDER | SM_DING, 4, 9,
+ _("Suspended for too long, IMAP connection broken"));
+
+--- 869,876 ----
+ _("Error loading \"%s\""), shell);
+ #endif
+
+! if(isremote && !ps_global->mail_stream->lock
+! && !pine_mail_ping(ps_global->mail_stream))
+ q_status_message(SM_ORDER | SM_DING, 4, 9,
+ _("Suspended for too long, IMAP connection broken"));
+
+diff -rc alpine-2.00/alpine/status.c alpine-2.00.I.USE/alpine/status.c
+*** alpine-2.00/alpine/status.c 2007-11-28 09:57:15.000000000 -0800
+--- alpine-2.00.I.USE/alpine/status.c 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 110,115 ****
+--- 110,118 ----
+ char *clean_msg;
+ size_t mlen;
+
++ if (ps_global->send_immediately)
++ return;
++
+ status_message_lock();
+
+ /*
+***************
+*** 604,609 ****
+--- 607,615 ----
+ SMQ_T *q, *copy_of_q;
+ int ding;
+
++ if(ps_global->send_immediately)
++ return;
++
+ start_over:
+ status_message_lock();
+
+diff -rc alpine-2.00/doc/alpine.1 alpine-2.00.I.USE/doc/alpine.1
+*** alpine-2.00/doc/alpine.1 2008-08-22 13:40:16.000000000 -0700
+--- alpine-2.00.I.USE/doc/alpine.1 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 164,169 ****
+--- 164,171 ----
+ .IP \fB-n\ \fInumber\fR 20
+ Start up with current message-number set to
+ .I number.
++ .IP \fB-noutf8\fR 20
++ Warns Alpine that piped input is not encoded in UTF-8.
+ .IP \fB-o\fR 20
+ Open first folder read-only.
+ .IP \fB-p\ \fIconfig-file\fR 20
+diff -rc alpine-2.00/imap/src/c-client/imap4r1.c alpine-2.00.I.USE/imap/src/c-client/imap4r1.c
+*** alpine-2.00/imap/src/c-client/imap4r1.c 2008-06-04 11:39:54.000000000 -0700
+--- alpine-2.00.I.USE/imap/src/c-client/imap4r1.c 2011-02-07 20:33:43.000000000 -0800
+***************
+*** 1121,1126 ****
+--- 1121,1127 ----
+ sprintf (tmp,"Retrying using %s authentication after %.80s",
+ at->name,lsterr);
+ mm_log (tmp,NIL);
++ delete_password(mb, usr);
+ fs_give ((void **) &lsterr);
+ }
+ trial = 0; /* initial trial count */
+***************
+*** 1129,1134 ****
+--- 1130,1136 ----
+ if (lsterr) { /* previous attempt with this one failed? */
+ sprintf (tmp,"Retrying %s authentication after %.80s",at->name,lsterr);
+ mm_log (tmp,WARN);
++ delete_password(mb, usr);
+ fs_give ((void **) &lsterr);
+ }
+ LOCAL->saslcancel = NIL;
+***************
+*** 1166,1171 ****
+--- 1168,1174 ----
+ sprintf (tmp,"Can not authenticate to IMAP server: %.80s",lsterr);
+ mm_log (tmp,ERROR);
+ }
++ delete_password(mb, usr);
+ fs_give ((void **) &lsterr);
+ }
+ return NIL; /* ran out of authenticators */
+***************
+*** 1207,1212 ****
+--- 1210,1216 ----
+ if (imap_OK (stream,reply = imap_send (stream,"LOGIN",args)))
+ ret = LONGT; /* success */
+ else {
++ delete_password(mb, usr);
+ mm_log (reply->text,WARN);
+ if (!LOCAL->referral && (trial == imap_maxlogintrials))
+ mm_log ("Too many login failures",ERROR);
+***************
+*** 4527,4532 ****
+--- 4531,4537 ----
+ if (*env) { /* need to merge this header into envelope? */
+ if (!(*env)->newsgroups) { /* need Newsgroups? */
+ (*env)->newsgroups = nenv->newsgroups;
++ (*env)->ngpathexists = nenv->ngpathexists;
+ nenv->newsgroups = NIL;
+ }
+ if (!(*env)->followup_to) { /* need Followup-To? */
+***************
+*** 4581,4586 ****
+--- 4586,4592 ----
+ if (oenv) { /* need to merge old envelope? */
+ (*env)->newsgroups = oenv->newsgroups;
+ oenv->newsgroups = NIL;
++ (*env)->ngpathexists = oenv->ngpathexists;
+ (*env)->followup_to = oenv->followup_to;
+ oenv->followup_to = NIL;
+ (*env)->references = oenv->references;
+diff -rc alpine-2.00/imap/src/c-client/mail.c alpine-2.00.I.USE/imap/src/c-client/mail.c
+*** alpine-2.00/imap/src/c-client/mail.c 2008-06-04 11:39:54.000000000 -0700
+--- alpine-2.00.I.USE/imap/src/c-client/mail.c 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 34,39 ****
+--- 34,41 ----
+
+ /* c-client global data */
+
++ static char *pwdfile = NIL; /*password file */
++ static int xlate_key; /* for password file support */
+ /* version of this library */
+ static char *mailcclientversion = CCLIENTVERSION;
+ /* list of mail drivers */
+***************
+*** 52,57 ****
+--- 54,61 ----
+ static rfc822out_t mail822out = NIL;
+ /* RFC-822 output generator (new style) */
+ static rfc822outfull_t mail822outfull = NIL;
++ /* Erase password (client side) */
++ static deletepwd_t erase_password = NIL;
+ /* SMTP verbose callback */
+ static smtpverbose_t mailsmtpverbose = mm_dlog;
+ /* proxy copy routine */
+***************
+*** 544,549 ****
+--- 548,558 ----
+ case GET_SENDCOMMAND:
+ ret = (void *) mailsendcommand;
+ break;
++ case SET_ERASEPASSWORD:
++ erase_password = (deletepwd_t) value;
++ case GET_ERASEPASSWORD:
++ ret = (void *) erase_password;
++ break;
+
+ case SET_SERVICENAME:
+ servicename = (char *) value;
+***************
+*** 640,645 ****
+--- 649,661 ----
+ case GET_SNARFMAILBOXNAME:
+ if (stream) ret = (void *) stream->snarf.name;
+ break;
++ case SET_PASSWORDFILE:
++ if (pwdfile) fs_give ((void **) &pwdfile);
++ pwdfile = cpystr ((char *) value);
++ break;
++ case GET_PASSWORDFILE:
++ ret = (void *) pwdfile;
++ break;
+ default:
+ if (r = smtp_parameters (function,value)) ret = r;
+ if (r = env_parameters (function,value)) ret = r;
+***************
+*** 991,997 ****
+ MAILSTREAM *ts;
+ char *s,*t,tmp[MAILTMPLEN];
+ size_t i;
+! DRIVER *d;
+ /* never allow names with newlines */
+ if (s = strpbrk (mailbox,"\015\012")) {
+ MM_LOG ("Can't create mailbox with such a name",ERROR);
+--- 1007,1013 ----
+ MAILSTREAM *ts;
+ char *s,*t,tmp[MAILTMPLEN];
+ size_t i;
+! DRIVER *d, *md;
+ /* never allow names with newlines */
+ if (s = strpbrk (mailbox,"\015\012")) {
+ MM_LOG ("Can't create mailbox with such a name",ERROR);
+***************
+*** 1015,1020 ****
+--- 1031,1038 ----
+ return NIL;
+ }
+
++ /* Hack, we should do this better, but it works */
++ for (md = maildrivers; md && strcmp (md->name, "md"); md = md->next);
+ /* see if special driver hack */
+ if ((mailbox[0] == '#') && ((mailbox[1] == 'd') || (mailbox[1] == 'D')) &&
+ ((mailbox[2] == 'r') || (mailbox[2] == 'R')) &&
+***************
+*** 1045,1050 ****
+--- 1063,1075 ----
+ (((*mailbox == '{') || (*mailbox == '#')) &&
+ (stream = mail_open (NIL,mailbox,OP_PROTOTYPE | OP_SILENT))))
+ d = stream->dtb;
++ else if(mailbox[0] == '#'
++ && (mailbox[1] == 'm' || mailbox[1] == 'M')
++ && (mailbox[2] == 'd' || mailbox[2] == 'D'
++ || mailbox[2] == 'c' || mailbox[2] == 'C')
++ && mailbox[3] == '/'
++ && mailbox[4] != '\0')
++ return (*md->create)(stream, mailbox);
+ else if ((*mailbox != '{') && (ts = default_proto (NIL))) d = ts->dtb;
+ else { /* failed utterly */
+ sprintf (tmp,"Can't create mailbox %.80s: indeterminate format",mailbox);
+***************
+*** 3352,3364 ****
+ long flags)
+ {
+ STRINGLIST *hdrs;
+! int notfound;
+ unsigned long i;
+ char c,*s,*e,*t,tmp[MAILTMPLEN];
+ char *src = text;
+ char *dst = src;
+ char *end = text + len;
+! text[len] = '\012'; /* guard against running off buffer */
+ while (src < end) { /* process header */
+ /* slurp header line name */
+ for (s = src,e = s + MAILTMPLEN - 1,e = (e < end ? e : end),t = tmp;
+--- 3377,3389 ----
+ long flags)
+ {
+ STRINGLIST *hdrs;
+! int notfound, fix = text[len - 1] == '\0';
+ unsigned long i;
+ char c,*s,*e,*t,tmp[MAILTMPLEN];
+ char *src = text;
+ char *dst = src;
+ char *end = text + len;
+! text[fix ? len - 1 : len] = '\012'; /* guard against running off buffer */
+ while (src < end) { /* process header */
+ /* slurp header line name */
+ for (s = src,e = s + MAILTMPLEN - 1,e = (e < end ? e : end),t = tmp;
+***************
+*** 3397,3402 ****
+--- 3422,3431 ----
+ }
+ }
+ *dst = '\0'; /* tie off destination */
++ if(fix){
++ text[len] = '\012';
++ text[len-1] = '\0';
++ }
+ return dst - text;
+ }
+
+***************
+*** 5108,5114 ****
+ unsigned long msgno)
+ {
+ if (msgno && ov) { /* just in case */
+! MESSAGECACHE telt;
+ SORTCACHE *s = (SORTCACHE *) (*mailcache) (stream,msgno,CH_SORTCACHE);
+ if (!s->subject && ov->subject) {
+ s->refwd = mail_strip_subject (ov->subject,&s->subject);
+--- 5137,5144 ----
+ unsigned long msgno)
+ {
+ if (msgno && ov) { /* just in case */
+! MESSAGECACHE telt, *elt;
+! ENVELOPE *env;
+ SORTCACHE *s = (SORTCACHE *) (*mailcache) (stream,msgno,CH_SORTCACHE);
+ if (!s->subject && ov->subject) {
+ s->refwd = mail_strip_subject (ov->subject,&s->subject);
+***************
+*** 5127,5133 ****
+ s->dirty = T;
+ }
+ if (!s->references &&
+! !(s->references = mail_thread_parse_references (ov->references,T))) {
+ /* don't do In-Reply-To with NNTP mailboxes */
+ s->references = mail_newstringlist ();
+ s->dirty = T;
+--- 5157,5168 ----
+ s->dirty = T;
+ }
+ if (!s->references &&
+! !(s->references = mail_thread_parse_references (ov->references,T))
+! && stream->dtb && !strcmp(stream->dtb->name, "imap")
+! && (elt = mail_elt (stream, msgno)) != NULL
+! && (env = elt->private.msg.env) != NULL
+! && env->in_reply_to
+! && !(s->references = mail_thread_parse_references(env->in_reply_to, NIL))) {
+ /* don't do In-Reply-To with NNTP mailboxes */
+ s->references = mail_newstringlist ();
+ s->dirty = T;
+***************
+*** 6115,6120 ****
+--- 6150,6164 ----
+ return i;
+ return 0;
+ }
++ /* Client side callback warning to delete wrong password
++ *
++ */
++ void delete_password(NETMBX *mb, char *user)
++ {
++ deletepwd_t ep = mail_parameters(NULL, GET_ERASEPASSWORD, NULL);
++ if (ep) (ep)(mb, user);
++ }
++
+
+ /* Standard TCP/IP network driver */
+
+***************
+*** 6329,6331 ****
+--- 6373,6450 ----
+ {
+ return (*stream->dtb->localhost) (stream->stream);
+ }
++
++ /*
++ *
++ * Module to add support for password file to a c-client application
++ *
++ * Written by Eduardo Chappa, based on password file support for Pine
++ *
++ */
++ #ifndef PWDFILE
++ #define PWDFILE 1
++ #endif
++
++ #define FIRSTCH 0x20
++ #define LASTCH 0x7e
++ #define TABSZ (LASTCH - FIRSTCH + 1)
++
++ char mm_xlate_out (char c);
++ void mm_userpwd (NETMBX *mb, char **username, char **password);
++
++ /* function that decodes passwords */
++
++ char mm_xlate_out (char c)
++ {
++ register int dti;
++ register int xch;
++
++ if((c >= FIRSTCH) && (c <= LASTCH)){
++ xch = c - (dti = xlate_key);
++ xch += (xch < FIRSTCH-TABSZ) ? 2*TABSZ : (xch < FIRSTCH) ? TABSZ : 0;
++ dti = (xch - FIRSTCH) + dti;
++ dti -= (dti >= 2*TABSZ) ? 2*TABSZ : (dti >= TABSZ) ? TABSZ : 0;
++ xlate_key = dti;
++ return(xch);
++ }
++ else
++ return(c);
++ }
++
++ void mm_userpwd (NETMBX *mb, char **username, char **password)
++ {
++ char *s;
++ char tmp[MAILTMPLEN], *ui[5];
++ FILE *fp;
++ int i, j, n;
++
++ if (!(pwdfile = env_parameters(GET_PASSWORDFILE, NULL)))
++ return;
++
++ if (fp = fopen(pwdfile, "r")){
++ for(n = 0; fgets(tmp, sizeof(tmp), fp); n++){
++ xlate_key = n;
++ for(i = 0; tmp[i]; i++)
++ tmp[i] = mm_xlate_out(tmp[i]);
++
++ if(i && tmp[i-1] == '\n')
++ tmp[i-1] = '\0';
++
++ ui[0] = ui[1] = ui[2] = ui[3] = ui[4] = NULL;
++ for(i = 0, j = 0; tmp[i] && j < 5; j++){
++ for(ui[j] = &tmp[i]; tmp[i] && tmp[i] != '\t'; i++);
++
++ if(tmp[i])
++ tmp[i++] = '\0';
++ }
++ if (*username && ui[1] && !strcmp(*username, ui[1]) && mb->host
++ && ((ui[2] && !strcmp(mb->host, ui[2]))
++ || (ui[4] && !strcmp(mb->host,ui[4]))
++ || (ui[2] && !strcmp(mb->orighost, ui[2]))
++ || (ui[4] && !strcmp(mb->orighost,ui[4]))))
++ strcpy (*password,ui[0]);
++ }
++ fclose(fp);
++ }
++ }
++
+diff -rc alpine-2.00/imap/src/c-client/mail.h alpine-2.00.I.USE/imap/src/c-client/mail.h
+*** alpine-2.00/imap/src/c-client/mail.h 2008-08-08 10:34:22.000000000 -0700
+--- alpine-2.00.I.USE/imap/src/c-client/mail.h 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 177,182 ****
+--- 177,186 ----
+ #define SET_EXTERNALAUTHID (long) 230
+ #define GET_SSLCAPATH (long) 231
+ #define SET_SSLCAPATH (long) 232
++ #define GET_ERASEPASSWORD (long) 233
++ #define SET_ERASEPASSWORD (long) 234
++ #define SET_PASSWORDFILE (long) 235
++ #define GET_PASSWORDFILE (long) 236
+
+ /* 3xx: TCP/IP */
+ #define GET_OPENTIMEOUT (long) 300
+***************
+*** 353,358 ****
+--- 357,366 ----
+ #define SET_SCANCONTENTS (long) 573
+ #define GET_MHALLOWINBOX (long) 574
+ #define SET_MHALLOWINBOX (long) 575
++ #define GET_COURIERSTYLE (long) 576
++ #define SET_COURIERSTYLE (long) 577
++ #define SET_MDINBOXPATH (long) 578
++ #define GET_MDINBOXPATH (long) 579
+
+ /* Driver flags */
+
+***************
+*** 685,690 ****
+--- 693,699 ----
+ /* Message envelope */
+
+ typedef struct mail_envelope {
++ unsigned int ngpathexists : 1; /* newsgroups may be bogus */
+ unsigned int incomplete : 1; /* envelope may be incomplete */
+ unsigned int imapenvonly : 1; /* envelope only has IMAP envelope */
+ char *remail; /* remail header if any */
+***************
+*** 1302,1308 ****
+ typedef void *(*mailcache_t) (MAILSTREAM *stream,unsigned long msgno,long op);
+ typedef long (*mailproxycopy_t) (MAILSTREAM *stream,char *sequence,
+ char *mailbox,long options);
+! typedef long (*tcptimeout_t) (long overall,long last);
+ typedef void *(*authchallenge_t) (void *stream,unsigned long *len);
+ typedef long (*authrespond_t) (void *stream,char *s,unsigned long size);
+ typedef long (*authcheck_t) (void);
+--- 1311,1317 ----
+ typedef void *(*mailcache_t) (MAILSTREAM *stream,unsigned long msgno,long op);
+ typedef long (*mailproxycopy_t) (MAILSTREAM *stream,char *sequence,
+ char *mailbox,long options);
+! typedef long (*tcptimeout_t) (long overall,long last, char *host);
+ typedef void *(*authchallenge_t) (void *stream,unsigned long *len);
+ typedef long (*authrespond_t) (void *stream,char *s,unsigned long size);
+ typedef long (*authcheck_t) (void);
+***************
+*** 1325,1330 ****
+--- 1334,1340 ----
+ typedef void *(*blocknotify_t) (int reason,void *data);
+ typedef long (*kinit_t) (char *host,char *reason);
+ typedef void (*sendcommand_t) (MAILSTREAM *stream,char *cmd,long flags);
++ typedef void (*deletepwd_t) (NETMBX *mb,char *user);
+ typedef char *(*newsrcquery_t) (MAILSTREAM *stream,char *mulname,char *name);
+ typedef void (*getacl_t) (MAILSTREAM *stream,char *mailbox,ACLLIST *acl);
+ typedef void (*listrights_t) (MAILSTREAM *stream,char *mailbox,char *id,
+***************
+*** 1604,1609 ****
+--- 1614,1621 ----
+ void mm_fatal (char *string);
+ void *mm_cache (MAILSTREAM *stream,unsigned long msgno,long op);
+
++ void delete_password (NETMBX *mb, char *user);
++
+ extern STRINGDRIVER mail_string;
+ void mail_versioncheck (char *version);
+ void mail_link (DRIVER *driver);
+diff -rc alpine-2.00/imap/src/c-client/nntp.c alpine-2.00.I.USE/imap/src/c-client/nntp.c
+*** alpine-2.00/imap/src/c-client/nntp.c 2008-06-04 11:18:34.000000000 -0700
+--- alpine-2.00.I.USE/imap/src/c-client/nntp.c 2011-02-07 20:33:43.000000000 -0800
+***************
+*** 2031,2036 ****
+--- 2031,2037 ----
+ sprintf (tmp,"Retrying using %s authentication after %.80s",
+ at->name,lsterr);
+ mm_log (tmp,NIL);
++ delete_password(mb, mb ? mb->user : NULL);
+ fs_give ((void **) &lsterr);
+ }
+ trial = 0; /* initial trial count */
+***************
+*** 2039,2044 ****
+--- 2040,2046 ----
+ if (lsterr) {
+ sprintf (tmp,"Retrying %s authentication after %.80s",at->name,lsterr);
+ mm_log (tmp,WARN);
++ delete_password(mb, mb ? mb->user : NULL);
+ fs_give ((void **) &lsterr);
+ }
+ stream->saslcancel = NIL;
+***************
+*** 2064,2069 ****
+--- 2066,2072 ----
+ sprintf (tmp,"Can not authenticate to NNTP server: %.80s",lsterr);
+ mm_log (tmp,ERROR);
+ }
++ delete_password(mb, mb ? mb->user : NULL);
+ fs_give ((void **) &lsterr);
+ }
+ else if (mb->secflag) /* no SASL, can't do /secure */
+***************
+*** 2092,2097 ****
+--- 2095,2102 ----
+ stream->sensitive = T; /* hide this command */
+ if (nntp_send_work (stream,"AUTHINFO PASS",pwd) == NNTPAUTHED)
+ ret = LONGT; /* password OK */
++ else
++ delete_password(mb, mb ? mb->user : NULL);
+ stream->sensitive = NIL; /* unhide */
+ if (ret) break; /* OK if successful */
+ default: /* authentication failed */
+diff -rc alpine-2.00/imap/src/c-client/pop3.c alpine-2.00.I.USE/imap/src/c-client/pop3.c
+*** alpine-2.00/imap/src/c-client/pop3.c 2008-06-04 11:18:34.000000000 -0700
+--- alpine-2.00.I.USE/imap/src/c-client/pop3.c 2011-02-07 20:33:43.000000000 -0800
+***************
+*** 615,620 ****
+--- 615,621 ----
+ sprintf (pwd,"Retrying using %.80s authentication after %.80s",
+ at->name,t);
+ mm_log (pwd,NIL);
++ delete_password(mb, usr);
+ fs_give ((void **) &t);
+ }
+ trial = 0; /* initial trial count */
+***************
+*** 622,627 ****
+--- 623,629 ----
+ if (t) {
+ sprintf (pwd,"Retrying %s authentication after %.80s",at->name,t);
+ mm_log (pwd,WARN);
++ delete_password(mb, usr);
+ fs_give ((void **) &t);
+ }
+ LOCAL->saslcancel = NIL;
+***************
+*** 667,672 ****
+--- 669,675 ----
+ LOCAL->sensitive=NIL; /* unhide */
+ }
+ if (!ret) { /* failure */
++ delete_password(mb, usr);
+ mm_log (LOCAL->reply,WARN);
+ if (trial == pop3_maxlogintrials)
+ mm_log ("Too many login failures",ERROR);
+diff -rc alpine-2.00/imap/src/c-client/rfc822.c alpine-2.00.I.USE/imap/src/c-client/rfc822.c
+*** alpine-2.00/imap/src/c-client/rfc822.c 2008-06-04 11:46:10.000000000 -0700
+--- alpine-2.00.I.USE/imap/src/c-client/rfc822.c 2011-02-07 20:33:43.000000000 -0800
+***************
+*** 128,133 ****
+--- 128,134 ----
+ ENVELOPE *env = (*en = mail_newenvelope ());
+ BODY *body = bdy ? (*bdy = mail_newbody ()) : NIL;
+ long MIMEp = -1; /* flag that MIME semantics are in effect */
++ long PathP = NIL; /* flag that a Path: was seen */
+ parseline_t pl = (parseline_t) mail_parameters (NIL,GET_PARSELINE,NIL);
+ if (!host) host = BADHOST; /* make sure that host is non-null */
+ while (i && *s != '\n') { /* until end of header */
+***************
+*** 230,235 ****
+--- 231,239 ----
+ *t++ = '\0';
+ }
+ break;
++ case 'P': /* possible Path: */
++ if (!strcmp (tmp+1,"ATH")) env->ngpathexists = T;
++ break;
+ case 'R': /* possible Reply-To: */
+ if (!strcmp (tmp+1,"EPLY-TO"))
+ rfc822_parse_adrlist (&env->reply_to,d,host);
+diff -rc alpine-2.00/imap/src/osdep/mac/tcp_mac.c alpine-2.00.I.USE/imap/src/osdep/mac/tcp_mac.c
+*** alpine-2.00/imap/src/osdep/mac/tcp_mac.c 2008-06-04 11:18:34.000000000 -0700
+--- alpine-2.00.I.USE/imap/src/osdep/mac/tcp_mac.c 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 383,389 ****
+ if (stream->pb.ioResult) { /* punt if got an error */
+ time_t tc = time (0);
+ if ((stream->pb.ioResult == commandTimeout) && tmoh &&
+! ((*tmoh) (tc - t,tc - tl))) continue;
+ /* nuke connection */
+ stream->pb.csCode = TCPAbort;
+ abortpb->userDataPtr = NIL;
+--- 383,389 ----
+ if (stream->pb.ioResult) { /* punt if got an error */
+ time_t tc = time (0);
+ if ((stream->pb.ioResult == commandTimeout) && tmoh &&
+! ((*tmoh) (tc - t,tc - tl, stream->host))) continue;
+ /* nuke connection */
+ stream->pb.csCode = TCPAbort;
+ abortpb->userDataPtr = NIL;
+diff -rc alpine-2.00/imap/src/osdep/nt/tcp_nt.c alpine-2.00.I.USE/imap/src/osdep/nt/tcp_nt.c
+*** alpine-2.00/imap/src/osdep/nt/tcp_nt.c 2008-06-04 11:18:34.000000000 -0700
+--- alpine-2.00.I.USE/imap/src/osdep/nt/tcp_nt.c 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 430,436 ****
+ SOCKET_ERROR) &&
+ ((errno = WSAGetLastError ()) == WSAEINTR));
+ else if (!i) { /* timeout, ignore if told to resume */
+! if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl))) continue;
+ /* otherwise punt */
+ if (tcpdebug) mm_log ("TCP buffer read timeout",TCPDEBUG);
+ return tcp_abort (stream);
+--- 430,438 ----
+ SOCKET_ERROR) &&
+ ((errno = WSAGetLastError ()) == WSAEINTR));
+ else if (!i) { /* timeout, ignore if told to resume */
+! if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl),
+! stream->host))
+! continue;
+ /* otherwise punt */
+ if (tcpdebug) mm_log ("TCP buffer read timeout",TCPDEBUG);
+ return tcp_abort (stream);
+***************
+*** 498,504 ****
+ SOCKET_ERROR) &&
+ ((errno = WSAGetLastError ()) == WSAEINTR));
+ else if (!i) { /* timeout, ignore if told to resume */
+! if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl))) continue;
+ /* otherwise punt */
+ if (tcpdebug) mm_log ("TCP data read timeout",TCPDEBUG);
+ return tcp_abort (stream);
+--- 500,507 ----
+ SOCKET_ERROR) &&
+ ((errno = WSAGetLastError ()) == WSAEINTR));
+ else if (!i) { /* timeout, ignore if told to resume */
+! if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl), stream->host))
+! continue;
+ /* otherwise punt */
+ if (tcpdebug) mm_log ("TCP data read timeout",TCPDEBUG);
+ return tcp_abort (stream);
+***************
+*** 582,588 ****
+ SOCKET_ERROR) &&
+ ((errno = WSAGetLastError ()) == WSAEINTR));
+ else if (!i) { /* timeout, ignore if told to resume */
+! if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl))) continue;
+ /* otherwise punt */
+ if (tcpdebug) mm_log ("TCP write timeout",TCPDEBUG);
+ return tcp_abort (stream);
+--- 585,592 ----
+ SOCKET_ERROR) &&
+ ((errno = WSAGetLastError ()) == WSAEINTR));
+ else if (!i) { /* timeout, ignore if told to resume */
+! if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl), stream->host))
+! continue;
+ /* otherwise punt */
+ if (tcpdebug) mm_log ("TCP write timeout",TCPDEBUG);
+ return tcp_abort (stream);
+diff -rc alpine-2.00/imap/src/osdep/unix/dummy.c alpine-2.00.I.USE/imap/src/osdep/unix/dummy.c
+*** alpine-2.00/imap/src/osdep/unix/dummy.c 2008-06-04 11:18:34.000000000 -0700
+--- alpine-2.00.I.USE/imap/src/osdep/unix/dummy.c 2011-02-07 20:33:41.000000000 -0800
+***************
+*** 106,118 ****
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+!
+ DRIVER *dummy_valid (char *name)
+ {
+! char *s,tmp[MAILTMPLEN];
+ struct stat sbuf;
+ /* must be valid local mailbox */
+! if (name && *name && (*name != '{') && (s = mailboxfile (tmp,name))) {
+ /* indeterminate clearbox INBOX */
+ if (!*s) return &dummydriver;
+ else if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) {
+--- 106,124 ----
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+! char * maildir_remove_root(char *);
+ DRIVER *dummy_valid (char *name)
+ {
+! char *s,tmp[MAILTMPLEN], *rname;
+ struct stat sbuf;
++
++ if(strlen(name) > MAILTMPLEN)
++ name[MAILTMPLEN] = '\0';
++
++ strcpy(tmp, name);
++ rname = maildir_remove_root(tmp);
+ /* must be valid local mailbox */
+! if (rname && *rname && (*rname != '{') && (s = mailboxfile (tmp,rname))) {
+ /* indeterminate clearbox INBOX */
+ if (!*s) return &dummydriver;
+ else if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) {
+***************
+*** 121,128 ****
+ return &dummydriver;
+ }
+ /* blackbox INBOX does not exist yet */
+! else if (!compare_cstring (name,"INBOX")) return &dummydriver;
+ }
+ return NIL;
+ }
+
+--- 127,135 ----
+ return &dummydriver;
+ }
+ /* blackbox INBOX does not exist yet */
+! else if (!compare_cstring (rname,"INBOX")) return &dummydriver;
+ }
++ if(rname) fs_give((void **)&rname);
+ return NIL;
+ }
+
+***************
+*** 454,459 ****
+--- 461,468 ----
+ {
+ char *s,tmp[MAILTMPLEN];
+ long ret = NIL;
++ if(!strncmp(mailbox,"#md/",4) || !strncmp(mailbox,"#mc/", 4))
++ return maildir_create(stream, mailbox);
+ /* validate name */
+ if (!(compare_cstring (mailbox,"INBOX") && (s = dummy_file (tmp,mailbox)))) {
+ sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
+***************
+*** 519,524 ****
+--- 528,541 ----
+ {
+ struct stat sbuf;
+ char *s,tmp[MAILTMPLEN];
++ if (!strncmp(mailbox,"#md/",4) || !strncmp(mailbox,"#mc/", 4)
++ || is_valid_maildir(&mailbox)){
++ char tmp[MAILTMPLEN] = {'\0'};
++ strcpy(tmp, mailbox);
++ if(tmp[strlen(tmp) - 1] != '/')
++ tmp[strlen(tmp)] = '/';
++ return maildir_delete(stream, tmp);
++ }
+ if (!(s = dummy_file (tmp,mailbox))) {
+ sprintf (tmp,"Can't delete - invalid name: %.80s",s);
+ MM_LOG (tmp,ERROR);
+***************
+*** 544,555 ****
+ long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
+ {
+ struct stat sbuf;
+! char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN];
+ /* no trailing / allowed */
+! if (!dummy_file (oldname,old) || !(s = dummy_file (mbx,newname)) ||
+ stat (oldname,&sbuf) || ((s = strrchr (s,'/')) && !s[1] &&
+ ((sbuf.st_mode & S_IFMT) != S_IFDIR))) {
+! sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",old,newname);
+ MM_LOG (mbx,ERROR);
+ return NIL;
+ }
+--- 561,583 ----
+ long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
+ {
+ struct stat sbuf;
+! char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN], *rold, *rnewname;
+!
+! if(strlen(old) > MAILTMPLEN)
+! old[MAILTMPLEN] = '\0';
+!
+! if(strlen(newname) > MAILTMPLEN)
+! newname[MAILTMPLEN] = '\0';
+!
+! strcpy(tmp, old);
+! rold = maildir_remove_root(tmp);
+! strcpy(tmp, newname);
+! rnewname = maildir_remove_root(tmp);
+ /* no trailing / allowed */
+! if (!dummy_file (oldname,rold) || !(s = dummy_file (mbx,rnewname)) ||
+ stat (oldname,&sbuf) || ((s = strrchr (s,'/')) && !s[1] &&
+ ((sbuf.st_mode & S_IFMT) != S_IFDIR))) {
+! sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",rold,rnewname);
+ MM_LOG (mbx,ERROR);
+ return NIL;
+ }
+***************
+*** 565,578 ****
+ }
+ }
+ /* rename of non-ex INBOX creates dest */
+! if (!compare_cstring (old,"INBOX") && stat (oldname,&sbuf))
+ return dummy_create (NIL,mbx);
+ if (rename (oldname,mbx)) {
+! sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",old,newname,
+ strerror (errno));
+ MM_LOG (tmp,ERROR);
+ return NIL;
+ }
+ return T; /* return success */
+ }
+
+--- 593,608 ----
+ }
+ }
+ /* rename of non-ex INBOX creates dest */
+! if (!compare_cstring (rold,"INBOX") && stat (oldname,&sbuf))
+ return dummy_create (NIL,mbx);
+ if (rename (oldname,mbx)) {
+! sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",rold,rnewname,
+ strerror (errno));
+ MM_LOG (tmp,ERROR);
+ return NIL;
+ }
++ if(rold) fs_give((void **)&rold);
++ if(rnewname) fs_give((void **)&rnewname);
+ return T; /* return success */
+ }
+
+diff -rc alpine-2.00/imap/src/osdep/unix/maildir.c alpine-2.00.I.USE/imap/src/osdep/unix/maildir.c
+*** alpine-2.00/imap/src/osdep/unix/maildir.c 2011-02-07 20:34:02.000000000 -0800
+--- alpine-2.00.I.USE/imap/src/osdep/unix/maildir.c 2011-02-07 20:33:41.000000000 -0800
+***************
+*** 0 ****
+--- 1,2584 ----
++ /*
++ * Maildir driver for Alpine 2.00
++ *
++ * Written by Eduardo Chappa <chappa@washington.edu>
++ * Last Update: November 6, 2010.
++ *
++ */
++
++ #include <stdio.h>
++ #include <ctype.h>
++ #include <errno.h>
++ extern int errno; /* just in case */
++ #include "mail.h"
++ #include <pwd.h>
++ #include <sys/stat.h>
++ #include <sys/time.h>
++ #include "osdep.h"
++ #include "rfc822.h"
++ #include "fdstring.h"
++ #include "misc.h"
++ #include "dummy.h"
++ #include "maildir.h"
++
++ /* Driver dispatch used by MAIL */
++ DRIVER maildirdriver = {
++ "md", /* driver name, yes it's md, not maildir */
++ /* driver flags */
++ DR_MAIL|DR_LOCAL|DR_NAMESPACE|DR_DIRFMT,
++ (DRIVER *) NIL, /* next driver */
++ maildir_valid, /* mailbox is valid for us */
++ maildir_parameters, /* manipulate parameters */
++ NIL, /* scan mailboxes */
++ maildir_list, /* find mailboxes */
++ maildir_lsub, /* find subscribed mailboxes */
++ maildir_sub, /* subscribe to mailbox */
++ maildir_unsub, /* unsubscribe from mailbox */
++ maildir_create, /* create mailbox */
++ maildir_delete, /* delete mailbox */
++ maildir_rename, /* rename mailbox */
++ mail_status_default, /* status of mailbox */
++ maildir_open, /* open mailbox */
++ maildir_close, /* close mailbox */
++ maildir_fast, /* fetch message "fast" attributes */
++ NIL, /* fetch message flags */
++ NIL, /* fetch overview */
++ NIL, /* fetch message structure */
++ maildir_header, /* fetch message header */
++ maildir_text, /* fetch message body */
++ NIL, /* fetch partial message text */
++ NIL, /* unique identifier */
++ NIL, /* message number */
++ NIL, /* modify flags */
++ maildir_flagmsg, /* per-message modify flags */
++ NIL, /* search for message based on criteria */
++ NIL, /* sort messages */
++ NIL, /* thread messages */
++ maildir_ping, /* ping mailbox to see if still alive */
++ maildir_check, /* check for new messages */
++ maildir_expunge, /* expunge deleted messages */
++ maildir_copy, /* copy messages to another mailbox */
++ maildir_append, /* append string message to mailbox */
++ NIL /* garbage collect stream */
++ };
++
++
++ DRIVER courierdriver = {
++ "mc", /* Why a separate driver? So that
++ createproto will work */
++ /* driver flags */
++ DR_MAIL|DR_LOCAL|DR_NAMESPACE|DR_DIRFMT,
++ (DRIVER *) NIL, /* next driver */
++ maildir_valid, /* mailbox is valid for us */
++ maildir_parameters, /* manipulate parameters */
++ NIL, /* scan mailboxes */
++ courier_list, /* find mailboxes */
++ maildir_lsub, /* find subscribed mailboxes */
++ maildir_sub, /* subscribe to mailbox */
++ maildir_unsub, /* unsubscribe from mailbox */
++ maildir_create, /* create mailbox */
++ maildir_delete, /* delete mailbox */
++ maildir_rename, /* rename mailbox */
++ mail_status_default, /* status of mailbox */
++ maildir_open, /* open mailbox */
++ maildir_close, /* close mailbox */
++ maildir_fast, /* fetch message "fast" attributes */
++ NIL, /* fetch message flags */
++ NIL, /* fetch overview */
++ NIL, /* fetch message structure */
++ maildir_header, /* fetch message header */
++ maildir_text, /* fetch message body */
++ NIL, /* fetch partial message text */
++ NIL, /* unique identifier */
++ NIL, /* message number */
++ NIL, /* modify flags */
++ maildir_flagmsg, /* per-message modify flags */
++ NIL, /* search for message based on criteria */
++ NIL, /* sort messages */
++ NIL, /* thread messages */
++ maildir_ping, /* ping mailbox to see if still alive */
++ maildir_check, /* check for new messages */
++ maildir_expunge, /* expunge deleted messages */
++ maildir_copy, /* copy messages to another mailbox */
++ maildir_append, /* append string message to mailbox */
++ NIL /* garbage collect stream */
++ };
++
++ MAILSTREAM maildirproto = {&maildirdriver}; /* prototype stream */
++ MAILSTREAM courierproto = {&courierdriver}; /* prototype stream */
++
++ long maildir_dirfmttest (char *name)
++ {
++ int i;
++ for (i = 0; mdstruct[i] && strcmp(name, mdstruct[i]); i++);
++ return (i < EndDir) || !strcmp(name, MDDIR)
++ || !strncmp(name, MDUIDLAST, strlen(MDUIDLAST))
++ || !strncmp(name, MDUIDTEMP, strlen(MDUIDTEMP)) ? LONGT : NIL;
++ }
++
++ void
++ md_domain_name(void)
++ {
++ int i;
++
++ strcpy(mdlocaldomain,mylocalhost ());
++ for (i = 0; mdlocaldomain[i] ; i++)
++ if(mdlocaldomain[i] == '/')
++ mdlocaldomain[i] = '\057';
++ else if (mdlocaldomain[i] == ':')
++ mdlocaldomain[i] = '\072';
++ }
++
++ char *
++ myrootdir(char *name)
++ {
++ return myhomedir();
++ }
++
++ char *
++ mdirpath(void)
++ {
++ char *path = maildir_parameters(GET_MDINBOXPATH,NIL);
++ return path ? (path[0] ? path : ".") : "Maildir";
++ }
++
++ /* remove the "#md/" or "#mc/" part from a folder name */
++ char *
++ maildir_remove_root (char *name)
++ {
++ int courier = IS_COURIER(name), offset;
++ char realname[MAILTMPLEN];
++
++ offset = maildir_valid_name(name) ? (name[3] == '/' ? 4 : 3) : 0;
++ if(courier)
++ courier_realname(name+offset, realname);
++ else
++ strcpy(realname, name+offset);
++ return cpystr(realname);
++ }
++
++
++ /* Check validity of the name, we accept:
++ * a) #md/directory/folder
++ * b) #md/inbox
++ * A few considerations: We can only accept as valid
++ * a) names that start with #md/ and the directory exists or
++ * b) names that do not start with #md/ but are maildir directories (have
++ * the /cur, /tmp and /new structure)
++ */
++ int maildir_valid_name (char *name)
++ {
++ char tmpname[MAILTMPLEN] = {'\0'};
++
++ if (mdfpath)
++ fs_give((void **)&mdfpath);
++ if (name && (name[0] != '#'))
++ sprintf(tmpname,"%s%s",MDPREFIX(CCLIENT), name);
++ mdfpath = cpystr(tmpname[0] ? tmpname : name);
++
++ return IS_CCLIENT(name) || IS_COURIER(name);
++ }
++
++ /* Check if the directory whose path is given by name is a valid maildir
++ * directory (contains /cur, /tmp and /new)
++ */
++ int maildir_valid_dir (char *name)
++ {
++ int len;
++ DirNamesType i;
++ struct stat sbuf;
++ char tmp[MAILTMPLEN];
++
++ if(name[strlen(name) - 1] == '/')
++ name[strlen(name) - 1] = '\0';
++ len = strlen(name);
++ for (i = Cur; i != EndDir; i++){
++ MDFLD(tmp, name, i);
++ if (stat(tmp, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode))
++ break;
++ }
++ name[len] = '\0';
++ return (i == EndDir) ? T : NIL;
++ }
++
++ void courier_realname(char *name, char *realname)
++ {
++ int i,j;
++
++ if(!name)
++ return;
++
++ for (i = 0, j = 0; i < MAILTMPLEN && j < strlen(name); j++, i++){
++ realname[i] = name[j];
++ if(name[j] == '/' && name[j+1] != '.' && name[j+1] != '%'
++ && name[j+1] != '*')
++ realname[++i] = '.';
++ }
++ if(realname[i-1] == '.')
++ i--;
++ realname[i] = '\0';
++ }
++
++
++ /* given a maildir folder, return its path. Memory freed by caller. Directory
++ * does not contain the trailing slash "/". On error NULL is returned.
++ */
++ int maildir_file_path (char *name, char *tmp)
++ {
++ char *maildirpath = mdirpath(), *rname;
++ int courier = IS_COURIER(name);
++
++ /* There are several ways in which the path can come, so we will handle
++ them here. First we deal with #mc/ or #md/ prefix by removing the
++ prefix, if any */
++
++ if(strlen(name) >= MAILTMPLEN)
++ name[MAILTMPLEN] = '\0';
++ strcpy(tmp, name);
++ rname = maildir_remove_root(tmp);
++ tmp[0] = '\0'; /* just in case something fails */
++
++ if (strlen(myrootdir(rname)) +
++ max(strlen(rname), strlen(maildirpath)) > MAILTMPLEN){
++ errno = ENAMETOOLONG;
++ sprintf(tmp,"Error opening \"%s\": %s", rname, strerror (errno));
++ mm_log(tmp,ERROR);
++ return NIL;
++ }
++
++ /* There are two ways in which the name can come here, either as a
++ full path or not. If it is not a full path it can come in two ways,
++ either as a file system path (Maildir/.Drafts) or as a maildir path
++ (INBOX.Drafts)
++ */
++
++ if(*rname == '/') /* full path */
++ strcpy(tmp, rname); /* do nothing */
++ else{
++ sprintf (tmp,"%s/%s%s%s", myrootdir (rname),
++ strncmp (ucase (strcpy (tmp, rname)), "INBOX", 5)
++ ? rname : maildirpath,
++ strncmp (ucase (strcpy (tmp, rname)), "INBOX", 5)
++ ? "" : (courier ? "/" : ""),
++ strncmp (ucase (strcpy (tmp, rname)), "INBOX", 5)
++ ? "" : (*(rname+5) == MDSEPARATOR(courier) ? rname+5 : ""));
++ }
++ if(rname) fs_give((void **)&rname);
++ return tmp[0] ? T : NIL;
++ }
++
++ /* This function is given a full path for a mailbox and returns
++ * if it is a valid maildir transformed to canonical notation
++ */
++ int
++ is_valid_maildir (char **name)
++ {
++ if (!strncmp(*name, myrootdir (*name), strlen(myrootdir(*name)))){
++ (*name) += strlen(myrootdir(*name));
++ if (**name == '/') (*name)++;
++ }
++ return maildir_valid(*name) ? T : NIL;
++ }
++
++ /* Check validity of mailbox. This routine does not send errors to log, other
++ * routines calling this one may do so, though
++ */
++
++ DRIVER *maildir_valid (char *name)
++ {
++ char tmpname[MAILTMPLEN];
++
++ maildir_file_path(name, tmpname);
++
++ return maildir_valid_dir(tmpname)
++ ? (IS_COURIER(name) ? &courierdriver : &maildirdriver) : NIL;
++ }
++
++ void maildir_fast (MAILSTREAM *stream,char *sequence,long flags)
++ {
++ unsigned long i;
++ MESSAGECACHE *elt;
++ /* get sequence */
++ if (stream && LOCAL && ((flags & FT_UID) ?
++ mail_uid_sequence (stream,sequence) :
++ mail_sequence (stream,sequence)))
++ for (i = 1L; i <= stream->nmsgs; i++) {
++ if ((elt = mail_elt (stream,i))->sequence && (elt->valid = T) &&
++ !(elt->day && elt->rfc822_size)) {
++ ENVELOPE **env = NIL;
++ ENVELOPE *e = NIL;
++ if (!stream->scache) env = &elt->private.msg.env;
++ else if (stream->msgno == i) env = &stream->env;
++ else env = &e;
++ if (!*env || !elt->rfc822_size) {
++ STRING bs;
++ unsigned long hs;
++ char *ht = (*stream->dtb->header) (stream,i,&hs,NIL);
++
++ if (!*env) rfc822_parse_msg (env,NIL,ht,hs,NIL,BADHOST,
++ stream->dtb->flags);
++ if (!elt->rfc822_size) {
++ (*stream->dtb->text) (stream,i,&bs,FT_PEEK);
++ elt->rfc822_size = hs + SIZE (&bs) - GETPOS (&bs);
++ }
++ }
++
++ if (!elt->day && *env && (*env)->date)
++ mail_parse_date (elt,(*env)->date);
++
++ if (!elt->day) elt->day = elt->month = 1;
++ mail_free_envelope (&e);
++ }
++ }
++ }
++
++ int
++ maildir_eliminate_duplicate (char *name, struct direct ***flist, unsigned long *nfiles)
++ {
++ int i, j, k, error = 0, scanr;
++ char new[MAILTMPLEN], old[MAILTMPLEN], tmp[MAILTMPLEN], *str;
++ struct direct **names = NIL;
++
++ if((scanr = maildir_doscandir(name, &names, CCLIENT)) < 0)
++ return -1;
++
++ if(nfiles) *nfiles = scanr;
++ for(i = 0, j = 1, k = 0; j < scanr; i++, j++){
++ if(k)
++ names[i] = names[i+k];
++ if(same_maildir_file(names[i]->d_name, names[j]->d_name)){
++ int d, f, r, s;
++ maildir_getflag(names[i]->d_name, &d, &f, &r, &s, NIL);
++ sprintf(old,"%s/%s", name, names[i]->d_name);
++ sprintf(new,"%s/.%s", name, names[i]->d_name);
++ if(rename(old, new) < 0 && errno != EEXIST)
++ error++;
++ if(!error){
++ for(; j < scanr
++ && same_maildir_file(names[i]->d_name, names[j]->d_name)
++ ; j++, k++){
++ maildir_getflag(names[j]->d_name, (d ? NIL : &d),
++ (f ? NIL : &f), (r ? NIL : &r), (s ? NIL : &s), NIL);
++ sprintf(tmp,"%s/%s", name, names[j]->d_name);
++ if(unlink(tmp) < 0){ /* Hmmm... a problem, let's see */
++ struct stat sbuf;
++ if (stat(tmp, &sbuf) == 0 && (sbuf.st_mode & S_IFMT) == S_IFREG)
++ error++;
++ }
++ }
++ if((str = strrchr(names[i]->d_name,FLAGSEP)) != NULL) *str = '\0';
++ sprintf (old,"%s/%s%s%s%s%s%s", name, names[i]->d_name, MDSEP(2),
++ MDFLAG(Draft, d), MDFLAG(Flagged, f), MDFLAG(Replied, r),
++ MDFLAG(Seen, s));
++ if(rename(new, old) < 0)
++ error++;
++ }
++ }
++
++ }
++ if(k > 0)
++ fs_give((void **)&names);
++ else
++ *flist = names;
++ return error ? -1 : k;
++ }
++
++ int
++ maildir_doscandir(char *name, struct direct ***flist, int flag)
++ {
++ return scandir(name, flist,
++ flag == CCLIENT ? maildir_select : courier_dir_select,
++ flag == CCLIENT ? maildir_namesort : courier_dir_sort);
++ }
++
++ /*
++ * return all files in a given directory. This is a separate call
++ * so that if there are warnings during compilation this only appears once.
++ */
++ unsigned long
++ maildir_scandir (char *name, struct direct ***flist,
++ unsigned long *nfiles, int *scand, int flag)
++ {
++ struct stat sbuf;
++ int rv = -2; /* impossible value */
++
++ if (scand)
++ *scand = -1; /* assume error for safety */
++ *nfiles = 0;
++ if((stat(name,&sbuf) < 0)
++ || (flag == CCLIENT
++ && ((rv = maildir_eliminate_duplicate(name, flist, nfiles)) < 0)))
++ return 0L;
++
++ if (scand && (rv > 0 || rv == -2))
++ *nfiles = maildir_doscandir(name, flist, flag);
++
++ if(scand) *scand = *nfiles;
++
++ return (unsigned long) sbuf.st_ctime;
++ }
++
++ /* Does a message with given name exists (or was it removed)?
++ * Returns: 1 - yes, such message exist,
++ * 0 - No, that message does not exist anymore
++ *
++ * Parameters: stream, name of mailbox, new name if his message does not
++ * exist.
++ */
++
++ int maildir_message_exists(MAILSTREAM *stream, char *name, char *newfile)
++ {
++ char tmp[MAILTMPLEN];
++ int gotit = NIL;
++ DIR *dir;
++ struct direct *d;
++ struct stat sbuf;
++
++ /* First check directly if it exists, if not there, look for it */
++ sprintf(tmp,"%s/%s", LOCAL->curdir, name);
++ if ((stat(tmp, &sbuf) == 0) && ((sbuf.st_mode & S_IFMT) == S_IFREG))
++ return T;
++
++ if (!(dir = opendir (LOCAL->curdir)))
++ return NIL;
++
++ while ((d = readdir(dir)) && gotit == NIL){
++ if (d->d_name[0] == '.')
++ continue;
++ if (same_maildir_file(d->d_name, name)){
++ gotit = T;
++ strcpy(newfile, d->d_name);
++ }
++ }
++ closedir(dir);
++ return gotit;
++ }
++
++ /* Maildir open */
++
++ MAILSTREAM *maildir_open (MAILSTREAM *stream)
++ {
++ char tmp[MAILTMPLEN];
++ struct stat sbuf;
++
++ if (!stream) return &maildirproto;
++ if (stream->local) fatal ("maildir recycle stream");
++ md_domain_name(); /* get domain name for maildir files in mdlocaldomain */
++ if(mypid == (pid_t) 0)
++ mypid = getpid();
++ if (!stream->rdonly){
++ stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
++ stream->perm_answered = stream->perm_draft = T;
++ }
++ stream->local = (MAILDIRLOCAL *) fs_get (sizeof (MAILDIRLOCAL));
++ memset(LOCAL, 0, sizeof(MAILDIRLOCAL));
++ LOCAL->fd = -1;
++
++ LOCAL->courier = IS_COURIER(stream->mailbox);
++ strcpy(tmp, stream->mailbox);
++ if (maildir_file_path (stream->mailbox, tmp))
++ LOCAL->dir = cpystr (tmp);
++ LOCAL->candouid = maildir_can_assign_uid(stream);
++ maildir_read_uid(stream, &stream->uid_last, &stream->uid_validity);
++ if (LOCAL->dir){
++ MDFLD(tmp, LOCAL->dir, Cur);
++ LOCAL->curdir = cpystr (tmp);
++ if (stat (LOCAL->curdir,&sbuf) < 0) {
++ sprintf (tmp,"Can't open folder %s: %s",
++ stream->mailbox,strerror (errno));
++ mm_log (tmp,ERROR);
++ maildir_close(stream, 0);
++ return NIL;
++ }
++ }
++
++ if(maildir_file_path (stream->mailbox, tmp)){
++ fs_give ((void **) &stream->mailbox);
++ stream->mailbox = cpystr(tmp);
++ }
++
++ LOCAL->buf = (char *) fs_get ((LOCAL->buflen = SENDBUFLEN) + 1);
++ stream->sequence++;
++ stream->nmsgs = stream->recent = 0L;
++
++ maildir_parse_folder(stream, 1);
++
++ return stream;
++ }
++
++ /* Maildir initial parsing of the folder */
++ void
++ maildir_parse_folder (MAILSTREAM *stream, int full)
++ {
++ char tmp[MAILTMPLEN], tmp2[MAILTMPLEN];
++ struct direct **namescur = NIL, **namesnew = NIL;
++ unsigned long i, nfilescur = 0L, nfilesnew = 0L, oldpos, newpos, total;
++ int scan_err, rescan, loop = 0;
++
++ if (!stream) /* what??? */
++ return;
++
++ MM_CRITICAL(stream);
++
++ MDFLD(tmp, LOCAL->dir, New);
++ maildir_scandir (tmp, &namesnew, &nfilesnew, &scan_err, CCLIENT);
++ if (scan_err < 0)
++ maildir_abort(stream);
++
++ /* Scan old messages first, escoba! */
++ if(stream->rdonly ||
++ (LOCAL && ((maildir_initial_check(stream, Cur) == 0)
++ || nfilesnew > 0L))){
++ MDFLD(tmp, LOCAL->dir, Cur);
++ LOCAL->scantime = maildir_scandir (tmp, &namescur, &nfilescur,
++ &scan_err, CCLIENT);
++ if (scan_err < 0){
++ if(namesnew){
++ for(i = 0L; i < nfilesnew; i++)
++ fs_give((void **)&namesnew[i]);
++ fs_give((void **) &namesnew);
++ }
++ maildir_abort(stream);
++ }
++ }
++ if(LOCAL && (maildir_initial_check(stream, New) == 0)
++ && (nfilescur > 0L)){
++ MDFLD(tmp, LOCAL->dir, New);
++ while(LOCAL && loop < 10){
++ if(nfilesnew == 0L)
++ maildir_scandir (tmp, &namesnew, &nfilesnew, &scan_err, CCLIENT);
++ if (scan_err < 0){
++ if(namesnew){
++ for(i = 0L; i < nfilesnew; i++)
++ fs_give((void **)&namesnew[i]);
++ fs_give((void **) &namesnew);
++ }
++ maildir_abort(stream);
++ break;
++ }
++ for(i = 0L, rescan = 0, newpos = oldpos = 0L;
++ newpos < nfilescur && i < nfilesnew; i++){
++ if(maildir_message_in_list(namesnew[i]->d_name, namescur, oldpos,
++ nfilescur - 1L, &newpos)){
++ oldpos = newpos;
++ sprintf(tmp2,"%s/%s",tmp,namesnew[i]->d_name);
++ if(unlink(tmp2) < 0)
++ scan_err = -1;
++ rescan++;
++ }
++ else
++ newpos = oldpos;
++ }
++ if(scan_err < 0)
++ maildir_abort(stream);
++ if(rescan == 0)
++ break;
++ else{ /* restart */
++ if(namesnew){
++ for(i = 0L; i < nfilesnew; i++)
++ fs_give((void **)&namesnew[i]);
++ fs_give((void **) &namesnew);
++ }
++ nfilesnew = 0L;
++ loop++;
++ }
++ }
++ }
++ if(loop == 10)
++ maildir_abort(stream);
++ if(LOCAL){
++ if(stream->rdonly)
++ stream->recent = 0L;
++ total = namescur || stream->rdonly
++ ? maildir_parse_dir(stream, 0L, Cur, namescur,
++ nfilescur, full) : stream->nmsgs;
++ stream->nmsgs = maildir_parse_dir(stream, total, New, namesnew,
++ nfilesnew, full);
++ }
++ if(namesnew){
++ for(i = 0L; i < nfilesnew; i++)
++ fs_give((void **)&namesnew[i]);
++ fs_give((void **) &namesnew);
++ }
++ if(namescur){
++ for(i = 0L; i < nfilescur; i++)
++ fs_give((void **)&namescur[i]);
++ fs_give((void **) &namescur);
++ }
++ MM_NOCRITICAL(stream);
++ }
++
++ int
++ maildir_initial_check (MAILSTREAM *stream, DirNamesType dirtype)
++ {
++ char tmp[MAILTMPLEN];
++ struct stat sbuf;
++
++ MDFLD(tmp, LOCAL->dir, dirtype);
++ if (access (tmp, R_OK|W_OK|X_OK) != 0){
++ maildir_abort(stream);
++ return -1;
++ }
++
++ MDFLD(tmp, LOCAL->dir, Cur);
++ if (dirtype != New &&
++ (stat(tmp, &sbuf) < 0 || sbuf.st_ctime == LOCAL->scantime))
++ return -1;
++ return 0;
++ }
++
++
++ /* Return the number of messages in the directory, while filling the
++ * elt structure.
++ */
++
++ unsigned long
++ maildir_parse_dir(MAILSTREAM *stream, unsigned long nmsgs,
++ DirNamesType dirtype, struct direct **names,
++ unsigned long nfiles, int full)
++ {
++ char tmp[MAILTMPLEN], tmp2[MAILTMPLEN], file[MAILTMPLEN],
++ newfile[MAILTMPLEN], *mdstr;
++ struct stat sbuf;
++ unsigned long i, new = 0L, l, uid_last;
++ unsigned long recent = stream ? stream->recent : 0L;
++ int d = 0, f = 0, r = 0, s = 0, t = 0;
++ int we_compute, in_list;
++ int silent = stream ? stream->silent : NIL;
++ MESSAGECACHE *elt;
++
++ MDFLD(tmp, LOCAL->dir, dirtype);
++ if (dirtype == Cur && !stream->rdonly)
++ for (i = 1L; i <= stream->nmsgs;){
++ elt = mail_elt(stream, i);
++ in_list = elt && elt->private.spare.ptr && nfiles > 0L
++ ? (MDPOS(elt) < nfiles
++ ? same_maildir_file(MDFILE(elt), names[MDPOS(elt)]->d_name)
++ : NIL)
++ || maildir_message_in_list(MDFILE(elt), names, 0L,
++ nfiles - 1L, &MDPOS(elt))
++ : NIL;
++ if (!in_list){
++ if (elt->private.spare.ptr)
++ maildir_free_file ((void **) &elt->private.spare.ptr);
++
++ if (elt->recent) --recent;
++ mail_expunged(stream,i);
++ }
++ else i++;
++ }
++
++ stream->silent = T;
++ uid_last = 0L;
++ for (we_compute = 0, i = l = 1L; l <= nfiles; l++){
++ unsigned long pos, uid;
++ if (dirtype == New && !stream->rdonly){ /* move new messages to cur */
++ pos = l - 1L;
++ sprintf (file,"%s/%s", tmp, names[pos]->d_name);
++ if(lstat(file,&sbuf) == 0)
++ switch(sbuf.st_mode & S_IFMT){
++ case S_IFREG:
++ strcpy(tmp2, names[pos]->d_name);
++ if((mdstr = strstr(tmp2,MDSEP(3)))
++ || (mdstr = strstr(tmp2,MDSEP(2))))
++ *(mdstr+1) = '2';
++ else
++ strcat(tmp2, MDSEP(2));
++ sprintf(newfile, "%s/%s",LOCAL->curdir, tmp2);
++ if(rename (file, newfile) != 0){
++ mm_log("Unable to read new mail!", WARN);
++ continue;
++ }
++ unlink (file);
++ new++;
++ break;
++ case S_IFLNK: /* clean up, clean up, everybody, everywhere */
++ if(unlink(file) < 0){
++ if(LOCAL->link == NIL){
++ mm_log("Unable to remove symbolic link", WARN);
++ LOCAL->link = T;
++ }
++ }
++ continue;
++ break;
++ default:
++ if(LOCAL && LOCAL->link == NIL){
++ mm_log("Unrecognized file or link in folder", WARN);
++ LOCAL->link = T;
++ }
++ continue;
++ break;
++ }
++ }
++ mail_exists(stream, i + nmsgs);
++ elt = mail_elt(stream, i + nmsgs);
++ pos = (elt && elt->private.spare.ptr) ? MDPOS(elt) : l - 1L;
++ if (dirtype == New) elt->recent = T;
++ maildir_getflag(names[pos]->d_name, &d, &f, &r ,&s, &t);
++ if (elt->private.spare.ptr)
++ maildir_free_file_only ((void **)&elt->private.spare.ptr);
++ else{
++ maildir_get_file((MAILDIRFILE **)&elt->private.spare.ptr);
++ we_compute++;
++ }
++ MDFILE(elt) = cpystr(names[pos]->d_name);
++ MDPOS(elt) = pos;
++ MDLOC(elt) = dirtype;
++ if (dirtype == Cur){ /* deal with UIDs */
++ if(elt->private.uid == 0L)
++ elt->private.uid = maildir_get_uid(MDFILE(elt));
++ if(elt->private.uid <= uid_last){
++ uid = (we_compute ? uid_last : stream->uid_last) + 1L;
++ if(LOCAL->candouid)
++ maildir_assign_uid(stream, i + nmsgs, uid);
++ else
++ elt->private.uid = uid;
++ }
++ else
++ uid = elt->private.uid;
++ uid_last = uid;
++ if(uid_last > stream->uid_last)
++ stream->uid_last = uid_last;
++ }
++ if(dirtype == New && !stream->rdonly){
++ maildir_free_file_only((void **)&elt->private.spare.ptr);
++ MDFILE(elt) = cpystr(tmp2);
++ MDSIZE(elt) = sbuf.st_size;
++ MDMTIME(elt) = sbuf.st_mtime;
++ MDLOC(elt) = Cur;
++ }
++ if (elt->draft != d || elt->flagged != f ||
++ elt->answered != r || elt->seen != s || elt->deleted != t){
++ elt->draft = d; elt->flagged = f; elt->answered = r;
++ elt->seen = s; elt->deleted = t;
++ if (!we_compute && !stream->rdonly)
++ MM_FLAGS(stream, i+nmsgs);
++ }
++ maildir_get_date(stream, i+nmsgs);
++ elt->valid = T;
++ i++;
++ }
++ stream->silent = silent;
++ if(LOCAL->candouid && dirtype == Cur)
++ maildir_read_uid(stream, NULL, &stream->uid_validity);
++ if (dirtype == New && stream->rdonly)
++ new = nfiles;
++ mail_exists(stream, nmsgs + ((dirtype == New) ? new : nfiles));
++ mail_recent(stream, recent + ((dirtype == New) ? new : 0L));
++
++ return (nmsgs + (dirtype == New ? new : nfiles));
++ }
++
++ long maildir_ping (MAILSTREAM *stream)
++ {
++ maildir_parse_folder(stream, 0);
++ if(stream && LOCAL){
++ if(LOCAL->candouid)
++ maildir_uid_renew_tempfile(stream);
++ else /* try again to get uids */
++ LOCAL->candouid = maildir_can_assign_uid(stream);
++ }
++ return stream && LOCAL ? LONGT : NIL;
++ }
++
++ int maildir_select (const struct direct *name)
++ {
++ return (name->d_name[0] != '.');
++ }
++
++ /*
++ * Unfortunately, there is no way to sort by arrival in this driver, this
++ * means that opening a folder in this driver using the scandir function
++ * will always make this driver slower than any driver that has a natural
++ * way of sorting by arrival (like a flat file format, "mbox", "mbx", etc).
++ */
++ int maildir_namesort (const void *d1, const void *d2)
++ {
++ const struct direct *e1 = *(const struct direct **) d1;
++ const struct direct *e2 = *(const struct direct **) d2;
++
++ return comp_maildir_file((char *) e1->d_name, (char *) e2->d_name);
++ }
++
++ /* Maildir close */
++
++ void maildir_close (MAILSTREAM *stream, long options)
++ {
++ MESSAGECACHE *elt;
++ unsigned long i;
++ int silent = stream ? stream->silent : 0;
++ mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
++
++ if (!stream) return;
++
++ for (i = 1L; i <= stream->nmsgs; i++)
++ if((elt = (MESSAGECACHE *) (*mc)(stream,i,CH_ELT)) && elt->private.spare.ptr)
++ maildir_free_file ((void **) &elt->private.spare.ptr);
++ stream->silent = T;
++ if (options & CL_EXPUNGE) maildir_expunge (stream, NIL, NIL);
++ maildir_abort(stream);
++ if (mdfpath) fs_give((void **)&mdfpath);
++ if (mypid) mypid = (pid_t) 0;
++ stream->silent = silent;
++ }
++
++ void maildir_check (MAILSTREAM *stream)
++ {
++ if (maildir_ping (stream)) mm_log ("Check completed",(long) NIL);
++ }
++
++ long maildir_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs, long flags)
++ {
++ char tmp[MAILTMPLEN];
++ unsigned long i;
++ MESSAGECACHE *elt;
++ char *s;
++ /* UID call "impossible" */
++ if (flags & FT_UID || !LOCAL) return NIL;
++ elt = mail_elt (stream, msgno);
++
++ if (!(flags & FT_PEEK) && !elt->seen){
++ elt->seen = T;
++ maildir_flagmsg (stream, elt);
++ MM_FLAGS(stream, elt->msgno);
++ }
++
++ MSGPATH(tmp, LOCAL->dir, MDFILE(elt), MDLOC(elt));
++ if (LOCAL->fd < 0) /* if file closed ? */
++ LOCAL->fd = open(tmp,O_RDONLY,NIL);
++
++ if (LOCAL->fd < 0 && (errno == EACCES || errno == ENOENT)){
++ INIT (bs, mail_string, "", 0);
++ elt->rfc822_size = 0L;
++ return NIL;
++ }
++
++ s = maildir_text_work(stream, elt, &i, flags);
++ INIT (bs, mail_string, s, i);
++ return LONGT;
++ }
++
++ char *maildir_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
++ unsigned long *length,long flags)
++ {
++ FDDATA d;
++ STRING bs;
++ char *s,tmp[CHUNK];
++ unsigned long msgno = elt->msgno;
++ static int try = 0;
++
++ if (length)
++ *length = 0L;
++ LOCAL->buf[0] = '\0';
++
++ MSGPATH(tmp, LOCAL->dir, MDFILE(elt), MDLOC(elt));
++ if (LOCAL->fd < 0) /* if file closed ? */
++ LOCAL->fd = open(tmp,O_RDONLY,NIL);
++
++ if (LOCAL->fd < 0){ /* flag change? */
++ if (try < 5){
++ try++;
++ if (maildir_update_elt_maildirp(stream, msgno) > 0)
++ try = 0;
++ return maildir_text_work(stream, mail_elt(stream, msgno),length, flags);
++ }
++ try = 0;
++ return NULL;
++ }
++
++ lseek (LOCAL->fd, elt->private.msg.text.offset,L_SET);
++
++ if (flags & FT_INTERNAL) { /* initial data OK? */
++ if (elt->private.msg.text.text.size > LOCAL->buflen) {
++ fs_give ((void **) &LOCAL->buf);
++ LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
++ elt->private.msg.text.text.size) + 1);
++ }
++ read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size);
++ LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0';
++ }
++ else {
++ if (elt->rfc822_size > LOCAL->buflen) {
++ fs_give ((void **) &LOCAL->buf);
++ LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->rfc822_size) + 1);
++ }
++ d.fd = LOCAL->fd; /* yes, set up file descriptor */
++ d.pos = elt->private.msg.text.offset;
++ d.chunk = tmp; /* initial buffer chunk */
++ d.chunksize = CHUNK;
++ INIT (&bs,fd_string,&d,elt->private.msg.text.text.size);
++ for (s = LOCAL->buf; SIZE (&bs);) switch (CHR (&bs)) {
++ case '\r': /* carriage return seen */
++ *s++ = SNX (&bs); /* copy it and any succeeding LF */
++ if (SIZE (&bs) && (CHR (&bs) == '\n')) *s++ = SNX (&bs);
++ break;
++ case '\n':
++ *s++ = '\r'; /* insert a CR */
++ default:
++ *s++ = SNX (&bs); /* copy characters */
++ }
++ *s = '\0'; /* tie off buffer */
++ *length = s - (char *) LOCAL->buf; /* calculate length */
++ }
++ close(LOCAL->fd); LOCAL->fd = -1;
++ return LOCAL->buf;
++ }
++
++ /* maildir parse, fill the elt structure... well not all of it... */
++ unsigned long maildir_parse_message(MAILSTREAM *stream, unsigned long msgno,
++ DirNamesType dirtype)
++ {
++ char *b, *s, *t, c;
++ char tmp[MAILTMPLEN];
++ struct stat sbuf;
++ unsigned long i, len;
++ int d, f, r, se, dt;
++ MESSAGECACHE *elt;
++
++ elt = mail_elt (stream,msgno);
++ MSGPATH(tmp, LOCAL->dir, MDFILE(elt), dirtype);
++ if(stat(tmp, &sbuf) == 0)
++ MDSIZE(elt) = sbuf.st_size;
++
++ maildir_get_date(stream, msgno);
++ maildir_getflag(MDFILE(elt), &d, &f, &r ,&se, &dt);
++ elt->draft = d; elt->flagged = f; elt->answered = r; elt->seen = se;
++ elt->deleted = dt; elt->valid = T;
++ if (LOCAL->fd < 0) /* if file closed ? */
++ LOCAL->fd = open(tmp,O_RDONLY,NIL);
++
++ if (LOCAL->fd >= 0){
++ s = (char *) fs_get (MDSIZE(elt) + 1);
++ read (LOCAL->fd,s,MDSIZE(elt));
++ s[MDSIZE(elt)] = '\0';
++ t = s + strlen(s); /* make t point to the end of s */
++ for (i = 0L, b = s; b < t && !(i && (*b == '\n')); i = (*b++ == '\n'));
++ len = (*b ? ++b : b) - s;
++ elt->private.msg.header.text.size =
++ elt->private.msg.text.offset = len;
++ elt->private.msg.text.text.size = MDSIZE(elt) - len;
++ for (i = 0L, b = s, c = *b; b &&
++ ((c < '\016' && ((c == '\012' && ++i)
++ ||(c == '\015' && *(b+1) == '\012' && ++b && (i +=2))))
++ || b < t); i++, c= *++b);
++ elt->rfc822_size = i;
++ fs_give ((void **) &s);
++ close(LOCAL->fd); LOCAL->fd = -1;
++ }
++ return elt->rfc822_size;
++ }
++
++ int
++ maildir_update_elt_maildirp(MAILSTREAM *stream, unsigned long msgno)
++ {
++ char tmp[MAILTMPLEN];
++ struct direct **names = NIL;
++ unsigned long i, nfiles, pos;
++ int d = 0, f = 0 , r = 0, s = 0, t = 0, in_list, scan_err;
++ MESSAGECACHE *elt;
++
++ MDFLD(tmp, LOCAL->dir, Cur);
++
++ maildir_scandir (tmp, &names, &nfiles, &scan_err, CCLIENT);
++
++ elt = mail_elt (stream,msgno);
++
++ in_list = nfiles > 0L
++ ? maildir_message_in_list(MDFILE(elt), names, 0L, nfiles - 1L, &pos)
++ : NIL;
++
++ if (in_list && pos >= 0L && pos < nfiles
++ && !strcmp(MDFILE(elt), names[pos]->d_name)){
++ in_list = NIL;
++ maildir_abort(stream);
++ }
++
++ if (in_list && pos >= 0L && pos < nfiles){
++ maildir_free_file_only((void **)&elt->private.spare.ptr);
++ MDFILE(elt) = cpystr(names[pos]->d_name);
++ maildir_getflag(MDFILE(elt), &d, &f, &r ,&s, &t);
++ if (elt->draft != d || elt->flagged != f ||
++ elt->answered != r || elt->seen != s || elt->deleted != t){
++ elt->draft = d; elt->flagged = f; elt->answered = r;
++ elt->seen = s; elt->deleted = t;
++ MM_FLAGS(stream, msgno);
++ }
++ }
++ for (i = 0L; i < nfiles; i++)
++ fs_give((void **) &names[i]);
++ if (names)
++ fs_give((void **) &names);
++ return in_list ? 1 : -1;
++ }
++
++ /* Maildir fetch message header */
++
++ char *maildir_header (MAILSTREAM *stream,unsigned long msgno,
++ unsigned long *length, long flags)
++ {
++ char tmp[MAILTMPLEN], *s;
++ MESSAGECACHE *elt;
++ static int try = 0;
++
++ if (length) *length = 0;
++ if (flags & FT_UID || !LOCAL) return ""; /* UID call "impossible" */
++ elt = mail_elt (stream,msgno);
++ if(elt->private.msg.header.text.size == 0)
++ maildir_parse_message(stream, msgno, MDLOC(elt));
++
++ MSGPATH(tmp, LOCAL->dir, MDFILE(elt), MDLOC(elt));
++ if (LOCAL->fd < 0)
++ LOCAL->fd = open (tmp,O_RDONLY,NIL);
++
++ if (LOCAL->fd < 0 && errno == EACCES){
++ mm_log ("Message exists but can not be read. Envelope and body lost!",ERROR);
++ return NULL;
++ }
++
++ if (LOCAL->fd < 0){ /* flag change? */
++ if (try < 5){
++ try++;
++ if (maildir_update_elt_maildirp(stream, msgno) > 0)
++ try = 0;
++ return maildir_header(stream, msgno, length, flags);
++ }
++ try = 0;
++ return NULL;
++ }
++
++ if (flags & FT_INTERNAL){
++ if(elt->private.msg.header.text.size > LOCAL->buflen){
++ fs_give ((void **) &LOCAL->buf);
++ LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
++ elt->private.msg.header.text.size) + 1);
++ }
++ read (LOCAL->fd, (void *)LOCAL->buf, elt->private.msg.header.text.size);
++ LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0';
++ }
++ else{
++ s = (char *) fs_get(elt->private.msg.header.text.size+1);
++ read (LOCAL->fd, (void *)s, elt->private.msg.header.text.size);
++ s[elt->private.msg.header.text.size] = '\0';
++ *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,
++ elt->private.msg.header.text.size);
++ fs_give ((void **) &s);
++ }
++ elt->private.msg.text.offset = elt->private.msg.header.text.size;
++ elt->private.msg.text.text.size = MDSIZE(elt) - elt->private.msg.text.offset;
++ close(LOCAL->fd); LOCAL->fd = -1;
++ return LOCAL->buf;
++ }
++
++ /* Maildir find list of subscribed mailboxes
++ * Accepts: mail stream
++ * pattern to search
++ */
++
++ void maildir_list (MAILSTREAM *stream,char *ref, char *pat)
++ {
++ char *s,test[MAILTMPLEN],file[MAILTMPLEN];
++ long i = 0L;
++
++ if((!pat || !*pat) && maildir_canonicalize (test,ref,"*")
++ && maildir_valid_name(test)){ /* there is a #md/ leading here */
++ for (i = 3L; test[i] && test[i] != '/'; i++);
++ if ((s = strchr (test+i+1,'/')) != NULL) *++s = '\0';
++ else test[0] = '\0';
++ mm_list (stream,'/',test, LATT_NOSELECT);
++ }
++ else if (maildir_canonicalize (test,ref,pat)) {
++ if (test[3] == '/') { /* looking down levels? */
++ /* yes, found any wildcards? */
++ if ((s = strpbrk (test,"%*")) != NULL){
++ /* yes, copy name up to that point */
++ strncpy (file,test+4,i = s - (test+4));
++ file[i] = '\0'; /* tie off */
++ }
++ else strcpy (file,test+4);/* use just that name then */
++ /* find directory name */
++ if ((s = strrchr (file, '/')) != NULL){
++ *s = '\0'; /* found, tie off at that point */
++ s = file;
++ }
++ /* do the work */
++ if(IS_COURIER(test))
++ courier_list_work (stream,s,test,0);
++ else
++ maildir_list_work (stream,s,test,0);
++ }
++ /* always an INBOX */
++ if (!compare_cstring (test,"#MD/INBOX"))
++ mm_list (stream,NIL,"#MD/INBOX",LATT_NOINFERIORS);
++ if (!compare_cstring (test,"#MC/INBOX"))
++ mm_list (stream,NIL,"#MC/INBOX",LATT_NOINFERIORS);
++ }
++ }
++
++ void courier_list (MAILSTREAM *stream,char *ref, char *pat)
++ {
++ /* I am too lazy to do anything. Do you care to ask maildir list, please?
++ The real reason why this is a dummy function is because we do not want to
++ see the same folder listed twice.
++ */
++ }
++
++ /* For those that want to hide things, we give them a chance to do so */
++ void *maildir_parameters (long function, void *value)
++ {
++ void *ret = NIL;
++ switch ((int) function) {
++ case SET_MDINBOXPATH:
++ if(strlen((char *) value ) > 49)
++ strcpy(myMdInboxDir, "Maildir");
++ else
++ strcpy(myMdInboxDir, (char *) value);
++ case GET_MDINBOXPATH:
++ if (myMdInboxDir[0] == '\0') strcpy(myMdInboxDir,"Maildir");
++ ret = (void *) myMdInboxDir;
++ break;
++ case SET_COURIERSTYLE:
++ CourierStyle = (long) value;
++ case GET_COURIERSTYLE:
++ ret = (void *) CourierStyle;
++ break;
++ case GET_DIRFMTTEST:
++ ret = (void *) maildir_dirfmttest;
++ break;
++ default:
++ break;
++ }
++ return ret;
++ }
++
++ int maildir_create_folder(char *mailbox)
++ {
++ char tmp[MAILTMPLEN], err[MAILTMPLEN];
++ int i;
++
++ for (i = Cur; i != EndDir; i++){
++ MDFLD(tmp, mailbox, i);
++ if (mkdir(tmp, 0700) && errno != EEXIST){ /* try to make new dir */
++ sprintf (err, "Can't create %s: %s", tmp, strerror(errno));
++ mm_log (err,ERROR);
++ return NIL;
++ }
++ }
++ return T;
++ }
++
++ int maildir_create_work(char *mailbox, int loop)
++ {
++ char *s, c, err[MAILTMPLEN], tmp[MAILTMPLEN], tmp2[MAILTMPLEN], mbx[MAILTMPLEN];
++ int fnlen, create_dir = 0, courier, mv;
++ struct stat sbuf;
++ long style = (long) maildir_parameters(GET_COURIERSTYLE, NIL);
++
++ courier = IS_COURIER(mailbox);
++ strcpy(mbx, mailbox);
++ mv = maildir_valid(mbx) ? 1 : 0;
++ maildir_file_path(mailbox, tmp);
++ if (mailbox[strlen(mailbox) - 1] == MDSEPARATOR(courier)){
++ create_dir++;
++ mailbox[strlen(mailbox) - 1] = '\0';
++ }
++
++ if(!loop && courier){
++ if(mv){
++ if(create_dir){
++ if(style == CCLIENT)
++ strcpy (err,"Can not create directory: folder exists. Create subfolder");
++ else
++ strcpy(err,"Folder and Directory already exist");
++ }
++ else
++ strcpy (err, "Can't create mailbox: mailbox already exists");
++ }
++ else{
++ if(create_dir)
++ strcpy(err, "Can not create directory. Cread folder instead");
++ else
++ err[0] = '\0';
++ }
++ if(err[0]){
++ mm_log (err,ERROR);
++ return NIL;
++ }
++ }
++
++ fnlen = strlen(tmp);
++ if ((s = strrchr(mailbox,MDSEPARATOR(courier))) != NULL){
++ c = *++s;
++ *s = '\0';
++ if ((stat(tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
++ !maildir_create_work (mailbox, ++loop))
++ return NIL;
++ *s = c;
++ }
++ tmp[fnlen] = '\0';
++
++ if (mkdir(tmp,0700) && errno != EEXIST)
++ return NIL;
++
++ if (create_dir)
++ mailbox[fnlen] = '/';
++
++ if (create_dir){
++ if(style == CCLIENT){
++ if(!courier){
++ FILE *fp = NULL;
++ sprintf(tmp2,"%s%s", tmp, MDDIR);
++ if ((fp = fopen(tmp2,"w")) == NULL){
++ sprintf (err,"Problem creating %s: %s", tmp2, strerror(errno));
++ mm_log (err,ERROR);
++ return NIL;
++ }
++ fclose(fp);
++ }
++ }
++ return T;
++ }
++ else
++ return maildir_create_folder(tmp);
++ }
++
++ long maildir_create (MAILSTREAM *stream,char *mailbox)
++ {
++ char tmp[MAILTMPLEN], err[MAILTMPLEN];
++ int rv, create_dir;
++
++ create_dir = mailbox ?
++ (mailbox[strlen(mailbox) - 1] ==
++ MDSEPARATOR(IS_COURIER(mailbox))) : 0;
++ maildir_file_path(mailbox, tmp);
++ strcpy(tmp, mailbox);
++ rv = maildir_create_work(mailbox, 0);
++ strcpy(mailbox, tmp);
++ if (rv == 0){
++ sprintf (err,"Can't create %s %s",
++ (create_dir ? "directory" : "mailbox"), mailbox);
++ mm_log (err,ERROR);
++ }
++ return rv ? LONGT : NIL;
++ }
++
++ #define MAXTRY 10000
++ void maildir_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
++ {
++ char oldfile[MAILTMPLEN],newfile[MAILTMPLEN],fn[MAILTMPLEN];
++ char *s;
++ int ren, try = 0;
++
++ if (elt->valid){
++ for (try = 1; try > 0 && try < MAXTRY; try++){
++ /* build the new filename */
++ sprintf (oldfile,"%s/%s",LOCAL->curdir, MDFILE(elt));
++ fn[0] = '\0';
++ if ((ren = maildir_message_exists(stream, MDFILE(elt), fn)) == 0){
++ errno = ENOENT;
++ try = MAXTRY;
++ }
++ if (*fn) /* new oldfile! */
++ sprintf (oldfile,"%s/%s",LOCAL->curdir,fn);
++ if ((s = strrchr (MDFILE(elt), FLAGSEP))) *s = '\0';
++ sprintf (fn,"%s%s%s%s%s%s%s", MDFILE(elt), MDSEP(2),
++ MDFLAG(Draft, elt->draft), MDFLAG(Flagged, elt->flagged),
++ MDFLAG(Replied, elt->answered), MDFLAG(Seen, elt->seen),
++ MDFLAG(Trashed, elt->deleted));
++ sprintf (newfile,"%s/%s",LOCAL->curdir,fn);
++ if (ren != 0 && rename (oldfile,newfile) >= 0)
++ try = -1;
++ }
++
++ if (try > 0){
++ sprintf(oldfile,"Unable to write flags to disk: %s",
++ (errno == ENOENT) ? "message is gone!" : strerror (errno));
++ mm_log(oldfile,ERROR);
++ return;
++ }
++ #ifdef __CYGWIN__
++ utime(LOCAL->curdir, NIL); /* make sure next scan will catch the change */
++ #endif
++ maildir_free_file_only ((void **) &elt->private.spare.ptr);
++ MDFILE(elt) = cpystr (fn);
++ }
++ }
++
++ long maildir_expunge (MAILSTREAM *stream, char *sequence, long options)
++ {
++ long ret;
++ MESSAGECACHE *elt;
++ unsigned long i, n = 0L;
++ unsigned long recent = stream->recent;
++ char tmp[MAILTMPLEN];
++
++ mm_critical (stream); /* go critical */
++ ret = sequence ? ((options & EX_UID) ?
++ mail_uid_sequence (stream,sequence) :
++ mail_sequence (stream,sequence)) : LONGT;
++ if(ret == 0L)
++ return 0L;
++ for (i = 1L; i <= stream->nmsgs;){
++ elt = mail_elt (stream,i);
++ if (elt->deleted && (sequence ? elt->sequence : T)){
++ sprintf (tmp,"%s/%s",LOCAL->curdir, MDFILE(elt));
++ if (unlink (tmp) < 0) {/* try to delete the message */
++ sprintf (tmp,"Expunge of message %ld failed, aborted: %s",i,
++ strerror (errno));
++ if (!stream->silent)
++ mm_log (tmp,WARN);
++ break;
++ }
++ if (elt->private.spare.ptr)
++ maildir_free_file ((void **) &elt->private.spare.ptr);
++ if (elt->recent) --recent;/* if recent, note one less recent message */
++ mail_expunged (stream,i); /* notify upper levels */
++ n++; /* count up one more expunged message */
++ }
++ else i++;
++ }
++ if(n){ /* output the news if any expunged */
++ sprintf (tmp,"Expunged %ld messages",n);
++ if (!stream->silent)
++ mm_log (tmp,(long) NIL);
++ }
++ else
++ if (!stream->silent)
++ mm_log ("No messages deleted, so no update needed",(long) NIL);
++ mm_nocritical (stream); /* release critical */
++ /* notify upper level of new mailbox size */
++ mail_exists (stream,stream->nmsgs);
++ mail_recent (stream,recent);
++ return ret;
++ }
++
++ long maildir_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
++ {
++ STRING st;
++ MESSAGECACHE *elt;
++ unsigned long len;
++ int fd;
++ unsigned long i;
++ struct stat sbuf;
++ char tmp[MAILTMPLEN], flags[MAILTMPLEN], path[MAILTMPLEN], *s;
++ /* copy the messages */
++ if ((options & CP_UID) ? mail_uid_sequence (stream, sequence) :
++ mail_sequence (stream,sequence))
++ for (i = 1L; i <= stream->nmsgs; i++)
++ if ((elt = mail_elt (stream,i))->sequence){
++ MSGPATH(path, LOCAL->dir, MDFILE(elt), MDLOC(elt));
++ if (((fd = open (path,O_RDONLY,NIL)) < 0)
++ ||((!elt->rfc822_size &&
++ ((stat(path, &sbuf) < 0) || !S_ISREG (sbuf.st_mode)))))
++ return NIL;
++ if(!elt->rfc822_size)
++ MDSIZE(elt) = sbuf.st_size;
++ s = (char *) fs_get(MDSIZE(elt) + 1);
++ read (fd,s,MDSIZE(elt));
++ s[MDSIZE(elt)] = '\0';
++ close (fd);
++ len = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen, s, MDSIZE(elt));
++ INIT (&st,mail_string, LOCAL->buf, len);
++ elt->rfc822_size = len;
++ fs_give ((void **)&s);
++
++ flags[0] = flags[1] = '\0';
++ if (elt->seen) strcat (flags," \\Seen");
++ if (elt->draft) strcat (flags," \\Draft");
++ if (elt->deleted) strcat (flags," \\Deleted");
++ if (elt->flagged) strcat (flags," \\Flagged");
++ if (elt->answered) strcat (flags," \\Answered");
++ flags[0] = '('; /* open list */
++ strcat (flags,")"); /* close list */
++ mail_date (tmp,elt); /* generate internal date */
++ if (!mail_append_full (NIL,mailbox,flags,tmp,&st))
++ return NIL;
++ if (options & CP_MOVE) elt->deleted = T;
++ }
++ return LONGT; /* return success */
++ }
++
++ long maildir_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
++ {
++ int fd, k;
++ STRING *message;
++ char c,*s, *flags, *date;
++ char tmp[MAILTMPLEN],file[MAILTMPLEN],path1[MAILTMPLEN],path2[MAILTMPLEN];
++ MESSAGECACHE elt;
++ long i, size = 0L, ret = LONGT, f;
++ unsigned long uf, ti;
++ static unsigned int transact = 0;
++
++ if (!maildir_valid(mailbox)) {
++ sprintf (tmp,"Not a valid Maildir mailbox: %s",mailbox);
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++
++ if (!*mdlocaldomain)
++ md_domain_name(); /* get domain name for maildir files in mdlocaldomain now! */
++
++ if (mypid == (pid_t) 0)
++ mypid = getpid();
++
++ if (!stream){
++ stream = &maildirproto;
++
++ for (k = 0; k < NUSERFLAGS && stream->user_flags[k]; ++k)
++ fs_give ((void **) &stream->user_flags[k]);
++ }
++
++ if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
++
++ mm_critical (stream); /* go critical */
++ /* call time(0) only once, use transact to distinguish instead */
++ ti = time(0);
++ do {
++ if (!SIZE (message)) { /* guard against zero-length */
++ mm_log ("Append of zero-length message",ERROR);
++ ret = NIL;
++ break;
++ }
++ if (date && !mail_parse_date(&elt,date)){
++ sprintf (tmp,"Bad date in append: %.80s",date);
++ mm_log (tmp,ERROR);
++ ret = NIL;
++ break;
++ }
++ f = mail_parse_flags (stream,flags,&uf);
++ /* build file name we will use */
++ sprintf (file,"%lu.%d_%09u.%s%s%s%s%s%s",
++ ti, mypid, transact++, mdlocaldomain, (f ? MDSEP(2) : ""),
++ MDFLAG(Draft, f&fDRAFT), MDFLAG(Flagged, f&fFLAGGED),
++ MDFLAG(Replied, f&fANSWERED), MDFLAG(Seen, f&fSEEN));
++ /* build tmp file name */
++ if (maildir_file_path(mailbox, tmp))
++ MSGPATH(path1, tmp, file, Tmp);
++
++ if ((fd = open (path1,O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE)) < 0) {
++ sprintf (tmp, "Can't open append mailbox: %s", strerror (errno));
++ mm_log (tmp, ERROR);
++ return NIL;
++ }
++ for (size = 0,i = SIZE (message),s = (char *) fs_get (i + 1); i; --i)
++ if ((c = SNX (message)) != '\015') s[size++] = c;
++ if ((write (fd, s, size) < 0) || fsync (fd)) {
++ unlink (path1); /* delete message */
++ sprintf (tmp, "Message append failed: %s", strerror (errno));
++ mm_log (tmp, ERROR);
++ ret = NIL;
++ }
++ fs_give ((void **) &s); /* flush the buffer */
++ close (fd); /* close the file */
++ /* build final filename to use */
++ if (maildir_file_path(mailbox, tmp))
++ MSGPATH(path2, tmp, file, New);
++ if (rename (path1,path2) < 0) {
++ sprintf (tmp, "Message append failed: %s", strerror (errno));
++ mm_log (tmp, ERROR);
++ ret = NIL;
++ }
++ unlink (path1);
++
++ if (ret)
++ if (!(*af) (stream,data,&flags,&date,&message)) ret = NIL;
++
++ } while (ret && message); /* write the data */
++ mm_nocritical (stream); /* release critical */
++ return ret;
++ }
++
++ long maildir_delete (MAILSTREAM *stream,char *mailbox)
++ {
++ DIR *dirp;
++ struct direct *d;
++ int i, remove_dir = 0, mddir = 0, rv, error = 0;
++ char tmp[MAILTMPLEN],tmp2[MAILTMPLEN], realname[MAILTMPLEN];
++ struct stat sbuf;
++ int courier = IS_COURIER(mailbox);
++
++ if (mailbox[strlen(mailbox) - 1] == MDSEPARATOR(courier)){
++ remove_dir++;
++ mailbox[strlen(mailbox) -1] = '\0';
++ }
++
++ if (!maildir_valid(mailbox)){
++ maildir_file_path(mailbox, tmp);
++ if (stat(tmp, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode)){
++ sprintf(tmp,"Can not remove %s", mailbox);
++ error++;
++ }
++ }
++
++ if (!error && remove_dir && !maildir_dir_is_empty(mailbox)){
++ sprintf(tmp,"Can not remove directory %s/: directory not empty", mailbox);
++ error++;
++ }
++
++ if(error){
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++
++ maildir_close(stream,0); /* even if stream was NULL */
++
++ maildir_file_path(mailbox, realname);
++
++ if (remove_dir){
++ sprintf(tmp,"%s/%s", realname, MDDIR);
++ if ((rv = stat (tmp,&sbuf)) == 0 && S_ISREG(sbuf.st_mode))
++ rv = unlink(tmp);
++ else if (errno == ENOENT)
++ rv = 0;
++ if (rv != 0){
++ sprintf(tmp,"Can not remove %s/%s: %s", tmp2, MDDIR, strerror(errno));
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++ if (!maildir_valid(realname) && rmdir(realname) != 0){
++ sprintf(tmp,"Can not remove %s/: %s", mailbox, strerror(errno));
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++ return LONGT;
++ }
++ /* else remove just the folder. Remove all hidden files, except MDDIR */
++ for (i = Cur; i != EndDir; i++){
++ MDFLD(tmp, realname, i);
++
++ if (!(dirp = opendir (tmp))){
++ sprintf(tmp,"Can not read %s/: %s", mailbox, strerror(errno));
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++
++ while ((d = readdir(dirp)) != NULL){
++ if (strcmp(d->d_name, ".") && strcmp(d->d_name,"..")){
++ sprintf(tmp2,"%s/%s", tmp, d->d_name);
++ if (unlink(tmp2) != 0){
++ sprintf(tmp2,"Can not remove %s: %s", mailbox, strerror(errno));
++ mm_log (tmp2,ERROR);
++ return NIL;
++ }
++ }
++ }
++ closedir(dirp);
++ if (rmdir(tmp) != 0){
++ sprintf(tmp,"Can not remove %s: %s", mailbox, strerror(errno));
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++ }
++ /*
++ * ok we have removed all subdirectories of the folder mailbox, Remove the
++ * hidden files.
++ */
++
++ if(!(dirp = opendir (realname))){
++ sprintf(tmp,"Can not read %s/: %s", realname, strerror(errno));
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++
++ while ((d = readdir(dirp)) != NULL){
++ if (strcmp(d->d_name, ".") && strcmp(d->d_name,"..")
++ && (!strcmp(d->d_name, MDDIR)
++ || !strncmp(d->d_name, MDUIDLAST, strlen(MDUIDLAST))
++ || !strncmp(d->d_name, MDUIDTEMP, strlen(MDUIDTEMP)))){
++ if(strcmp(d->d_name, MDDIR) == 0)
++ mddir++;
++ sprintf(tmp,"%s/%s", realname, d->d_name);
++ if (unlink(tmp) != 0)
++ error++;
++ }
++ }
++ closedir(dirp);
++ if (error ||
++ (maildir_dir_is_empty(mailbox) && mddir == 0 && rmdir(realname) < 0)){
++ sprintf(tmp,"Can not remove folder %s: %s", mailbox, strerror(errno));
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++ return LONGT;
++ }
++
++ long maildir_rename (MAILSTREAM *stream, char *old, char *new)
++ {
++ char tmp[MAILTMPLEN],tmpnew[MAILTMPLEN], realold[MAILTMPLEN];
++ char realnew[MAILTMPLEN];
++ int courier = IS_COURIER(old) && IS_COURIER(new);
++ int i;
++ long rv = LONGT;
++ COURIER_S *cdir;
++
++ if((IS_COURIER(old) || IS_COURIER(new)) && !courier){
++ sprintf (tmp,"Can't rename mailbox %s to %s",old, new);
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++
++ if (!maildir_valid(old)){
++ sprintf (tmp,"Can't rename mailbox %s: folder not in maildir format",old);
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++ maildir_file_path(old, realold);
++ if (!maildir_valid_name(new) && new[0] == '#'){
++ sprintf (tmp,"Can't rename mailbox %s: folder not in maildir format",new);
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++ maildir_file_path(new, realnew);
++ if (access(tmpnew,F_OK) == 0){ /* new mailbox name must not exist */
++ sprintf (tmp,"Can't rename to mailbox %s: destination already exists",new);
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++
++ if(!courier){
++ if (rename (realold,realnew)){ /* try to rename the directory */
++ sprintf (tmp,"Can't rename mailbox %s to %s: %s",old, new,
++ strerror(errno));
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++ return LONGT; /* return success */
++ }
++
++ cdir = courier_list_dir(old);
++ for (i = 0; cdir && i < cdir->total; i++){
++ if(strstr(cdir->data[i]->name, old)){
++ sprintf(tmp,"%s%s", new, cdir->data[i]->name+strlen(old));
++ maildir_file_path(cdir->data[i]->name, realold);
++ maildir_file_path(tmp, realnew);
++ if (rename (realold,realnew)){
++ sprintf (tmp,"Can't rename mailbox %s to %s: %s",old, new,
++ strerror(errno));
++ mm_log (tmp,ERROR);
++ rv = NIL;
++ }
++ }
++ }
++ courier_free_cdir(&cdir);
++ return rv;
++ }
++
++ long maildir_sub (MAILSTREAM *stream,char *mailbox)
++ {
++ return sm_subscribe (mailbox);
++ }
++
++ long maildir_unsub (MAILSTREAM *stream,char *mailbox)
++ {
++ return sm_unsubscribe (mailbox);
++ }
++
++ void maildir_lsub (MAILSTREAM *stream,char *ref,char *pat)
++ {
++ void *sdb = NIL;
++ char *s, test[MAILTMPLEN];
++ /* get canonical form of name */
++ if (maildir_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) {
++ do if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,NIL);
++ while ((s = sm_read (&sdb)) != NULL); /* until no more subscriptions */
++ }
++ }
++
++ long maildir_canonicalize (char *pattern,char *ref,char *pat)
++ {
++ if (ref && *ref) { /* have a reference */
++ strcpy (pattern,ref); /* copy reference to pattern */
++ /* # overrides mailbox field in reference */
++ if (*pat == '#') strcpy (pattern,pat);
++ /* pattern starts, reference ends, with / */
++ else if ((*pat == '/') && (pattern[strlen (pattern) - 1] == '/'))
++ strcat (pattern,pat + 1); /* append, omitting one of the period */
++
++ else strcat (pattern,pat); /* anything else is just appended */
++ }
++ else strcpy (pattern,pat); /* just have basic name */
++ return maildir_valid_name(pattern) ? LONGT : NIL;
++ }
++
++ void maildir_list_work (MAILSTREAM *stream,char *dir,char *pat,long level)
++ {
++ DIR *dp;
++ struct direct *d;
++ struct stat sbuf;
++ char curdir[MAILTMPLEN],name[MAILTMPLEN], tmp[MAILTMPLEN];
++ char realpat[MAILTMPLEN];
++ long i;
++ char *maildirpath = mdirpath();
++
++ sprintf(curdir,"%s/%s/", myrootdir(pat), dir ? dir : maildirpath);
++ if ((dp = opendir (curdir)) != NULL){
++ if (dir) sprintf (name,"%s%s/",MDPREFIX(CCLIENT),dir);
++ else strcpy (name, pat);
++
++ if (level == 0 && !strpbrk(pat,"%*")){
++ if(maildir_valid(pat)){
++ i = maildir_contains_folder(pat, NULL)
++ ? LATT_HASCHILDREN
++ : (maildir_is_dir(pat, NULL)
++ ? LATT_HASNOCHILDREN : LATT_NOINFERIORS);
++ maildir_file_path(pat, realpat);
++ i += maildir_any_new_msgs(realpat)
++ ? LATT_MARKED : LATT_UNMARKED;
++ mm_list (stream,'/', pat, i);
++ }
++ else
++ if(pat[strlen(pat) - 1] == '/')
++ mm_list (stream,'/', pat, LATT_NOSELECT);
++ }
++
++ while ((d = readdir (dp)) != NULL)
++ if(strcmp(d->d_name, ".") && strcmp(d->d_name,"..")
++ && strcmp(d->d_name, MDNAME(Cur))
++ && strcmp(d->d_name, MDNAME(Tmp))
++ && strcmp(d->d_name, MDNAME(New))){
++
++ if (dir) sprintf (tmp,"%s%s", name,d->d_name);
++ else strcpy(tmp, d->d_name);
++
++ if(pmatch_full (tmp, pat,'/')){
++ sprintf(tmp,"%s/%s/%s", myrootdir(d->d_name),
++ (dir ? dir : maildirpath), d->d_name);
++ if(stat (tmp,&sbuf) == 0
++ && ((sbuf.st_mode & S_IFMT) == S_IFDIR)){
++ if (dir) sprintf (tmp,"%s%s", name,d->d_name);
++ else strcpy(tmp, d->d_name);
++ i = maildir_valid(tmp)
++ ? (maildir_contains_folder(dir, d->d_name)
++ ? LATT_HASCHILDREN
++ : (maildir_is_dir(dir, d->d_name)
++ ? LATT_HASNOCHILDREN : LATT_NOINFERIORS))
++ : LATT_NOSELECT;
++ i += maildir_any_new_msgs(tmp)
++ ? LATT_MARKED : LATT_UNMARKED;
++ mm_list (stream,'/',tmp, i);
++ strcat (tmp, "/");
++ if(dmatch (tmp, pat,'/') &&
++ (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL))){
++ sprintf(tmp,"%s/%s",dir,d->d_name);
++ maildir_list_work (stream,tmp,pat,level+1);
++ }
++ }
++ }
++ }
++ closedir (dp);
++ }
++ }
++
++ void courier_list_work (MAILSTREAM *stream, char *dir, char *pat, long level)
++ {
++ char c, curdir[MAILTMPLEN], tmp[MAILTMPLEN];
++ char realname[MAILTMPLEN], realpat[MAILTMPLEN] = {'\0'};
++ int i, found;
++ long style = (long) maildir_parameters(GET_COURIERSTYLE, NIL), j;
++ char *maildirpath = mdirpath();
++ COURIER_S *cdir;
++
++ if(!strpbrk(pat,"%*")){ /* a mailbox */
++ maildir_file_path(pat, curdir);
++ i = strlen(curdir) - 1;
++ if(curdir[i] == '/')
++ curdir[i] = '\0';
++ cdir = courier_list_dir(curdir);
++ if(cdir){
++ found = 0; j = 0L;
++ if(maildir_valid_name(pat)){
++ for(i = 0; !found && i < cdir->total; i++)
++ if(strstr(curdir, cdir->data[i]->name)){
++ if(strlen(curdir) < strlen(cdir->data[i]->name))
++ found += 2;
++ else if(strlen(curdir) == strlen(cdir->data[i]->name))
++ found -= 1;
++ }
++ if(found > 0)
++ j = LATT_HASCHILDREN;
++ else if(found == 0)
++ j = (style == COURIER) ? LATT_HASNOCHILDREN : LATT_NOINFERIORS;
++ }
++ else
++ j = LATT_NOSELECT;
++ j += maildir_any_new_msgs(curdir) ? LATT_MARKED : LATT_UNMARKED;
++ if (found)
++ mm_list (stream, '.', pat, j);
++ courier_free_cdir(&cdir);
++ }
++ return;
++ }
++
++ strcpy(tmp,pat + 4); /* a directory */
++ j = strlen(pat) - 1;
++ maildir_file_path(pat, realpat);
++ c = pat[j];
++ pat[j] = '\0';
++ realname[0] = '\0';
++ if(dir)
++ maildir_file_path(dir, realname);
++ sprintf(curdir,"%s%s%s/%s", (dir ? "" : myrootdir(pat)), (dir ? "" : "/"),
++ (dir ? realname : maildirpath), (dir ? "" : "."));
++ sprintf(tmp, "%s%s/.", MDPREFIX(COURIER), dir ? dir : maildirpath);
++ if (level == 0 && tmp && pmatch_full (tmp, realpat, '.'))
++ mm_list (stream,'.', tmp, LATT_NOSELECT);
++
++ cdir = courier_list_dir(pat);
++ pat[j] = c;
++ for (i = 0; cdir && i < cdir->total; i++)
++ if(pmatch_full (cdir->data[i]->name, pat, '.')){
++ sprintf(tmp, "%s.", cdir->data[i]->name);
++ courier_list_info(&cdir, tmp, i);
++ mm_list (stream,'.',cdir->data[i]->name, cdir->data[i]->attribute);
++ }
++ courier_free_cdir(&cdir);
++ }
++
++ int
++ same_maildir_file(char *name1, char *name2)
++ {
++ char tmp1[MAILTMPLEN], tmp2[MAILTMPLEN];
++ char *s;
++
++ strcpy(tmp1, name1 ? name1 : "");
++ strcpy(tmp2, name2 ? name2 : "");
++ if ((s = strrchr(tmp1, FLAGSEP)) != NULL)
++ *s = '\0';
++ if (((s = strrchr(tmp1, SIZESEP)) != NULL) && (strchr(s,'.') == NULL))
++ *s = '\0';
++ if ((s = strrchr(tmp2, FLAGSEP)) != NULL)
++ *s = '\0';
++ if (((s = strrchr(tmp2, SIZESEP)) != NULL) && (strchr(s,'.') == NULL))
++ *s = '\0';
++
++ return !strcmp(tmp1, tmp2);
++ }
++
++ unsigned long antoul(char *seed)
++ {
++ int i, error = 0;
++ unsigned long val = 0L, rv1 = 0L, t;
++ char c, *p;
++ if(!seed)
++ return 0L;
++ t = strtoul(seed, &p, 10);
++ if(p && (*p == '.' || *p == '_'))
++ return t;
++ /* else */
++ if((p = strchr(seed,'.')) != NULL)
++ *p = '\0';
++ error = (strlen(seed) > 6); /* too long */
++ for(i= strlen(seed)-1; error == 0 && i >= 0; i--){
++ c = seed[i];
++ if (c >= 'A' && c <= 'Z') val = c - 'A';
++ else if (c >= 'a' && c <= 'z') val = c - 'a' + 26;
++ else if (c >= '0' && c <= '9') val = c - '0' + 26 + 26;
++ else if (c == '-') val = c - '-' + 26 + 26 + 10;
++ else if (c == '_') val = c - '_' + 26 + 26 + 10 + 1;
++ else error++;
++ rv1 = val + (rv1 << 6);
++ }
++ if(p)
++ *p = '.';
++ return error ? 0L : rv1;
++ }
++
++ unsigned long mdfntoul (char *name)
++ {
++ unsigned long t;
++ char *r, last;
++
++ if((*name == '_') && ((r = strpbrk(name,".,%+")) != NULL)){ /* Grrr!!! */
++ last = *r;
++ *r = '\0';
++ t = antoul(r+1);
++ *r = last;
++ }
++ else
++ t = antoul(name);
++ return t;
++ }
++
++ int comp_maildir_file(char *name1, char *name2)
++ {
++ int uset1 = 1, uset2 = 1, i, j, cmp;
++ unsigned long t1, t2;
++ char *s1, *s2;
++
++ if (!(name1 && *name1))
++ return (name2 && *name2) ? (*name2 == FLAGSEP ? 0 : -1) : 0;
++
++ if (!(name2 && *name2))
++ return (name1 && *name1) ? (*name1 == FLAGSEP ? 0 : 1) : 0;
++
++ if((cmp = strcmp(name1,name2)) == 0)
++ return 0;
++
++ t1 = strtoul(name1, &s1, 10);
++ t2 = strtoul(name2, &s2, 10);
++
++ if(!s1 || *s1 != '.')
++ uset1 = 0;
++
++ if(!s2 || *s2 != '.')
++ uset2 = 0;
++
++ if(uset1 && uset2) /* normal sort order */
++ return (t1 < t2) ? -1 : (t1 > t2 ? 1 : (cmp < 0 ? -1 : 1));
++
++ /* If we make it here we say Grrrr.... first, then we try to figure out
++ * how to sort this mess.
++ * These are the rules.
++ * If there is a number at the beginning it is bigger than anything else.
++ * If there are digits, then the number of digits decides which one is bigger.
++ */
++
++ for(i = 0; isdigit(name1[i]); i++);
++ for(j = 0; isdigit(name2[j]); j++);
++
++ return(uset1 ? 1
++ : (uset2 ? -1
++ : (i < j ? -1 : (i > j ? 1 : (cmp < 0 ? -1 : 1)))));
++ }
++
++ void
++ maildir_getflag(char *name, int *d, int *f, int *r ,int *s, int *t)
++ {
++ char tmp[MAILTMPLEN], *b;
++ int offset = 0;
++ int tmpd, tmpf, tmpr, tmps, tmpt;
++
++ if(d) *d = 0;
++ if(f) *f = 0;
++ if(r) *r = 0;
++ if(s) *s = 0;
++ if(t) *t = 0;
++
++ tmpd = tmpf = tmpr = tmps = tmpt = NIL; /* no flags set by default */
++ strcpy(tmp,name);
++ while ((b = strrchr(tmp+offset, FLAGSEP)) != NULL){
++ char flag,last;
++ int k;
++ if (!++b) break;
++ switch (*b){
++ case '1':
++ case '2':
++ case '3': flag = *b; b += 2;
++ for (k = 0; b[k] && b[k] != FLAGSEP && b[k] != ','; k++);
++ last = b[k];
++ b[k] = '\0';
++ if (flag == '2' || flag == '3'){
++ tmpd = strchr (b, MDFLAGC(Draft)) ? T : NIL;
++ tmpf = strchr (b, MDFLAGC(Flagged)) ? T : NIL;
++ tmpr = strchr (b, MDFLAGC(Replied)) ? T : NIL;
++ tmps = strchr (b, MDFLAGC(Seen)) ? T : NIL;
++ tmpt = strchr (b, MDFLAGC(Trashed)) ? T : NIL;
++ }
++ b[k] = last;
++ b += k;
++ for (; tmp[offset] && tmp[offset] != FLAGSEP; offset++);
++ offset++;
++ break;
++ default: break; /* Should we crash?... Nahhh */
++ }
++ }
++ if(d) *d = tmpd;
++ if(f) *f = tmpf;
++ if(r) *r = tmpr;
++ if(s) *s = tmps;
++ if(t) *t = tmpt;
++ }
++
++ int
++ maildir_message_in_list(char *msgname, struct direct **names,
++ unsigned long bottom, unsigned long top, unsigned long *pos)
++ {
++ unsigned long middle = (bottom + top)/2;
++ int test;
++
++ if (!msgname)
++ return NIL;
++
++ if (pos) *pos = middle;
++
++ if (same_maildir_file(msgname, names[middle]->d_name))
++ return T;
++
++ if (middle == bottom){ /* 0 <= 0 < 1 */
++ int rv = NIL;
++ if (same_maildir_file(msgname, names[middle]->d_name)){
++ rv = T;
++ if (pos) *pos = middle;
++ }
++ else
++ if (same_maildir_file(msgname, names[top]->d_name)){
++ rv = T;
++ if (pos) *pos = top;
++ }
++ return rv;
++ }
++
++ test = comp_maildir_file(msgname, names[middle]->d_name);
++
++ if (top <= bottom)
++ return test ? NIL : T;
++
++ if (test < 0 ) /* bottom < msgname < middle */
++ return maildir_message_in_list(msgname, names, bottom, middle, pos);
++ else if (test > 0) /* middle < msgname < top */
++ return maildir_message_in_list(msgname, names, middle, top, pos);
++ else return T;
++ }
++
++ void
++ maildir_abort(MAILSTREAM *stream)
++ {
++ if (LOCAL){
++ if(LOCAL->candouid)
++ maildir_read_uid(stream, NULL, &stream->uid_validity);
++ if (LOCAL->dir) fs_give ((void **) &LOCAL->dir);
++ if (LOCAL->curdir) fs_give ((void **) &LOCAL->curdir);
++ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
++ if(LOCAL->uidtempfile){
++ unlink(LOCAL->uidtempfile);
++ fs_give ((void **) &LOCAL->uidtempfile);
++ }
++ fs_give ((void **) &stream->local);
++ }
++ if (mdfpath) fs_give((void **)&mdfpath);
++ stream->dtb = NIL;
++ }
++
++ int
++ maildir_contains_folder(char *dirname, char *name)
++ {
++ char tmp[MAILTMPLEN], tmp2[MAILTMPLEN];
++ int rv = 0;
++ DIR *dir;
++ struct direct *d;
++
++ maildir_file_path(dirname, tmp2);
++ if(name){
++ strcat(tmp2,"/");
++ strcat(tmp2, name);
++ }
++
++ if (!(dir = opendir (tmp2)))
++ return NIL;
++
++ while ((d = readdir(dir)) != NULL){
++ if (strcmp(d->d_name, ".") && strcmp(d->d_name,"..")
++ && strcmp(d->d_name, MDNAME(Cur))
++ && strcmp(d->d_name, MDNAME(Tmp))
++ && strcmp(d->d_name, MDNAME(New))){
++
++ sprintf(tmp,"%s/%s", tmp2, d->d_name);
++ if(maildir_valid(tmp)){
++ rv++;
++ break;
++ }
++ }
++ }
++ closedir(dir);
++ return rv;
++ }
++
++ int
++ maildir_is_dir(char *dirname, char *name)
++ {
++ char tmp[MAILTMPLEN];
++ struct stat sbuf;
++
++ maildir_file_path(dirname, tmp);
++ if(name){
++ strcat(tmp,"/");
++ strcat(tmp,name);
++ }
++ strcat(tmp,"/");
++ strcat(tmp,MDDIR);
++
++ return ((stat(tmp, &sbuf) == 0) && S_ISREG (sbuf.st_mode)) ? 1 : 0;
++ }
++
++ int
++ maildir_dir_is_empty(char *mailbox)
++ {
++ char tmp[MAILTMPLEN], tmp2[MAILTMPLEN], tmp3[MAILTMPLEN],*s;
++ int rv = 1, courier = IS_COURIER(mailbox);
++ DIR *dir;
++ struct direct *d;
++ struct stat sbuf;
++
++ maildir_file_path(mailbox, tmp2);
++
++ if(courier){
++ strcpy(tmp3, tmp2);
++ if(s = strrchr(tmp2, '/'))
++ *s = '\0';
++ }
++
++ if (!(dir = opendir (tmp2)))
++ return rv;
++
++ if(courier){
++ while((d = readdir(dir)) != NULL){
++ sprintf(tmp,"%s/%s", tmp2, d->d_name);
++ if(!strncmp(tmp, tmp3, strlen(tmp3))
++ && tmp[strlen(tmp3)] == '.'){
++ rv = 0;
++ break;
++ }
++ }
++ }
++ else
++ while ((d = readdir(dir)) != NULL){
++ sprintf(tmp,"%s/%s", tmp2, d->d_name);
++ if (strcmp(d->d_name, ".")
++ && strcmp(d->d_name,"..")
++ && strcmp(d->d_name, MDNAME(Cur))
++ && strcmp(d->d_name, MDNAME(Tmp))
++ && strcmp(d->d_name, MDNAME(New))
++ && strcmp(d->d_name, MDDIR)
++ && strcmp(d->d_name, MDUIDVALIDITY)
++ && !(d->d_name[0] == '.'
++ && stat (tmp,&sbuf) == 0
++ && S_ISREG(sbuf.st_mode))){
++ rv = 0;
++ break;
++ }
++ }
++ closedir(dir);
++ return rv;
++ }
++
++ void
++ maildir_get_file (MAILDIRFILE **mdfile)
++ {
++ MAILDIRFILE *md;
++
++ md = (MAILDIRFILE *) fs_get(sizeof(MAILDIRFILE));
++ memset(md, 0, sizeof(MAILDIRFILE));
++ *mdfile = md;
++ }
++
++ void
++ maildir_free_file (void **mdfile)
++ {
++ MAILDIRFILE *md = (mdfile && *mdfile) ? (MAILDIRFILE *) *mdfile : NULL;
++
++ if (md){
++ if (md->name) fs_give((void **)&md->name);
++ fs_give((void **)&md);
++ }
++ }
++
++ void
++ maildir_free_file_only (void **mdfile)
++ {
++ MAILDIRFILE *md = (mdfile && *mdfile) ? (MAILDIRFILE *) *mdfile : NULL;
++
++ if (md && md->name)
++ fs_give((void **)&md->name);
++ }
++
++ int
++ maildir_any_new_msgs(char *mailbox)
++ {
++ char tmp[MAILTMPLEN];
++ int rv = NIL;
++ DIR *dir;
++ struct direct *d;
++
++ MDFLD(tmp, mailbox, New);
++
++ if (!(dir = opendir (tmp)))
++ return rv;
++
++ while ((d = readdir(dir)) != NULL){
++ if (d->d_name[0] == '.')
++ continue;
++ rv = T;
++ break;
++ }
++ closedir(dir);
++ return rv;
++ }
++
++
++ void
++ maildir_get_date(MAILSTREAM *stream, unsigned long msgno)
++ {
++ MESSAGECACHE *elt;
++ struct tm *t;
++ time_t ti;
++ int i,k;
++
++ elt = mail_elt (stream,msgno);
++ if(elt && elt->year != 0)
++ return;
++ if ((ti = mdfntoul(MDFILE(elt))) > 0L && (t = gmtime(&ti))){
++ i = t->tm_hour * 60 + t->tm_min;
++ k = t->tm_yday;
++ t = localtime(&ti);
++ i = t->tm_hour * 60 + t->tm_min - i;
++ if((k = t->tm_yday - k) != 0)
++ i += ((k < 0) == (abs (k) == 1)) ? -24*60 : 24*60;
++ k = abs (i);
++ elt->hours = t->tm_hour;
++ elt->minutes = t->tm_min;
++ elt->seconds = t->tm_sec;
++ elt->day = t->tm_mday; elt->month = t->tm_mon + 1;
++ elt->year = t->tm_year - (BASEYEAR - 1900);
++ elt->zoccident = (k == i) ? 0 : 1;
++ elt->zhours = k/60;
++ elt->zminutes = k % 60;
++ }
++ }
++
++ /* Support for Courier Style directories
++ When this code is complete there will be two types of support, which
++ will be configurable. The problem is the following: In Courier style
++ folder structure, a "folder" may have a subfolder called
++ "folder.subfolder", which is not natural in the file system in the
++ sense that I can not stat for "folder.subfolder" wihtout knowing what
++ "subfolder" is. It needs to be guessed. Because of this I need to look
++ in the list of folders if there is a folder with a name
++ "folder.subfolder", before I can say if the folder is dual or not. One
++ can avoid this annoyance if one ignores the problem by declaring that
++ every folder is dual. I will however code as the default the more
++ complicated idea of scaning the containing directory each time it is
++ modified and search for subfolders, and list the entries it found.
++ */
++
++ int courier_dir_select (const struct direct *name)
++ {
++ return name->d_name[0] == '.' && (strlen(name->d_name) > 2
++ || (strlen(name->d_name) == 2 && name->d_name[1] != '.'));
++ }
++
++ int courier_dir_sort (const void *d1, const void *d2)
++ {
++ const struct direct *e1 = *(const struct direct **) d1;
++ const struct direct *e2 = *(const struct direct **) d2;
++
++ return strcmp((char *) e1->d_name, (char *) e2->d_name);
++ }
++
++ void courier_free_cdir (COURIER_S **cdir)
++ {
++ int i;
++
++ if (!*cdir)
++ return;
++
++ if ((*cdir)->path) fs_give((void **)&((*cdir)->path));
++ for (i = 0; i < (*cdir)->total; i++)
++ if((*cdir)->data[i]->name) fs_give((void **)&((*cdir)->data[i]->name));
++ fs_give((void **)&((*cdir)->data));
++ fs_give((void **)&(*cdir));
++ }
++
++ COURIER_S *courier_get_cdir (int total)
++ {
++ COURIER_S *cdir;
++
++ cdir = (COURIER_S *)fs_get(sizeof(COURIER_S));
++ memset(cdir, 0, sizeof(COURIER_S));
++ cdir->data = (COURIERLOCAL **) fs_get(total*sizeof(COURIERLOCAL *));
++ memset(cdir->data, 0, sizeof(COURIERLOCAL *));
++ cdir->total = total;
++ return cdir;
++ }
++
++ int courier_search_list(COURIERLOCAL **data, char *name, int first, int last)
++ {
++ int try = (first + last)/2;
++
++ if(!strstr(data[try]->name, name)){
++ if(first == try) /* first == last || first + 1 == last */
++ return strstr(data[last]->name, name) ? 1 : 0;
++ if(strcmp(data[try]->name, name) < 0) /*data[try] < name < data[end] */
++ return courier_search_list(data, name, try, last);
++ else /* data[begin] < name < data[try] */
++ return courier_search_list(data, name, first, try);
++ }
++ return 1;
++ }
++
++ /* Lists all directories that are subdirectories of a given directory */
++
++ COURIER_S *courier_list_dir(char *curdir)
++ {
++ struct direct **names = NIL;
++ struct stat sbuf;
++ unsigned long ndir;
++ COURIER_S *cdir = NULL;
++ char tmp[MAILTMPLEN], tmp2[MAILTMPLEN], pathname[MAILTMPLEN],
++ realname[MAILTMPLEN];
++ int i, j, scand, td;
++
++ /* There are two cases, either curdir is
++ #mc/INBOX. #mc/INBOX.foo
++ or
++ #mc/Maildir/. #mc/Maildir/.foo
++ */
++ strcpy(tmp,curdir + 4);
++ if(!strncmp(ucase(tmp), "INBOX", 5))
++ strcpy(tmp, "#mc/INBOX.");
++ else{
++ strcpy(tmp, curdir);
++ for (i = strlen(tmp) - 1; tmp[i] && tmp[i] != '/'; i--);
++ tmp[i+2] = '\0'; /* keep the last "." intact */
++ }
++ maildir_file_path(tmp, realname);
++ maildir_scandir (realname, &names, &ndir, &scand, COURIER);
++
++ if (scand > 0){
++ cdir = courier_get_cdir(ndir);
++ cdir->path = cpystr(realname);
++ for(i = 0, j = 0; i < ndir; i++){
++ td = realname[strlen(realname) - 1] == '.'
++ && *names[i]->d_name == '.';
++ sprintf(tmp2,"%s%s", tmp, names[i]->d_name+1);
++ sprintf(pathname,"%s%s", realname, names[i]->d_name + td);
++ if(stat(pathname, &sbuf) == 0 && S_ISDIR(sbuf.st_mode)){
++ cdir->data[j] = (COURIERLOCAL *) fs_get(sizeof(COURIERLOCAL));
++ cdir->data[j++]->name = cpystr(tmp2);
++ }
++ fs_give((void **)&names[i]);
++ }
++ cdir->total = j;
++ if(cdir->total == 0)
++ courier_free_cdir(&cdir);
++ }
++ if(names)
++ fs_give((void **) &names);
++ return cdir;
++ }
++
++ void
++ courier_list_info(COURIER_S **cdirp, char *data, int i)
++ {
++ long style = (long) maildir_parameters(GET_COURIERSTYLE, NIL);
++ COURIER_S *cdir = *cdirp;
++
++ if(maildir_valid(cdir->data[i]->name)){
++ if(courier_search_list(cdir->data, data, 0, cdir->total - 1))
++ cdir->data[i]->attribute = LATT_HASCHILDREN;
++ else
++ cdir->data[i]->attribute = (style == COURIER)
++ ? LATT_HASNOCHILDREN : LATT_NOINFERIORS;
++ }
++ else
++ cdir->data[i]->attribute = LATT_NOSELECT;
++ cdir->data[i]->attribute += maildir_any_new_msgs(cdir->data[i]->name)
++ ? LATT_MARKED : LATT_UNMARKED;
++ }
++
++ /* UID Support */
++ /* Yes, I know I procastinated a lot about this, but here it is finally */
++
++ unsigned int
++ maildir_can_assign_uid (MAILSTREAM *stream)
++ {
++ unsigned int rv = 0;
++ int createtemp;
++ unsigned long t;
++ char tmp[MAILTMPLEN], *s;
++ DIR *dir;
++ struct direct *d;
++
++ if(!stream || stream->rdonly
++ || !LOCAL || !LOCAL->dir || !(dir = opendir(LOCAL->dir)))
++ return rv;
++
++ sprintf(tmp, "%s.%d", MDUIDTEMP, mypid);
++ while ((d = readdir(dir)) != NULL){
++ if(!strncmp(d->d_name, tmp, strlen(tmp))
++ || !strncmp(d->d_name, MDUIDTEMP, strlen(MDUIDTEMP)))
++ break;
++ }
++ rv = d ? !strncmp(d->d_name, tmp, strlen(tmp)) : 1;
++ createtemp = d ? 0 : 1;
++ if (d && rv == 0){ /* is there a temp file that is not ours? */
++ s = strrchr(d->d_name, '.');
++ t = strtoul(s+1, &s, 10);
++ if(s != NULL && *s != '\0')
++ createtemp++;
++ if(time(0) > t + MAXTEMPUID){
++ createtemp++;
++ sprintf(tmp,"%s/%s", LOCAL->dir, d->d_name);
++ unlink(tmp);
++ }
++ }
++ closedir(dir);
++ if(createtemp){
++ FILE *fp;
++ sprintf(tmp,"%s/%s.%d.%lu", LOCAL->dir, MDUIDTEMP, mypid, time(0));
++ if(fp = fopen(tmp, "w")){
++ fclose(fp);
++ if(LOCAL->uidtempfile)
++ fs_give((void **)&LOCAL->uidtempfile);
++ LOCAL->uidtempfile = cpystr(tmp);
++ rv++;
++ }
++ }
++ return rv;
++ }
++
++ void
++ maildir_read_uid(MAILSTREAM *stream, unsigned long *uid_last,
++ unsigned long *uid_validity)
++ {
++ int createuid, deleteuid = 0;
++ char tmp[MAILTMPLEN], *s = NULL;
++ DIR *dir;
++ struct direct *d;
++
++ if(uid_last) *uid_last = 0L;
++ if(uid_last && uid_validity) *uid_validity = time(0);
++ if(!stream || !LOCAL || !LOCAL->dir || !(dir = opendir(LOCAL->dir)))
++ return;
++
++ while ((d = readdir(dir)) != NULL){
++ if(!strncmp(d->d_name, MDUIDLAST, strlen(MDUIDLAST)))
++ break;
++ }
++ createuid = d == NULL ? 1 : 0;
++ if(uid_last == NULL)
++ deleteuid++;
++ if(d){
++ if(uid_last){
++ s = d->d_name + strlen(MDUIDLAST) + 1;
++ *uid_last = strtoul(s, &s, 10);
++ if(!s || *s != '.'){
++ deleteuid++;
++ createuid++;
++ *uid_last = 0L;
++ }
++ }
++ if(s && *s == '.'){
++ if(uid_validity){
++ s++;
++ *uid_validity = strtoul(s, &s, 10);
++ if(s && *s != '\0'){
++ *uid_validity = time(0);
++ deleteuid++;
++ createuid++;
++ }
++ }
++ }
++ else{
++ deleteuid++;
++ createuid++;
++ }
++ }
++ if(deleteuid){
++ sprintf(tmp,"%s/%s", LOCAL->dir, d->d_name);
++ unlink(tmp);
++ }
++ if(createuid)
++ maildir_write_uid(stream, (uid_last ? *uid_last : stream->uid_last),
++ uid_validity ? *uid_validity : time(0));
++ closedir(dir);
++ }
++
++ void
++ maildir_write_uid(MAILSTREAM *stream, unsigned long uid_last,
++ unsigned long uid_validity)
++ {
++ char tmp[MAILTMPLEN];
++ FILE *fp;
++
++ if(!stream || stream->rdonly || !LOCAL || !LOCAL->dir)
++ return;
++
++ sprintf(tmp,"%s/%s.%010lu.%010lu", LOCAL->dir, MDUIDLAST,
++ uid_last, uid_validity);
++ if(fp = fopen(tmp, "w"))
++ fclose(fp);
++ }
++
++ unsigned long
++ maildir_get_uid(char *name)
++ {
++ char *s;
++ unsigned long rv = 0L;
++
++ if(!name || (s = strstr(name,MDUIDSEP)) == NULL)
++ return rv;
++
++ s += strlen(MDUIDSEP);
++ rv = strtoul(s, NULL, 10);
++ return rv;
++ }
++
++
++ void
++ maildir_delete_uid(MAILSTREAM *stream, unsigned long msgno)
++ {
++ char old[MAILTMPLEN], new[MAILTMPLEN], *s, *t;
++ MESSAGECACHE *elt;
++
++ elt = mail_elt(stream, msgno);
++ if(!stream || !elt || !elt->private.spare.ptr || !LOCAL || !LOCAL->dir)
++ return;
++
++ sprintf(old, "%s/%s/%s", LOCAL->dir, MDNAME(Cur), MDFILE(elt));
++ t = MDFILE(elt);
++ if(s = strstr(MDFILE(elt), MDUIDSEP)){
++ *s = '\0';
++ s += strlen(MDUIDSEP);
++ strtoul(s, &s, 10);
++ sprintf(new, "%s/%s/%s%s", LOCAL->dir, MDNAME(Cur), t, s);
++ if(rename(old, new) == 0){
++ maildir_free_file_only ((void **)&elt->private.spare.ptr);
++ s = strrchr(new, '/');
++ MDFILE(elt) = cpystr(s+1);
++ }
++ elt->private.uid = 0L;
++ }
++ }
++
++ void
++ maildir_assign_uid(MAILSTREAM *stream, unsigned long msgno, unsigned long uid)
++ {
++ int createuid, deleteuid = 0;
++ char old[MAILTMPLEN], new[MAILTMPLEN], *s, *t;
++ MESSAGECACHE *elt;
++
++ elt = mail_elt(stream, msgno);
++ if(!stream || !elt || !elt->private.spare.ptr || !LOCAL || !LOCAL->dir)
++ return;
++
++ maildir_delete_uid(stream, msgno);
++ sprintf(old, "%s/%s/%s", LOCAL->dir, MDNAME(Cur), MDFILE(elt));
++ t = MDFILE(elt);
++ if((s = strrchr(MDFILE(elt),FLAGSEP)) != NULL){
++ *s++ = '\0';
++ sprintf(new, "%s/%s/%s%s%lu%c%s",
++ LOCAL->dir, MDNAME(Cur), t, MDUIDSEP, uid, FLAGSEP, s);
++ if(rename(old, new) == 0){
++ maildir_free_file_only ((void **)&elt->private.spare.ptr);
++ s = strrchr(new, '/');
++ MDFILE(elt) = cpystr(s+1);
++ stream->uid_validity = time(0);
++ }
++ elt->private.uid = uid;
++ }
++ }
++
++ void
++ maildir_uid_renew_tempfile(MAILSTREAM *stream)
++ {
++ char tmp[MAILTMPLEN];
++
++ if(!stream || stream->rdonly
++ || !LOCAL || !LOCAL->candouid || !LOCAL->dir || !LOCAL->uidtempfile)
++ return;
++
++ sprintf(tmp,"%s/%s.%d.%lu", LOCAL->dir, MDUIDTEMP, mypid, time(0));
++ if(rename(LOCAL->uidtempfile, tmp) == 0){
++ fs_give((void **)&LOCAL->uidtempfile);
++ LOCAL->uidtempfile = cpystr(tmp);
++ }
++ }
+diff -rc alpine-2.00/imap/src/osdep/unix/maildir.h alpine-2.00.I.USE/imap/src/osdep/unix/maildir.h
+*** alpine-2.00/imap/src/osdep/unix/maildir.h 2011-02-07 20:34:02.000000000 -0800
+--- alpine-2.00.I.USE/imap/src/osdep/unix/maildir.h 2011-02-07 20:33:41.000000000 -0800
+***************
+*** 0 ****
+--- 1,226 ----
++ /*
++ * A few definitions that try to make this module portable to other
++ * platforms (e.g. Cygwin). This module is based on the information from
++ * http://cr.yp.to/proto/maildir.html
++ */
++
++ /* First we deal with the separator character */
++ #ifndef FLAGSEP
++ #define FLAGSEP ':'
++ #endif
++ #define SIZESEP ','
++
++ const char sep1[] = {FLAGSEP, '1', ',', '\0'}; /* experimental semantics*/
++ const char sep2[] = {FLAGSEP, '2', ',', '\0'}; /* Flags Information */
++ const char sep3[] = {FLAGSEP, '3', ',', '\0'}; /* Grrrr.... */
++
++ const char *sep[] = { sep1, sep2, sep3, NULL};
++
++ #define MDSEP(i) sep[((i) - 1)]
++
++ /* Now we deal with flags. Woohoo! */
++ typedef enum {Draft, Flagged, Passed, Replied, Seen, Trashed,
++ EmptyFlag, EndFlags} MdFlagNamesType;
++ const int mdimapflags[] = {Draft, Flagged, Replied, Seen, Trashed, EmptyFlag, EndFlags};
++ const int mdkwdflags[] = {Passed, EmptyFlag, EndFlags};
++
++ /* this array lists the codes for mdflgnms (maildir flag names) above */
++ const char *mdflags[] = { "D", "F", "P", "R", "S", "T", "", NULL};
++ /* and as characters too */
++ const char cmdflags[] = { 'D', 'F', 'P', 'R', 'S', 'T', '0', '\0'};
++
++ /* MDFLAG(Seen, elt->seen) */
++ #define MDFLAG(i,j) mdflags[j ? (i) : EmptyFlag]
++ /* MDFLAGC(Seen) */
++ #define MDFLAGC(i) cmdflags[(i)]
++
++ /* Now we deal with the directory structure */
++ typedef enum {Cur, Tmp, New, EndDir} DirNamesType;
++ char *mdstruct[] = {"cur", "tmp", "new", NULL};
++ #define MDNAME(i) mdstruct[(i)]
++ #define MDFLD(tmp, dir, i) sprintf((tmp),"%s/%s", (dir), mdstruct[(i)])
++ #define MSGPATH(tmp, dir, msg,i) sprintf((tmp),"%s/%s/%s", (dir), mdstruct[(i)],(msg))
++
++ /* Files associated to a maildir directory */
++
++ #define MDUIDVALIDITY ".uidvalidity" /* support for old maildirs */
++ #define MDDIR ".mdir" /* this folder is a directory */
++ #define MDUIDLAST ".uidlast" /* last assigned uid */
++ #define MDUIDTEMP ".uidtemp" /* We assign uid's no one else */
++
++
++
++ /* Support of Courier Structure */
++ #define CCLIENT 0
++ #define COURIER 1
++ #define IS_CCLIENT(t) \
++ (((t) && (t)[0] == '#' && ((t)[1] == 'm' || (t)[1] == 'M')\
++ && ((t)[2] == 'd' || (t)[2] == 'D')\
++ && (t)[3] == '/' && (t)[4] != '\0') ? 1 : 0)
++
++ #define IS_COURIER(t) \
++ (((t) && (t)[0] == '#' && ((t)[1] == 'm' || (t)[1] == 'M')\
++ && ((t)[2] == 'c' || (t)[2] == 'C')\
++ && (t)[3] == '/' && (t)[4] != '\0') ? 1 : 0)
++ #define MDPREFIX(s) ((s) ? "#mc/" : "#md/")
++ #define MDSEPARATOR(s) ((s) ? '.' : '/')
++
++ /* UID Support */
++
++ #define MAXTEMPUID (unsigned long) 180L
++ const char mduid[] = {',','u','=','\0'};
++ #define MDUIDSEP mduid
++
++
++ /* Now we deal with messages filenames */
++ char mdlocaldomain[MAILTMPLEN+1] = {'\0'};
++ pid_t mypid = (pid_t) 0;
++ static char *mdfpath = NULL;
++ static char myMdInboxDir[50] = { '\0' };/* Location of the Maildir INBOX */
++ static long CourierStyle = CCLIENT;
++
++ #define CHUNK 16384 /* from unix.h */
++
++ typedef struct courier_local {
++ char *name; /* name of directory/folder */
++ int attribute; /* attributes (children/marked/etc) */
++ } COURIERLOCAL;
++
++ typedef struct courier {
++ char *path; /* Path to collection */
++ time_t scantime; /* time at which information was generated */
++ int total; /* total number of elements in data */
++ COURIERLOCAL **data;
++ } COURIER_S;
++
++ /* In gdb this is the *(struct maildir_local *)stream->local structure */
++ typedef struct maildir_local {
++ unsigned int dirty : 1; /* diskcopy needs updating */
++ unsigned int courier : 1; /* It is Courier style file system */
++ unsigned int link : 1; /* There is a symbolic link */
++ unsigned int candouid; /* we can assign uids and no one else */
++ char *uidtempfile; /* path to uid temp file */
++ int fd; /* fd of open message */
++ char *dir; /* mail directory name */
++ char *curdir; /* mail directory name/cur */
++ unsigned char *buf; /* temporary buffer */
++ unsigned long buflen; /* current size of temporary buffer */
++ time_t scantime; /* last time directory scanned */
++ } MAILDIRLOCAL;
++
++ /* Convenient access to local data */
++ #define LOCAL ((MAILDIRLOCAL *) stream->local)
++
++ typedef struct maildir_file_info {
++ char *name; /* name of the file */
++ DirNamesType loc; /* location of this file */
++ unsigned long pos; /* place in list where this file is listed */
++ off_t size; /* size in bytes, on disk */
++ time_t atime; /* last access time */
++ time_t mtime; /* last modified time */
++ time_t ctime; /* last changed time */
++ } MAILDIRFILE;
++
++ #define MDFILE(F) (((MAILDIRFILE *)((F)->private.spare.ptr))->name)
++ #define MDLOC(F) (((MAILDIRFILE *)((F)->private.spare.ptr))->loc)
++ #define MDPOS(F) (((MAILDIRFILE *)((F)->private.spare.ptr))->pos)
++ #define MDSIZE(F) (((MAILDIRFILE *)((F)->private.spare.ptr))->size)
++ #define MDATIME(F) (((MAILDIRFILE *)((F)->private.spare.ptr))->atime)
++ #define MDMTIME(F) (((MAILDIRFILE *)((F)->private.spare.ptr))->mtime)
++ #define MDCTIME(F) (((MAILDIRFILE *)((F)->private.spare.ptr))->ctime)
++
++ /* Function prototypes */
++
++ DRIVER *maildir_valid (char *name);
++ MAILSTREAM *maildir_open (MAILSTREAM *stream);
++ void maildir_close (MAILSTREAM *stream, long options);
++ long maildir_ping (MAILSTREAM *stream);
++ void maildir_check (MAILSTREAM *stream);
++ long maildir_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
++ char *maildir_header (MAILSTREAM *stream,unsigned long msgno,
++ unsigned long *length, long flags);
++ void maildir_list (MAILSTREAM *stream,char *ref,char *pat);
++ void *maildir_parameters (long function,void *value);
++ int maildir_create_folder (char *mailbox);
++ long maildir_create (MAILSTREAM *stream,char *mailbox);
++ void maildir_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); /*check */
++ long maildir_expunge (MAILSTREAM *stream, char *sequence, long options);
++ long maildir_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
++ long maildir_append (MAILSTREAM *stream,char *mailbox, append_t af, void *data);
++ long maildir_delete (MAILSTREAM *stream,char *mailbox);
++ long maildir_rename (MAILSTREAM *stream,char *old,char *new);
++ long maildir_sub (MAILSTREAM *stream,char *mailbox);
++ long maildir_unsub (MAILSTREAM *stream,char *mailbox);
++ void maildir_lsub (MAILSTREAM *stream,char *ref,char *pat);
++ void courier_list (MAILSTREAM *stream,char *ref, char *pat);
++
++ /* utility functions */
++ void courier_realname (char *name, char *realname);
++ long maildir_dirfmttest (char *name);
++ char *maildir_file (char *dst,char *name);
++ int maildir_select (const struct direct *name);
++ int maildir_namesort (const void *d1, const void *d2);
++ unsigned long antoul (char *seed);
++ unsigned long mdfntoul (char *name);
++ int courier_dir_select (const struct direct *name);
++ int courier_dir_sort (const void *d1, const void *d2);
++ long maildir_canonicalize (char *pattern,char *ref,char *pat);
++ void maildir_list_work (MAILSTREAM *stream,char *subdir,char *pat,long level);
++ void courier_list_work (MAILSTREAM *stream,char *subdir,char *pat,long level);
++ int maildir_file_path(char *name, char *tmp);
++ int maildir_valid_name (char *name);
++ int maildir_valid_dir (char *name);
++ int is_valid_maildir (char **name);
++ int maildir_message_exists(MAILSTREAM *stream,char *name, char *tmp);
++ char *maildir_remove_root(char *name);
++ char *maildir_text_work (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned long *length,long flags);
++ unsigned long maildir_parse_message(MAILSTREAM *stream, unsigned long msgno,
++ DirNamesType dirtype);
++ int maildir_eliminate_duplicate (char *name, struct direct ***flist,
++ unsigned long *nfiles);
++ int maildir_doscandir (char *name, struct direct ***flist, int flag);
++ unsigned long maildir_scandir (char *name, struct direct ***flist,
++ unsigned long *nfiles, int *scand, int flag);
++ void maildir_parse_folder (MAILSTREAM *stream, int full);
++ void md_domain_name (void);
++ char *myrootdir (char *name);
++ char *mdirpath (void);
++ int maildir_initial_check (MAILSTREAM *stream, DirNamesType dirtype);
++ unsigned long maildir_parse_dir(MAILSTREAM *stream, unsigned long nmsgs,
++ DirNamesType dirtype, struct direct **names, unsigned long nfiles, int full);
++ int same_maildir_file(char *name1, char *name2);
++ int comp_maildir_file(char *name1, char *name2);
++ int maildir_message_in_list(char *msgname, struct direct **names,
++ unsigned long bottom, unsigned long top, unsigned long *pos);
++ void maildir_getflag(char *name, int *d, int *f, int *r ,int *s, int *t);
++ int maildir_update_elt_maildirp(MAILSTREAM *stream, unsigned long msgno);
++ void maildir_abort (MAILSTREAM *stream);
++ int maildir_contains_folder(char *dirname, char *name);
++ int maildir_is_dir(char *dirname, char *name);
++ int maildir_dir_is_empty(char *mailbox);
++ int maildir_create_work (char *mailbox, int loop);
++ void maildir_get_file (MAILDIRFILE **mdfile);
++ void maildir_free_file (void **mdfile);
++ void maildir_free_file_only (void **mdfile);
++ int maildir_any_new_msgs(char *mailbox);
++ void maildir_get_date(MAILSTREAM *stream, unsigned long msgno);
++ void maildir_fast (MAILSTREAM *stream,char *sequence,long flags);
++
++ /* Courier server support */
++ void courier_free_cdir (COURIER_S **cdir);
++ COURIER_S *courier_get_cdir (int total);
++ int courier_search_list(COURIERLOCAL **data, char *name, int first, int last);
++ COURIER_S *courier_list_dir(char *curdir);
++ void courier_list_info(COURIER_S **cdirp, char *data, int i);
++
++ /* UID Support */
++ unsigned int maildir_can_assign_uid (MAILSTREAM *stream);
++ void maildir_read_uid(MAILSTREAM *stream, unsigned long *uid_last,
++ unsigned long *uid_validity);
++ void maildir_write_uid(MAILSTREAM *stream, unsigned long uid_last,
++ unsigned long uid_validity);
++ unsigned long maildir_get_uid(char *name);
++ void maildir_delete_uid(MAILSTREAM *stream, unsigned long msgno);
++ void maildir_assign_uid(MAILSTREAM *stream, unsigned long msgno, unsigned long uid);
++ void maildir_uid_renew_tempfile(MAILSTREAM *stream);
++
+diff -rc alpine-2.00/imap/src/osdep/unix/Makefile alpine-2.00.I.USE/imap/src/osdep/unix/Makefile
+*** alpine-2.00/imap/src/osdep/unix/Makefile 2008-06-04 11:18:34.000000000 -0700
+--- alpine-2.00.I.USE/imap/src/osdep/unix/Makefile 2011-02-07 20:33:41.000000000 -0800
+***************
+*** 144,150 ****
+ # However, mh needs to be before any sysinbox formats (such as mmdf or unix)
+ # since otherwise INBOX won't work correctly when mh_allow_inbox is set.
+ #
+! DEFAULTDRIVERS=imap nntp pop3 mix mx mbx tenex mtx mh mmdf unix news phile
+ CHUNKSIZE=65536
+
+ # Normally no need to change any of these
+--- 144,150 ----
+ # However, mh needs to be before any sysinbox formats (such as mmdf or unix)
+ # since otherwise INBOX won't work correctly when mh_allow_inbox is set.
+ #
+! DEFAULTDRIVERS=maildir courier imap nntp pop3 mix mx mbx tenex mtx mh mmdf unix news phile
+ CHUNKSIZE=65536
+
+ # Normally no need to change any of these
+***************
+*** 153,159 ****
+ BINARIES=osdep.o mail.o misc.o newsrc.o smanager.o utf8.o utf8aux.o siglocal.o \
+ dummy.o pseudo.o netmsg.o flstring.o fdstring.o \
+ rfc822.o nntp.o smtp.o imap4r1.o pop3.o \
+! unix.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o mix.o
+ CFLAGS=-g
+
+ CAT=cat
+--- 153,159 ----
+ BINARIES=osdep.o mail.o misc.o newsrc.o smanager.o utf8.o utf8aux.o siglocal.o \
+ dummy.o pseudo.o netmsg.o flstring.o fdstring.o \
+ rfc822.o nntp.o smtp.o imap4r1.o pop3.o \
+! unix.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o mix.o maildir.o
+ CFLAGS=-g
+
+ CAT=cat
+***************
+*** 282,288 ****
+
+ cyg: # Cygwin - note that most local file drivers don't work!!
+ $(BUILD) `$(CAT) SPECIALS` OS=$@ \
+! DEFAULTDRIVERS="imap nntp pop3 mbx unix phile" \
+ SIGTYPE=psx CHECKPW=cyg LOGINPW=cyg CRXTYPE=std \
+ SPOOLDIR=/var \
+ ACTIVEFILE=/usr/local/news/lib/active \
+--- 282,288 ----
+
+ cyg: # Cygwin - note that most local file drivers don't work!!
+ $(BUILD) `$(CAT) SPECIALS` OS=$@ \
+! DEFAULTDRIVERS="imap nntp pop3 mbx unix maildir phile" \
+ SIGTYPE=psx CHECKPW=cyg LOGINPW=cyg CRXTYPE=std \
+ SPOOLDIR=/var \
+ ACTIVEFILE=/usr/local/news/lib/active \
+***************
+*** 892,898 ****
+ unix.o: mail.h misc.h osdep.h unix.h pseudo.h dummy.h
+ utf8.o: mail.h misc.h osdep.h utf8.h tmap.c widths.c
+ utf8aux.o: mail.h misc.h osdep.h utf8.h
+!
+
+ # OS-dependent
+
+--- 892,898 ----
+ unix.o: mail.h misc.h osdep.h unix.h pseudo.h dummy.h
+ utf8.o: mail.h misc.h osdep.h utf8.h tmap.c widths.c
+ utf8aux.o: mail.h misc.h osdep.h utf8.h
+! maildir.o: mail.h misc.h osdep.h maildir.h dummy.h
+
+ # OS-dependent
+
+diff -rc alpine-2.00/imap/src/osdep/unix/os_cyg.h alpine-2.00.I.USE/imap/src/osdep/unix/os_cyg.h
+*** alpine-2.00/imap/src/osdep/unix/os_cyg.h 2008-06-04 11:18:34.000000000 -0700
+--- alpine-2.00.I.USE/imap/src/osdep/unix/os_cyg.h 2011-02-07 20:33:41.000000000 -0800
+***************
+*** 47,52 ****
+--- 47,53 ----
+ #define setpgrp setpgid
+
+ #define SYSTEMUID 18 /* Cygwin returns this for SYSTEM */
++ #define FLAGSEP ';'
+ #define geteuid Geteuid
+ uid_t Geteuid (void);
+
+diff -rc alpine-2.00/imap/src/osdep/unix/ssl_unix.c alpine-2.00.I.USE/imap/src/osdep/unix/ssl_unix.c
+*** alpine-2.00/imap/src/osdep/unix/ssl_unix.c 2008-06-04 11:18:34.000000000 -0700
+--- alpine-2.00.I.USE/imap/src/osdep/unix/ssl_unix.c 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 524,530 ****
+ if (tcpdebug) mm_log ("Successfully read SSL data",TCPDEBUG);
+ }
+ /* timeout, punt unless told not to */
+! else if (!tmoh || !(*tmoh) (now - t,now - tl)) {
+ if (tcpdebug) mm_log ("SSL data read timeout",TCPDEBUG);
+ return ssl_abort (stream);
+ }
+--- 524,530 ----
+ if (tcpdebug) mm_log ("Successfully read SSL data",TCPDEBUG);
+ }
+ /* timeout, punt unless told not to */
+! else if (!tmoh || !(*tmoh) (now - t,now - tl, stream->tcpstream->host)) {
+ if (tcpdebug) mm_log ("SSL data read timeout",TCPDEBUG);
+ return ssl_abort (stream);
+ }
+diff -rc alpine-2.00/imap/src/osdep/unix/tcp_unix.c alpine-2.00.I.USE/imap/src/osdep/unix/tcp_unix.c
+*** alpine-2.00/imap/src/osdep/unix/tcp_unix.c 2008-06-04 11:18:34.000000000 -0700
+--- alpine-2.00.I.USE/imap/src/osdep/unix/tcp_unix.c 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 585,591 ****
+ if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG);
+ }
+ /* timeout, punt unless told not to */
+! else if (!tmoh || !(*tmoh) (now - t,now - tl)) {
+ if (tcpdebug) mm_log ("TCP buffer read timeout",TCPDEBUG);
+ return tcp_abort (stream);
+ }
+--- 585,591 ----
+ if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG);
+ }
+ /* timeout, punt unless told not to */
+! else if (!tmoh || !(*tmoh) (now - t,now - tl, stream->host)) {
+ if (tcpdebug) mm_log ("TCP buffer read timeout",TCPDEBUG);
+ return tcp_abort (stream);
+ }
+***************
+*** 645,651 ****
+ if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG);
+ }
+ /* timeout, punt unless told not to */
+! else if (!tmoh || !(*tmoh) (now - t,now - tl)) {
+ if (tcpdebug) mm_log ("TCP data read timeout",TCPDEBUG);
+ return tcp_abort (stream);/* error or timeout no-continue */
+ }
+--- 645,651 ----
+ if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG);
+ }
+ /* timeout, punt unless told not to */
+! else if (!tmoh || !(*tmoh) (now - t,now - tl, stream->host)) {
+ if (tcpdebug) mm_log ("TCP data read timeout",TCPDEBUG);
+ return tcp_abort (stream);/* error or timeout no-continue */
+ }
+***************
+*** 716,722 ****
+ if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
+ }
+ /* timeout, punt unless told not to */
+! else if (!tmoh || !(*tmoh) (now - t,now - tl)) {
+ if (tcpdebug) mm_log ("TCP write timeout",TCPDEBUG);
+ return tcp_abort (stream);
+ }
+--- 716,722 ----
+ if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
+ }
+ /* timeout, punt unless told not to */
+! else if (!tmoh || !(*tmoh) (now - t,now - tl, stream->host)) {
+ if (tcpdebug) mm_log ("TCP write timeout",TCPDEBUG);
+ return tcp_abort (stream);
+ }
+diff -rc alpine-2.00/include/general.h alpine-2.00.I.USE/include/general.h
+*** alpine-2.00/include/general.h 2007-01-25 12:29:45.000000000 -0800
+--- alpine-2.00.I.USE/include/general.h 2011-02-07 20:33:44.000000000 -0800
+***************
+*** 32,37 ****
+--- 32,38 ----
+ #undef TRUE
+ #define TRUE 1 /* True, yes, good, etc. */
+ #define ABORT 2 /* Death, ^G, abort, etc. */
++ #define COUNT 3 /* For control-c command */
+
+
+ #undef MIN
+diff -rc alpine-2.00/patchlevel alpine-2.00.I.USE/patchlevel
+*** alpine-2.00/patchlevel 2011-02-07 20:34:02.000000000 -0800
+--- alpine-2.00.I.USE/patchlevel 2011-02-07 20:34:02.000000000 -0800
+***************
+*** 0 ****
+--- 1 ----
++ char plevstamp[]="VERSION=84 created on Mon Feb 07 2011 20:34:02 PST";
+diff -rc alpine-2.00/pico/attach.c alpine-2.00.I.USE/pico/attach.c
+*** alpine-2.00/pico/attach.c 2008-06-11 10:21:24.000000000 -0700
+--- alpine-2.00.I.USE/pico/attach.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 108,115 ****
+ switch(status){
+ case HELPCH:
+ if(Pmaster){
+- VARS_TO_SAVE *saved_state;
+-
+ saved_state = save_pico_state();
+ (*Pmaster->helper)(Pmaster->attach_help, _("Attach Help"), 1);
+ if(saved_state){
+--- 108,113 ----
+diff -rc alpine-2.00/pico/basic.c alpine-2.00.I.USE/pico/basic.c
+*** alpine-2.00/pico/basic.c 2007-11-26 15:45:22.000000000 -0800
+--- alpine-2.00.I.USE/pico/basic.c 2011-02-07 20:33:44.000000000 -0800
+***************
+*** 25,33 ****
+ * framing, are hard.
+ */
+ #include "headers.h"
+!
+ #include "osdep/terminal.h"
+
+
+ /*
+ * Move the cursor to the
+--- 25,34 ----
+ * framing, are hard.
+ */
+ #include "headers.h"
+! #include "../pith/osdep/color.h"
+ #include "osdep/terminal.h"
+
++ int indent_match(char *, LINE *, char *, int, int);
+
+ /*
+ * Move the cursor to the
+***************
+*** 284,290 ****
+ gotobop(int f, int n)
+ {
+ int quoted, qlen;
+! UCS qstr[NLINE], qstr2[NLINE];
+
+ if (n < 0) /* the other way...*/
+ return(gotoeop(f, -n));
+--- 285,291 ----
+ gotobop(int f, int n)
+ {
+ int quoted, qlen;
+! char qstr[NLINE], qstr2[NLINE], ind_str[NLINE], pqstr[NLINE];;
+
+ if (n < 0) /* the other way...*/
+ return(gotoeop(f, -n));
+***************
+*** 296,301 ****
+--- 297,310 ----
+ curwp->w_dotp = lback(curwp->w_dotp);
+ curwp->w_doto = 0;
+ }
++
++ if (indent_match(default_qstr(), curwp->w_dotp,ind_str, NLINE, 0)){
++ if (n){ /* look for another paragraph ? */
++ curwp->w_dotp = lback(curwp->w_dotp);
++ continue;
++ }
++ break;
++ }
+
+ /* scan line by line until we come to a line ending with
+ * a <NL><NL> or <NL><TAB> or <NL><SPACE>
+***************
+*** 303,322 ****
+ * PLUS: if there's a quote string, a quoted-to-non-quoted
+ * line transition.
+ */
+! quoted = glo_quote_str ? quote_match(glo_quote_str, curwp->w_dotp, qstr, NLINE) : 0;
+! qlen = quoted ? ucs4_strlen(qstr) : 0;
+ while(lback(curwp->w_dotp) != curbp->b_linep
+ && llength(lback(curwp->w_dotp)) > qlen
+! && (glo_quote_str
+! ? (quoted == quote_match(glo_quote_str,
+! lback(curwp->w_dotp),
+! qstr2, NLINE)
+! && !ucs4_strcmp(qstr, qstr2))
+! : 1)
+! && lgetc(curwp->w_dotp, qlen).c != TAB
+! && lgetc(curwp->w_dotp, qlen).c != ' ')
+ curwp->w_dotp = lback(curwp->w_dotp);
+
+ if(n){
+ /* keep looking */
+ if(lback(curwp->w_dotp) == curbp->b_linep)
+--- 312,369 ----
+ * PLUS: if there's a quote string, a quoted-to-non-quoted
+ * line transition.
+ */
+! quoted = quote_match(default_qstr(), curwp->w_dotp, qstr, NLINE, 0);
+! qlen = quoted ? strlen(qstr) : 0;
+ while(lback(curwp->w_dotp) != curbp->b_linep
+ && llength(lback(curwp->w_dotp)) > qlen
+! && (quoted == quote_match(default_qstr(),
+! lback(curwp->w_dotp), qstr2, NLINE, 0))
+! && !strcmp(qstr, qstr2) /* processed string */
+! && (quoted == quote_match(default_qstr(),
+! lback(curwp->w_dotp), qstr2, NLINE, 1))
+! && !strcmp(qstr, qstr2) /* raw string */
+! && !indent_match(default_qstr(),
+! lback(curwp->w_dotp),ind_str, NLINE, 0)
+! && !ISspace(lgetc(curwp->w_dotp, qlen).c))
+ curwp->w_dotp = lback(curwp->w_dotp);
+
++ /*
++ * Ok, we made it here and we assume that we are at the begining
++ * of the paragraph. Let's double check this now. In order to do
++ * so we shell check if the first line was indented in a special
++ * way.
++ */
++ if(lback(curwp->w_dotp) == curbp->b_linep)
++ break;
++ else{
++ int i, j;
++
++ /*
++ * First we test if the preceding line is indented.
++ * for the following test we need to have the raw values,
++ * not the processed values
++ */
++ quote_match(default_qstr(), curwp->w_dotp, qstr, NLINE, 1);
++ quote_match(default_qstr(), lback(curwp->w_dotp), qstr2, NLINE, 1);
++ for (i = 0, j = 0;
++ qstr[i] && qstr2[i] && (qstr[i] == qstr2[i]); i++, j++);
++ for (; ISspace(qstr2[i]); i++);
++ for (; ISspace(qstr[j]); j++);
++ if ((indent_match(default_qstr(), lback(curwp->w_dotp),
++ ind_str, NLINE, 1)
++ && (strlenis(qstr2)
++ + strlenis(ind_str) >= strlenis(qstr)))
++ || (lback(curwp->w_dotp) != curbp->b_linep
++ && llength(lback(curwp->w_dotp)) > qlen
++ && (quoted == quote_match(default_qstr(),
++ lback(curwp->w_dotp), pqstr, NLINE, 0))
++ && !strcmp(qstr, pqstr)
++ && !ISspace(lgetc(curwp->w_dotp, qlen).c)
++ && (strlenis(qstr2) > strlenis(qstr)))
++ && !qstr2[i] && !qstr[j])
++ curwp->w_dotp = lback(curwp->w_dotp);
++ }
++
+ if(n){
+ /* keep looking */
+ if(lback(curwp->w_dotp) == curbp->b_linep)
+***************
+*** 329,335 ****
+ else{
+ /* leave cursor on first word in para */
+ curwp->w_doto = 0;
+! while(ucs4_isspace(lgetc(curwp->w_dotp, curwp->w_doto).c))
+ if(++curwp->w_doto >= llength(curwp->w_dotp)){
+ curwp->w_doto = 0;
+ curwp->w_dotp = lforw(curwp->w_dotp);
+--- 376,382 ----
+ else{
+ /* leave cursor on first word in para */
+ curwp->w_doto = 0;
+! while(ISspace(lgetc(curwp->w_dotp, curwp->w_doto).c))
+ if(++curwp->w_doto >= llength(curwp->w_dotp)){
+ curwp->w_doto = 0;
+ curwp->w_dotp = lforw(curwp->w_dotp);
+***************
+*** 343,348 ****
+--- 390,578 ----
+ return(TRUE);
+ }
+
++ unsigned char GetAccent()
++ {
++ UCS c,d;
++ c = GetKey();
++ if ((c == '?') || (c == '!')) {
++ d = c;
++ c = '\\';
++ }
++ else
++ if ((c == 's') || (c == 'S')){
++ c = d = 's';
++ }
++ else
++ if ((c == 'l') || (c == 'L')){
++ c = d = 'l';
++ }
++ else
++ d = GetKey();
++ return accent(c,d);
++ }
++
++ int pineaccent(f,n)
++ int f,n;
++ { unsigned char e;
++
++ if (e = GetAccent())
++ execute(e, 0, 1);
++ return 1;
++ }
++
++ unsigned char accent(f,n)
++ UCS f,n;
++ { UCS c,d;
++
++ c = f;
++ d = n;
++ switch(c){
++ case '~' :
++ switch(d){
++ case 'a' : return '\343';
++ case 'n' : return '\361';
++ case 'o' : return '\365';
++ case 'A' : return '\303';
++ case 'N' : return '\321';
++ case 'O' : return '\325';
++ }
++ break;
++ case '\047' :
++ switch(d){
++ case 'a' : return '\341';
++ case 'e' : return '\351';
++ case 'i' : return '\355';
++ case 'o' : return '\363';
++ case 'u' : return '\372';
++ case 'y' : return '\375';
++ case 'A' : return '\301';
++ case 'E' : return '\311';
++ case 'I' : return '\315';
++ case 'O' : return '\323';
++ case 'U' : return '\332';
++ case 'Y' : return '\335';
++ }
++ break;
++ case '"' :
++ switch(d){
++ case 'a' : return '\344';
++ case 'e' : return '\353';
++ case 'i' : return '\357';
++ case 'o' : return '\366';
++ case 'u' : return '\374';
++ case 'y' : return '\377';
++ case 'A' : return '\304';
++ case 'E' : return '\313';
++ case 'I' : return '\317';
++ case 'O' : return '\326';
++ case 'U' : return '\334';
++ }
++ break;
++ case '^' :
++ switch(d){
++ case 'a' : return '\342';
++ case 'e' : return '\352';
++ case 'i' : return '\356';
++ case 'o' : return '\364';
++ case 'u' : return '\373';
++ case 'A' : return '\302';
++ case 'E' : return '\312';
++ case 'I' : return '\316';
++ case 'O' : return '\324';
++ case 'U' : return '\333';
++ case '0' : return '\260';
++ case '1' : return '\271';
++ case '2' : return '\262';
++ case '3' : return '\263';
++ }
++ break;
++ case '`' :
++ switch(d){
++ case 'a' : return '\340';
++ case 'e' : return '\350';
++ case 'i' : return '\354';
++ case 'o' : return '\362';
++ case 'u' : return '\371';
++ case 'A' : return '\300';
++ case 'E' : return '\310';
++ case 'I' : return '\314';
++ case 'O' : return '\322';
++ case 'U' : return '\331';
++ }
++ break;
++ case 'o' :
++ switch(d){
++ case 'a' : return '\345';
++ case 'A' : return '\305';
++ case '/' : return '\370';
++ case 'r' : return '\256';
++ case 'R' : return '\256';
++ case 'c' : return '\251';
++ case 'C' : return '\251';
++ }
++ break;
++ case '-' :
++ switch(d){
++ case 'o' : return '\272';
++ case 'O' : return '\272';
++ case '0' : return '\272';
++ case 'a' : return '\252';
++ case 'A' : return '\252';
++ case 'l' : return '\243';
++ case 'L' : return '\243';
++ }
++ break;
++ case 'O' :
++ switch(d){
++ case '/' : return '\330';
++ case 'r' : return '\256';
++ case 'R' : return '\256';
++ case 'c' : return '\251';
++ case 'C' : return '\251';
++ }
++ case '/' :
++ switch(d){
++ case 'o' : return '\370';
++ case 'O' : return '\330';
++ }
++ break;
++ case 'a' :
++ switch(d){
++ case 'e' : return '\346';
++ case 'E' : return '\346';
++ }
++ break;
++ case 'A' :
++ switch(d){
++ case 'E' : return '\306';
++ case 'e' : return '\306';
++ }
++ break;
++ case ',' :
++ switch(d){
++ case 'c' : return '\347';
++ case 'C' : return '\307';
++ }
++ break;
++ case '\\' :
++ switch(d){
++ case '?' : return '\277';
++ case '!' : return '\241';
++ }
++ break;
++ case 's' :
++ switch(d){
++ case 's' : return '\337';
++ }
++ break;
++ case 'l' :
++ switch(d){
++ case 'l' : return '\243';
++ }
++ break;
++ }
++ return '\0';
++ }
+
+ /*
+ * go forword to the end of the current paragraph
+***************
+*** 352,359 ****
+ int
+ gotoeop(int f, int n)
+ {
+! int quoted, qlen;
+! UCS qstr[NLINE], qstr2[NLINE];
+
+ if (n < 0) /* the other way...*/
+ return(gotobop(f, -n));
+--- 582,590 ----
+ int
+ gotoeop(int f, int n)
+ {
+! int quoted, qlen, indented, changeqstr = 0;
+! int i,j, fli = 0; /* fli = first line indented a boolean variable */
+! char qstr[NLINE], qstr2[NLINE], ind_str[NLINE];
+
+ if (n < 0) /* the other way...*/
+ return(gotobop(f, -n));
+***************
+*** 366,392 ****
+ break;
+ }
+
+ /* scan line by line until we come to a line ending with
+ * a <NL><NL> or <NL><TAB> or <NL><SPACE>
+ *
+ * PLUS: if there's a quote string, a quoted-to-non-quoted
+ * line transition.
+ */
+! quoted = glo_quote_str
+! ? quote_match(glo_quote_str,
+! curwp->w_dotp, qstr, NLINE) : 0;
+! qlen = quoted ? ucs4_strlen(qstr) : 0;
+
+ while(curwp->w_dotp != curbp->b_linep
+ && llength(lforw(curwp->w_dotp)) > qlen
+! && (glo_quote_str
+! ? (quoted == quote_match(glo_quote_str,
+! lforw(curwp->w_dotp),
+! qstr2, NLINE)
+! && !ucs4_strcmp(qstr, qstr2))
+! : 1)
+! && lgetc(lforw(curwp->w_dotp), qlen).c != TAB
+! && lgetc(lforw(curwp->w_dotp), qlen).c != ' ')
+ curwp->w_dotp = lforw(curwp->w_dotp);
+
+ curwp->w_doto = llength(curwp->w_dotp);
+--- 597,666 ----
+ break;
+ }
+
++ /*
++ * We need to figure out if this line is the first line of
++ * a paragraph that has been indented in a special way. If this
++ * is the case, we advance one more line before we use the
++ * algorithm below
++ */
++
++ if(curwp->w_dotp != curbp->b_linep){
++ quote_match(default_qstr(), curwp->w_dotp, qstr, NLINE, 1);
++ quote_match(default_qstr(), lforw(curwp->w_dotp), qstr2, NLINE, 1);
++ indented = indent_match(default_qstr(), curwp->w_dotp, ind_str,
++ NLINE, 1);
++ if (strlenis(qstr)
++ + strlenis(ind_str) < strlenis(qstr2)){
++ curwp->w_doto = llength(curwp->w_dotp);
++ if(n){ /* this line is a paragraph by itself */
++ curwp->w_dotp = lforw(curwp->w_dotp);
++ continue;
++ }
++ break;
++ }
++ for (i=0,j=0; qstr[i] && qstr2[i] && (qstr[i] == qstr2[i]);i++,j++);
++ for (; ISspace(qstr[i]); i++);
++ for (; ISspace(qstr2[j]); j++);
++ if (!qstr[i] && !qstr2[j] && indented){
++ fli++;
++ if (indent_match(default_qstr(), lforw(curwp->w_dotp),
++ ind_str, NLINE, 0)){
++ if (n){ /* look for another paragraph ? */
++ curwp->w_dotp = lforw(curwp->w_dotp);
++ continue;
++ }
++ }
++ else{
++ if (!lisblank(lforw(curwp->w_dotp)))
++ curwp->w_dotp = lforw(curwp->w_dotp);
++ }
++ }
++ }
++
+ /* scan line by line until we come to a line ending with
+ * a <NL><NL> or <NL><TAB> or <NL><SPACE>
+ *
+ * PLUS: if there's a quote string, a quoted-to-non-quoted
+ * line transition.
+ */
+! /* if the first line is indented (fli == 1), then the test below
+! is on the second line, and in that case we will need the raw
+! string, not the processed string
+! */
+! quoted = quote_match(default_qstr(), curwp->w_dotp, qstr, NLINE, fli);
+! qlen = quoted ? strlen(qstr) : 0;
+
+ while(curwp->w_dotp != curbp->b_linep
+ && llength(lforw(curwp->w_dotp)) > qlen
+! && (quoted == quote_match(default_qstr(),
+! lforw(curwp->w_dotp), qstr2, NLINE, fli))
+! && !strcmp(qstr, qstr2)
+! && (quoted == quote_match(default_qstr(),
+! lforw(curwp->w_dotp), qstr2, NLINE, 1))
+! && !strcmp(qstr, qstr2)
+! && !indent_match(default_qstr(),
+! lforw(curwp->w_dotp), ind_str, NLINE, 0)
+! && !ISspace(lgetc(lforw(curwp->w_dotp), qlen).c))
+ curwp->w_dotp = lforw(curwp->w_dotp);
+
+ curwp->w_doto = llength(curwp->w_dotp);
+***************
+*** 683,689 ****
+--- 957,1013 ----
+ return (scrollforw (1, FALSE));
+ }
+
++ /* deltext deletes from the specified position until the end of the file
++ * or until the signature (when called from Pine), whichever comes first.
++ */
+
++ int
++ deltext (f,n)
++ int f,n;
++ {
++ LINE *currline = curwp->w_dotp;
++ static int firsttime = 0;
++
++ if ((lastflag&CFKILL) == 0)
++ kdelete();
++
++ curwp->w_markp = curwp->w_dotp;
++ curwp->w_marko = curwp->w_doto;
++
++ while (curwp->w_dotp != curbp->b_linep){
++ if ((Pmaster)
++ && (llength(curwp->w_dotp) == 3)
++ && (lgetc(curwp->w_dotp, 0).c == '-')
++ && (lgetc(curwp->w_dotp, 1).c == '-')
++ && (lgetc(curwp->w_dotp, 2).c == ' ')){
++ if (curwp->w_dotp == currline){
++ if (curwp->w_doto)
++ curwp->w_dotp = lforw(curwp->w_dotp);
++ else
++ break;
++ }
++ else{
++ curwp->w_dotp = lback(curwp->w_dotp);
++ curwp->w_doto = llength(curwp->w_dotp);
++ break;
++ }
++ }
++ else{
++ if(lforw(curwp->w_dotp) != curbp->b_linep)
++ curwp->w_dotp = lforw(curwp->w_dotp);
++ else{
++ curwp->w_doto = llength(curwp->w_dotp);
++ break;
++ }
++ }
++ }
++ killregion(FALSE,1);
++ lastflag |= CFKILL;
++ if(firsttime == 0)
++ emlwrite("Deleted text can be recovered with the ^U command", NULL);
++ firsttime = 1;
++ return TRUE;
++ }
+
+ /*
+ * Scroll to a position.
+diff -rc alpine-2.00/pico/bind.c alpine-2.00.I.USE/pico/bind.c
+*** alpine-2.00/pico/bind.c 2007-12-07 15:45:22.000000000 -0800
+--- alpine-2.00.I.USE/pico/bind.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 132,139 ****
+ }
+
+ if(Pmaster){
+- VARS_TO_SAVE *saved_state;
+-
+ saved_state = save_pico_state();
+ (*Pmaster->helper)(Pmaster->composer_help,
+ Pmaster->headents
+--- 132,137 ----
+diff -rc alpine-2.00/pico/blddate.c alpine-2.00.I.USE/pico/blddate.c
+*** alpine-2.00/pico/blddate.c 2006-11-22 14:50:13.000000000 -0800
+--- alpine-2.00.I.USE/pico/blddate.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 19,25 ****
+ char **argv;
+ {
+ struct tm *t;
+! FILE *outfile=stdout;
+ time_t ltime;
+
+ if(argc > 1 && (outfile = fopen(argv[1], "w")) == NULL){
+--- 19,25 ----
+ char **argv;
+ {
+ struct tm *t;
+! FILE *outfile=stdout, *infile;
+ time_t ltime;
+
+ if(argc > 1 && (outfile = fopen(argv[1], "w")) == NULL){
+***************
+*** 46,51 ****
+--- 46,57 ----
+ 1900 + t->tm_year);
+
+ fprintf(outfile, "char hoststamp[]=\"random-pc\";\n");
++ if((infile = fopen("../patchlevel", "r")) != NULL){
++ int c;
++ while ((c = getc(infile)) != EOF) putc(c, outfile);
++ fclose(infile);
++ }
++ else fprintf(outfile, "char plevstamp[]=\"No information available\";\n");
+
+ fclose(outfile);
+
+diff -rc alpine-2.00/pico/browse.c alpine-2.00.I.USE/pico/browse.c
+*** alpine-2.00/pico/browse.c 2008-02-26 15:07:15.000000000 -0800
+--- alpine-2.00.I.USE/pico/browse.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 931,938 ****
+ }
+
+ if(Pmaster){
+- VARS_TO_SAVE *saved_state;
+-
+ saved_state = save_pico_state();
+ (*Pmaster->helper)(Pmaster->browse_help,
+ _("Help for Browsing"), 1);
+--- 931,936 ----
+diff -rc alpine-2.00/pico/composer.c alpine-2.00.I.USE/pico/composer.c
+*** alpine-2.00/pico/composer.c 2008-03-21 14:31:58.000000000 -0700
+--- alpine-2.00.I.USE/pico/composer.c 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 93,98 ****
+--- 93,103 ----
+ */
+ struct on_display ods; /* global on_display struct */
+
++ /* a pointer to the subject line. This is so that we do not have to compute
++ * the header line in every call. It saves a few CPU cycles
++ */
++
++ struct hdr_line *subject_line = NULL;
+
+ /*
+ * useful macros
+***************
+*** 495,500 ****
+--- 500,510 ----
+ mswin_setscrollrange (0, 0);
+ #endif /* _WINDOWS */
+
++ if(Pmaster)
++ for (subject_line = NULL, i=0; headents[i].name; i++)
++ if(strcmp(headents[i].name, "Subject") == 0)
++ subject_line = headents[i].hd_text;
++
+ /*
+ * Decide where to begin editing. if f == TRUE begin editing
+ * at the bottom. this case results from the cursor backing
+***************
+*** 794,802 ****
+ len += lmp->fname ? strlen(lmp->fname) : 0;
+
+ if(len+3 > sizeof(buf)){
+- bfp = malloc(len+3);
+ space = len+3;
+! if((bfp=malloc(len+3)) == NULL){
+ emlwrite("\007Can't malloc space for filename",
+ NULL);
+ continue;
+--- 804,812 ----
+ len += lmp->fname ? strlen(lmp->fname) : 0;
+
+ if(len+3 > sizeof(buf)){
+ space = len+3;
+! bfp = malloc(space*sizeof(char));
+! if(bfp == NULL){
+ emlwrite("\007Can't malloc space for filename",
+ NULL);
+ continue;
+***************
+*** 1270,1278 ****
+ len += strlen(lmp->size);
+
+ if(len+3 > sizeof(buf)){
+- bfp = malloc(len+3);
+ space = len+3;
+! if((bfp=malloc(len+3)) == NULL){
+ emlwrite("\007Can't malloc space for filename",
+ NULL);
+ continue;
+--- 1280,1288 ----
+ len += strlen(lmp->size);
+
+ if(len+3 > sizeof(buf)){
+ space = len+3;
+! bfp = malloc(space*sizeof(char));
+! if(bfp == NULL){
+ emlwrite("\007Can't malloc space for filename",
+ NULL);
+ continue;
+***************
+*** 1309,1316 ****
+ zotlmlist(lm);
+ } /* else, nothing of interest */
+ } else if (headents[ods.cur_e].selector != NULL) {
+- VARS_TO_SAVE *saved_state;
+-
+ /*---- General selector for non-attachments -----*/
+
+ /*
+--- 1319,1324 ----
+***************
+*** 1485,1491 ****
+ struct hdr_line *line;
+ int sz = 0;
+ char *filename = NULL;
+- VARS_TO_SAVE *saved_state;
+
+ /*
+ * Since the fileedit will make a new call back to pico()
+--- 1493,1498 ----
+***************
+*** 1852,1857 ****
+--- 1859,1866 ----
+ }
+
+ UpdateHeader(0);
++ if(sendnow)
++ return(status !=0);
+ PaintHeader(COMPOSER_TOP_LINE, status != 0);
+ PaintBody(1);
+ return(status != 0);
+***************
+*** 1899,1904 ****
+--- 1908,1918 ----
+
+ while(1){ /* edit the line... */
+
++ if(Pmaster && subject_line != NULL
++ && ods.cur_l == subject_line
++ && ods.cur_l->text[0] == 0)
++ (*Pmaster->newthread)();
++
+ if(skipmove)
+ skipmove = 0;
+ else
+***************
+*** 1990,1996 ****
+ tbufp = &strng[ods.p_len];
+
+ if(VALID_KEY(ch)){ /* char input */
+! /*
+ * if we are allowing editing, insert the new char
+ * end up leaving tbufp pointing to newly
+ * inserted character in string, and offset to the
+--- 2004,2010 ----
+ tbufp = &strng[ods.p_len];
+
+ if(VALID_KEY(ch)){ /* char input */
+! insert_char:/*
+ * if we are allowing editing, insert the new char
+ * end up leaving tbufp pointing to newly
+ * inserted character in string, and offset to the
+***************
+*** 2070,2075 ****
+--- 2084,2096 ----
+ }
+ else { /* interpret ch as a command */
+ switch (ch = normalize_cmd(ch, ckm, 2)) {
++ case (CTRL|'\\') :
++ if (ch = GetAccent())
++ goto insert_char;
++ else
++ clearcursor();
++ break;
++
+ case (CTRL|KEY_LEFT): /* word skip left */
+ if(ods.p_ind > 0) /* Scoot one char left if possible */
+ ods.p_ind--;
+***************
+*** 2937,2943 ****
+ ComposerHelp(int level)
+ {
+ char buf[80];
+- VARS_TO_SAVE *saved_state;
+
+ curwp->w_flag |= WFMODE;
+ sgarbf = TRUE;
+--- 2958,2963 ----
+***************
+*** 3337,3342 ****
+--- 3357,3365 ----
+ {
+ UCS *bufp, *buf;
+
++ if (sendnow)
++ return;
++
+ if(ComposerTopLine - 1 >= BOTTOM()) /* silently forget it */
+ return;
+
+***************
+*** 3393,3398 ****
+--- 3416,3424 ----
+ UCS *end;
+ int i;
+
++ if (sendnow)
++ return(TRUE);
++
+ buf = utf8_to_ucs4_cpystr(headents[entry].prompt); /* fresh prompt paint */
+ if(!buf)
+ return(-1);
+***************
+*** 3606,3612 ****
+ char *tmp;
+ struct headerentry *e;
+ BUILDER_ARG *nextarg, *arg = NULL, *headarg = NULL;
+- VARS_TO_SAVE *saved_state;
+
+ if(!entry->builder)
+ return(0);
+--- 3632,3637 ----
+***************
+*** 3826,3832 ****
+ call_expander(void)
+ {
+ char **s = NULL;
+- VARS_TO_SAVE *saved_state;
+ int expret;
+
+ if(!Pmaster->expander)
+--- 3851,3856 ----
+***************
+*** 4348,4353 ****
+--- 4372,4380 ----
+ void
+ ShowPrompt(void)
+ {
++ if (sendnow)
++ return;
++
+ if(headents[ods.cur_e].key_label){
+ menu_header[TO_KEY].name = "^T";
+ menu_header[TO_KEY].label = headents[ods.cur_e].key_label;
+***************
+*** 4716,4721 ****
+--- 4743,4750 ----
+ free(state->opertree);
+
+ free(state);
++
++ state = NULL;
+ }
+
+
+diff -rc alpine-2.00/pico/display.c alpine-2.00.I.USE/pico/display.c
+*** alpine-2.00/pico/display.c 2008-03-26 10:27:45.000000000 -0700
+--- alpine-2.00.I.USE/pico/display.c 2011-02-07 20:33:44.000000000 -0800
+***************
+*** 386,391 ****
+--- 386,394 ----
+ int scroll = 0;
+ CELL c;
+
++ if (sendnow)
++ return;
++
+ #if TYPEAH
+ if (typahead())
+ return;
+***************
+*** 915,921 ****
+ int nbflag; /* non-blanks to the right flag? */
+ int cleartoeol = 0;
+
+! if(row < 0 || row > term.t_nrow)
+ return;
+
+ /* set up pointers to virtual and physical lines */
+--- 918,924 ----
+ int nbflag; /* non-blanks to the right flag? */
+ int cleartoeol = 0;
+
+! if(row < 0 || row > term.t_nrow || sendnow)
+ return;
+
+ /* set up pointers to virtual and physical lines */
+***************
+*** 1284,1290 ****
+ void
+ mlerase(void)
+ {
+! if (term.t_nrow < term.t_mrow)
+ return;
+
+ movecursor(term.t_nrow - term.t_mrow, 0);
+--- 1287,1293 ----
+ void
+ mlerase(void)
+ {
+! if (term.t_nrow < term.t_mrow || sendnow)
+ return;
+
+ movecursor(term.t_nrow - term.t_mrow, 0);
+***************
+*** 1359,1364 ****
+--- 1362,1371 ----
+ menu_yesno[6].label = N_("Cancel");
+ menu_yesno[7].name = "N";
+ menu_yesno[7].label = (dflt == FALSE) ? "[" N_("No") "]" : N_("No");
++ if(Pmaster && Pmaster->onctrlc){
++ menu_yesno[8].name = "T";
++ menu_yesno[8].label = N_("counT");
++ }
+ wkeyhelp(menu_yesno); /* paint generic menu */
+ sgarbk = TRUE; /* mark menu dirty */
+ if(Pmaster && curwp)
+***************
+*** 1437,1442 ****
+--- 1444,1457 ----
+ km_popped++;
+ break;
+ }
++
++ case 'T':
++ case 't':
++ if(Pmaster && Pmaster->onctrlc){
++ pputs_utf8(_("counT"), 1);
++ rv = COUNT;
++ break;
++ }
+ /* else fall through */
+
+ default:
+***************
+*** 1750,1755 ****
+--- 1765,1775 ----
+ b = &buf[ucs4_strlen(buf)];
+ continue;
+
++ case (CTRL|'\\'):
++ if (c = GetAccent())
++ goto text;
++ continue;
++
+ case (CTRL|'F') : /* CTRL-F forward a char*/
+ case KEY_RIGHT :
+ if(*b == '\0')
+***************
+*** 1759,1764 ****
+--- 1779,1796 ----
+
+ continue;
+
++ case (CTRL|'N'): /* Insert pattern */
++ if (pat[0] != '\0'){
++ ucs4_strncpy(buf+ucs4_strlen(buf), pat, NPAT);
++ pputs(pat,1);
++ b = &buf[ucs4_strlen(buf)];
++ dline.vused += ucs4_strlen(pat);
++ changed = TRUE;
++ }
++ else
++ (*term.t_beep)();
++ continue;
++
+ case (CTRL|'G') : /* CTRL-G help */
+ if(term.t_mrow == 0 && km_popped == 0){
+ movecursor(term.t_nrow-2, 0);
+***************
+*** 1868,1874 ****
+ #endif
+
+ default :
+!
+ /* look for match in extra_v */
+ for(i = 0; i < 12; i++)
+ if(c && c == extra_v[i]){
+--- 1900,1906 ----
+ #endif
+
+ default :
+! text:
+ /* look for match in extra_v */
+ for(i = 0; i < 12; i++)
+ if(c && c == extra_v[i]){
+***************
+*** 1962,1968 ****
+
+ mlerase();
+
+! if(!(message && *message) || term.t_nrow < 2)
+ return; /* nothing to write or no space to write, bag it */
+
+ bufp = message;
+--- 1994,2000 ----
+
+ mlerase();
+
+! if(!(message && *message) || term.t_nrow < 2 || sendnow)
+ return; /* nothing to write or no space to write, bag it */
+
+ bufp = message;
+***************
+*** 2151,2158 ****
+ }
+
+ ret = ttcol;
+! while(ttcol < term.t_ncol)
+! pputc(' ', 0);
+
+ movecursor(term.t_nrow - term.t_mrow, ret);
+
+--- 2183,2191 ----
+ }
+
+ ret = ttcol;
+! if(sendnow == 0)
+! while(ttcol < term.t_ncol)
+! pputc(' ', 0);
+
+ movecursor(term.t_nrow - term.t_mrow, ret);
+
+***************
+*** 2631,2636 ****
+--- 2664,2671 ----
+ {
+ int ind, width, printable_ascii = 0;
+
++ if(sendnow)
++ return;
+ /*
+ * This is necessary but not sufficient to allow us to draw. Note that
+ * ttrow runs from 0 to t_nrow (so total number of rows is t_nrow+1)
+***************
+*** 2685,2690 ****
+--- 2720,2727 ----
+ pputs(UCS *s, /* string to write */
+ int a) /* and its attribute */
+ {
++ if(sendnow)
++ return;
+ while (*s != '\0')
+ pputc(*s++, a);
+ }
+***************
+*** 2695,2700 ****
+--- 2732,2739 ----
+ {
+ UCS *ucsstr = NULL;
+
++ if(sendnow)
++ return;
+ if(s && *s){
+ ucsstr = utf8_to_ucs4_cpystr(s);
+ if(ucsstr){
+***************
+*** 2995,3000 ****
+--- 3034,3042 ----
+ char nbuf[NLINE];
+ #endif
+
++ if(sendnow)
++ return;
++
+ #ifdef _WINDOWS
+ pico_config_menu_items (keymenu);
+ #endif
+diff -rc alpine-2.00/pico/ebind.h alpine-2.00.I.USE/pico/ebind.h
+*** alpine-2.00/pico/ebind.h 2007-11-06 15:51:13.000000000 -0800
+--- alpine-2.00.I.USE/pico/ebind.h 2011-02-07 20:33:43.000000000 -0800
+***************
+*** 61,67 ****
+ #ifdef MOUSE
+ {KEY_MOUSE, mousepress},
+ #ifndef _WINDOWS
+! {CTRL|'\\', toggle_xterm_mouse},
+ #endif
+ #endif
+ {CTRL|'A', gotobol},
+--- 61,67 ----
+ #ifdef MOUSE
+ {KEY_MOUSE, mousepress},
+ #ifndef _WINDOWS
+! {CTRL|'|', toggle_xterm_mouse},
+ #endif
+ #endif
+ {CTRL|'A', gotobol},
+***************
+*** 100,106 ****
+ {CTRL|KEY_HOME, gotobob},
+ {CTRL|KEY_END, gotoeob},
+ {0x7F, backdel},
+! {0, NULL}
+ };
+
+
+--- 100,108 ----
+ {CTRL|KEY_HOME, gotobob},
+ {CTRL|KEY_END, gotoeob},
+ {0x7F, backdel},
+! {CTRL|'\\', pineaccent},
+! {0,
+! NULL}
+ };
+
+
+***************
+*** 123,129 ****
+ #ifdef MOUSE
+ {KEY_MOUSE, mousepress},
+ #ifndef _WINDOWS
+! {CTRL|'\\', toggle_xterm_mouse},
+ #endif
+ #endif
+ {CTRL|'A', gotobol},
+--- 125,131 ----
+ #ifdef MOUSE
+ {KEY_MOUSE, mousepress},
+ #ifndef _WINDOWS
+! {CTRL|'|', toggle_xterm_mouse},
+ #endif
+ #endif
+ {CTRL|'A', gotobol},
+diff -rc alpine-2.00/pico/edef.h alpine-2.00.I.USE/pico/edef.h
+*** alpine-2.00/pico/edef.h 2008-01-04 16:41:49.000000000 -0800
+--- alpine-2.00.I.USE/pico/edef.h 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 32,37 ****
+--- 32,38 ----
+
+ /* initialized global definitions */
+
++ int sendnow = 0; /* should we send now */
+ int fillcol = 72; /* Current fill column */
+ int userfillcol = -1; /* Fillcol set from cmd line */
+ UCS pat[NPAT]; /* Search pattern */
+***************
+*** 55,60 ****
+--- 56,62 ----
+ char *keyboard_character_set = NULL;
+ UCS *glo_wordseps = NULL; /* points to word separators if set */
+ char *glo_wordseps_orig = NULL;
++ VARS_TO_SAVE *saved_state = NULL;
+
+ /* uninitialized global definitions */
+ int currow; /* Cursor row */
+***************
+*** 84,89 ****
+--- 86,92 ----
+
+ /* initialized global external declarations */
+
++ extern int sendnow; /* should we send now */
+ extern int fillcol; /* Fill column */
+ extern int userfillcol; /* Fillcol set from cmd line */
+ extern UCS pat[]; /* Search pattern */
+***************
+*** 149,154 ****
+--- 152,158 ----
+ extern KBESC_T *kbesc; /* keyboard esc sequence trie */
+ #endif /* HAS_TERMCAP/HAS_TERMINFO/VMS */
+ extern void *input_cs; /* passed to mbtow() via kbseq() */
++ extern VARS_TO_SAVE *saved_state;
+
+ #endif /* maindef */
+
+diff -rc alpine-2.00/pico/efunc.h alpine-2.00.I.USE/pico/efunc.h
+*** alpine-2.00/pico/efunc.h 2007-11-06 15:51:13.000000000 -0800
+--- alpine-2.00.I.USE/pico/efunc.h 2011-02-07 20:33:44.000000000 -0800
+***************
+*** 53,60 ****
+--- 53,64 ----
+ extern int backline(int, int);
+ extern int gotobop(int, int);
+ extern int gotoeop(int, int);
++ extern int pineaccent(int, int);
++ extern unsigned char accent(UCS, UCS);
++ extern unsigned char GetAccent(void);
+ extern int forwpage(int, int);
+ extern int backpage(int, int);
++ extern int deltext (int, int);
+ extern int scrollupline(int, int);
+ extern int scrolldownline(int, int);
+ extern int scrollto(int, int);
+***************
+*** 248,257 ****
+ extern int fillpara(int, int);
+ extern int fillbuf(int, int);
+ extern int inword(void);
+! extern int quote_match(UCS *, LINE *, UCS *, size_t);
+ extern int ucs4_isalnum(UCS);
+ extern int ucs4_isalpha(UCS);
+ extern int ucs4_isspace(UCS);
+ extern int ucs4_ispunct(UCS);
+
+ #endif /* EFUNC_H */
+--- 252,268 ----
+ extern int fillpara(int, int);
+ extern int fillbuf(int, int);
+ extern int inword(void);
+! extern int quote_match(char *, LINE *, char *, size_t, int);
+! extern char *default_qstr(void);
+! extern void flatten_qstring(QSTRING_S *, char *, int);
+! extern void free_qs(QSTRING_S **);
+! extern QSTRING_S *do_quote_match (char *, char *, char *, char *, char *, int, int);
+! extern QSTRING_S *do_raw_quote_match(char *, char *, char *, char *, QSTRING_S **, QSTRING_S **);
+! extern int indent_match(char *, LINE *, char *, int, int);
+ extern int ucs4_isalnum(UCS);
+ extern int ucs4_isalpha(UCS);
+ extern int ucs4_isspace(UCS);
+ extern int ucs4_ispunct(UCS);
+
+ #endif /* EFUNC_H */
++
+diff -rc alpine-2.00/pico/file.c alpine-2.00.I.USE/pico/file.c
+*** alpine-2.00/pico/file.c 2008-06-11 10:21:24.000000000 -0700
+--- alpine-2.00.I.USE/pico/file.c 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 331,338 ****
+ #endif /* !(DOS || MAC) */
+ case HELPCH:
+ if(Pmaster){
+- VARS_TO_SAVE *saved_state;
+-
+ saved_state = save_pico_state();
+ (*Pmaster->helper)(msg ? Pmaster->ins_m_help
+ : Pmaster->ins_help,
+--- 331,336 ----
+diff -rc alpine-2.00/pico/line.c alpine-2.00.I.USE/pico/line.c
+*** alpine-2.00/pico/line.c 2007-08-15 16:07:18.000000000 -0700
+--- alpine-2.00.I.USE/pico/line.c 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 607,620 ****
+ lisblank(LINE *line)
+ {
+ int n = 0;
+! UCS qstr[NLINE];
+
+! n = (glo_quote_str
+! && quote_match(glo_quote_str, line, qstr, NLINE))
+! ? ucs4_strlen(qstr) : 0;
+
+ for(; n < llength(line); n++)
+! if(!ucs4_isspace(lgetc(line, n).c))
+ return(FALSE);
+
+ return(TRUE);
+--- 607,618 ----
+ lisblank(LINE *line)
+ {
+ int n = 0;
+! char qstr[NLINE];
+
+! n = quote_match(default_qstr(), line, qstr, NLINE, 1);
+
+ for(; n < llength(line); n++)
+! if(!ISspace(lgetc(line, n).c))
+ return(FALSE);
+
+ return(TRUE);
+diff -rc alpine-2.00/pico/main.c alpine-2.00.I.USE/pico/main.c
+*** alpine-2.00/pico/main.c 2008-04-02 15:09:20.000000000 -0700
+--- alpine-2.00.I.USE/pico/main.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 162,167 ****
+--- 162,168 ----
+ char *file_to_edit = NULL;
+ char *display_charmap = NULL;
+ char *keyboard_charmap = NULL;
++ int line_information_on = FALSE;
+ int use_system = 0;
+ char *err = NULL;
+
+***************
+*** 187,193 ****
+ if(display_character_set)
+ display_charmap = cpstr(display_character_set);
+ #if HAVE_LANGINFO_H && defined(CODESET)
+! else
+ display_charmap = cpstr(nl_langinfo_codeset_wrapper());
+ #endif
+
+--- 188,194 ----
+ if(display_character_set)
+ display_charmap = cpstr(display_character_set);
+ #if HAVE_LANGINFO_H && defined(CODESET)
+! else if (nl_langinfo_codeset_wrapper() != NULL)
+ display_charmap = cpstr(nl_langinfo_codeset_wrapper());
+ #endif
+
+***************
+*** 415,420 ****
+--- 416,427 ----
+ emlwrite(_("You may possibly have new mail."), NULL);
+ }
+
++ if (c == (CTRL|'\\')){
++ c = GetAccent();
++ if (!c)
++ c = NODATA;
++ }
++
+ if(km_popped)
+ switch(c){
+ case NODATA:
+***************
+*** 436,449 ****
+ mlerase();
+ }
+
+! f = FALSE;
+ n = 1;
+
+ #ifdef MOUSE
+ clear_mfunc(mouse_in_content);
+ #endif
+ /* Do it. */
+ execute(normalize_cmd(c, fkm, 1), f, n);
+ }
+ }
+
+--- 443,471 ----
+ mlerase();
+ }
+
+! f = (c == (CTRL|'J'));
+ n = 1;
++ if (!line_information_on)
++ line_information_on = (c == (CTRL|'C'));
++ else
++ line_information_on = ((c == KEY_DOWN) || (c == KEY_UP) ||
++ (c == KEY_RIGHT) || (c == KEY_LEFT) ||
++ (c == (CTRL|'V')) || (c == (CTRL|'Y')) ||
++ (c == (CTRL|'D')) || (c == (CTRL|'F')) ||
++ (c == (CTRL|'B')) || (c == (CTRL|'N')) ||
++ (c == (CTRL|'P')) || (c == (CTRL|'A')) ||
++ (c == (CTRL|'E')) || (c == (CTRL|'U')))
++ && (c != (CTRL|'C'));
+
+ #ifdef MOUSE
+ clear_mfunc(mouse_in_content);
+ #endif
+ /* Do it. */
+ execute(normalize_cmd(c, fkm, 1), f, n);
++ if (line_information_on){
++ c = (CTRL|'C');
++ execute(normalize_cmd(c, fkm, 1), f, n);
++ }
+ }
+ }
+
+diff -rc alpine-2.00/pico/osdep/getkey.c alpine-2.00.I.USE/pico/osdep/getkey.c
+*** alpine-2.00/pico/osdep/getkey.c 2007-08-20 12:46:37.000000000 -0700
+--- alpine-2.00.I.USE/pico/osdep/getkey.c 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 130,135 ****
+--- 130,145 ----
+ {
+ UCS ch, status, cc;
+
++ if(sendnow){
++ ch = Pmaster && Pmaster->auto_cmds && *Pmaster->auto_cmds
++ ? *Pmaster->auto_cmds++ : NODATA;
++
++ if (ch >= 0x00 && ch <= 0x1F)
++ ch = CTRL | (ch+'@');
++
++ return(ch);
++ }
++
+ if(!ReadyForKey(FUDGE-5))
+ return(NODATA);
+
+diff -rc alpine-2.00/pico/osdep/terminal.c alpine-2.00.I.USE/pico/osdep/terminal.c
+*** alpine-2.00/pico/osdep/terminal.c 2008-01-29 15:21:10.000000000 -0800
+--- alpine-2.00.I.USE/pico/osdep/terminal.c 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 25,30 ****
+--- 25,31 ----
+ #include "../keydefs.h"
+ #include "../pico.h"
+ #include "../mode.h"
++ #include "../edef.h"
+
+ #include "raw.h"
+ #include "color.h"
+***************
+*** 477,482 ****
+--- 478,489 ----
+ {
+ int row, col;
+
++ if (sendnow){
++ term.t_nrow = 23;
++ term.t_ncol = 80;
++ return 0;
++ }
++
+ /*
+ * determine the terminal's communication speed and decide
+ * if we need to do optimization ...
+***************
+*** 1252,1257 ****
+--- 1259,1270 ----
+ {
+ int row, col;
+
++ if (sendnow){
++ term.t_nrow = 23;
++ term.t_ncol = 80;
++ return 0;
++ }
++
+ /*
+ * determine the terminal's communication speed and decide
+ * if we need to do optimization ...
+diff -rc alpine-2.00/pico/osdep/tty.c alpine-2.00.I.USE/pico/osdep/tty.c
+*** alpine-2.00/pico/osdep/tty.c 2007-08-15 16:07:18.000000000 -0700
+--- alpine-2.00.I.USE/pico/osdep/tty.c 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 223,229 ****
+ int row = -1, col = -1;
+
+ ttgetwinsz(&row, &col);
+! resize_pico(row, col);
+ }
+
+
+--- 223,236 ----
+ int row = -1, col = -1;
+
+ ttgetwinsz(&row, &col);
+! if(saved_state == NULL || wheadp != NULL)
+! resize_pico(row, col);
+! else{ /* this is awkward */
+! restore_pico_state(saved_state);
+! free_pico_state(saved_state);
+! resize_pico(row,col);
+! saved_state = save_pico_state();
+! }
+ }
+
+
+diff -rc alpine-2.00/pico/pico.c alpine-2.00.I.USE/pico/pico.c
+*** alpine-2.00/pico/pico.c 2008-01-30 16:44:12.000000000 -0800
+--- alpine-2.00.I.USE/pico/pico.c 2011-02-07 20:33:44.000000000 -0800
+***************
+*** 137,142 ****
+--- 137,151 ----
+ pico_all_done = 0;
+ km_popped = 0;
+
++ if (pm->auto_cmds){
++ int i;
++ #define CTRL_X 24
++ for (i = 0; pm->auto_cmds[i]; i++);
++ if ((i > 1) && (pm->auto_cmds[i - 2] == CTRL_X) &&
++ ((pm->auto_cmds[i - 1] == 'y') || (pm->auto_cmds[i-1] == 'Y')))
++ sendnow++;
++ }
++
+ if(!vtinit()) /* Init Displays. */
+ return(COMP_CANCEL);
+
+***************
+*** 637,648 ****
+ result = "";
+
+ Pmaster->arm_winch_cleanup++;
+ if(Pmaster->canceltest){
+ if(((Pmaster->pine_flags & MDHDRONLY) && !any_header_changes())
+ || (result = (*Pmaster->canceltest)(redraw_pico_for_callback))){
+- pico_all_done = COMP_CANCEL;
+ emlwrite(result, NULL);
+ Pmaster->arm_winch_cleanup--;
+ return(TRUE);
+ }
+ else{
+--- 646,664 ----
+ result = "";
+
+ Pmaster->arm_winch_cleanup++;
++ Pmaster->onctrlc++;
+ if(Pmaster->canceltest){
+ if(((Pmaster->pine_flags & MDHDRONLY) && !any_header_changes())
+ || (result = (*Pmaster->canceltest)(redraw_pico_for_callback))){
+ emlwrite(result, NULL);
+ Pmaster->arm_winch_cleanup--;
++ if(Pmaster->curpos[0]){
++ curwp->w_flag |= WFMODE; /* and modeline so we */
++ sgarbk = TRUE; /* redraw the keymenu */
++ pclear(term.t_nrow - 1, term.t_nrow + 1);
++ return(FALSE);
++ }
++ pico_all_done = COMP_CANCEL;
+ return(TRUE);
+ }
+ else{
+***************
+*** 671,676 ****
+--- 687,698 ----
+ emlwrite(_("\007Cancel Cancelled"), NULL);
+ break;
+
++ case COUNT:
++ showcpos(1,0);
++ emlwrite(Pmaster->curpos, NULL);
++ Pmaster->onctrlc--;
++ break;
++
+ default:
+ mlerase();
+ }
+***************
+*** 713,718 ****
+--- 735,753 ----
+ return(FALSE);
+ }
+
++ /* When we send a message using the command line we are going to
++ ignore if the user wants to spell check, we assume he already
++ did */
++ if (sendnow){
++ ret = (*Pmaster->exittest)(Pmaster->headents,
++ redraw_pico_for_callback,
++ Pmaster->allow_flowed_text,
++ &result);
++ if (!ret)
++ pico_all_done = COMP_EXIT;
++ return(result ? FALSE : TRUE);
++ }
++
+ #ifdef SPELLER
+ if(Pmaster->always_spell_check)
+ if(spell(0, 0) == -1)
+diff -rc alpine-2.00/pico/pico.h alpine-2.00.I.USE/pico/pico.h
+*** alpine-2.00/pico/pico.h 2008-08-22 13:40:16.000000000 -0700
+--- alpine-2.00.I.USE/pico/pico.h 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 198,208 ****
+--- 198,210 ----
+ PCOLORS *colors; /* colors for titlebar and keymenu */
+ void *input_cs; /* passed to mbtow() via kbseq() */
+ long pine_flags; /* entry mode flags */
++ char curpos[80]; /* where are we now? */
+ /* The next few bits are features that don't fit in pine_flags */
+ /* If we had this to do over, it would probably be one giant bitmap */
+ unsigned always_spell_check:1; /* always spell-checking upon quit */
+ unsigned strip_ws_before_send:1; /* don't default strip bc of flowed */
+ unsigned allow_flowed_text:1; /* clean text when done to keep flowed */
++ unsigned onctrlc; /* are we on ctrl-c command? */
+ int (*helper)(); /* Pine's help function */
+ int (*showmsg)(); /* Pine's display_message */
+ UCS (*suspend)(); /* Pine's suspend */
+***************
+*** 219,225 ****
+--- 221,229 ----
+ int (*user_says_noflow)(); /* callback to tell us we're not flowing */
+ void (*resize)(); /* callback handling screen resize */
+ void (*winch_cleanup)(); /* callback handling screen resize */
++ void (*newthread)(); /* callback to create new thread */
+ int arm_winch_cleanup; /* do the winch_cleanup if resized */
++ int *auto_cmds; /* Initial keystroke commands */
+ HELP_T search_help;
+ HELP_T ins_help;
+ HELP_T ins_m_help;
+diff -rc alpine-2.00/pico/pilot.c alpine-2.00.I.USE/pico/pilot.c
+*** alpine-2.00/pico/pilot.c 2008-04-02 15:09:20.000000000 -0700
+--- alpine-2.00.I.USE/pico/pilot.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 142,148 ****
+ if(display_character_set)
+ display_charmap = cpstr(display_character_set);
+ #if HAVE_LANGINFO_H && defined(CODESET)
+! else
+ display_charmap = cpstr(nl_langinfo_codeset_wrapper());
+ #endif
+
+--- 142,148 ----
+ if(display_character_set)
+ display_charmap = cpstr(display_character_set);
+ #if HAVE_LANGINFO_H && defined(CODESET)
+! else if (nl_langinfo_codeset_wrapper() != NULL)
+ display_charmap = cpstr(nl_langinfo_codeset_wrapper());
+ #endif
+
+diff -rc alpine-2.00/pico/random.c alpine-2.00.I.USE/pico/random.c
+*** alpine-2.00/pico/random.c 2007-08-15 16:07:18.000000000 -0700
+--- alpine-2.00.I.USE/pico/random.c 2011-02-07 20:33:44.000000000 -0800
+***************
+*** 73,79 ****
+ thisline+1, lines+1, (int)((100L*(thisline+1))/(lines+1)),
+ nbc, nch, (nch) ? (int)((100L*nbc)/nch) : 0);
+
+! emlwrite(buffer, NULL);
+ return (TRUE);
+ }
+
+--- 73,82 ----
+ thisline+1, lines+1, (int)((100L*(thisline+1))/(lines+1)),
+ nbc, nch, (nch) ? (int)((100L*nbc)/nch) : 0);
+
+! if(Pmaster)
+! strcpy(Pmaster->curpos, buffer);
+! else
+! emlwrite(buffer, NULL);
+ return (TRUE);
+ }
+
+diff -rc alpine-2.00/pico/search.c alpine-2.00.I.USE/pico/search.c
+*** alpine-2.00/pico/search.c 2008-01-04 14:49:15.000000000 -0800
+--- alpine-2.00.I.USE/pico/search.c 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 35,41 ****
+ int readpattern(char *, int);
+ int replace_pat(UCS *, int *);
+ int replace_all(UCS *, UCS *);
+!
+
+ #define FWS_RETURN(RV) { \
+ thisflag |= CFSRCH; \
+--- 35,41 ----
+ int readpattern(char *, int);
+ int replace_pat(UCS *, int *);
+ int replace_all(UCS *, UCS *);
+! int deletepara(int, int);
+
+ #define FWS_RETURN(RV) { \
+ thisflag |= CFSRCH; \
+***************
+*** 75,80 ****
+--- 75,84 ----
+ N_("~ Hitting only ~R~e~t~u~r~n or at the prompt will cause the"),
+ N_(" search to be made with the default value."),
+ " ",
++ N_("~ Hitting ~^~N will reinsert the last string you searched for"),
++ N_(" so that you can edit it (in case you made a mistake entering the"),
++ N_(" search pattern the first time)."),
++ " ",
+ N_(" The text search is not case sensitive, and will examine the"),
+ N_(" entire message."),
+ " ",
+***************
+*** 139,146 ****
+
+ case HELPCH: /* help requested */
+ if(Pmaster){
+- VARS_TO_SAVE *saved_state;
+-
+ saved_state = save_pico_state();
+ (*Pmaster->helper)(Pmaster->search_help,
+ _("Help for Searching"), 1);
+--- 143,148 ----
+***************
+*** 231,240 ****
+--- 233,251 ----
+ mlerase();
+ FWS_RETURN(TRUE);
+
++ case (CTRL|'P'):
++ deletepara(0, 1);
++ mlerase();
++ FWS_RETURN(TRUE);
++
+ case (CTRL|'R'): /* toggle replacement option */
+ repl_mode = !repl_mode;
+ break;
+
++ case (CTRL|'X'):
++ deltext(f,n);
++ FWS_RETURN(TRUE);
++
+ default:
+ if(status == ABORT)
+ emlwrite(_("Search Cancelled"), NULL);
+***************
+*** 273,279 ****
+ }
+
+ if(status + curwp->w_doto >= llength(curwp->w_dotp) ||
+! !eq(defpat[status],lgetc(curwp->w_dotp, curwp->w_doto + status).c))
+ break; /* do nothing! */
+ status++;
+ }
+--- 284,290 ----
+ }
+
+ if(status + curwp->w_doto >= llength(curwp->w_dotp) ||
+! !eq((unsigned char)defpat[status],lgetc(curwp->w_dotp, curwp->w_doto + status).c))
+ break; /* do nothing! */
+ status++;
+ }
+***************
+*** 430,437 ****
+
+ case HELPCH: /* help requested */
+ if(Pmaster){
+- VARS_TO_SAVE *saved_state;
+-
+ saved_state = save_pico_state();
+ (*Pmaster->helper)(Pmaster->search_help,
+ _("Help for Searching"), 1);
+--- 441,446 ----
+***************
+*** 463,470 ****
+ break;
+
+ default:
+! if(status == ABORT)
+ emlwrite(_("Replacement Cancelled"), NULL);
+ else{
+ mlerase();
+ chword(defpat, origpat);
+--- 472,481 ----
+ break;
+
+ default:
+! if(status == ABORT){
+ emlwrite(_("Replacement Cancelled"), NULL);
++ pico_refresh(FALSE, 1);
++ }
+ else{
+ mlerase();
+ chword(defpat, origpat);
+***************
+*** 597,603 ****
+ UCS *b;
+ UCS prompt[NPMT];
+ UCS *promptp;
+! EXTRAKEYS menu_pat[8];
+
+ menu_pat[i = 0].name = "^Y";
+ menu_pat[i].label = N_("FirstLine");
+--- 608,614 ----
+ UCS *b;
+ UCS prompt[NPMT];
+ UCS *promptp;
+! EXTRAKEYS menu_pat[10];
+
+ menu_pat[i = 0].name = "^Y";
+ menu_pat[i].label = N_("FirstLine");
+***************
+*** 615,620 ****
+--- 626,636 ----
+ KS_OSDATASET(&menu_pat[i], KS_NONE);
+
+ if(!repl_mode){
++ menu_pat[++i].name = "^X";
++ menu_pat[i].label = N_("DelEnd");
++ menu_pat[i].key = (CTRL|'X');
++ KS_OSDATASET(&menu_pat[i], KS_NONE);
++
+ menu_pat[++i].name = "^T";
+ menu_pat[i].label = N_("LineNumber");
+ menu_pat[i].key = (CTRL|'T');
+***************
+*** 631,636 ****
+--- 647,657 ----
+ menu_pat[i].key = (CTRL|'O');
+ KS_OSDATASET(&menu_pat[i], KS_NONE);
+
++ menu_pat[++i].name = "^P";
++ menu_pat[i].label = N_("Delete Para");
++ menu_pat[i].key = (CTRL|'P');
++ KS_OSDATASET(&menu_pat[i], KS_NONE);
++
+ menu_pat[++i].name = "^U";
+ /* TRANSLATORS: Instead of justifying (formatting) just a
+ single paragraph, Full Justify justifies the entire
+***************
+*** 766,772 ****
+ UCS *b;
+ UCS tpat[NPAT+20];
+ UCS *tpatp;
+! EXTRAKEYS menu_pat[7];
+
+ menu_pat[i = 0].name = "^Y";
+ menu_pat[i].label = N_("FirstLine");
+--- 787,793 ----
+ UCS *b;
+ UCS tpat[NPAT+20];
+ UCS *tpatp;
+! EXTRAKEYS menu_pat[9];
+
+ menu_pat[i = 0].name = "^Y";
+ menu_pat[i].label = N_("FirstLine");
+***************
+*** 779,784 ****
+--- 800,810 ----
+ KS_OSDATASET(&menu_pat[i], KS_NONE);
+
+ if(text_mode){
++ menu_pat[++i].name = "^X";
++ menu_pat[i].label = N_("DelEnd");
++ menu_pat[i].key = (CTRL|'X');
++ KS_OSDATASET(&menu_pat[i], KS_NONE);
++
+ menu_pat[++i].name = "^T";
+ menu_pat[i].label = N_("LineNumber");
+ menu_pat[i].key = (CTRL|'T');
+***************
+*** 794,799 ****
+--- 820,830 ----
+ menu_pat[i].key = (CTRL|'O');
+ KS_OSDATASET(&menu_pat[i], KS_NONE);
+
++ menu_pat[++i].name = "^P";
++ menu_pat[i].label = N_("Delete Para");
++ menu_pat[i].key = (CTRL|'P');
++ KS_OSDATASET(&menu_pat[i], KS_NONE);
++
+ menu_pat[++i].name = "^U";
+ menu_pat[i].label = N_("FullJustify");
+ menu_pat[i].key = (CTRL|'U');
+***************
+*** 924,930 ****
+ c = lgetc(curline, curoff++).c; /* get the char */
+
+ /* test it against first char in pattern */
+! if (eq(c, patrn[0]) != FALSE) { /* if we find it..*/
+ /* setup match pointers */
+ matchline = curline;
+ matchoff = curoff;
+--- 955,961 ----
+ c = lgetc(curline, curoff++).c; /* get the char */
+
+ /* test it against first char in pattern */
+! if (eq(c, (unsigned char)patrn[0]) != FALSE) { /* if we find it..*/
+ /* setup match pointers */
+ matchline = curline;
+ matchoff = curoff;
+***************
+*** 945,951 ****
+ return(FALSE);
+
+ /* and test it against the pattern */
+! if (eq(*patptr, c) == FALSE)
+ goto fail;
+ }
+
+--- 976,982 ----
+ return(FALSE);
+
+ /* and test it against the pattern */
+! if (eq((unsigned char) *patptr, c) == FALSE)
+ goto fail;
+ }
+
+***************
+*** 1032,1034 ****
+--- 1063,1087 ----
+
+ curwp->w_flag |= WFEDIT;
+ }
++
++ int
++ deletepara(int f, int n) /* Delete the current paragraph */
++ {
++ if(curbp->b_mode&MDVIEW) /* don't allow this command if */
++ return(rdonly()); /* we are in read only mode */
++
++ if(!lisblank(curwp->w_dotp))
++ gotobop(FALSE, 1);
++
++ curwp->w_markp = curwp->w_dotp;
++ curwp->w_marko = 0;
++
++ gotoeop(FALSE, 1);
++ if (curwp->w_dotp != curbp->b_linep){ /* if we are not at the end of buffer */
++ curwp->w_dotp = lforw(curwp->w_dotp); /* get one more line */
++ curwp->w_doto = 0; /* but only the beginning */
++ }
++ killregion(f,n);
++ return(TRUE);
++ }
++
+diff -rc alpine-2.00/pico/word.c alpine-2.00.I.USE/pico/word.c
+*** alpine-2.00/pico/word.c 2007-08-20 12:46:37.000000000 -0700
+--- alpine-2.00.I.USE/pico/word.c 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 24,33 ****
+ */
+
+ #include "headers.h"
+!
+
+ int fpnewline(UCS *quote);
+! int fillregion(UCS *qstr, REGION *addedregion);
+ int setquotelevelinregion(int quotelevel, REGION *addedregion);
+ int is_user_separator(UCS c);
+
+--- 24,33 ----
+ */
+
+ #include "headers.h"
+! #include "../pith/osdep/color.h"
+
+ int fpnewline(UCS *quote);
+! int fillregion(UCS *qstr, UCS *istr, REGION *addedregion);
+ int setquotelevelinregion(int quotelevel, REGION *addedregion);
+ int is_user_separator(UCS c);
+
+***************
+*** 430,471 ****
+ return 0;
+ }
+
+
+ /*
+ * Return number of quotes if whatever starts the line matches the quote string
+ */
+ int
+! quote_match(UCS *q, LINE *l, UCS *buf, size_t buflen)
+ {
+! register int i, n, j, qb;
+
+! *buf = '\0';
+! if(*q == '\0')
+! return(1);
+!
+! qb = (ucs4_strlen(q) > 1 && q[ucs4_strlen(q)-1] == ' ') ? 1 : 0;
+! for(n = 0, j = 0; ;){
+! for(i = 0; j <= llength(l) && qb ? q[i+1] : q[i]; i++, j++)
+! if(q[i] != lgetc(l, j).c)
+! return(n);
+!
+! n++;
+! if((!qb && q[i] == '\0') || (qb && q[i+1] == '\0')){
+! if(ucs4_strlen(buf) + ucs4_strlen(q) + 1 < buflen){
+! ucs4_strncat(buf, q, buflen-ucs4_strlen(q)-1);
+! buf[buflen-1] = '\0';
+! if(qb && (j > llength(l) || lgetc(l, j).c != ' '))
+! buf[ucs4_strlen(buf)-1] = '\0';
+! }
+! }
+! if(j > llength(l))
+! return(n);
+! else if(qb && lgetc(l, j).c == ' ')
+! j++;
+ }
+! return(n); /* never reached */
+ }
+
+
+ /* Justify the entire buffer instead of just a paragraph */
+ int
+--- 430,600 ----
+ return 0;
+ }
+
++ /* Support of indentation of paragraphs */
++ #define is_indent_char(c) (((c) == '.' || (c) == '}' || (c) == RPAREN || \
++ (c) == '*' || (c) == '+' || is_a_digit(c) || \
++ ISspace(c) || (c) == '-' || \
++ (c) == ']') ? 1 : 0)
++ #define allowed_after_digit(c,word,k) ((((c) == '.' && \
++ allowed_after_period(next((word),(k)))) ||\
++ (c) == RPAREN || (c) == '}' || (c) == ']' ||\
++ ISspace(c) || is_a_digit(c) || \
++ ((c) == '-' ) && \
++ allowed_after_dash(next((word),(k)))) \
++ ? 1 : 0)
++ #define allowed_after_period(c) (((c) == RPAREN || (c) == '}' || (c) == ']' ||\
++ ISspace(c) || (c) == '-' || \
++ is_a_digit(c)) ? 1 : 0)
++ #define allowed_after_parenth(c) (ISspace(c) ? 1 : 0)
++ #define allowed_after_space(c) (ISspace(c) ? 1 : 0)
++ #define allowed_after_braces(c) (ISspace(c) ? 1 : 0)
++ #define allowed_after_star(c) ((ISspace(c) || (c) == RPAREN ||\
++ (c) == ']' || (c) == '}') ? 1 : 0)
++ #define allowed_after_dash(c) ((ISspace(c) || is_a_digit(c)) ? 1 : 0)
++ #define EOLchar(c) (((c) == '.' || (c) == ':' || (c) == '?' ||\
++ (c) == '!') ? 1 : 0)
++
++ int indent_match(char *, LINE *, char *, int, int);
++
++ /* Extended justification support */
++ #define is_cquote(c) ((c) == '>' || (c) == '|' || (c) == ']' || (c) == ':')
++ #define is_cword(c) ((((c) >= 'a') && ((c) <= 'z')) || \
++ (((c) >= 'A') && ((c) <= 'Z')) || \
++ (((c) >= '0') && ((c) <= '9')) || \
++ ((c) == ' ') || ((c) == '?') || \
++ ((c) == '@') || ((c) == '.') || \
++ ((c) == '!') || ((c) == '\'') || \
++ ((c) == ',') || ((c) == '\"') ? 1 : 0)
++ #define isaquote(c) ((c) == '\"' || (c) == '\'')
++ #define is8bit(c) ((((int) (c)) & 0x80) ? 1 : 0)
++ #define iscontrol(c) (iscntrl(((int) (c)) & 0x7f) ? 1 : 0)
++ #define forbidden(c) (((c) == '\"') || ((c) == '\'') || ((c) == '$') ||\
++ ((c) == ',') || ((c) == '.') || ((c) == '-') ||\
++ ((c) == LPAREN) || ((c) == '/')|| ((c) == '`') ||\
++ ((c) == '{') || ((c) == '\\') || (iscontrol((c))) ||\
++ (((c) >= '0') && ((c) <= '9')) || ((c) == '?'))
++ #define is_cletter(c) ((((c) >= 'a') && ((c) <= 'z'))) ||\
++ ((((c) >= 'A') && ((c) <= 'Z'))||\
++ is8bit(c))
++ #define is_cnumber(c) ((c) >= '0' && (c) <= '9')
++ #define allwd_after_word(c) (((c) == ' ') || ((c) == '>') || is_cletter(c))
++ #define allwd_after_qsword(c) (((c) != '\\') && ((c) != RPAREN))
++ #define before(word,i) (((i) > 0) ? (word)[(i) - 1] : 0)
++ #define next(w,i) ((((w)[(i)]) != 0) ? ((w)[(i) + 1]) : 0)
++ #define now(w,i) ((w)[(i)])
++ #define is_qsword(c) (((c) == ':') || ((c) == RPAREN) ? 1 : 0)
++ #define is_colon(c) (((c) == ':') ? 1 : 0)
++ #define is_rarrow(c) (((c) == '>') ? 1 : 0)
++ #define is_tilde(c) (((c) == '~') ? 1 : 0)
++ #define is_dash(c) (((c) == '-') ? 1 : 0)
++ #define is_pound(c) (((c) == '#') ? 1 : 0)
++ #define is_a_digit(c) ((((c) >= '0') && ((c) <= '9')) ? 1 : 0)
++ #define is_allowed(c) (is_cquote(c) || is_cword(c) || is_dash(c) || \
++ is_pound(c))
++ #define qs_allowed(a) (((a)->qstype != qsGdb) && ((a)->qstype != qsProg))
++
++ /* Internal justification functions */
++ QSTRING_S *qs_quote_match(char *, LINE *, char *, int);
++ int ucs4_strlenis(UCS *);
++ void linencpy(char *, LINE *, int);
++
++
++ char *
++ default_qstr(void)
++ {
++ char *default_qs;
++ static char ucs_def[NSTRING] = {'\0'};
++
++ if(ucs_def[0] == '\0'){
++ default_qs = ucs4_to_utf8_cpystr(glo_quote_str);
++ strncpy(ucs_def, (default_qs ? default_qs : ""), NSTRING);
++ fs_give((void **)&default_qs);
++ }
++
++ return glo_quote_str ? ucs_def : "";
++ }
++
++ void
++ linencpy(word, l, buflen)
++ char word[NSTRING];
++ LINE *l;
++ int buflen;
++ {
++ int i;
++ UCS ucs_word[NSTRING];
++ char *utf_word;
++
++ word[0] = '\0';
++ if(l){
++ for (i = 0; i < buflen && i < llength(l)
++ && (ucs_word[i] = lgetc(l,i).c); i++);
++ ucs_word[i == buflen ? i-1 : i] = '\0';
++ utf_word = ucs4_to_utf8_cpystr(ucs_word);
++ strncpy(word, utf_word, (NSTRING < buflen ? NSTRING : buflen));
++ word[NSTRING-1] = '\0';
++ if(utf_word) fs_give((void **)&utf_word);
++ }
++ }
++
++ /*
++ * This function returns the quote string as a structure. In this way we
++ * have two ways to get the quote string: as a char * or as a QSTRING_S *
++ * directly.
++ */
++ QSTRING_S *
++ qs_quote_match(char *q, LINE *l, char *rqstr, int rqstrlen)
++ {
++ char GLine[NSTRING], NLine[NSTRING], PLine[NSTRING];
++ LINE *nl = l != curbp->b_linep ? lforw(l) : NULL;
++ LINE *pl = lback(l) != curbp->b_linep ? lback(l) : NULL;
++ int plb = 1;
++
++ linencpy(GLine, l, NSTRING);
++ linencpy(NLine, nl, NSTRING);
++
++ if (pl){
++ linencpy(PLine, pl, NSTRING);
++ if(lback(pl) != curbp->b_linep){
++ char PPLine[NSTRING];
++
++ linencpy(PPLine, lback(pl), NSTRING);
++ plb = line_isblank(q, PLine, GLine, PPLine, NSTRING);
++ }
++ }
++ return do_quote_match(q, GLine, NLine, PLine, rqstr, rqstrlen, plb);
++ }
+
+ /*
+ * Return number of quotes if whatever starts the line matches the quote string
++ * rqstring is pointer to raw qstring, buf points to processed qstring
+ */
+ int
+! quote_match(char *q, LINE *l, char *buf, size_t buflen, int raw)
+ {
+! QSTRING_S *qs;
+! char rqstr[NSTRING];
+
+! qs = qs_quote_match(q, l, rqstr, NSTRING);
+! flatten_qstring(qs, buf, buflen);
+! if (qs)
+! free_qs(&qs);
+!
+! if(raw){
+! strncpy(buf, rqstr, buflen < NSTRING ? buflen : NSTRING);
+! buf[buflen-1] = '\0';
+ }
+!
+! return buf && buf[0] ? strlen(buf) : 0;
+ }
+
++ int ucs4_strlenis(UCS *ucs_qstr)
++ {
++ char *str = ucs4_to_utf8_cpystr(ucs_qstr);
++ int i = (int) strlenis(str);
++
++ if(str) fs_give((void **)&str);
++ return i;
++ }
+
+ /* Justify the entire buffer instead of just a paragraph */
+ int
+***************
+*** 720,725 ****
+--- 849,855 ----
+ }
+
+ if(action == 'R' && curwp->w_markp){
++ char qstrfl[NSTRING];
+ /* let yank() know that it may be restoring a paragraph */
+ thisflag |= CFFILL;
+
+***************
+*** 732,752 ****
+
+ /* determine if we're justifying quoted text or not */
+ qstr = (glo_quote_str
+! && quote_match(glo_quote_str,
+! curwp->w_doto > 0 ? curwp->w_dotp->l_fp : curwp->w_dotp,
+! qstr2, NSTRING)
+! && *qstr2) ? qstr2 : NULL;
+!
+
+ /*
+ * Fillregion moves dot to the end of the filled region.
+ */
+! if(!fillregion(qstr, &addedregion))
+ return(FALSE);
+
+ set_last_region_added(&addedregion);
+ }
+ else if(action == 'P'){
+
+ /*
+ * Justfiy the current paragraph.
+--- 862,886 ----
+
+ /* determine if we're justifying quoted text or not */
+ qstr = (glo_quote_str
+! && quote_match(default_qstr(),
+! (curwp->w_doto > 0 ? curwp->w_dotp->l_fp : curwp->w_dotp),
+! qstrfl, NSTRING, 0)
+! && *qstrfl) ? utf8_to_ucs4_cpystr(qstrfl) : NULL;
+
+ /*
+ * Fillregion moves dot to the end of the filled region.
+ */
+! if(!fillregion(qstr, NULL, &addedregion))
+ return(FALSE);
+
+ set_last_region_added(&addedregion);
++
++ if(qstr)
++ fs_give((void **)&qstr);
+ }
+ else if(action == 'P'){
++ char ind_str[NSTRING], qstrfl[NSTRING];
++ UCS *istr;
+
+ /*
+ * Justfiy the current paragraph.
+***************
+*** 758,774 ****
+ if(gotoeop(FALSE, 1) == FALSE)
+ return(FALSE);
+
+- /* determine if we're justifying quoted text or not */
+- qstr = (glo_quote_str
+- && quote_match(glo_quote_str,
+- curwp->w_dotp, qstr2, NSTRING)
+- && *qstr2) ? qstr2 : NULL;
+-
+ setmark(0,0); /* mark last line of para */
+
+ /* jump back to the beginning of the paragraph */
+ gotobop(FALSE, 1);
+
+ /* let yank() know that it may be restoring a paragraph */
+ thisflag |= (CFFILL | CFFLPA);
+
+--- 892,907 ----
+ if(gotoeop(FALSE, 1) == FALSE)
+ return(FALSE);
+
+ setmark(0,0); /* mark last line of para */
+
+ /* jump back to the beginning of the paragraph */
+ gotobop(FALSE, 1);
+
++ istr = indent_match(default_qstr(), curwp->w_dotp, ind_str, NSTRING, 0)
++ && *ind_str ? utf8_to_ucs4_cpystr(ind_str) : NULL;
++ qstr = (quote_match(default_qstr(), curwp->w_dotp, qstrfl, NSTRING, 0)
++ && *qstrfl) ? utf8_to_ucs4_cpystr(qstrfl) : NULL;
++
+ /* let yank() know that it may be restoring a paragraph */
+ thisflag |= (CFFILL | CFFLPA);
+
+***************
+*** 782,790 ****
+ /*
+ * Fillregion moves dot to the end of the filled region.
+ */
+! if(!fillregion(qstr, &addedregion))
+ return(FALSE);
+
+ set_last_region_added(&addedregion);
+
+ /* Leave cursor on first char of first line after justified region */
+--- 915,929 ----
+ /*
+ * Fillregion moves dot to the end of the filled region.
+ */
+! if(!fillregion(qstr, istr, &addedregion))
+ return(FALSE);
+
++ if(qstr)
++ fs_give((void **)&qstr);
++
++ if(istr)
++ fs_give((void **)&istr);
++
+ set_last_region_added(&addedregion);
+
+ /* Leave cursor on first char of first line after justified region */
+***************
+*** 826,841 ****
+ * can delete it and restore the saved part.
+ */
+ int
+! fillregion(UCS *qstr, REGION *addedregion)
+ {
+ long c, sz, last_char = 0;
+! int i, j, qlen, same_word,
+ spaces, word_len, word_ind, line_len, ww;
+ int starts_midline = 0;
+ int ends_midline = 0;
+ int offset_into_start;
+ LINE *line_before_start, *lp;
+! UCS line_last, word[NSTRING];
+ REGION region;
+
+ /* if region starts midline insert a newline */
+--- 965,980 ----
+ * can delete it and restore the saved part.
+ */
+ int
+! fillregion(UCS *qstr, UCS *istr, REGION *addedregion)
+ {
+ long c, sz, last_char = 0;
+! int i, j, qlen, same_word, qi, pqi, qlenis,
+ spaces, word_len, word_ind, line_len, ww;
+ int starts_midline = 0;
+ int ends_midline = 0;
+ int offset_into_start;
+ LINE *line_before_start, *lp;
+! UCS line_last, word[NSTRING], quoid[NSTRING], qstr2[NSTRING];
+ REGION region;
+
+ /* if region starts midline insert a newline */
+***************
+*** 846,851 ****
+--- 985,1019 ----
+ if(curwp->w_marko > 0 && curwp->w_marko < llength(curwp->w_markp))
+ ends_midline++;
+
++ for (i = 0; (i < NSTRING) && qstr && (quoid[i] = qstr[i]); i++);
++ for (j = 0; ((i + j) < NSTRING) && istr && (quoid[i] = istr[j]); i++,j++);
++ quoid[i] = '\0';
++ qi = ucs4_strlen(quoid);
++ if (istr) /* strip trailing spaces */
++ for (;ISspace(quoid[qi - 1]); qi--);
++ quoid[qi] = '\0'; /* we have closed quoid at "X" in the first line */
++
++ if (ucs4_strlenis(quoid) > fillcol)
++ return FALSE; /* Too wide, we can't justify this! */
++
++ if (qstr && istr){
++ for (i = ucs4_strlen(qstr) - 1; ISspace(qstr[i]); i--);
++ qstr[i + 1] = '\0'; /* qstrfl */
++ }
++ qlen = ucs4_strlen(qstr); /* qstrfl*/
++ qlenis = ucs4_strlenis(qstr);
++
++ for(i = 0, qstr2[0] = '\0'; qstr && qstr[i] && (qstr2[i] = qstr[i]); i++);
++
++ if (istr && ((j = ucs4_strlenis(quoid) - ucs4_strlenis(qstr)) > 0)){
++ pqi = ucs4_strlen(qstr);
++ for (i = 0; (i < j) && (qstr2[pqi + i] = ' '); i++);
++ if (ISspace(istr[ucs4_strlen(istr) - 1]))
++ qstr2[pqi + i++] = ' ';
++ qstr2[pqi + i] = '\0';
++ qstr = qstr2;
++ }
++
+ /* cut the paragraph into our fill buffer */
+ fdelete();
+ if(!getregion(&region, curwp->w_markp, curwp->w_marko))
+***************
+*** 862,889 ****
+
+ /* Now insert it back wrapped */
+ spaces = word_len = word_ind = line_len = same_word = 0;
+- qlen = qstr ? ucs4_strlen(qstr) : 0;
+
+ /* Beginning with leading quoting... */
+! if(qstr){
+! i = 0;
+! while(qstr[i]){
+! ww = wcellwidth(qstr[i]);
+! line_len += (ww >= 0 ? ww : 1);
+! linsert(1, qstr[i++]);
+! }
+
+ line_last = ' '; /* no word-flush space! */
+ }
+
+ /* remove first leading quotes if any */
+ if(starts_midline)
+ i = 0;
+! else
+! for(i = qlen; (c = fremove(i)) == ' ' || c == TAB; i++){
+ linsert(1, line_last = (UCS) c);
+ line_len += ((c == TAB) ? (~line_len & 0x07) + 1 : 1);
+ }
+
+ /* then digest the rest... */
+ while((c = fremove(i++)) >= 0){
+--- 1030,1065 ----
+
+ /* Now insert it back wrapped */
+ spaces = word_len = word_ind = line_len = same_word = 0;
+
+ /* Beginning with leading quoting... */
+! if(qstr || istr){
+! for(i = 0; quoid[i] != '\0' ; i++)
+! linsert(1, quoid[i]);
+
+ line_last = ' '; /* no word-flush space! */
++ line_len = ucs4_strlenis(quoid); /* we demand a recount! */
+ }
+
+ /* remove first leading quotes if any */
+ if(starts_midline)
+ i = 0;
+! else{
+! if(qstr || istr){
+! for (i = 0; (c = fremove(i)) != '\0'; i++){
+! word[i] = c;
+! word[i+1] = '\0';
+! if(ucs4_strlenis(word) >= ucs4_strlenis(quoid))
+! break;
+! }
+! i++;
+! }
+! else
+! i = 0;
+! for(; ISspace(c = fremove(i)); i++){
+ linsert(1, line_last = (UCS) c);
+ line_len += ((c == TAB) ? (~line_len & 0x07) + 1 : 1);
+ }
++ }
+
+ /* then digest the rest... */
+ while((c = fremove(i++)) >= 0){
+***************
+*** 905,925 ****
+
+ case TAB :
+ case ' ' :
+ spaces++;
+ same_word = 0;
+ break;
+
+ default :
+ if(spaces){ /* flush word? */
+! if((line_len - qlen > 0)
+ && line_len + word_len + 1 > fillcol
+! && ((ucs4_isspace(line_last))
+ || (linsert(1, ' ')))
+ && (line_len = fpnewline(qstr)))
+ line_last = ' '; /* no word-flush space! */
+
+ if(word_len){ /* word to write? */
+! if(line_len && !ucs4_isspace(line_last)){
+ linsert(1, ' '); /* need padding? */
+ line_len++;
+ }
+--- 1081,1102 ----
+
+ case TAB :
+ case ' ' :
++ case NBSP:
+ spaces++;
+ same_word = 0;
+ break;
+
+ default :
+ if(spaces){ /* flush word? */
+! if((line_len - qlenis > 0)
+ && line_len + word_len + 1 > fillcol
+! && ((ISspace(line_last))
+ || (linsert(1, ' ')))
+ && (line_len = fpnewline(qstr)))
+ line_last = ' '; /* no word-flush space! */
+
+ if(word_len){ /* word to write? */
+! if(line_len && !ISspace(line_last)){
+ linsert(1, ' '); /* need padding? */
+ line_len++;
+ }
+***************
+*** 941,948 ****
+
+ if(word_ind + 1 >= NSTRING){
+ /* Magic! Fake that we output a wrapped word */
+! if((line_len - qlen > 0) && !same_word++){
+! if(!ucs4_isspace(line_last))
+ linsert(1, ' ');
+ line_len = fpnewline(qstr);
+ }
+--- 1118,1125 ----
+
+ if(word_ind + 1 >= NSTRING){
+ /* Magic! Fake that we output a wrapped word */
+! if((line_len - qlenis > 0) && !same_word++){
+! if(!ISspace(line_last))
+ linsert(1, ' ');
+ line_len = fpnewline(qstr);
+ }
+***************
+*** 964,975 ****
+ }
+
+ if(word_len){
+! if((line_len - qlen > 0) && (line_len + word_len + 1 > fillcol)){
+! if(!ucs4_isspace(line_last))
+ linsert(1, ' ');
+ (void) fpnewline(qstr);
+ }
+! else if(line_len && !ucs4_isspace(line_last))
+ linsert(1, ' ');
+
+ for(j = 0; j < word_ind; j++)
+--- 1141,1152 ----
+ }
+
+ if(word_len){
+! if((line_len - qlenis > 0) && (line_len + word_len + 1 > fillcol)){
+! if(!ISspace(line_last))
+ linsert(1, ' ');
+ (void) fpnewline(qstr);
+ }
+! else if(line_len && !ISspace(line_last))
+ linsert(1, ' ');
+
+ for(j = 0; j < word_ind; j++)
+***************
+*** 1027,1037 ****
+ int len;
+
+ lnewline();
+! for(len = 0; quote && *quote; quote++){
+ int ww;
+
+! ww = wcellwidth(*quote);
+! len += (ww >= 0 ? ww : 1);
+ linsert(1, *quote);
+ }
+
+--- 1204,1214 ----
+ int len;
+
+ lnewline();
+! for(len = ucs4_strlenis(quote); quote && *quote; quote++){
+ int ww;
+
+! /* ww = wcellwidth(*quote);
+! len += (ww >= 0 ? ww : 1);*/
+ linsert(1, *quote);
+ }
+
+***************
+*** 1175,1179 ****
+--- 1352,1396 ----
+ markregion(1);
+ }
+
++ /*
++ * This puts us at the end of the quoted region instead
++ * of on the following line. This makes it convenient
++ * for the user to follow a quotelevel adjustment with
++ * a Justify if desired.
++ */
++ if(backuptoprevline){
++ curwp->w_doto = 0;
++ backchar(0, 1);
++ }
++
++ if(ends_midline){ /* doesn't need fixing otherwise */
++ unmarkbuffer();
++ markregion(1);
++ }
++
+ return (TRUE);
+ }
++
++ /*
++ * If there is an indent string this function returns
++ * its length
++ */
++ int
++ indent_match(char *q, LINE *l, char *buf, int buflen, int raw)
++ {
++ char GLine[NSTRING];
++ int i, k, plb;
++
++ k = quote_match(q,l, buf, buflen, raw);
++ linencpy(GLine, l, NSTRING);
++ plb = (lback(l) != curbp->b_linep) ? lisblank(lback(l)) : 1;
++ if (!plb){
++ i = llength(lback(l)) - 1;
++ for (; i >= 0 && ISspace(lgetc(lback(l), i).c); i--);
++ if (EOLchar(lgetc(lback(l), i).c))
++ plb++;
++ }
++
++ return get_indent_raw_line(q, GLine, buf, buflen, k, plb);
++ }
++
+diff -rc alpine-2.00/pith/adrbklib.c alpine-2.00.I.USE/pith/adrbklib.c
+*** alpine-2.00/pith/adrbklib.c 2008-06-03 08:54:15.000000000 -0700
+--- alpine-2.00.I.USE/pith/adrbklib.c 2011-02-07 20:33:41.000000000 -0800
+***************
+*** 5119,5126 ****
+ if(as.cur >= as.how_many_personals)
+ pab->type |= GLOBAL;
+
+! pab->access = adrbk_access(pab);
+!
+ /* global address books are forced readonly */
+ if(pab->type & GLOBAL && pab->access != NoAccess)
+ pab->access = ReadOnly;
+--- 5119,5132 ----
+ if(as.cur >= as.how_many_personals)
+ pab->type |= GLOBAL;
+
+! if(ps_global->mail_stream &&
+! ps_global->mail_stream->lock && (pab->type & REMOTE_VIA_IMAP)){
+! as.initialized = 0;
+! pab->access = NoAccess;
+! }
+! else{
+! pab->access = adrbk_access(pab);
+! }
+ /* global address books are forced readonly */
+ if(pab->type & GLOBAL && pab->access != NoAccess)
+ pab->access = ReadOnly;
+diff -rc alpine-2.00/pith/charconv/utf8.c alpine-2.00.I.USE/pith/charconv/utf8.c
+*** alpine-2.00/pith/charconv/utf8.c 2008-04-02 15:09:20.000000000 -0700
+--- alpine-2.00.I.USE/pith/charconv/utf8.c 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 1048,1053 ****
+--- 1048,1103 ----
+
+
+ /*
++ * Returns the screen cells width of the UTF-8 string argument, treating tabs
++ * in a special way.
++ */
++ unsigned
++ utf8_widthis(char *str)
++ {
++ unsigned width = 0;
++ int this_width;
++ UCS ucs;
++ unsigned long remaining_octets;
++ char *readptr;
++
++ if(!(str && *str))
++ return(width);
++
++ readptr = str;
++ remaining_octets = readptr ? strlen(readptr) : 0;
++
++ while(remaining_octets > 0 && *readptr){
++
++ ucs = (UCS) utf8_get((unsigned char **) &readptr, &remaining_octets);
++
++ if(ucs & U8G_ERROR){
++ /*
++ * This should not happen, but do something to handle it anyway.
++ * Treat each character as a single width character, which is what should
++ * probably happen when we actually go to write it out.
++ */
++ remaining_octets--;
++ readptr++;
++ this_width = 1;
++ }
++ else{
++ this_width = (ucs == TAB) ? ((~width & 0x07) + 1) : wcellwidth(ucs);
++
++ /*
++ * If this_width is -1 that means we can't print this character
++ * with our current locale. Writechar will print a '?'.
++ */
++ if(this_width < 0)
++ this_width = 1;
++ }
++
++ width += (unsigned) this_width;
++ }
++
++ return(width);
++ }
++
++ /*
+ * Copy UTF-8 characters from src into dst.
+ * This is intended to be used if you want to truncate a string at
+ * the start instead of the end. For example, you have a long string
+diff -rc alpine-2.00/pith/charconv/utf8.h alpine-2.00.I.USE/pith/charconv/utf8.h
+*** alpine-2.00/pith/charconv/utf8.h 2008-04-02 15:09:20.000000000 -0700
+--- alpine-2.00.I.USE/pith/charconv/utf8.h 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 80,85 ****
+--- 80,86 ----
+ UCS *ucs4_strchr(UCS *s, UCS c);
+ UCS *ucs4_strrchr(UCS *s, UCS c);
+ unsigned utf8_width(char *);
++ unsigned utf8_widthis(char *);
+ size_t utf8_to_width_rhs(char *, char *, size_t, unsigned);
+ int utf8_snprintf(char *, size_t, char *, ...);
+ size_t utf8_to_width(char *, char *, size_t, unsigned, unsigned *);
+diff -rc alpine-2.00/pith/color.c alpine-2.00.I.USE/pith/color.c
+*** alpine-2.00/pith/color.c 2007-08-15 13:28:09.000000000 -0700
+--- alpine-2.00.I.USE/pith/color.c 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 20,26 ****
+ #include "../pith/state.h"
+ #include "../pith/conf.h"
+ #include "../pith/filter.h"
+!
+
+ char *
+ color_embed(char *fg, char *bg)
+--- 20,27 ----
+ #include "../pith/state.h"
+ #include "../pith/conf.h"
+ #include "../pith/filter.h"
+! #include "../pith/mailview.h"
+! #include "../pico/estruct.h"
+
+ char *
+ color_embed(char *fg, char *bg)
+***************
+*** 69,91 ****
+ struct quote_colors *next;
+ };
+
+
+ int
+ color_a_quote(long int linenum, char *line, LT_INS_S **ins, void *is_flowed_msg)
+ {
+! int countem = 0;
+ struct variable *vars = ps_global->vars;
+! char *p;
+ struct quote_colors *colors = NULL, *cp, *next;
+ COLOR_PAIR *col = NULL;
+ int is_flowed = is_flowed_msg ? *((int *)is_flowed_msg) : 0;
+
+ p = line;
+! if(!is_flowed)
+! while(isspace((unsigned char)*p))
+! p++;
+
+! if(p[0] == '>'){
+ struct quote_colors *c;
+
+ /*
+--- 70,179 ----
+ struct quote_colors *next;
+ };
+
++ int
++ is_word (buf, i, j)
++ char buf[NSTRING];
++ int i, j;
++ {
++ return i <= j && is_letter(buf[i]) ?
++ (i < j ? is_word(buf,i+1,j) : 1) : 0;
++ }
++
++ int
++ is_mailbox(buf,i,j)
++ char buf[NSTRING];
++ int i, j;
++ {
++ return i <= j && (is_letter(buf[i]) || is_digit(buf[i]) || buf[i] == '.')
++ ? (i < j ? is_mailbox(buf,i+1,j) : 1) : 0;
++ }
++
++ int
++ next_level_quote(buf, line, i, is_flowed)
++ char *buf;
++ char **line;
++ int i;
++ int is_flowed;
++ {
++ int j;
++
++ if (!single_level(buf[i])){
++ if(is_mailbox(buf,i,i)){
++ for (j = i; buf[j] && !isspace(buf[j]); j++);
++ if (is_word(buf,i,j-1) || is_mailbox(buf,i,j-1))
++ j += isspace(buf[j]) ? 2 : 1;
++ }
++ else{
++ switch(buf[i]){
++ case ':' :
++ if (next(buf,i) != RPAREN)
++ j = i + 1;
++ else
++ j = i + 2;
++ break;
++
++ case '-' :
++ if (next(buf,i) != '-')
++ j = i + 2;
++ else
++ j = i + 3;
++ break;
++
++ case '+' :
++ case '*' :
++ if (next(buf,i) != ' ')
++ j = i + 2;
++ else
++ j = i + 3;
++ break;
++
++ default :
++ for (j = i; buf[j] && !isspace(buf[j])
++ && (!single_level(buf[i]) && !is_letter(buf[j])); j++);
++
++ j += isspace(buf[j]) ? 1 : 0;
++ break;
++ }
++ }
++ if (line && *line)
++ (*line) += j - i;
++ }
++ else{
++ j = i+1;
++ if (line && *line)
++ (*line)++;
++ }
++ if(!is_flowed){
++ if(line && *line)
++ for(; isspace((unsigned char)*(*line)); (*line)++);
++ for (i = j; isspace((unsigned char) buf[i]); i++);
++ }
++ else i = j;
++ if (is_flowed && i != j)
++ buf[i] = '\0';
++ return i;
++ }
+
+ int
+ color_a_quote(long int linenum, char *line, LT_INS_S **ins, void *is_flowed_msg)
+ {
+! int countem = 0, i, j = 0;
+ struct variable *vars = ps_global->vars;
+! char *p, buf[NSTRING] = {'\0'};
+ struct quote_colors *colors = NULL, *cp, *next;
+ COLOR_PAIR *col = NULL;
+ int is_flowed = is_flowed_msg ? *((int *)is_flowed_msg) : 0;
++ int code;
++
++ code = (is_flowed ? IS_FLOWED : NO_FLOWED) | COLORAQUO;
++ select_quote(linenum, line, ins, (void *) &code);
++ strncpy(buf, tmp_20k_buf, NSTRING < SIZEOF_20KBUF ? NSTRING : SIZEOF_20KBUF);
++ buf[sizeof(buf)-1] = '\0';
+
+ p = line;
+! for(i = 0; isspace((unsigned char)buf[i]); i++, p++);
+
+! if(buf[i]){
+ struct quote_colors *c;
+
+ /*
+***************
+*** 134,140 ****
+ free_color_pair(&col);
+
+ cp = NULL;
+! while(*p == '>'){
+ cp = (cp && cp->next) ? cp->next : colors;
+
+ if(countem > 0)
+--- 222,228 ----
+ free_color_pair(&col);
+
+ cp = NULL;
+! while(buf[i]){
+ cp = (cp && cp->next) ? cp->next : colors;
+
+ if(countem > 0)
+***************
+*** 144,153 ****
+
+ countem = (countem == 1) ? 0 : countem;
+
+! p++;
+! if(!is_flowed)
+! for(; isspace((unsigned char)*p); p++)
+! ;
+ }
+
+ if(colors){
+--- 232,240 ----
+
+ countem = (countem == 1) ? 0 : countem;
+
+! i = next_level_quote(buf, &p, i, is_flowed);
+! for (; isspace((unsigned char)*p); p++);
+! for (; isspace((unsigned char)buf[i]); i++);
+ }
+
+ if(colors){
+***************
+*** 210,216 ****
+ }
+ }
+
+! return(0);
+ }
+
+
+--- 297,303 ----
+ }
+ }
+
+! return(1);
+ }
+
+
+diff -rc alpine-2.00/pith/color.h alpine-2.00.I.USE/pith/color.h
+*** alpine-2.00/pith/color.h 2007-05-08 16:38:08.000000000 -0700
+--- alpine-2.00.I.USE/pith/color.h 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 21,26 ****
+--- 21,44 ----
+ #include "../pith/pattern.h"
+ #include "../pith/osdep/color.h"
+
++ #define NO_FLOWED 0x0000
++ #define IS_FLOWED 0x0001
++ #define DELETEQUO 0x0010
++ #define COLORAQUO 0x0100
++ #define RAWSTRING 0x1000
++
++ /* This is needed for justification, I will move it to a better place later
++ * or maybe not
++ */
++ #define is_digit(c) ((((c) >= '0') && ((c) <= '9')) ? 1 : 0)
++
++ #define is_letter(c) (((c) >= 'a' && (c) <= 'z') || \
++ ((c) >= 'A' && (c) <= 'Z'))
++
++ #define next(w,i) ((((w)[(i)]) != 0) ? ((w)[(i) + 1]) : 0)
++
++ #define single_level(c) (((c) == '>') || ((c) == '|') || ((c) == '~') || \
++ ((c) == ']'))
+
+ typedef struct spec_color_s {
+ int inherit; /* this isn't a color, it is INHERIT */
+***************
+*** 80,85 ****
+--- 98,104 ----
+ /* exported protoypes */
+ char *color_embed(char *, char *);
+ int colorcmp(char *, char *);
++ int next_level_quote(char *, char **, int, int);
+ int color_a_quote(long, char *, LT_INS_S **, void *);
+ void free_spec_colors(SPEC_COLOR_S **);
+
+diff -rc alpine-2.00/pith/conf.c alpine-2.00.I.USE/pith/conf.c
+*** alpine-2.00/pith/conf.c 2008-08-22 17:07:05.000000000 -0700
+--- alpine-2.00.I.USE/pith/conf.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 28,33 ****
+--- 28,34 ----
+ #include "../pith/remote.h"
+ #include "../pith/keyword.h"
+ #include "../pith/mailview.h"
++ #include "../pith/rules.h"
+ #include "../pith/list.h"
+ #include "../pith/status.h"
+ #include "../pith/ldap.h"
+***************
+*** 197,208 ****
+--- 198,213 ----
+
+ CONF_TXT_T cf_text_view_hdr_color[] = "When viewing messages, these are the header colors";
+
++ CONF_TXT_T cf_text_index_token_color[] = "Colors in which tokens will be displayed in the index screen";
++
+ CONF_TXT_T cf_text_save_msg_name_rule[] = "Determines default folder name for Saves...\n# Choices: default-folder, by-sender, by-from, by-recipient, last-folder-used.\n# Default: \"default-folder\", i.e. \"saved-messages\" (Unix) or \"SAVEMAIL\" (PC).";
+
+ CONF_TXT_T cf_text_fcc_name_rule[] = "Determines default name for Fcc...\n# Choices: default-fcc, by-recipient, last-fcc-used.\n# Default: \"default-fcc\" (see also \"default-fcc=\" variable.)";
+
+ CONF_TXT_T cf_text_sort_key[] = "Sets presentation order of messages in Index. Choices:\n# Subject, From, Arrival, Date, Size, To, Cc, OrderedSubj, Score, and Thread.\n# Order may be reversed by appending /Reverse. Default: \"Arrival\".";
+
++ CONF_TXT_T cf_text_thread_sort_key[] = "#Sets presentation order of threads in thread index. Choices:\n#arrival, and thread.";
++
+ CONF_TXT_T cf_text_addrbook_sort_rule[] = "Sets presentation order of address book entries. Choices: dont-sort,\n# fullname-with-lists-last, fullname, nickname-with-lists-last, nickname\n# Default: \"fullname-with-lists-last\".";
+
+ CONF_TXT_T cf_text_folder_sort_rule[] = "Sets presentation order of folder list entries. Choices: alphabetical,\n# alpha-with-dirs-last, alpha-with-dirs-first.\n# Default: \"alpha-with-directories-last\".";
+***************
+*** 219,230 ****
+--- 224,267 ----
+
+ CONF_TXT_T cf_text_editor[] = "Specifies the program invoked by ^_ in the Composer,\n# or the \"enable-alternate-editor-implicitly\" feature.";
+
++ CONF_TXT_T cf_text_compose_rules[] = "Allows a user to set rules when composing messages.";
++
++ CONF_TXT_T cf_text_forward_rules[] = "Allows a user to set rules when forwarding messages.";
++
++ CONF_TXT_T cf_text_reply_rules[] = "Allows a user to set rules when replying messages.";
++
++ CONF_TXT_T cf_text_index_rules[] = "Allows a user to supersede global index format variable in designated folders.";
++
++ CONF_TXT_T cf_text_key_def_rules[] = "Allows a user to override keystrokes in certain screens.";
++
++ CONF_TXT_T cf_text_replace_rules[] = "Allows a user to change the form a specify field in the index-format is \n# displayed.";
++
++ CONF_TXT_T cf_text_reply_indent_rules[] = "Allows a user to change the form a specify a reply-indent-string\n# based of rules.";
++
++ CONF_TXT_T cf_text_reply_leadin_rules[] = "Allows a user to replace the reply-leadin message based on different parameters.";
++
++ CONF_TXT_T cf_text_reply_subject_rules[] = "Allows a user to replace the subject of a message in a customs based way";
++
++ CONF_TXT_T cf_text_thread_displaystyle_rule[] = "Allows a user to specify the threading style of specific folders";
++
++ CONF_TXT_T cf_text_thread_indexstyle_rule[] = "Allows a user to specify the threading index style of specific folders";
++
++ CONF_TXT_T cf_text_save_rules[] = "Allows a user to specify a save folder message for specific senders or folders.";
++
++ CONF_TXT_T cf_text_smtp_rules[] = "Allows a user to specify a smtp server to be used when sending e-mail,\n# according to the rules specified here.";
++
++ CONF_TXT_T cf_text_sort_rules[] = "Allows a user to specify the sort default order of a specific folder.";
++
++ CONF_TXT_T cf_text_startup_rules[] = "Allows a user to specify the position of a highlighted message when opening a \n# folder.";
++
+ CONF_TXT_T cf_text_speller[] = "Specifies the program invoked by ^T in the Composer.";
+
+ CONF_TXT_T cf_text_deadlets[] = "Specifies the number of dead letter files to keep when canceling.";
+
+ CONF_TXT_T cf_text_fillcol[] = "Specifies the column of the screen where the composer should wrap.";
+
++ CONF_TXT_T cf_special_text_color[] = "Specifies a comma separated list of text and regular expresions that Pine\n# will highlight";
++
+ CONF_TXT_T cf_text_replystr[] = "Specifies the string to insert when replying to a message.";
+
+ CONF_TXT_T cf_text_quotereplstr[] = "Specifies the string to replace quotes with when viewing a message.";
+***************
+*** 427,432 ****
+--- 464,472 ----
+
+ CONF_TXT_T cf_text_newsrc_path[] = "Full path and name of NEWSRC file";
+
++ #ifndef _WINDOWS
++ CONF_TXT_T cf_text_maildir_location[] = "Location relative to your HOME directory of the directory where your INBOX\n# for the maildir format is located. Default value is \"Maildir\". If your\n# inbox is located at \"~/Maildir\" you do not need to change this value.\n# A common value is also \".maildir\"";
++ #endif
+
+ /*----------------------------------------------------------------------
+ These are the variables that control a number of pine functions. They
+***************
+*** 517,522 ****
+--- 557,564 ----
+ NULL, cf_text_fcc_name_rule},
+ {"sort-key", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
+ NULL, cf_text_sort_key},
++ {"thread-sort-key", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
++ NULL, cf_text_thread_sort_key},
+ {"addrbook-sort-rule", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
+ "Address Book Sort Rule", cf_text_addrbook_sort_rule},
+ {"folder-sort-rule", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
+***************
+*** 539,544 ****
+--- 581,614 ----
+ NULL, cf_text_thread_exp_char},
+ {"threading-lastreply-character", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
+ "Threading Last Reply Character", cf_text_thread_lastreply_char},
++ {"threading-display-style-rule", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
++ "Threading Display Style Rule", cf_text_thread_displaystyle_rule},
++ {"threading-index-style-rule", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
++ "Threading Index Style Rule", cf_text_thread_indexstyle_rule},
++ {"compose-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
++ "Compose Rules", cf_text_compose_rules},
++ {"forward-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
++ "Forward Rules", cf_text_forward_rules},
++ {"index-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
++ "Index Rules", cf_text_index_rules},
++ {"key-definition-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
++ "Key Definition Rules", cf_text_key_def_rules},
++ {"replace-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
++ "Replace Rules", cf_text_replace_rules},
++ {"reply-indent-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
++ "Reply Indent Rules", cf_text_reply_indent_rules},
++ {"reply-leadin-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
++ "Reply Leadin Rules", cf_text_reply_leadin_rules},
++ {"reply-subject-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
++ "Reply Subject Rules", cf_text_reply_subject_rules},
++ {"save-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
++ "Save Rules", cf_text_save_rules},
++ {"smtp-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
++ "Smtp Rules", cf_text_smtp_rules},
++ {"sort-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
++ "Sort Rules", cf_text_sort_rules},
++ {"startup-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
++ "Startup Rules", cf_text_startup_rules},
+ #ifndef _WINDOWS
+ {"display-character-set", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
+ NULL, cf_text_disp_char_set},
+***************
+*** 557,562 ****
+--- 627,634 ----
+ NULL, cf_text_speller},
+ {"composer-wrap-column", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
+ NULL, cf_text_fillcol},
++ {"special-text-color", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
++ NULL, cf_special_text_color},
+ {"reply-indent-string", 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0,
+ NULL, cf_text_replystr},
+ {"reply-leadin", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
+***************
+*** 627,632 ****
+--- 699,708 ----
+ NULL, cf_text_news_active},
+ {"news-spool-directory", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
+ NULL, cf_text_news_spooldir},
++ #ifndef _WINDOWS
++ {"maildir-location", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
++ "Maildir Location", cf_text_maildir_location},
++ #endif
+ {"upload-command", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
+ NULL, cf_text_upload_cmd},
+ {"upload-command-prefix", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
+***************
+*** 788,793 ****
+--- 864,875 ----
+ {"title-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"title-closed-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"title-closed-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
++ {"folder-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
++ {"folder-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
++ {"directory-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
++ {"directory-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
++ {"folder-list-text-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
++ {"folder-list-text-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"status-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"status-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"keylabel-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+***************
+*** 808,813 ****
+--- 890,897 ----
+ {"incoming-unseen-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"signature-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"signature-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
++ {"special-text-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
++ {"special-text-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"prompt-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"prompt-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"header-general-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+***************
+*** 840,845 ****
+--- 924,931 ----
+ {"index-from-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"index-opening-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"index-opening-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
++ {"index-token-colors", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
++ NULL, cf_text_index_token_color},
+ {"viewer-hdr-colors", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
+ "Viewer Header Colors", cf_text_view_hdr_color},
+ {"keyword-colors", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
+***************
+*** 1555,1561 ****
+ register struct variable *vars = ps->vars;
+ int obs_header_in_reply = 0, /* the obs_ variables are to */
+ obs_old_style_reply = 0, /* support backwards compatibility */
+! obs_save_by_sender, i, def_sort_rev;
+ long rvl;
+ PINERC_S *fixedprc = NULL;
+ FeatureLevel obs_feature_level;
+--- 1641,1647 ----
+ register struct variable *vars = ps->vars;
+ int obs_header_in_reply = 0, /* the obs_ variables are to */
+ obs_old_style_reply = 0, /* support backwards compatibility */
+! obs_save_by_sender, i, def_sort_rev, thread_def_sort_rev;
+ long rvl;
+ PINERC_S *fixedprc = NULL;
+ FeatureLevel obs_feature_level;
+***************
+*** 1580,1585 ****
+--- 1666,1672 ----
+ GLO_FEATURE_LEVEL = cpystr("sappling");
+ GLO_OLD_STYLE_REPLY = cpystr(DF_OLD_STYLE_REPLY);
+ GLO_SORT_KEY = cpystr(DF_SORT_KEY);
++ GLO_THREAD_SORT_KEY = cpystr(DF_THREAD_SORT_KEY);
+ GLO_SAVED_MSG_NAME_RULE = cpystr(DF_SAVED_MSG_NAME_RULE);
+ GLO_FCC_RULE = cpystr(DF_FCC_RULE);
+ GLO_AB_SORT_RULE = cpystr(DF_AB_SORT_RULE);
+***************
+*** 1642,1647 ****
+--- 1729,1737 ----
+ GLO_TITLE_BACK_COLOR = cpystr(DEFAULT_TITLE_BACK_RGB);
+ GLO_TITLECLOSED_FORE_COLOR = cpystr(DEFAULT_TITLECLOSED_FORE_RGB);
+ GLO_TITLECLOSED_BACK_COLOR = cpystr(DEFAULT_TITLECLOSED_BACK_RGB);
++ GLO_FOLDER_FORE_COLOR = cpystr(DEFAULT_NORM_FORE_RGB);
++ GLO_DIRECTORY_FORE_COLOR = cpystr(DEFAULT_NORM_FORE_RGB);
++ GLO_FOLDER_LIST_FORE_COLOR = cpystr(DEFAULT_NORM_FORE_RGB);
+ GLO_METAMSG_FORE_COLOR = cpystr(DEFAULT_METAMSG_FORE_RGB);
+ GLO_METAMSG_BACK_COLOR = cpystr(DEFAULT_METAMSG_BACK_RGB);
+ GLO_QUOTE1_FORE_COLOR = cpystr(DEFAULT_QUOTE1_FORE_RGB);
+***************
+*** 1943,1948 ****
+--- 2033,2040 ----
+ set_current_val(&vars[V_FORM_FOLDER], TRUE, TRUE);
+ set_current_val(&vars[V_EDITOR], TRUE, TRUE);
+ set_current_val(&vars[V_SPELLER], TRUE, TRUE);
++ set_current_val(&vars[V_SPECIAL_TEXT], TRUE, TRUE);
++ regex_pattern(VAR_SPECIAL_TEXT);
+ set_current_val(&vars[V_IMAGE_VIEWER], TRUE, TRUE);
+ set_current_val(&vars[V_BROWSER], TRUE, TRUE);
+ set_current_val(&vars[V_SMTP_SERVER], TRUE, TRUE);
+***************
+*** 2216,2221 ****
+--- 2308,2319 ----
+ mail_parameters(NULL, SET_NEWSSPOOL,
+ (void *)VAR_NEWS_SPOOL_DIR);
+
++ #ifndef _WINDOWS
++ set_current_val(&vars[V_MAILDIR_LOCATION], TRUE, TRUE);
++ if(VAR_MAILDIR_LOCATION && VAR_MAILDIR_LOCATION[0])
++ mail_parameters(NULL, SET_MDINBOXPATH, (void *)VAR_MAILDIR_LOCATION);
++ #endif
++
+ /* guarantee a save default */
+ set_current_val(&vars[V_DEFAULT_SAVE_FOLDER], TRUE, TRUE);
+ if(!VAR_DEFAULT_SAVE_FOLDER || !VAR_DEFAULT_SAVE_FOLDER[0])
+***************
+*** 2446,2452 ****
+ set_current_val(&vars[V_ARCHIVED_FOLDERS], TRUE, TRUE);
+ set_current_val(&vars[V_INCOMING_FOLDERS], TRUE, TRUE);
+ set_current_val(&vars[V_SORT_KEY], TRUE, TRUE);
+! if(decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev) == -1){
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Sort type \"%.200s\" is invalid", VAR_SORT_KEY);
+ init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
+ ps->def_sort = SortArrival;
+--- 2544,2550 ----
+ set_current_val(&vars[V_ARCHIVED_FOLDERS], TRUE, TRUE);
+ set_current_val(&vars[V_INCOMING_FOLDERS], TRUE, TRUE);
+ set_current_val(&vars[V_SORT_KEY], TRUE, TRUE);
+! if(decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev,0) == -1){
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Sort type \"%.200s\" is invalid", VAR_SORT_KEY);
+ init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
+ ps->def_sort = SortArrival;
+***************
+*** 2455,2460 ****
+--- 2553,2569 ----
+ else
+ ps->def_sort_rev = def_sort_rev;
+
++ set_current_val(&vars[V_THREAD_SORT_KEY], TRUE, TRUE);
++ if(decode_sort(VAR_THREAD_SORT_KEY, &ps->thread_def_sort,
++ &thread_def_sort_rev, 1) == -1){
++ sprintf(tmp_20k_buf, "Sort type \"%s\" is invalid", VAR_THREAD_SORT_KEY);
++ init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
++ ps->thread_def_sort = SortThread;
++ ps->thread_def_sort_rev = 0;
++ }
++ else
++ ps->thread_def_sort_rev = thread_def_sort_rev;
++
+ cur_rule_value(&vars[V_SAVED_MSG_NAME_RULE], TRUE, TRUE);
+ {NAMEVAL_S *v; int i;
+ for(i = 0; (v = save_msg_rules(i)); i++)
+***************
+*** 2541,2546 ****
+--- 2650,2656 ----
+ if(cmds_f)
+ (*cmds_f)(ps, VAR_INIT_CMD_LIST);
+
++ (void)create_rule_list(ps_global->vars);
+ #ifdef _WINDOWS
+ mswin_set_quit_confirm (F_OFF(F_QUIT_WO_CONFIRM, ps_global));
+ #endif /* _WINDOWS */
+***************
+*** 2744,2749 ****
+--- 2854,2861 ----
+ F_ALWAYS_SPELL_CHECK, h_config_always_spell_check, PREF_COMP, 0},
+
+ /* Reply Prefs */
++ {"alternate-reply-menu", NULL,
++ F_ALT_REPLY_MENU, h_config_alt_reply_menu, PREF_RPLY, 0},
+ {"copy-to-address-to-from-if-it-is-us", "Copy To Address to From if it is Us",
+ F_COPY_TO_TO_FROM, h_config_copy_to_to_from, PREF_RPLY, 0},
+ {"enable-reply-indent-string-editing", NULL,
+***************
+*** 2762,2767 ****
+--- 2874,2881 ----
+ F_ENABLE_STRIP_SIGDASHES, h_config_strip_sigdashes, PREF_RPLY, 0},
+ {"forward-as-attachment", "Forward messages as attachments",
+ F_FORWARD_AS_ATTACHMENT, h_config_forward_as_attachment, PREF_RPLY, 0},
++ {"preserve-original-fields", NULL,
++ F_PRESERVE_ORIGINAL_FIELD, h_config_preserve_field, PREF_RPLY, 0},
+
+ /* Sending Prefs */
+ {"disable-sender", "Do Not Generate Sender Header",
+***************
+*** 2786,2791 ****
+--- 2900,2907 ----
+ F_NO_FCC_ATTACH, h_config_no_fcc_attach, PREF_SEND, 0},
+ {"fcc-on-bounce", "Include Fcc When Bouncing Messages",
+ F_FCC_ON_BOUNCE, h_config_fcc_on_bounce, PREF_SEND, 0},
++ {"return-path-uses-domain-name", NULL,
++ F_USE_DOMAIN_NAME, h_config_use_domain, PREF_SEND, 0},
+ {"mark-fcc-seen", NULL,
+ F_MARK_FCC_SEEN, h_config_mark_fcc_seen, PREF_SEND, 0},
+ {"fcc-only-without-confirm", "Send to Fcc Only Without Confirming",
+***************
+*** 2832,2837 ****
+--- 2948,2957 ----
+ F_SORT_DEFAULT_SAVE_ALPHA, h_config_sort_save_alpha, PREF_FLDR, 0},
+ {"vertical-folder-list", "Use Vertical Folder List",
+ F_VERTICAL_FOLDER_LIST, h_config_vertical_list, PREF_FLDR, 0},
++ #ifndef _WINDOWS
++ {"use-courier-folder-list", "Courier Style Folder List",
++ F_COURIER_FOLDER_LIST, h_config_courier_list, PREF_FLDR, 0},
++ #endif
+
+ /* Addr book */
+ {"combined-addrbook-display", "Combined Address Book Display",
+***************
+*** 2848,2853 ****
+--- 2968,2975 ----
+ /* Index prefs */
+ {"auto-open-next-unread", NULL,
+ F_AUTO_OPEN_NEXT_UNREAD, h_config_auto_open_unread, PREF_INDX, 0},
++ {"enable-circular-tab", NULL,
++ F_AUTO_CIRCULAR_TAB, h_config_circular_tab, PREF_INDX, 0},
+ {"continue-tab-without-confirm", "Continue NextNew Without Confirming",
+ F_TAB_NO_CONFIRM, h_config_tab_no_prompt, PREF_INDX, 0},
+ {"convert-dates-to-localtime", NULL,
+***************
+*** 2876,2881 ****
+--- 2998,3005 ----
+ F_COLOR_LINE_IMPORTANT, h_config_color_thrd_import, PREF_INDX, 0},
+ {"thread-sorts-by-arrival", "Thread Sorts by Arrival",
+ F_THREAD_SORTS_BY_ARRIVAL, h_config_thread_sorts_by_arrival, PREF_INDX, 0},
++ {"enhanced-fancy-thread-support", "Enhanced Fancy Thread Support",
++ F_ENHANCED_THREAD, h_config_enhanced_thread, PREF_INDX, 0},
+
+ /* Viewer prefs */
+ {"enable-msg-view-addresses", "Enable Message View Address Links",
+***************
+*** 2886,2891 ****
+--- 3010,3017 ----
+ F_VIEW_SEL_URL, h_config_enable_view_url, PREF_VIEW, 1},
+ {"enable-msg-view-web-hostnames", "Enable Message View Web Hostname Links",
+ F_VIEW_SEL_URL_HOST, h_config_enable_view_web_host, PREF_VIEW, 1},
++ {"enable-msg-view-long-url", "Enable Recognition of Long URLS without Delimiter",
++ F_VIEW_LONG_URL, h_config_enable_long_url, PREF_VIEW, 0},
+ {"enable-msg-view-forced-arrows", "Enable Message View Forced Arrows",
+ F_FORCE_ARROWS, h_config_enable_view_arrows, PREF_VIEW, 0},
+ /* set to TRUE for windows */
+***************
+*** 2983,2988 ****
+--- 3109,3116 ----
+ F_FORCE_LOW_SPEED, h_config_force_low_speed, PREF_OS_LWSD, 0},
+ {"auto-move-read-msgs", "Auto Move Read Messages",
+ F_AUTO_READ_MSGS, h_config_auto_read_msgs, PREF_MISC, 0},
++ {"auto-move-read-msgs-using-rules", "Auto Move Read Messages Using Rules",
++ F_AUTO_READ_MSGS_RULES, h_config_auto_read_msgs_rules, PREF_MISC, 0},
+ {"auto-unselect-after-apply", NULL,
+ F_AUTO_UNSELECT, h_config_auto_unselect, PREF_MISC, 0},
+ {"auto-unzoom-after-apply", NULL,
+***************
+*** 3044,3049 ****
+--- 3172,3179 ----
+ F_FULL_AUTO_EXPUNGE, h_config_full_auto_expunge, PREF_MISC, 0},
+ {"force-arrow-cursor", NULL,
+ F_FORCE_ARROW, h_config_force_arrow, PREF_MISC, 0},
++ {"ignore-size-changes", NULL,
++ F_IGNORE_SIZE, h_config_ignore_size, PREF_MISC, 0},
+ {"maildrops-preserve-state", NULL,
+ F_MAILDROPS_PRESERVE_STATE, h_config_maildrops_preserve_state,
+ PREF_MISC, 0},
+***************
+*** 3179,3184 ****
+--- 3309,3316 ----
+ F_DISABLE_SHARED_NAMESPACES, h_config_disable_shared, PREF_HIDDEN, 0},
+ {"disable-signature-edit-cmd", NULL,
+ F_DISABLE_SIGEDIT_CMD, h_config_disable_signature_edit, PREF_HIDDEN, 0},
++ {"new-thread-on-blank-subject", "New Thread on Blank Subject",
++ F_NEW_THREAD_ON_BLANK_SUBJECT, h_config_new_thread_blank_subject, PREF_HIDDEN, 1},
+ {"quell-personal-name-prompt", NULL,
+ F_QUELL_PERSONAL_NAME_PROMPT, h_config_quell_personal_name_prompt, PREF_HIDDEN, 0},
+ {"quell-user-id-prompt", "Quell User ID Prompt",
+***************
+*** 4734,4750 ****
+ but also after each : in the path.
+
+ ----*/
+
+ char *
+ expand_variables(char *lineout, size_t lineoutlen, char *linein, int colon_path)
+ {
+ char *src = linein, *dest = lineout, *p;
+ char *limit = lineout + lineoutlen;
+! int envexpand = 0;
+
+ if(!linein)
+ return(NULL);
+
+ while(*src ){ /* something in input string */
+ if(*src == '$' && *(src+1) == '$'){
+ /*
+--- 4866,4887 ----
+ but also after each : in the path.
+
+ ----*/
++ #define is_allowed_envchar(C, S) ((S) == 0 ? !isspace((C)) \
++ : (((C) >= 'a' && (C) <= 'z') \
++ || ((C) >= 'A' && (C) <= 'Z') \
++ || ((C) >= '0' && (C) <= '9')))
+
+ char *
+ expand_variables(char *lineout, size_t lineoutlen, char *linein, int colon_path)
+ {
+ char *src = linein, *dest = lineout, *p;
+ char *limit = lineout + lineoutlen;
+! int envexpand = 0, sp;
+
+ if(!linein)
+ return(NULL);
+
++ sp = strncmp(src,"LIT:pattern=\"/NICK=", strlen("LIT:pattern=\"/NICK=")) == 0;
+ while(*src ){ /* something in input string */
+ if(*src == '$' && *(src+1) == '$'){
+ /*
+***************
+*** 4825,4831 ****
+ src = rbrace + 1;
+ }
+ else{
+! while(*src && !isspace((unsigned char) *src)
+ && (p-word < sizeof(word)-1))
+ *p++ = *src++;
+ }
+--- 4962,4968 ----
+ src = rbrace + 1;
+ }
+ else{
+! while(*src && is_allowed_envchar((unsigned char) *src, sp)
+ && (p-word < sizeof(word)-1))
+ *p++ = *src++;
+ }
+***************
+*** 6356,6361 ****
+--- 6493,6501 ----
+
+ set_color_val(&vars[V_TITLE_FORE_COLOR], 1);
+ set_color_val(&vars[V_TITLECLOSED_FORE_COLOR], 0);
++ set_color_val(&vars[V_FOLDER_FORE_COLOR], 0);
++ set_color_val(&vars[V_DIRECTORY_FORE_COLOR], 0);
++ set_color_val(&vars[V_FOLDER_LIST_FORE_COLOR], 0);
+ set_color_val(&vars[V_STATUS_FORE_COLOR], 1);
+ set_color_val(&vars[V_KEYLABEL_FORE_COLOR], 1);
+ set_color_val(&vars[V_KEYNAME_FORE_COLOR], 1);
+***************
+*** 6379,6385 ****
+--- 6519,6527 ----
+ set_color_val(&vars[V_IND_OP_FORE_COLOR], 0);
+ set_color_val(&vars[V_INCUNSEEN_FORE_COLOR], 0);
+ set_color_val(&vars[V_SIGNATURE_FORE_COLOR], 0);
++ set_color_val(&vars[V_SPECIAL_TEXT_FORE_COLOR], 0);
+
++ set_current_val(&ps->vars[V_INDEX_TOKEN_COLORS], TRUE, TRUE);
+ set_current_val(&ps->vars[V_VIEW_HDR_COLORS], TRUE, TRUE);
+ set_current_val(&ps->vars[V_KW_COLORS], TRUE, TRUE);
+ set_custom_spec_colors(ps);
+***************
+*** 6532,6537 ****
+--- 6674,6684 ----
+ void
+ set_custom_spec_colors(struct pine *ps)
+ {
++ if(ps->index_token_colors)
++ free_spec_colors(&ps->index_token_colors);
++
++ ps->index_token_colors = spec_colors_from_varlist(ps->VAR_INDEX_TOKEN_COLORS, 1);
++
+ if(ps->hdr_colors)
+ free_spec_colors(&ps->hdr_colors);
+
+***************
+*** 6895,6900 ****
+--- 7042,7053 ----
+
+ break;
+
++ #ifndef _WINDOWS
++ case F_COURIER_FOLDER_LIST:
++ mail_parameters(NULL,SET_COURIERSTYLE,(void *)(F_ON(f->id ,ps)? 1 : 0));
++ break; /* COURIER == 1, CCLIENT == 0, see maildir.h */
++ #endif
++
+ case F_COLOR_LINE_IMPORTANT :
+ case F_DATES_TO_LOCAL :
+ clear_index_cache(ps->mail_stream, 0);
+***************
+*** 7500,7509 ****
+--- 7653,7692 ----
+ return(h_config_fcc_rule);
+ case V_SORT_KEY :
+ return(h_config_sort_key);
++ case V_THREAD_SORT_KEY :
++ return(h_config_thread_sort_key);
+ case V_AB_SORT_RULE :
+ return(h_config_ab_sort_rule);
+ case V_FLD_SORT_RULE :
+ return(h_config_fld_sort_rule);
++ case V_THREAD_DISP_STYLE_RULES:
++ return(h_config_thread_display_style_rule);
++ case V_THREAD_INDEX_STYLE_RULES:
++ return(h_config_thread_index_style_rule);
++ case V_COMPOSE_RULES:
++ return(h_config_compose_rules);
++ case V_FORWARD_RULES:
++ return(h_config_forward_rules);
++ case V_INDEX_RULES:
++ return(h_config_index_rules);
++ case V_KEY_RULES:
++ return(h_config_key_macro_rules);
++ case V_REPLACE_RULES:
++ return(h_config_replace_rules);
++ case V_REPLY_INDENT_RULES:
++ return(h_config_reply_indent_rules);
++ case V_REPLY_LEADIN_RULES:
++ return(h_config_reply_leadin_rules);
++ case V_RESUB_RULES:
++ return(h_config_resub_rules);
++ case V_SAVE_RULES:
++ return(h_config_save_rules);
++ case V_SMTP_RULES:
++ return(h_config_smtp_rules);
++ case V_SORT_RULES:
++ return(h_config_sort_rules);
++ case V_STARTUP_RULES:
++ return(h_config_startup_rules);
+ case V_POST_CHAR_SET :
+ return(h_config_post_char_set);
+ case V_UNK_CHAR_SET :
+***************
+*** 7554,7559 ****
+--- 7737,7744 ----
+ return(h_config_scroll_margin);
+ case V_DEADLETS :
+ return(h_config_deadlets);
++ case V_SPECIAL_TEXT :
++ return(h_config_special_text_to_color);
+ case V_FILLCOL :
+ return(h_config_composer_wrap_column);
+ case V_TCPOPENTIMEO :
+***************
+*** 7676,7681 ****
+--- 7861,7870 ----
+ return(h_config_newmailwidth);
+ case V_NEWSRC_PATH :
+ return(h_config_newsrc_path);
++ #ifndef _WINDOWS
++ case V_MAILDIR_LOCATION :
++ return(h_config_maildir_location);
++ #endif
+ case V_BROWSER :
+ return(h_config_browser);
+ #if defined(DOS) || defined(OS2)
+***************
+*** 7694,7699 ****
+--- 7883,7894 ----
+ case V_TITLECLOSED_FORE_COLOR :
+ case V_TITLECLOSED_BACK_COLOR :
+ return(h_config_titleclosed_color);
++ case V_FOLDER_FORE_COLOR:
++ return(h_config_folder_color);
++ case V_DIRECTORY_FORE_COLOR:
++ return(h_config_directory_color);
++ case V_FOLDER_LIST_FORE_COLOR:
++ return(h_config_folder_list_color);
+ case V_STATUS_FORE_COLOR :
+ case V_STATUS_BACK_COLOR :
+ return(h_config_status_color);
+***************
+*** 7713,7718 ****
+--- 7908,7916 ----
+ case V_SIGNATURE_FORE_COLOR :
+ case V_SIGNATURE_BACK_COLOR :
+ return(h_config_signature_color);
++ case V_SPECIAL_TEXT_FORE_COLOR :
++ case V_SPECIAL_TEXT_BACK_COLOR :
++ return(h_config_special_text_color);
+ case V_PROMPT_FORE_COLOR :
+ case V_PROMPT_BACK_COLOR :
+ return(h_config_prompt_color);
+***************
+*** 7764,7769 ****
+--- 7962,7969 ----
+ return(h_config_metamsg_color);
+ case V_VIEW_HDR_COLORS :
+ return(h_config_customhdr_color);
++ case V_INDEX_TOKEN_COLORS :
++ return(h_config_indextoken_color);
+ case V_PRINTER :
+ return(h_config_printer);
+ case V_PERSONAL_PRINT_CATEGORY :
+***************
+*** 8194,8196 ****
+--- 8394,8397 ----
+ }
+
+ #endif /* _WINDOWS */
++
+diff -rc alpine-2.00/pith/conf.h alpine-2.00.I.USE/pith/conf.h
+*** alpine-2.00/pith/conf.h 2008-08-19 17:27:11.000000000 -0700
+--- alpine-2.00.I.USE/pith/conf.h 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 143,152 ****
+--- 143,195 ----
+ #define VAR_SORT_KEY vars[V_SORT_KEY].current_val.p
+ #define GLO_SORT_KEY vars[V_SORT_KEY].global_val.p
+ #define COM_SORT_KEY vars[V_SORT_KEY].cmdline_val.p
++ #define VAR_THREAD_SORT_KEY vars[V_THREAD_SORT_KEY].current_val.p
++ #define GLO_THREAD_SORT_KEY vars[V_THREAD_SORT_KEY].global_val.p
++ #define COM_THREAD_SORT_KEY vars[V_THREAD_SORT_KEY].cmdline_val.p
+ #define VAR_AB_SORT_RULE vars[V_AB_SORT_RULE].current_val.p
+ #define GLO_AB_SORT_RULE vars[V_AB_SORT_RULE].global_val.p
+ #define VAR_FLD_SORT_RULE vars[V_FLD_SORT_RULE].current_val.p
+ #define GLO_FLD_SORT_RULE vars[V_FLD_SORT_RULE].global_val.p
++ #define VAR_COMPOSE_RULES vars[V_COMPOSE_RULES].current_val.l
++ #define GLO_COMPOSE_RULES vars[V_COMPOSE_RULES].global_val.l
++ #define USR_COMPOSE_RULES vars[V_COMPOSE_RULES].user_val.l
++ #define VAR_FORWARD_RULES vars[V_FORWARD_RULES].current_val.l
++ #define GLO_FORWARD_RULES vars[V_FORWARD_RULES].global_val.l
++ #define USR_FORWARD_RULES vars[V_FORWARD_RULES].user_val.l
++ #define VAR_INDEX_RULES vars[V_INDEX_RULES].current_val.l
++ #define GLO_INDEX_RULES vars[V_INDEX_RULES].global_val.l
++ #define USR_INDEX_RULES vars[V_INDEX_RULES].user_val.l
++ #define VAR_KEY_RULES vars[V_KEY_RULES].current_val.l
++ #define GLO_KEY_RULES vars[V_KEY_RULES].global_val.l
++ #define USR_KEY_RULES vars[V_KEY_RULES].user_val.l
++ #define VAR_REPLACE_RULES vars[V_REPLACE_RULES].current_val.l
++ #define GLO_REPLACE_RULES vars[V_REPLACE_RULES].global_val.l
++ #define USR_REPLACE_RULES vars[V_REPLACE_RULES].user_val.l
++ #define VAR_REPLY_INDENT_RULES vars[V_REPLY_INDENT_RULES].current_val.l
++ #define GLO_REPLY_INDENT_RULES vars[V_REPLY_INDENT_RULES].global_val.l
++ #define USR_REPLY_INDENT_RULES vars[V_REPLY_INDENT_RULES].user_val.l
++ #define VAR_REPLY_LEADIN_RULES vars[V_REPLY_LEADIN_RULES].current_val.l
++ #define GLO_REPLY_LEADIN_RULES vars[V_REPLY_LEADIN_RULES].global_val.l
++ #define USR_REPLY_LEADIN_RULES vars[V_REPLY_LEADIN_RULES].user_val.l
++ #define VAR_RESUB_RULES vars[V_RESUB_RULES].current_val.l
++ #define GLO_RESUB_RULES vars[V_RESUB_RULES].global_val.l
++ #define USR_RESUB_RULES vars[V_RESUB_RULES].user_val.l
++ #define VAR_THREAD_DISP_STYLE_RULES vars[V_THREAD_DISP_STYLE_RULES].current_val.l
++ #define GLO_THREAD_DISP_STYLE_RULES vars[V_THREAD_DISP_STYLE_RULES].global_val.l
++ #define VAR_THREAD_INDEX_STYLE_RULES vars[V_THREAD_INDEX_STYLE_RULES].current_val.l
++ #define GLO_THREAD_INDEX_STYLE_RULES vars[V_THREAD_INDEX_STYLE_RULES].global_val.l
++ #define VAR_SAVE_RULES vars[V_SAVE_RULES].current_val.l
++ #define GLO_SAVE_RULES vars[V_SAVE_RULES].global_val.l
++ #define USR_SAVE_RULES vars[V_SAVE_RULES].user_val.l
++ #define VAR_SMTP_RULES vars[V_SMTP_RULES].current_val.l
++ #define GLO_SMTP_RULES vars[V_SMTP_RULES].global_val.l
++ #define USR_SMTP_RULES vars[V_SMTP_RULES].user_val.l
++ #define VAR_SORT_RULES vars[V_SORT_RULES].current_val.l
++ #define GLO_SORT_RULES vars[V_SORT_RULES].global_val.l
++ #define USR_SORT_RULES vars[V_SORT_RULES].user_val.l
++ #define VAR_STARTUP_RULES vars[V_STARTUP_RULES].current_val.l
++ #define GLO_STARTUP_RULES vars[V_STARTUP_RULES].global_val.l
++ #define USR_STARTUP_RULES vars[V_STARTUP_RULES].user_val.l
+ #ifndef _WINDOWS
+ #define VAR_CHAR_SET vars[V_CHAR_SET].current_val.p
+ #define GLO_CHAR_SET vars[V_CHAR_SET].global_val.p
+***************
+*** 160,165 ****
+--- 203,210 ----
+ #define GLO_EDITOR vars[V_EDITOR].global_val.l
+ #define VAR_SPELLER vars[V_SPELLER].current_val.p
+ #define GLO_SPELLER vars[V_SPELLER].global_val.p
++ #define VAR_SPECIAL_TEXT vars[V_SPECIAL_TEXT].current_val.l
++ #define GLO_SPECIAL_TEXT vars[V_SPECIAL_TEXT].global_val.l
+ #define VAR_FILLCOL vars[V_FILLCOL].current_val.p
+ #define GLO_FILLCOL vars[V_FILLCOL].global_val.p
+ #define VAR_DEADLETS vars[V_DEADLETS].current_val.p
+***************
+*** 249,254 ****
+--- 294,303 ----
+ #define GLO_NEWS_ACTIVE_PATH vars[V_NEWS_ACTIVE_PATH].global_val.p
+ #define VAR_NEWS_SPOOL_DIR vars[V_NEWS_SPOOL_DIR].current_val.p
+ #define GLO_NEWS_SPOOL_DIR vars[V_NEWS_SPOOL_DIR].global_val.p
++ #ifndef _WINDOWS
++ #define VAR_MAILDIR_LOCATION vars[V_MAILDIR_LOCATION].current_val.p
++ #define GLO_MAILDIR_LOCATION vars[V_MAILDIR_LOCATION].global_val.p
++ #endif
+ #define VAR_DISABLE_DRIVERS vars[V_DISABLE_DRIVERS].current_val.l
+ #define VAR_DISABLE_AUTHS vars[V_DISABLE_AUTHS].current_val.l
+ #define VAR_REMOTE_ABOOK_METADATA vars[V_REMOTE_ABOOK_METADATA].current_val.p
+***************
+*** 373,378 ****
+--- 422,439 ----
+ #define GLO_TITLECLOSED_FORE_COLOR vars[V_TITLECLOSED_FORE_COLOR].global_val.p
+ #define VAR_TITLECLOSED_BACK_COLOR vars[V_TITLECLOSED_BACK_COLOR].current_val.p
+ #define GLO_TITLECLOSED_BACK_COLOR vars[V_TITLECLOSED_BACK_COLOR].global_val.p
++ #define VAR_FOLDER_FORE_COLOR vars[V_FOLDER_FORE_COLOR].current_val.p
++ #define GLO_FOLDER_FORE_COLOR vars[V_FOLDER_FORE_COLOR].global_val.p
++ #define VAR_FOLDER_BACK_COLOR vars[V_FOLDER_BACK_COLOR].current_val.p
++ #define GLO_FOLDER_BACK_COLOR vars[V_FOLDER_BACK_COLOR].global_val.p
++ #define VAR_DIRECTORY_FORE_COLOR vars[V_DIRECTORY_FORE_COLOR].current_val.p
++ #define GLO_DIRECTORY_FORE_COLOR vars[V_DIRECTORY_FORE_COLOR].global_val.p
++ #define VAR_DIRECTORY_BACK_COLOR vars[V_DIRECTORY_BACK_COLOR].current_val.p
++ #define GLO_DIRECTORY_BACK_COLOR vars[V_DIRECTORY_BACK_COLOR].global_val.p
++ #define VAR_FOLDER_LIST_FORE_COLOR vars[V_FOLDER_LIST_FORE_COLOR].current_val.p
++ #define GLO_FOLDER_LIST_FORE_COLOR vars[V_FOLDER_LIST_FORE_COLOR].global_val.p
++ #define VAR_FOLDER_LIST_BACK_COLOR vars[V_FOLDER_LIST_BACK_COLOR].current_val.p
++ #define GLO_FOLDER_LIST_BACK_COLOR vars[V_FOLDER_LIST_BACK_COLOR].global_val.p
+ #define VAR_STATUS_FORE_COLOR vars[V_STATUS_FORE_COLOR].current_val.p
+ #define VAR_STATUS_BACK_COLOR vars[V_STATUS_BACK_COLOR].current_val.p
+ #define VAR_HEADER_GENERAL_FORE_COLOR vars[V_HEADER_GENERAL_FORE_COLOR].current_val.p
+***************
+*** 443,451 ****
+--- 504,515 ----
+ #define GLO_SIGNATURE_FORE_COLOR vars[V_SIGNATURE_FORE_COLOR].global_val.p
+ #define VAR_SIGNATURE_BACK_COLOR vars[V_SIGNATURE_BACK_COLOR].current_val.p
+ #define GLO_SIGNATURE_BACK_COLOR vars[V_SIGNATURE_BACK_COLOR].global_val.p
++ #define VAR_SPECIAL_TEXT_FORE_COLOR vars[V_SPECIAL_TEXT_FORE_COLOR].current_val.p
++ #define VAR_SPECIAL_TEXT_BACK_COLOR vars[V_SPECIAL_TEXT_BACK_COLOR].current_val.p
+ #define VAR_PROMPT_FORE_COLOR vars[V_PROMPT_FORE_COLOR].current_val.p
+ #define VAR_PROMPT_BACK_COLOR vars[V_PROMPT_BACK_COLOR].current_val.p
+ #define VAR_VIEW_HDR_COLORS vars[V_VIEW_HDR_COLORS].current_val.l
++ #define VAR_INDEX_TOKEN_COLORS vars[V_INDEX_TOKEN_COLORS].current_val.l
+ #ifdef SMIME
+ #define VAR_PUBLICCERT_DIR vars[V_PUBLICCERT_DIR].current_val.p
+ #define GLO_PUBLICCERT_DIR vars[V_PUBLICCERT_DIR].global_val.p
+diff -rc alpine-2.00/pith/conftype.h alpine-2.00.I.USE/pith/conftype.h
+*** alpine-2.00/pith/conftype.h 2008-08-19 17:27:11.000000000 -0700
+--- alpine-2.00.I.USE/pith/conftype.h 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 58,63 ****
+--- 58,64 ----
+ , V_SAVED_MSG_NAME_RULE
+ , V_FCC_RULE
+ , V_SORT_KEY
++ , V_THREAD_SORT_KEY
+ , V_AB_SORT_RULE
+ , V_FLD_SORT_RULE
+ , V_GOTO_DEFAULT_RULE
+***************
+*** 69,74 ****
+--- 70,89 ----
+ , V_THREAD_MORE_CHAR
+ , V_THREAD_EXP_CHAR
+ , V_THREAD_LASTREPLY_CHAR
++ , V_THREAD_DISP_STYLE_RULES
++ , V_THREAD_INDEX_STYLE_RULES
++ , V_COMPOSE_RULES
++ , V_FORWARD_RULES
++ , V_INDEX_RULES
++ , V_KEY_RULES
++ , V_REPLACE_RULES
++ , V_REPLY_INDENT_RULES
++ , V_REPLY_LEADIN_RULES
++ , V_RESUB_RULES
++ , V_SAVE_RULES
++ , V_SMTP_RULES
++ , V_SORT_RULES
++ , V_STARTUP_RULES
+ #ifndef _WINDOWS
+ , V_CHAR_SET
+ , V_OLD_CHAR_SET
+***************
+*** 79,84 ****
+--- 94,100 ----
+ , V_EDITOR
+ , V_SPELLER
+ , V_FILLCOL
++ , V_SPECIAL_TEXT
+ , V_REPLY_STRING
+ , V_REPLY_INTRO
+ , V_QUOTE_REPLACE_STRING
+***************
+*** 114,119 ****
+--- 130,138 ----
+ , V_NEWSRC_PATH
+ , V_NEWS_ACTIVE_PATH
+ , V_NEWS_SPOOL_DIR
++ #ifndef _WINDOWS
++ , V_MAILDIR_LOCATION
++ #endif
+ , V_UPLOAD_CMD
+ , V_UPLOAD_CMD_PREFIX
+ , V_DOWNLOAD_CMD
+***************
+*** 203,208 ****
+--- 222,233 ----
+ , V_TITLE_BACK_COLOR
+ , V_TITLECLOSED_FORE_COLOR
+ , V_TITLECLOSED_BACK_COLOR
++ , V_FOLDER_FORE_COLOR
++ , V_FOLDER_BACK_COLOR
++ , V_DIRECTORY_FORE_COLOR
++ , V_DIRECTORY_BACK_COLOR
++ , V_FOLDER_LIST_FORE_COLOR
++ , V_FOLDER_LIST_BACK_COLOR
+ , V_STATUS_FORE_COLOR
+ , V_STATUS_BACK_COLOR
+ , V_KEYLABEL_FORE_COLOR
+***************
+*** 223,228 ****
+--- 248,255 ----
+ , V_INCUNSEEN_BACK_COLOR
+ , V_SIGNATURE_FORE_COLOR
+ , V_SIGNATURE_BACK_COLOR
++ , V_SPECIAL_TEXT_FORE_COLOR
++ , V_SPECIAL_TEXT_BACK_COLOR
+ , V_PROMPT_FORE_COLOR
+ , V_PROMPT_BACK_COLOR
+ , V_HEADER_GENERAL_FORE_COLOR
+***************
+*** 255,260 ****
+--- 282,288 ----
+ , V_IND_FROM_BACK_COLOR
+ , V_IND_OP_FORE_COLOR
+ , V_IND_OP_BACK_COLOR
++ , V_INDEX_TOKEN_COLORS
+ , V_VIEW_HDR_COLORS
+ , V_KW_COLORS
+ #if defined(DOS) || defined(OS2)
+***************
+*** 319,324 ****
+--- 347,353 ----
+ F_FULL_AUTO_EXPUNGE,
+ F_EXPUNGE_MANUALLY,
+ F_AUTO_READ_MSGS,
++ F_AUTO_READ_MSGS_RULES,
+ F_AUTO_FCC_ONLY,
+ F_READ_IN_NEWSRC_ORDER,
+ F_SELECT_WO_CONFIRM,
+***************
+*** 334,342 ****
+--- 363,373 ----
+ F_FORCE_ARROW,
+ F_PRUNE_USES_ISO,
+ F_ALT_ED_NOW,
++ F_IGNORE_SIZE,
+ F_SHOW_DELAY_CUE,
+ F_CANCEL_CONFIRM,
+ F_AUTO_OPEN_NEXT_UNREAD,
++ F_AUTO_CIRCULAR_TAB,
+ F_DISABLE_INDEX_LOCALE_DATES,
+ F_SELECTED_SHOWN_BOLD,
+ F_QUOTE_ALL_FROMS,
+***************
+*** 380,389 ****
+--- 411,424 ----
+ F_PASS_C1_CONTROL_CHARS,
+ F_SINGLE_FOLDER_LIST,
+ F_VERTICAL_FOLDER_LIST,
++ #ifndef _WINDOWS
++ F_COURIER_FOLDER_LIST,
++ #endif
+ F_TAB_CHK_RECENT,
+ F_AUTO_REPLY_TO,
+ F_VERBOSE_POST,
+ F_FCC_ON_BOUNCE,
++ F_USE_DOMAIN_NAME,
+ F_SEND_WO_CONFIRM,
+ F_USE_SENDER_NOT_X,
+ F_BLANK_KEYMENU,
+***************
+*** 428,439 ****
+--- 463,476 ----
+ F_TCAP_WINS,
+ F_ENABLE_SIGDASHES,
+ F_ENABLE_STRIP_SIGDASHES,
++ F_NEW_THREAD_ON_BLANK_SUBJECT,
+ F_QUELL_PARTIAL_FETCH,
+ F_QUELL_PERSONAL_NAME_PROMPT,
+ F_QUELL_USER_ID_PROMPT,
+ F_VIEW_SEL_ATTACH,
+ F_VIEW_SEL_URL,
+ F_VIEW_SEL_URL_HOST,
++ F_VIEW_LONG_URL,
+ F_SCAN_ADDR,
+ F_FORCE_ARROWS,
+ F_PREFER_PLAIN_TEXT,
+***************
+*** 492,502 ****
+--- 529,541 ----
+ F_MAILDROPS_PRESERVE_STATE,
+ F_EXPOSE_HIDDEN_CONFIG,
+ F_ALT_COMPOSE_MENU,
++ F_ALT_REPLY_MENU,
+ F_ALT_ROLE_MENU,
+ F_ALWAYS_SPELL_CHECK,
+ F_QUELL_TIMEZONE,
+ F_QUELL_USERAGENT,
+ F_COLOR_LINE_IMPORTANT,
++ F_ENHANCED_THREAD,
+ F_SLASH_COLL_ENTIRE,
+ F_ENABLE_FULL_HDR_AND_TEXT,
+ F_QUELL_FULL_HDR_RESET,
+***************
+*** 514,519 ****
+--- 553,559 ----
+ F_RENDER_HTML_INTERNALLY,
+ F_ENABLE_JUMP_CMD,
+ F_FORWARD_AS_ATTACHMENT,
++ F_PRESERVE_ORIGINAL_FIELD,
+ #ifndef _WINDOWS
+ F_USE_SYSTEM_TRANS,
+ #endif /* ! _WINDOWS */
+***************
+*** 703,707 ****
+--- 743,748 ----
+
+ /* exported protoypes */
+
++ #define DF_THREAD_SORT_KEY "thread"
+
+ #endif /* PITH_CONFTYPE_INCLUDED */
+diff -rc alpine-2.00/pith/detoken.c alpine-2.00.I.USE/pith/detoken.c
+*** alpine-2.00/pith/detoken.c 2007-08-14 12:02:07.000000000 -0700
+--- alpine-2.00.I.USE/pith/detoken.c 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 24,30 ****
+ #include "../pith/reply.h"
+ #include "../pith/mailindx.h"
+ #include "../pith/options.h"
+!
+
+ /*
+ * Hook to read signature from local file
+--- 24,30 ----
+ #include "../pith/reply.h"
+ #include "../pith/mailindx.h"
+ #include "../pith/options.h"
+! #include "../pith/rules.h"
+
+ /*
+ * Hook to read signature from local file
+***************
+*** 90,95 ****
+--- 90,97 ----
+
+ if(is_sig){
+ /*
++ * First we check if there is a rule about signatures, if there is
++ * use it, otherwise keep going and do the following:
+ * If role->litsig is set, we use it;
+ * Else, if VAR_LITERAL_SIG is set, we use that;
+ * Else, if role->sig is set, we use that;
+***************
+*** 103,116 ****
+ * there is no reason to mix them, so we don't provide support to
+ * do so.
+ */
+! if(role && role->litsig)
+! literal_sig = role->litsig;
+! else if(ps_global->VAR_LITERAL_SIG)
+! literal_sig = ps_global->VAR_LITERAL_SIG;
+! else if(role && role->sig)
+! sigfile = role->sig;
+! else
+! sigfile = ps_global->VAR_SIGNATURE_FILE;
+ }
+ else if(role && role->template)
+ sigfile = role->template;
+--- 105,129 ----
+ * there is no reason to mix them, so we don't provide support to
+ * do so.
+ */
+! { RULE_RESULT *rule;
+! rule = get_result_rule(V_COMPOSE_RULES, FOR_COMPOSE, env);
+! if (rule){
+! sigfile = cpystr(rule->result);
+! if (rule->result)
+! fs_give((void **)&rule->result);
+! fs_give((void **)&rule);
+! }
+! }
+! if (!sigfile){
+! if(role && role->litsig)
+! literal_sig = role->litsig;
+! else if(ps_global->VAR_LITERAL_SIG)
+! literal_sig = ps_global->VAR_LITERAL_SIG;
+! else if(role && role->sig)
+! sigfile = role->sig;
+! else
+! sigfile = ps_global->VAR_SIGNATURE_FILE;
+! }
+ }
+ else if(role && role->template)
+ sigfile = role->template;
+***************
+*** 301,307 ****
+ }
+ }
+ }
+! else if(pt->what_for & FOR_REPLY_INTRO)
+ repl = get_reply_data(env, role, pt->ctype,
+ subbuf, sizeof(subbuf)-1);
+
+--- 314,320 ----
+ }
+ }
+ }
+! else if(pt->what_for & (FOR_REPLY_INTRO | FOR_RULE))
+ repl = get_reply_data(env, role, pt->ctype,
+ subbuf, sizeof(subbuf)-1);
+
+diff -rc alpine-2.00/pith/filter.c alpine-2.00.I.USE/pith/filter.c
+*** alpine-2.00/pith/filter.c 2008-08-21 16:50:47.000000000 -0700
+--- alpine-2.00.I.USE/pith/filter.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 45,50 ****
+--- 45,51 ----
+ #include "../pith/conf.h"
+ #include "../pith/store.h"
+ #include "../pith/color.h"
++ #include "../pith/osdep/color.h"
+ #include "../pith/escapes.h"
+ #include "../pith/pipe.h"
+ #include "../pith/status.h"
+***************
+*** 1020,1026 ****
+ */
+ char *
+ gf_filter(char *cmd, char *prepend, STORE_S *source_so, gf_io_t pc,
+! FILTLIST_S *aux_filters, int disable_reset,
+ void (*pipecb_f)(PIPE_S *, int, void *))
+ {
+ unsigned char c, obuf[MAX(MB_LEN_MAX,32)];
+--- 1021,1027 ----
+ */
+ char *
+ gf_filter(char *cmd, char *prepend, STORE_S *source_so, gf_io_t pc,
+! FILTLIST_S *aux_filters, int silent, int disable_reset,
+ void (*pipecb_f)(PIPE_S *, int, void *))
+ {
+ unsigned char c, obuf[MAX(MB_LEN_MAX,32)];
+***************
+*** 1057,1064 ****
+ * Spawn filter feeding it data, and reading what it writes.
+ */
+ so_seek(source_so, 0L, 0);
+! flags = PIPE_WRITE | PIPE_READ | PIPE_NOSHELL |
+! (!disable_reset ? PIPE_RESET : 0);
+
+ if((fpipe = open_system_pipe(cmd, NULL, NULL, flags, 0, pipecb_f, pipe_report_error)) != NULL){
+
+--- 1058,1066 ----
+ * Spawn filter feeding it data, and reading what it writes.
+ */
+ so_seek(source_so, 0L, 0);
+! flags = PIPE_WRITE | PIPE_READ | PIPE_NOSHELL
+! | (silent ? PIPE_SILENT : 0)
+! | (!disable_reset ? PIPE_RESET : 0);
+
+ if((fpipe = open_system_pipe(cmd, NULL, NULL, flags, 0, pipecb_f, pipe_report_error)) != NULL){
+
+***************
+*** 1373,1386 ****
+ register unsigned char t = f->t;
+ register int n = (int) f->n;
+ register int state = f->f1;
+
+ while(GF_GETC(f, c)){
+
+ if(state){
+ state = 0;
+ if (c != '=') {
+! gf_error("Illegal '=' in base64 text");
+! /* NO RETURN */
+ }
+ }
+
+--- 1375,1398 ----
+ register unsigned char t = f->t;
+ register int n = (int) f->n;
+ register int state = f->f1;
++ register unsigned char lastc;
+
+ while(GF_GETC(f, c)){
+
++ lastc = c;
++ if(f->f2){
++ GF_PUTC(f->next, c);
++ continue;
++ }
++
+ if(state){
+ state = 0;
+ if (c != '=') {
+! f->f2++;
+! GF_PUTC(f->next, c);
+! q_status_message(SM_ORDER,3,3,
+! _("Warning: Illegal '=' in base64 text"));
+! continue;
+ }
+ }
+
+***************
+*** 1397,1404 ****
+ break;
+
+ default: /* impossible quantum position */
+! gf_error("Internal base64 decoder error");
+! /* NO RETURN */
+ }
+ }
+ }
+--- 1409,1419 ----
+ break;
+
+ default: /* impossible quantum position */
+! f->f2++;
+! GF_PUTC(f->next, lastc);
+! q_status_message(SM_ORDER,3,3,
+! _("Warning: Internal base64 decode error"));
+! break;
+ }
+ }
+ }
+***************
+*** 1439,1444 ****
+--- 1454,1460 ----
+ dprint((9, "-- gf_reset b64_binary\n"));
+ f->n = 0L; /* quantum position */
+ f->f1 = 0; /* state holder: equal seen? */
++ f->f2 = 0; /* No errors when we start */
+ }
+ }
+
+***************
+*** 4979,4984 ****
+--- 4995,5001 ----
+ && p->value
+ && (HANDLES_LOC(hd->html_data)
+ || struncmp(p->value, "x-alpine-", 9)
++ || struncmp(p->value, "x-pine-help", 11)
+ || p->value[0] == '#'))
+ href = p;
+ else if(!strucmp(p->attribute, "NAME"))
+***************
+*** 7587,7592 ****
+--- 7604,7610 ----
+ char *p, buf[MAILTMPLEN];
+ ADDRESS *adr;
+ extern char datestamp[];
++ extern char plevstamp[];
+
+ if(!strcmp(s = removing_quotes(s + 4), "ALPINE_VERSION")){
+ p = ALPINE_VERSION;
+***************
+*** 7600,7605 ****
+--- 7618,7626 ----
+ else if(!strcmp(s, "ALPINE_COMPILE_DATE")){
+ p = datestamp;
+ }
++ else if(!strcmp(s, "ALPINE_PATCHLEVEL")){
++ p = plevstamp;
++ }
+ else if(!strcmp(s, "ALPINE_TODAYS_DATE")){
+ rfc822_date(p = buf);
+ }
+***************
+*** 9155,9160 ****
+--- 9176,9186 ----
+ margin_r,
+ indent;
+ char special[256];
++ long curlinenum; /* current line number */
++ int curqstrpos; /* current position in quote string */
++ long linenum; /* line number */
++ long qstrlen; /* multiples of 100 */
++ char **qstrln; /* qstrln[i] = quote string line i - 1 */
+ } WRAP_S;
+
+ #define WRAP_MARG_L(F) (((WRAP_S *)(F)->opt)->margin_l)
+***************
+*** 9196,9201 ****
+--- 9222,9233 ----
+ #define WRAP_COLOR(F) (((WRAP_S *)(F)->opt)->color)
+ #define WRAP_COLOR_SET(F) ((WRAP_COLOR(F)) && (WRAP_COLOR(F)->fg[0]))
+ #define WRAP_SPACES(F) (((WRAP_S *)(F)->opt)->spaces)
++ #define WRAP_CURLINE(F) (((WRAP_S *)(F)->opt)->curlinenum)
++ #define WRAP_CURPOS(F) (((WRAP_S *)(F)->opt)->curqstrpos)
++ #define WRAP_LINENUM(F) (((WRAP_S *)(F)->opt)->linenum)
++ #define WRAP_QSTRLEN(F) (((WRAP_S *)(F)->opt)->qstrlen)
++ #define WRAP_QSTRN(F) (((WRAP_S *)(F)->opt)->qstrln)
++ #define WRAP_QSTR(F, N) (((WRAP_S *)(F)->opt)->qstrln[(N)])
+ #define WRAP_PUTC(F,C,W) { \
+ if((F)->linep == WRAP_LASTC(F)){ \
+ size_t offset = (F)->linep - (F)->line; \
+***************
+*** 9273,9278 ****
+--- 9305,9312 ----
+ case CCR : /* CRLF or CR in text ? */
+ state = BOL; /* either way, handle start */
+
++ WRAP_CURLINE(f)++;
++ WRAP_CURPOS(f) = 0;
+ if(WRAP_FLOW(f)){
+ /* wrapped line? */
+ if(f->f2 == 0 && WRAP_SPC_LEN(f) && WRAP_TRL_SPC(f)){
+***************
+*** 9366,9372 ****
+
+ case BOL :
+ if(WRAP_FLOW(f)){
+! if(c == '>'){
+ WRAP_FL_QC(f) = 1; /* init it */
+ state = FL_QLEV; /* go collect it */
+ }
+--- 9400,9410 ----
+
+ case BOL :
+ if(WRAP_FLOW(f)){
+! if(WRAP_CURLINE(f) < WRAP_QSTRLEN(f)
+! && WRAP_QSTR(f, WRAP_CURLINE(f))
+! && WRAP_QSTR(f, WRAP_CURLINE(f))[WRAP_CURPOS(f)]
+! && WRAP_QSTR(f, WRAP_CURLINE(f))[WRAP_CURPOS(f)] == c){
+! WRAP_CURPOS(f)++;
+ WRAP_FL_QC(f) = 1; /* init it */
+ state = FL_QLEV; /* go collect it */
+ }
+***************
+*** 9380,9386 ****
+ }
+
+ /* quote level change implies new paragraph */
+! if(WRAP_FL_QD(f)){
+ WRAP_FL_QD(f) = 0;
+ if(WRAP_HARD(f) == 0){
+ WRAP_HARD(f) = 1;
+--- 9418,9433 ----
+ }
+
+ /* quote level change implies new paragraph */
+! if (WRAP_CURLINE(f) > 0
+! && WRAP_CURLINE(f) < WRAP_QSTRLEN(f)
+! && (WRAP_QSTR(f, WRAP_CURLINE(f)) != NULL
+! || WRAP_QSTR(f, WRAP_CURLINE(f) - 1) != NULL)
+! && ((WRAP_QSTR(f, WRAP_CURLINE(f)) != NULL &&
+! WRAP_QSTR(f, WRAP_CURLINE(f) - 1) == NULL)
+! || (WRAP_QSTR(f, WRAP_CURLINE(f)) == NULL &&
+! WRAP_QSTR(f, WRAP_CURLINE(f) - 1) != NULL)
+! || strcmp(WRAP_QSTR(f, WRAP_CURLINE(f)),
+! WRAP_QSTR(f, WRAP_CURLINE(f) - 1)))){
+ WRAP_FL_QD(f) = 0;
+ if(WRAP_HARD(f) == 0){
+ WRAP_HARD(f) = 1;
+***************
+*** 9432,9439 ****
+ break;
+
+ case FL_QLEV :
+! if(c == '>'){ /* another level */
+! WRAP_FL_QC(f)++;
+ }
+ else {
+ /* if EMBEDed, process it and return here */
+--- 9479,9490 ----
+ break;
+
+ case FL_QLEV :
+! if(WRAP_CURLINE(f) < WRAP_QSTRLEN(f)
+! && WRAP_QSTR(f, WRAP_CURLINE(f))
+! && WRAP_QSTR(f, WRAP_CURLINE(f))[WRAP_CURPOS(f)]
+! && WRAP_QSTR(f, WRAP_CURLINE(f))[WRAP_CURPOS(f)] == c){
+! WRAP_CURPOS(f)++;
+! WRAP_FL_QC(f)++; /* another level */
+ }
+ else {
+ /* if EMBEDed, process it and return here */
+***************
+*** 9445,9451 ****
+ }
+
+ /* quote level change signals new paragraph */
+! if(WRAP_FL_QC(f) != WRAP_FL_QD(f)){
+ WRAP_FL_QD(f) = WRAP_FL_QC(f);
+ if(WRAP_HARD(f) == 0){ /* add hard newline */
+ WRAP_HARD(f) = 1; /* hard newline */
+--- 9496,9511 ----
+ }
+
+ /* quote level change signals new paragraph */
+! if (WRAP_CURLINE(f) > 0
+! && WRAP_CURLINE(f) < WRAP_QSTRLEN(f)
+! && (WRAP_QSTR(f, WRAP_CURLINE(f))
+! || WRAP_QSTR(f, WRAP_CURLINE(f) - 1))
+! && ((WRAP_QSTR(f, WRAP_CURLINE(f)) &&
+! !WRAP_QSTR(f, WRAP_CURLINE(f) - 1))
+! || (!WRAP_QSTR(f, WRAP_CURLINE(f)) &&
+! WRAP_QSTR(f, WRAP_CURLINE(f) - 1))
+! || strcmp(WRAP_QSTR(f, WRAP_CURLINE(f)),
+! WRAP_QSTR(f, WRAP_CURLINE(f) - 1)))){
+ WRAP_FL_QD(f) = WRAP_FL_QC(f);
+ if(WRAP_HARD(f) == 0){ /* add hard newline */
+ WRAP_HARD(f) = 1; /* hard newline */
+***************
+*** 9502,9507 ****
+--- 9562,9574 ----
+ state = FL_SIG;
+ break;
+
++ case ' ' : /* what? */
++ if (WRAP_CURLINE(f) < WRAP_QSTRLEN(f)
++ && WRAP_QSTR(f, WRAP_CURLINE(f))){
++ WRAP_SPC_LEN(f)++;
++ so_writec(' ', WRAP_SPACES(f));
++ }
++
+ default : /* something else */
+ state = DFL;
+ goto case_dfl; /* handle c like DFL */
+***************
+*** 9518,9524 ****
+ &eob); /* note any embedded*/
+ wrap_eol(f, 1, &ip, &eib,
+ &op, &eob); /* plunk down newline */
+! wrap_bol(f, 1, 1, &ip, &eib,
+ &op, &eob); /* write any prefix */
+ }
+
+--- 9585,9591 ----
+ &eob); /* note any embedded*/
+ wrap_eol(f, 1, &ip, &eib,
+ &op, &eob); /* plunk down newline */
+! wrap_bol(f, 1, WRAP_FLOW(f), &ip, &eib,
+ &op, &eob); /* write any prefix */
+ }
+
+***************
+*** 10015,10021 ****
+ wrap_flush_embed(f, &ip, &eib, &op, &eob);
+ wrap_eol(f, 1, &ip, &eib, &op,
+ &eob); /* plunk down newline */
+! wrap_bol(f,1,1, &ip, &eib, &op,
+ &eob); /* write any prefix */
+ }
+
+--- 10082,10088 ----
+ wrap_flush_embed(f, &ip, &eib, &op, &eob);
+ wrap_eol(f, 1, &ip, &eib, &op,
+ &eob); /* plunk down newline */
+! wrap_bol(f,1,WRAP_FLOW(f), &ip, &eib, &op,
+ &eob); /* write any prefix */
+ }
+
+***************
+*** 10088,10093 ****
+--- 10155,10167 ----
+ if(WRAP_COLOR(f))
+ free_color_pair(&WRAP_COLOR(f));
+
++ { long i;
++ for (i = 0L; i < WRAP_QSTRLEN(f); i++)
++ if (WRAP_QSTR(f,i))
++ fs_give((void **) &(WRAP_QSTR(f,i)));
++ fs_give((void **)&WRAP_QSTRN(f));
++ }
++
+ fs_give((void **) &f->line); /* free temp line buffer */
+ so_give(&WRAP_SPACES(f));
+ fs_give((void **) &f->opt); /* free wrap widths struct */
+***************
+*** 10438,10444 ****
+ {
+ int j, i;
+ COLOR_PAIR *col = NULL;
+! char *prefix = NULL, *last_prefix = NULL;
+
+ if(ps_global->VAR_QUOTE_REPLACE_STRING){
+ get_pair(ps_global->VAR_QUOTE_REPLACE_STRING, &prefix, &last_prefix, 0, 0);
+--- 10512,10519 ----
+ {
+ int j, i;
+ COLOR_PAIR *col = NULL;
+! char *prefix = NULL, *last_prefix = NULL, *wrap_qstr = NULL;
+! int level = 0, oldj, len;
+
+ if(ps_global->VAR_QUOTE_REPLACE_STRING){
+ get_pair(ps_global->VAR_QUOTE_REPLACE_STRING, &prefix, &last_prefix, 0, 0);
+***************
+*** 10447,10456 ****
+ last_prefix = NULL;
+ }
+ }
+!
+! for(j = 0; j < WRAP_FL_QD(f); j++){
+ if(WRAP_USE_CLR(f)){
+! if((j % 3) == 0
+ && ps_global->VAR_QUOTE1_FORE_COLOR
+ && ps_global->VAR_QUOTE1_BACK_COLOR
+ && (col = new_color_pair(ps_global->VAR_QUOTE1_FORE_COLOR,
+--- 10522,10543 ----
+ last_prefix = NULL;
+ }
+ }
+!
+! if(WRAP_CURLINE(f) < WRAP_QSTRLEN(f) && WRAP_QSTR(f, WRAP_CURLINE(f)))
+! wrap_qstr = cpystr(WRAP_QSTR(f, WRAP_CURLINE(f)));
+! len = wrap_qstr ? strlen(wrap_qstr) : 0;
+!
+! for (j = wrap_qstr && *wrap_qstr == ' ' ? 1 : 0;
+! j < len && isspace((unsigned char)wrap_qstr[j]); j++){
+! GF_PUTC_GLO(f->next, wrap_qstr[j]);
+! f->n += ((wrap_qstr[j] == TAB) ? (~f->n & 0x07) + 1 : 1);
+! }
+!
+! for(; j < len && level < len; level++){
+! oldj = j;
+! j = next_level_quote(wrap_qstr, (char **)NULL, j, WRAP_FLOW(f));
+ if(WRAP_USE_CLR(f)){
+! if((level % 3) == 0
+ && ps_global->VAR_QUOTE1_FORE_COLOR
+ && ps_global->VAR_QUOTE1_BACK_COLOR
+ && (col = new_color_pair(ps_global->VAR_QUOTE1_FORE_COLOR,
+***************
+*** 10458,10464 ****
+ && pico_is_good_colorpair(col)){
+ GF_COLOR_PUTC(f, col);
+ }
+! else if((j % 3) == 1
+ && ps_global->VAR_QUOTE2_FORE_COLOR
+ && ps_global->VAR_QUOTE2_BACK_COLOR
+ && (col = new_color_pair(ps_global->VAR_QUOTE2_FORE_COLOR,
+--- 10545,10551 ----
+ && pico_is_good_colorpair(col)){
+ GF_COLOR_PUTC(f, col);
+ }
+! else if((level % 3) == 1
+ && ps_global->VAR_QUOTE2_FORE_COLOR
+ && ps_global->VAR_QUOTE2_BACK_COLOR
+ && (col = new_color_pair(ps_global->VAR_QUOTE2_FORE_COLOR,
+***************
+*** 10466,10472 ****
+ && pico_is_good_colorpair(col)){
+ GF_COLOR_PUTC(f, col);
+ }
+! else if((j % 3) == 2
+ && ps_global->VAR_QUOTE3_FORE_COLOR
+ && ps_global->VAR_QUOTE3_BACK_COLOR
+ && (col = new_color_pair(ps_global->VAR_QUOTE3_FORE_COLOR,
+--- 10553,10559 ----
+ && pico_is_good_colorpair(col)){
+ GF_COLOR_PUTC(f, col);
+ }
+! else if((level % 3) == 2
+ && ps_global->VAR_QUOTE3_FORE_COLOR
+ && ps_global->VAR_QUOTE3_BACK_COLOR
+ && (col = new_color_pair(ps_global->VAR_QUOTE3_FORE_COLOR,
+***************
+*** 10480,10522 ****
+ }
+ }
+
+ if(!WRAP_LV_FLD(f)){
+ if(!WRAP_FOR_CMPS(f) && ps_global->VAR_QUOTE_REPLACE_STRING && prefix){
+ for(i = 0; prefix[i]; i++)
+ GF_PUTC_GLO(f->next, prefix[i]);
+! f->n += utf8_width(prefix);
+! }
+! else if(ps_global->VAR_REPLY_STRING
+! && (!strcmp(ps_global->VAR_REPLY_STRING, ">")
+! || !strcmp(ps_global->VAR_REPLY_STRING, "\">\""))){
+! GF_PUTC_GLO(f->next, '>');
+! f->n += 1;
+ }
+ else{
+! GF_PUTC_GLO(f->next, '>');
+! GF_PUTC_GLO(f->next, ' ');
+! f->n += 2;
+ }
+ }
+ else{
+! GF_PUTC_GLO(f->next, '>');
+! f->n += 1;
+ }
+ }
+ if(j && WRAP_LV_FLD(f)){
+ GF_PUTC_GLO(f->next, ' ');
+ f->n++;
+ }
+! else if(j && last_prefix){
+ for(i = 0; last_prefix[i]; i++)
+ GF_PUTC_GLO(f->next, last_prefix[i]);
+! f->n += utf8_width(last_prefix);
+ }
+
+ if(prefix)
+ fs_give((void **)&prefix);
+ if(last_prefix)
+ fs_give((void **)&last_prefix);
+
+ return 0;
+ }
+--- 10567,10626 ----
+ }
+ }
+
++ if (j > 1 && wrap_qstr[j-1] == ' ')
++ j -= 1;
++
+ if(!WRAP_LV_FLD(f)){
+ if(!WRAP_FOR_CMPS(f) && ps_global->VAR_QUOTE_REPLACE_STRING && prefix){
+ for(i = 0; prefix[i]; i++)
+ GF_PUTC_GLO(f->next, prefix[i]);
+! f->n += utf8_widthis(prefix);
+ }
+ else{
+! for (i = oldj; i < j; i++)
+! GF_PUTC_GLO(f->next, wrap_qstr[i]);
+! f->n += j - oldj;
+ }
+ }
+ else{
+! for (i = oldj; i < j; i++)
+! GF_PUTC_GLO(f->next, wrap_qstr[i]);
+! f->n += j - oldj;
+! }
+! for (i = j; isspace((unsigned char)wrap_qstr[i]); i++);
+! if(!wrap_qstr[i]){
+! f->n += i - j;
+! for (; j < i; j++)
+! GF_PUTC_GLO(f->next, ' ');
+! }
+! else{
+! if((WRAP_LV_FLD(f)
+! || !ps_global->VAR_QUOTE_REPLACE_STRING || !prefix)
+! || !ps_global->VAR_REPLY_STRING
+! || (strcmp(ps_global->VAR_REPLY_STRING, ">")
+! && strcmp(ps_global->VAR_REPLY_STRING, "\">\""))){
+! GF_PUTC_GLO(f->next, ' ');
+! f->n += 1;
+! }
+ }
++ for (; isspace((unsigned char)wrap_qstr[j]); j++);
+ }
+ if(j && WRAP_LV_FLD(f)){
+ GF_PUTC_GLO(f->next, ' ');
+ f->n++;
+ }
+! else if(j && !value_is_space(wrap_qstr) && last_prefix){
+ for(i = 0; last_prefix[i]; i++)
+ GF_PUTC_GLO(f->next, last_prefix[i]);
+! f->n += utf8_widthis(last_prefix);
+ }
+
+ if(prefix)
+ fs_give((void **)&prefix);
+ if(last_prefix)
+ fs_give((void **)&last_prefix);
++ if (wrap_qstr)
++ fs_give((void **)&wrap_qstr);
+
+ return 0;
+ }
+***************
+*** 10548,10553 ****
+--- 10652,10663 ----
+ wrap->hdr_color = (GFW_HDRCOLOR & flags) == GFW_HDRCOLOR;
+ wrap->for_compose = (GFW_FORCOMPOSE & flags) == GFW_FORCOMPOSE;
+ wrap->handle_soft_hyphen = (GFW_SOFTHYPHEN & flags) == GFW_SOFTHYPHEN;
++ wrap->curlinenum = 0L;
++ wrap->curqstrpos = 0;
++ wrap->linenum = 0L;
++ wrap->qstrlen = 100L;
++ wrap->qstrln = (char **) fs_get(100*sizeof(char *));
++ memset(wrap->qstrln, 0, 100*sizeof(char *));
+
+ return((void *) wrap);
+ }
+***************
+*** 10991,10997 ****
+--- 11101,11315 ----
+ } \
+ }
+
++ #define ADD_QUOTE_STRING(F) { \
++ int len = tmp_20k_buf[0] ? strlen(tmp_20k_buf) + 1 : 0; \
++ FILTER_S *fltr; \
++ \
++ for(fltr = (F); fltr && fltr->f != gf_wrap; fltr = fltr->next); \
++ if (fltr){ \
++ if (WRAP_LINENUM(fltr) >= WRAP_QSTRLEN(fltr)){ \
++ fs_resize((void **)&WRAP_QSTRN(fltr), \
++ (WRAP_QSTRLEN(fltr) + 100) * sizeof(char *)); \
++ memset(WRAP_QSTRN(fltr)+WRAP_QSTRLEN(fltr), 0, \
++ 100*sizeof(char*)); \
++ WRAP_QSTRLEN(fltr) += 100L; \
++ } \
++ if (len){ \
++ WRAP_QSTR(fltr, WRAP_LINENUM(fltr)) = \
++ (char *) fs_get(len*sizeof(char)); \
++ WRAP_QSTR(fltr, WRAP_LINENUM(fltr)) = cpystr(tmp_20k_buf);\
++ } \
++ WRAP_LINENUM(fltr)++; \
++ } \
++ }
++
++ int end_of_line(char *line)
++ {
++ int i;
++
++ for(i= 0; line && line[i]; i++){
++ if((line[i] == '\015' && line[i+1] == '\012') || line[i] == '\012')
++ break;
++ }
++ return i;
++ }
++
++ /* This macro is used in gf_quote_test. It receives a return code
++ from a filter. All filters that will print something must send
++ return code 0, except color_a_quote which must send return code
++ 1
++ */
++
++ #define GF_ADD_QUOTED_LINE(F, line) \
++ { \
++ LT_INS_S *ins = NULL, *insp; \
++ int done; \
++ char *gline, *cline;\
++ unsigned char ch;\
++ register char *cp;\
++ register int l;\
++ \
++ for (gline = cline = line; gline && cline; ){\
++ if(cline = strchr(gline,'\012'))\
++ *cline = '\0';\
++ done = (*((LINETEST_S *) (F)->opt)->f)((F)->n++, gline, &ins,\
++ ((LINETEST_S *) (F)->opt)->local);\
++ if (done < 2){ \
++ if(done == 1)\
++ ADD_QUOTE_STRING((F));\
++ for(insp = ins, cp = gline; *cp ; ){\
++ if(insp && cp == insp->where){\
++ if(insp->len > 0){ \
++ for(l = 0; l < insp->len; l++){\
++ ch = (unsigned char) insp->text[l];\
++ GF_PUTC((F)->next, ch);\
++ }\
++ insp = insp->next;\
++ continue; \
++ } else if(insp->len < 0){ \
++ cp -= insp->len; \
++ insp = insp->next; \
++ continue; \
++ } \
++ }\
++ GF_PUTC((F)->next, *cp);\
++ cp++;\
++ }\
++ while(insp){\
++ for(l = 0; l < insp->len; l++){\
++ ch = (unsigned char) insp->text[l];\
++ GF_PUTC((F)->next, ch);\
++ }\
++ insp = insp->next;\
++ }\
++ gf_line_test_free_ins(&ins);\
++ if(cline){ \
++ *cline = '\012';\
++ gline += cline - gline + 1;\
++ }\
++ GF_PUTC((F)->next, '\015');\
++ GF_PUTC((F)->next, '\012');\
++ }\
++ }\
++ }
++ /* test second line of old line first */
++ #define SECOND_LINE_QUOTE_TEST(line, F) \
++ {\
++ *p = '\0';\
++ i = end_of_line((F)->oldline); \
++ if (((F)->oldline)[i]){\
++ i += (((F)->oldline)[i] == '\015') ? 2 : 1;\
++ line = (F)->oldline + i;\
++ i = end_of_line(line); \
++ if(line[i])\
++ line[i] = '\0'; \
++ }\
++ for (i = 0; ((F)->line) \
++ && (i < LINE_TEST_BLOCK) \
++ && (i < SIZEOF_20KBUF)\
++ && ((F)->line)[i] \
++ && (((F)->line)[i] != '\015')\
++ && (((F)->line)[i] != '\012')\
++ && (tmp_20k_buf[i] = ((F)->line)[i]); i++);\
++ tmp_20k_buf[i] = '\0';\
++ GF_ADD_QUOTED_LINE((F), line);\
++ }
++
++ #define FIRST_LINE_QUOTE_TEST(line, F)\
++ {\
++ *p = '\0';\
++ line = (F)->line;\
++ if ((F)->oldline)\
++ fs_give((void **)&(F)->oldline);\
++ (F)->oldline = cpystr(line);\
++ i = end_of_line(line); \
++ if (line[i]){ \
++ j = (line[i] == '\015') ? 2 : 1;\
++ line[i] = '\0'; \
++ i += j; \
++ }\
++ for (j = 0; ((F)->line) \
++ && ((i + j) < LINE_TEST_BLOCK) \
++ && (j < SIZEOF_20KBUF) \
++ && ((F)->line)[i + j] \
++ && (((F)->line)[i + j] != '\015')\
++ && (((F)->line)[i + j] != '\012')\
++ && (tmp_20k_buf[j] = ((F)->line)[i + j]); j++);\
++ tmp_20k_buf[j] = '\0';\
++ GF_ADD_QUOTED_LINE((F), line);\
++ }
++
++
++ void
++ gf_quote_test(f, flg)
++ FILTER_S *f;
++ int flg;
++ {
++ register char *p = f->linep;
++ register char *eobuf = GF_LINE_TEST_EOB(f);
++ char *line = NULL;
++ int i, j;
++ GF_INIT(f, f->next);
++
++ if(flg == GF_DATA){
++ register unsigned char c;
++ register int state = f->f1;
++
++ while(GF_GETC(f, c)){
++
++ GF_LINE_TEST_ADD(f, c);
++ if(c == '\012')
++ state++;
++ if(state == 2){ /* two full lines read */
++ state = 0;
++
++ /* first process the second line of an old line */
++ if (f->oldline && f->oldline[0])
++ SECOND_LINE_QUOTE_TEST(line, f);
++
++ /* now we process the first line */
++ FIRST_LINE_QUOTE_TEST(line, f);
+
++ p = f->line;
++ }
++ }
++
++ f->f1 = state;
++ GF_END(f, f->next);
++ }
++ else if(flg == GF_EOD){
++ /* first process the second line of an old line */
++ if (f->oldline && f->oldline[0])
++ SECOND_LINE_QUOTE_TEST(line, f);
++
++ /* now we process the first line */
++ FIRST_LINE_QUOTE_TEST(line, f);
++
++ /* We are out of data. In this case we have processed the second
++ * line of an oldline, then the first line of a line, but we need
++ * to process the second line of the given line. We do this by
++ * processing it now!.
++ */
++ if (line[i]){
++ tmp_20k_buf[0] = '\0'; /* No next line */
++ GF_ADD_QUOTED_LINE(f, line+i);
++ }
++
++ fs_give((void **) &f->oldline); /* free old line buffer */
++ fs_give((void **) &f->line); /* free line buffer */
++ fs_give((void **) &f->opt); /* free test struct */
++ GF_FLUSH(f->next);
++ (*f->next->f)(f->next, GF_EOD);
++ }
++ else if(flg == GF_RESET){
++ f->f1 = 0; /* state */
++ f->n = 0L; /* line number */
++ f->f2 = LINE_TEST_BLOCK; /* size of alloc'd line */
++ f->line = p = (char *) fs_get(f->f2 * sizeof(char));
++ }
++
++ f->linep = p;
++ }
+
+ /*
+ * this simple filter accumulates characters until a newline, offers it
+diff -rc alpine-2.00/pith/filter.h alpine-2.00.I.USE/pith/filter.h
+*** alpine-2.00/pith/filter.h 2008-08-22 12:46:13.000000000 -0700
+--- alpine-2.00.I.USE/pith/filter.h 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 175,181 ****
+ char *gf_pipe(gf_io_t, gf_io_t);
+ long gf_bytes_piped(void);
+ char *gf_filter(char *, char *, STORE_S *, gf_io_t, FILTLIST_S *, int,
+! void (*)(PIPE_S *, int, void *));
+ void gf_binary_b64(FILTER_S *, int);
+ void gf_b64_binary(FILTER_S *, int);
+ void gf_qp_8bit(FILTER_S *, int);
+--- 175,181 ----
+ char *gf_pipe(gf_io_t, gf_io_t);
+ long gf_bytes_piped(void);
+ char *gf_filter(char *, char *, STORE_S *, gf_io_t, FILTLIST_S *, int,
+! int, void (*)(PIPE_S *, int, void *));
+ void gf_binary_b64(FILTER_S *, int);
+ void gf_b64_binary(FILTER_S *, int);
+ void gf_qp_8bit(FILTER_S *, int);
+***************
+*** 215,220 ****
+--- 215,221 ----
+ void *gf_prepend_editorial_opt(prepedtest_t, char *);
+ void gf_nvtnl_local(FILTER_S *, int);
+ void gf_local_nvtnl(FILTER_S *, int);
++ void gf_quote_test(FILTER_S *, int);
+ void *gf_url_hilite_opt(URL_HILITE_S *, HANDLE_S **, int);
+
+
+diff -rc alpine-2.00/pith/filttype.h alpine-2.00.I.USE/pith/filttype.h
+*** alpine-2.00/pith/filttype.h 2007-04-25 21:06:02.000000000 -0700
+--- alpine-2.00.I.USE/pith/filttype.h 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 35,40 ****
+--- 35,42 ----
+ unsigned char t; /* temporary char */
+ char *line; /* place for temporary storage */
+ char *linep; /* pointer into storage space */
++ char *oldline; /* the previous line to "line" */
++ char *oldlinep; /* the previous line to "line" */
+ void *opt; /* optional per instance data */
+ void *data; /* misc internal data pointer */
+ unsigned char queue[1 + GF_MAXBUF];
+diff -rc alpine-2.00/pith/flag.c alpine-2.00.I.USE/pith/flag.c
+*** alpine-2.00/pith/flag.c 2008-07-14 11:01:54.000000000 -0700
+--- alpine-2.00.I.USE/pith/flag.c 2011-02-07 20:33:41.000000000 -0800
+***************
+*** 593,606 ****
+
+ was_invisible = (pelt->hidden || pelt->colhid) ? 1 : 0;
+
+ if((chk_thrd_cnt = ((msgs->visible_threads >= 0L)
+ && THRD_INDX_ENABLED() && (f & MN_HIDE) && (pelt->hidden != v))) != 0){
+ thrd = fetch_thread(stream, rawno);
+ if(thrd && thrd->top){
+! if(thrd->top == thrd->rawno)
+ topthrd = thrd;
+ else
+! topthrd = fetch_thread(stream, thrd->top);
+ }
+
+ if(topthrd){
+--- 593,608 ----
+
+ was_invisible = (pelt->hidden || pelt->colhid) ? 1 : 0;
+
++ thrd = fetch_thread(stream, rawno);
++
+ if((chk_thrd_cnt = ((msgs->visible_threads >= 0L)
+ && THRD_INDX_ENABLED() && (f & MN_HIDE) && (pelt->hidden != v))) != 0){
+ thrd = fetch_thread(stream, rawno);
+ if(thrd && thrd->top){
+! if(top_thread(stream, thrd->top) == thrd->rawno)
+ topthrd = thrd;
+ else
+! topthrd = fetch_thread(stream, top_thread(stream, thrd->top));
+ }
+
+ if(topthrd){
+diff -rc alpine-2.00/pith/handle.h alpine-2.00.I.USE/pith/handle.h
+*** alpine-2.00/pith/handle.h 2007-11-13 16:47:15.000000000 -0800
+--- alpine-2.00.I.USE/pith/handle.h 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 39,44 ****
+--- 39,45 ----
+ unsigned using_is_used:1; /* bit below is being used */
+ unsigned is_used:1; /* if not, remove it from list */
+ unsigned color_unseen:1; /* we're coloring folders with unseen */
++ unsigned color_folder:1; /* and just folders for that matter... */
+ unsigned is_dual_do_open:1; /* choosing this handle means open */
+ union {
+ struct { /* URL corresponding to this handle */
+diff -rc alpine-2.00/pith/imap.c alpine-2.00.I.USE/pith/imap.c
+*** alpine-2.00/pith/imap.c 2008-07-14 11:01:54.000000000 -0700
+--- alpine-2.00.I.USE/pith/imap.c 2011-02-07 20:33:43.000000000 -0800
+***************
+*** 1108,1110 ****
+--- 1108,1172 ----
+
+ return(block);
+ }
++
++
++ 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"));
++
++ /* 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;
++ }
++
++ for(l = mm_login_list; l; l = l->next)
++ if(imap_same_host(l->hosts, hostlist)
++ && !strcmp(l->user, user ? user : "")
++ && l->passwd){
++ l->passwd[0] = '\0';
++ break;
++ }
++ }
+diff -rc alpine-2.00/pith/imap.h alpine-2.00.I.USE/pith/imap.h
+*** alpine-2.00/pith/imap.h 2008-04-23 19:00:26.000000000 -0700
+--- alpine-2.00.I.USE/pith/imap.h 2011-02-07 20:33:43.000000000 -0800
+***************
+*** 123,129 ****
+ int imap_get_passwd(MMLOGIN_S *, char *, char *, STRLIST_S *, int);
+ void imap_set_passwd(MMLOGIN_S **, char *, char *, STRLIST_S *, int, int, int);
+ void imap_flush_passwd_cache(int);
+!
+
+ /* currently mandatory to implement stubs */
+
+--- 123,129 ----
+ int imap_get_passwd(MMLOGIN_S *, char *, char *, STRLIST_S *, int);
+ void imap_set_passwd(MMLOGIN_S **, char *, char *, STRLIST_S *, int, int, int);
+ void imap_flush_passwd_cache(int);
+! void pine_delete_pwd(NETMBX *mb, char *user);
+
+ /* currently mandatory to implement stubs */
+
+diff -rc alpine-2.00/pith/indxtype.h alpine-2.00.I.USE/pith/indxtype.h
+*** alpine-2.00/pith/indxtype.h 2008-05-28 13:19:56.000000000 -0700
+--- alpine-2.00.I.USE/pith/indxtype.h 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 75,86 ****
+ iKey, iKeyInit,
+ iPrefDate, iPrefTime, iPrefDateTime,
+ iCurPrefDate, iCurPrefTime, iCurPrefDateTime,
+! iSize, iSizeComma, iSizeNarrow, iDescripSize,
+ iNewsAndTo, iToAndNews, iNewsAndRecips, iRecipsAndNews,
+ iFromTo, iFromToNotNews, iFrom, iTo, iSender, iCc, iNews, iRecips,
+ iCurNews, iArrow,
+ iMailbox, iAddress, iInit, iCursorPos,
+ iDay2Digit, iMon2Digit, iYear2Digit,
+ iSTime, iKSize,
+ iRoleNick, iNewLine,
+ iHeader, iText,
+--- 75,89 ----
+ iKey, iKeyInit,
+ iPrefDate, iPrefTime, iPrefDateTime,
+ iCurPrefDate, iCurPrefTime, iCurPrefDateTime,
+! iSize, iSizeComma, iSizeNarrow, iDescripSize, iSizeThread,
+ iNewsAndTo, iToAndNews, iNewsAndRecips, iRecipsAndNews,
+ iFromTo, iFromToNotNews, iFrom, iTo, iSender, iCc, iNews, iRecips,
+ iCurNews, iArrow,
+ iMailbox, iAddress, iInit, iCursorPos,
+ iDay2Digit, iMon2Digit, iYear2Digit,
++ iFolder, iFlag, iCollection, iRole, iProcid, iScreen, iPkey,
++ iNick, iAddressTo, iAddressCc, iAddressRecip, iBcc, iLcc,
++ iFfrom, iFadd,
+ iSTime, iKSize,
+ iRoleNick, iNewLine,
+ iHeader, iText,
+***************
+*** 102,116 ****
+
+
+ /* these are flags for the what_for field in INDEX_PARSE_T */
+! #define FOR_NOTHING 0x00
+! #define FOR_INDEX 0x01
+! #define FOR_REPLY_INTRO 0x02
+! #define FOR_TEMPLATE 0x04 /* or for signature */
+! #define FOR_FILT 0x08
+! #define DELIM_USCORE 0x10
+! #define DELIM_PAREN 0x20
+! #define DELIM_COLON 0x40
+!
+
+ #define DEFAULT_REPLY_INTRO "default"
+
+--- 105,130 ----
+
+
+ /* these are flags for the what_for field in INDEX_PARSE_T */
+! #define FOR_NOTHING 0x00000
+! #define FOR_INDEX 0x00001
+! #define FOR_REPLY_INTRO 0x00002
+! #define FOR_TEMPLATE 0x00004 /* or for signature */
+! #define FOR_FILT 0x00008
+! #define DELIM_USCORE 0x00010
+! #define DELIM_PAREN 0x00020
+! #define DELIM_COLON 0x00040
+! #define FOR_FOLDER 0x00080 /* for rules */
+! #define FOR_RULE 0x00100 /* for rules */
+! #define FOR_TRIM 0x00200 /* for rules */
+! #define FOR_RESUB 0x00400 /* for rules */
+! #define FOR_REPLACE 0x00800 /* for rules */
+! #define FOR_SORT 0x01000 /* for rules */
+! #define FOR_FLAG 0x02000 /* for rules */
+! #define FOR_COMPOSE 0x04000 /* for rules */
+! #define FOR_THREAD 0x08000 /* for rules */
+! #define FOR_STARTUP 0x10000 /* for rules */
+! #define FOR_KEY 0x20000 /* for rules */
+! #define FOR_SAVE 0x40000 /* for rules */
+
+ #define DEFAULT_REPLY_INTRO "default"
+
+diff -rc alpine-2.00/pith/init.c alpine-2.00.I.USE/pith/init.c
+*** alpine-2.00/pith/init.c 2007-08-16 15:25:10.000000000 -0700
+--- alpine-2.00.I.USE/pith/init.c 2011-02-07 20:33:41.000000000 -0800
+***************
+*** 407,412 ****
+--- 407,415 ----
+ && stricmp(filename, folder_base)){
+ #else
+ if(strncmp(filename, folder_base, folder_base_len) == 0
++ #ifndef _WINDOWS
++ && filename[folder_base_len] != list_cntxt->dir->delim
++ #endif
+ && strcmp(filename, folder_base)){
+ #endif
+ #endif
+diff -rc alpine-2.00/pith/mailcap.c alpine-2.00.I.USE/pith/mailcap.c
+*** alpine-2.00/pith/mailcap.c 2008-03-18 10:24:31.000000000 -0700
+--- alpine-2.00.I.USE/pith/mailcap.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 52,57 ****
+--- 52,58 ----
+ int needsterminal;
+ char *contenttype;
+ char *command;
++ char *nametemplate;
+ char *testcommand;
+ char *label; /* unused */
+ char *printcommand; /* unused */
+***************
+*** 212,217 ****
+--- 213,221 ----
+ if(mc->printcommand)
+ dprint((11, " printcommand: %s",
+ mc->printcommand ? mc->printcommand : "?"));
++ if(mc->nametemplate)
++ dprint((11, " nametemplate: %s",
++ mc->nametemplate ? mc->nametemplate : "?"));
+ dprint((11, " needsterminal %d\n", mc->needsterminal));
+ }
+ }
+***************
+*** 487,492 ****
+--- 491,501 ----
+ dprint((9, "mailcap: printcommand=%s\n",
+ mc->printcommand ? mc->printcommand : "?"));
+ }
++ else if(arg && !strucmp(*tokens, "nametemplate")){
++ mc->nametemplate = arg;
++ dprint((9, "mailcap: nametemplate=%s\n",
++ arg ? arg : "?"));
++ }
+ else if(arg && !strucmp(*tokens, "compose")){
+ /* not used */
+ dprint((9, "mailcap: not using compose=%s\n",
+***************
+*** 973,975 ****
+--- 982,1041 ----
+ mail_free_stringlist(&MailcapData.raw);
+ mc_free_entry(&MailcapData.head);
+ }
++
++ char *
++ mc_template(char *tmp_file, BODY *body, int chk_extension)
++ {
++ MailcapEntry *mc;
++ int quoted = 0;
++ char *s, *to, *namefile = NULL;
++
++ mc = mc_get_command(body->type, body->subtype, body, chk_extension, NULL);
++ if(!mc || !mc->nametemplate || !tmp_file)
++ return tmp_file;
++
++ /* remove extension if requested for a specific extension */
++ if(mc->nametemplate && tmp_file && (s = strrchr(tmp_file, '.')) != NULL
++ && strchr(s, C_FILESEP) == NULL)
++ *s = '\0';
++
++ to = tmp_20k_buf;
++ if((s = strrchr(tmp_file, C_FILESEP)) != NULL){
++ *s++ = '\0';
++ sstrncpy(&to, tmp_file, SIZEOF_20KBUF-(to-tmp_20k_buf));
++ if(to-tmp_20k_buf < SIZEOF_20KBUF)
++ *to++ = C_FILESEP;
++ namefile = s;
++ }
++
++ for(s = mc->nametemplate; *s; s++)
++ if(quoted){
++ quoted = 0;
++ switch(*s){
++ case '%':
++ if(to-tmp_20k_buf < SIZEOF_20KBUF)
++ *to++ = '%';
++ break;
++
++ case 's':
++ sstrncpy(&to, namefile ? namefile : tmp_file, SIZEOF_20KBUF-(to-tmp_20k_buf));
++ break;
++
++ default:
++ dprint((9,
++ "Ignoring unercognized format code in nametemplate: %%%c\n", *s ));
++ break;
++ }
++ }
++ else if(*s == '%')
++ quoted = 1;
++ else if(to-tmp_20k_buf < SIZEOF_20KBUF)
++ *to++ = *s;
++
++ *to++ = '\0';
++
++ fs_give((void **)&tmp_file);
++ tmp_file = cpystr(tmp_20k_buf);
++ return tmp_file;
++ }
++
+diff -rc alpine-2.00/pith/mailcap.h alpine-2.00.I.USE/pith/mailcap.h
+*** alpine-2.00/pith/mailcap.h 2008-03-18 10:24:31.000000000 -0700
+--- alpine-2.00.I.USE/pith/mailcap.h 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 28,33 ****
+--- 28,34 ----
+ int mailcap_can_display(int, char *, BODY *, int);
+ MCAP_CMD_S *mailcap_build_command(int, char *, BODY *, char *, int *, int);
+ void mailcap_free(void);
++ char *mc_template(char *, BODY *, int);
+
+ /* currently mandatory to implement stubs */
+
+diff -rc alpine-2.00/pith/mailcmd.c alpine-2.00.I.USE/pith/mailcmd.c
+*** alpine-2.00/pith/mailcmd.c 2008-07-09 22:01:13.000000000 -0700
+--- alpine-2.00.I.USE/pith/mailcmd.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 38,43 ****
+--- 38,44 ----
+ #include "../pith/ablookup.h"
+ #include "../pith/search.h"
+ #include "../pith/charconv/utf8.h"
++ #include "../pith/rules.h"
+
+ #ifdef _WINDOWS
+ #include "../pico/osdep/mswin.h"
+***************
+*** 659,664 ****
+--- 660,666 ----
+ strncpy(ps_global->cur_folder, p, sizeof(ps_global->cur_folder)-1);
+ ps_global->cur_folder[sizeof(ps_global->cur_folder)-1] = '\0';
+ ps_global->context_current = ps_global->context_list;
++ setup_threading_index_style();
+ reset_index_format();
+ clear_index_cache(ps_global->mail_stream, 0);
+ /* MUST sort before restoring msgno! */
+***************
+*** 771,776 ****
+--- 773,783 ----
+ if(stream)
+ sp_set_first_unseen(stream, 0L);
+
++ /* in case we closed the old stream by cancelling the connection, do
++ * not let that interfere with opening the new stream.
++ */
++ ps_global->user_says_cancel = 0;
++
+ m = context_open((new_context && !open_inbox) ? new_context : NULL,
+ stream,
+ open_inbox ? ps_global->VAR_INBOX_PATH : expanded_file,
+***************
+*** 974,979 ****
+--- 981,987 ----
+
+ clear_index_cache(ps_global->mail_stream, 0);
+ reset_index_format();
++ setup_threading_index_style();
+
+ /*
+ * Start news reading with messages the user's marked deleted
+***************
+*** 1092,1098 ****
+
+ if(!cur_already_set && mn_get_total(ps_global->msgmap) > 0L){
+
+! perfolder_startup_rule = reset_startup_rule(ps_global->mail_stream);
+
+ if(ps_global->start_entry > 0){
+ mn_set_cur(ps_global->msgmap, mn_get_revsort(ps_global->msgmap)
+--- 1100,1109 ----
+
+ if(!cur_already_set && mn_get_total(ps_global->msgmap) > 0L){
+
+! perfolder_startup_rule = get_perfolder_startup_rule(ps_global->mail_stream,
+! V_STARTUP_RULES, newfolder);
+!
+! reset_startup_rule(ps_global->mail_stream);
+
+ if(ps_global->start_entry > 0){
+ mn_set_cur(ps_global->msgmap, mn_get_revsort(ps_global->msgmap)
+***************
+*** 1114,1237 ****
+ else
+ use_this_startup_rule = ps_global->inc_startup_rule;
+
+! switch(use_this_startup_rule){
+! /*
+! * For news in incoming collection we're doing the same thing
+! * for first-unseen and first-recent. In both those cases you
+! * get first-unseen if FAKE_NEW is off and first-recent if
+! * FAKE_NEW is on. If FAKE_NEW is on, first unseen is the
+! * same as first recent because all recent msgs are unseen
+! * and all unrecent msgs are seen (see pine_mail_open).
+! */
+! case IS_FIRST_UNSEEN:
+! first_unseen:
+! mn_set_cur(ps_global->msgmap,
+! (sp_first_unseen(m)
+! && mn_get_sort(ps_global->msgmap) == SortArrival
+! && !mn_get_revsort(ps_global->msgmap)
+! && !get_lflag(ps_global->mail_stream, NULL,
+! sp_first_unseen(m), MN_EXLD)
+! && (n = mn_raw2m(ps_global->msgmap,
+! sp_first_unseen(m))))
+! ? n
+! : first_sorted_flagged(F_UNSEEN | F_UNDEL, m, pc,
+! THREADING() ? 0 : FSF_SKIP_CHID));
+! break;
+!
+! case IS_FIRST_RECENT:
+! first_recent:
+! /*
+! * We could really use recent for news but this is the way
+! * it has always worked, so we'll leave it. That is, if
+! * the FAKE_NEW feature is on, recent and unseen are
+! * equivalent, so it doesn't matter. If the feature isn't
+! * on, all the undeleted messages are unseen and we start
+! * at the first one. User controls with the FAKE_NEW feature.
+! */
+! if(IS_NEWS(ps_global->mail_stream)){
+! mn_set_cur(ps_global->msgmap,
+! first_sorted_flagged(F_UNSEEN|F_UNDEL, m, pc,
+! THREADING() ? 0 : FSF_SKIP_CHID));
+! }
+! else{
+! mn_set_cur(ps_global->msgmap,
+! first_sorted_flagged(F_RECENT | F_UNSEEN
+! | F_UNDEL,
+! m, pc,
+! THREADING() ? 0 : FSF_SKIP_CHID));
+! }
+! break;
+!
+! case IS_FIRST_IMPORTANT:
+! mn_set_cur(ps_global->msgmap,
+! first_sorted_flagged(F_FLAG|F_UNDEL, m, pc,
+! THREADING() ? 0 : FSF_SKIP_CHID));
+! break;
+!
+! case IS_FIRST_IMPORTANT_OR_UNSEEN:
+!
+! if(IS_NEWS(ps_global->mail_stream))
+! goto first_unseen;
+!
+! {
+! MsgNo flagged, first_unseen;
+!
+! flagged = first_sorted_flagged(F_FLAG|F_UNDEL, m, pc,
+! THREADING() ? 0 : FSF_SKIP_CHID);
+! first_unseen = (sp_first_unseen(m)
+! && mn_get_sort(ps_global->msgmap) == SortArrival
+! && !mn_get_revsort(ps_global->msgmap)
+! && !get_lflag(ps_global->mail_stream, NULL,
+! sp_first_unseen(m), MN_EXLD)
+! && (n = mn_raw2m(ps_global->msgmap,
+! sp_first_unseen(m))))
+! ? n
+! : first_sorted_flagged(F_UNSEEN|F_UNDEL, m, pc,
+! THREADING() ? 0 : FSF_SKIP_CHID);
+! mn_set_cur(ps_global->msgmap,
+! (MsgNo) MIN((int) flagged, (int) first_unseen));
+!
+! }
+!
+! break;
+!
+! case IS_FIRST_IMPORTANT_OR_RECENT:
+!
+! if(IS_NEWS(ps_global->mail_stream))
+! goto first_recent;
+!
+! {
+! MsgNo flagged, first_recent;
+!
+! flagged = first_sorted_flagged(F_FLAG|F_UNDEL, m, pc,
+! THREADING() ? 0 : FSF_SKIP_CHID);
+! first_recent = first_sorted_flagged(F_RECENT | F_UNSEEN
+! | F_UNDEL,
+! m, pc,
+! THREADING() ? 0 : FSF_SKIP_CHID);
+! mn_set_cur(ps_global->msgmap,
+! (MsgNo) MIN((int) flagged, (int) first_recent));
+! }
+!
+! break;
+!
+! case IS_FIRST:
+! mn_set_cur(ps_global->msgmap,
+! first_sorted_flagged(F_UNDEL, m, pc,
+! THREADING() ? 0 : FSF_SKIP_CHID));
+! break;
+!
+! case IS_LAST:
+! mn_set_cur(ps_global->msgmap,
+! first_sorted_flagged(F_UNDEL, m, pc,
+! FSF_LAST | (THREADING() ? 0 : FSF_SKIP_CHID)));
+! break;
+!
+! default:
+! panic("Unexpected incoming startup case");
+! break;
+!
+! }
+ }
+ else if(IS_NEWS(ps_global->mail_stream)){
+ /*
+--- 1125,1131 ----
+ else
+ use_this_startup_rule = ps_global->inc_startup_rule;
+
+! find_startup_position(use_this_startup_rule, m, pc);
+ }
+ else if(IS_NEWS(ps_global->mail_stream)){
+ /*
+***************
+*** 1409,1417 ****
+ /* Save read messages? */
+ if(VAR_READ_MESSAGE_FOLDER && VAR_READ_MESSAGE_FOLDER[0]
+ && sp_flagged(stream, SP_INBOX)
+! && (seen_not_del = count_flagged(stream, F_SEEN | F_UNDEL))){
+
+ if(F_ON(F_AUTO_READ_MSGS,ps_global)
+ || (pith_opt_read_msg_prompt
+ && (*pith_opt_read_msg_prompt)(seen_not_del, VAR_READ_MESSAGE_FOLDER)))
+ /* move inbox's read messages */
+--- 1303,1313 ----
+ /* Save read messages? */
+ if(VAR_READ_MESSAGE_FOLDER && VAR_READ_MESSAGE_FOLDER[0]
+ && sp_flagged(stream, SP_INBOX)
+! && (F_ON(F_AUTO_READ_MSGS_RULES, ps_global) ||
+! (seen_not_del = count_flagged(stream, F_SEEN | F_UNDEL)))){
+
+ if(F_ON(F_AUTO_READ_MSGS,ps_global)
++ || F_ON(F_AUTO_READ_MSGS_RULES, ps_global)
+ || (pith_opt_read_msg_prompt
+ && (*pith_opt_read_msg_prompt)(seen_not_del, VAR_READ_MESSAGE_FOLDER)))
+ /* move inbox's read messages */
+***************
+*** 1682,1687 ****
+--- 1578,1586 ----
+ char *bufp = NULL;
+ MESSAGECACHE *mc;
+
++ if (F_ON(F_AUTO_READ_MSGS_RULES, ps_global))
++ return move_read_msgs_using_rules(stream, dstfldr, buf);
++
+ if(!is_absolute_path(dstfldr)
+ && !(save_context = default_save_context(ps_global->context_list)))
+ save_context = ps_global->context_list;
+***************
+*** 1721,1728 ****
+ snprintf(buf, buflen, "Moving %s read message%s to \"%s\"",
+ comatose(searched), plural(searched), dstfldr);
+ we_cancel = busy_cue(buf, NULL, 0);
+! if(save(ps_global, stream, save_context, dstfldr, msgmap,
+! SV_DELETE | SV_FIX_DELS | SV_INBOXWOCNTXT) == searched)
+ strncpy(bufp = buf + 1, "Moved", MIN(5,buflen)); /* change Moving to Moved */
+
+ buf[buflen-1] = '\0';
+--- 1620,1628 ----
+ snprintf(buf, buflen, "Moving %s read message%s to \"%s\"",
+ comatose(searched), plural(searched), dstfldr);
+ we_cancel = busy_cue(buf, NULL, 0);
+! ps_global->exiting = 1;
+! if((save(ps_global, stream, save_context, dstfldr, msgmap,
+! SV_DELETE | SV_FIX_DELS | SV_INBOXWOCNTXT) == searched))
+ strncpy(bufp = buf + 1, "Moved", MIN(5,buflen)); /* change Moving to Moved */
+
+ buf[buflen-1] = '\0';
+***************
+*** 1760,1766 ****
+ && ((context_isambig(folder)
+ && folder_is_nick(folder, FOLDERS(context), 0))
+ || folder_index(folder, context, FI_FOLDER) > 0)
+! && (seen_undel = count_flagged(stream, F_SEEN | F_UNDEL))){
+
+ for(; f && *archive; archive++){
+ char *p;
+--- 1660,1668 ----
+ && ((context_isambig(folder)
+ && folder_is_nick(folder, FOLDERS(context), 0))
+ || folder_index(folder, context, FI_FOLDER) > 0)
+! && ((seen_undel = count_flagged(stream, F_SEEN | F_UNDEL))
+! || (F_ON(F_AUTO_READ_MSGS,ps_global) &&
+! F_ON(F_AUTO_READ_MSGS_RULES, ps_global)))){
+
+ for(; f && *archive; archive++){
+ char *p;
+***************
+*** 2158,2165 ****
+
+
+ int
+! agg_text_select(MAILSTREAM *stream, MSGNO_S *msgmap, char type, int not,
+! int check_for_my_addresses,
+ char *sstring, char *charset, SEARCHSET **limitsrch)
+ {
+ int old_imap, we_cancel;
+--- 2060,2067 ----
+
+
+ int
+! agg_text_select(MAILSTREAM *stream, MSGNO_S *msgmap, char type, char *namehdr,
+! int not, int check_for_my_addresses,
+ char *sstring, char *charset, SEARCHSET **limitsrch)
+ {
+ int old_imap, we_cancel;
+***************
+*** 2308,2313 ****
+--- 2210,2219 ----
+
+ if(!mepgm)
+ switch(type){
++ case 'h' : /* Any header */
++ pgm->header = mail_newsearchheader (namehdr, sstring);
++ break;
++
+ case 'r' : /* TO or CC */
+ if(old_imap){
+ /* No OR on old servers */
+***************
+*** 2714,2716 ****
+--- 2620,2921 ----
+
+ return(*target ? target : NULL);
+ }
++
++ char *
++ move_read_msgs_using_rules(MAILSTREAM *stream, char *dstfldr, char *buf)
++ {
++ CONTEXT_S *save_context = NULL;
++ char **folder_to_save = NULL;
++ int num, we_cancel;
++ long i, j, success;
++ MSGNO_S *msgmap = NULL;
++ unsigned long nmsgs = 0L, stream_nmsgs;
++
++ saved_stream = stream; /* horrible hack! */
++ if(!is_absolute_path(dstfldr)
++ && !(save_context = default_save_context(ps_global->context_list)))
++ save_context = ps_global->context_list;
++
++ folder_to_save = (char **)fs_get((stream->nmsgs + 1)*sizeof(char *));
++ folder_to_save[0] = NULL;
++ mn_init(&msgmap, stream->nmsgs);
++ stream_nmsgs = stream->nmsgs;
++ for (i = 1L; i <= stream_nmsgs ; i++){
++ set_lflag(stream, msgmap, i, MN_SLCT, 0);
++ folder_to_save[i] = get_lflag(stream, NULL, i, MN_EXLD)
++ ? NULL : get_folder_to_save(stream, i, dstfldr);
++ }
++ for (i = 1L; i <= stream_nmsgs; i++){
++ num = 0;
++ if (folder_to_save[i]){
++ mn_init(&msgmap, stream_nmsgs);
++ for (j = i; j <= stream_nmsgs ; j++){
++ if (folder_to_save[j]){
++ if (!strcmp(folder_to_save[i], folder_to_save[j])){
++ set_lflag(stream, msgmap, j, MN_SLCT, 1);
++ num++;
++ if (j != i)
++ fs_give((void **)&folder_to_save[j]);
++ }
++ }
++ }
++ pseudo_selected(stream, msgmap);
++ sprintf(buf, "Moving %s read message%s to \"%.45s\"",
++ comatose(num), plural(num), folder_to_save[i]);
++ we_cancel = busy_cue(buf, NULL, 1);
++ ps_global->exiting = 1;
++ if(success = save(ps_global, stream,save_context, folder_to_save[i],
++ msgmap, SV_DELETE | SV_FIX_DELS))
++ nmsgs += success;
++ if(we_cancel)
++ cancel_busy_cue(success ? 0 : -1);
++ for (j = i; j <= stream_nmsgs ; j++)
++ set_lflag(stream, msgmap, j, MN_SLCT, 0);
++ fs_give((void **)&folder_to_save[i]);
++ mn_give(&msgmap);
++ }
++ }
++ ps_global->exiting = 0; /* useful if we call from aggregate operations */
++ sprintf(buf, "Moved automatically %s message%s",
++ comatose(nmsgs), plural(nmsgs));
++ if (folder_to_save)
++ fs_give((void **)folder_to_save);
++ rule_curpos = 0L;
++ return buf;
++ }
++
++ char *
++ get_folder_to_save(MAILSTREAM *stream, long i, char *dstfldr)
++ {
++ MESSAGECACHE *mc = NULL;
++ RULE_RESULT *rule;
++ MSGNO_S *msgmap = NULL;
++ char *folder_to_save = NULL, *save_folder = NULL;
++ int n;
++ long msgno;
++
++ /* The plan is as follows: Select each message of the folder. We
++ * need to set the cursor correctly so that iFlag gets the value
++ * correctly too, otherwise iFlag will get the value of the position
++ * of the cursor. After that we need to look for a rule that applies
++ * to the message and get the saving folder. If we get a saving folder,
++ * and we used the _FLAG_ token, use that folder, if no
++ * _FLAG_ token was used, move only if seen and not deleted, to the
++ * folder specified in the saving rule. If we did not get a saving
++ * folder from the rule, just save in the default folder.
++ */
++ mn_init(&msgmap, stream->nmsgs);
++ rule_curpos = i;
++ msgno = mn_m2raw(msgmap, i);
++ if (msgno > 0L){
++ mc = mail_elt(stream, msgno);
++ rule = (RULE_RESULT *)
++ get_result_rule(V_SAVE_RULES, FOR_SAVE, mc->private.msg.env);
++ if (rule){
++ folder_to_save = cpystr(rule->result);
++ n = rule->number;
++ fs_give((void **)&rule->result);
++ fs_give((void **)&rule);
++ }
++ }
++
++ if (folder_to_save && *folder_to_save){
++ RULELIST *list = get_rulelist_from_code(V_SAVE_RULES,
++ ps_global->rule_list);
++ RULE_S *prule = get_rule(list, n);
++ if (condition_contains_token(prule->condition, "_FLAG_")
++ || (mc->valid && mc->seen && !mc->deleted)
++ || (!mc->valid && mc->searched))
++ save_folder = cpystr(folder_to_save);
++ else
++ save_folder = NULL;
++ }
++ else
++ if (!mc || (mc->seen && !mc->deleted))
++ save_folder = cpystr(dstfldr);
++ mn_give(&msgmap);
++ rule_curpos = 0L;
++ return save_folder;
++ }
++
++ MAILSTREAM *
++ find_open_stream(void)
++ {
++ return saved_stream;
++ }
++
++ unsigned long
++ rules_cursor_pos(MAILSTREAM *stream)
++ {
++ MSGNO_S *msgmap = sp_msgmap(stream);
++ return rule_curpos != 0L ? rule_curpos : mn_m2raw(msgmap,mn_get_cur(msgmap));
++ }
++
++ void
++ setup_threading_index_style(void)
++ {
++ RULE_RESULT *rule;
++ NAMEVAL_S *v;
++ int i;
++
++ rule = get_result_rule(V_THREAD_INDEX_STYLE_RULES, FOR_THREAD, NULL);
++ if (rule || ps_global->VAR_THREAD_INDEX_STYLE){
++ for(i = 0; v = thread_index_styles(i); i++)
++ if(!strucmp(rule ? rule->result : ps_global->VAR_THREAD_INDEX_STYLE,
++ rule ? (v ? v->name : "" ) : S_OR_L(v))){
++ ps_global->thread_index_style = v->value;
++ break;
++ }
++ if (rule){
++ if (rule->result)
++ fs_give((void **)&rule->result);
++ fs_give((void **)&rule);
++ }
++ }
++ }
++
++ unsigned
++ get_perfolder_startup_rule(MAILSTREAM *stream, int rule_type, char *folder)
++ {
++ unsigned startup_rule;
++ char *rule_result;
++
++ startup_rule = reset_startup_rule(stream);
++ rule_result = get_rule_result(FOR_STARTUP, folder, rule_type);
++ if (rule_result && *rule_result){
++ int i;
++ NAMEVAL_S *v;
++
++ for(i = 0; v = incoming_startup_rules(i); i++)
++ if(!strucmp(rule_result, v->name)){
++ startup_rule = v->value;
++ break;
++ }
++ fs_give((void **)&rule_result);
++ }
++ return startup_rule;
++ }
++
++ void
++ find_startup_position(int rule, MAILSTREAM *m, long pc)
++ {
++ long n;
++ switch(rule){
++ /*
++ * For news in incoming collection we're doing the same thing
++ * for first-unseen and first-recent. In both those cases you
++ * get first-unseen if FAKE_NEW is off and first-recent if
++ * FAKE_NEW is on. If FAKE_NEW is on, first unseen is the
++ * same as first recent because all recent msgs are unseen
++ * and all unrecent msgs are seen (see pine_mail_open).
++ */
++ case IS_FIRST_UNSEEN:
++ first_unseen:
++ mn_set_cur(ps_global->msgmap,
++ (sp_first_unseen(m)
++ && mn_get_sort(ps_global->msgmap) == SortArrival
++ && !mn_get_revsort(ps_global->msgmap)
++ && !get_lflag(ps_global->mail_stream, NULL,
++ sp_first_unseen(m), MN_EXLD)
++ && (n = mn_raw2m(ps_global->msgmap,
++ sp_first_unseen(m))))
++ ? n
++ : first_sorted_flagged(F_UNSEEN | F_UNDEL, m, pc,
++ THREADING() ? 0 : FSF_SKIP_CHID));
++ break;
++
++ case IS_FIRST_RECENT:
++ first_recent:
++ /*
++ * We could really use recent for news but this is the way
++ * it has always worked, so we'll leave it. That is, if
++ * the FAKE_NEW feature is on, recent and unseen are
++ * equivalent, so it doesn't matter. If the feature isn't
++ * on, all the undeleted messages are unseen and we start
++ * at the first one. User controls with the FAKE_NEW feature.
++ */
++ if(IS_NEWS(ps_global->mail_stream)){
++ mn_set_cur(ps_global->msgmap,
++ first_sorted_flagged(F_UNSEEN|F_UNDEL, m, pc,
++ THREADING() ? 0 : FSF_SKIP_CHID));
++ }
++ else{
++ mn_set_cur(ps_global->msgmap,
++ first_sorted_flagged(F_RECENT | F_UNSEEN
++ | F_UNDEL,
++ m, pc,
++ THREADING() ? 0 : FSF_SKIP_CHID));
++ }
++ break;
++
++ case IS_FIRST_IMPORTANT:
++ mn_set_cur(ps_global->msgmap,
++ first_sorted_flagged(F_FLAG|F_UNDEL, m, pc,
++ THREADING() ? 0 : FSF_SKIP_CHID));
++ break;
++
++ case IS_FIRST_IMPORTANT_OR_UNSEEN:
++
++ if(IS_NEWS(ps_global->mail_stream))
++ goto first_unseen;
++
++ {
++ MsgNo flagged, first_unseen;
++
++ flagged = first_sorted_flagged(F_FLAG|F_UNDEL, m, pc,
++ THREADING() ? 0 : FSF_SKIP_CHID);
++ first_unseen = (sp_first_unseen(m)
++ && mn_get_sort(ps_global->msgmap) == SortArrival
++ && !mn_get_revsort(ps_global->msgmap)
++ && !get_lflag(ps_global->mail_stream, NULL,
++ sp_first_unseen(m), MN_EXLD)
++ && (n = mn_raw2m(ps_global->msgmap,
++ sp_first_unseen(m))))
++ ? n
++ : first_sorted_flagged(F_UNSEEN|F_UNDEL, m, pc,
++ THREADING() ? 0 : FSF_SKIP_CHID);
++ mn_set_cur(ps_global->msgmap,
++ (MsgNo) MIN((int) flagged, (int) first_unseen));
++
++ }
++
++ break;
++
++ case IS_FIRST_IMPORTANT_OR_RECENT:
++
++ if(IS_NEWS(ps_global->mail_stream))
++ goto first_recent;
++
++ {
++ MsgNo flagged, first_recent;
++
++ flagged = first_sorted_flagged(F_FLAG|F_UNDEL, m, pc,
++ THREADING() ? 0 : FSF_SKIP_CHID);
++ first_recent = first_sorted_flagged(F_RECENT | F_UNSEEN
++ | F_UNDEL,
++ m, pc,
++ THREADING() ? 0 : FSF_SKIP_CHID);
++ mn_set_cur(ps_global->msgmap,
++ (MsgNo) MIN((int) flagged, (int) first_recent));
++ }
++
++ break;
++
++ case IS_FIRST:
++ mn_set_cur(ps_global->msgmap,
++ first_sorted_flagged(F_UNDEL, m, pc,
++ THREADING() ? 0 : FSF_SKIP_CHID));
++ break;
++
++ case IS_LAST:
++ mn_set_cur(ps_global->msgmap,
++ first_sorted_flagged(F_UNDEL, m, pc,
++ FSF_LAST | (THREADING() ? 0 : FSF_SKIP_CHID)));
++ break;
++
++ default:
++ panic("Unexpected incoming startup case");
++ break;
++
++ }
++ }
+diff -rc alpine-2.00/pith/mailcmd.h alpine-2.00.I.USE/pith/mailcmd.h
+*** alpine-2.00/pith/mailcmd.h 2008-07-09 22:01:13.000000000 -0700
+--- alpine-2.00.I.USE/pith/mailcmd.h 2011-02-07 20:33:44.000000000 -0800
+***************
+*** 41,46 ****
+--- 41,48 ----
+ #define DB_FROMTAB 0x02 /* opening because of TAB command */
+ #define DB_INBOXWOCNTXT 0x04 /* interpret inbox as one true inbox */
+
++ static MAILSTREAM *saved_stream;
++ static unsigned long rule_curpos = 0L;
+
+ /*
+ * generic "is aggregate message command?" test
+***************
+*** 53,58 ****
+--- 55,61 ----
+ void bogus_utf8_command(char *, char *);
+ int can_set_flag(struct pine *, char *, int);
+ void cmd_cancelled(char *);
++ void cmd_quota(struct pine *);
+ int cmd_delete(struct pine *, MSGNO_S *, int, char *(*)(struct pine *, MSGNO_S *));
+ int cmd_undelete(struct pine *, MSGNO_S *, int);
+ int cmd_expunge_work(MAILSTREAM *, MSGNO_S *);
+***************
+*** 61,71 ****
+ void expunge_and_close(MAILSTREAM *, char **, unsigned long);
+ void agg_select_all(MAILSTREAM *, MSGNO_S *, long *, int);
+ char *move_read_msgs(MAILSTREAM *, char *, char *, size_t, long);
+ char *move_read_incoming(MAILSTREAM *, CONTEXT_S *, char *, char **, char *, size_t);
+ void cross_delete_crossposts(MAILSTREAM *);
+ long zoom_index(struct pine *, MAILSTREAM *, MSGNO_S *, int);
+ int unzoom_index(struct pine *, MAILSTREAM *, MSGNO_S *);
+! int agg_text_select(MAILSTREAM *, MSGNO_S *, char, int, int, char *,
+ char *, SEARCHSET **);
+ int agg_flag_select(MAILSTREAM *, int, int, SEARCHSET **);
+ char *get_uname(char *, char *, int);
+--- 64,81 ----
+ void expunge_and_close(MAILSTREAM *, char **, unsigned long);
+ void agg_select_all(MAILSTREAM *, MSGNO_S *, long *, int);
+ char *move_read_msgs(MAILSTREAM *, char *, char *, size_t, long);
++ char *move_read_msgs_using_rules (MAILSTREAM *, char *, char *);
++ unsigned get_perfolder_startup_rule (MAILSTREAM *, int, char *);
++ void setup_threading_index_style (void);
++ void find_startup_position (int, MAILSTREAM *, long);
++ char *get_folder_to_save (MAILSTREAM *, long, char *);
+ char *move_read_incoming(MAILSTREAM *, CONTEXT_S *, char *, char **, char *, size_t);
++ MAILSTREAM *find_open_stream (void);
++ unsigned long rules_cursor_pos (MAILSTREAM *);
+ void cross_delete_crossposts(MAILSTREAM *);
+ long zoom_index(struct pine *, MAILSTREAM *, MSGNO_S *, int);
+ int unzoom_index(struct pine *, MAILSTREAM *, MSGNO_S *);
+! int agg_text_select(MAILSTREAM *, MSGNO_S *, char, char *, int, int, char *,
+ char *, SEARCHSET **);
+ int agg_flag_select(MAILSTREAM *, int, int, SEARCHSET **);
+ char *get_uname(char *, char *, int);
+diff -rc alpine-2.00/pith/mailindx.c alpine-2.00.I.USE/pith/mailindx.c
+*** alpine-2.00/pith/mailindx.c 2008-03-03 09:52:11.000000000 -0800
+--- alpine-2.00.I.USE/pith/mailindx.c 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 16,21 ****
+--- 16,22 ----
+
+ #include "../pith/headers.h"
+ #include "../pith/mailindx.h"
++ #include "../pith/pineelt.h"
+ #include "../pith/mailview.h"
+ #include "../pith/flag.h"
+ #include "../pith/icache.h"
+***************
+*** 39,44 ****
+--- 40,46 ----
+ #include "../pith/send.h"
+ #include "../pith/options.h"
+ #include "../pith/ablookup.h"
++ #include "../pith/rules.h"
+ #ifdef _WINDOWS
+ #include "../pico/osdep/mswin.h"
+ #endif
+***************
+*** 103,109 ****
+ void set_print_format(IELEM_S *, int, int);
+ void set_ielem_widths_in_field(IFIELD_S *);
+
+-
+ #define BIGWIDTH 2047
+
+
+--- 105,110 ----
+***************
+*** 227,232 ****
+--- 228,234 ----
+ case iSTime:
+ case iKSize:
+ case iSize:
++ case iSizeThread:
+ case iPrioAlpha:
+ (*answer)[column].req_width = 7;
+ break;
+***************
+*** 291,296 ****
+--- 293,301 ----
+ case iSDate:
+ case iSDateTime:
+ case iSDateTime24:
++ case iPrefDate:
++ case iPrefTime:
++ case iPrefDateTime:
+ {
+ /*
+ * Format a date to see how long it is.
+***************
+*** 299,312 ****
+ * of the translated yesterdays and friends but...
+ */
+ struct tm tm;
+ char ss[100];
+
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_year = 106;
+ tm.tm_mon = 11;
+ tm.tm_mday = 31;
+! our_strftime(ss, sizeof(ss), "%x", &tm);
+! (*answer)[column].req_width = MIN(MAX(9, utf8_width(ss)), 20);
+ }
+
+ (*answer)[column].monabb_width = monabb_width;
+--- 304,332 ----
+ * of the translated yesterdays and friends but...
+ */
+ struct tm tm;
++ int len = 20;
+ char ss[100];
+
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_year = 106;
+ tm.tm_mon = 11;
+ tm.tm_mday = 31;
+! tm.tm_hour = 3;
+! tm.tm_min = 23;
+! tm.tm_wday = 3;
+! switch((*answer)[column].ctype){
+! case iPrefTime:
+! our_strftime(ss, sizeof(ss), "%X", &tm);
+! break;
+! case iPrefDateTime:
+! our_strftime(ss, sizeof(ss), "%c", &tm);
+! len = 32;
+! break;
+! default:
+! our_strftime(ss, sizeof(ss), "%x", &tm);
+! break;
+! }
+! (*answer)[column].req_width = MIN(MAX(9, utf8_width(ss)), len);
+ }
+
+ (*answer)[column].monabb_width = monabb_width;
+***************
+*** 355,360 ****
+--- 375,387 ----
+ PAT_STATE pstate;
+ PAT_S *pat;
+ int we_set_it = 0;
++ char *rule;
++
++ if(rule = get_rule_result(FOR_INDEX, ps_global->cur_folder, V_INDEX_RULES)){
++ init_index_format(rule, &ps_global->index_disp_format);
++ fs_give((void **)&rule);
++ return;
++ }
+
+ if(ps_global->mail_stream && nonempty_patterns(rflags, &pstate)){
+ for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)){
+***************
+*** 428,441 ****
+ static INDEX_PARSE_T itokens[] = {
+ {"STATUS", iStatus, FOR_INDEX},
+ {"MSGNO", iMessNo, FOR_INDEX},
+! {"DATE", iDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+ {"FROMORTO", iFromTo, FOR_INDEX},
+ {"FROMORTONOTNEWS", iFromToNotNews, FOR_INDEX},
+ {"SIZE", iSize, FOR_INDEX},
+ {"SIZECOMMA", iSizeComma, FOR_INDEX},
+ {"SIZENARROW", iSizeNarrow, FOR_INDEX},
+ {"KSIZE", iKSize, FOR_INDEX},
+! {"SUBJECT", iSubject, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+ {"FULLSTATUS", iFStatus, FOR_INDEX},
+ {"IMAPSTATUS", iIStatus, FOR_INDEX},
+ {"SHORTIMAPSTATUS", iSIStatus, FOR_INDEX},
+--- 455,469 ----
+ static INDEX_PARSE_T itokens[] = {
+ {"STATUS", iStatus, FOR_INDEX},
+ {"MSGNO", iMessNo, FOR_INDEX},
+! {"DATE", iDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"FROMORTO", iFromTo, FOR_INDEX},
+ {"FROMORTONOTNEWS", iFromToNotNews, FOR_INDEX},
+ {"SIZE", iSize, FOR_INDEX},
+ {"SIZECOMMA", iSizeComma, FOR_INDEX},
++ {"SIZETHREAD", iSizeThread, FOR_INDEX},
+ {"SIZENARROW", iSizeNarrow, FOR_INDEX},
+ {"KSIZE", iKSize, FOR_INDEX},
+! {"SUBJECT", iSubject, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_TRIM},
+ {"FULLSTATUS", iFStatus, FOR_INDEX},
+ {"IMAPSTATUS", iIStatus, FOR_INDEX},
+ {"SHORTIMAPSTATUS", iSIStatus, FOR_INDEX},
+***************
+*** 444,498 ****
+ {"SUBJECTTEXT", iSubjectText, FOR_INDEX},
+ {"SUBJKEYTEXT", iSubjKeyText, FOR_INDEX},
+ {"SUBJKEYINITTEXT", iSubjKeyInitText, FOR_INDEX},
+! {"OPENINGTEXT", iOpeningText, FOR_INDEX},
+! {"OPENINGTEXTNQ", iOpeningTextNQ, FOR_INDEX},
+! {"KEY", iKey, FOR_INDEX},
+! {"KEYINIT", iKeyInit, FOR_INDEX},
+ {"DESCRIPSIZE", iDescripSize, FOR_INDEX},
+ {"ATT", iAtt, FOR_INDEX},
+ {"SCORE", iScore, FOR_INDEX},
+ {"PRIORITY", iPrio, FOR_INDEX},
+ {"PRIORITYALPHA", iPrioAlpha, FOR_INDEX},
+! {"PRIORITY!", iPrioBang, FOR_INDEX},
+! {"LONGDATE", iLDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SHORTDATE1", iS1Date, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SHORTDATE2", iS2Date, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SHORTDATE3", iS3Date, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SHORTDATE4", iS4Date, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"DATEISO", iDateIso, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SHORTDATEISO", iDateIsoS, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATE", iSDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTTIME", iSTime, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATEISO", iSDateIso, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATESHORTISO",iSDateIsoS, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATES1", iSDateS1, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATES2", iSDateS2, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATES3", iSDateS3, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATES4", iSDateS4, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATETIME", iSDateTime, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATETIMEISO",iSDateTimeIso, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATETIMESHORTISO",iSDateTimeIsoS,FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATETIMES1", iSDateTimeS1, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATETIMES2", iSDateTimeS2, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATETIMES3", iSDateTimeS3, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATETIMES4", iSDateTimeS4, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATETIME24", iSDateTime24, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATETIMEISO24", iSDateTimeIso24,FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATETIMESHORTISO24",iSDateTimeIsoS24,FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATETIMES124", iSDateTimeS124, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATETIMES224", iSDateTimeS224, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATETIMES324", iSDateTimeS324, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SMARTDATETIMES424", iSDateTimeS424, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"TIME24", iTime24, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"TIME12", iTime12, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"TIMEZONE", iTimezone, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"MONTHABBREV", iMonAbb, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"DAYOFWEEKABBREV", iDayOfWeekAbb, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"DAYOFWEEK", iDayOfWeek, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"FROM", iFrom, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"TO", iTo, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"SENDER", iSender, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"CC", iCc, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+ {"RECIPS", iRecips, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+ {"NEWS", iNews, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+ {"TOANDNEWS", iToAndNews, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+--- 472,529 ----
+ {"SUBJECTTEXT", iSubjectText, FOR_INDEX},
+ {"SUBJKEYTEXT", iSubjKeyText, FOR_INDEX},
+ {"SUBJKEYINITTEXT", iSubjKeyInitText, FOR_INDEX},
+! {"OPENINGTEXT", iOpeningText, FOR_INDEX|FOR_RULE|FOR_SAVE|FOR_TRIM},
+! {"OPENINGTEXTNQ", iOpeningTextNQ, FOR_INDEX|FOR_RULE|FOR_SAVE|FOR_TRIM},
+! {"KEY", iKey, FOR_INDEX|FOR_RULE|FOR_SAVE|FOR_COMPOSE},
+! {"KEYINIT", iKeyInit, FOR_INDEX|FOR_RULE|FOR_SAVE|FOR_COMPOSE},
+ {"DESCRIPSIZE", iDescripSize, FOR_INDEX},
+ {"ATT", iAtt, FOR_INDEX},
+ {"SCORE", iScore, FOR_INDEX},
+ {"PRIORITY", iPrio, FOR_INDEX},
+ {"PRIORITYALPHA", iPrioAlpha, FOR_INDEX},
+! {"PRIORITY!", iPrioBang, FOR_INDEX},
+! {"LONGDATE", iLDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SHORTDATE1", iS1Date, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SHORTDATE2", iS2Date, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SHORTDATE3", iS3Date, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SHORTDATE4", iS4Date, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"DATEISO", iDateIso, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SHORTDATEISO", iDateIsoS, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATE", iSDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTTIME", iSTime, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATEISO", iSDateIso, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATESHORTISO",iSDateIsoS, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATES1", iSDateS1, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATES2", iSDateS2, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATES3", iSDateS3, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATES4", iSDateS4, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATETIME", iSDateTime, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATETIMEISO",iSDateTimeIso, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATETIMESHORTISO",iSDateTimeIsoS,FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATETIMES1", iSDateTimeS1, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATETIMES2", iSDateTimeS2, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATETIMES3", iSDateTimeS3, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATETIMES4", iSDateTimeS4, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATETIME24", iSDateTime24, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATETIMEISO24", iSDateTimeIso24,FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATETIMESHORTISO24",iSDateTimeIsoS24,FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATETIMES124", iSDateTimeS124, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATETIMES224", iSDateTimeS224, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATETIMES324", iSDateTimeS324, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"SMARTDATETIMES424", iSDateTimeS424, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"TIME24", iTime24, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"TIME12", iTime12, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"TIMEZONE", iTimezone, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"MONTHABBREV", iMonAbb, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"DAYOFWEEKABBREV", iDayOfWeekAbb, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"DAYOFWEEK", iDayOfWeek, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"FROM", iFrom, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_COMPOSE},
+! {"TO", iTo, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_COMPOSE},
+! {"SENDER", iSender, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"CC", iCc, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_SAVE|FOR_SAVE},
+! {"ADDRESSTO", iAddressTo, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"ADDRESSCC", iAddressCc, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"ADDRESSRECIPS", iAddressRecip, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"RECIPS", iRecips, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+ {"NEWS", iNews, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+ {"TOANDNEWS", iToAndNews, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+***************
+*** 501,559 ****
+ {"NEWSANDRECIPS", iNewsAndRecips, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+ {"MSGID", iMsgID, FOR_REPLY_INTRO|FOR_TEMPLATE},
+ {"CURNEWS", iCurNews, FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"DAYDATE", iRDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"PREFDATE", iPrefDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"PREFTIME", iPrefTime, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"PREFDATETIME", iPrefDateTime, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"DAY", iDay, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"DAYORDINAL", iDayOrdinal, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"DAY2DIGIT", iDay2Digit, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"MONTHLONG", iMonLong, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"MONTH", iMon, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"MONTH2DIGIT", iMon2Digit, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"YEAR", iYear, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"YEAR2DIGIT", iYear2Digit, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"ADDRESS", iAddress, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+ {"MAILBOX", iMailbox, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+ {"ROLENICK", iRoleNick, FOR_REPLY_INTRO|FOR_TEMPLATE},
+ {"INIT", iInit, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"CURDATE", iCurDate, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"CURDATEISO", iCurDateIso, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"CURDATEISOS", iCurDateIsoS, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"CURTIME24", iCurTime24, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"CURTIME12", iCurTime12, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"CURDAY", iCurDay, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"CURDAY2DIGIT", iCurDay2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"CURDAYOFWEEK", iCurDayOfWeek, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+ {"CURDAYOFWEEKABBREV", iCurDayOfWeekAbb,
+! FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"CURMONTH", iCurMon, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"CURMONTH2DIGIT", iCurMon2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"CURMONTHLONG", iCurMonLong, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"CURMONTHABBREV", iCurMonAbb, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"CURYEAR", iCurYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"CURYEAR2DIGIT", iCurYear2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"CURPREFDATE", iCurPrefDate, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"CURPREFTIME", iCurPrefTime, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+ {"CURPREFDATETIME", iCurPrefDateTime,
+! FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"LASTMONTH", iLstMon, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"LASTMONTH2DIGIT", iLstMon2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"LASTMONTHLONG", iLstMonLong, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"LASTMONTHABBREV", iLstMonAbb, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"LASTMONTHYEAR", iLstMonYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+ {"LASTMONTHYEAR2DIGIT", iLstMonYear2Digit,
+! FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"LASTYEAR", iLstYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+! {"LASTYEAR2DIGIT", iLstYear2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+ {"HEADER", iHeader, FOR_INDEX},
+ {"TEXT", iText, FOR_INDEX},
+ {"ARROW", iArrow, FOR_INDEX},
+ {"NEWLINE", iNewLine, FOR_REPLY_INTRO},
+ {"CURSORPOS", iCursorPos, FOR_TEMPLATE},
+ {NULL, iNothing, FOR_NOTHING}
+ };
+
+ INDEX_PARSE_T *
+ itoken(int i)
+ {
+--- 532,613 ----
+ {"NEWSANDRECIPS", iNewsAndRecips, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+ {"MSGID", iMsgID, FOR_REPLY_INTRO|FOR_TEMPLATE},
+ {"CURNEWS", iCurNews, FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"DAYDATE", iRDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"PREFDATE", iPrefDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"PREFTIME", iPrefTime, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"PREFDATETIME", iPrefDateTime, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"DAY", iDay, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"DAYORDINAL", iDayOrdinal, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"DAY2DIGIT", iDay2Digit, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"MONTHLONG", iMonLong, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"MONTH", iMon, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"MONTH2DIGIT", iMon2Digit, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"YEAR", iYear, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"YEAR2DIGIT", iYear2Digit, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+! {"ADDRESS", iAddress, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE},
+ {"MAILBOX", iMailbox, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+ {"ROLENICK", iRoleNick, FOR_REPLY_INTRO|FOR_TEMPLATE},
+ {"INIT", iInit, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+! {"CURDATE", iCurDate, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"CURDATEISO", iCurDateIso, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"CURDATEISOS", iCurDateIsoS, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"CURTIME24", iCurTime24, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"CURTIME12", iCurTime12, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"CURDAY", iCurDay, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"CURDAY2DIGIT", iCurDay2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"CURDAYOFWEEK", iCurDayOfWeek, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"CURDAYOFWEEKABBREV", iCurDayOfWeekAbb,
+! FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"CURMONTH", iCurMon, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"CURMONTH2DIGIT", iCurMon2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"CURMONTHLONG", iCurMonLong, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"CURMONTHABBREV", iCurMonAbb, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"CURYEAR", iCurYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"CURYEAR2DIGIT", iCurYear2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"CURPREFDATE", iCurPrefDate, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"CURPREFTIME", iCurPrefTime, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"CURPREFDATETIME", iCurPrefDateTime,
+! FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"LASTMONTH", iLstMon, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"LASTMONTH2DIGIT", iLstMon2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"LASTMONTHLONG", iLstMonLong, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"LASTMONTHABBREV", iLstMonAbb, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"LASTMONTHYEAR", iLstMonYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"LASTMONTHYEAR2DIGIT", iLstMonYear2Digit,
+! FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"LASTYEAR", iLstYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+! {"LASTYEAR2DIGIT", iLstYear2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"HEADER", iHeader, FOR_INDEX},
+ {"TEXT", iText, FOR_INDEX},
+ {"ARROW", iArrow, FOR_INDEX},
+ {"NEWLINE", iNewLine, FOR_REPLY_INTRO},
+ {"CURSORPOS", iCursorPos, FOR_TEMPLATE},
++ {"NICK", iNick, FOR_RULE|FOR_SAVE},
++ {"FOLDER", iFolder, FOR_RULE|FOR_SAVE|FOR_FOLDER},
++ {"ROLE", iRole, FOR_RULE|FOR_RESUB|FOR_TRIM|FOR_TEMPLATE},
++ {"PROCID", iProcid, FOR_RULE|FOR_RESUB|FOR_FLAG|FOR_COMPOSE|FOR_TRIM|FOR_TEMPLATE},
++ {"PKEY", iPkey, FOR_RULE|FOR_KEY},
++ {"SCREEN", iScreen, FOR_RULE|FOR_KEY},
++ {"FLAG", iFlag, FOR_RULE|FOR_SAVE|FOR_FLAG},
++ {"COLLECTION", iCollection, FOR_RULE|FOR_SAVE|FOR_COMPOSE|FOR_FOLDER},
++ {"BCC", iBcc, FOR_COMPOSE|FOR_RULE},
++ {"LCC", iLcc, FOR_COMPOSE|FOR_RULE},
++ {"FORWARDFROM", iFfrom, FOR_COMPOSE|FOR_RULE},
++ {"FORWARDADDRESS", iFadd, FOR_COMPOSE|FOR_RULE},
+ {NULL, iNothing, FOR_NOTHING}
+ };
+
++ INDEX_PARSE_T itokensinv[sizeof(itokens)/sizeof(itokens[0])];
++
++ void
++ inverse_itokens(void)
++ {
++ INDEX_PARSE_T *pt;
++ for (pt = itokens; pt->name; pt++)
++ itokensinv[pt->ctype].ctype = pt - itokens;
++
++ }
++
+ INDEX_PARSE_T *
+ itoken(int i)
+ {
+***************
+*** 913,919 ****
+ iSDateTimeS1, iSDateTimeS2, iSDateTimeS3, iSDateTimeS4,
+ iSDateTimeIso24, iSDateTimeIsoS24,
+ iSDateTimeS124, iSDateTimeS224, iSDateTimeS324, iSDateTimeS424,
+! iSize, iSizeComma, iSizeNarrow, iKSize, iDescripSize,
+ iPrio, iPrioBang, iPrioAlpha,
+ iAtt, iTime24, iTime12, iTimezone, iMonAbb, iYear, iYear2Digit,
+ iDay2Digit, iMon2Digit, iDayOfWeekAbb, iScore, iMonLong, iDayOfWeek
+--- 967,973 ----
+ iSDateTimeS1, iSDateTimeS2, iSDateTimeS3, iSDateTimeS4,
+ iSDateTimeIso24, iSDateTimeIsoS24,
+ iSDateTimeS124, iSDateTimeS224, iSDateTimeS324, iSDateTimeS424,
+! iSize, iSizeComma, iSizeNarrow, iKSize, iDescripSize, iSizeThread,
+ iPrio, iPrioBang, iPrioAlpha,
+ iAtt, iTime24, iTime12, iTimezone, iMonAbb, iYear, iYear2Digit,
+ iDay2Digit, iMon2Digit, iDayOfWeekAbb, iScore, iMonLong, iDayOfWeek
+***************
+*** 1105,1110 ****
+--- 1159,1165 ----
+ case iTime12:
+ case iSize:
+ case iKSize:
++ case iSizeThread:
+ cdesc->actual_length = 7;
+ cdesc->adjustment = Right;
+ break;
+***************
+*** 1198,1204 ****
+ cdesc->ctype != iNothing;
+ cdesc++)
+ if(cdesc->ctype == iSize || cdesc->ctype == iKSize ||
+! cdesc->ctype == iSizeNarrow ||
+ cdesc->ctype == iSizeComma || cdesc->ctype == iDescripSize){
+ if(cdesc->actual_length == 0){
+ if((fix=cdesc->width) > 0){ /* had this reserved */
+--- 1253,1259 ----
+ cdesc->ctype != iNothing;
+ cdesc++)
+ if(cdesc->ctype == iSize || cdesc->ctype == iKSize ||
+! cdesc->ctype == iSizeNarrow || cdesc->ctype == iSizeThread ||
+ cdesc->ctype == iSizeComma || cdesc->ctype == iDescripSize){
+ if(cdesc->actual_length == 0){
+ if((fix=cdesc->width) > 0){ /* had this reserved */
+***************
+*** 1581,1590 ****
+
+ /* find next thread which is visible */
+ do{
+ if(mn_get_revsort(msgmap) && thrd->prevthd)
+ thrd = fetch_thread(stream, thrd->prevthd);
+! else if(!mn_get_revsort(msgmap) && thrd->nextthd)
+! thrd = fetch_thread(stream, thrd->nextthd);
+ else
+ thrd = NULL;
+ } while(thrd
+--- 1636,1647 ----
+
+ /* find next thread which is visible */
+ do{
++ unsigned long branch;
+ if(mn_get_revsort(msgmap) && thrd->prevthd)
+ thrd = fetch_thread(stream, thrd->prevthd);
+! /*branch = get_branch(stream,thrd)*/
+! else if(!mn_get_revsort(msgmap) && thrd->branch)
+! thrd = fetch_thread(stream, thrd->branch);
+ else
+ thrd = NULL;
+ } while(thrd
+***************
+*** 1970,1975 ****
+--- 2027,2033 ----
+ ICE_S *ice, **icep;
+ IFIELD_S *ifield;
+ IELEM_S *ielem;
++ COLOR_PAIR *color = NULL;
+ struct variable *vars = ps_global->vars;
+
+ dprint((8, "=== format_index_line(msgno=%ld,rawno=%ld) ===\n",
+***************
+*** 1995,2007 ****
+ */
+ ice = copy_ice(ice);
+
+ /* is this a collapsed thread index line? */
+! if(!idata->bogus && THREADING()){
+! thrd = fetch_thread(idata->stream, idata->rawno);
+! collapsed = thrd && thrd->next
+! && get_lflag(idata->stream, NULL,
+! idata->rawno, MN_COLL);
+! }
+
+ /* calculate contents of the required fields */
+ for(cdesc = ps_global->index_disp_format; cdesc->ctype != iNothing; cdesc++)
+--- 2053,2062 ----
+ */
+ ice = copy_ice(ice);
+
++ thrd = fetch_thread(idata->stream, idata->rawno);
+ /* is this a collapsed thread index line? */
+! if(!idata->bogus && THREADING())
+! collapsed = thrd && thread_is_kolapsed(ps_global, idata->stream, ps_global->msgmap, idata->rawno);
+
+ /* calculate contents of the required fields */
+ for(cdesc = ps_global->index_disp_format; cdesc->ctype != iNothing; cdesc++)
+***************
+*** 2433,2438 ****
+--- 2488,2511 ----
+ from_str(cdesc->ctype, idata, str, sizeof(str), ice);
+ break;
+
++ case iAddressTo:
++ case iAddressCc:
++ case iAddressRecip:
++ {ENVELOPE *env;
++ int we_clear;
++ env = rules_fetchenvelope(idata, &we_clear);
++ sprintf(str, "%-*.*s", ifield->width, ifield->width,
++ detoken_src((cdesc->ctype == iAddressTo
++ ? "_ADDRESSTO_"
++ : (cdesc->ctype == iAddressCc
++ ? "_ADRESSCC_"
++ : "_ADRESSRECIPS_")), FOR_INDEX,
++ env, NULL, NULL, NULL));
++ if(we_clear)
++ mail_free_envelope(&env);
++ }
++ break;
++
+ case iTo:
+ if(((field = ((addr = fetch_to(idata))
+ ? "To"
+***************
+*** 2499,2505 ****
+--- 2572,2601 ----
+
+ break;
+
++ case iSizeThread:
++ if (!THREADING()){
++ goto getsize;
++ } else if (collapsed){
++ l = count_flags_in_thread(idata->stream, thrd, F_NONE);
++ snprintf(str, sizeof(str), "(%lu)", l);
++ }
++ else{
++ thrd = fetch_thread(idata->stream, idata->rawno);
++ if(!thrd)
++ snprintf(str, sizeof(str), "%s", "Error");
++ else{
++ long lengthb;
++ lengthb = get_length_branch(idata->stream, idata->rawno);
++ if (lengthb > 0L)
++ snprintf(str, sizeof(str), "(%lu)", lengthb);
++ else
++ snprintf(str,sizeof(str), "%s", " ");
++ }
++ }
++ break;
++
+ case iSize:
++ getsize:
+ /* 0 ... 9999 */
+ if((l = fetch_size(idata)) < 10*1000L)
+ snprintf(str, sizeof(str), "(%lu)", l);
+***************
+*** 2753,2759 ****
+ if(first_text){
+ strncpy(str, first_text, BIGWIDTH);
+ str[BIGWIDTH] = '\0';
+- fs_give((void **) &first_text);
+ }
+ }
+
+--- 2849,2854 ----
+***************
+*** 2913,2918 ****
+--- 3008,3021 ----
+ if(!ifield->ielem){
+ ielem = new_ielem(&ifield->ielem);
+
++ if(color = hdr_color(itokens[itokensinv[cdesc->ctype].ctype].name, NULL, ps_global->index_token_colors)){
++ if(pico_usingcolor()){
++ ielem->color = new_color_pair(color->fg, color->bg);
++ ielem->type = eTypeCol;
++ }
++ free_color_pair(&color);
++ }
++
+ ielem->freedata = 1;
+ ielem->data = cpystr(str);
+ ielem->datalen = strlen(str);
+***************
+*** 3670,3675 ****
+--- 3773,3829 ----
+ gf_io_t pc;
+ long partial_fetch_len = 0L;
+ SEARCHSET *ss, **sset;
++ MESSAGECACHE *mc;
++ PINELT_S *pelt;
++
++ /* we cache the result we get from this function, so that we do not have to
++ * refetch the text in case there is a change. We could cache in the envelope
++ * but c-client does not have a special field for that, nor we want to use the
++ * sparep pointer, since there could be other uses for sparep later, and even
++ * if we add a pointer to the ENVELOPE structure, we would be caching the same
++ * text twice (one in a private pointer, and the new pointer) and that would
++ * not make sense. Instead we will use an elt for this
++ */
++
++ if((mc = mail_elt(idata->stream, idata->rawno))
++ && ((pelt = (PINELT_S *) mc->sparep) == NULL)){
++ pelt = (PINELT_S *) fs_get(sizeof(PINELT_S));
++ memset(pelt, 0, sizeof(PINELT_S));
++ }
++
++ /* If there were no rules, we would just return the firsttext
++ * as cached in the pelt pointer, but if we are here and there
++ * is a rule, and the firsttext that is cached changes as a
++ * result of the rule, we need to refetch the text and process it
++ * again
++ */
++
++ if(pelt && pelt->firsttextraw != NULL){
++ char buf[4*1024+1], ftext[6*1024+1], *rule_result;
++ strncpy(buf, pelt->firsttextraw, sizeof(buf));
++ buf[sizeof(buf)-1] = '\0';
++ if(rule_result = find_value((delete_quotes
++ ? "_OPENINGTEXTNQ_" : "_OPENINGTEXT_"),
++ buf, PROCESS_SP, idata, 4)){
++ collspaces(rule_result);
++ strncpy(buf, rule_result, sizeof(buf));
++ buf[sizeof(buf) - 1] = '\0';
++ fs_give((void **) &rule_result);
++ }
++ ftext[0] = '\0';
++ iutf8ncpy(ftext, buf, sizeof(ftext));
++ ftext[sizeof(ftext)-1] = '\0';
++ removing_trailing_white_space(ftext);
++ if(!strcmp(ftext, pelt->firsttext)) /* same as last pass */
++ return(pelt->firsttext);
++ if(strlen(pelt->firsttextraw) > 256 /* not the same, but long enough */
++ && utf8_width(ftext) >= 50){
++ fs_give((void **)&pelt->firsttext);
++ pelt->firsttext = cpystr(ftext);
++ return pelt->firsttext;
++ }
++ fs_give((void **)&pelt->firsttext); /* do it again */
++ }
+
+ try_again:
+
+***************
+*** 3706,3712 ****
+ && ALLOWED_SUBTYPE(subtype))){
+
+ if((so = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){
+! char buf[1025], *p;
+ unsigned char c;
+ int success;
+ int one_space_done = 0;
+--- 3860,3866 ----
+ && ALLOWED_SUBTYPE(subtype))){
+
+ if((so = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){
+! char buf[4*1024+1], rawbuf[6*1024+1], *p;
+ unsigned char c;
+ int success;
+ int one_space_done = 0;
+***************
+*** 3763,3769 ****
+--- 3917,3939 ----
+
+ if(p > buf){
+ size_t l;
++ ENVELOPE *env;
++ char *rule_result;
+
++ if(pelt && pelt->firsttextraw)
++ fs_give((void **)&pelt->firsttextraw);
++ iutf8ncpy(rawbuf, buf, sizeof(rawbuf));
++ rawbuf[sizeof(rawbuf)-1] = '\0';
++ removing_trailing_white_space(rawbuf);
++ pelt->firsttextraw = cpystr(rawbuf);
++ if(rule_result = find_value((delete_quotes
++ ? "_OPENINGTEXTNQ_" : "_OPENINGTEXT_"),
++ buf, PROCESS_SP, idata, 4)){
++ collspaces(rule_result);
++ strncpy(buf, rule_result, sizeof(buf));
++ buf[sizeof(buf) - 1] = '\0';
++ fs_give((void **) &rule_result);
++ }
+ l = strlen(buf);
+ l += 100;
+ firsttext = fs_get((l+1) * sizeof(char));
+***************
+*** 3787,3792 ****
+--- 3957,3964 ----
+ goto try_again;
+ }
+ }
++ if(mc && pelt)
++ pelt->firsttext = firsttext;
+ }
+ }
+ }
+***************
+*** 4271,4276 ****
+--- 4443,4449 ----
+ tm.tm_mday = MIN(MAX(d.day, 1), 31);
+ tm.tm_hour = MIN(MAX(d.hour, 0), 23);
+ tm.tm_min = MIN(MAX(d.minute, 0), 59);
++ tm.tm_wday = MIN(MAX(d.wkday, 0), 6);
+ tmptr = &tm;
+ }
+
+***************
+*** 5226,5235 ****
+ {
+ char *subject, *origsubj, *origstr, *rawsubj, *sptr = NULL;
+ char *p, *border, *q = NULL, *free_subj = NULL;
+! char *sp;
+ size_t len;
+ int width = -1;
+! int depth = 0, mult = 2;
+ int save;
+ int do_subj = 0, truncated_tree = 0;
+ PINETHRD_S *thd, *thdorig;
+--- 5399,5408 ----
+ {
+ char *subject, *origsubj, *origstr, *rawsubj, *sptr = NULL;
+ char *p, *border, *q = NULL, *free_subj = NULL;
+! char *sp, *rule_result;
+ size_t len;
+ int width = -1;
+! int depth = 0, mult = 2, collapsed, i, we_clear = 0;
+ int save;
+ int do_subj = 0, truncated_tree = 0;
+ PINETHRD_S *thd, *thdorig;
+***************
+*** 5283,5289 ****
+ * origsubj is the original subject but it has been decoded. We need
+ * to free it at the end of this routine.
+ */
+!
+
+ /*
+ * prepend_keyword will put the keyword stuff before the subject
+--- 5456,5468 ----
+ * origsubj is the original subject but it has been decoded. We need
+ * to free it at the end of this routine.
+ */
+! if (rule_result = find_value("_SUBJECT_", origsubj, PROCESS_SP, idata, 4)){
+! if(origsubj)
+! fs_give((void **)&origsubj);
+! we_clear++;
+! origsubj = cpystr(rule_result);
+! fs_give((void **)&rule_result);
+! }
+
+ /*
+ * prepend_keyword will put the keyword stuff before the subject
+***************
+*** 5371,5380 ****
+
+ if(pith_opt_condense_thread_cue)
+ width = (*pith_opt_condense_thread_cue)(thd, ice, &str, &strsize, width,
+! thd && thd->next
+! && get_lflag(idata->stream,
+! NULL,idata->rawno,
+! MN_COLL));
+
+ /*
+ * width is < available strsize and
+--- 5550,5557 ----
+
+ if(pith_opt_condense_thread_cue)
+ width = (*pith_opt_condense_thread_cue)(thd, ice, &str, &strsize, width,
+! this_thread_is_kolapsed(ps_global, idata->stream, ps_global->msgmap, idata->rawno) &&
+! (count_thread(ps_global,idata->stream, ps_global->msgmap, idata->rawno) != 1));
+
+ /*
+ * width is < available strsize and
+***************
+*** 5724,5729 ****
+--- 5901,5909 ----
+
+ if(free_subj)
+ fs_give((void **) &free_subj);
++
++ if (we_clear && origsubj)
++ fs_give((void **)&origsubj);
+ }
+
+
+***************
+*** 6002,6012 ****
+ border = str + width;
+ if(pith_opt_condense_thread_cue)
+ width = (*pith_opt_condense_thread_cue)(thd, ice, &str, &strsize, width,
+! thd && thd->next
+! && get_lflag(idata->stream,
+! NULL,idata->rawno,
+! MN_COLL));
+!
+ fptr = str;
+
+ if(thd)
+--- 6182,6189 ----
+ border = str + width;
+ if(pith_opt_condense_thread_cue)
+ width = (*pith_opt_condense_thread_cue)(thd, ice, &str, &strsize, width,
+! this_thread_is_kolapsed(ps_global, idata->stream, ps_global->msgmap, idata->rawno) &&
+! (count_thread(ps_global,idata->stream, ps_global->msgmap, idata->rawno) != 1));
+ fptr = str;
+
+ if(thd)
+***************
+*** 6092,6107 ****
+ ? "To"
+ : (addr = fetch_cc(idata))
+ ? "Cc"
+! : NULL))
+! && set_index_addr(idata, field, addr, "To: ",
+! strsize-1, fptr))
+! break;
+
+ if(ctype == iFromTo &&
+ (newsgroups = fetch_newsgroups(idata)) &&
+ *newsgroups){
+! snprintf(fptr, strsize, "To: %-*.*s", strsize-1-4, strsize-1-4,
+! newsgroups);
+ break;
+ }
+
+--- 6269,6301 ----
+ ? "To"
+ : (addr = fetch_cc(idata))
+ ? "Cc"
+! : NULL))){
+! char *rule_result;
+! rule_result = find_value("_FROM_", NULL, 0, idata, 1);
+! if (!rule_result)
+! set_index_addr(idata, field, addr, "To: ",
+! strsize-1, fptr);
+! else{
+! sprintf(str, "%-*.*s", strsize-1, strsize-1,
+! rule_result);
+! fs_give((void **)&rule_result);
+! }
+
++ break;
++ }
+ if(ctype == iFromTo &&
+ (newsgroups = fetch_newsgroups(idata)) &&
+ *newsgroups){
+! char *rule_result;
+! rule_result = find_value("_FROM_", NULL, 0, idata, 1);
+! if (!rule_result)
+! sprintf(str, "To: %-*.*s", strsize-1-4,
+! strsize-1-4, newsgroups);
+! else{
+! sprintf(str, "%-*.*s", strsize-1, strsize-1,
+! rule_result);
+! fs_give((void **)&rule_result);
+! }
+ break;
+ }
+
+***************
+*** 6114,6120 ****
+ break;
+
+ case iFrom:
+! set_index_addr(idata, "From", fetch_from(idata), NULL, strsize-1, fptr);
+ break;
+
+ case iAddress:
+--- 6308,6322 ----
+ break;
+
+ case iFrom:
+! { char *rule_result;
+! rule_result = find_value("_FROM_", NULL, 0, idata, 4);
+! if (!rule_result)
+! set_index_addr(idata, "From", fetch_from(idata), NULL, strsize-1, fptr);
+! else{
+! sprintf(str, "%-*.*s", strsize-1, strsize-1, rule_result);
+! fs_give((void **)&rule_result);
+! }
+! }
+ break;
+
+ case iAddress:
+***************
+*** 6411,6413 ****
+--- 6613,6676 ----
+ }
+ }
+ }
++
++ void
++ setup_threading_display_style(void)
++ {
++ RULE_RESULT *rule;
++ NAMEVAL_S *v;
++ int i;
++
++ rule = get_result_rule(V_THREAD_DISP_STYLE_RULES, FOR_THREAD, NULL);
++ if (rule || ps_global->VAR_THREAD_DISP_STYLE){
++ for(i = 0; v = thread_disp_styles(i); i++)
++ if(!strucmp(rule ? rule->result : ps_global->VAR_THREAD_DISP_STYLE,
++ rule ? (v ? v->name : "" ) : S_OR_L(v))){
++ ps_global->thread_disp_style = v->value;
++ break;
++ }
++ if (rule){
++ if (rule->result)
++ fs_give((void **)&rule->result);
++ fs_give((void **)&rule);
++ }
++ }
++ }
++
++ char *
++ find_value(char *token, char *use_this, int flag, INDEXDATA_S *idata, int nfcn)
++ {
++ int n = 0, i, rule_context, we_clear;
++ char *rule_result = NULL, **list;
++ ENVELOPE *env;
++ RULELIST *rule;
++ RULE_S *prule;
++
++ env = rules_fetchenvelope(idata, &we_clear);
++ if(env && env->sparep)
++ fs_give((void **)&env->sparep);
++ if(we_clear)
++ mail_free_envelope(&env);
++ if(rule = get_rulelist_from_code(V_REPLACE_RULES, ps_global->rule_list)){
++ list = functions_for_token(token);
++ while(rule_result == NULL && (prule = get_rule(rule,n++))){
++ rule_context = 0;
++ if (prule->action->token && !strcmp(prule->action->token, token)){
++ for (i = 0; i < nfcn; i++)
++ if(list[i+1] && !strcmp(prule->action->function, list[i+1]))
++ rule_context |= context_for_function(list[i+1]);
++ if (rule_context){
++ env = rules_fetchenvelope(idata, &we_clear);
++ if(use_this)
++ env->sparep = get_sparep_for_rule(use_this, flag);
++ rule_result = process_rule(prule, rule_context, env);
++ if(env->sparep)
++ free_sparep_for_rule(&env->sparep);
++ if(we_clear)
++ mail_free_envelope(&env);
++ }
++ }
++ }
++ }
++ return rule_result;
++ }
+diff -rc alpine-2.00/pith/mailindx.h alpine-2.00.I.USE/pith/mailindx.h
+*** alpine-2.00/pith/mailindx.h 2008-02-01 10:42:29.000000000 -0800
+--- alpine-2.00.I.USE/pith/mailindx.h 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 29,34 ****
+--- 29,37 ----
+
+
+ /* exported prototypes */
++ SortOrder translate (char *, int);
++ char *find_value (char *, char *, int, INDEXDATA_S *, int);
++ void setup_threading_display_style (void);
+ int msgline_hidden(MAILSTREAM *, MSGNO_S *, long, int);
+ void adjust_cur_to_visible(MAILSTREAM *, MSGNO_S *);
+ unsigned long line_hash(char *);
+***************
+*** 36,41 ****
+--- 39,45 ----
+ void free_index_format(INDEX_COL_S **);
+ void reset_index_format(void);
+ INDEX_PARSE_T *itoktype(char *, int);
++ void inverse_itokens(void);
+ char *prepend_keyword_subject(MAILSTREAM *, long, char *, SubjKW, IELEM_S **, char *);
+ int get_index_line_color(MAILSTREAM *, SEARCHSET *, PAT_STATE **, COLOR_PAIR **);
+ void setup_for_index_index_screen(void);
+diff -rc alpine-2.00/pith/mailview.c alpine-2.00.I.USE/pith/mailview.c
+*** alpine-2.00/pith/mailview.c 2008-07-11 16:20:32.000000000 -0700
+--- alpine-2.00.I.USE/pith/mailview.c 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 51,57 ****
+ #include "../pith/escapes.h"
+ #include "../pith/keyword.h"
+ #include "../pith/smime.h"
+!
+
+ #define FBUF_LEN (50)
+
+--- 51,60 ----
+ #include "../pith/escapes.h"
+ #include "../pith/keyword.h"
+ #include "../pith/smime.h"
+! #include "../pith/osdep/color.h"
+! #include "../pico/estruct.h"
+! #include "../pico/pico.h"
+! #include "../pico/efunc.h"
+
+ #define FBUF_LEN (50)
+
+***************
+*** 281,289 ****
+ if((flgs & FM_DISPLAY)
+ && !(flgs & FM_NOCOLOR)
+ && pico_usingcolor()
+ && ps_global->VAR_SIGNATURE_FORE_COLOR
+ && ps_global->VAR_SIGNATURE_BACK_COLOR){
+! gf_link_filter(gf_line_test, gf_line_test_opt(color_signature, &is_in_sig));
+ }
+
+ if((flgs & FM_DISPLAY)
+--- 284,300 ----
+ if((flgs & FM_DISPLAY)
+ && !(flgs & FM_NOCOLOR)
+ && pico_usingcolor()
++ && ps_global->VAR_SPECIAL_TEXT_FORE_COLOR
++ && ps_global->VAR_SPECIAL_TEXT_BACK_COLOR){
++ gf_link_filter(gf_line_test, gf_line_test_opt(color_this_text, NULL));
++ }
++
++ if((flgs & FM_DISPLAY)
++ && !(flgs & FM_NOCOLOR)
++ && pico_usingcolor()
+ && ps_global->VAR_SIGNATURE_FORE_COLOR
+ && ps_global->VAR_SIGNATURE_BACK_COLOR){
+! gf_link_filter(gf_quote_test, gf_line_test_opt(color_signature, &is_in_sig));
+ }
+
+ if((flgs & FM_DISPLAY)
+***************
+*** 291,298 ****
+ && pico_usingcolor()
+ && ps_global->VAR_QUOTE1_FORE_COLOR
+ && ps_global->VAR_QUOTE1_BACK_COLOR){
+! gf_link_filter(gf_line_test, gf_line_test_opt(color_a_quote, NULL));
+ }
+
+ if(!(flgs & FM_NOWRAP)){
+ wrapflags = (flgs & FM_DISPLAY) ? (GFW_HANDLES|GFW_SOFTHYPHEN) : GFW_NONE;
+--- 302,311 ----
+ && pico_usingcolor()
+ && ps_global->VAR_QUOTE1_FORE_COLOR
+ && ps_global->VAR_QUOTE1_BACK_COLOR){
+! gf_link_filter(gf_quote_test, gf_line_test_opt(color_a_quote, NULL));
+ }
++ else
++ gf_link_filter(gf_quote_test,gf_line_test_opt(select_quote, NULL));
+
+ if(!(flgs & FM_NOWRAP)){
+ wrapflags = (flgs & FM_DISPLAY) ? (GFW_HANDLES|GFW_SOFTHYPHEN) : GFW_NONE;
+***************
+*** 1096,1122 ****
+ color_signature(long int linenum, char *line, LT_INS_S **ins, void *is_in_sig)
+ {
+ struct variable *vars = ps_global->vars;
+! int *in_sig_block;
+ COLOR_PAIR *col = NULL;
+
+ if(is_in_sig == NULL)
+ return 0;
+
+ in_sig_block = (int *) is_in_sig;
+
+! if(!strcmp(line, SIGDASHES))
+! *in_sig_block = START_SIG_BLOCK;
+! else if(*line == '\0')
+ /*
+ * Suggested by Eduardo: allow for a blank line right after
+ * the sigdashes.
+ */
+ *in_sig_block = (*in_sig_block == START_SIG_BLOCK)
+ ? IN_SIG_BLOCK : OUT_SIG_BLOCK;
+ else
+ *in_sig_block = (*in_sig_block != OUT_SIG_BLOCK)
+ ? IN_SIG_BLOCK : OUT_SIG_BLOCK;
+
+ if(*in_sig_block != OUT_SIG_BLOCK
+ && VAR_SIGNATURE_FORE_COLOR && VAR_SIGNATURE_BACK_COLOR
+ && (col = new_color_pair(VAR_SIGNATURE_FORE_COLOR,
+--- 1109,1197 ----
+ color_signature(long int linenum, char *line, LT_INS_S **ins, void *is_in_sig)
+ {
+ struct variable *vars = ps_global->vars;
+! int *in_sig_block, i, j,same_qstr = 0, plb;
+ COLOR_PAIR *col = NULL;
++ static char GLine[NSTRING] = {'\0'};
++ static char PLine[NSTRING] = {'\0'};
++ static char PPLine[NSTRING] = {'\0'};
++ char NLine[NSTRING] = {'\0'};
++ char rqstr[NSTRING] = {'\0'};
++ char *p;
++ static char *buf, buf2[NSTRING] = {'\0'};
++ QSTRING_S *qs;
++ static int qstrlen = 0;
+
+ if(is_in_sig == NULL)
+ return 0;
+
++ if (linenum > 0){
++ strncpy(PLine, GLine, sizeof(PLine));
++ PLine[sizeof(PLine)-1] = '\0';
++ }
++
++ if(p = strchr(tmp_20k_buf, '\015')) *p = '\0';
++ strncpy(NLine, tmp_20k_buf, sizeof(NLine));
++ NLine[sizeof(NLine) - 1] = '\0';
++ if (p) *p = '\015';
++
++ strncpy(GLine, line, sizeof(GLine));
++ GLine[sizeof(GLine) - 1] = '\0';
++
++ plb = line_isblank((ps_global->prefix && *ps_global->prefix
++ ? ps_global->prefix : ">"), PLine, GLine, PPLine, NSTRING);
++ qs = do_quote_match((ps_global->prefix && *ps_global->prefix
++ ? ps_global->prefix : ">"),
++ GLine, NLine, PLine, rqstr, NSTRING, plb);
++ if(linenum > 0)
++ strncpy(PPLine, PLine, NSTRING);
++ strncpy(buf2, rqstr, NSTRING);
++ i = buf2 && buf2[0] ? strlen(buf2) : 0;
++ free_qs(&qs);
++
++ /* determine if buf and buf2 are the same quote string */
++ if (!struncmp(buf, buf2, qstrlen)){
++ for (j = qstrlen; buf2[j] && isspace((unsigned char)buf2[j]); j++);
++ if (!buf2[j] || buf2[j] == '|' || (buf2[j] == '*' && buf2[j+1] != '>'))
++ same_qstr++;
++ }
++
+ in_sig_block = (int *) is_in_sig;
+
+! if (*in_sig_block != OUT_SIG_BLOCK){
+! if (line && *line && (strlen(line) >= qstrlen) && same_qstr)
+! line += qstrlen;
+! else if (strlen(line) < qstrlen)
+! line += i;
+! else if (!same_qstr)
+! *in_sig_block = OUT_SIG_BLOCK;
+! }
+! else
+! line += i;
+!
+! if(!strcmp(line, SIGDASHES) || !strcmp(line, "--")){
+! *in_sig_block = START_SIG_BLOCK;
+! buf = (char *) fs_get((i + 1)*sizeof(char));
+! buf = cpystr(buf2);
+! qstrlen = i;
+! }
+! else if(*line == '\0'){
+ /*
+ * Suggested by Eduardo: allow for a blank line right after
+ * the sigdashes.
+ */
+ *in_sig_block = (*in_sig_block == START_SIG_BLOCK)
+ ? IN_SIG_BLOCK : OUT_SIG_BLOCK;
++ }
+ else
+ *in_sig_block = (*in_sig_block != OUT_SIG_BLOCK)
+ ? IN_SIG_BLOCK : OUT_SIG_BLOCK;
+
++ if (*in_sig_block == OUT_SIG_BLOCK){
++ qstrlen = 0; /* reset back in case there's another paragraph */
++ if (buf)
++ fs_give((void **)&buf);
++ }
++
+ if(*in_sig_block != OUT_SIG_BLOCK
+ && VAR_SIGNATURE_FORE_COLOR && VAR_SIGNATURE_BACK_COLOR
+ && (col = new_color_pair(VAR_SIGNATURE_FORE_COLOR,
+***************
+*** 1480,1497 ****
+ return(0);
+ }
+
+
+ int
+ url_hilite(long int linenum, char *line, LT_INS_S **ins, void *local)
+ {
+ register char *lp, *up = NULL, *urlp = NULL,
+ *weburlp = NULL, *mailurlp = NULL;
+! int n, n1, n2, n3, l;
+ char buf[256], color[256];
+ HANDLE_S *h;
+ URL_HILITE_S *uh;
+
+! for(lp = line; ; lp = up + n){
+ /* scan for all of them so we can choose the first */
+ if(F_ON(F_VIEW_SEL_URL,ps_global))
+ urlp = rfc1738_scan(lp, &n1);
+--- 1555,1632 ----
+ return(0);
+ }
+
++ int
++ incomplete_url(char *up, int n, int delim)
++ {
++ char *line, *line2;
++ int rv = 0, len;
++
++ if(*(up + n) != '\0')
++ return 0;
++
++ if(delim > 0)
++ return 1;
++
++ if(F_ON(F_VIEW_LONG_URL, ps_global)){
++ line = up;
++ if(!strncmp(line, "http://", 7))
++ line += 7;
++ else if(!strncmp(line, "https://", 8))
++ line += 8;
++ if(strchr(line, '/') != NULL && (line = strrchr(line, '/')) != NULL){
++ line++;
++ line2 = strrchr(line, '.');
++ rv = (strpbrk(line,"+#?=&") != NULL)
++ || (!line2 || line-line2 > 4);
++ }
++ }
++ return rv;
++ }
++
+
+ int
+ url_hilite(long int linenum, char *line, LT_INS_S **ins, void *local)
+ {
+ register char *lp, *up = NULL, *urlp = NULL,
+ *weburlp = NULL, *mailurlp = NULL;
+! char *use_this_line, c, *begin_line, *end_line;
+! static int scannextline, delim = -1;
+! int n, n1, n2, n3, l, len;
+! int we_clear = 0, newhandle = 1, tie_off = 0;
+ char buf[256], color[256];
+ HANDLE_S *h;
+ URL_HILITE_S *uh;
+
+! uh = (URL_HILITE_S *) local;
+! if((uh && uh->handlesp && ((h = *(uh->handlesp)) == NULL) || h->key == 0) ||
+! (!line || !*line) || linenum == 0)
+! scannextline = 0; /* initialize scannextline */
+!
+! if(scannextline != 0){
+! up = rfc1738_scan(line, &n1);
+!
+! /* if we found a url in the current line, but it is not at the beginning of
+! * the next line, or if there is no url in this line, we check if the url
+! * in the previous line continues in this line.
+! */
+!
+! if(line != up){
+! if(*uh->handlesp == NULL)
+! h = new_handle(uh->handlesp);
+! for(h = *uh->handlesp; h->next; h = h->next); /* get last handle */
+! len = h->h.url.path ? strlen(h->h.url.path) : 0;
+! use_this_line = (char *) fs_get((len + strlen(line) + 1)*sizeof(char));
+! sprintf(use_this_line,"%s%s", (h->h.url.path ? h->h.url.path : ""), line);
+! we_clear++;
+! newhandle = 0;
+! }
+! else
+! use_this_line = line;
+! }
+! else
+! use_this_line = line;
+!
+! for(lp = use_this_line; ; lp = up + n){
+ /* scan for all of them so we can choose the first */
+ if(F_ON(F_VIEW_SEL_URL,ps_global))
+ urlp = rfc1738_scan(lp, &n1);
+***************
+*** 1501,1506 ****
+--- 1636,1645 ----
+ mailurlp = mail_addr_scan(lp, &n3);
+
+ if(urlp || weburlp || mailurlp){
++ if(scannextline == 0){
++ newhandle++;
++ delim = -1;
++ }
+ up = urlp ? urlp :
+ weburlp ? weburlp : mailurlp;
+ if(up == urlp && weburlp && weburlp < up)
+***************
+*** 1509,1515 ****
+--- 1648,1663 ----
+ up = mailurlp;
+
+ if(up == urlp){
++ if(delim < 0)
++ delim = up > use_this_line && *(up - 1) == '<';
+ n = n1;
++ if(incomplete_url(up,n, delim))
++ scannextline++;
++ else{
++ if(scannextline)
++ tie_off++;
++ scannextline = 0;
++ }
+ weburlp = mailurlp = NULL;
+ }
+ else if(up == weburlp){
+***************
+*** 1526,1561 ****
+
+ uh = (URL_HILITE_S *) local;
+
+! h = new_handle(uh->handlesp);
+! h->type = URL;
+! h->h.url.path = (char *) fs_get((n + 10) * sizeof(char));
+! snprintf(h->h.url.path, n+10, "%s%.*s",
+ weburlp ? "http://" : (mailurlp ? "mailto:" : ""), n, up);
+! h->h.url.path[n+10-1] = '\0';
+
+ if(handle_start_color(color, sizeof(color), &l, uh->hdr_color))
+! ins = gf_line_test_new_ins(ins, up, color, l);
+ else if(F_OFF(F_SLCTBL_ITEM_NOBOLD, ps_global))
+! ins = gf_line_test_new_ins(ins, up, url_embed(TAG_BOLDON), 2);
+
+ buf[0] = TAG_EMBED;
+ buf[1] = TAG_HANDLE;
+ snprintf(&buf[3], sizeof(buf)-3, "%d", h->key);
+ buf[sizeof(buf)-1] = '\0';
+ buf[2] = strlen(&buf[3]);
+! ins = gf_line_test_new_ins(ins, up, buf, (int) buf[2] + 3);
+
+ /* in case it was the current selection */
+! ins = gf_line_test_new_ins(ins, up + n, url_embed(TAG_INVOFF), 2);
+
+ if(scroll_handle_end_color(color, sizeof(color), &l, uh->hdr_color))
+! ins = gf_line_test_new_ins(ins, up + n, color, l);
+ else
+! ins = gf_line_test_new_ins(ins, up + n, url_embed(TAG_BOLDOFF), 2);
+
+ urlp = weburlp = mailurlp = NULL;
+ }
+
+ return(0);
+ }
+
+--- 1674,1731 ----
+
+ uh = (URL_HILITE_S *) local;
+
+! if(tie_off){
+! tie_off = 0; /* do only once */
+! begin_line = line;
+! end_line = line + n - strlen(h->h.url.path);
+! fs_give((void **)&h->h.url.path);
+! c = *(use_this_line + n);
+! *(use_this_line+n) = '\0';
+! h->h.url.path = cpystr(use_this_line);
+! *(use_this_line+n) = c;
+! }
+! else{
+! if(newhandle){
+! h = new_handle(uh->handlesp);
+! h->type = URL;
+! }
+! begin_line = newhandle ? (we_clear ? line + strlen(line) - strlen(up)
+! : up) : line;
+! end_line = newhandle ? begin_line + n : line + strlen(line);
+! if(scannextline && h->h.url.path)
+! fs_give((void **)&h->h.url.path);
+! h->h.url.path = (char *) fs_get((n + 10) * sizeof(char));
+! snprintf(h->h.url.path, n+10, "%s%.*s",
+ weburlp ? "http://" : (mailurlp ? "mailto:" : ""), n, up);
+! h->h.url.path[n+10-1] = '\0';
+! }
+
+ if(handle_start_color(color, sizeof(color), &l, uh->hdr_color))
+! ins = gf_line_test_new_ins(ins, begin_line, color, l);
+ else if(F_OFF(F_SLCTBL_ITEM_NOBOLD, ps_global))
+! ins = gf_line_test_new_ins(ins, begin_line, url_embed(TAG_BOLDON), 2);
+
+ buf[0] = TAG_EMBED;
+ buf[1] = TAG_HANDLE;
+ snprintf(&buf[3], sizeof(buf)-3, "%d", h->key);
+ buf[sizeof(buf)-1] = '\0';
+ buf[2] = strlen(&buf[3]);
+! ins = gf_line_test_new_ins(ins, begin_line, buf, (int) buf[2] + 3);
+
+ /* in case it was the current selection */
+! ins = gf_line_test_new_ins(ins, end_line, url_embed(TAG_INVOFF), 2);
+
+ if(scroll_handle_end_color(color, sizeof(color), &l, uh->hdr_color))
+! ins = gf_line_test_new_ins(ins, end_line, color, l);
+ else
+! ins = gf_line_test_new_ins(ins, end_line, url_embed(TAG_BOLDOFF), 2);
+
+ urlp = weburlp = mailurlp = NULL;
+ }
+
++ if(we_clear)
++ fs_give((void **)&use_this_line);
++
+ return(0);
+ }
+
+***************
+*** 1676,1681 ****
+--- 1846,1922 ----
+ }
+
+
++ /* This filter gives a quote string of a line. It sends its reply back to the
++ calling filter in the tmp_20k_buf variable. This filter replies with
++ the full quote string including tailing spaces if any. It is the
++ responsibility of the calling filter to figure out if thos spaces are
++ useful for that filter or if they should be removed before doing any
++ useful work. For example, color_a_quote does not require the trailing
++ spaces, but gf_wrap does.
++ */
++ int
++ select_quote(long linenum, char *line, LT_INS_S **ins, void *local)
++ {
++ int i, plb, *code;
++ char rqstr[NSTRING] = {'\0'}, buf[NSTRING] = {'\0'};
++ char GLine[NSTRING] = {'\0'}, PLine[NSTRING] = {'\0'};
++ char PPLine[NSTRING] = {'\0'}, NLine[NSTRING] = {'\0'};
++ static char GLine1[NSTRING] = {'\0'};
++ static char PLine1[NSTRING] = {'\0'};
++ static char PPLine1[NSTRING] = {'\0'};
++ static char GLine2[NSTRING] = {'\0'};
++ static char PLine2[NSTRING] = {'\0'};
++ static char PPLine2[NSTRING] = {'\0'};
++ QSTRING_S *qs;
++ int buflen = NSTRING < SIZEOF_20KBUF ? NSTRING - 1: SIZEOF_20KBUF - 1;
++ int who, raw;
++
++ code = (int *)local;
++ who = code ? (*code & COLORAQUO) : 0; /* may I ask who is calling? */
++ raw = code ? (*code & RAWSTRING) : 0; /* return raw string */
++ strncpy(GLine, (who ? GLine1 : GLine2), buflen);
++ strncpy(PLine, (who ? PLine1 : PLine2), buflen);
++ strncpy(PPLine, (who ? PPLine1 : PPLine2), buflen);
++
++ if (linenum > 0)
++ strncpy(PLine, GLine, buflen);
++
++ strncpy(NLine, tmp_20k_buf, buflen);
++
++ if (line)
++ strncpy(GLine, line, buflen);
++ else
++ GLine[0] = '\0';
++
++
++ plb = line_isblank((ps_global->prefix && *ps_global->prefix
++ ? ps_global->prefix : ">"), PLine, GLine, PPLine, NSTRING);
++
++ qs = do_quote_match((ps_global->prefix && *ps_global->prefix
++ ? ps_global->prefix : ">"), GLine, NLine, PLine,
++ rqstr, NSTRING, plb);
++ if (raw)
++ strncpy(buf, rqstr, NSTRING);
++ else
++ flatten_qstring(qs, buf, NSTRING);
++ free_qs(&qs);
++
++ /* do not paint an extra level for a line with a >From string at the
++ * begining of it
++ */
++ if (buf[0]){
++ i = strlen(buf);
++ if (strlen(line) >= i + 6 && !strncmp(line+i-1,">From ", 6))
++ buf[i - 1] = '\0';
++ }
++ strncpy(tmp_20k_buf, buf, buflen);
++ if (linenum > 0)
++ strncpy((who ? PPLine1 : PPLine2), PLine, buflen);
++ strncpy((who ? GLine1 : GLine2), GLine, buflen);
++ strncpy((who ? PLine1 : PLine2), PLine, buflen);
++ return 1;
++ }
++
+
+ #define UES_LEN 12
+ #define UES_MAX 32
+***************
+*** 2377,2384 ****
+ format_addr_string(s, n, sect, "Return-Path: ", e->return_path,
+ flags, oacs, pc);
+
+! if((which & FE_NEWSGROUPS) && e->newsgroups)
+ format_newsgroup_string("Newsgroups: ", e->newsgroups, flags, pc);
+
+ if((which & FE_FOLLOWUPTO) && e->followup_to)
+ format_newsgroup_string("Followup-To: ", e->followup_to, flags, pc);
+--- 2618,2638 ----
+ format_addr_string(s, n, sect, "Return-Path: ", e->return_path,
+ flags, oacs, pc);
+
+! if((which & FE_NEWSGROUPS) && e->newsgroups){
+! int bogus = NIL;
+ format_newsgroup_string("Newsgroups: ", e->newsgroups, flags, pc);
++ if (!e->ngpathexists && e->message_id &&
++ strncmp (e->message_id,"<alpine.",8) &&
++ strncmp (e->message_id,"<Pine.",6) &&
++ strncmp (e->message_id,"<MS-C.",6) &&
++ strncmp (e->message_id,"<MailManager.",13) &&
++ strncmp (e->message_id,"<EasyMail.",11) &&
++ strncmp (e->message_id,"<ML-",4)) bogus = T;
++
++ if(bogus)
++ q_status_message(SM_ORDER, 0, 3,
++ "Unverified Newsgroup header -- Message MAY or MAY NOT have been posted");
++ }
+
+ if((which & FE_FOLLOWUPTO) && e->followup_to)
+ format_newsgroup_string("Followup-To: ", e->followup_to, flags, pc);
+***************
+*** 2488,2493 ****
+--- 2742,2962 ----
+ return(color_pair);
+ }
+
++ void
++ interval_free(ival)
++ IVAL_S **ival;
++ {
++ if (!(*ival))
++ return;
++
++ if ((*ival)->next)
++ interval_free(&((*ival)->next));
++
++ fs_give((void **)(ival));
++ }
++
++ IVAL_S *
++ compute_interval (string, endm)
++ char *string;
++ int endm;
++ {
++ IVAL_S *ival = NULL, *nextival= NULL, *d;
++ regmatch_t pmatch;
++
++ if(ps_global->paterror == 0)
++ if (regexec(&ps_global->colorpat, string, 1, &pmatch, 0) == 0){
++ ival = (IVAL_S *) fs_get(sizeof(IVAL_S));
++ memset (ival, 0, sizeof(IVAL_S));
++ ival->start = endm + pmatch.rm_so;
++ ival->end = endm + pmatch.rm_eo;
++ nextival = compute_interval(string+pmatch.rm_so+1, ival->start+1);
++ if (nextival){
++ if (nextival->start <= ival->end){
++ ival->end = nextival->end;
++ d = nextival->next;
++ nextival->next = NULL;
++ ival->next = d;
++ interval_free(&nextival);
++ }
++ else
++ ival->next = nextival;
++ }
++ }
++ return ival;
++ }
++
++ void
++ regex_pattern(plist)
++ char **plist;
++ {
++ int i = 0, j = 0, len = 0;
++ char *pattern = NULL;
++ regex_t preg;
++
++ if(ps_global->paterror == 0)
++ regfree(&ps_global->colorpat);
++
++ if(plist && *plist && *plist){
++ for (i = 0; plist[i] && plist[i][0]; i++)
++ len += strlen(plist[i]) + 1;
++ pattern = (char *) fs_get(len * sizeof(char));
++ *pattern = '\0';
++ for (j = 0; j < i; j++){
++ strcat(pattern, plist[j]);
++ strcat(pattern, (j < i - 1) ? "|" : "");
++ }
++ if ((ps_global->paterror = regcomp(&preg, pattern, REG_EXTENDED)) != 0)
++ regfree(&preg);
++ else
++ ps_global->colorpat = preg;
++ }
++ if(pattern)
++ fs_give((void **)&pattern);
++ }
++
++ LT_INS_S **
++ insert_color_special_text(ins, p, ival, last_end, col)
++ LT_INS_S **ins;
++ char **p;
++ IVAL_S *ival;
++ int last_end;
++ COLOR_PAIR *col;
++ {
++ struct variable *vars = ps_global->vars;
++
++ if (ival){
++ *p += ival->start - last_end;
++ ins = gf_line_test_new_ins(ins, *p, color_embed(col->fg, col->bg),
++ (2 * RGBLEN) + 4);
++ *p += ival->end - ival->start;
++ ins = gf_line_test_new_ins(ins, *p, color_embed(VAR_NORM_FORE_COLOR,
++ VAR_NORM_BACK_COLOR), (2 * RGBLEN) + 4);
++ ins = insert_color_special_text(ins, p, ival->next, ival->end, col);
++ }
++ return ins;
++ }
++
++ int
++ length_color(p, begin_color)
++ char *p;
++ int begin_color;
++ {
++ int len = 0, done = begin_color ? 0 : -1;
++ char *orig = p;
++
++ while (*p && done <= 0){
++ switch(*p++){
++ case TAG_HANDLE :
++ p += *p + 1;
++ done++;
++ break;
++
++ case TAG_FGCOLOR :
++ case TAG_BGCOLOR :
++ p += RGBLEN;
++ if (!begin_color)
++ done++;
++ break;
++
++ default :
++ break;
++ }
++ }
++ len = p - orig;
++ return len;
++ }
++
++ int
++ any_color_in_string(p)
++ char *p;
++ {
++ int rv = 0;
++ char *orig = p;
++ while (*p && !rv)
++ if (*p++ == TAG_EMBED)
++ rv = p - orig;
++ return rv;
++ }
++
++ void
++ remove_spaces_ival(ivalp, p)
++ IVAL_S **ivalp;
++ char *p;
++ {
++ IVAL_S *ival;
++ int i;
++ if (!ivalp || !*ivalp)
++ return;
++ ival = *ivalp;
++ for (i = 0; isspace((unsigned char) p[ival->start + i]); i++);
++ if (ival->start + i < ival->end) /* do not do this if match only spaces */
++ ival->start += i;
++ else
++ return;
++ for (i = 0; isspace((unsigned char) p[ival->end - i - 1]); i++);
++ ival->end -= i;
++ if (ival->next)
++ remove_spaces_ival(&(ival->next), p);
++ }
++
++ int
++ color_this_text(linenum, line, ins, local)
++ long linenum;
++ char *line;
++ LT_INS_S **ins;
++ void *local;
++ {
++ struct variable *vars = ps_global->vars;
++ COLOR_PAIR *col = NULL;
++ char *p;
++ int i = 0;
++ static char *pattern = NULL;
++ /* char *buf;
++
++ select_quote(linenum, line, ins, (void *)code);
++ for (i = 0; tmp_20k_buf[i] && (buf[i] = tmp_20k_buf[i]); i++);
++ buf[i] = '\0'; */
++ p = line + i;
++
++ if(VAR_SPECIAL_TEXT_FORE_COLOR && VAR_SPECIAL_TEXT_BACK_COLOR
++ && (col = new_color_pair(VAR_SPECIAL_TEXT_FORE_COLOR,
++ VAR_SPECIAL_TEXT_BACK_COLOR))
++ && !pico_is_good_colorpair(col))
++ free_color_pair(&col);
++
++ if(ps_global->VAR_SPECIAL_TEXT && *ps_global->VAR_SPECIAL_TEXT
++ && **ps_global->VAR_SPECIAL_TEXT && col){
++ IVAL_S *ival;
++ int done = 0, begin_color = 0;
++
++ while (!done){
++ if (i = any_color_in_string(p)){
++ begin_color = (begin_color + 1) % 2;
++ if (begin_color){
++ p[i - 1] = '\0';
++ ival = compute_interval(p, 0);
++ remove_spaces_ival(&ival, p);
++ p[i - 1] = TAG_EMBED;
++ ins = insert_color_special_text(ins, &p, ival, 0, col);
++ }
++ for (;*p++ != TAG_EMBED; );
++ p += length_color(p, begin_color);
++ }
++ else{
++ ival = compute_interval(p, 0);
++ remove_spaces_ival(&ival, p);
++ ins = insert_color_special_text(ins, &p, ival, 0, col);
++ done++;
++ }
++ interval_free(&ival);
++ if (!*p)
++ done++;
++ }
++ free_color_pair(&col);
++ }
++
++ return 0;
++ }
+
+ /*
+ * The argument fieldname is something like "Subject:..." or "Subject".
+diff -rc alpine-2.00/pith/mailview.h alpine-2.00.I.USE/pith/mailview.h
+*** alpine-2.00/pith/mailview.h 2008-06-03 08:54:15.000000000 -0700
+--- alpine-2.00.I.USE/pith/mailview.h 2011-02-07 20:33:43.000000000 -0800
+***************
+*** 29,34 ****
+--- 29,40 ----
+ #include "../pith/color.h"
+
+
++ typedef struct IVAL {
++ int start;
++ int end;
++ struct IVAL *next;
++ } IVAL_S;
++
+ /* format_message flags */
+ #define FM_DISPLAY 0x0001 /* result is headed for display */
+ #define FM_NEW_MESS 0x0002 /* a new message so zero out attachment descrip */
+***************
+*** 125,130 ****
+--- 131,145 ----
+ int url_hilite(long, char *, LT_INS_S **, void *);
+ int handle_start_color(char *, size_t, int *, int);
+ int handle_end_color(char *, size_t, int *);
++ IVAL_S *compute_interval(char *, int);
++ void remove_spaces_ival(IVAL_S **, char *);
++ void interval_free(IVAL_S **);
++ void regex_pattern(char **);
++ LT_INS_S **insert_color_special_text(LT_INS_S **, char **, IVAL_S *,
++ int, COLOR_PAIR *);
++ int any_color_in_string(char *);
++ int length_color(char *, int);
++ int color_this_text(long, char *, LT_INS_S **, void *);
+
+ /*
+ * BUG: BELOW IS UNIX/PC ONLY since config'd browser means nothing to webpine
+***************
+*** 141,146 ****
+--- 156,162 ----
+ char *display_parameters(PARAMETER *);
+ char *pine_fetch_header(MAILSTREAM *, long, char *, char **, long);
+ int color_signature(long, char *, LT_INS_S **, void *);
++ int select_quote(long, char *, LT_INS_S **, void *);
+ int scroll_handle_start_color(char *, size_t, int *);
+ int scroll_handle_end_color(char *, size_t, int *, int);
+ int width_at_this_position(unsigned char *, unsigned long);
+diff -rc alpine-2.00/pith/Makefile.am alpine-2.00.I.USE/pith/Makefile.am
+*** alpine-2.00/pith/Makefile.am 2008-06-03 08:54:15.000000000 -0700
+--- alpine-2.00.I.USE/pith/Makefile.am 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 25,31 ****
+ filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c imap.c init.c \
+ keyword.c ldap.c list.c mailcap.c mailcmd.c mailindx.c maillist.c mailview.c \
+ margin.c mimedesc.c mimetype.c msgno.c newmail.c news.c pattern.c pipe.c \
+! readfile.c remote.c reply.c rfc2231.c save.c search.c sequence.c send.c sort.c \
+ state.c status.c store.c stream.c string.c strlst.c takeaddr.c tempfile.c text.c \
+ thread.c adjtime.c url.c util.c helptext.c smkeys.c smime.c
+
+--- 25,31 ----
+ filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c imap.c init.c \
+ keyword.c ldap.c list.c mailcap.c mailcmd.c mailindx.c maillist.c mailview.c \
+ margin.c mimedesc.c mimetype.c msgno.c newmail.c news.c pattern.c pipe.c \
+! readfile.c remote.c reply.c rfc2231.c rules.c save.c search.c sequence.c send.c sort.c \
+ state.c status.c store.c stream.c string.c strlst.c takeaddr.c tempfile.c text.c \
+ thread.c adjtime.c url.c util.c helptext.c smkeys.c smime.c
+
+diff -rc alpine-2.00/pith/Makefile.in alpine-2.00.I.USE/pith/Makefile.in
+*** alpine-2.00/pith/Makefile.in 2008-06-03 08:54:15.000000000 -0700
+--- alpine-2.00.I.USE/pith/Makefile.in 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 77,83 ****
+ margin.$(OBJEXT) mimedesc.$(OBJEXT) mimetype.$(OBJEXT) \
+ msgno.$(OBJEXT) newmail.$(OBJEXT) news.$(OBJEXT) \
+ pattern.$(OBJEXT) pipe.$(OBJEXT) readfile.$(OBJEXT) \
+! remote.$(OBJEXT) reply.$(OBJEXT) rfc2231.$(OBJEXT) \
+ save.$(OBJEXT) search.$(OBJEXT) sequence.$(OBJEXT) \
+ send.$(OBJEXT) sort.$(OBJEXT) state.$(OBJEXT) status.$(OBJEXT) \
+ store.$(OBJEXT) stream.$(OBJEXT) string.$(OBJEXT) \
+--- 77,83 ----
+ margin.$(OBJEXT) mimedesc.$(OBJEXT) mimetype.$(OBJEXT) \
+ msgno.$(OBJEXT) newmail.$(OBJEXT) news.$(OBJEXT) \
+ pattern.$(OBJEXT) pipe.$(OBJEXT) readfile.$(OBJEXT) \
+! remote.$(OBJEXT) reply.$(OBJEXT) rfc2231.$(OBJEXT) rules.$(OBJEXT) \
+ save.$(OBJEXT) search.$(OBJEXT) sequence.$(OBJEXT) \
+ send.$(OBJEXT) sort.$(OBJEXT) state.$(OBJEXT) status.$(OBJEXT) \
+ store.$(OBJEXT) stream.$(OBJEXT) string.$(OBJEXT) \
+***************
+*** 275,281 ****
+ filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c imap.c init.c \
+ keyword.c ldap.c list.c mailcap.c mailcmd.c mailindx.c maillist.c mailview.c \
+ margin.c mimedesc.c mimetype.c msgno.c newmail.c news.c pattern.c pipe.c \
+! readfile.c remote.c reply.c rfc2231.c save.c search.c sequence.c send.c sort.c \
+ state.c status.c store.c stream.c string.c strlst.c takeaddr.c tempfile.c text.c \
+ thread.c adjtime.c url.c util.c helptext.c smkeys.c smime.c
+
+--- 275,281 ----
+ filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c imap.c init.c \
+ keyword.c ldap.c list.c mailcap.c mailcmd.c mailindx.c maillist.c mailview.c \
+ margin.c mimedesc.c mimetype.c msgno.c newmail.c news.c pattern.c pipe.c \
+! readfile.c remote.c reply.c rfc2231.c rules.c save.c search.c sequence.c send.c sort.c \
+ state.c status.c store.c stream.c string.c strlst.c takeaddr.c tempfile.c text.c \
+ thread.c adjtime.c url.c util.c helptext.c smkeys.c smime.c
+
+***************
+*** 404,409 ****
+--- 404,410 ----
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@
++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rules.Po@am__quote@
+
+ .c.o:
+ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+diff -rc alpine-2.00/pith/makefile.wnt alpine-2.00.I.USE/pith/makefile.wnt
+*** alpine-2.00/pith/makefile.wnt 2007-10-24 14:58:00.000000000 -0700
+--- alpine-2.00.I.USE/pith/makefile.wnt 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 44,50 ****
+ init.h keyword.h ldap.h list.h mailcap.h mailcmd.h mailindx.h maillist.h \
+ mailpart.h mailview.h margin.h mimedesc.h mimetype.h msgno.h newmail.h news.h \
+ options.h pattern.h pineelt.h pipe.h readfile.h remote.h remtype.h repltype.h reply.h \
+! rfc2231.h save.h savetype.h search.h send.h sequence.h signal.h sort.h sorttype.h \
+ state.h status.h store.h stream.h string.h strlst.h takeaddr.h tempfile.h text.h \
+ thread.h url.h user.h util.h
+
+--- 44,50 ----
+ init.h keyword.h ldap.h list.h mailcap.h mailcmd.h mailindx.h maillist.h \
+ mailpart.h mailview.h margin.h mimedesc.h mimetype.h msgno.h newmail.h news.h \
+ options.h pattern.h pineelt.h pipe.h readfile.h remote.h remtype.h repltype.h reply.h \
+! rfc2231.h rules.h save.h savetype.h search.h send.h sequence.h signal.h sort.h sorttype.h \
+ state.h status.h store.h stream.h string.h strlst.h takeaddr.h tempfile.h text.h \
+ thread.h url.h user.h util.h
+
+***************
+*** 53,59 ****
+ filter.obj flag.obj folder.obj handle.obj help.obj helptext.obj hist.obj icache.obj imap.obj init.obj \
+ keyword.obj ldap.obj list.obj mailcap.obj mailcmd.obj mailindx.obj maillist.obj mailview.obj \
+ margin.obj mimedesc.obj mimetype.obj msgno.obj newmail.obj news.obj pattern.obj pipe.obj \
+! readfile.obj remote.obj reply.obj rfc2231.obj save.obj search.obj sequence.obj send.obj sort.obj state.obj \
+ status.obj store.obj stream.obj string.obj strlst.obj takeaddr.obj tempfile.obj text.obj \
+ thread.obj adjtime.obj url.obj util.obj
+
+--- 53,59 ----
+ filter.obj flag.obj folder.obj handle.obj help.obj helptext.obj hist.obj icache.obj imap.obj init.obj \
+ keyword.obj ldap.obj list.obj mailcap.obj mailcmd.obj mailindx.obj maillist.obj mailview.obj \
+ margin.obj mimedesc.obj mimetype.obj msgno.obj newmail.obj news.obj pattern.obj pipe.obj \
+! readfile.obj remote.obj reply.obj rfc2231.obj rules.obj save.obj search.obj sequence.obj send.obj sort.obj state.obj \
+ status.obj store.obj stream.obj string.obj strlst.obj takeaddr.obj tempfile.obj text.obj \
+ thread.obj adjtime.obj url.obj util.obj
+
+diff -rc alpine-2.00/pith/mimetype.c alpine-2.00.I.USE/pith/mimetype.c
+*** alpine-2.00/pith/mimetype.c 2008-03-06 12:54:01.000000000 -0800
+--- alpine-2.00.I.USE/pith/mimetype.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 178,183 ****
+--- 178,212 ----
+ panic("Unhandled mime type search");
+ }
+
++ /* if we still can not find the type, but it is a .docx (or alike) extension
++ set the type here. Do not use the grope function.
++ */
++ if(rv == 0){
++ rv = 1; /* assume success */
++ mt_map->to.mime.type = TYPEAPPLICATION;
++ if(!strucmp(mt_map->from.ext, "docx"))
++ mt_map->to.mime.subtype = cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.WORDPROCESSINGML.DOCUMENT");
++ else if(!strucmp(mt_map->from.ext, "xslx"))
++ mt_map->to.mime.subtype = cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.SPREADSHEETML.SHEET");
++ else if(!strucmp(mt_map->from.ext, "xltx"))
++ mt_map->to.mime.subtype = cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.SPREADSHEETML.TEMPLATE");
++ else if(!strucmp(mt_map->from.ext, "potx"))
++ mt_map->to.mime.subtype = cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.PRESENTATIONML.TEMPLATE");
++ else if(!strucmp(mt_map->from.ext, "ppsx"))
++ mt_map->to.mime.subtype = cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.PRESENTATIONML.SLIDESHOW");
++ else if(!strucmp(mt_map->from.ext, "pptx"))
++ mt_map->to.mime.subtype = cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.PRESENTATIONML.PRESENTATION");
++ else if(!strucmp(mt_map->from.ext, "sldx"))
++ mt_map->to.mime.subtype = cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.PRESENTATIONML.SLIDE");
++ else if(!strucmp(mt_map->from.ext, "dotx"))
++ mt_map->to.mime.subtype = cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.WORDPROCESSINGML.TEMPLATE");
++ else if(!strucmp(mt_map->from.ext, "xlam"))
++ mt_map->to.mime.subtype = cpystr("VND.MS-EXCEL.ADDIN.MACROENABLED.12");
++ else if(!strucmp(mt_map->from.ext, "xslb"))
++ mt_map->to.mime.subtype = cpystr("VND.MS-EXCEL.SHEET.BINARY.MACROENABLED.12");
++ else rv = 0; /* else, failure */
++ }
++
+
+ return(rv);
+ }
+diff -rc alpine-2.00/pith/msgno.c alpine-2.00.I.USE/pith/msgno.c
+*** alpine-2.00/pith/msgno.c 2007-12-03 16:13:55.000000000 -0800
+--- alpine-2.00.I.USE/pith/msgno.c 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 932,937 ****
+--- 932,943 ----
+ if((*peltp)->pthrd)
+ fs_give((void **) &(*peltp)->pthrd);
+
++ if((*peltp)->firsttext)
++ fs_give((void **) &(*peltp)->firsttext);
++
++ if((*peltp)->firsttextraw)
++ fs_give((void **) &(*peltp)->firsttextraw);
++
+ if((*peltp)->ice)
+ free_ice(&(*peltp)->ice);
+
+diff -rc alpine-2.00/pith/newmail.c alpine-2.00.I.USE/pith/newmail.c
+*** alpine-2.00/pith/newmail.c 2008-07-14 11:01:54.000000000 -0700
+--- alpine-2.00.I.USE/pith/newmail.c 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 684,692 ****
+ if(!for_new_mail_win)
+ q_status_message5(SM_ASYNC | SM_DING, 0, 60,
+ "%s%s%s%.80s%.80s", intro,
+! from ? ((number > 1L) ? " Most recent f" : " F") : "",
+! from ? "rom " : "",
+! from ? from : "",
+ subjtext);
+ #if (!defined(DOS) && !defined(OS2) && !defined(LEAVEOUTFIFO)) || defined(_WINDOWS)
+ else {
+--- 684,692 ----
+ if(!for_new_mail_win)
+ q_status_message5(SM_ASYNC | SM_DING, 0, 60,
+ "%s%s%s%.80s%.80s", intro,
+! from && from[0] ? ((number > 1L) ? " Most recent f" : " F") : "",
+! from && from[0] ? "rom " : "",
+! from && from[0] ? from : "",
+ subjtext);
+ #if (!defined(DOS) && !defined(OS2) && !defined(LEAVEOUTFIFO)) || defined(_WINDOWS)
+ else {
+***************
+*** 724,732 ****
+ }
+ else
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s%.80s", intro,
+! from ? ((number > 1L) ? " Most recent f" : " F") : "",
+! from ? "rom " : "",
+! from ? from : "");
+
+ (*pith_opt_icon_text)(tmp_20k_buf, IT_NEWMAIL);
+ }
+--- 724,732 ----
+ }
+ else
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s%.80s", intro,
+! from && from[0] ? ((number > 1L) ? " Most recent f" : " F") : "",
+! from && from[0] ? "rom " : "",
+! from && from[0] ? from : "");
+
+ (*pith_opt_icon_text)(tmp_20k_buf, IT_NEWMAIL);
+ }
+diff -rc alpine-2.00/pith/osdep/color.c alpine-2.00.I.USE/pith/osdep/color.c
+*** alpine-2.00/pith/osdep/color.c 2006-09-26 12:30:49.000000000 -0700
+--- alpine-2.00.I.USE/pith/osdep/color.c 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 31,37 ****
+
+ #include <system.h>
+ #include "./color.h"
+!
+
+
+ /*
+--- 31,37 ----
+
+ #include <system.h>
+ #include "./color.h"
+! #include "./collate.h"
+
+
+ /*
+***************
+*** 91,93 ****
+--- 91,1278 ----
+ {
+ return(pico_set_colors(col ? col->fg : NULL, col ? col->bg : NULL, flags));
+ }
++
++
++ /*
++ * Extended Justification support also does not belong here
++ * but otherwise webpine will not build, so we move everything
++ * here. Hopefully this will be the permanent place for these
++ * routines. This routines used to be in pico/word.c
++ */
++ #define NSTRING 256
++ #include "../../include/general.h"
++
++ /* Support of indentation of paragraphs */
++ #define is_indent_char(c) (((c) == '.' || (c) == '}' || (c) == RPAREN || \
++ (c) == '*' || (c) == '+' || is_a_digit(c) || \
++ ISspace(c) || (c) == '-' || \
++ (c) == ']') ? 1 : 0)
++ #define allowed_after_digit(c,word,k) ((((c) == '.' && \
++ allowed_after_period(next((word),(k)))) ||\
++ (c) == RPAREN || (c) == '}' || (c) == ']' ||\
++ ISspace(c) || is_a_digit(c) || \
++ ((c) == '-' ) && \
++ allowed_after_dash(next((word),(k)))) \
++ ? 1 : 0)
++ #define allowed_after_period(c) (((c) == RPAREN || (c) == '}' || (c) == ']' ||\
++ ISspace(c) || (c) == '-' || \
++ is_a_digit(c)) ? 1 : 0)
++ #define allowed_after_parenth(c) (ISspace(c) ? 1 : 0)
++ #define allowed_after_space(c) (ISspace(c) ? 1 : 0)
++ #define allowed_after_braces(c) (ISspace(c) ? 1 : 0)
++ #define allowed_after_star(c) ((ISspace(c) || (c) == RPAREN ||\
++ (c) == ']' || (c) == '}') ? 1 : 0)
++ #define allowed_after_dash(c) ((ISspace(c) || is_a_digit(c)) ? 1 : 0)
++ #define EOLchar(c) (((c) == '.' || (c) == ':' || (c) == '?' ||\
++ (c) == '!') ? 1 : 0)
++
++
++ /* Extended justification support */
++ #define is_cquote(c) ((c) == '>' || (c) == '|' || (c) == ']' || (c) == ':')
++ #define is_cword(c) ((((c) >= 'a') && ((c) <= 'z')) || \
++ (((c) >= 'A') && ((c) <= 'Z')) || \
++ (((c) >= '0') && ((c) <= '9')) || \
++ ((c) == ' ') || ((c) == '?') || \
++ ((c) == '@') || ((c) == '.') || \
++ ((c) == '!') || ((c) == '\'') || \
++ ((c) == ',') || ((c) == '\"') ? 1 : 0)
++ #define isaquote(c) ((c) == '\"' || (c) == '\'')
++ #define is8bit(c) ((((int) (c)) & 0x80) ? 1 : 0)
++ #define iscontrol(c) (iscntrl(((int) (c)) & 0x7f) ? 1 : 0)
++ #define forbidden(c) (((c) == '\"') || ((c) == '\'') || ((c) == '$') ||\
++ ((c) == ',') || ((c) == '.') || ((c) == '-') ||\
++ ((c) == LPAREN) || ((c) == '/')|| ((c) == '`') ||\
++ ((c) == '{') || ((c) == '\\') || (iscontrol((c))) ||\
++ (((c) >= '0') && ((c) <= '9')) || ((c) == '?'))
++ #define is_cletter(c) ((((c) >= 'a') && ((c) <= 'z'))) ||\
++ ((((c) >= 'A') && ((c) <= 'Z'))||\
++ is8bit(c))
++ #define is_cnumber(c) ((c) >= '0' && (c) <= '9')
++ #define allwd_after_word(c) (((c) == ' ') || ((c) == '>') || is_cletter(c))
++ #define allwd_after_qsword(c) (((c) != '\\') && ((c) != RPAREN))
++ #define before(word,i) (((i) > 0) ? (word)[(i) - 1] : 0)
++ #define next(w,i) ((((w)[(i)]) != 0) ? ((w)[(i) + 1]) : 0)
++ #define now(w,i) ((w)[(i)])
++ #define is_qsword(c) (((c) == ':') || ((c) == RPAREN) ? 1 : 0)
++ #define is_colon(c) (((c) == ':') ? 1 : 0)
++ #define is_rarrow(c) (((c) == '>') ? 1 : 0)
++ #define is_tilde(c) (((c) == '~') ? 1 : 0)
++ #define is_dash(c) (((c) == '-') ? 1 : 0)
++ #define is_pound(c) (((c) == '#') ? 1 : 0)
++ #define is_a_digit(c) ((((c) >= '0') && ((c) <= '9')) ? 1 : 0)
++ #define is_allowed(c) (is_cquote(c) || is_cword(c) || is_dash(c) || \
++ is_pound(c))
++ #define qs_allowed(a) (((a)->qstype != qsGdb) && ((a)->qstype != qsProg))
++
++ /* Internal justification functions */
++ QSTRING_S *is_quote(char *, char *, int);
++ QSTRING_S *qs_normal_part(QSTRING_S *);
++ QSTRING_S *qs_remove_trailing_spaces(QSTRING_S *);
++ QSTRING_S *trim_qs_from_cl(QSTRING_S *, QSTRING_S *, QSTRING_S *);
++ QSTRING_S *fix_qstring(QSTRING_S *, QSTRING_S *, QSTRING_S *);
++ QSTRING_S *fix_qstring_allowed(QSTRING_S *, QSTRING_S *, QSTRING_S *);
++ QSTRING_S *qs_add(char *, char *, QStrType, int, int, int, int);
++ QSTRING_S *remove_qsword(QSTRING_S *);
++ QSTRING_S *do_raw_quote_match(char *, char *, char *, char *, QSTRING_S **, QSTRING_S **);
++ void free_qs(QSTRING_S **);
++ int word_is_prog(char *);
++ int qstring_is_normal(QSTRING_S *);
++ int exists_good_part(QSTRING_S *);
++ int strcmp_qs(char *, char *);
++ int count_levels_qstring(QSTRING_S *);
++ int same_qstring(QSTRING_S *, QSTRING_S *);
++ int advance_quote_string(char *, char *, int);
++ int isaword(char *,int ,int);
++ int isamailbox(char *,int ,int);
++
++
++ int
++ word_is_prog(char *word)
++ {
++ static char *list1[] = {"#include",
++ "#define",
++ "#ifdef",
++ "#ifndef",
++ "#elif",
++ "#if",
++ NULL};
++ static char *list2[] = {"#else",
++ "#endif",
++ NULL};
++ int i, j = strlen(word), k, rv = 0;
++
++ for(i = 0; rv == 0 && list1[i] && (k = strlen(list1[i])) && k < j; i++)
++ if(!strncmp(list1[i], word, k) && ISspace(word[k]))
++ rv++;
++
++ if(rv)
++ return rv;
++
++ for(i = 0; rv == 0 && list2[i] && (k = strlen(list2[i])) && k <= j; i++)
++ if(!strncmp(list2[i], word, k) && (!word[k] || ISspace(word[k])))
++ rv++;
++
++ return rv;
++ }
++
++ /*
++ * This function creates a qstring pointer with the information that
++ * is_quote handles to it.
++ * Parameters:
++ * qs - User supplied quote string
++ * word - The line of text that the user is trying to read/justify
++ * beginw - Where we need to start copying from
++ * endw - Where we end copying
++ * offset - Any offset in endw that we need to account for
++ * typeqs - type of the string to be created
++ * neednext - boolean, indicating if we need to compute the next field
++ * of leave it NULL
++ *
++ * It is a mistake to call this function if beginw >= endw + offset.
++ * Please note the equality sign in the above inequality (this is because
++ * we always assume that qstring->value != "").
++ */
++ QSTRING_S *
++ qs_add(qs, word, typeqs, beginw, endw, offset, neednext)
++ char *qs;
++ char word[NSTRING];
++ QStrType typeqs;
++ int beginw, endw, offset, neednext;
++ {
++ QSTRING_S *qstring, *nextqs;
++ int i;
++
++ qstring = (QSTRING_S *) malloc (sizeof(QSTRING_S));
++ memset (qstring, 0, sizeof(QSTRING_S));
++ qstring->qstype = qsNormal;
++
++ if (beginw == 0){
++ beginw = endw + offset;
++ qstring->qstype = typeqs;
++ }
++
++ nextqs = neednext ? is_quote(qs, word+beginw, 1) : NULL;
++
++ qstring->value = (char *) malloc((beginw+1)*sizeof(char));
++ strncpy(qstring->value, word, beginw);
++ qstring->value[beginw] = '\0';
++
++ qstring->next = nextqs;
++
++ return qstring;
++ }
++
++ int
++ qstring_is_normal(cl)
++ QSTRING_S *cl;
++ {
++ for (;cl && (cl->qstype == qsNormal); cl = cl->next);
++ return cl ? 0 : 1;
++ }
++
++ /*
++ * Given a quote string, this function returns the part that is the leading
++ * normal part of it. (the normal part is the part that is tagged qsNormal,
++ * that is to say, the one that is not controversial at all (like qsString
++ * for example).
++ */
++ QSTRING_S *
++ qs_normal_part(cl)
++ QSTRING_S *cl;
++ {
++
++ if (!cl) /* nothing in, nothing out */
++ return cl;
++
++ if (cl->qstype != qsNormal)
++ free_qs(&cl);
++
++ if (cl)
++ cl->next = qs_normal_part(cl->next);
++
++ return cl;
++ }
++
++ /*
++ * this function removes trailing spaces from a quote string, but leaves the
++ * last one if there are trailing spaces
++ */
++ QSTRING_S *
++ qs_remove_trailing_spaces(cl)
++ QSTRING_S *cl;
++ {
++ QSTRING_S *rl = cl;
++ if (!cl) /* nothing in, nothing out */
++ return cl;
++
++ if (cl->next)
++ cl->next = qs_remove_trailing_spaces(cl->next);
++ else{
++ if (value_is_space(cl->value))
++ free_qs(&cl);
++ else{
++ int i, l;
++ i = l = strlen(cl->value) - 1;
++ while (cl->value && cl->value[i]
++ && ISspace(cl->value[i]))
++ i--;
++ i += (i < l) ? 2 : 1;
++ cl->value[i] = '\0';
++ }
++ }
++ return cl;
++ }
++
++ /*
++ * This function returns if two strings are the same quote string.
++ * The call is not symmetric. cl must preceed the line nl. This function
++ * should be called for comparing the last part of cl and nl.
++ */
++ int
++ strcmp_qs(char *valuecl, char *valuenl)
++ {
++ int j;
++
++ for (j = 0; valuecl[j] && (valuecl[j] == valuenl[j]); j++);
++ return !strcmp(valuecl, valuenl)
++ || (valuenl[j] && value_is_space(valuenl+j)
++ && value_is_space(valuecl+j)
++ && strlenis(valuecl+j) >= strlenis(valuenl+j))
++ || (!valuenl[j] && value_is_space(valuecl+j));
++ }
++
++ int
++ count_levels_qstring(cl)
++ QSTRING_S *cl;
++ {
++ int count;
++ for (count = 0; cl ; count++, cl = cl->next);
++
++ return count;
++ }
++
++ int
++ value_is_space(char *value)
++ {
++ for (; value && *value && ISspace(*value); value++);
++
++ return value && *value ? 0 : 1;
++ }
++
++ void
++ free_qs(QSTRING_S **cl)
++ {
++ if (!(*cl))
++ return;
++
++ if ((*cl)->next)
++ free_qs(&((*cl)->next));
++
++ (*cl)->next = (QSTRING_S *) NULL;
++
++ if ((*cl)->value)
++ free((void *)(*cl)->value);
++ (*cl)->value = (char *) NULL;
++ free((void *)(*cl));
++ *cl = (QSTRING_S *) NULL;
++ }
++
++ /*
++ * This function returns the number of agreements between
++ * cl and nl. The call is not symmetric. cl must be the line
++ * preceding nl.
++ */
++ int
++ same_qstring(QSTRING_S *cl, QSTRING_S *nl)
++ {
++ int same = 0, done = 0;
++
++ for (;cl && nl && !done; cl = cl->next, nl = nl->next)
++ if (cl->qstype == nl->qstype
++ && (!strcmp(cl->value, nl->value)
++ || (!cl->next && strcmp_qs(cl->value, nl->value))))
++ same++;
++ else
++ done++;
++ return same;
++ }
++
++ QSTRING_S *
++ trim_qs_from_cl(QSTRING_S *cl, QSTRING_S *nl, QSTRING_S *pl)
++ {
++ QSTRING_S *cqstring = pl ? pl : nl;
++ QSTRING_S *tl = pl ? pl : nl;
++ int p, c;
++
++ if (qstring_is_normal(tl))
++ return tl;
++
++ p = same_qstring(pl ? pl : cl, pl ? cl : nl);
++
++ for (c = 1; c < p; c++, cl = cl->next, tl = tl->next);
++
++ /*
++ * cl->next and tl->next differ, it may be because cl->next does not
++ * exist or tl->next does not exist or simply both exist but are
++ * different. In this last case, it may be that cl->next->value is made
++ * of spaces. If this is the case, tl advances once more.
++ */
++
++ if (tl->next){
++ if (cl && cl->next && value_is_space(cl->next->value))
++ tl = tl->next;
++ if (tl->next)
++ free_qs(&(tl->next));
++ }
++
++ if (!p)
++ free_qs(&cqstring);
++
++ return cqstring;
++ }
++
++ /* This function trims cl so that it returns a real quote string based
++ * on information gathered from the previous and next lines. pl and cl are
++ * also trimmed, but that is done in another function, not here.
++ */
++ QSTRING_S *
++ fix_qstring(QSTRING_S *cl, QSTRING_S *nl, QSTRING_S *pl)
++ {
++ QSTRING_S *cqstring = cl, *nqstring = nl, *pqstring = pl;
++ int c, n;
++
++ if (qstring_is_normal(cl))
++ return cl;
++
++ c = count_levels_qstring(cl);
++ n = same_qstring(cl,nl);
++
++ if (!n){ /* no next line or no agreement with next line */
++ int p = same_qstring(pl, cl); /* number of agreements between pl and cl */
++ QSTRING_S *tl; /* test line */
++
++ /*
++ * Here p <= c, so either p < c or p == c. If p == c, we are done,
++ * and return cl. If not, there are two cases, either p == 0 or
++ * 0 < p < c. In the first case, we do not have enough evidence
++ * to return anything other than the normal part of cl, in the second
++ * case we can only return p levels of cl.
++ */
++
++ if (p == c)
++ tl = cqstring;
++ else{
++ if (p){
++ for (c = 1; c < p; c++)
++ cl = cl->next;
++ free_qs(&(cl->next));
++ tl = cqstring;
++ }
++ else{
++ int done = 0;
++ QSTRING_S *al = cl; /* another line */
++ /*
++ * Ok, we reaelly don't have enough evidence to return anything,
++ * different from the normal part of cl, but it could be possible
++ * that we may want to accept the not-normal part, so we better
++ * make an extra test to determine what needs to be freed
++ */
++ while (pl && cl && cl->qstype == pl->qstype
++ && !strucmp(cl->value, pl->value)){
++ cl = cl->next;
++ pl = pl->next;
++ }
++ if (pl && cl && cl->qstype == pl->qstype
++ && strcmp_qs(pl->value, cl->value))
++ cl = cl->next; /* next level differs only in spaces */
++ while (!done){
++ while (cl && cl->qstype == qsNormal)
++ cl = cl->next;
++ if (cl){
++ if ((cl->qstype == qsString)
++ && (cl->value[strlen(cl->value) - 1] == '>'))
++ cl = cl->next;
++ else done++;
++ }
++ else done++;
++ }
++ if (al == cl){
++ free_qs(&(cl));
++ tl = cl;
++ }
++ else {
++ while (al && (al->next != cl))
++ al = al->next;
++ cl = al;
++ if (cl && cl->next)
++ free_qs(&(cl->next));
++ tl = cqstring;
++ }
++ }
++ }
++ return tl;
++ }
++ if (n + 1 < c){ /* if there are not enough agreements */
++ int p = same_qstring(pl, cl); /* number of agreement between pl and cl */
++ QSTRING_S *tl; /* test line */
++ /*
++ * There's no way we can use cl in this case, but we can use
++ * part of cl, this is if pl does not have more agreements
++ * with cl.
++ */
++ if (p == c)
++ tl = cqstring;
++ else{
++ int m = p < n ? n : p;
++ for (c = 1; c < m; c++){
++ pl = pl ? pl->next : (QSTRING_S *) NULL;
++ nl = nl ? nl->next : (QSTRING_S *) NULL;
++ cl = cl->next;
++ }
++ if (p == n && pl && pl->next && nl && nl->next
++ && ((cl->next->qstype == pl->next->qstype)
++ || (cl->next->qstype == nl->next->qstype))
++ && (strcmp_qs(cl->next->value, pl->next->value)
++ || strcmp_qs(pl->next->value, cl->next->value)
++ || strcmp_qs(cl->next->value, nl->next->value)
++ || strcmp_qs(nl->next->value, cl->next->value)))
++ cl = cl->next; /* next level differs only in spaces */
++ if (cl->next)
++ free_qs(&(cl->next));
++ tl = cqstring;
++ }
++ return tl;
++ }
++ if (n + 1 == c){
++ int p = same_qstring(pl, cl);
++ QSTRING_S *tl; /* test line */
++
++ /*
++ * p <= c, so p <= n+1, which means p < n + 1 or p == n + 1.
++ * If p < n + 1, then p <= n.
++ * so we have three possibilities:
++ * p == n + 1 or p == n or p < n.
++ * In the first case we copy p == n + 1 == c levels, in the second
++ * and third case we copy n levels, and check if we can copy the
++ * n + 1 == c level.
++ */
++ if (p == n + 1) /* p == c, in the above sense of c */
++ tl = cl; /* use cl, this is enough evidence */
++ else{
++ for (c = 1; c < n; c++)
++ cl = cl->next;
++ /*
++ * Here c == n, we only have one more level of cl, and at least one
++ * more level of nl
++ */
++ if (cl->next->qstype == qsNormal)
++ cl = cl->next;
++ if (cl->next)
++ free_qs(&(cl->next));
++ tl = cqstring;
++ }
++ return tl;
++ }
++ if (n == c) /* Yeah!!! */
++ return cqstring;
++ }
++
++ QSTRING_S *
++ fix_qstring_allowed(QSTRING_S *cl, QSTRING_S *nl, QSTRING_S *pl)
++ {
++ if(!cl)
++ return (QSTRING_S *) NULL;
++
++ if (qs_allowed(cl))
++ cl->next = fix_qstring_allowed(cl->next, (nl ? nl->next : NULL),
++ (pl ? pl->next : NULL));
++ else
++ if((nl && cl->qstype == nl->qstype) || (pl && cl->qstype == pl->qstype)
++ || (!nl && !pl))
++ free_qs(&cl);
++ return cl;
++ }
++
++ /*
++ * This function flattens the quote string returned to us by is_quote. A
++ * crash in this function implies a bug elsewhere.
++ */
++ void
++ flatten_qstring(QSTRING_S *qs, char *buff, int bufflen)
++ {
++ int i, j;
++ if(!buff || bufflen <= 0)
++ return;
++
++ for (i = 0; qs; qs = qs->next)
++ for (j = 0; i < bufflen - 1
++ && (qs->value[j]) && (buff[i++] = qs->value[j]); j++);
++ buff[i] = '\0';
++ }
++
++ /*
++ * Given a string, we return the position where the function thinks that
++ * the quote string is over, if you are ever thinking of fixing something,
++ * you got to the right place. Memory freed by caller. Experience shows
++ * that it only makes sense to initialize memory when we need it, not at
++ * the start of this function.
++ */
++ QSTRING_S *
++ is_quote (char *qs,char *word, int been_here)
++ {
++ int i = 0, j, nxt, prev, finished = 0, offset;
++ unsigned char c;
++ QSTRING_S *qstring = (QSTRING_S *) NULL;
++
++ if (!word || !word[0])
++ return (QSTRING_S *) NULL;
++
++ while (!finished){
++ /*
++ * Before we apply our rules, let's advance past the quote string
++ * given by the user, this will avoid not recognition of the
++ * user's indent string and application of the arbitrary rules
++ * below. Notice that this step may bring bugs into this
++ * procedure, but these bugs will only appear if the indent string
++ * is really really strange and the text to be justified
++ * cooperates a lot too, so in general this will not be a problem.
++ * If you are concerned about this bug, simply remove the
++ * following lines after this comment and before the "switch"
++ * command below and use a more normal quote string!.
++ */
++ i += advance_quote_string(qs, word, i);
++ if (!word[i]) /* went too far? */
++ return qs_add(qs, word, qsNormal, 0, i, 0, 0);
++
++ switch (c = (unsigned char) now(word,i)){
++ case NBSP:
++ case TAB :
++ case ' ' : { QSTRING_S *nextqs, *d;
++
++ for (; ISspace(word[i]); i++); /* FIX ME */
++ nextqs = is_quote(qs,word+i, 1);
++ /*
++ * Merge qstring and nextqs, since this is an artificial
++ * separation, unless nextqs is of different type.
++ * What this means in practice is that if
++ * qs->qstype == qsNormal and qs->next != NULL, then
++ * qs->next->qstype != qsNormal.
++ *
++ * Can't use qs_add to merge because it could lead
++ * to an infinite loop (e.g a line "^ ^").
++ */
++ i += nextqs && nextqs->qstype == qsNormal
++ ? strlen(nextqs->value) : 0;
++ qstring = (QSTRING_S *) malloc (sizeof(QSTRING_S));
++ memset (qstring, 0, sizeof(QSTRING_S));
++ qstring->value = (char *) malloc((i+1)*sizeof(char));
++ strncpy(qstring->value, word, i);
++ qstring->value[i] = '\0';
++ qstring->qstype = qsNormal;
++ if(nextqs && nextqs->qstype == qsNormal){
++ d = nextqs->next;
++ nextqs->next = NULL;
++ qstring->next = d;
++ free_qs(&nextqs);
++ }
++ else
++ qstring->next = nextqs;
++
++ return qstring;
++ }
++ break;
++ case RPAREN: /* parenthesis ')' */
++ if ((i != 0) || ((i == 0) && been_here))
++ i++;
++ else
++ if (i == 0)
++ return qs_add(qs, word, qsChar, i, i, 1, 1);
++ else
++ finished++;
++ break;
++
++ case ':': /* colon */
++ case '~': nxt = next(word,i);
++ if ((is_tilde(c) && (nxt == '/'))
++ || (is_colon(c) && !is_cquote(nxt)
++ && !is_cword(nxt) && nxt != RPAREN))
++ finished++;
++ else if (is_cquote(c)
++ || is_cquote(nxt)
++ || (c != '~' && nxt == RPAREN)
++ || (i != 0 && ISspace(nxt))
++ || is_cquote(prev = before(word,i))
++ || (ISspace(prev) && !is_tilde(c))
++ || (is_tilde(c) && nxt != '/'))
++ i++;
++ else if (i == 0 && been_here)
++ return qs_add(qs, word, qsChar, i, i, 1, 1);
++ else
++ finished++;
++ break;
++
++ case '<' :
++ case '=' :
++ case '-' : offset = is_cquote(nxt = next(word,i)) ? 2
++ : (nxt == c && is_cquote(next(word,i+1))) ? 3 : -1;
++
++ if (offset > 0)
++ return qs_add(qs, word, qsString, i, i, offset, 1);
++ else
++ finished++;
++ break;
++
++ case '[' :
++ case '+' : /* accept +>, *> */
++ case '*' : if (is_rarrow(nxt = next(word, i)) || /* stars */
++ (ISspace(nxt) && is_rarrow(next(word,i+1))))
++ i++;
++ else
++ finished++;
++ break;
++
++ case '^' :
++ case '!' :
++ case '%' : if (next(word,i) != c)
++ return qs_add(qs, word, qsChar, i, i+1, 0, 1);
++ else
++ finished++;
++ break;
++
++ case '_' : if(ISspace(next(word, i)))
++ return qs_add(qs, word, qsChar, i, i+1, 0, 1);
++ else
++ finished++;
++ break;
++
++ case '#' : { QStrType qstype = qsChar;
++ if((nxt = next(word, i)) != c){
++ if(isdigit((int) nxt))
++ qstype = qsGdb;
++ else
++ if(word_is_prog(word))
++ qstype = qsProg;
++ return qs_add(qs, word, qstype, i, i+1, 0, 1);
++ }
++ else
++ finished++;
++ break;
++ }
++
++ default:
++ if (is_cquote(c))
++ i++;
++ else if (is_cletter(c)){
++ for (j = i; (is_cletter(nxt = next(word,j)) || is_cnumber(nxt))
++ && !(ISspace(nxt));j++);
++ /*
++ * The whole reason why we are splitting the quote
++ * string is so that we will be able to accept quote
++ * strings that are strange in some way. Here we got to
++ * a point in which a quote string might exist, but it
++ * could be strange, so we need to create a "next" field
++ * for the quote string to warn us that something
++ * strange is coming. We need to confirm if this is a
++ * good choice later. For now we will let it pass.
++ */
++ if (isaword(word,i,j) || isamailbox(word,i,j)){
++ int offset;
++ QStrType qstype;
++
++ offset = (is_cquote(c = next(word,j))
++ || (c == RPAREN)) ? 2
++ : ((ISspace(c)
++ && is_cquote(next(word,j+1))) ? 3 : -1);
++
++ qstype = (is_cquote(c) || (c == RPAREN))
++ ? (is_qsword(c) ? qsWord : qsString)
++ : ((ISspace(c) && is_cquote(next(word,j+1)))
++ ? (is_qsword(next(word,j+1))
++ ? qsWord : qsString)
++ : qsString);
++
++ /*
++ * qsWords are valid quote strings only when
++ * they are followed by text.
++ */
++ if (offset > 0 && qstype == qsWord &&
++ !allwd_after_qsword(now(word,j + offset)))
++ offset = -1;
++
++ if (offset > 0)
++ return qs_add(qs, word, qstype, i, j, offset, 1);
++ }
++ finished++;
++ }
++ else{
++ if(i > 0)
++ return qs_add(qs, word, qsNormal, 0, i, 0, 1);
++ else if(!forbidden(c))
++ return qs_add(qs, word, qsChar, 0, 1, 0, 1);
++ else /* chao pescao */
++ finished++;
++ }
++ break;
++ } /* End Switch */
++ } /* End while */
++ if (i > 0)
++ qstring = qs_add(qs, word, qsNormal, 0, i, 0, 0);
++ return qstring;
++ }
++
++ int
++ isaword(word,i,j)
++ char word[NSTRING];
++ int i;
++ int j;
++ {
++ return i <= j && is_cletter(word[i]) ?
++ (i < j ? isaword(word,i+1,j) : 1) : 0;
++ }
++
++ int
++ isamailbox(word,i,j)
++ char word[NSTRING];
++ int i, j;
++ {
++ return i <= j && (is_cletter(word[i]) || is_a_digit(word[i])
++ || word[i] == '.')
++ ? (i < j ? isamailbox(word,i+1,j) : 1) : 0;
++ }
++
++ /*
++ This routine removes the last part that is qsword or qschar that is not
++ followed by a normal part. This means that if a qsword or qschar is
++ followed by a qsnormal (or qsstring), we accept the qsword (or qschar)
++ as part of a quote string.
++ */
++ QSTRING_S *
++ remove_qsword(cl)
++ QSTRING_S *cl;
++ {
++ QSTRING_S *np = cl;
++ QSTRING_S *cp = np; /* this variable trails cl */
++
++ while(1){
++ while (cl && cl->qstype == qsNormal)
++ cl = cl->next;
++
++ if (cl){
++ if (((cl->qstype == qsWord) || (cl->qstype == qsChar))
++ && !exists_good_part(cl)){
++ if (np == cl) /* qsword or qschar at the beginning */
++ free_qs(&cp);
++ else{
++ while (np->next != cl)
++ np = np->next;
++ free_qs(&(np->next));
++ }
++ break;
++ }
++ else
++ cl = cl->next;
++ }
++ else
++ break;
++ }
++ return cp;
++ }
++
++ int
++ exists_good_part (cl)
++ QSTRING_S *cl;
++ {
++ return (cl ? (((cl->qstype != qsWord) && (cl->qstype != qsChar)
++ && qs_allowed(cl) && !value_is_space(cl->value))
++ ? 1 : exists_good_part(cl->next))
++ : 0);
++ }
++
++ int
++ line_isblank(char *q, char *GLine, char *NLine, char *PLine, int buflen)
++ {
++ int n = 0;
++ QSTRING_S *cl;
++ char qstr[NSTRING];
++
++ cl = do_raw_quote_match(q, GLine, NLine, PLine, NULL, NULL);
++
++ flatten_qstring(cl, qstr, NSTRING);
++
++ free_qs(&cl);
++
++ for(n = strlen(qstr); n < buflen && GLine[n]; n++)
++ if(!ISspace((unsigned char) GLine[n]))
++ return(FALSE);
++
++ return(TRUE);
++ }
++
++ QSTRING_S *
++ do_raw_quote_match(char *q, char *GLine, char *NLine, char *PLine, QSTRING_S **nlp, QSTRING_S **plp)
++ {
++ QSTRING_S *cl, *nl = NULL, *pl = NULL;
++ char nbuf[NSTRING], pbuf[NSTRING], buf[NSTRING];
++ int emptypl = 0, emptynl = 0;
++
++ if (!(cl = is_quote(q, GLine, 0))) /* if nothing in, nothing out */
++ return cl;
++
++ nl = is_quote(q, NLine, 0); /* Next Line */
++ if (nlp) *nlp = nl;
++ pl = is_quote(q, PLine, 0); /* Previous Line */
++ if (plp) *plp = pl;
++ /*
++ * If there's nothing in the preceeding or following line
++ * there is not enough information to accept it or discard it. In this
++ * case it's likely to be an isolated line, so we better accept it
++ * if it does not look like a word.
++ */
++ flatten_qstring(pl, pbuf, NSTRING);
++ emptypl = (!PLine || !PLine[0] ||
++ (pl && value_is_space(pbuf)) && !PLine[strlen(pbuf)]) ? 1 : 0;
++ if (emptypl){
++ flatten_qstring(nl, nbuf, NSTRING);
++ emptynl = (!NLine || !NLine[0] ||
++ (nl && value_is_space(nbuf) && !NLine[strlen(nbuf)])) ? 1 : 0;
++ if (emptynl){
++ cl = remove_qsword(cl);
++ if((cl = fix_qstring_allowed(cl, NULL, NULL)) != NULL)
++ cl = qs_remove_trailing_spaces(cl);
++ free_qs(&nl);
++ free_qs(&pl);
++ if(nlp) *nlp = NULL;
++ if(plp) *plp = NULL;
++
++ return cl;
++ }
++ }
++
++ /*
++ * If either cl, nl or pl contain suspicious characters that may make
++ * them (or not) be quote strings, we need to fix them, so that the
++ * next pass will be done correctly.
++ */
++
++ cl = fix_qstring(cl, nl, pl);
++ nl = trim_qs_from_cl(cl, nl, NULL);
++ pl = trim_qs_from_cl(cl, NULL, pl);
++ if((cl = fix_qstring_allowed(cl, nl, pl)) != NULL){
++ nl = trim_qs_from_cl(cl, nl, NULL);
++ pl = trim_qs_from_cl(cl, NULL, pl);
++ }
++ else{
++ free_qs(&nl);
++ free_qs(&pl);
++ }
++ if(nlp)
++ *nlp = nl;
++ else
++ free_qs(&nl);
++ if(plp)
++ *plp = pl;
++ else
++ free_qs(&pl);
++ return cl;
++ }
++
++ QSTRING_S *
++ do_quote_match(q, GLine, NLine, PLine, rqstr, rqstrlen, plb)
++ char *q, *GLine, *NLine, *PLine, *rqstr;
++ int rqstrlen, plb;
++ {
++ QSTRING_S *cl, *nl = NULL, *pl = NULL;
++ int c, n, p,i, j, NewP, NewC, NewN, clength, same = 0;
++ char nbuf[NSTRING], pbuf[NSTRING], buf[NSTRING];
++
++ if(rqstr)
++ *rqstr = '\0';
++
++ /* if nothing in, nothing out */
++ cl = do_raw_quote_match(q, GLine, NLine, PLine, &nl, &pl);
++ if(cl == NULL){
++ free_qs(&nl);
++ free_qs(&pl);
++ return cl;
++ }
++
++ flatten_qstring(cl, rqstr, rqstrlen);
++ flatten_qstring(cl, buf, NSTRING);
++ flatten_qstring(nl, nbuf, NSTRING);
++ flatten_qstring(pl, pbuf, NSTRING);
++
++ /*
++ * Once upon a time, is_quote used to return the length of the quote
++ * string that it had found. One day, not long ago, black hand came
++ * and changed all that, and made is_quote return a quote string
++ * divided in several fields, making the algorithm much more
++ * complicated. Fortunately black hand left a few comments in the
++ * source code to make it more understandable. Because of this change
++ * we need to compute the lengths of the quote strings separately
++ */
++ c = buf && buf[0] ? strlen(buf) : 0;
++ n = nbuf && nbuf[0] ? strlen(nbuf) : 0;
++ p = pbuf && pbuf[0] ? strlen(pbuf) : 0;
++ /*
++ * When quote strings contain only blank spaces (ascii code 32) the
++ * above count is equal to the length of the quote string, but if
++ * there are TABS, the length of the quote string as seen by the user
++ * is different than the number that was just computed. Because of
++ * this we demand a recount (hmm.. unless you are in Florida, where
++ * recounts are forbidden)
++ */
++ NewP = strlenis(pbuf);
++ NewC = strlenis(buf);
++ NewN = strlenis(nbuf);
++
++ /*
++ * For paragraphs with spaces in the first line, but no space in the
++ * quote string of the second line, we make sure we choose the quote
++ * string without a space at the end of it.
++ */
++ if ((NLine && !NLine[0])
++ && ((PLine && !PLine[0])
++ || (((same = same_qstring(pl, cl)) != 0)
++ && (same != count_levels_qstring(cl)))))
++ cl = qs_remove_trailing_spaces(cl);
++ else
++ if (NewC > NewN){
++ int agree = 0;
++ for (j = 0; (j < n) && (GLine[j] == NLine[j]); j++);
++ clength = j;
++ /* clength is the common length in which Gline and Nline agree */
++ /* j < n means that they do not agree fully */
++ /* GLine = " \tText"
++ NLine = " Text" */
++ if(j == n)
++ agree++;
++ if (clength < n){ /* see if buf and nbuf are padded with spaces and tabs */
++ for (i = clength; i < n && ISspace(NLine[i]); i++);
++ if (i == n){/* padded NLine until the end of spaces? */
++ for (i = clength; i < c && ISspace(GLine[i]); i++);
++ if (i == c) /* Padded CLine until the end of spaces? */
++ agree++;
++ }
++ }
++ if (agree){
++ for (j = clength; j < c && ISspace(GLine[j]); j++);
++ if (j == c){
++ /*
++ * If we get here, it means that the current line has the same
++ * quote string (visually) than the next line, but both of them
++ * are padded with different amount of TABS or spaces at the end.
++ * The current line (GLine) has more spaces/TABs than the next
++ * line. This is the typical situation that is found at the
++ * begining of a paragraph. We need to check this, however, by
++ * checking the previous line. This avoids that we confuse
++ * ourselves with being in the last line of a paragraph.
++ * Example when it should not free_qs(cl)
++ * " Text in Paragraph 1" (PLine)
++ * " Text in Paragraph 1" (GLine)
++ * " Other Paragraph Number 2" (NLine)
++ *
++ * Example when it should free_qs(cl):
++ * ":) " (PLine) p = 3, j = 3
++ * ":) Text" (GLine) c = 5
++ * ":) More text" (NLine) n = 3
++ *
++ * Example when it should free_qs(cl):
++ * ":) " (PLine) p = 3, j = 3
++ * ":) > > > Text" (GLine) c = 11
++ * ":) > > > More text" (NLine) n = 9
++ *
++ * Example when it should free_qs(cl):
++ * ":) :) " (PLine) p = 6, j = 3
++ * ":) > > > Text" (GLine) c = 11
++ * ":) > > > More text" (NLine) n = 9
++ *
++ * Example when it should free_qs(cl):
++ * ":) > > > " (PLine) p = 13, j = 11
++ * ":) > > > Text" (GLine) c = 11
++ * ":) > > > More text" (NLine) n = 9
++ *
++ * The following example is very interesting. The "Other Text"
++ * line below should free the quote string an make it equal to the
++ * quote string of the line below it, but any algorithm trying
++ * to advance past that line should make it stop there, so
++ * we need one more check, to check the raw quote string and the
++ * processed quote string at the same time.
++ * FREE qs in this example.
++ * " Some Text" (PLine) p = 3, j = 0
++ * "\tOther Text" (GLine) c = 1
++ * " More Text" (NLine) n = 3
++ *
++ */
++ for (j = 0; (j < p) && (GLine[j] == PLine[j]); j++);
++ if ((p != c || j != p) && NLine[n])
++ if(!get_indent_raw_line(q, PLine, nbuf, NSTRING, p, plb)
++ || NewP + strlenis(nbuf) != NewC){
++ free_qs(&cl);
++ free_qs(&pl);
++ return nl;
++ }
++ }
++ }
++ }
++
++ free_qs(&nl);
++ free_qs(&pl);
++
++ return cl;
++ }
++
++ /*
++ * Given a line, an initial position, and a quote string, we advance the
++ * current line past the quote string, including arbitraty spaces
++ * contained in the line, except that it removes trailing spaces. We do
++ * not handle TABs, if any, contained in the quote string. At least not
++ * yet.
++ *
++ * Arguments: q - quote string
++ * l - a line to process
++ * i - position in the line to start processing. i = 0 is the
++ * begining of that line.
++ */
++ int
++ advance_quote_string(q, l, i)
++ char *q;
++ char l[NSTRING];
++ int i;
++ {
++ int n = 0, j = 0, is = 0, es = 0;
++ int k, m, p, adv;
++ char qs[NSTRING] = {'\0'};
++ if(!q || !*q)
++ return(0);
++ for (p = strlen(q); (p > 0) && (q[p - 1] == ' '); p--, es++);
++ if (!p){ /* string contains only spaces */
++ for (k = 0; ISspace(l[i + k]); k++);
++ k -= k % es;
++ return k;
++ }
++ for (is = 0; ISspace(q[is]); is++); /* count initial spaces */
++ for (m = 0 ; is + m < p ; m++)
++ qs[m] = q[is + m]; /* qs = quote string without any space at the end */
++ /* advance as many spaces as there are at the begining */
++ for (k = 0; ISspace(l[i + j]); k++, j++);
++ /* now find the visible string in the line */
++ for (m = 0; qs[m] && l[i + j] == qs[m]; m++, j++);
++ if (!qs[m]){ /* no match */
++ /*
++ * So far we have advanced at least "is" spaces, plus the visible
++ * string "qs". Now we need to advance the trailing number of
++ * spaces "es". If we can do that, we have found the quote string.
++ */
++ for (p = 0; ISspace(l[i + j + p]); p++);
++ adv = advance_quote_string(q, l, i + j + ((p < es) ? p : es));
++ n = ((p < es) ? 0 : es) + k + m + adv;
++ }
++ return n;
++ }
++
++ /*
++ * This function returns the effective length in screen of the quote
++ * string. If the string contains a TAB character, it is added here, if
++ * not, the length returned is the length of the string
++ */
++ int strlenis(char *qstr)
++ {
++ int i, rv = 0;
++ for (i = 0; qstr && qstr[i]; i++)
++ rv += ((qstr[i] == TAB) ? (~rv & 0x07) + 1 : 1);
++ return rv;
++ }
++
++ int
++ is_indent (word, plb)
++ char word[NSTRING];
++ int plb;
++ {
++ int i = 0, finished = 0, c, nxt, j, k, digit = 0, bdigits = -1, alpha = 0;
++
++ if (!word || !word[0])
++ return i;
++
++ for (i = 0, j = 0; ISspace(word[i]); i++, j++);
++ while ((i < NSTRING - 2) && !finished){
++ switch (c = now(word,i)){
++ case NBSP:
++ case TAB :
++ case ' ' : for (; ISspace(word[i]); i++);
++ if (!is_indent_char(now(word,i)))
++ finished++;
++ break;
++
++ case '+' :
++ case '.' :
++ case ']' :
++ case '*' :
++ case '}' :
++ case '-' :
++ case RPAREN:
++ nxt = next(word,i);
++ if ((c == '.' && allowed_after_period(nxt) && alpha)
++ || (c == '*' && allowed_after_star(nxt))
++ || (c == '}' && allowed_after_braces(nxt))
++ || (c == '-' && allowed_after_dash(nxt))
++ || (c == '+' && allowed_after_dash(nxt))
++ || (c == RPAREN && allowed_after_parenth(nxt))
++ || (c == ']' && allowed_after_parenth(nxt)))
++ i++;
++ else
++ finished++;
++ break;
++
++ default : if (is_a_digit(c) && plb){
++ if (bdigits < 0)
++ bdigits = i; /* first digit */
++ for (k = i; is_a_digit(now(word,k)); k++);
++ if (k - bdigits > 2){ /* more than 2 digits? */
++ i = bdigits; /* too many! */
++ finished++;
++ }
++ else{
++ if(allowed_after_digit(now(word,k),word,k)){
++ alpha++;
++ i = k;
++ }
++ else{
++ i = bdigits;
++ finished++;
++ }
++ }
++ }
++ else
++ finished++;
++ break;
++
++ }
++ }
++ if (i == j)
++ i = 0; /* there must be something more than spaces in an indent string */
++ return i;
++ }
++
++ int
++ get_indent_raw_line(char *q, char *GLine, char *buf, int buflen, int k, int plb)
++ {
++ int i, j;
++ char testline[1024];
++
++ if(k > 0){
++ for(j = 0; GLine[j] != '\0'; j++){
++ testline[j] = GLine[j];
++ testline[j+1] = '\0';
++ if(strlenis(testline) >= strlenis(buf))
++ break;
++ }
++ k = ++j; /* reset k */
++ }
++ i = is_indent(GLine+k, plb);
++
++ for (j = 0; j < i && j < buflen && (buf[j] = GLine[j + k]); j++);
++ buf[j] = '\0';
++
++ return i;
++ }
++
+diff -rc alpine-2.00/pith/osdep/color.h alpine-2.00.I.USE/pith/osdep/color.h
+*** alpine-2.00/pith/osdep/color.h 2008-03-24 12:35:31.000000000 -0700
+--- alpine-2.00.I.USE/pith/osdep/color.h 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 43,48 ****
+--- 43,69 ----
+ #define PSC_REV 0x2
+ #define PSC_RET 0x4 /* return an allocated copy of previous color */
+
++ /*
++ * struct that will help us determine what the quote string of a line
++ * is. The "next" field indicates the presence of a possible continuation.
++ * The idea is that if a continuation fails, we free it and check for the
++ * remaining structure left
++ */
++
++ typedef enum {qsNormal, qsString, qsWord, qsChar,
++ qsGdb, qsProg, qsText} QStrType;
++
++ typedef struct QSTRING {
++ char *value; /* possible quote string */
++ QStrType qstype; /* type of quote string */
++ struct QSTRING *next; /* possible continuation */
++ } QSTRING_S;
++
++ #define UCH(c) ((unsigned char) (c))
++ #define NBSP UCH('\240')
++ #define ISspace(c) (UCH(c) == ' ' || UCH(c) == TAB || UCH(c) == NBSP)
++
++
+
+ /*
+ * MATCH_NORM_COLOR means that the color that is set to this value
+***************
+*** 92,97 ****
+--- 113,123 ----
+ char *pico_get_last_bg_color(void);
+ char *color_to_canonical_name(char *);
+ int pico_count_in_color_table(void);
++ int is_indent(char *, int);
++ int get_indent_raw_line (char *, char *, char *, int, int, int);
++ int line_isblank(char *, char *, char *, char *, int);
++ int strlenis(char *);
++ int value_is_space(char *);
+
+
+ #endif /* PITH_OSDEP_COLOR_INCLUDED */
+diff -rc alpine-2.00/pith/osdep/domnames.c alpine-2.00.I.USE/pith/osdep/domnames.c
+*** alpine-2.00/pith/osdep/domnames.c 2006-11-17 18:46:41.000000000 -0800
+--- alpine-2.00.I.USE/pith/osdep/domnames.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 51,57 ****
+ char **alias;
+ char *maybe = NULL;
+
+! gethostname(hname, MAX_ADDRESS);
+ he = gethostbyname(hname);
+ hostname[0] = '\0';
+
+--- 51,70 ----
+ char **alias;
+ char *maybe = NULL;
+
+! if (gethostname(hname, MAX_ADDRESS)) hname[0] = 0xff;
+! /* sanity check of hostname string */
+! for (dn = hname; (*dn > 0x20) && (*dn < 0x7f); ++dn);
+! if (*dn) { /* only if invalid string returned */
+! #if 0
+! hostname[0] = domainname[0] = '\0';
+! #else
+! /* Contrary to the comments above, the UNIX code does not expect
+! these strings to be blank.
+! */
+! strcpy (hostname, (strcpy (domainname,"unknown")));
+! #endif
+! return;
+! }
+ he = gethostbyname(hname);
+ hostname[0] = '\0';
+
+diff -rc alpine-2.00/pith/osdep/hostname.c alpine-2.00.I.USE/pith/osdep/hostname.c
+*** alpine-2.00/pith/osdep/hostname.c 2006-12-11 10:06:32.000000000 -0800
+--- alpine-2.00.I.USE/pith/osdep/hostname.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 47,53 ****
+ {
+ #if HAVE_GETHOSTNAME
+
+! return(gethostname(hostname, size));
+
+ #elif HAVE_UNAME
+
+--- 47,57 ----
+ {
+ #if HAVE_GETHOSTNAME
+
+! if(gethostname(hostname, size)) return -1;
+! /* sanity check of hostname string */
+! for (*dn = hname; (*dn > 0x20) && (*dn < 0x7f); ++dn);
+! if (*dn) strcpy (hostname,"unknown");
+! return 0;
+
+ #elif HAVE_UNAME
+
+diff -rc alpine-2.00/pith/pattern.c alpine-2.00.I.USE/pith/pattern.c
+*** alpine-2.00/pith/pattern.c 2008-07-14 11:01:54.000000000 -0700
+--- alpine-2.00.I.USE/pith/pattern.c 2011-02-07 20:33:41.000000000 -0800
+***************
+*** 1755,1761 ****
+ SortOrder def_sort;
+ int def_sort_rev;
+
+! if(decode_sort(p, &def_sort, &def_sort_rev) != -1){
+ action->sort_is_set = 1;
+ action->sortorder = def_sort;
+ action->revsort = (def_sort_rev ? 1 : 0);
+--- 1755,1761 ----
+ SortOrder def_sort;
+ int def_sort_rev;
+
+! if(decode_sort(p, &def_sort, &def_sort_rev, 0) != -1){
+ action->sort_is_set = 1;
+ action->sortorder = def_sort;
+ action->revsort = (def_sort_rev ? 1 : 0);
+***************
+*** 5482,5487 ****
+--- 5482,5496 ----
+ break;
+
+ case '#':
++ #ifndef _WINDOWS
++ if(!struncmp(patfolder, "#md/", 4)
++ || !struncmp(patfolder, "#mc/", 4)){
++ maildir_file_path(patfolder, tmp1);
++ if(!strcmp(patfolder, stream->mailbox))
++ match++;
++ break;
++ }
++ #endif
+ if(!strcmp(patfolder, stream->mailbox))
+ match++;
+
+***************
+*** 7894,7900 ****
+ int we_cancel = 0, width;
+ CONTEXT_S *save_context = NULL;
+ char buf[MAX_SCREEN_COLS+1], sbuf[MAX_SCREEN_COLS+1];
+! char *save_ref = NULL;
+ #define FILTMSG_MAX 30
+
+ if(!stream)
+--- 7903,7909 ----
+ int we_cancel = 0, width;
+ CONTEXT_S *save_context = NULL;
+ char buf[MAX_SCREEN_COLS+1], sbuf[MAX_SCREEN_COLS+1];
+! char *save_ref = NULL, *save_dstfldr = NULL, *save_dstfldr2 = NULL;
+ #define FILTMSG_MAX 30
+
+ if(!stream)
+***************
+*** 7928,7933 ****
+--- 7937,7952 ----
+ if(F_OFF(F_QUELL_FILTER_MSGS, ps_global))
+ we_cancel = busy_cue(buf, NULL, 0);
+
++ #ifndef _WINDOWS
++ if(!struncmp(dstfldr, "#md/", 4) || !struncmp(dstfldr, "#mc/", 4)){
++ char tmp1[MAILTMPLEN];
++ maildir_file_path(dstfldr, tmp1);
++ save_dstfldr2 = dstfldr;
++ save_dstfldr = cpystr(tmp1);
++ dstfldr = save_dstfldr;
++ }
++ #endif
++
+ if(!is_absolute_path(dstfldr)
+ && !(save_context = default_save_context(ps_global->context_list)))
+ save_context = ps_global->context_list;
+***************
+*** 7991,7996 ****
+--- 8010,8020 ----
+ if(we_cancel)
+ cancel_busy_cue(buf[0] ? 0 : -1);
+
++ if(save_dstfldr){
++ fs_give((void **)&save_dstfldr);
++ dstfldr = save_dstfldr2;
++ }
++
+ return(buf[0] != '\0');
+ }
+
+diff -rc alpine-2.00/pith/pineelt.h alpine-2.00.I.USE/pith/pineelt.h
+*** alpine-2.00/pith/pineelt.h 2008-07-09 22:01:13.000000000 -0700
+--- alpine-2.00.I.USE/pith/pineelt.h 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 40,45 ****
+--- 40,47 ----
+ PINETHRD_S *pthrd;
+ PARTEX_S *exceptions;
+ ICE_S *ice;
++ char *firsttext;
++ char *firsttextraw;
+ /* per-message pine state bits */
+ unsigned int hidden:1;
+ unsigned int excluded:1;
+diff -rc alpine-2.00/pith/pine.hlp alpine-2.00.I.USE/pith/pine.hlp
+*** alpine-2.00/pith/pine.hlp 2008-08-22 17:07:05.000000000 -0700
+--- alpine-2.00.I.USE/pith/pine.hlp 2011-02-07 20:33:48.000000000 -0800
+***************
+*** 88,93 ****
+--- 88,94 ----
+ ALPINE_VERSION
+ ALPINE_REVISION
+ ALPINE_COMPILE_DATE
++ ALPINE_PATCHLEVEL
+ ALPINE_TODAYS_DATE
+ C_CLIENT_VERSION
+ _LOCAL_FULLNAME_
+***************
+*** 158,163 ****
+--- 159,172 ----
+ </DIV>
+
+ <P>
++ This version was modified from its original source code. More information
++ about some of the patches applied to this version can be found <A HREF="h_patches">here</A>.
++ <!--chtml if pinemode="running"-->
++ The patch level of this version, including creation date of the patch is:
++ <!--#echo var=ALPINE_PATCHLEVEL-->.
++ <!--chtml endif-->
++
++ <P>
+ Alpine is an &quot;Alternatively Licensed Program for Internet
+ News and Email&quot; produced by the University of Washington.
+ It is intended to be an easy-to-use program for
+***************
+*** 919,924 ****
+--- 928,1016 ----
+ &lt;End of Configuration Notes&gt;
+ </BODY>
+ </HTML>
++ ====== h_patches ======
++ <html>
++ <head>
++ <TITLE>Information on patches added to this release</TITLE>
++ </head>
++ <body>
++ <H1>Information on patches added to this release</H1>
++ <P>
++ This version of Alpine has been modified by including patches from
++ <A HREF="http://staff.washington.edu/chappa/alpine/">
++ http://staff.washington.edu/chappa/alpine/</A>. These patches include
++ new features and bug fixes. More complete information on each patch
++ included in this version can be found in the web.
++
++ <P>If you have any problems with this release of Alpine, please contact
++ Eduardo Chappa <A HREF="mailto:chappa@washington.edu">&lt;chappa@washington.edu&gt;</A>.
++
++ <P>The list of patches included in this release are:
++ <P>New Features:
++
++ <UL>
++ <LI> Enhanced Fancy thread interface. <A HREF="http://staff.washington.edu/chappa/alpine/info/fancy.html">(more)</A>
++ <!--chtml if pinemode="os_windows"-->
++
++ <!--chtml else-->
++ <LI> Patch that gives support for the maildir driver in Alpine <A HREF="h_config_maildir">(more)</A>
++ <!--chtml endif-->
++ <LI> Rules patch, to make Alpine flexible. <A HREF="h_config_new_rules">(more)</A>
++ <LI> Send mail from the command Line. <A HREF="http://staff.washington.edu/chappa/alpine/info/outgoing.html">(more)</A>
++ <LI> Add a few more options when replying to a message <A HREF="h_config_alt_reply_menu">(more)</A>
++ <LI> Choose a role when composing a message from a mailto: link <A HREF="http://staff.washington.edu/chappa/alpine/info/composeurl.html">(more)</A>
++ <LI> Alpine justifies paragraphs with more than one level of indentation. <A HREF="h_compose_justify">(more)</A>
++ <LI> Patch to write accents and foreign characters <A HREF="http://staff.washington.edu/chappa/alpine/info/WrtAcc.html">(more)</A>
++ <LI> Change your From Header without any effort! <A HREF="http://staff.washington.edu/chappa/alpine/info/fromheader.html">(more)</A>
++ <LI> Tab checks folders on cycles <A HREF="h_config_circular_tab">(more)</A>
++ <LI> Patch for Pico to update its status line according to cursor movements <A HREF="http://staff.washington.edu/chappa/alpine/info/status.html">(more)</A>
++ <LI> Reuse your old search pattern to create a new one <A HREF="http://staff.washington.edu/chappa/alpine/info/insertpat.html">(more)</A>
++ <LI> Paint special text in the body of a message in any color. <A HREF="h_config_special_text_to_color">(more)</A>
++ <LI> Select messages by the content of an arbitrary header. <A HREF="http://staff.washington.edu/chappa/alpine/info/searchheader.html">(more)</A>
++ <LI> Remove incorrect passwords from memory <A HREF="http://staff.washington.edu/chappa/alpine/info/delpassword.html">(more)</A>
++ <LI> Get the quota report in an IMAP server <A HREF="http://staff.washington.edu/chappa/alpine/info/quota.html">(more)</A>
++ <LI> Remove text until the end of the file or a message <A HREF="http://staff.washington.edu/chappa/alpine/info/DelText.html">(more)</A>
++ <LI> Get the internal name of a help topic to use it with a x-alpine-help or x-pine-help URL scheme. <A HREF="http://staff.washington.edu/chappa/alpine/info/help.html">(more)</A>
++ <LI> Get the number of characters in a composed message <A HREF="http://staff.washington.edu/chappa/alpine/info/count.html">(more)</A>
++ <LI> Configure ignoring change in size of a message <A HREF="h_config_ignore_size">(more)</A>
++ <LI> Add one more token to a sending filter <A HREF="http://staff.washington.edu/chappa/alpine/info/addressfilter.html">(more)</A>
++ <LI> Make Alpine preserve To: and Cc: fields <A HREF="h_config_preserve_field">(more)</A>
++ <LI> Allow non utf-8 piped input in Alpine <A HREF="http://staff.washington.edu/chappa/alpine/info/noutf8.html">(more)</A>
++ <LI> Allow errors in base64 encoding <A HREF="http://staff.washington.edu/chappa/alpine/info/base64errors.html">(more)</A>
++ <LI> Get the name of the slow server <A HREF="http://staff.washington.edu/chappa/alpine/info/streaminfo.html">(more)</A>
++ <LI> Color the text in the folder list screen <A HREF="http://staff.washington.edu/chappa/alpine/info/colorfolder.html">(more)</A>
++ <LI> Color text in the index screen <A HREF="http://staff.washington.edu/chappa/alpine/info/tokencolor.html">(more)</A>
++ <LI> Avoid clearing the screen when executing a display filter <A HREF="http://staff.washington.edu/chappa/alpine/info/silenttoken.html">(more)</A>
++ <LI> Cache OPENINGTEXT information <A HREF="http://staff.washington.edu/chappa/alpine/info/cachefirsttext.html">(more)</A>
++ <LI> Recognize multiline URLs <A HREF="http://staff.washington.edu/chappa/alpine/info/longurl.html">(more)</A>
++ <LI> Recognize the nametemplate token in a mailcap file <A HREF="http://staff.washington.edu/chappa/alpine/info/nametemplate.html">(more)</A>
++ <LI> Create new threads even when replying to a message <A HREF="http://staff.washington.edu/chappa/alpine/info/newthread.html">(more)</A>
++ </UL>
++
++ <P>Bug Fixes:
++
++ <UL>
++ <LI> Fix a bug that makes Alpine not to give a warning if the Newsgroup header is present <A HREF="http://staff.washington.edu/chappa/alpine/info/unverified.html">(more)</A>
++ <LI> Fix a bug in Pico which makes it not update the screen <A HREF="http://staff.washington.edu/chappa/alpine/info/replacebug.html">(more)</A>
++ <LI> Fix a bug in Pico and Pilot that makes them crash for bad locale information <A HREF="http://staff.washington.edu/chappa/alpine/info/nlinfobug.html">(more)</A>
++ <LI> Fix a bug in Alpine that makes it not to set a flag in a filtered message <A HREF="http://staff.washington.edu/chappa/alpine/info/filterflagbug.html">(more)</A>
++ <LI> Fix a bug that makes Alpine crash when suspending it <A HREF="http://staff.washington.edu/chappa/alpine/info/streamlock.html">(more)</A>
++ <LI> Fix a bug that makes Alpine crash when opening a unix type folder <A HREF="http://staff.washington.edu/chappa/alpine/info/unixnullbug.html">(more)</A>
++ <LI> Force update of the index screen after adding an address to the addressbook <A HREF="http://staff.washington.edu/chappa/alpine/info/updateindexcolors.html">(more)</A>
++ <LI> Fix a bug that makes Alpine ignore the week day of a preftime token <A HREF="http://staff.washington.edu/chappa/alpine/info/preftimebug.html">(more)</A>
++ <LI> Fix the type of a .docx document <A HREF="http://staff.washington.edu/chappa/alpine/info/docxmimetype.html">(more)</A>
++ <LI> Parse environment variables correctly <A HREF="http://staff.washington.edu/chappa/alpine/info/envvar.html">(more)</A>
++ <LI> Do not reopen a folder that is meant to be closed <A HREF="http://staff.washington.edu/chappa/alpine/info/closebug.html">(more)</A>
++ <LI> Fix a bug that makes Alpine crash when the screen is resized <A HREF="http://staff.washington.edu/chappa/alpine/info/resizeldap.html">(more)</A>
++ <LI> Fix a bug in the threading algorithm <A HREF="http://staff.washington.edu/chappa/alpine/info/threadbug.html">(more)</A>
++ <LI> Fix a memory leak in Alpine <A HREF="http://staff.washington.edu/chappa/alpine/info/composerleak.html">(more)</A>
++ <LI> Fix a bug that sends Alpine in an infinite loop <A HREF="http://staff.washington.edu/chappa/alpine/info/scrolltool.html">(more)</A>
++ <LI> Fix a bug that makes Alpine not give a correct new mail message <A HREF="http://staff.washington.edu/chappa/alpine/info/newmailmsg.html">(more)</A>
++ <LI> Fix a bug that makes Alpine not show a login prompt <A HREF="http://staff.washington.edu/chappa/alpine/info/loginbug.html">(more)</A>
++ <LI> Patch by Mark Crispin, which fixes a bug which makes Alpine not generate correct headers for servers that return UTF-8 names. <A HREF="http://staff.washington.edu/chappa/alpine/patches/others.html#markhostbug-2.00">(more)</A>
++ </UL>
++ </body>
++ </html>
+ ====== h_news_legal ======
+ <html>
+ <head>
+***************
+*** 3035,3043 ****
+--- 3127,3137 ----
+ <li><a href="h_config_alt_role_menu">FEATURE: <!--#echo var="FEAT_alternate-role-menu"--></a>
+ <li><a href="h_config_force_low_speed">FEATURE: <!--#echo var="FEAT_assume-slow-link"--></a>
+ <li><a href="h_config_auto_read_msgs">FEATURE: <!--#echo var="FEAT_auto-move-read-msgs"--></a>
++ <li><a href="h_config_auto_read_msgs_rules">FEATURE: <!--#echo var="FEAT_auto-move-read-msgs-using-rules"--></a>
+ <li><a href="h_config_auto_open_unread">FEATURE: <!--#echo var="FEAT_auto-open-next-unread"--></a>
+ <li><a href="h_config_auto_unselect">FEATURE: <!--#echo var="FEAT_auto-unselect-after-apply"--></a>
+ <li><a href="h_config_auto_unzoom">FEATURE: <!--#echo var="FEAT_auto-unzoom-after-apply"--></a>
++ <li><a href="h_config_circular_tab">FEATURE: <!--#echo var="FEAT_enable-circular-tab"--></a>
+ <li><a href="h_config_auto_zoom">FEATURE: <!--#echo var="FEAT_auto-zoom-after-select"--></a>
+ <li><a href="h_config_use_boring_spinner">FEATURE: <!--#echo var="FEAT_busy-cue-spinner-only"--></a>
+ <li><a href="h_config_check_mail_onquit">FEATURE: <!--#echo var="FEAT_check-newmail-when-quitting"--></a>
+***************
+*** 3120,3125 ****
+--- 3214,3220 ----
+ <li><a href="h_config_prefix_editing">FEATURE: <!--#echo var="FEAT_enable-reply-indent-string-editing"--></a>
+ <li><a href="h_config_enable_search_and_repl">FEATURE: <!--#echo var="FEAT_enable-search-and-replace"--></a>
+ <li><a href="h_config_sigdashes">FEATURE: <!--#echo var="FEAT_enable-sigdashes"--></a>
++ <li><a href="h_config_new_thread_blank_subject">FEATURE: <!--#echo var="FEAT_new-thread-on-blank-subject"--></a>
+ <li><a href="h_config_can_suspend">FEATURE: <!--#echo var="FEAT_enable-suspend"--></a>
+ <li><a href="h_config_enable_tab_complete">FEATURE: <!--#echo var="FEAT_enable-tab-completion"--></a>
+ <li><a href="h_config_enable_take_export">FEATURE: <!--#echo var="FEAT_enable-take-export"--></a>
+***************
+*** 3136,3142 ****
+--- 3231,3239 ----
+ <li><a href="h_config_full_auto_expunge">FEATURE: <!--#echo var="FEAT_expunge-without-confirm-everywhere"--></a>
+ <li><a href="h_config_no_fcc_attach">FEATURE: <!--#echo var="FEAT_fcc-without-attachments"--></a>
+ <li><a href="h_config_force_arrow">FEATURE: <!--#echo var="FEAT_force-arrow-cursor"--></a>
++ <li><a href="h_config_ignore_size">FEATURE: <!--#echo var="FEAT_ignore-size-changes"--></a>
+ <li><a href="h_config_forward_as_attachment">FEATURE: <!--#echo var="FEAT_forward-as-attachment"--></a>
++ <li><a href="h_config_preserve_field">FEATURE: <!--#echo var="FEAT_preserve-original-fields"--></a>
+ <li><a href="h_config_quell_empty_dirs">FEATURE: <!--#echo var="FEAT_quell-empty-directories"--></a>
+ <li><a href="h_config_hide_nntp_path">FEATURE: <!--#echo var="FEAT_hide-nntp-path"--></a>
+ <li><a href="h_config_attach_in_reply">FEATURE: <!--#echo var="FEAT_include-attachments-in-reply"--></a>
+***************
+*** 3402,3407 ****
+--- 3499,3505 ----
+ <li><a href="h_config_print_cat">OPTION: <!--#echo var="VAR_personal-print-category"--></a>
+ <li><a href="h_config_print_command">OPTION: <!--#echo var="VAR_personal-print-command"--></a>
+ <li><a href="h_config_post_char_set">OPTION: <!--#echo var="VAR_posting-character-set"--></a>
++ <li><a href="h_config_special_text_to_color">OPTION: <!--#echo var="VAR_h_config_special_text_to_color"--></a>
+ <li><a href="h_config_postponed_folder">OPTION: <!--#echo var="VAR_postponed-folder"--></a>
+ <li><a href="h_config_print_font_char_set">OPTION: Print-Font-Char-Set</a>
+ <li><a href="h_config_print_font_name">OPTION: Print-Font-Name</a>
+***************
+*** 3430,3438 ****
+--- 3528,3538 ----
+ <li><a href="h_config_sending_filter">OPTION: <!--#echo var="VAR_sending-filters"--></a>
+ <li><a href="h_config_sendmail_path">OPTION: <!--#echo var="VAR_sendmail-path"--></a>
+ <li><a href="h_config_signature_color">OPTION: Signature Color</a>
++ <li><a href="h_config_special_text_color">OPTION: Special Text Color</a>
+ <li><a href="h_config_signature_file">OPTION: <!--#echo var="VAR_signature-file"--></a>
+ <li><a href="h_config_smtp_server">OPTION: <!--#echo var="VAR_smtp-server"--></a>
+ <li><a href="h_config_sort_key">OPTION: <!--#echo var="VAR_sort-key"--></a>
++ <li><a href="h_config_thread_sort_key">OPTION: <!--#echo var="VAR_thread-sort-key"--></a>
+ <li><a href="h_config_speller">OPTION: <!--#echo var="VAR_speller"--></a>
+ <li><a href="h_config_sshcmd">OPTION: <!--#echo var="VAR_ssh-command"--></a>
+ <li><a href="h_config_ssh_open_timeo">OPTION: <!--#echo var="VAR_ssh-open-timeout"--></a>
+***************
+*** 4058,4063 ****
+--- 4158,4172 ----
+ key will Exit the Help system altogether.
+
+ <P>
++ The "N" command will tell you the internal name of the help text you are
++ reading each time, so that you can send this name in the text of a message
++ and create a direct link to that internal help using the x-pine-help URL
++ scheme. For example, the direct link to this item is
++ x-pine-help:h_special_help_nav. If you add this text to a message, then
++ a person using Pine to read such message would have a direct link to this
++ help text.
++
++ <P>
+ When you are finished reading this help text, you can press the
+ <!--chtml if pinemode="function_key"-->
+ F3 function
+***************
+*** 5316,5321 ****
+--- 5425,5583 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ======= h_thread_index_sort_arrival =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: Arrival</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: Arrival</H1>
++
++ The <EM>Arrival</EM> sort option arranges threads according to the last
++ time that a message was added to it. In this order the last thread
++ contains the most recent message in the folder.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ======= h_thread_index_sort_date =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: Date</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: Date</H1>
++
++ The <EM>Date</EM> sort option in the THREAD&nbsp;INDEX screen sorts
++ threads by the date in which messages were sent. The thread containing the
++ last message in this order is displayed last.
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ======= h_thread_index_sort_subj =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: Subject</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: Subject</H1>
++
++ The <EM>Subject</EM> sort option has not been defined yet.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ======= h_thread_index_sort_ordsubj =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: OrderedSubject</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: OrderedSubject</H1>
++
++ The <EM>OrderedSubject</EM> sort option in the THREAD&nbsp;INDEX screen is
++ the same as sorting by <A HREF="h_thread_index_sort_subj">Subject</A>.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ======= h_thread_index_sort_thread =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: Thread</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: Thread</H1>
++
++ The <EM>Thread</EM> sort option in the THREAD&nbsp;INDEX screen sorts all
++ messages by the proposed algorithm by Crispin and Murchison. In this
++ method of sorting once threads have been isolated they are sorted by the
++ date of their parents, or if that is missing, the first message in that
++ thread.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ======= h_thread_index_sort_from =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: From</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: From</H1>
++
++ The <EM>From</EM> sort option has not been defined yet.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ======= h_thread_index_sort_size =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: Size</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: Size</H1>
++
++ The <EM>Size</EM> sort option has not been defined yet.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ======= h_thread_index_sort_score =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: Score</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: Score</H1>
++
++ The <EM>Score</EM> sort option means that threads are sorted according to
++ the maximum score of a message in that thread. A thread all of whose
++ messages contain a smaller score than a message in some other thread is
++ placed in an earlier place in the list of messages for that folder; that
++ is, threads with the highest scores appear at the bottom of the index
++ list.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ======= h_thread_index_sort_to =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: To</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: To</H1>
++
++ The <EM>To</EM> sort option has not been defined yet.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ======= h_thread_index_sort_cc =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: Cc</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: Cc</H1>
++
++ The <EM>Cc</EM> sort option has not been defined yet.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ======= h_index_cmd_whereis =======
+ <HTML>
+ <HEAD>
+***************
+*** 6503,6508 ****
+--- 6765,6810 ----
+ &quot;type the character ^&quot;.
+
+ <P>
++ This version of Alpine contains an enhanced algorithm for justification,
++ which allows you to justify text that contains more complicated quote
++ strings. This algorithm is based on pragmatics, rather than on a theory,
++ and seems to work well with most messages. Below you will find technical
++ information on how this algorithm works.
++
++ <P>
++ When justifying, Alpine goes through each line of the text and tries to
++ determine for each line what the quote string of that line is. The quote
++ string you provided is always recognized. Among other characters
++ recognized is &quot;&gt;&quot;.
++
++ <P>
++ Some other constructions of quote strings are recognized only if they
++ appear enough in the text. For example &quot;Peter :&quot; is only
++ recognized if it appears in two consecutive lines.
++
++ <P>
++ Additionaly, Alpine recognizes indent-strings and justifies text in a
++ paragraph to the right of indent-string, padding with spaces if necessary.
++ An indent string is one which you use to delimit elements of a list. For
++ example, if you were to write a list of groceries, one may write:
++
++ <UL>
++ <LI> Fruit
++ <LI> Bread
++ <LI> Eggs
++ </UL>
++
++ <P>
++ In this case the character &quot;*&quot; is the indent-string. Aline
++ recognizes numbers (0, 1, 2.5, etc) also as indent-strings, and certain
++ combinations of spaces, periods, and parenthesis. In any case, numbers are
++ recognized <B>ONLY</B> if the line preceeding the given line is empty or
++ ends in one of the characters &quot;.&quot; or &quot;:&quot;.
++ In addition to the explanation of what constitutes a paragraph above, a
++ new paragraph is recognized when an indent-string is found in it (and
++ validated according to the above stated rules).
++
++ <P>
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
+***************
+*** 18069,18074 ****
+--- 18371,18377 ----
+ <A HREF="h_config_index_format">&quot;<!--#echo var="VAR_index-format"-->&quot;</A> option,
+ in the <A HREF="h_config_reply_intro">&quot;<!--#echo var="VAR_reply-leadin"-->&quot;</A> option,
+ in signature files,
++ in the <A HREF="h_config_reply_leadin_rules">&quot;new-rules&quot; option</A>,
+ in template files used in
+ <A HREF="h_rules_roles">&quot;roles&quot;</A>, and in the folder name
+ that is the target of a Filter Rule.
+***************
+*** 18081,18087 ****
+ <P>
+ <P>
+
+! <H1><EM>Tokens Available for all Cases (except Filter Rules)</EM></H1>
+
+ <DL>
+ <DT>SUBJECT</DT>
+--- 18384,18390 ----
+ <P>
+ <P>
+
+! <H1><EM>Tokens Available for all Cases (except Filter Rules or in some cases for new-rules)</EM></H1>
+
+ <DL>
+ <DT>SUBJECT</DT>
+***************
+*** 18114,18119 ****
+--- 18417,18431 ----
+ For example, &quot;mailbox@domain&quot;.
+ </DD>
+
++ <DT>ADDRESSTO</DT>
++ <DD>
++ This is similar to the &quot;TO&quot; token, only it is always the
++ email address of all people listed in the TO: field of the messages. Addresses
++ are separated by a blank space. Example, &quot;mailbox@domain&quot; when
++ the e-mail message contains only one person in the To: field, or
++ &quot;peter@flintstones.com president@world.com&quot;.
++ </DD>
++
+ <DT>MAILBOX</DT>
+ <DD>
+ This is the same as the &quot;ADDRESS&quot; except that the
+***************
+*** 18161,18166 ****
+--- 18473,18487 ----
+ message's &quot;Cc:&quot; header field.
+ </DD>
+
++ <DT>ADDRESSCC</DT>
++ <DD>
++ This is similar to the &quot;CC&quot; token, only it is always the
++ email address of all people listed in the Cc: field of the messages. Addresses
++ are separated by a blank space. Example: &quot;mailbox@domain&quot; when
++ the e-mail message contains only one person in the Cc: field, or
++ &quot;peter@flintstones.com president@world.com&quot;.
++ </DD>
++
+ <DT>RECIPS</DT>
+ <DD>
+ This token represents the personal names (or email addresses if the names
+***************
+*** 18169,18174 ****
+--- 18490,18503 ----
+ the message's &quot;Cc:&quot; header field.
+ </DD>
+
++ <DT>ADDRESSRECIPS</DT>
++ <DD>
++ This token represent the e-mail addresses of the people in the To: and
++ Cc: fields, exactly in that order separated by a space. It is almost obtained
++ by concatenating the ADDRESSTO and ADDRESSCC tokens.
++ </DD>
++
++
+ <DT>NEWSANDRECIPS</DT>
+ <DD>
+ This token represents the newsgroups from the
+***************
+*** 18650,18655 ****
+--- 18979,18992 ----
+ <P>
+ </DD>
+
++ <DT>SIZETHREAD</DT>
++ <DD>
++ This token represents the total size of the thread for a collapsed thread
++ or the size of the branch for an expanded thread. The field is omitted for
++ messages that are not top of threads nor branches and it defaults to
++ the SIZE token when your folders is not sorted by thread.
++ </DD>
++
+ <DT>SIZENARROW</DT>
+ <DD>
+ This token represents the total size, in bytes, of the message.
+***************
+*** 19265,19270 ****
+--- 19602,19679 ----
+ </DL>
+
+ <P>
++ <H1><EM>Tokens Available Only for New-Rules</EM></H1>
++
++ <DL>
++ <DT>FOLDER</DT>
++ <DD>
++ Name of the folder where the rule will be applied
++ </DD>
++ </DL>
++
++ <DL>
++ <DT>COLLECTION</DT>
++ <DD>
++ Name of the collection list where the rule will be applied.
++ </DD>
++ </DL>
++
++ <DL>
++ <DT>ROLE</DT>
++ <DD>
++ Name of the Role used to reply a message.
++ </DD>
++ </DL>
++
++ <DL>
++ <DT>BCC</DT>
++ <DD>
++ Not implemented yet, but it will be implemented in future versions. It will
++ be used for <A HREF="h_config_compose_rules">compose</A>
++ <A HREF="h_config_reply_rules">reply</A>
++ <A HREF="h_config_forward_rules">forward</A>
++ rules.
++ </DD>
++ </DL>
++
++ <DL>
++ <DT>LCC</DT>
++ <DD>
++ This is the value of the Lcc: field at the moment that you start the composition.
++ </DD>
++ </DL>
++
++ <DL>
++ <DT>FORWARDFROM</DT>
++ <DD>
++ This corresponds to the personal name (or address if there's no personal
++ name) of the person who sent the message that you are forwarding.
++ </DD>
++ </DL>
++
++ <DL>
++ <DT>FORWARDADDRESS</DT>
++ <DD>
++ This is the address of the person that sent the message that you
++ are forwarding.
++ </DD>
++ </DL>
++
++
++
++
++ <DL>
++ <DT>FLAG</DT>
++ <DD>
++ A string containing the value of all the flags associated to a specific
++ message. The possible values of allowed flags are "*" for Important, "N"
++ for recent or new, "U" for unseen or unread, "R" for seen or read, "A" for
++ answered and "D" for deleted. See an example of its use in the
++ <A HREF="h_config_new_rules">new rules</A> explanation and example help.
++ </DD>
++ </DL>
++
++ <P>
+ <H1><EM>Token Available Only for Templates and Signatures</EM></H1>
+
+ <DL>
+***************
+*** 21253,21258 ****
+--- 21662,21763 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_maildir_location ======
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: <!--#echo var="VAR_maildir-location"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: <!--#echo var="VAR_maildir-location"--></H1>
++
++ <P>
++ This option should be used only if you have a Maildir folder which you
++ want to use as your INBOX. If this is not your case (or don't know what
++ this is), you can safely ignore this option.
++
++ <P>
++ This option overrides the default directory Pine uses to find the location of
++ your INBOX, in case this is in Maildir format. The default value of this
++ option is "Maildir", but in some systems, this directory could have been
++ renamed (e.g. to ".maildir"). If this is your case use this option to change
++ the default.
++
++ <P>
++ The value of this option is prefixed with the "~/" string to determine the
++ full path to your INBOX.
++
++ <P>
++ You should probably <A HREF="h_config_maildir">read</A> a few tips that
++ teach you how to configure your maildir for optimal performance. This
++ version also has <A HREF="h_config_courier_list">support</A> for the
++ Courier style file system when a maildir collection is accessed locally.
++
++ <P><UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL>
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ====== h_config_maildir =====
++ <HTML>
++ <HEAD>
++ <TITLE>Maildir Support</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>Maildir Support</H1>
++
++ This version of Alpine has been enhanced with Maildir support. This text is
++ intended to be a reference on its support.
++ <P>
++
++ A Maildir folder is a directory that contains three directories called
++ cur, tmp and new. A program that delivers mail (e.g. postfix) will put new
++ mail in the new directory. A program that reads mail will look for for old
++ messages in the cur directory, while it will look for new mail in the new
++ directory.
++ <P>
++
++ In order to use maildir support it is better to set your inbox-path to the
++ value &quot;#md/inbox&quot; (without quotes). This assumes that your mail
++ delivery agent is delivering new mail to ~/Maildir/new. If the directory
++ where new mail is being delivered is not called "Maildir", you can set the
++ name of the subdirectory of home where it is being delivered in the <A
++ HREF="h_config_maildir_location"><!--#echo var="VAR_maildir-location"--></A> configuration
++ variable. Most of the time you will not have to worry about the
++ <!--#echo var="VAR_maildirlocation"--> variable, because it will probably be set by your
++ administrator in the pine.conf configuration file.
++ <P>
++
++ One of the advantages of the Maildir support of this version of Alpine is
++ that you do not have to stop using folders in another styles (mbox, mbx,
++ etc.). This is desirable since the usage of a specific mail storage system
++ is a personal decision. Folders in the maildir format that are part of the
++ Mail collection will be recognized without any extra configuration of your
++ part. If your mail/ collection is located under the mail/ directory, then
++ creating a new maildir folder in this collection is done by pressing "A"
++ and entering the string "#driver.md/mail/newfolder". Observe that adding a
++ new folder as "newfolder" may not create such folder in maildir format.
++
++ <P>
++ If you would like to have all folders created in the maildir format by
++ default, you do so by adding a Maildir Collection. In order to convert
++ your current mail/ collection into a maildir collection, edit the
++ collection and change the path variable from &quot;mail/&quot; to
++ &quot;#md/mail&quot;. In a maildir collection folders of any other format
++ are ignored.
++
++ <P> Finally, This version also has
++ <A HREF="h_config_courier_list">support</A> for the Courier style file system
++ when a maildir collection is accessed locally.
++
++ <P>
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_literal_sig =====
+ <HTML>
+ <HEAD>
+***************
+*** 22015,22020 ****
+--- 22520,22564 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_thread_sort_key =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: <!--#echo var="VAR_thread-sort-key--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: <!--#echo var="VAR_thread-sort-key--></TITLE></H1>
++
++ This option determines the order in which threads will be displayed. You
++ can choose from the options listed below. Each folder is sorted in one of
++ the sort orders displayed below first, then the thread containing the last
++ message of that sorted list is put at the end of the index. All messages
++ of that thread are &quot;removed&quot; from the sorted list and the
++ process is repeated with the remaining messages in that list.
++
++ <P>
++ <UL>
++ <LI> <A HREF="h_thread_index_sort_arrival">Arrival</A>
++ <LI> <A HREF="h_thread_index_sort_date">Date</A>
++ <!-- <LI> <A HREF="h_thread_index_sort_subj">Subject</A>
++ <LI> <A HREF="h_thread_index_sort_ordsubj">OrderedSubj</A>-->
++ <LI> <A HREF="h_thread_index_sort_thread">Thread</A>
++ <!-- <LI> <A HREF="h_thread_index_sort_from">From</A>
++ <LI> <A HREF="h_thread_index_sort_size">Size</A> -->
++ <LI> <A HREF="h_thread_index_sort_score">Score</A>
++ <!-- <LI> <A HREF="h_thread_index_sort_to">To</A>
++ <LI> <A HREF="h_thread_index_sort_cc">Cc</A>-->
++ </UL>
++
++ <P> Each type of sort may also be reversed. Normal default is by
++ &quot;Thread&quot;.
++
++ <P>
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_other_startup =====
+ <HTML>
+ <HEAD>
+***************
+*** 22285,22290 ****
+--- 22829,23726 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_procid =====
++ <HTML>
++ <HEAD>
++ <TITLE>Token: PROCID</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>TOKEN: PROCID explained</H1>
++
++ <P>
++ The PROCID token is a way in which the user and the program can differentiate
++ between different parts of a program. It allows the user to tell the
++ program when to use a specific rule, and only use it at that specific
++ moment.
++
++ <P> The normal way in which this is done is by adding a new configuration
++ variable. The idea behind the PROCID token is that instead of adding a new
++ configuration variable (which means the user has to go through more
++ configuration variables just to tune the program to his liking), we reuse
++ an old variable and let the user look inside that variable for the desired
++ behavior, which is actually set by setting the PROCID token.
++
++ <P>
++ Consider the following examples for forward-rules:
++
++ <P>
++ _ROLE_ == {work} =&gt; _SUBJECT_ := _COPY_{[tag] _SUBJECT_}
++
++ <P>
++ and
++
++ <P>
++ _ROLE_ == {work} =&gt; _LCC_ := _TRIM_{_FORWARDFROM_ &lt;_FORWARDADDRESS_&gt;}
++
++ <P>
++ both are triggered by the same condition. Since both are configured in the
++ same variable, only one of them will be executed all the time (whichever
++ is first). Therefore in order to differentiate, we add a _PROCID_ token.
++ So, for example, the first example above will be executed only when we are
++ determining the subject. In this case, the following rule will accomplish
++ this task
++
++ <P>
++ _PROCID_ == {fwd-subject} && _ROLE_ == {work} =&gt; _SUBJECT_ := _COPY_{[tag] _SUBJECT_}
++
++ <P>
++ In this case, this rule will be tested fully only when we are determining
++ the subject line of a forwarded message, not otherwise.
++
++ <P>
++ It is wise to add the _PROCID_ token as the first condition in a rule, so
++ that other conditions will not be tested in a long list of rules.
++
++ <P>&lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ====== h_config_compose_rules =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: <!--#echo var="VAR_compose-rules"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: <!--#echo var="VAR_compose-rules"--></H1>
++
++ <P> At this time, this option is used to generate values for signature
++ files that is not possible to do with the use of
++ <A HREF="h_rules_roles">roles</A>.
++
++ <P> For example, you can have a rule like:<BR>
++ _TO_ >> {Peter Flinstones} => _SIGNATURE_{~/.petersignature}
++
++ <P> This configuration option is just one of many that allow you to
++ override the value of some global configurations within Alpine. There is a
++ help text explaining how to define all of them, which you can read by
++ following this <A HREF="h_config_new_rules">link</A>.
++
++ <P>&lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ====== h_config_forward_rules =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: <!--#echo var="VAR_forward-rules"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: <!--#echo var="VAR_forward-rules"--></H1>
++
++ <P> This option has several uses. This feature uses the PROCID function
++ to identify different features of forwarding. You can read more about PROCID
++ by following <A HREF="h_config_procid">this link</A>.
++
++ <P> If you want to edit the subject of a forwarded message, use the
++ PROCID <I>fwd-subject</I>. For example you could have a rule like
++
++ <P>
++ _ROLE_ == {admin} && _SUBJECT_ !&gt; {[tag] } =&gt; _COPY_{[tag] _SUBJECT_}
++
++ <P> Another way in which this option can be used, is to trim the values of
++ some fields. For this application the PROCID is <I>fwd-lcc</I>. For
++ example it can be used in the following way:
++
++ <P>
++ _ROLE_ == {work} => _LCC_ := _TRIM_{_FORWARDFROM_ &lt;_FORWARDADDRESS_&gt;}
++
++ <P> Other functions that can be used in this option are _EXEC_ and _REXTRIM_.
++
++ <P> You can also use the _EXEC_ function. The documentation for this function
++ is in the
++ <A HREF="h_config_resub_rules"><!--#echo var="VAR_reply-subject-rules"--></A>
++ help text.
++
++ <P> This configuration option is just one of many that allow you to
++ override the value of some global configurations within Alpine. There is a
++ help text explaining how to define all of them, which you can read by
++ following this <A HREF="h_config_new_rules">link</A>.
++
++ <P>&lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ====== h_config_index_rules =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: <!--#echo var="VAR_index-rules"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: <!--#echo var="VAR_index-rules"--></H1>
++
++ <P> This option is used to supersede the value of the option <A
++ HREF="h_config_index_format"><!--#echo var="VAR_index-format"--></A> for specific folders. In
++ this form you can have different index-formats for different folders. For
++ example an entry here may be:
++
++ <P>
++ _FOLDER_ == {INBOX} => _INDEX_{IMAPSTATUS DATE FROM(33%) SIZE SUBJECT(67%)}
++
++ <P> This configuration option is just one of many that allow you to
++ override the value of some global configurations within Alpine. There is a
++ help text explaining how to define all of them, which you can read by
++ following this <A HREF="h_config_new_rules">link</A>.
++
++ <P>&lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ====== h_config_pretty_command =====
++ <HTML>
++ <HEAD>
++ <TITLE>Pretty-Command Explained</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>Pretty Command Explained</H1>
++
++ <P> This text explains how to encode keys so that they will be recognized
++ by Alpine in the _PKEY_ token. Most direct keystrokes are recognized in the
++ same way. For example, the key ~ is recognized by the same character. The
++ issue is how control, or functions keys are recognized. The internal code
++ is most times easy to find out. If the key you want to use is not already
++ recognized by Alpine simply press it. Alpine will print its code. For example,
++ the return key is not recognized in this screen, so if you press it, you
++ will see the following message.
++
++ <P> [Command &quot;RETURN&quot; not defined for this screen. Use ? for help]
++
++ <P> from here you can guess that the code for the return command is
++ RETURN. You can try other commands, like Control-C, the TAB key, F4, etc.
++ to see their codes.
++
++ <P>&lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ====== h_config_key_macro_rules =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: <!--#echo var="VAR_key-definition-rules"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: <!--#echo var="VAR_key-definition-rules"--></H1>
++
++ <P> This option can be used to define macros, that is, to define a key that
++ when pressed executes a group of predetermined keystrokes. Since Alpine is
++ a menu driven program, sometimes the same key may have different meanings
++ in different screens, so a global redefinition of a key although possible
++ is not advisable.
++
++ <P> <B>Always use the _SCREEN_ token as defined below.</B>. You have been
++ warned!
++
++ <P> In each screen, every time you press a recognized key a command is
++ activated. In order to understand this feature, think of commands instead
++ of keystrokes. For example, you can think of the sort by thread command.
++ This command is associated to the keystrokes $ and h. You may want to
++ associate this command to a specific keystroke, like ~, so every time you
++ press the ~ key, Alpine understand the $ and h keystrokes, which activates
++ the sort by thread command.
++
++ <P> Therefore, in order to use this option you must think of three
++ components. The screen where you will use the macro, the keystroke you
++ want to use and the set of keystrokes used by Alpine to accomplish the task
++ you want to accomplish. We will talk about these three components in what
++ follows.
++
++ <P> First you must decide in which screen the macro will be used. This
++ feature is currently only available for the screen where your messages
++ are listed in index form (<A HREF="h_mail_index">MESSAGE INDEX</A>),
++ the screen where your message is displayed
++ (<A HREF="h_mail_view">MESSAGE TEXT</A>) and the screen where the list of
++ folders is displayed (<A HREF="h_folder_maint">FOLDER LIST</A>). The
++ internal names of these screens for this patch are &quot;index&quot;,
++ &quot;text&quot; and
++ &quot;folder&quot; respectively. Please note that the internal names are
++ all in lowercase are are case sensitive.
++
++ <P> In order to define the screen, you use the _SCREEN_ token, so for
++ example, you can write _SCREEN_ == {index}.
++
++ <P> Second you must think of which key you will use to activate the macro.
++ Here you can use any key of your choice. The token you use to designate a
++ key is the _PKEY_ token (PKEY stands for &quot;pressed key&quot;). For
++ example you could use _PKEY_ == {~}, to designate the &quot;~&quot;
++ character to activate the command. Some keystrokes (like control, or
++ function keys) are encoded in special ways. You should read the
++ <A HREF="h_config_pretty_command">full explanation</A> on how to find
++ out the encoding for each keystroke.
++
++ <P> Last, you must think of the list of keys you will use to accomplish
++ the task you want Alpine to perform. Say for example you want to have the
++ folder sorted by thread. That means you want Aline to execute the keys
++ &quot;$&quot; and &quot;h&quot;. You use the _COMMAND_ function to specify
++ this. The syntax in this case is _COMMAND_{$,h}.
++
++ <P> Observe that in the above example the different inputs are separated
++ by commas. This is the standard way in which the
++ <A HREF="h_config_init_cmd_list"><!--#echo var="VAR_initial-keystroke-list"--></A> command works from
++ the command line. Due to restrictions in the way Alpine works, a comma is a
++ special character, which when added to a configuration option like this
++ will cause the configuration to split into several lines in the
++ configuration screen. This has the effect of producing several
++ configuration options, all of which are incorrect. This is undesirable
++ because what you want is to have it all in one line. In order to force the
++ configuration into one line you must quote the comma. The best way to
++ accomplish this is by quoting the full definition of the rule. For
++ example.
++
++ <P>
++ &quot;_SCREEN_ == {index} && _PKEY_ == {~} => _COMMAND_{$,h}&quot;
++
++ <P> Another way to accomplish the same effect is by quoting the command and
++ not using quotes for the full command, nor commas to separate the
++ keystrokes in the command, for example
++
++ <P>
++ _SCREEN_ == {index} && _PKEY_ == {~} => _COMMAND_{&quot;$h&quot;}
++
++ <P> For more information on how to define the argument of the _COMMAND_
++ token see the help of
++ <A HREF="h_config_init_cmd_list"><!--#echo var="VAR_initial-keystroke-list"--></A>.
++
++ <P> Because the $ command can also be used as the first character in the
++ definition of an environemnt variable, no expansion of environment variables
++ is done when parsing this variable. The $ character does not need quoting
++ and quoting it will make Alpine fail to produce the correct result.
++
++ <P> This configuration option is just one of many that allow you to
++ override the value of some global configurations within Alpine. There is a
++ help text explaining how to define all of them, which you can read by
++ following this <A HREF="h_config_new_rules">link</A>.
++
++ <P>&lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ====== h_config_replace_rules =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: <!--#echo var="VAR_replace-rules"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: <!--#echo var="VAR_replace-rules"--></H1>
++
++ <P> This option is used to have Alpine print different values for specific
++ tokens in the <A HREF="h_config_index_format"><!--#echo var="VAR_index-format"--></A>. For example you
++ can replace strings like "To: newsgroup" by your name.
++
++ <P> Here are examples of possible rules:<BR>
++ _FOLDER_ != {sent-mail} && _NICK_ != {} => _FROM_ := _REPLACE_{_FROM_ (_NICK_)}
++
++ <P> or if you receive messages with tags that contain arbitrary numbers, and
++ you want them removed from the index (but not from the subject), use a rule
++ like the following<BR>
++ _FOLDER_ == {INBOX} => _SUBJECT_ := _REXTRIM_{&#92;[some-tag-here #[0-9].*&#92;]}
++
++ <P> You can also use this configuration option to remove specific strings of
++ the index display screen, so that you can trim unnecessary information in
++ your index, like the reply leadin string in the OPENINGTEXTNQ token of the index.
++ <BR>
++ _FOLDER_ == {mailing-list} => _OPENINGTEXTNQ_ := _REXTRIM_{On.*wrote: }
++
++ <P> or if you receive messages with tags that contain arbitrary numbers, and
++ you want them removed from the index (but not from the subject), use a rule
++ like the following<BR>
++
++ <P> You can also use the _EXEC_ function. The documentation for this function
++ is in the
++ <A HREF="h_config_resub_rules"><!--#echo var="VAR_reply-subject-rules"--></A>
++ help text.
++
++ <P> This configuration option is just one of many that allow you to
++ override the value of some global configurations within Alpine. There is a
++ help text explaining how to define all of them, which you can read by
++ following this <A HREF="h_config_new_rules">link</A>.
++
++ <P>&lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ====== h_config_reply_leadin_rules =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: <!--#echo var="VAR_reply-leadin-rules"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: <!--#echo var="VAR_reply-leadin-rules"--></H1>
++
++ <P> This option is used to have Alpine generate a different
++ <A HREF="h_config_reply_intro"><!--#echo var="VAR_reply-leadin"--></A> string dependent either on
++ the person you are replying to, or the folder where the message is being
++ replied is in, or both.
++
++ <P> Here there are examples of how this can be used. One can use the definition
++ below to post to newsgroups and the pine-info mailing list, say:
++ <P>
++ _FOLDER_ << {pine-info;_NEWS_} => _REPLY_{*** _FROM_ _ADDRESS_("_FROM_" "" "(_ADDRESS_) ")wrote in_NEWS_("" " the" "") _FOLDER_ _NEWS_("" "list " "")_SMARTDATE_("Today" "today" "on _LONGDATE_"):}
++
++ <P> Here there is an example that one can use to change the reply indent string
++ to reply people that speak spanish.
++ <P>
++ _FROM_{Condorito;Quico} => _REPLY_{*** _FROM_ (_ADDRESS_) escribi&oacute; _SMARTDATE_("Today" "hoy" "en _LONGDATE_"):}
++
++ <P> This configuration option is just one of many that allow you to
++ override the value of some global configurations within Alpine. There is a
++ help text explaining how to define all of them, which you can read by
++ following this <A HREF="h_config_new_rules">link</A>.
++
++ <P>&lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ====== h_config_resub_rules =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: <!--#echo var="VAR_reply-subject-rules"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: <!--#echo var="VAR_reply-subject-rules"--></H1>
++
++ <P> This option is used to have Alpine generate a different subject when
++ replying rather than the one Alpine would generate automatically.
++
++ <P> Here there are a couple of examples about how to use this
++ configuration option:
++
++ <P> In order to have messages with empty subject to be replied with the message
++ "your message" use the rule<BR>
++ <center>_SUBJECT_ == {} => _RESUB_{Re: your message}</center>
++
++ <P> If you want to trim some parts of the subject when you reply use the
++ rule<BR>
++ <center>_SUBJECT_ >> {[one];two} => _SUBJECT_ := _TRIM_{[;];two}</center>
++
++ <P>this rule removes the brackets "[" and "]" whenever the string "[one]"
++ appears in it, it also removes the word "two" from it.
++
++ <P>Another example where you may want to use this rule is when you
++ correspond with people that change the reply string from &quot;Re:&quot;
++ to &quot;AW:&quot; or &quot;Sv:&quot;. In this case a rule like<BR>
++ <center>_SUBJECT_ >> {Sv: ;AW: } => _SUBJECT_ := _TRIM_{Sv: ;AW: }</center>
++ <P>
++ would eliminate undesired strings in replies.
++
++ <P> Another interesting use of this option is the use of the _EXEC_ function.
++ This function takes as an argument a program or a script. This program
++ must take as the input a file, and write its output to that file. For example,
++ below is a sample of a script that removes the letter &quot;a&quot; of a file.
++
++ <PRE>
++ #!/bin/sh
++ sed 's/a//g' $1 > /tmp/mytest
++ mv /tmp/mytest $1
++ </PRE>
++
++ <P>
++ As you can see this script took &quot;$1&quot; as input file, the sed program
++ wrote its output to /tmp/mytest, and then the move program moved the file
++ /tmp/mytest to the input file &quot;$1&quot;. This is the kind of behavior
++ that your program is expected to have.
++
++ <P>
++ The content of the input file (&quot;$1&quot; above) is the value of a token
++ like _SUBJECT_. In order to indicate this, we use the notation
++
++ <P>
++ _SUBJECT_ := _EXEC_{/path/to/script}
++
++ <P> for the action. So for example
++
++ <P>
++ _FOLDER_ := {sent-mail} =&gt; _SUBJECT_ := _EXEC_{/path/to/script}
++
++ <P> is a valid rule.
++
++ <P> You can also use this configuration option to customize reply subjects
++ according to the sender of the message.
++
++ <P> This configuration option is just one of many that allow you to
++ override the value of some global configurations within Alpine. There is a
++ help text explaining how to define all of them, which you can read by
++ following this <A HREF="h_config_new_rules">link</A>.
++
++ <P>&lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ====== h_config_sort_rules =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: <!--#echo var="VAR_sort-rules"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: <!--#echo var="VAR_sort-rules"--></H1>
++
++ <P> This option is used to have Alpine sort different folders in different orders
++ and thus override the value already set in the
++ <A HREF="h_config_sort_key"><!--#echo var="VAR_sort-key"--></A> configuration option.
++
++ <P> Here's an example of the way it can be used. In this case all incoming
++ folders are mailing lists, except for INBOX, so we sort INBOX by arrival
++ (which is the default type of sort), but we want all the rest of mailing
++ lists and newsgroups to be sorted by thread.
++
++ <P>
++ _COLLECTION_ >> {Incoming-Folders;News} && _FOLDER_ != {INBOX} => _SORT_{tHread}
++
++ <P> Another example could be<BR>
++ _FOLDER_ == {Mailing List} => _SORT_{Reverse tHread}
++
++ <P> This configuration option is just one of many that allow you to
++ override the value of some global configurations within Alpine. There is a
++ help text explaining how to define all of them, which you can read by
++ following this <A HREF="h_config_new_rules">link</A>.
++
++ <P>&lt;End of help on this topic&gt;
++
++ </BODY>
++ </HTML>
++ ====== h_config_save_rules =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: <!--#echo var="VAR_save-rules"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: <!--#echo var="VAR_save-rules"--></H1>
++
++ <P> This option is used to specify which folder should be used to save a
++ message depending either on the folder the message is in, who the message
++ is from, or text that the message contains in specific headers (Cc:,
++ Subject:, etc).
++
++ <P> If this option is set and the
++ <A HREF="h_config_auto_read_msgs"><!--#echo var="FEAT_auto-move-read-msgs"--></A> configuration
++ option is also enabled then these definitions will be used to move messages
++ from your INBOX when exiting Alpine.
++
++ <P>Here there are some examples<BR>
++ _FLAG_ >> {D} -> Trash<BR>
++ _FROM_ == {U2} -> Bono<BR>
++ _FOLDER_ == {comp.mail.pine} -> pine-stuff<BR>
++ _NICK_ != {} -> _NICK_/_NICK_<BR>
++ _DATEISO_ >> {02-10;02-11} -> archive-oct-nov-2002
++
++ <P> This configuration option is just one of many that allow you to
++ override the value of some global configurations within Alpine. There is a
++ help text explaining how to define all of them, which you can read by
++ following this <A HREF="h_config_new_rules">link</A>.
++
++ <P>&lt;End of help on this topic&gt;
++
++ </BODY>
++ </HTML>
++ ====== h_config_reply_indent_rules =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: <!--#echo var="VAR_reply-indent-rules"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: <!--#echo var="VAR_reply-indent-rules"--></H1>
++
++ <P> This option is used to specify which reply-indent-string is to be used
++ when replying to an e-mail. If none of the rules are successful, the result in
++ the variable <a href="h_config_reply_indent_string"><!--#echo var="VAR_reply-indent-string"--></a>
++ is used.
++
++ <P> The associated function to this configuration option is called "RESTR" (for
++ REply STRing). Some examples of its use are:<BR>
++ _FROM_ == {Your Boss} => _RESTR_{"> "}<BR>
++ _FROM_ == {My Wife} => _RESTR_{":* "}<BR>
++ _FROM_ == {Perter Flinstone;Wilma Flinstone} => _RESTR_{"_INIT_ > "}<BR>
++
++ <P> This configuration option is just one of many that allow you to
++ override the value of some global configurations within Alpine. There is a
++ help text explaining how to define all of them, which you can read by
++ following this <A HREF="h_config_new_rules">link</A>.
++
++ <P>&lt;End of help on this topic&gt;
++
++ </BODY>
++ </HTML>
++ ====== h_config_smtp_rules =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: <!--#echo var="VAR_smtp-rules"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: <!--#echo var="VAR_smtp-rules"--></H1>
++
++ <P> This option is used to specify which SMTP server should be used when
++ sending a message, if this rule is not defined, or the execution of the rule
++ results in no server selected, then Alpine will look for
++ the value from the role that is being used to compose the message. If no smtp
++ server is defined in that role or you are not using a role, then Alpine will get
++ the name of the server from the
++ <A HREF="h_config_smtp_server">&quot;<!--#echo var="VAR_smtp-server"-->&quot;</A> configuration
++ option according to the rules used in that variable.
++
++ <P> The function associated to this configuration option is _SMTP_, an example
++ of the use of this function is<BR>
++ _ADDRESSTO_ == {peter@bedrock.com} => _SMTP_{smtp.bedrock.com}
++
++ <P> This configuration option is just one of many that allow you to
++ override the value of some global configurations within Alpine. There is a
++ help text explaining how to define all of them, which you can read by
++ following this <A HREF="h_config_new_rules">link</A>.
++
++ <P>&lt;End of help on this topic&gt;
++
++ </BODY>
++ </HTML>
++ ====== h_config_startup_rules =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: <!--#echo var="VAR_startup-rules"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: <!--#echo var="VAR_startup-rules"--></H1>
++
++ <P> This option is used when a folder is being opened. You can use it to specify its <A
++ HREF="h_config_inc_startup"><!--#echo var="VAR_incoming-startup-rule"--></A> and override
++ Alpine's global value set for all folders.
++
++ <P> An example of the usage of this option is:<BR>
++ _FOLDER_ == {Lynx;pine-info;_NEWS_} => _STARTUP_{first-unseen}
++
++ <P> This configuration option is just one of many that allow you to
++ override the value of some global configurations within Alpine. There is a
++ help text explaining how to define all of them, which you can read by
++ following this <A HREF="h_config_new_rules">link</A>.
++
++ <P>&lt;End of help on this topic&gt;
++
++ </BODY>
++ </HTML>
++ ====== h_config_new_rules =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: New Rules Explained</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: New Rules Explained</H1>
++
++ This is a quite powerful option. Here you can define rules that override
++ the values of any other option you have set in Alpine.
++
++ <P>
++ For example, you can set your folders to be sorted in a certain way when
++ you open them (say by Arrival). You may want, however, your newsgroups to
++ be sorted by thread. The set of &quot;rules&quot; options allows you to
++ configure this and many other options, including the index-format for
++ specific folders, the way the subject is displayed in the index screen or
++ the reply-leadin-string, to name a few.
++
++ <P>
++ Every rule has three parts: a condition, a separator and an action. The
++ action is what will happen if the condition of the rule is satisified.
++
++ <P>
++ Here is an example:
++
++ <P>
++ _FROM_ == {Fred Flinstone} =&gt; _SAVE_{Fred}
++
++ <P>
++ Here the separator is "=&gt;". Whatever is to the left of the separator
++ is the condition (that is _FROM_ == {Fred Flinstone}) and to the right is
++ the action (_SAVE_{Fred}). The condition means that the rule will be
++ applied only if the message that you are reading is from &quot;Fred
++ Flinstone&quot;, and the action will be that you will be offered to save
++ it in the folder &quot;Fred&quot;, whenever you press the letter
++ &quot;S&quot; to save a message.
++
++ <P>
++ The separator is always &quot;=&gt;&quot;, with one exception to be seen
++ later. But for the most part this will be the only one you will ever need.
++
++ <P>
++ Now let us see how to do it. There are 13 functions already defined for
++ you. These are: _EXEC_, _INDEX_, _REPLACE_, _REPLY_, _RESUB_, _SAVE_,
++ _SIGNATURE_, _SORT_, _STARTUP_, _TRIM_, _REXTRIM_, _THREADSTYLE and
++ _THREADINDEX_. The parameter of a function has to be enclosed between
++ &quot;{&quot; and &quot;}&quot;, so for example you can specify
++ _SAVE_{saved-messages} as a valid sentence.
++
++ <P>
++ Later in the document you will find examples. Here is a short
++ description of what each function does:
++
++ <P>
++ <UL>
++ <LI> _EXEC_ : This function takes as an argument a program. This program
++ gets as the input a file and must rewrite its output to that file, which
++ is then taken as the value to replace from the contents of that file. You
++ can use this function with
++ <A HREF="h_config_resub_rules"><!--#echo var="VAR_reply-subject-rules"--></A>,
++ <A HREF="h_config_replace_rules"><!--#echo var="VAR_replace-rules"--></A> and
++ <A HREF="h_config_forward_rules"><!--#echo var="VAR_forward-rules"--></A>.
++ See the help of those options for examples of how to use this function
++ and configure these rules.
++ <BR>&nbsp;<BR>
++ <LI> _INDEX_ : This function takes as an argument an index-format, and
++ makes that the index-format for the specified folder.
++ <BR>&nbsp;<BR>
++ <LI> _REPLACE_ : This function replaces the subject/from of the given e-mail by
++ another subject/from only when displaying the index.
++ <BR>&nbsp;<BR>
++ <LI> _REPLY_ : This function takes as an argument a definition of a
++ reply-leadin-string and makes this the reply-leading-string of the
++ specified folder or person.
++ <BR>&nbsp;<BR>
++ <LI> _RESTR_ : This function takes as an argument the value of the
++ reply-indent-string to be used to answer the message being replied to.
++ <BR>&nbsp;<BR>
++ <LI> _RESUB_ : This function replaces the subject of the given e-mail by
++ another subject only when replying to a message.
++ <BR>&nbsp;<BR>
++ <LI> _SAVE_ : The save function takes as an argument the name of a
++ possibly non existing folder, whenever you want to save a message, that
++ folder will be offered for you to save.
++ <BR>&nbsp;<BR>
++ <LI> _SIGNATURE_ : This function takes as an argument a signature file and
++ uses that file as the signature for the message you are about to
++ compose/reply/forward.
++ <BR>&nbsp;<BR>
++ <LI> _SMTP_ : This function takes as an argument the definition of a
++ SMTP server.
++ <BR>&nbsp;<BR>
++ <LI> _SORT_ : This function takes as an argument a Sort Style, and sorts a
++ specified folder in that sort order.
++ <BR>&nbsp;<BR>
++ <LI> _TRIM_ : This function takes as an argument a list of strings that
++ you want removed from another string. At this time this only works for
++ _FROM_ and _SUBJECT_.
++ <BR>&nbsp;<BR>
++ <LI> _REXTRIM_ : Same as _TRIM_ but its argument is one and
++ only one extended regular expression.
++ <BR>&nbsp;<BR>
++ <LI> _STARTUP_ : This function takes as an argument an
++ incoming-startup-rule, and open an specified folder using that rule.
++ <BR>&nbsp;<BR>
++ <LI> _THREADSTYLE_ : This function takes as an argument a
++ threading-display-style and uses it to display threads in a folder.
++ <BR>&nbsp;<BR>
++ <LI> _THREADINDEX_ : This function takes as an argument a
++ threading-index-style and uses it to display threads in a folder.
++ </UL>
++
++ <P>
++ You must me wondering how to define the person/folder over who to apply
++ the action. This is done in the condition. When you specify a rule, the
++ rule is only executed if the condition is satisfied. In another words for
++ the rule:
++
++ <P>
++ _FROM_ == {Fred Flinstone} =&gt; _SAVE_{Fred}
++
++ <P> it will only be applied if the from is &quot;Fred Flinstone&quot;. If
++ the From is &quot;Wilma Flinstone&quot; the rule will be skipped.
++
++ <P> In order to test a condition you can use the following tokens (in
++ alphabetical order): _ADDRESS_, _CC_, _FOLDER_, _FROM_,_NICK_, _ROLE,
++ _SENDER_, _SUBJECT_ and _TO_. The token will always be tested against what
++ it is between &quot;{&quot; and &quot;}&quot; in the condition, this part
++ of the condition is called the &quot;condition set&quot;. The definition
++ of each token can be found <A HREF="h_index_tokens">here</A>.
++
++ <P> A special testing token called _PROCID_ can be used to differentiate
++ inside a rule, between two rules that are triggered by the same condition.
++ A full explanation of the _PROCID_ token can be found in
++ <A HREF="h_config_procid">this link</A>.
++
++ <P> There are two more tokens related to the option
++ <A HREF="h_config_key_macro_rules">key-definition-rules</A>. Those tokens
++ are only specific to that option, and hence are not explained here.
++
++ <P> You can also test in different ways, you can use the following
++ &quot;test operands&quot;: &lt;&lt;, !&lt;, &gt;&gt;, !&gt;, == and !=.
++ All of them are two strings long. Here is the meaning of them:
++
++ <P>
++ <UL>
++ <LI> &lt;&lt; : It tests if the value of the token is contained in
++ the condition set. Here for example if the condition set were equal to
++ &quot;Freddy&quot;, then the condition: _NICK_ &lt;&lt; {Freddy}, would be true if
++ the value of _NICK_ were &quot;Fred&quot;, &quot;red&quot; or &quot;Freddy&quot;. You are just looking
++ for substrings here.
++ <LI> &gt;&gt; : It tests if the value of the token contains the value of
++ the condition set. Here for example if the condittion set were equal to
++ &quot;Fred&quot;, then the condition: _FROM_ &gt;&gt; {Fred}, would be true if
++ the value of _FROM_ were &quot;Fred Flinstone&quot; or &quot;Fred P. Flinstone&quot; or &quot;Freddy&quot;.
++ <LI> == : It tests if the value of the token is exactly equal to the value
++ of the set condition. For example _NICK_ == {Fred} will be false if the value
++ of _NICK_ is &quot;Freddy&quot; or &quot;red&quot;.
++ <LI> !&lt; : This is true only when &lt;&lt; is false and viceversa.
++ <LI> !&gt; : This is true only when &gt;&gt; is false and viceversa.
++ <LI> != : This is true only when == is false and viceversa.
++ </UL>
++
++ <P>
++ Now let us say that you want the same action to be applied to more than
++ one person or folder, say you want &quot;folder1&quot; and &quot;folder2&quot; to be sorted by
++ Ordered Subject upon entering. Then you can list them all of them in the
++ condition part separting them by a &quot;;&quot;. Here is the way to do it.
++
++ <P>
++ _FOLDER_ &lt;&lt; {folder1; folder2} =&gt; _SORT_{OrderedSubj}
++
++ <P>
++ Here is the first subtelty about these definitions. Notice that the
++ following rule:
++
++ <P>
++ _FOLDER_ == {folder1; folder2} =&gt; _SORT_{Reverse OrderedSubj}
++
++ <P> works only for &quot;folder1&quot; but not for &quot;folder2&quot;. This is because the
++ comparison of the name of the folder is done with whatever is in between
++ &quot;{&quot;, &quot;;&quot; or &quot;}&quot;, so in the above rule you would be testing <BR>
++ &quot;folder2&quot; == &quot; folder2&quot;. The extra space makes the difference.
++ The reason why the first rule does not fail is because
++ &quot;folder2&quot; &lt;&lt; &quot; folder2&quot; is actually
++ true. If something ever fails this may be something to look into.
++
++ <P>
++ Here are a few examples of what we have talked about before.
++
++ <P>
++ _NICK_ == {lisa;kika} =&gt; _SAVE_{_NICK_/_NICK_} <BR>
++ This means that if the nick is lisa, it will
++ save the message in the folder &quot;lisa/lisa&quot;, and if the nick
++ is &quot;kika&quot;, it will save the message in the folder &quot;kika/kika&quot;
++
++ <P>
++ _FOLDER_ == {Lynx} -&gt; lynx <BR>
++ This, is an abreviation of the following rule:<BR>
++ _FOLDER_ == {Lynx} =&gt; _SAVE_{lynx} <BR>
++ (note the change in separator from &quot;=&gt;&quot; to &quot;-&gt;&quot;). In the future
++ I will use that abreviation.
++
++ <P> _FOLDER_ &lt;&lt; {comp.mail.pine; pine-info; pine-alpha} -&gt; pine <BR>
++ Any message in the folders &quot;comp.mail.pine&quot;, &quot;pine-info&quot; or &quot;pine-alpha&quot;
++ will be saved to the folder &quot;pine&quot;.
++
++ <P> _FROM_ &lt;&lt; {Pine Master} -&gt; pine <BR>
++ Any message whose From field contains
++ &quot;Pine Master&quot; will be saved in the folder pine.
++
++ <P> _FOLDER_ &lt;&lt; {Lynx; pine-info; comp.mail.pine} =&gt;
++ _INDEX_{IMAPSTATUS MSGNO DATE FROMORTO(33%) SUBJECT(66%)} <BR> Use a
++ different index-format for the folders &quot;Lynx&quot;, &quot;pine-info&quot; and
++ &quot;comp.mail.pine&quot;, where the size is not present.
++
++ <P> _FOLDER_ == {Lynx;pine-info} =&gt; _REPLY_{*** _FROM_ (_ADDRESS_)
++ wrote in the _FOLDER_ list _SMARTDATE_(&quot;Today&quot; &quot;today&quot; &quot;on
++ _LONGDATE_&quot;):}<BR> If a message is in one of the incoming folders &quot;Lynx&quot;
++ or &quot;pine-info&quot;, create a reply-leadin-string that acknowledges that. Note
++ the absence of &quot;,&quot; in the function _SMARTDATE_. For example answering to a
++ message in the pine-info list would look like:
++
++ <P>
++ *** Steve Hubert (hubert@cac.washington.edu) wrote in the pine-info list today:
++
++ <P>
++ However replying for a message in the Lynx list would look:
++
++ <P>
++ *** mattack@area.com (mattack@area.com) wrote in the Lynx list today:
++
++ <P>
++ If you write in more than one language you can use this feature to create
++ Reply-leadin-strings in different languages.
++
++ <P> Note that at least for people you can create particular
++ reply-leadin-string using the role features, but it does not work as this
++ one does. This seems to be the right way to do it.
++
++ <P> _FOLDER_ &lt;&lt; {Lynx; comp.mail.pine; pine_info; pine-alpha} =&gt;
++ _SORT_{OrderedSubj}<BR> This means upon opening, sort the folders &quot;Lynx&quot;,
++ &quot;comp.mail.pine&quot;, etc in ordered subject. All the others use the default
++ sort order. You can not sort in reverse in this form. The possible
++ arguments of this function are listed in the definition of the
++ default-sort-rule (Arrival, scorE, siZe, etc).
++
++ <P> The last examples use the function _TRIM_ which has a special form.
++ This function can only be used in the index list.
++
++ <P> _FOLDER_ &lt;&lt; {Lynx} =&gt; _SUBJECT_ := _TRIM_{lynx-dev }<BR> In
++ the folder &quot;Lynx&quot; eliminate from the subject the string &quot;lynx-dev &quot; (with
++ the space at the end). For example a message whose subject is &quot;Re:
++ lynx-dev unvisited Visited Links&quot;, would be shown in the index with
++ subject: &quot;Re: unvisited Visited Links&quot;, making the subject shorter and
++ giving the same information.
++
++ <P> _FROM_ &gt;&gt; {Name (Comment)} =&gt; _FROM_ :=
++ _TRIM_{ (Comment)}<BR> Remove the part &quot; (Comment)&quot;
++ from the _FROM_, so when displaying in the index the real From &quot;Name&quot;
++ will appear.
++
++ <P> _SUBJECT_ == {} =&gt; _RESUB_{Re: your mail without subject}
++ If there is no subject in the message, use the subject &quot;Re: your mail
++ wiyhout subject&quot; as a subject for the reply message.
++
++ <P> You can add more complexity to your rules by checking more than one
++ conditions before a rule is executed. For example: Assume that you want to
++ answer every email that contains the string &quot;bug report&quot;, with the subject
++ &quot;Re: About your bug report&quot;, you could make
++
++ <P>
++ _SUBJECT_ == {bug report} =&gt; _RESUB_{Re: About your _SUBJECT_}
++
++ <P> The problem with this construction is that if the person emails you
++ back, then the next time you answer the message the subject will be: &quot;Re:
++ About your Re: About your bug report&quot;, so it grew. You may want to avoid
++ this growth by using the following rule:
++
++ <P>
++ _SUBJECT_ &gt;&gt; {bug report} && _SUBJECT_ !&gt; {Re: } =&gt; _RESUB_{Re: About your _SUBJECT_}<BR>
++
++ <P>
++ which will only add the string &quot;Re: About your&quot; only the first time the
++ message is replied.
++
++ <P>
++ Say your personal name is &quot;Fred Flinstones&quot;, and assume that you don't
++ like to see &quot;To: comp.mail.pine&quot; in every post you make to this newsgroup,
++ but instead would like to see it as everyone else sees it. <BR>
++ _FOLDER_ == {comp.mail.pine} && _FROM_ == {Fred Flinstones} => _FROM_ := _REPLACE_{_FROM_}
++
++ <P>
++ You can also list your index by nick, in the following way:<BR>
++ _NICK_ != {} => _FROM_ := _REPLACE_{_NICK_}
++
++ <P>
++ If you want to open the folder &quot;pine-info&quot; in the first non-read message
++ use the rule:<BR>
++ _FOLDER_ == {pine-info} => _STARTUP_{first-unseen}
++
++ <P>
++ If you want to move your deleted messages to a folder, called &quot;Trash&quot;, use
++ the following rule:<BR>
++ _FLAG_ >> {D} -> Trash
++
++ <P>
++ The reason why the above test is not &quot;_FLAG_ == {D}&quot; is because that would mean
++ that this is the only flag set in the message. It's better to test by containment in this case.
++
++ <P> If you want to use a specific signature when you are in a specific collection
++ use the following rule:<BR>
++ _COLLECTION_ == {Mail} => _SIGNATURE_{/full/path/to/.signature}
++
++ <P> Finally about the question of which rule will be executed. Only the
++ first rule that matches will be executed. It is important to notice though
++ that &quot;saving&quot; rules do not compete with &quot;sorting&quot; rules. So the first
++ &quot;saving&quot; rule that matches will be executed in the case of saving and so
++ on.
++
++ <P>
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_char_set =====
+ <HTML>
+ <HEAD>
+***************
+*** 22592,22597 ****
+--- 24028,24070 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_special_text_to_color =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: <!--#echo var="VAR_special-text-color"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: <!--#echo var="VAR_special-text-color"--></H1>
++
++ Use this option to enter patterns (text or regular expressions) that
++ Alpine will highlight in the body of the text that is not part of a handle
++ (an internal or external link that Alpine paints in a different color).
++
++ <P>
++ Enter each pattern in a different line. Pine will internally merge these
++ patterns (by adding a "|" character), or you can add them all in one line
++ by separating them by a "|" character. There is only a <A
++ HREF="h_regex_text">set</A> of regular expressions that are matched.
++
++ <P>
++ Pine will use the colors defined in the
++ <A HREF="h_config_special_text_color">Special Text Color</A> variable.
++ to paint any match.
++
++ <P>
++ If the Special Text Color is not set, setting this variable will not
++ cause that special text to be indicated in any special way. It will look
++ like any normal text. You must set those colors in order to make Pine
++ paint the screen differently when it finds the patterns specified in this
++ variable.
++
++ <P>
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_display_filters =====
+ <HTML>
+ <HEAD>
+***************
+*** 22713,22718 ****
+--- 24186,24198 ----
+ improve security. The number is unique to the current Alpine session
+ and is only generated once per session.
+ </DD>
++
++ <DT>_SILENT_</DT>
++ <DD>When the filter is executed, this token tells Alpine not to repaint
++ the screen while the command is being executed. This can be used with
++ filters that do not interact with the user, and therefore repainting
++ the screen is not necessary.
++ </DD>
+ </DL>
+
+ <P>
+***************
+*** 22749,22754 ****
+--- 24229,24240 ----
+ Command Modifying Tokens:
+
+ <DL>
++ <DT>_ADDRESS_</DT>
++ <DD>When the command is executed, this token is replaced
++ with the address of the person sending the message in the format
++ mailbox@host.
++ </DD>
++
+ <DT>_RECIPIENTS_</DT>
+ <DD>When the command is executed, this token is replaced
+ with the space delimited list of recipients of the
+***************
+*** 25861,25866 ****
+--- 27347,27422 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_thread_display_style_rule =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: Threading-Display-Style-Rule</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: Threading-Display-Style-Rule</H1>
++
++ This option is very similar to <A HREF="h_config_thread_disp_style">
++ <!--#echo var="VAR_threading-display-style"--></A>, but it is a rule which specifies the
++ display styles for a thread that you want displayed in a specific
++ folder or collection.
++ <P>
++ The token to be used in this function is _THREADSTYLE_. Here there is
++ an example of its use
++ <P>
++ _FOLDER_ == {pine-info} => _THREADSTYLE_{mutt-like}
++ <P>
++ The values that can be given for the _THREADSTYLE_ function are the
++ values of the threading-display-style function, which can be found
++ listed in the <A HREF="h_config_thread_disp_style">threading-display-style</A>
++ configuration option.
++
++ <P> This configuration option is just one of many that allow you to
++ override the value of some global configurations within Alpine. There is a
++ help text explaining how to define all of them, which you can read by
++ following this <A HREF="h_config_new_rules">link</A>.
++
++ <P>
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ====== h_config_thread_index_style_rule =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: Threading-Index-Style-Rule</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: Threading-Index-Style-Rule</H1>
++
++ This option is very similar to <A HREF="h_config_thread_index_style">
++ <!--#echo var="VAR_threading-index-style"--></A>, but it is a rule which specifies the
++ index styles for a thread that you want displayed in a specific
++ folder or collection.
++ <P>
++ The token to be used in this function is _THREADINDEX_. Here there is
++ an example of its use
++ <P>
++ _FOLDER_ == {pine-info} => _THREADINDEX_{regular-index-with-expanded-threads}
++ <P>
++ The values that can be given for the _THREADINDEX_ function are the
++ values of the threading-index-display function, which can be found
++ listed in the <A HREF="h_config_thread_index_style"><!--#echo var="VAR_threading-index-style"--></A>
++ configuration option.
++
++ <P> This configuration option is just one of many that allow you to
++ override the value of some global configurations within Alpine. There is a
++ help text explaining how to define all of them, which you can read by
++ following this <A HREF="h_config_new_rules">link</A>.
++
++ <P>
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_pruning_rule =====
+ <HTML>
+ <HEAD>
+***************
+*** 27467,27472 ****
+--- 29023,29058 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_new_thread_blank_subject =====
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: <!--#echo var="FEAT_new-thread-on-blank-subject"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: <!--#echo var="FEAT_new-thread-on-blank-subject"--></H1>
++
++ When this feature is enabled (the default) Alpine will create a new thread
++ every time that the subject line becomes empty at any time during composition.
++
++ <P>
++ This behavior is particularly useful in case you are replying to a message.
++ Replying to a message causes the message to be in the same thread than the
++ original message that is being replied to. However, many authors want to create
++ a new message (in a different thread) while replying to a message, and they do
++ this by changing the full subject, by first deleting the original subject and
++ typing the new subject of the current message.
++
++ <P>
++ Enabling this feature causes that any time that the subject is deleted, the
++ message being composed will be considered the first message of a new thread.
++
++ <P>
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_strip_sigdashes =====
+ <HTML>
+ <HEAD>
+***************
+*** 27517,27522 ****
+--- 29103,29144 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_preserve_field =====
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: <!--#echo var="FEAT_preserve-original-fields"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: <!--#echo var="FEAT_preserve-original-fields"--></H1>
++
++ When you reply to a message that has been sent to several recipients, some of
++ them may have been added in different parts of the headers. For example,
++ some of the recipients will be listed in the To: header, while others will
++ be listed in the Cc: header.
++ <P>
++ If this feature is disabled, the default behavior of Alpine will be used,
++ and that is, that almost all recipients of the message will be
++ listed in the Cc: field. However, if you enable this feature, then,
++ excepting you, recipients originally listed in the Cc: field will be
++ listed again in the Cc: field, and those listed in the To: field in the
++ original message will be listed in the To: field again. The person in the
++ From: field will be added to the To: field.
++ <P>
++ Note that this will cause some messages that you send in Alpine to look
++ different. In particular, the To: field of a message will not be put in the
++ Cc: field, as is normally done. In fact, most people expect this to happen.
++ If you find that this is a problem you should disable this feature. You can
++ still make Alpine have this behavior on a per message basis. In order to do
++ this, you will see a new option in the menu for the &quot;Reply to all
++ recipients?&quot; question. In this case, pressing &quot;p&quot; will make
++ Alpine toggle its question so you can preserve the To: and Cc: fields for that
++ message.
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_sub_lists =====
+ <HTML>
+ <HEAD>
+***************
+*** 27701,27706 ****
+--- 29323,29344 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_use_domain =====
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: <!--#echo var="FEAT_return-path-uses-domain-name"--> </TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: <!--#echo var="FEAT_return-path-uses-domain-name"--></H1>
++
++ If you enable this configuration option Pine will use your domain name and your
++ username in that domain name to construct your Return-Path header, if not Pine
++ will use the address that you have set in the From: field to construct it.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_use_sender_not_x =====
+ <HTML>
+ <HEAD>
+***************
+*** 28297,28302 ****
+--- 29935,30005 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_alt_reply_menu =====
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: <!--#echo var="FEAT_alternate-reply-menu"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: <!--#echo var="FEAT_alternate-reply-menu"--></H1>
++
++ This feature controls the menu that is displayed when Reply is selected.
++ If set, a list of options will be presented, with each option representing
++ the type of composition that could be used. This feature is most useful
++ for users who want to avoid being prompted with each option separately, or
++ would like to override some defaults set in your configuration for the
++ message that you are replying (e.g. you may have set the option to strip
++ signatures, but for the message you are answering you would like not to do
++ that)
++
++ <P>
++ The way this feature works is as follows. Initially you get the question
++ if you want to include the message, and in the menu you will see several
++ options, each option is accompanied by some text explaining what will
++ happen if you press the associated command. For example, if you read the
++ text &quot;S Strip Sig&quot;, it means that if you press the letter
++ &quot;S&quot; the signature will be stripped off the message you are
++ replying. Observer that the menu will change to
++ &quot;S No Strip&quot;, which means that if you press &quot;S&quot;, the
++ signature will not be stripped off from the message. Your choices are
++ activated when you press RETURN.
++
++ <P>
++ Another way to remember what Pine will do, is that what will be done is
++ exactly the opposite of what you read in the menu.
++
++ <P>
++ The possible options are:
++
++ <OL>
++ <LI> A: This determines if Pine will include or not the attachments sent to
++ you in the message that you are replying. By default Pine will use the value
++ of the configuration option
++ <A HREF="h_config_attach_in_reply"><!--#echo var="FEAT_include-attachments-in-reply"--></A>, but
++ you can use this option to override such behavior in a per message basis.
++
++ <LI> F: To decide if you want to send flowed text or not. This option appears
++ unless you have quelled sending flowed text.
++
++ <LI> H: This option determines if the headers of a message are to be
++ included in the body of the message that is being replied. By default Pine
++ will use the value of the configuration option
++ <A HREF="h_config_include_header"><!--#echo var="FEAT_include-header-in-reply"--></A>, but
++ you can use this option to override such behavior in a per message basis.
++
++ <LI> R: To set a role, if you do not want Pine to set one automatically for you
++ or would like to set one when you can not select any.
++
++ <LI> S: To strip the signature from a message, only available is the feature
++ <a href="h_config_sigdashes"><!--#echo var="FEAT_enable-sigdashes"--></a> or the
++ <a href="h_config_strip_sigdashes"><!--#echo var="FEAT_strip-from-sigdashes-on-reply"--></a> option are
++ enabled.
++
++ </OL>
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_del_from_dot =====
+ <HTML>
+ <HEAD>
+***************
+*** 28820,28825 ****
+--- 30523,30560 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_enable_long_url =====
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: <!--#echo var="FEAT_enable-msg-view-long-url"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: <!--#echo var="FEAT_enable-msg-view-long-url"--></H1>
++
++ This feature modifies the behavior of Alpine's MESSAGE TEXT screen. When this feature
++ is set alpine will attempt to recognize long urls (those that spread over several
++ lines in the text) for the HTTP protocol, even when they have not been enclosed between
++ delimiters &quot;&lt;&quot; and &quot;&gt;&quot;.
++
++ <P>The normal behavior in Alpine is that if a URL is preceeded by the &quot;&lt;&quot;
++ character and this URL was not finished before the end of the line, then a
++ continuation of the URL is searched in the following line(s). Normally, this type of
++ URLs will be ended by the &quot;&gt;&quot; character, and if it is not, there is a
++ possibility of including erroneous text into the URL.
++
++ <P>Enabling this feature will make Alpine search for a continuation of certain URLs in
++ lines following its location. This will be of great help most times, but in some cases
++ the algorithm will catch some text into the URL that is not part of the URL.
++
++ <P>If you find that Alpine failed to recognize correctly a URL simply edit the URL before
++ passing it to your browser.
++
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_enable_view_addresses =====
+ <HTML>
+ <HEAD>
+***************
+*** 29127,29132 ****
+--- 30862,30910 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_courier_list =====
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: <!--#echo var="FEAT_courier-folder-list"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: <!--#echo var="FEAT_courier-folder-list"--></H1>
++
++ In a maildir collection, a folder could be used as a directory to store
++ folders. In the Courier server if you create a folder, then a directory
++ with the same name is created. If you use this patch to access a
++ collection created by the Courier server, then the display of such
++ collection will look confusing. The best way to access a maildir
++ collection created by the Courier server is by using the &quot;#mc/&quot;
++ prefix instead of the &quot;#md/&quot; prefix. If you use this alternate
++ prefix, then this feature applies to you, otherwise you can safely ignore
++ the text that follows.
++ <P>
++ Depending on if you have enabled the option
++ <a href="h_config_separate_fold_dir_view"><!--#echo var="FEAT_separate-folder-and-directory-entries"--></a>
++ a folder may be listed as &quot;folder[.]&quot;, or as two entries in the
++ list by &quot;folder&quot; and &quot;folder.&quot;.
++ <P>
++ If this option is disabled, Pine will list local folders that are in Courier
++ style format, as &quot;folder&quot;, and those that are also directories as
++ &quot;folder[.]&quot;. This makes the default display cleaner.
++ <P>
++ If this feature is enabled then creating folders in a maildir collection
++ will create a directory with the same name. If this feature is disabled, then
++ a folder is considered a directory only if it contains subfolders, so you can
++ not create a directory with the same name as an exisiting folder unless
++ you create a subfolder of that folder first (e.g. if you have a folder
++ called &quot;foo&quot; simply add &quot;foo.bar&quot; directly. This will
++ create the directory &quot;foo&quot; and the subfolder &quot;bar&quot; of it).
++ <P>
++ Observe that this feature works only for maildir collections that are accessed
++ locally. If a collection is accessed remotely then this feature has no value,
++ as the report is created in a server, and Pine only reports what received
++ from the server in this case.
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_verbose_post =====
+ <HTML>
+ <HEAD>
+***************
+*** 29281,29286 ****
+--- 31059,31087 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_auto_read_msgs_rules =====
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: auto-move-read-msgs-using-rules</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: auto-move-read-msgs-using-rules</H1>
++ This feature controls an aspect of Alpine's behavior upon quitting. If set,
++ and the
++ <A HREF="h_config_read_message_folder">&quot;<!--#echo var="VAR_read-message-folder"-->&quot;</A>
++ option is also set, then Alpine will automatically transfer all read
++ messages to the designated folder using the rules that you have defined in
++ your
++ <A HREF="h_config_save_rules">&quot;<!--#echo var="VAR_save-rules"-->&quot;</A> and mark
++ them as deleted in the INBOX. Messages in the INBOX marked with an
++ &quot;N&quot; (meaning New, or unseen) are not affected.
++ <P>
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_auto_fcc_only =====
+ <HTML>
+ <HEAD>
+***************
+*** 29731,29736 ****
+--- 31532,31554 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_enhanced_thread =====
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: <!--#echo var="FEAT_enhanced-fancy-thread-support"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: <!--#echo var="FEAT_enhanced-fancy-thread-support"--></H1>
++
++ If this option is set certain commands in Pine will operate in loose
++ threads too. For example, the command ^D marks a thread deleted, but if
++ this feature is set, it will remove all threads that share the same missing
++ parent with this thread.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_news_cross_deletes =====
+ <HTML>
+ <HEAD>
+***************
+*** 30209,30214 ****
+--- 32027,32066 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_ignore_size =====
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: <!--#echo var="FEAT_ignore-size-changes"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: <!--#echo var="FEAT_ignore-size-changes"--></H1>
++
++ When you have an account residing in an IMAP server, Alpine gets the size of
++ each message from the server. However, when Alpine saves a message residing
++ in an IMAP server, Alpine computes the size of the message independently. If
++ these two numbers do not match for a message, Alpine asks you if you still
++ want to take the risk of saving the message, since data corruption or loss
++ of data could result of this save.
++
++ <P>
++ Sometimes the root of this problem is that the server is defective, and
++ there will not be loss of information when saving such message. Enabling
++ this feature will make Aline ignore such error and continue saving the
++ message. If you can determine that this is the case, enable this feature
++ so that the saving operation will succeed. An example of a defective server
++ is the Gmail IMAP server. Another example is some versions of the Exchange
++ server.
++
++ <P>
++ It is recommended that this feature be disabled most of the time and only
++ enabled when you find a server which you can determine that has the above
++ mentioned defect, but be disabled again after making this operation
++ succeed.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_force_low_speed =====
+ <HTML>
+ <HEAD>
+***************
+*** 30479,30484 ****
+--- 32331,32357 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_circular_tab =====
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: <!--#echo var="FEAT_enable-circular-tab"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: <!--#echo var="FEAT_enable-circular-tab"--></H1>
++
++ <P>
++ This Feature is like
++ <A HREF="h_config_auto_open_unread">&quot;<!--#echo var="FEAT_auto-open-next-unread"-->&quot;</A>,
++ in the sense that you can use TAB to browse through all of your Incoming
++ Folders checking for new mail. Once it gets to the last folder of the
++ collection it goes back to check again until it returns to the original
++ folder where it started.
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_auto_include_reply =====
+ <HTML>
+ <HEAD>
+***************
+*** 31142,31147 ****
+--- 33015,33113 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_folder_color =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: Folder Color</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: Folder Color</H1>
++
++ Sets the colors Alpine uses for coloring a folder in the FOLDER LIST
++ screen. By default, the Folder Color is the normal text color.
++
++ <P>
++ If you set a color for this feature, other than the normal color
++ (the default), or a color for
++ <A HREF="h_config_directory_color">Directory Color</A>, then directories
++ will be colored according to the color specified in the
++ <A HREF="h_config_directory_color">Directory Color</A> option. In this
++ case, the color will be the only indication that the colored name
++ refers to a directory. The normal behavior is that Alpine
++ indicates that a name refers to a directory by appending a
++ separator (like &quot;/&quot; or &quot;.&quot;) to the name of
++ the folder.
++
++ <P>
++ If a folder is a directory, then the folder name will be painted
++ according to the color defined by this variable, and a separator
++ indicator (like &quot;/&quot; or &quot;.&quot;) will be added
++ to the name. That
++ indicator will be painted according to the color defined in the
++ <A HREF="h_config_directory_color">Directory Color</A> option.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ====== h_config_directory_color =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: Directory Color</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: Directory Color</H1>
++
++ Sets the colors Alpine uses for coloring a directory in the FOLDER LIST
++ screen. By default, the Folder Color is the normal text color.
++ <P>
++ If you set a color for this feature, other than the normal color
++ (the default), or a color for
++ <A HREF="h_config_folder_color">Folder Color</A>, then folders
++ will be colored according to the color specified in the
++ <A HREF="h_config_folder_color">Folder Color</A> option. In this
++ case, the color will be the only indication that the colored name
++ refers to a directory. The normal behavior is that Alpine
++ indicates that a name refers to a directory by appending a
++ separator (like &quot;/&quot; or &quot;.&quot;) to the name of
++ the folder.
++ <P>
++ If a folder is a directory, then the folder name will be painted
++ according to the color defined by the option
++ <A HREF="h_config_folder_color">Folder Color</A>, and the separator
++ indicator (like &quot;/&quot; or &quot;.&quot;) will be added
++ after the name. That
++ indicator will be painted according to the color defined in this
++ option.
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ====== h_config_folder_list_color =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: Folder-List Color</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: Folder-List Color</H1>
++
++ Sets the colors Alpine uses for coloring normal text in the FOLDER LIST
++ screen. By default, the Folder-List Color is the normal text color.
++ <P>
++ This text refers to the informative text that Alpine displays so you
++ can recognize each collection. The color of the content of each collection
++ is determined by the options <A HREF="h_config_folder_color">Folder Color</A>
++ and <A HREF="h_config_directory_color">Directory Color</A>.
++ <P>
++ Unlike the options
++ <A HREF="h_config_folder_color">Folder Color</A>
++ and <A HREF="h_config_directory_color">Directory Color</A>, configuring
++ this option does not affect the way that it tradinionally reports folders,
++ directories and folders that are directories.
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_incunseen_color =====
+ <HTML>
+ <HEAD>
+***************
+*** 31197,31202 ****
+--- 33163,33192 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_special_text_color =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: Special Text Color</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: Special Text Color</H1>
++
++ Sets the color Pine uses for coloring any text in the body of the message
++ that is not part of a handle (and internal or external link that Pine
++ paints in a different color). By default, this variable is not defined,
++ which means that text that matches the pattern is not painted in any
++ particular way. This variable must be set in a special form if you
++ want text to be painted.
++
++ <P>
++ <A HREF="h_color_setup">Descriptions of the available commands</A>
++ <P>
++ Look <A HREF="h_edit_nav_cmds">here</A>
++ to see the available Editing and Navigation commands.
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_prompt_color =====
+ <HTML>
+ <HEAD>
+***************
+*** 31464,31469 ****
+--- 33454,33488 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_indextoken_color =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: <!--#echo var="VAR_index-token-colors"--></TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: <!--#echo var="VAR_index-token-colors"--></H1>
++
++ This option allows you to set up the color in which any token, not specified by the
++ previous options, will be colored in the MESSAGE INDEX screen.
++ <P>
++ In order to use this option, you must press the &quot;I&quot; <B>IndxHdr</B> command, and add
++ a token that can be used in the index format.
++ The list of available tokens is <A HREF="h_index_tokens">here</A>.
++ <P>
++ If you fail to enter a valid token your entry will be ignored, and you will be asked to
++ enter a new one. Once you have entered a valid token, a line will be added to the
++ configuration screen that you can use to set up the colors in which that token will
++ be painted. This is done in the same way that you configure colors for other
++ variables.
++
++ <A HREF="h_color_setup">Descriptions of the available commands</A>
++ <P>
++ Look <A HREF="h_edit_nav_cmds">here</A>
++ to see the available Editing and Navigation commands.
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_customhdr_pattern =====
+ <HTML>
+ <HEAD>
+***************
+*** 35075,35077 ****
+--- 37094,37099 ----
+ ========== h_select_by_smaller_size ==========
+ Enter a number or ^C to cancel. All messages less than this many characters
+ in size will be selected. Examples: 2176, 1.53K (1530), or 3M (3000000).
++ ========== h_preserve_field ==========
++ Use 'p' to toggle between preserving or not preserving the original To:
++ and Cc: fields of the message. Enter ^C to cancel message.
+diff -rc alpine-2.00/pith/reply.c alpine-2.00.I.USE/pith/reply.c
+*** alpine-2.00/pith/reply.c 2008-06-03 12:27:23.000000000 -0700
+--- alpine-2.00.I.USE/pith/reply.c 2011-02-07 20:33:44.000000000 -0800
+***************
+*** 45,50 ****
+--- 45,52 ----
+ #include "../pith/ablookup.h"
+ #include "../pith/mailcmd.h"
+ #include "../pith/margin.h"
++ #include "../pith/copyaddr.h"
++ #include "../pith/rules.h"
+
+
+ /*
+***************
+*** 372,391 ****
+ /* Put Reply-To or From in To. */
+ *to_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->to,
+ (ADDRESS *) NULL, saved_from, RCA_ALL);
+- /* and the rest in cc */
+ if(replytoall){
+! *cc_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->cc,
+ outgoing->to, saved_to, RCA_ALL);
+! while(*cc_tail) /* stay on last address */
+! cc_tail = &(*cc_tail)->next;
+
+! *cc_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->cc,
+ outgoing->to, saved_cc, RCA_ALL);
+! while(*cc_tail)
+! cc_tail = &(*cc_tail)->next;
+
+! *cc_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->cc,
+ outgoing->to, saved_resent, RCA_ALL);
+ }
+ }
+ else if(saved_to){
+--- 374,410 ----
+ /* Put Reply-To or From in To. */
+ *to_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->to,
+ (ADDRESS *) NULL, saved_from, RCA_ALL);
+ if(replytoall){
+! if(ps->preserve){
+! while(*to_tail)
+! to_tail = &(*to_tail)->next;
+!
+! *to_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->to,
+! (ADDRESS *) NULL, saved_to, RCA_ALL);
+!
+! while(*to_tail)
+! to_tail = &(*to_tail)->next;
+!
+! *to_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->cc,
+! outgoing->to, saved_resent, RCA_ALL);
+!
+! *cc_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->cc,
+! outgoing->to, saved_cc, RCA_ALL);
+! }
+! else{ /* and the rest in cc */
+! *cc_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->cc,
+ outgoing->to, saved_to, RCA_ALL);
+! while(*cc_tail) /* stay on last address */
+! cc_tail = &(*cc_tail)->next;
+
+! *cc_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->cc,
+ outgoing->to, saved_cc, RCA_ALL);
+! while(*cc_tail)
+! cc_tail = &(*cc_tail)->next;
+
+! *cc_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->cc,
+ outgoing->to, saved_resent, RCA_ALL);
++ }
+ }
+ }
+ else if(saved_to){
+***************
+*** 796,803 ****
+ reply_quote_str(ENVELOPE *env)
+ {
+ char *prefix, *repl, *p, buf[MAX_PREFIX+1], pbf[MAX_SUBSTITUTION+1];
+
+! strncpy(buf, ps_global->VAR_REPLY_STRING, sizeof(buf)-1);
+ buf[sizeof(buf)-1] = '\0';
+
+ /* set up the prefix to quote included text */
+--- 815,841 ----
+ reply_quote_str(ENVELOPE *env)
+ {
+ char *prefix, *repl, *p, buf[MAX_PREFIX+1], pbf[MAX_SUBSTITUTION+1];
++ char reply_string[MAX_PREFIX+1];
++
++ { RULE_RESULT *rule;
++ rule = get_result_rule(V_REPLY_INDENT_RULES, FOR_COMPOSE , env);
++ if (rule){
++ strncpy(reply_string,rule->result,sizeof(reply_string));
++ reply_string[sizeof(reply_string)-1] = '\0';
++ if (rule->result)
++ fs_give((void **)&rule->result);
++ fs_give((void **)&rule);
++ }
++ else
++ if ((ps_global->VAR_REPLY_STRING) && (ps_global->VAR_REPLY_STRING[0])){
++ strncpy(reply_string,ps_global->VAR_REPLY_STRING, sizeof(reply_string)-1);
++ reply_string[sizeof(reply_string)-1] = '\0';
++ }
++ else
++ strncpy(reply_string,"> ",sizeof("> "));
++ }
+
+! strncpy(buf, reply_string, sizeof(buf)-1);
+ buf[sizeof(buf)-1] = '\0';
+
+ /* set up the prefix to quote included text */
+***************
+*** 849,858 ****
+ int
+ reply_quote_str_contains_tokens(void)
+ {
+! return(ps_global->VAR_REPLY_STRING && ps_global->VAR_REPLY_STRING[0] &&
+! (strstr(ps_global->VAR_REPLY_STRING, from_token) ||
+! strstr(ps_global->VAR_REPLY_STRING, nick_token) ||
+! strstr(ps_global->VAR_REPLY_STRING, init_token)));
+ }
+
+
+--- 887,915 ----
+ int
+ reply_quote_str_contains_tokens(void)
+ {
+! char *reply_string;
+!
+! reply_string = (char *) malloc( 80*sizeof(char));
+! { RULE_RESULT *rule;
+! rule = get_result_rule(V_REPLY_INDENT_RULES, FOR_COMPOSE, NULL);
+! if (rule){
+! reply_string = cpystr(rule->result);
+! if (rule->result)
+! fs_give((void **)&rule->result);
+! fs_give((void **)&rule);
+! }
+! else
+! if ((ps_global->VAR_REPLY_STRING) && (ps_global->VAR_REPLY_STRING[0])){
+! strncpy(reply_string,ps_global->VAR_REPLY_STRING, sizeof(reply_string)-1);
+! reply_string[sizeof(reply_string)-1] = '\0';
+! }
+! else
+! reply_string = cpystr("> ");
+! }
+! return(reply_string && reply_string[0] &&
+! (strstr(reply_string, from_token) ||
+! strstr(reply_string, nick_token) ||
+! strstr(reply_string, init_token)));
+ }
+
+
+***************
+*** 954,960 ****
+ if(!orig_body
+ || orig_body->type == TYPETEXT
+ || reply_raw_body
+! || F_OFF(F_ATTACHMENTS_IN_REPLY, ps_global)){
+ char *charset = NULL;
+
+ /*------ Simple text-only message ----*/
+--- 1011,1017 ----
+ if(!orig_body
+ || orig_body->type == TYPETEXT
+ || reply_raw_body
+! || !ps_global->reply.attach){
+ char *charset = NULL;
+
+ /*------ Simple text-only message ----*/
+***************
+*** 962,968 ****
+ body->type = TYPETEXT;
+ body->contents.text.data = msgtext;
+ reply_delimiter(env, role, pc);
+! if(F_ON(F_INCLUDE_HEADER, ps_global))
+ reply_forward_header(stream, msgno, sect_prefix,
+ env, pc, prefix);
+
+--- 1019,1025 ----
+ body->type = TYPETEXT;
+ body->contents.text.data = msgtext;
+ reply_delimiter(env, role, pc);
+! if(ps_global->reply.inchdr)
+ reply_forward_header(stream, msgno, sect_prefix,
+ env, pc, prefix);
+
+***************
+*** 1020,1026 ****
+
+ if(reply_body_text(orig_body, &tmp_body)){
+ reply_delimiter(env, role, pc);
+! if(F_ON(F_INCLUDE_HEADER, ps_global))
+ reply_forward_header(stream, msgno, sect_prefix,
+ env, pc, prefix);
+
+--- 1077,1083 ----
+
+ if(reply_body_text(orig_body, &tmp_body)){
+ reply_delimiter(env, role, pc);
+! if(ps_global->reply.inchdr)
+ reply_forward_header(stream, msgno, sect_prefix,
+ env, pc, prefix);
+
+***************
+*** 1058,1064 ****
+ body->nested.part->body.subtype = cpystr("Plain");
+ }
+ reply_delimiter(env, role, pc);
+! if(F_ON(F_INCLUDE_HEADER, ps_global))
+ reply_forward_header(stream, msgno, sect_prefix,
+ env, pc, prefix);
+
+--- 1115,1121 ----
+ body->nested.part->body.subtype = cpystr("Plain");
+ }
+ reply_delimiter(env, role, pc);
+! if(ps_global->reply.inchdr)
+ reply_forward_header(stream, msgno, sect_prefix,
+ env, pc, prefix);
+
+***************
+*** 1081,1087 ****
+ int partnum;
+
+ reply_delimiter(env, role, pc);
+! if(F_ON(F_INCLUDE_HEADER, ps_global))
+ reply_forward_header(stream, msgno, sect_prefix,
+ env, pc, prefix);
+
+--- 1138,1144 ----
+ int partnum;
+
+ reply_delimiter(env, role, pc);
+! if(ps_global->reply.inchdr)
+ reply_forward_header(stream, msgno, sect_prefix,
+ env, pc, prefix);
+
+***************
+*** 1316,1321 ****
+--- 1373,1382 ----
+ buf[0] = '\0';
+
+ switch(type){
++ case iFfrom:
++ addr = env && env->sparep ? env->sparep : NULL;
++ break;
++
+ case iFrom:
+ addr = env ? env->from : NULL;
+ break;
+***************
+*** 1701,1721 ****
+
+ break;
+
+ case iFrom:
+ case iTo:
+ case iCc:
+ case iSender:
+ case iRecips:
+ case iInit:
+ get_addr_data(env, type, buf, maxlen);
+ break;
+
+! case iRoleNick:
+! if(role && role->nick){
+! strncpy(buf, role->nick, maxlen);
+! buf[maxlen] = '\0';
+! }
+! break;
+
+ case iNewLine:
+ if(maxlen >= strlen(NEWLINE)){
+--- 1762,1912 ----
+
+ break;
+
++ case iProcid:
++ if(ps_global->procid){
++ strncpy(buf, ps_global->procid, maxlen);
++ buf[maxlen] = '\0';
++ }
++ break;
++
++ case iRole:
++ if (ps_global->role){
++ strncpy(buf, ps_global->role, maxlen);
++ buf[maxlen] = '\0';
++ }
++ break;
++
++ case iRoleNick:
++ if(role && role->nick){
++ strncpy(buf, role->nick, maxlen);
++ buf[maxlen] = '\0';
++ }
++ break;
++
++ case iPkey:
++ if(ps_global->pressed_key){
++ strcpy(buf, ps_global->pressed_key);
++ buf[maxlen] = '\0';
++ }
++ break;
++
++ case iScreen:
++ if(ps_global->screen_name){
++ strncpy(buf, ps_global->screen_name, maxlen);
++ buf[maxlen] = '\0';
++ }
++ break;
++
++ case iFfrom:
+ case iFrom:
+ case iTo:
+ case iCc:
+ case iSender:
+ case iRecips:
+ case iInit:
++ if (env)
+ get_addr_data(env, type, buf, maxlen);
+ break;
+
+! case iFolder:
+! if(ps_global->cur_folder){
+! strncpy(buf,ps_global->cur_folder, maxlen);
+! buf[maxlen] = '\0';
+! }
+! break;
+!
+! case iCollection:
+! if(ps_global->context_current->nickname){
+! strncpy(buf,ps_global->context_current->nickname, maxlen);
+! buf[maxlen] = '\0';
+! }
+! break;
+!
+! case iFlag:
+! {MAILSTREAM *stream = find_open_stream();
+! MSGNO_S *msgmap = NULL;
+! long msgno;
+! MESSAGECACHE *mc;
+! strncpy(buf, "_FLAG_", maxlen); /* default value */
+! if (stream){
+! mn_init(&msgmap, stream->nmsgs);
+! msgno = mn_m2raw(msgmap, rules_cursor_pos(stream));
+! if (msgno > 0L) mc = stream ? mail_elt(stream, msgno) : NULL;
+! if (mc)
+! sprintf(buf,"%s%s%s%s",mc->flagged ? "*" : "",
+! mc->recent ? (mc->seen ? "R" : "N") : (mc->seen) ? "R" : "U",
+! mc->answered ? "A" : "",
+! mc->deleted ? "D" : "" );
+! mn_give(&msgmap);
+! }
+! buf[maxlen] = '\0';
+! }
+! break;
+!
+! case iNick:
+! {
+! ADDRESS *tmp_adr = NULL;
+! if (env){
+! tmp_adr = env->from ? copyaddr(env->from)
+! : env->sender ? copyaddr(env->sender) : NULL;
+! get_nickname_from_addr(tmp_adr,buf,maxlen);
+! mail_free_address(&tmp_adr);
+! }
+! }
+! break;
+!
+! case iAddressCc:
+! case iAddressRecip:
+! case iAddressTo:
+! case iFadd:
+! {
+! int plen = 0; /* partial length */
+! ADDRESS *sparep2 = (type == iAddressTo || type == iAddressRecip)
+! ? ((env && env->to)
+! ? copyaddrlist(env->to)
+! : NULL)
+! : (type == iAddressCc)
+! ? ((env && env->cc)
+! ? copyaddrlist(env->cc)
+! : NULL)
+! : ((env && env->sparep)
+! ? copyaddr((ADDRESS *)env->sparep)
+! : NULL);
+! ADDRESS *sparep;
+!
+! if (type == iAddressRecip){
+! ADDRESS *last_to = NULL;
+!
+! for(last_to = sparep2;last_to && last_to->next; last_to= last_to->next);
+!
+! /* Make the end of To list point to cc list */
+! if(last_to)
+! last_to->next = (env && env->cc ? copyaddrlist(env->cc) : NULL);
+!
+! }
+! sparep = sparep2;
+! for(; sparep ; sparep = sparep->next)
+! if(sparep && sparep->mailbox && sparep->mailbox[0] &&
+! (plen ? plen + 1 : plen) + strlen(sparep->mailbox) <= maxlen){
+! if (plen == 0)
+! strcpy(buf, sparep->mailbox);
+! else{
+! strcat(buf, " ");
+! strcat(buf, sparep->mailbox);
+! }
+! if(sparep->host &&
+! sparep->host[0] &&
+! sparep->host[0] != '.' &&
+! strlen(buf) + strlen(sparep->host) + 1 <= maxlen){
+! strcat(buf, "@");
+! strcat(buf, sparep->host);
+! }
+! plen = strlen(buf);
+! }
+! mail_free_address(&sparep2);
+! }
+!
+! break;
+
+ case iNewLine:
+ if(maxlen >= strlen(NEWLINE)){
+***************
+*** 1744,1749 ****
+--- 1935,1945 ----
+
+ break;
+
++ case iLcc: /* fake it, there are not enough spare pointers */
++ if (env && env->date)
++ sprintf(buf,"%s",env->date);
++ break;
++
+ case iNews:
+ case iCurNews:
+ get_news_data(env, type, buf, maxlen);
+***************
+*** 1793,1798 ****
+--- 1989,2002 ----
+
+ break;
+
++ case iOpeningText:
++ case iOpeningTextNQ:
++ if(env && env->sparep){
++ strncpy(buf, ((SPAREP_S *)env->sparep)->value, maxlen);
++ buf[maxlen] = '\0';
++ }
++ break;
++
+ case iSubject:
+ if(env && env->subject){
+ size_t n, len;
+***************
+*** 1851,1857 ****
+ if(!env)
+ return;
+
+! strncpy(buf, ps_global->VAR_REPLY_INTRO, MAX_DELIM);
+ buf[MAX_DELIM] = '\0';
+ /* preserve exact default behavior from before */
+ if(!strcmp(buf, DEFAULT_REPLY_INTRO)){
+--- 2055,2072 ----
+ if(!env)
+ return;
+
+! { RULE_RESULT *rule;
+! rule = get_result_rule(V_REPLY_LEADIN_RULES, FOR_REPLY_INTRO, env);
+! if(rule){
+! strncpy(buf, rule->result, MAX_DELIM);
+! if (rule->result)
+! fs_give((void **)&rule->result);
+! fs_give((void **)&rule);
+! }
+! else
+! strncpy(buf, ps_global->VAR_REPLY_INTRO, MAX_DELIM);
+! }
+!
+ buf[MAX_DELIM] = '\0';
+ /* preserve exact default behavior from before */
+ if(!strcmp(buf, DEFAULT_REPLY_INTRO)){
+***************
+*** 2110,2115 ****
+--- 2325,2331 ----
+ {
+ size_t l;
+ char *p, buftmp[MAILTMPLEN];
++ RULE_RESULT *rule;
+
+ if(!env)
+ return(NULL);
+***************
+*** 2117,2125 ****
+ dprint((9, "checking subject: \"%s\"\n",
+ env->subject ? env->subject : "NULL"));
+
+! if(env->subject && env->subject[0]){ /* add (fwd)? */
+! snprintf(buftmp, sizeof(buftmp), "%s", env->subject);
+! buftmp[sizeof(buftmp)-1] = '\0';
+ /* decode any 8bit (copy to the temp buffer if decoding doesn't) */
+ if(rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf,
+ SIZEOF_20KBUF, buftmp) == (unsigned char *) buftmp)
+--- 2333,2352 ----
+ dprint((9, "checking subject: \"%s\"\n",
+ env->subject ? env->subject : "NULL"));
+
+! buftmp[0] = '\0';
+! ps_global->procid = cpystr("fwd-subject");
+! if (rule = get_result_rule(V_FORWARD_RULES,FOR_COMPOSE, env)){
+! sprintf(buftmp, "%.200s", rule->result);
+! if(rule->result)
+! fs_give((void **)&rule->result);
+! fs_give((void **)&rule);
+! }
+! else if(env->subject)
+! sprintf(buftmp, "%.200s", env->subject);
+! buftmp[sizeof(buftmp)-1] = '\0';
+! fs_give((void **)&ps_global->procid);
+!
+! if(buftmp[0]){ /* add (fwd)? */
+ /* decode any 8bit (copy to the temp buffer if decoding doesn't) */
+ if(rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf,
+ SIZEOF_20KBUF, buftmp) == (unsigned char *) buftmp)
+***************
+*** 2620,2628 ****
+ * tied our hands, alter the prefix to continue flowed
+ * formatting...
+ */
+! if(flow_res)
+ wrapflags |= GFW_FLOW_RESULT;
+
+ filters[filtcnt].filter = gf_wrap;
+ /*
+ * The 80 will cause longer lines than what is likely
+--- 2847,2858 ----
+ * tied our hands, alter the prefix to continue flowed
+ * formatting...
+ */
+! if(flow_res && !ps_global->reply.no_send_flowed)
+ wrapflags |= GFW_FLOW_RESULT;
+
++ filters[filtcnt].filter = gf_quote_test;
++ filters[filtcnt++].data = gf_line_test_opt(select_quote, NULL);
++
+ filters[filtcnt].filter = gf_wrap;
+ /*
+ * The 80 will cause longer lines than what is likely
+***************
+*** 2656,2664 ****
+ * We also want to fold "> " quotes so we get the
+ * attributions correct.
+ */
+! if(flow_res && prefix && !strucmp(prefix, "> "))
+ *(prefix_p = prefix + 1) = '\0';
+!
+ if(!(wrapflags & GFW_FLOWED)
+ && flow_res){
+ filters[filtcnt].filter = gf_line_test;
+--- 2886,2894 ----
+ * We also want to fold "> " quotes so we get the
+ * attributions correct.
+ */
+! if(flow_res && !ps_global->reply.no_send_flowed && prefix && !strucmp(prefix, "> "))
+ *(prefix_p = prefix + 1) = '\0';
+! ps_global->reply.no_send_flowed = 0; /* reset for next call */
+ if(!(wrapflags & GFW_FLOWED)
+ && flow_res){
+ filters[filtcnt].filter = gf_line_test;
+***************
+*** 2691,2699 ****
+ }
+
+ if(prefix){
+! if(ps_global->full_header != 2
+! && (F_ON(F_ENABLE_SIGDASHES, ps_global)
+! || F_ON(F_ENABLE_STRIP_SIGDASHES, ps_global))){
+ dashdata = 0;
+ filters[filtcnt].filter = gf_line_test;
+ filters[filtcnt++].data = gf_line_test_opt(sigdash_strip, &dashdata);
+--- 2921,2927 ----
+ }
+
+ if(prefix){
+! if(ps_global->reply.strip){
+ dashdata = 0;
+ filters[filtcnt].filter = gf_line_test;
+ filters[filtcnt++].data = gf_line_test_opt(sigdash_strip, &dashdata);
+***************
+*** 2718,2724 ****
+ dq.do_color = 0;
+ dq.delete_all = 1;
+
+! filters[filtcnt].filter = gf_line_test;
+ filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq);
+ }
+
+--- 2946,2952 ----
+ dq.do_color = 0;
+ dq.delete_all = 1;
+
+! filters[filtcnt].filter = gf_quote_test;
+ filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq);
+ }
+
+diff -rc alpine-2.00/pith/rules.c alpine-2.00.I.USE/pith/rules.c
+*** alpine-2.00/pith/rules.c 2011-02-07 20:34:02.000000000 -0800
+--- alpine-2.00.I.USE/pith/rules.c 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 0 ****
+--- 1,1149 ----
++ /* This module was written by
++ *
++ * Eduardo Chappa (chappa@washington.edu)
++ * http://staff.washington.edu/chappa/pine/
++ *
++ * Original Version: November 1999
++ * Last Modified : January 24, 2008
++ *
++ * Send bug reports about this module to the address above.
++ */
++
++ #include "../pith/headers.h"
++ #include "../pith/state.h"
++ #include "../pith/conf.h"
++ #include "../pith/copyaddr.h"
++ #include "../pith/rules.h"
++
++ /* Internal Prototypes */
++
++ int test_condition (CONDITION_S *, int, ENVELOPE *);
++ int test_in (CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int);
++ int test_ni (CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int);
++ int test_not_in (CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int);
++ int test_not_ni (CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int);
++ int test_eq (CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int);
++ int test_not_eq (CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int);
++ int isolate_condition (char *, char **, int *);
++ char *test_rule (RULELIST *, int, ENVELOPE *, int *);
++ char *trim (RULEACTION_S *, int, ENVELOPE *);
++ char *rextrim (RULEACTION_S *, int, ENVELOPE *);
++ char *raw_value (RULEACTION_S *, int, ENVELOPE *);
++ char *extended_value (RULEACTION_S *, int, ENVELOPE *);
++ char *exec_fcn (RULEACTION_S *, int, ENVELOPE *);
++ char *expand (char *, void *);
++ char *get_name_token (char *);
++ char *advance_to_char (char *, char, int, int *);
++ char **functions_for_token (char *);
++ void free_token_value (TOKEN_VALUE **);
++ void free_condition (CONDITION_S **);
++ void free_ruleaction (RULEACTION_S **);
++ void free_rule (RULE_S **);
++ void free_rule_list (RULELIST **);
++ void free_alloc_rule (void **, int);
++ void *alloc_mem (size_t);
++ void add_rule (int, int);
++ void set_rule_list (struct variable *);
++ void parse_patterns_into_action(TOKEN_VALUE **);
++ void free_parsed_value(TOKEN_VALUE **value);
++ RULE_S *parse_rule (char *, int);
++ RULELIST *get_rule_list (char **, int, int);
++ TOKEN_VALUE *parse_group_data (char *,int *);
++ TOKEN_VALUE *copy_parsed_value (TOKEN_VALUE *, int, ENVELOPE *);
++ CONDITION_S *fill_condition (char *);
++ CONDITION_S *parse_condition (char *, int *);
++ PRULELIST_S *add_prule (PRULELIST_S *, PRULELIST_S *);
++ RULEACTION_S *parse_action (char *, int);
++
++ REL_TOKEN rel_rules_test[] = {
++ {EQ_REL, Equal, test_eq},
++ {IN_REL, Subset, test_in},
++ {NI_REL, Includes, test_ni},
++ {NOT_EQ_REL, NotEqual, test_not_eq},
++ {NOT_IN_REL, NotSubset, test_not_in},
++ {NOT_NI_REL, NotIncludes, test_not_ni},
++ {NULL, EndTypes, NULL}
++ };
++
++ #define NREL (sizeof(rel_rules_test)/sizeof(rel_rules_test[0]) - 1)
++
++ RULE_FCN rule_fcns[] = {
++ {COPY_FCN, extended_value, FOR_SAVE|FOR_COMPOSE},
++ {SAVE_FCN, extended_value, FOR_SAVE},
++ {EXEC_FCN, exec_fcn, FOR_REPLACE|FOR_TRIM|FOR_RESUB|FOR_COMPOSE},
++ {REPLY_FCN, extended_value, FOR_REPLY_INTRO},
++ {TRIM_FCN, trim, FOR_TRIM|FOR_RESUB|FOR_COMPOSE},
++ {REPLACE_FCN, extended_value, FOR_REPLACE},
++ {SORT_FCN, raw_value, FOR_SORT},
++ {INDEX_FCN, raw_value, FOR_INDEX},
++ {COMMAND_FCN, raw_value, FOR_KEY},
++ {REPLYSTR_FCN, raw_value, FOR_COMPOSE},
++ {SIGNATURE_FCN, raw_value, FOR_COMPOSE},
++ {RESUB_FCN, extended_value, FOR_RESUB},
++ {STARTUP_FCN, raw_value, FOR_STARTUP},
++ {REXTRIM_FCN, rextrim, FOR_TRIM|FOR_RESUB|FOR_COMPOSE},
++ {THRDSTYLE_FCN, raw_value, FOR_THREAD},
++ {THRDINDEX_FCN, raw_value, FOR_THREAD},
++ {SMTP_FCN, raw_value, FOR_COMPOSE},
++ {NULL, 0, FOR_NOTHING}
++ };
++
++ char* token_rules[] = {
++ FROM_TOKEN,
++ NICK_TOKEN,
++ OTEXT_TOKEN,
++ OTEXTNQ_TOKEN,
++ ROLE_TOKEN,
++ FOLDER_TOKEN,
++ SUBJ_TOKEN,
++ PROCID_TOKEN,
++ THDDSPSTY_TOKEN,
++ THDNDXSTY_TOKEN,
++ FLAG_TOKEN,
++ COLLECT_TOKEN,
++ THDDSPSTY_TOKEN,
++ ADDR_TOKEN,
++ TO_TOKEN,
++ ADDTO_TOKEN,
++ ADDCC_TOKEN,
++ ADDRECIP_TOKEN,
++ SCREEN_TOKEN,
++ KEY_TOKEN,
++ SEND_TOKEN,
++ CC_TOKEN,
++ LCC_TOKEN,
++ BCC_TOKEN,
++ FFROM_TOKEN,
++ FADDRESS_TOKEN,
++ NULL
++ };
++
++ #define NTOKENS (sizeof(token_rules)/sizeof(token_rules[0]) - 1)
++ #define NFCN (sizeof(rule_fcns)/sizeof(rule_fcns[0]) - 1)
++
++ char *subj_fcn[] = {SUBJ_TOKEN, REPLACE_FCN, TRIM_FCN, REXTRIM_FCN, EXEC_FCN};
++ char *from_fcn[] = {FROM_TOKEN, REPLACE_FCN, TRIM_FCN, REXTRIM_FCN, EXEC_FCN};
++ char *otext_fcn[] = {OTEXT_TOKEN, REPLACE_FCN, TRIM_FCN, REXTRIM_FCN, EXEC_FCN};
++ char *otextnq_fcn[] = {OTEXTNQ_TOKEN, REPLACE_FCN, TRIM_FCN, REXTRIM_FCN, EXEC_FCN};
++
++ char *adto_fcn[] = {ADDTO_TOKEN, EXEC_FCN, NULL, NULL, NULL};
++
++ char **fcns_for_index[] = {subj_fcn, from_fcn, otext_fcn, otextnq_fcn};
++
++ #define NFCNFI (sizeof(fcns_for_index)/sizeof(fcns_for_index[0])) /*for idx*/
++ #define NFPT (sizeof(fcns_for_index[0])) /* functions pert token */
++
++ SPAREP_S *
++ get_sparep_for_rule(char *value, int flag)
++ {
++ SPAREP_S *rv;
++ rv = (SPAREP_S *) alloc_mem(sizeof(SPAREP_S));
++ rv->flag = flag;
++ rv->value = value ? cpystr(value) : NULL;
++ return rv;
++ }
++
++ void free_sparep_for_rule(void **sparep)
++ {
++ SPAREP_S *spare = (SPAREP_S *) *sparep;
++ if(!spare) return;
++ if(spare->value)
++ fs_give((void **)&spare->value);
++ fs_give((void **)sparep);
++ }
++
++
++ int context_for_function(char *name)
++ {
++ int i, j;
++ for (i = 0; i < NFCN && strcmp(rule_fcns[i].name, name); i++);
++ return i == NFCN ? 0 : rule_fcns[i].what_for;
++
++ }
++
++ char **functions_for_token(char *name)
++ {
++ int i;
++ for (i = 0; i < NFCNFI && strcmp(fcns_for_index[i][0], name); i++);
++ return i == NFCNFI ? NULL : fcns_for_index[i];
++ }
++
++ void
++ free_alloc_rule (void **voidtext, int code)
++ {
++ switch(code){
++ case FREEREGEX : regfree((regex_t *)*voidtext);
++ break;
++ default: break;
++ }
++ }
++
++
++
++ void free_token_value(TOKEN_VALUE **token)
++ {
++ if(token && *token){
++ if ((*token)->testxt)
++ fs_give((void **)&(*token)->testxt);
++ free_alloc_rule (&(*token)->voidtxt, (*token)->codefcn);
++ if((*token)->next)
++ free_token_value(&(*token)->next);
++ fs_give((void **)token);
++ }
++ }
++
++ void free_condition(CONDITION_S **condition)
++ {
++ if(condition && *condition){
++ if ((*condition)->tname)
++ fs_give((void **)&((*condition)->tname));
++ if ((*condition)->value)
++ free_token_value(&((*condition)->value));
++ if((*condition)->next)
++ free_condition(&((*condition)->next));
++ fs_give((void **)condition);
++ }
++ }
++
++ void free_ruleaction(RULEACTION_S **raction)
++ {
++ if(raction && *raction){
++ if ((*raction)->token)
++ fs_give((void **)&((*raction)->token));
++ if ((*raction)->function)
++ fs_give((void **)&((*raction)->function));
++ if ((*raction)->value)
++ free_token_value(&(*raction)->value);
++ fs_give((void **)raction);
++ }
++ }
++
++ void free_rule(RULE_S **rule)
++ {
++ if(rule && *rule){
++ free_condition(&((*rule)->condition));
++ free_ruleaction(&((*rule)->action));
++ fs_give((void **)rule);
++ }
++ }
++
++ void free_rule_list(RULELIST **rule)
++ {
++ if(!*rule)
++ return;
++
++ if((*rule)->next)
++ free_rule_list(&((*rule)->next));
++
++ if((*rule)->prule)
++ free_rule(&((*rule)->prule));
++
++ fs_give((void **)rule);
++ }
++
++ void
++ free_parsed_rule_list(PRULELIST_S **rule)
++ {
++ if(!*rule)
++ return;
++
++ if((*rule)->next)
++ free_parsed_rule_list(&((*rule)->next));
++
++ if((*rule)->rlist)
++ free_rule_list(&((*rule)->rlist));
++
++ fs_give((void **)rule);
++ }
++
++ void *
++ alloc_mem (size_t amount)
++ {
++ void *genmem;
++ memset(genmem = fs_get(amount), 0, amount);
++ return genmem;
++ }
++
++
++ void
++ parse_patterns_into_action(TOKEN_VALUE **tokenp)
++ {
++ if(!*tokenp)
++ return;
++
++ if((*tokenp)->testxt){
++ regex_t preg;
++
++ (*tokenp)->voidtxt = NULL;
++ (*tokenp)->voidtxt = fs_get(sizeof(regex_t));
++ if (regcomp((regex_t *)(*tokenp)->voidtxt,
++ (*tokenp)->testxt, REG_EXTENDED) != 0){
++ regfree((regex_t *)(*tokenp)->voidtxt);
++ (*tokenp)->voidtxt = NULL;
++ }
++ }
++ if((*tokenp)->voidtxt)
++ (*tokenp)->codefcn = FREEREGEX;
++ if((*tokenp)->next)
++ parse_patterns_into_action(&(*tokenp)->next);
++ }
++
++
++ int
++ isolate_condition (char *data, char **cvalue, int *len)
++ {
++ char *p = data;
++ int done = 0, error = 0, next_condition = 0, l;
++
++ if(*p == '"' && p[strlen(p) - 1] == '"'){
++ p[strlen(p) - 1] = '\0';
++ p++;
++ }
++ *cvalue = NULL;
++ while (*p && !done){
++ switch (*p){
++ case '_': *cvalue = advance_to_char(p,'}', STRICTLY, NULL);
++ if(*cvalue){
++ strcat(*cvalue,"}");
++ p += strlen(*cvalue);
++ }
++ else
++ error++;
++ done++;
++ case ' ': p++;
++ break;
++ case '&': if (*(p+1) == '&'){ /* looking for && */
++ p += 2;
++ next_condition++;
++ }
++ else{
++ error++;
++ done++;
++ }
++ break;
++ case '=': /* looking for => or -> */
++ case '-': if ((*(p+1) == '>') && (!next_condition)){
++ is_save = (*p == '-');
++ p += 2;
++ }
++ else
++ error++;
++ done++;
++ break;
++ default : done++;
++ error++;
++ break;
++ }
++ }
++ *len = p - data;
++ return error ? -1 : (*cvalue ? 1 : 0);
++ }
++
++ TOKEN_VALUE *
++ parse_group_data (char *data, int *error)
++ {
++ TOKEN_VALUE *rvalue;
++ char *p;
++ int offset, err = 0;
++
++ if(error)
++ *error = 0;
++
++ if (!data)
++ return (TOKEN_VALUE *) NULL;
++
++ rvalue = (TOKEN_VALUE *) alloc_mem(sizeof(TOKEN_VALUE));
++ if (p = advance_to_char(data,';', STRICTLY, &offset)){
++ rvalue->testxt = cpystr(p);
++ data += strlen(p) + 1 + offset;
++ rvalue->next = parse_group_data(data, error);
++ }
++ else if (p = advance_to_char(data,'}', STRICTLY, NULL))
++ rvalue->testxt = cpystr(p);
++ else if (data && *data == '}')
++ rvalue->testxt = cpystr("");
++ else{
++ err++;
++ free_token_value(&rvalue);
++ }
++ if (error)
++ *error += err;
++ return(rvalue);
++ }
++
++ CONDITION_S *
++ fill_condition(char *data)
++ {
++ CONDITION_S *condition;
++ int i, done, error = 0;
++ char *group;
++
++ for (i = 0, done = 0; !done && (i < NTOKENS); i++)
++ done = strncmp(data,token_rules[i], strlen(token_rules[i])) ? 0 : 1;
++ if (done){
++ condition = (CONDITION_S *) alloc_mem(sizeof(CONDITION_S));
++ condition->tname = cpystr(token_rules[--i]);
++ }
++ else
++ return (CONDITION_S *)NULL;
++
++ data += strlen(token_rules[i]);
++ for (; *data && *data == ' '; data++);
++ if (*data){
++ for (i = 0, done = 0; !done && (i < NREL); i++)
++ done = strncmp(data, rel_rules_test[i].value, 2) ? 0 : 1;
++ if (done)
++ condition->ttype = rel_rules_test[--i].ttype;
++ else{
++ free_condition(&condition);
++ return (CONDITION_S *) NULL;
++ }
++ }
++ data += 2;
++ for (; *data && *data == ' '; data++);
++ if (*data++ != '{'){
++ free_condition(&condition);
++ return (CONDITION_S *) NULL;
++ }
++ group = advance_to_char(data,'}', STRICTLY, &error);
++ if (group || (!group && error < 0)){
++ condition->value = parse_group_data(data, &error);
++ if(group && error)
++ free_condition(&condition);
++ if(group)
++ fs_give((void **) &group);
++ }
++ else
++ free_condition(&condition);
++ return condition;
++ }
++
++ /* eoc = end of condition, equal to -1 on error */
++ CONDITION_S *
++ parse_condition (char *data, int *eoc)
++ {
++ CONDITION_S *condition = NULL;
++ char *p = data, *cvalue;
++ int len, error = 0, rv;
++
++ if((rv = isolate_condition(data, &cvalue, &len)) > 0){
++ if(condition = fill_condition(cvalue))
++ condition->next = parse_condition(data+len, eoc);
++ else
++ error++;
++ }
++ *eoc += len;
++ if (error)
++ *eoc = -1;
++ return condition;
++ }
++
++ RULEACTION_S *
++ parse_action (char *data, int context)
++ {
++ int i, done;
++ RULEACTION_S *raction = NULL;
++ char *function, *p = data;
++
++ if (!p)
++ return (RULEACTION_S *) NULL;
++
++ for (; *p && *p == ' '; p++);
++ if (!*p)
++ return (RULEACTION_S *) NULL;
++
++ if (is_save){
++ raction = (RULEACTION_S *) alloc_mem(sizeof(RULEACTION_S));
++ raction->function = cpystr("_SAVE_");
++ raction->value = (TOKEN_VALUE *) alloc_mem(sizeof(TOKEN_VALUE));
++ raction->context |= FOR_SAVE;
++ raction->exec = extended_value;
++ raction->value->testxt = cpystr(p);
++ return raction;
++ }
++ for (i = 0, done = 0; !done && (i < NFCN); i++)
++ done = (strstr(p,rule_fcns[i].name) == p);
++ p += done ? strlen(rule_fcns[--i].name) + 1 : 0;
++ if(!*p || (rule_fcns[i].what_for && !(rule_fcns[i].what_for & context)))
++ return (RULEACTION_S *) NULL;
++ if (done){
++ raction = (RULEACTION_S *) alloc_mem(sizeof(RULEACTION_S));
++ /* We assign raction->token to be subject. This is not necessary for
++ most rules. It is done only for rules that need it and will not
++ make any difference in rules that do not need it. It will hopefully
++ reduce complexity in the language
++ */
++ raction->token = cpystr(SUBJ_TOKEN);
++ raction->function = cpystr(rule_fcns[i].name);
++ raction->context = rule_fcns[i].what_for;
++ raction->exec = rule_fcns[i].execute;
++ raction->value = (TOKEN_VALUE *) alloc_mem(sizeof(TOKEN_VALUE));
++ raction->value->testxt = advance_to_char(p,'}', STRICTLY, NULL);
++ if(!raction->value->testxt)
++ free_ruleaction(&raction);
++ return raction;
++ }
++
++ done = (((function = strstr(p, "_TRIM_")) != NULL)
++ ? 1 : ((function = strstr(p, "_COPY_")) != NULL)
++ ? 2 : ((function = strstr(p, "_EXEC_")) != NULL)
++ ? 3 : ((function = strstr(p, "_REXTRIM_")) != NULL)
++ ? 4 : ((function = strstr(p, "_REPLACE_")) != NULL)
++ ? 5 : 0);
++
++ if(!function)
++ return (RULEACTION_S *) NULL;
++
++ *function = '\0';
++ raction = (RULEACTION_S *) alloc_mem(sizeof(RULEACTION_S));
++ raction->token = get_name_token(p);
++ *function = '_';
++ p += strlen(raction->token) + 1;
++ for (; *p && *p == ' '; p++);
++ if (!strncmp(p,":=",2))
++ p += 2;
++ else{
++ free_ruleaction(&raction);
++ return (RULEACTION_S *) NULL;
++ }
++ for (; *p && *p == ' '; p++);
++ if (p != function){
++ free_ruleaction(&raction);
++ return (RULEACTION_S *) NULL;
++ }
++ p += done <= 3 ? 6 : 9; /* 6 = strlen("_EXEC_"), 9 = strlen("_REPLACE_") */
++ if (*p != '{'){
++ free_ruleaction(&raction);
++ return (RULEACTION_S *) NULL;
++ }
++ *p = '\0';
++ for(i = 0; i < NFCN && strcmp(function, rule_fcns[i].name);i++);
++ raction->function = cpystr(function);
++ raction->is_trim = strcmp(function,"_TRIM_") ? 0 : 1;
++ raction->is_rextrim = strcmp(function,"_REXTRIM_") ? 0 : 1;
++ raction->is_replace = strcmp(function,"_REPLACE_") ? 0 : 1;
++ raction->context = rule_fcns[i].what_for;
++ raction->exec = rule_fcns[i].execute;
++ *p++ = '{';
++ if((raction->value = parse_group_data(p, NULL)) == NULL
++ || raction->value->testxt == NULL)
++ free_ruleaction(&raction);
++ if(raction && raction->is_rextrim)
++ parse_patterns_into_action(&raction->value);
++ return raction;
++ }
++
++ RULE_S *
++ parse_rule (char *data, int context)
++ {
++ RULE_S *prule; /*parsed rule */
++ int len = 0;
++
++ if (!(prule = (RULE_S *) alloc_mem(sizeof(RULE_S))) ||
++ !(prule->condition = parse_condition(data, &len)) ||
++ !(prule->action = parse_action(data+len, context)))
++ free_rule(&prule);
++
++ return prule;
++ }
++
++ RULELIST *
++ get_rule_list(char **list, int context, int i)
++ {
++ RULE_S *rule;
++ RULELIST *trulelist = NULL;
++
++ if (list[i] && *list[i]){
++ if(rule = parse_rule(list[i], context)){
++ trulelist = (RULELIST *)alloc_mem(sizeof(RULELIST));
++ trulelist->prule = rule;
++ trulelist->next = get_rule_list(list, context, i+1);
++ }
++ else
++ trulelist = get_rule_list(list, context, i+1);
++ }
++ return trulelist;
++ }
++
++ PRULELIST_S *
++ add_prule(PRULELIST_S *rule_list, PRULELIST_S *rule)
++ {
++ if (!rule_list)
++ rule_list = (PRULELIST_S *) alloc_mem(sizeof(PRULELIST_S));
++
++ if(rule_list->next)
++ rule_list->next = add_prule(rule_list->next, rule);
++ else{
++ if (rule_list->rlist)
++ rule_list->next = rule;
++ else
++ rule_list = rule;
++ }
++ return rule_list;
++ }
++
++ void
++ add_rule(int code, int context)
++ {
++ char **list = ps_global->vars[code].current_val.l;
++ PRULELIST_S *prulelist, *trulelist, *orulelist;
++
++ if (list && *list && **list){
++ trulelist = (PRULELIST_S *)alloc_mem(sizeof(PRULELIST_S));
++ trulelist->varnum = code;
++ if (trulelist->rlist = get_rule_list(list, context, 0))
++ ps_global->rule_list = add_prule(ps_global->rule_list, trulelist);
++ else
++ free_parsed_rule_list(&trulelist);
++ }
++ }
++
++ /* see create_rule_list below */
++ void
++ set_rule_list(struct variable *vars)
++ {
++ set_current_val(&vars[V_THREAD_DISP_STYLE_RULES], TRUE, TRUE);
++ set_current_val(&vars[V_THREAD_INDEX_STYLE_RULES], TRUE, TRUE);
++ set_current_val(&vars[V_COMPOSE_RULES], TRUE, TRUE);
++ set_current_val(&vars[V_FORWARD_RULES], TRUE, TRUE);
++ set_current_val(&vars[V_INDEX_RULES], TRUE, TRUE);
++ set_current_val(&vars[V_KEY_RULES], FALSE, TRUE);
++ set_current_val(&vars[V_REPLACE_RULES], TRUE, TRUE);
++ set_current_val(&vars[V_REPLY_INDENT_RULES], TRUE, TRUE);
++ set_current_val(&vars[V_REPLY_LEADIN_RULES], TRUE, TRUE);
++ set_current_val(&vars[V_RESUB_RULES], TRUE, TRUE);
++ set_current_val(&vars[V_SAVE_RULES], TRUE, TRUE);
++ set_current_val(&vars[V_SMTP_RULES], TRUE, TRUE);
++ set_current_val(&vars[V_SORT_RULES], TRUE, TRUE);
++ set_current_val(&vars[V_STARTUP_RULES], TRUE, TRUE);
++ }
++
++ /* see set_rule_list above */
++ void
++ create_rule_list(struct variable *vars)
++ {
++ set_rule_list(vars);
++ add_rule(V_THREAD_DISP_STYLE_RULES, FOR_THREAD);
++ add_rule(V_THREAD_INDEX_STYLE_RULES, FOR_THREAD);
++ add_rule(V_COMPOSE_RULES, FOR_COMPOSE);
++ add_rule(V_FORWARD_RULES, FOR_COMPOSE);
++ add_rule(V_INDEX_RULES, FOR_INDEX);
++ add_rule(V_KEY_RULES, FOR_KEY);
++ add_rule(V_REPLACE_RULES, FOR_REPLACE);
++ add_rule(V_REPLY_INDENT_RULES, FOR_COMPOSE);
++ add_rule(V_REPLY_LEADIN_RULES, FOR_REPLY_INTRO);
++ add_rule(V_RESUB_RULES, FOR_RESUB|FOR_TRIM);
++ add_rule(V_SAVE_RULES, FOR_SAVE);
++ add_rule(V_SMTP_RULES, FOR_COMPOSE);
++ add_rule(V_SORT_RULES, FOR_SORT);
++ add_rule(V_STARTUP_RULES, FOR_STARTUP);
++ }
++
++ int
++ condition_contains_token(CONDITION_S *condition, char *token)
++ {
++ return condition ? (!strcmp(condition->tname, token)
++ ? 1
++ : condition_contains_token(condition->next, token))
++ : 0;
++ }
++
++ RULELIST *
++ get_rulelist_from_code(int code, PRULELIST_S *list)
++ {
++ return list ? (list->varnum == code ? list->rlist
++ : get_rulelist_from_code(code, list->next))
++ : (RULELIST *) NULL;
++ }
++
++ char *
++ test_rule(RULELIST *rlist, int ctxt, ENVELOPE *env, int *n)
++ {
++ char *result;
++
++ if(!rlist)
++ return NULL;
++
++ if (result = process_rule(rlist->prule, ctxt, env))
++ return result;
++ else{
++ (*n)++;
++ return test_rule(rlist->next, ctxt, env, n);
++ }
++ }
++
++ RULE_S *
++ get_rule (RULELIST *rule, int n)
++ {
++ return rule ? (n ? get_rule(rule->next, n-1) : rule->prule)
++ : (RULE_S *) NULL;
++ }
++
++ /* get_result_rule:
++ * Parameters: list: the list of rules to be passed to the function to check
++ * rule_context: context of the rule
++ * env : envelope used to check the rule, if needed.
++ *
++ * Returns: The value of the first rule that is satisfied in the list, or
++ * NULL if not. This function should be called in the following
++ * way (notice that memory is freed by caller).
++ *
++ * You should use this function to obtain the result of a rule. You can
++ * also call directly "process_rule", but I advice to use this function if
++ * there's no difference on which function to call.
++
++ RULE_RESULT *rule;
++
++ rule = (RULE_RESULT *)
++ get_result_rule(V_SOME_RULE, context, envelope);
++
++ if (rule){
++ assign the value of rule->result;
++ if (rule->result)
++ fs_give((void **)&rule->result);
++ fs_give((void **)&rule);
++ }
++ */
++
++ RULE_RESULT *
++ get_result_rule(int code, int rule_context, ENVELOPE *env)
++ {
++ char *rule_result;
++ RULE_RESULT *rule = NULL;
++ RULELIST *rlist;
++ int n = 0;
++
++ if(!(rule_context & FOR_RULE))
++ rule_context |= FOR_RULE;
++ rlist = get_rulelist_from_code(code, ps_global->rule_list);
++ if (rlist){
++ rule_result = test_rule(rlist, rule_context, env, &n);
++ if (rule_result && *rule_result){
++ rule = (RULE_RESULT *) fs_get (sizeof(RULE_RESULT));
++ rule->result = rule_result;
++ rule->number = n;
++ }
++ }
++ return rule;
++ }
++
++ char *get_rule_result(int rule_context, char *newfolder, int code)
++ {
++ char *rule_result = NULL;
++ ENVELOPE *news_envelope;
++ RULE_RESULT *rule;
++
++ if (IS_NEWS(ps_global->mail_stream)){
++ news_envelope = mail_newenvelope();
++ news_envelope->newsgroups = cpystr(newfolder);
++ }
++ else
++ news_envelope = NULL;
++
++ rule = get_result_rule(code, rule_context, news_envelope);
++
++ if (news_envelope)
++ mail_free_envelope (&news_envelope);
++
++ if (rule){
++ rule_result = cpystr(rule->result);
++ if (rule->result)
++ fs_give((void **)&rule->result);
++ fs_give((void **)&rule);
++ }
++ return rule_result;
++ }
++
++ /* process_rule:
++ Parameters: rule_data, is a rule. It's obtained as
++ rule_data = ps_global->VAR_SOME_RULE[n], for
++ some integer n
++ rule_context: context of the rule, and
++ env: An envelope if needed.
++
++ Returns : The value of the processed rule_data if the processing was
++ successful and matches context and possibly the envelope, or
++ NULL if there's no match
++ */
++
++ char *
++ process_rule (RULE_S *prule, int rule_context, ENVELOPE *env)
++ {
++ char *result = NULL;
++ int rv;
++ CONDITION_S *condition;
++
++ if(!prule)
++ return NULL;
++
++ if(!(rule_context & FOR_RULE))
++ rule_context |= FOR_RULE;
++
++ for(condition = prule->condition;
++ condition &&
++ (rv = test_condition(condition, rule_context, env));
++ condition = condition->next);
++
++ if(rv && !condition)
++ result = (prule->action->exec)(prule->action, rule_context, env);
++
++ return result;
++ }
++
++ TOKEN_VALUE *
++ copy_parsed_value(TOKEN_VALUE *value, int ctxt, ENVELOPE *env)
++ {
++ TOKEN_VALUE *tval = NULL;
++
++ if(!value)
++ return NULL;
++
++ if(value->testxt){
++ tval = (TOKEN_VALUE *) alloc_mem(sizeof(TOKEN_VALUE));
++ tval->testxt = detoken_src(value->testxt, ctxt, env, NULL, NULL, NULL);
++ tval->voidtxt = value->voidtxt;
++ tval->codefcn = value->codefcn;
++ }
++ if(value->next)
++ tval->next = copy_parsed_value(value->next, ctxt, env);
++
++ return tval;
++ }
++
++ void
++ free_parsed_value(TOKEN_VALUE **value)
++ {
++ TOKEN_VALUE *tval = NULL;
++
++ if(!*value)
++ return;
++
++ if((*value)->testxt)
++ fs_give((void **)&(*value)->testxt);
++
++ if((*value)->next)
++ free_parsed_value(&(*value)->next);
++
++ fs_give((void **)value);
++ }
++
++
++ int
++ test_condition(CONDITION_S *condition, int rule_context, ENVELOPE *env)
++ {
++ int next_step;
++ TOKEN_VALUE *group;
++
++ group = copy_parsed_value(condition->value, rule_context, env);
++ next_step = (*rel_rules_test[condition->ttype].execute)(condition, group, env, rule_context);
++ free_parsed_value(&group);
++ return next_step;
++ }
++
++ /* returns the name of the token it found or NULL if there is no token, the
++ * real value of the token is obtained by calling the detoken_src function.
++ */
++
++ char *
++ get_name_token (char *condition)
++ {
++ char *p = NULL, *q, *s;
++
++ if ((q = strchr(condition,'_')) && (s = strchr(q+1,'_'))){
++ char c = *++s;
++ *s = '\0';
++ p = cpystr(q);
++ *s = c;
++ }
++ return p;
++ }
++
++ /* This function tests if a string contained in the variable "group" is
++ * in the "condition"
++ */
++ int test_in (CONDITION_S *condition, TOKEN_VALUE *group, ENVELOPE *env,
++ int context)
++ {
++ int rv = 0;
++ char *test;
++ TOKEN_VALUE *test_group = group;
++
++ test = env && env->sparep && ((SPAREP_S *)env->sparep)->flag & USE_RAW_SP
++ ? cpystr(((SPAREP_S *)env->sparep)->value)
++ : detoken_src(condition->tname, context, env, NULL, NULL, NULL);
++ if (test){
++ while (rv == 0 && test_group){
++ if(!*test || strstr(test_group->testxt, test))
++ rv++;
++ else
++ test_group = test_group->next;
++ }
++ fs_give((void **)&test);
++ }
++ return rv;
++ }
++
++ int test_ni (CONDITION_S *condition, TOKEN_VALUE *group,
++ ENVELOPE *env, int context)
++ {
++ int rv = 0;
++ char *test;
++ TOKEN_VALUE *test_group = group;
++
++ test = env && env->sparep && ((SPAREP_S *)env->sparep)->flag & USE_RAW_SP
++ ? cpystr(((SPAREP_S *)env->sparep)->value)
++ : detoken_src(condition->tname, context, env, NULL, NULL, NULL);
++ if (test){
++ if(!test_group)
++ rv++;
++ while (rv == 0 && test_group){
++ if(!*test_group->testxt || strstr(test, test_group->testxt))
++ rv++;
++ else
++ test_group = test_group->next;
++ }
++ fs_give((void **)&test);
++ }
++ return rv;
++ }
++
++ int test_not_in (CONDITION_S *condition, TOKEN_VALUE *group,
++ ENVELOPE *env, int context)
++ {
++ return !test_in(condition, group, env, context);
++ }
++
++ int test_not_ni (CONDITION_S *condition, TOKEN_VALUE *group,
++ ENVELOPE *env, int context)
++ {
++ return !test_ni(condition, group, env, context);
++ }
++
++ int test_eq (CONDITION_S *condition, TOKEN_VALUE *group,
++ ENVELOPE *env, int context)
++ {
++ int rv = 0;
++ char *test;
++ TOKEN_VALUE *test_group = group;
++
++ test = env && env->sparep && ((SPAREP_S *)env->sparep)->flag & USE_RAW_SP
++ ? cpystr(((SPAREP_S *)env->sparep)->value)
++ :detoken_src(condition->tname, context, env, NULL, NULL, NULL);
++ if (test){
++ while (rv == 0 && test_group){
++ if((!*test && !*test_group->testxt) || !strcmp(test_group->testxt, test))
++ rv++;
++ else
++ test_group = test_group->next;
++ }
++ fs_give((void **)&test);
++ }
++ return rv;
++ }
++
++ int test_not_eq (CONDITION_S *condition, TOKEN_VALUE *group,
++ ENVELOPE *env, int context)
++ {
++ return !test_eq(condition, group, env, context);
++ }
++
++ char *
++ do_trim (char *test, TOKEN_VALUE *tval)
++ {
++ char *begin_text;
++ int offset = 0;
++
++ if (!tval)
++ return test;
++
++ while(begin_text = strstr(test+offset,tval->testxt)){
++ strcpy(begin_text, begin_text+strlen(tval->testxt));
++ offset = begin_text - test;
++ }
++
++ return do_trim(test, tval->next);
++ }
++
++ char *
++ trim (RULEACTION_S *action, int context, ENVELOPE *env)
++ {
++ char *begin_text, *test;
++ RULEACTION_S *taction = action;
++ int offset;
++
++ if (taction->context & context){
++ if (test = detoken_src(taction->token, context, env, NULL, NULL, NULL))
++ test = do_trim(test, taction->value);
++ return test;
++ }
++ return NULL;
++ }
++
++
++ char *
++ do_rextrim (char *test, TOKEN_VALUE *tval)
++ {
++ char *begin_text, *trim_text;
++ int offset = 0;
++
++ if (!tval)
++ return test;
++
++ trim_text = expand(test, tval->voidtxt);
++ while(trim_text && (begin_text = strstr(test+offset,trim_text))){
++ strcpy(begin_text, begin_text+strlen(trim_text));
++ offset = begin_text - test;
++ }
++
++ return do_rextrim(test, tval->next);
++ }
++
++ char *
++ rextrim (RULEACTION_S *action, int context, ENVELOPE *env)
++ {
++ char *test = NULL;
++ RULEACTION_S *taction = action;
++
++ if (taction->context & context &&
++ (test = detoken_src(taction->token, context, env, NULL, NULL, NULL)))
++ test = do_rextrim(test, taction->value);
++ return test;
++ }
++
++ char *
++ raw_value (RULEACTION_S *action, int context, ENVELOPE *env)
++ {
++ return (action->context & context) ? cpystr(action->value->testxt) : NULL;
++ }
++
++ char *
++ extended_value (RULEACTION_S *action, int ctxt, ENVELOPE *env)
++ {
++ return (action->context & ctxt)
++ ? detoken_src(action->value->testxt, ctxt, env, NULL, NULL, NULL)
++ : NULL;
++ }
++
++ /* advances given_string until it finds given_char */
++ char *
++ advance_to_char(char *given_string, char given_char, int flag, int *error)
++ {
++ char *b, *s, c;
++ int i, err = 0, quoted ;
++
++ if (error)
++ *error = 0;
++
++ if (!given_string || !*given_string)
++ return NULL;
++
++ b = s = cpystr(given_string);
++ for(i = 0, quoted = 0, c = *s; c ; c = *++s){
++ if(c == '\\'){
++ quoted++;
++ continue;
++ }
++ if(quoted){
++ quoted = 0;
++ if (c == given_char){
++ err += flag & STRICTLY ? 0 : 1;
++ err++;
++ break;
++ }
++ b[i++] = '\\';
++ }
++ if(c == given_char){
++ err += flag & STRICTLY ? 0 : 1;
++ break;
++ }
++ b[i++] = c;
++ }
++ b[i] = '\0';
++ if (b && (strlen(b) == strlen(given_string)) && (flag & STRICTLY))
++ return NULL; /* character not found */
++
++ if(b && !*b){
++ fs_give((void **)&b);
++ err = -1;
++ }
++
++ if (error)
++ *error = err;
++
++ return b;
++ }
++
++ /* Regular Expressions Support */
++ char *
++ expand (char *string, void *pattern)
++ {
++ char c, *ret_string = NULL;
++ regmatch_t pmatch;
++
++ if((regex_t *)pattern == NULL)
++ return NULL;
++
++ if(regexec((regex_t *)pattern, string , 1, &pmatch, 0) == 0
++ && pmatch.rm_so < pmatch.rm_eo){
++ c = string[pmatch.rm_eo];
++ string[pmatch.rm_eo] = '\0';
++ ret_string = cpystr(string+pmatch.rm_so);
++ string[pmatch.rm_eo] = c;
++ }
++ return ret_string;
++ }
++
++
++ char *
++ exec_fcn (RULEACTION_S *action, int ctxt, ENVELOPE *env)
++ {
++ STORE_S *output_so;
++ gf_io_t gc, pc;
++ char *status, *rv, *cmd, *test;
++
++ if(!(action->context & ctxt))
++ return NULL;
++
++ if((test = detoken_src(action->token, ctxt, env, NULL, NULL, NULL)) != NULL)
++ gf_set_readc(&gc, test, (unsigned long)strlen(test), CharStar, 0);
++
++ if((output_so = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL)
++ gf_set_so_writec(&pc, output_so);
++
++ cmd = (char *)fs_get((strlen(action->value->testxt) + strlen("_TMPFILE_") + 2)*sizeof(char));
++ sprintf(cmd,"%s _TMPFILE_", action->value->testxt);
++ status = (*ps_global->tools.exec_rule)(cmd, gc, pc);
++
++ so_seek(output_so, 0L, 0);
++ rv = cpystr(output_so->dp);
++ gf_clear_so_writec(output_so);
++ so_give(&output_so);
++ if(test)
++ fs_give((void **)&test);
++
++ return status ? NULL : rv;
++ }
++
++ ENVELOPE *
++ rules_fetchenvelope(INDEXDATA_S *idata, int *we_clear)
++ {
++ ENVELOPE *env;
++
++ if (idata->no_fetch){
++ if(we_clear)
++ *we_clear = 1;
++ env = mail_newenvelope();
++ env->from = copyaddrlist(idata->from);
++ env->to = copyaddrlist(idata->to);
++ env->cc = copyaddrlist(idata->cc);
++ env->sender = copyaddrlist(idata->sender);
++ env->subject = cpystr(idata->subject);
++ env->date = cpystr((unsigned char *) idata->date);
++ env->newsgroups = cpystr(idata->newsgroups);
++ return env;
++ }
++ if(we_clear)
++ *we_clear = 0;
++ env = pine_mail_fetchenvelope(idata->stream, idata->rawno);
++ return env;
++ }
+diff -rc alpine-2.00/pith/rules.h alpine-2.00.I.USE/pith/rules.h
+*** alpine-2.00/pith/rules.h 2011-02-07 20:34:02.000000000 -0800
+--- alpine-2.00.I.USE/pith/rules.h 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 0 ****
+--- 1,151 ----
++ /* Included file rules.h */
++
++ #ifndef PITH_RULES_INCLUDED
++ #define PITH_RULES_INCLUDED
++
++ #include "../pith/conftype.h"
++ #include "../pith/detoken.h"
++ #include "../pith/indxtype.h"
++ #include "../pith/rulestype.h"
++
++ int is_save; /* this rule has the form condition -> folder */
++
++ /* Exported prototypes */
++
++ void create_rule_list (struct variable *);
++ SPAREP_S *get_sparep_for_rule(char *, int);
++ void free_sparep_for_rule(void **);
++ void free_parsed_rule_list (PRULELIST_S **);
++ RULE_RESULT *get_result_rule (int, int, ENVELOPE *);
++ char *get_rule_result (int , char *, int);
++ char *process_rule (RULE_S *, int, ENVELOPE *);
++ char **functions_for_token (char *);
++ RULELIST *get_rulelist_from_code (int, PRULELIST_S *);
++ RULE_S *get_rule (RULELIST *, int);
++ int condition_contains_token (CONDITION_S *, char *);
++ int context_for_function (char *);
++ ENVELOPE *rules_fetchenvelope(INDEXDATA_S *idata, int *we_clear);
++
++ /* Separators:
++ *
++ * A separator is a string that separates the rule condition with the rule
++ * action. Below is the list of separators
++ *
++ */
++
++ #define SAVE_TO_SEP "->"
++ #define APPLY_SEP "=>"
++
++ /*------- Definitions of tokens -------*/
++ /*------ Keep the list alphabetically sorted, thanks -------*/
++
++ #define ADDR_TOKEN "_ADDRESS_"
++ #define ADDCC_TOKEN "_ADDRESSCC_"
++ #define ADDRECIP_TOKEN "_ADDRESSRECIPS_"
++ #define ADDTO_TOKEN "_ADDRESSTO_"
++ #define BCC_TOKEN "_BCC_"
++ #define CC_TOKEN "_CC_"
++ #define COLLECT_TOKEN "_COLLECTION_"
++ #define FLAG_TOKEN "_FLAG_"
++ #define FOLDER_TOKEN "_FOLDER_"
++ #define FADDRESS_TOKEN "_FORWARDADDRESS_"
++ #define FFROM_TOKEN "_FORWARDFROM_"
++ #define FROM_TOKEN "_FROM_"
++ #define KEY_TOKEN "_PKEY_"
++ #define LCC_TOKEN "_LCC_"
++ #define NICK_TOKEN "_NICK_"
++ #define OTEXT_TOKEN "_OPENINGTEXT_"
++ #define OTEXTNQ_TOKEN "_OPENINGTEXTNQ_"
++ #define PROCID_TOKEN "_PROCID_"
++ #define ROLE_TOKEN "_ROLE_"
++ #define SCREEN_TOKEN "_SCREEN_"
++ #define SEND_TOKEN "_SENDER_"
++ #define SUBJ_TOKEN "_SUBJECT_"
++ #define THDDSPSTY_TOKEN "_THREADSTYLE_"
++ #define THDNDXSTY_TOKEN "_THREADINDEX_"
++ #define TO_TOKEN "_TO_"
++
++ /*------ Definitions of relational operands -------------*/
++
++ typedef struct {
++ char *value;
++ TestType ttype;
++ int (*execute)();
++ } REL_TOKEN;
++
++ /* Relational Operands */
++ #define AND_REL "&&" /* For putting more than one condition */
++ #define IN_REL "<<" /* For belonging relation */
++ #define NI_REL ">>" /* For contain relation */
++ #define NOT_IN_REL "!<" /* Negation of IN_REL */
++ #define NOT_NI_REL "!>" /* Negation of NI_REL */
++ #define EQ_REL "==" /* Test of equality */
++ #define NOT_EQ_REL "!=" /* Test of inequality */
++ #define OPEN_SET "{" /* Braces to open a set */
++ #define CLOSE_SET "}" /* Braces to close a set*/
++
++ /*--- Context in which these variables can be used ---*/
++
++ typedef struct use_context {
++ char *name;
++ int what_for;
++ } USE_IN_CONTEXT;
++
++
++ static USE_IN_CONTEXT tokens_use[] = {
++ {NICK_TOKEN, FOR_SAVE},
++ {FROM_TOKEN, FOR_SAVE},
++ {OTEXT_TOKEN, FOR_SAVE|FOR_FOLDER},
++ {OTEXTNQ_TOKEN, FOR_SAVE|FOR_FOLDER},
++ {ROLE_TOKEN, FOR_COMPOSE},
++ {FOLDER_TOKEN, FOR_SAVE|FOR_FOLDER|FOR_THREAD|FOR_COMPOSE},
++ {SUBJ_TOKEN, FOR_SAVE|FOR_FOLDER|FOR_COMPOSE},
++ {FLAG_TOKEN, FOR_SAVE|FOR_FLAG},
++ {COLLECT_TOKEN, FOR_SAVE|FOR_COMPOSE|FOR_FOLDER|FOR_THREAD},
++ {THDDSPSTY_TOKEN, FOR_THREAD},
++ {THDNDXSTY_TOKEN, FOR_THREAD},
++ {ADDR_TOKEN, FOR_SAVE|FOR_FOLDER},
++ {TO_TOKEN, FOR_SAVE},
++ {ADDTO_TOKEN, FOR_SAVE|FOR_COMPOSE},
++ {ADDCC_TOKEN, FOR_SAVE|FOR_COMPOSE},
++ {ADDRECIP_TOKEN, FOR_SAVE|FOR_COMPOSE},
++ {SCREEN_TOKEN, FOR_KEY},
++ {KEY_TOKEN, FOR_KEY},
++ {SEND_TOKEN, FOR_SAVE},
++ {CC_TOKEN, FOR_SAVE},
++ {BCC_TOKEN, FOR_COMPOSE},
++ {LCC_TOKEN, FOR_COMPOSE},
++ {FFROM_TOKEN, FOR_COMPOSE},
++ {FADDRESS_TOKEN, FOR_COMPOSE},
++ {NULL, FOR_NOTHING}
++ };
++
++
++ typedef struct {
++ char *name;
++ char* (*execute)();
++ int what_for;
++ } RULE_FCN;
++
++ #define COMMAND_FCN "_COMMAND_"
++ #define COPY_FCN "_COPY_"
++ #define EXEC_FCN "_EXEC_"
++ #define INDEX_FCN "_INDEX_"
++ #define REPLACE_FCN "_REPLACE_"
++ #define REPLYSTR_FCN "_RESTR_"
++ #define REPLY_FCN "_REPLY_"
++ #define RESUB_FCN "_RESUB_"
++ #define REXTRIM_FCN "_REXTRIM_"
++ #define SAVE_FCN "_SAVE_"
++ #define SIGNATURE_FCN "_SIGNATURE_"
++ #define SMTP_FCN "_SMTP_"
++ #define SORT_FCN "_SORT_"
++ #define STARTUP_FCN "_STARTUP_"
++ #define THRDSTYLE_FCN "_THREADSTYLE_"
++ #define THRDINDEX_FCN "_THREADINDEX_"
++ #define TRIM_FCN "_TRIM_"
++
++ #define STRICTLY 0x1
++ #define RELAXED 0x2
++
++ #endif /* PITH_RULES_INCLUDED */
+diff -rc alpine-2.00/pith/rulestype.h alpine-2.00.I.USE/pith/rulestype.h
+*** alpine-2.00/pith/rulestype.h 2011-02-07 20:34:02.000000000 -0800
+--- alpine-2.00.I.USE/pith/rulestype.h 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 0 ****
+--- 1,78 ----
++ #ifndef PITH_RULESTYPE_INCLUDED
++ #define PITH_RULESTYPE_INCLUDED
++
++ typedef struct rule {
++ char *result; /* The result of the rule */
++ int number; /* The number of the rule that succeded, -1 if not */
++ } RULE_RESULT;
++
++ typedef struct {
++ char *value;
++ int type;
++ } RULE_ACTION;
++
++
++ #define TOKEN_VALUE struct tokenvalue_s
++ #define CONDITION_S struct condition_s
++ #define RULEACTION_S struct ruleaction_s
++ #define RULE_S struct rule_s
++ #define RULELIST struct rulelist_s
++ #define PRULELIST_S struct parsedrulelist_s
++
++ #define FREEREGEX 1
++
++ TOKEN_VALUE {
++ char *testxt;
++ void *voidtxt;
++ int codefcn;
++ TOKEN_VALUE *next;
++ };
++
++ typedef enum {Equal, Subset, Includes,
++ NotEqual, NotSubset, NotIncludes,
++ EndTypes} TestType;
++
++ CONDITION_S {
++ char *tname; /* tname ttype {value} */
++ TestType ttype; /* tname ttype {value} */
++ TOKEN_VALUE *value; /* value to check against */
++ CONDITION_S *next; /* next condition to test */
++ };
++
++ RULEACTION_S {
++ char *token; /* token := function{value} or token = null */
++ char *function; /* token := function{value} or simply function{value}*/
++ TOKEN_VALUE *value; /* token := function{value} or simply function{value}*/
++ int context; /* context in which this rule can be used */
++ char* (*exec)();
++ unsigned int is_trim:1;
++ unsigned int is_rextrim:1;
++ unsigned int is_replace:1;
++ };
++
++ RULE_S {
++ CONDITION_S *condition;
++ RULEACTION_S *action;
++ };
++
++ RULELIST {
++ RULE_S *prule;
++ RULELIST *next;
++ };
++
++ PRULELIST_S {
++ int varnum; /* number associated to the variable */
++ RULELIST *rlist;
++ PRULELIST_S *next;
++ };
++
++ #define USE_RAW_SP 0x001
++ #define PROCESS_SP 0x010
++
++ typedef struct sparep {
++ int flag;
++ char *value;
++ } SPAREP_S;
++
++
++ #endif /* PITH_RULESTYPE_INCLUDED */
+diff -rc alpine-2.00/pith/save.c alpine-2.00.I.USE/pith/save.c
+*** alpine-2.00/pith/save.c 2008-05-02 14:58:34.000000000 -0700
+--- alpine-2.00.I.USE/pith/save.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 421,426 ****
+--- 421,427 ----
+ {
+ int rv, rc, j, our_stream = 0, cancelled = 0;
+ int delete, filter, k, worry_about_keywords = 0;
++ int flags_for_save = F_ANS|F_FWD|F_FLAG|F_SEEN|F_KEYWORD;
+ char *save_folder, *seq, *flags = NULL, date[64], tmp[MAILTMPLEN];
+ long i, nmsgs, rawno;
+ size_t len;
+***************
+*** 864,870 ****
+ STRING msg;
+
+ pkg.stream = stream;
+! pkg.flags = NULL;
+ pkg.date = date;
+ pkg.msg = &msg;
+ pkg.msgmap = msgmap;
+--- 865,871 ----
+ STRING msg;
+
+ pkg.stream = stream;
+! pkg.flags = flgs & SV_FIX_DELS ? NULL : cpystr("\\DELETED");
+ pkg.date = date;
+ pkg.msg = &msg;
+ pkg.msgmap = msgmap;
+***************
+*** 938,944 ****
+ mc = (rawno > 0L && stream && rawno <= stream->nmsgs)
+ ? mail_elt(stream, rawno) : NULL;
+
+! flags = flag_string(stream, rawno, F_ANS|F_FWD|F_FLAG|F_SEEN|F_KEYWORD);
+
+ if(mc && mc->day)
+ mail_date(date, mc);
+--- 939,946 ----
+ mc = (rawno > 0L && stream && rawno <= stream->nmsgs)
+ ? mail_elt(stream, rawno) : NULL;
+
+! flags_for_save |= flgs & SV_FIX_DELS ? 0 : F_DEL;
+! flags = flag_string(stream, rawno, flags_for_save);
+
+ if(mc && mc->day)
+ mail_date(date, mc);
+***************
+*** 946,952 ****
+ *date = '\0';
+
+ rv = save_fetch_append(stream, mn_m2raw(msgmap, i),
+! NULL, save_stream, save_folder, context,
+ mc ? mc->rfc822_size : 0L, flags, date, so);
+
+ if(flags)
+--- 948,954 ----
+ *date = '\0';
+
+ rv = save_fetch_append(stream, mn_m2raw(msgmap, i),
+! NULL, save_stream, folder, context,
+ mc ? mc->rfc822_size : 0L, flags, date, so);
+
+ if(flags)
+***************
+*** 1043,1048 ****
+--- 1045,1051 ----
+ MESSAGECACHE *mc;
+ char *fetch;
+ int rc;
++ int flags_for_save = F_ANS|F_FWD|F_FLAG|F_SEEN|F_KEYWORD;
+ unsigned long raw, hlen, tlen, mlen;
+
+ if(pkg->so && (pkg->msgno > 0L)) {
+***************
+*** 1051,1060 ****
+ ? mail_elt(pkg->stream, raw) : NULL;
+ if(mc){
+ size = mc->rfc822_size;
+! if(pkg->flags)
+ fs_give((void **) &pkg->flags);
+!
+! pkg->flags = flag_string(pkg->stream, raw, F_ANS|F_FWD|F_FLAG|F_SEEN|F_KEYWORD);
+ }
+
+ if(mc && mc->day)
+--- 1054,1065 ----
+ ? mail_elt(pkg->stream, raw) : NULL;
+ if(mc){
+ size = mc->rfc822_size;
+! if(pkg->flags){
+! if(strstr(pkg->flags,"\\DELETED"))
+! flags_for_save |= F_DEL;
+ fs_give((void **) &pkg->flags);
+! }
+! pkg->flags = flag_string(pkg->stream, raw, flags_for_save);
+ }
+
+ if(mc && mc->day)
+***************
+*** 1136,1141 ****
+--- 1141,1147 ----
+ snprintf(buf, sizeof(buf),
+ "Message to save shrank: source msg # %ld may be saved incorrectly",
+ mn_raw2m(pkg->msgmap, raw));
++ if(F_OFF(F_IGNORE_SIZE, ps_global))
+ q_status_message(SM_ORDER, 0, 3, buf);
+ }
+ else{
+diff -rc alpine-2.00/pith/send.c alpine-2.00.I.USE/pith/send.c
+*** alpine-2.00/pith/send.c 2008-08-06 11:25:58.000000000 -0700
+--- alpine-2.00.I.USE/pith/send.c 2011-02-07 20:33:43.000000000 -0800
+***************
+*** 43,48 ****
+--- 43,49 ----
+ #include "../pith/ablookup.h"
+ #include "../pith/sort.h"
+ #include "../pith/smime.h"
++ #include "../pith/rules.h"
+
+ #include "../c-client/smtp.h"
+ #include "../c-client/nntp.h"
+***************
+*** 52,58 ****
+ /* name::type::canedit::writehdr::localcopy::rcptto */
+ PINEFIELD pf_template[] = {
+ {"X-Auth-Received", FreeText, 0, 1, 1, 0}, /* N_AUTHRCVD */
+! {"From", Address, 0, 1, 1, 0},
+ {"Reply-To", Address, 0, 1, 1, 0},
+ {TONAME, Address, 1, 1, 1, 1},
+ {CCNAME, Address, 1, 1, 1, 1},
+--- 53,59 ----
+ /* name::type::canedit::writehdr::localcopy::rcptto */
+ PINEFIELD pf_template[] = {
+ {"X-Auth-Received", FreeText, 0, 1, 1, 0}, /* N_AUTHRCVD */
+! {"From", Address, 1, 1, 1, 0},
+ {"Reply-To", Address, 0, 1, 1, 0},
+ {TONAME, Address, 1, 1, 1, 1},
+ {CCNAME, Address, 1, 1, 1, 1},
+***************
+*** 256,261 ****
+--- 257,269 ----
+
+ if(exists & FEX_ISFILE){
+ context_apply(tmp, p_cntxt, mbox, sizeof(tmp));
++ #ifndef _WINDOWS
++ if (!struncmp(tmp, "#md/",4) || !struncmp(tmp, "#mc/", 4)){
++ char tmp2[MAILTMPLEN];
++ maildir_file_path(tmp, tmp2);
++ strcpy(tmp, tmp2);
++ }
++ #endif
+ if(!(IS_REMOTE(tmp) || is_absolute_path(tmp))){
+ /*
+ * The mbox is relative to the home directory.
+***************
+*** 1228,1234 ****
+ *p = *(p+4);
+
+ pf->type = pf_template[i].type;
+! pf->canedit = pf_template[i].canedit;
+ pf->rcptto = pf_template[i].rcptto;
+ pf->writehdr = pf_template[i].writehdr;
+ pf->localcopy = pf_template[i].localcopy;
+--- 1236,1242 ----
+ *p = *(p+4);
+
+ pf->type = pf_template[i].type;
+! pf->canedit = (i == N_FROM) ? CAN_EDIT(ps_global) : pf_template[i].canedit;
+ pf->rcptto = pf_template[i].rcptto;
+ pf->writehdr = pf_template[i].writehdr;
+ pf->localcopy = pf_template[i].localcopy;
+***************
+*** 1737,1745 ****
+ char error_buf[200], *error_mess = NULL, *postcmd;
+ ADDRESS *a;
+ ENVELOPE *fake_env = NULL;
+! int addr_error_count, we_cancel = 0;
+ long smtp_opts = 0L;
+! char *verbose_file = NULL;
+ BODY *bp = NULL;
+ PINEFIELD *pf;
+ BODY *origBody = body;
+--- 1745,1753 ----
+ char error_buf[200], *error_mess = NULL, *postcmd;
+ ADDRESS *a;
+ ENVELOPE *fake_env = NULL;
+! int addr_error_count, we_cancel = 0, choice, num_rules = 0, added_rules = -1;
+ long smtp_opts = 0L;
+! char *verbose_file = NULL, **smtp_list;
+ BODY *bp = NULL;
+ PINEFIELD *pf;
+ BODY *origBody = body;
+***************
+*** 1892,1911 ****
+ * OK, who posts what? We tried an mta_handoff above, but there
+ * was either none specified or we decided not to use it. So,
+ * if there's an smtp-server defined anywhere,
+ */
+! if(alt_smtp_servers && alt_smtp_servers[0] && alt_smtp_servers[0][0]){
+! /*---------- SMTP ----------*/
+! dprint((4, "call_mailer: via TCP (%s)\n",
+! alt_smtp_servers[0]));
+! TIME_STAMP("smtp-open start (tcp)", 1);
+! sending_stream = smtp_open(alt_smtp_servers, smtp_opts);
+! }
+! else if(ps_global->VAR_SMTP_SERVER && ps_global->VAR_SMTP_SERVER[0]
+! && ps_global->VAR_SMTP_SERVER[0][0]){
+! /*---------- SMTP ----------*/
+! dprint((4, "call_mailer: via TCP\n"));
+! TIME_STAMP("smtp-open start (tcp)", 1);
+! sending_stream = smtp_open(ps_global->VAR_SMTP_SERVER, smtp_opts);
+ }
+ else if((postcmd = smtp_command(ps_global->c_client_error, sizeof(ps_global->c_client_error))) != NULL){
+ char *cmdlist[2];
+--- 1900,1948 ----
+ * OK, who posts what? We tried an mta_handoff above, but there
+ * was either none specified or we decided not to use it. So,
+ * if there's an smtp-server defined anywhere,
++ * First we check for rules and make a list using the rules.
+ */
+! if(ps_global->VAR_SMTP_RULES && ps_global->VAR_SMTP_RULES[0]
+! && ps_global->VAR_SMTP_RULES[0][0])
+! while (ps_global->VAR_SMTP_RULES[num_rules]) num_rules++;
+!
+! if(num_rules){
+! int i, j;
+!
+! added_rules = 0;
+! smtp_list = (char **) fs_get ((num_rules + 1)*sizeof(char*));
+! for (i = 0, j = 0; i < num_rules; i++){
+! RULELIST *rule = get_rulelist_from_code(V_SMTP_RULES,
+! ps_global->rule_list);
+! RULE_S *prule = get_rule(rule, i);
+! if(prule){
+! char *rule_result = process_rule(prule, FOR_COMPOSE, header->env);
+! if(rule_result && *rule_result){
+! smtp_list[j++] = cpystr(rule_result);
+! added_rules++;
+! }
+! }
+! }
+! }
+!
+! if (added_rules < 0){
+! smtp_list = (char **) fs_get (sizeof(char*));
+! added_rules = 0;
+! }
+! smtp_list[added_rules] = NULL;
+!
+! choice = smtp_list && smtp_list[0] && smtp_list[0][0] ? 3 :
+! (alt_smtp_servers && alt_smtp_servers[0] && alt_smtp_servers[0][0] ? 2 :
+! (ps_global->VAR_SMTP_SERVER && ps_global->VAR_SMTP_SERVER[0]
+! && ps_global->VAR_SMTP_SERVER[0][0] ? 1 : -1));
+!
+! if(choice > 0){
+! /*---------- SMTP ----------*/
+! dprint((4, "call_mailer: via TCP (%s)\n",smtp_list[0]));
+! TIME_STAMP("smtp-open start (tcp)", 1);
+! sending_stream = smtp_open(choice == 3 ? smtp_list
+! : (choice == 2 ? alt_smtp_servers
+! : ps_global->VAR_SMTP_SERVER), smtp_opts);
+ }
+ else if((postcmd = smtp_command(ps_global->c_client_error, sizeof(ps_global->c_client_error))) != NULL){
+ char *cmdlist[2];
+***************
+*** 2141,2146 ****
+--- 2178,2185 ----
+ if(error_mess){
+ q_status_message(SM_ORDER | SM_DING, 4, 7, error_mess);
+ dprint((1, "call_mailer ERROR: %s\n", error_mess));
++ if (ps_global->send_immediately)
++ printf("%s\n",error_mess);
+ }
+
+ return(-1);
+diff -rc alpine-2.00/pith/send.h alpine-2.00.I.USE/pith/send.h
+*** alpine-2.00/pith/send.h 2008-06-30 15:03:35.000000000 -0700
+--- alpine-2.00.I.USE/pith/send.h 2011-02-07 20:33:43.000000000 -0800
+***************
+*** 158,163 ****
+--- 158,165 ----
+ unsigned text_written:1;
+ };
+
++ #define CAN_EDIT(x) (!((x)->never_allow_changing_from) && \
++ F_ON(F_ALLOW_CHANGING_FROM, (x)))
+
+ #define TONAME "To"
+ #define CCNAME "cc"
+diff -rc alpine-2.00/pith/sort.c alpine-2.00.I.USE/pith/sort.c
+*** alpine-2.00/pith/sort.c 2008-07-09 22:01:13.000000000 -0700
+--- alpine-2.00.I.USE/pith/sort.c 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 29,35 ****
+ #include "../pith/signal.h"
+ #include "../pith/busy.h"
+ #include "../pith/icache.h"
+!
+
+ /*
+ * global place to store mail_sort and mail_thread results
+--- 29,35 ----
+ #include "../pith/signal.h"
+ #include "../pith/busy.h"
+ #include "../pith/icache.h"
+! #include "../pith/rules.h"
+
+ /*
+ * global place to store mail_sort and mail_thread results
+***************
+*** 90,96 ****
+ ----*/
+ void
+ sort_folder(MAILSTREAM *stream, MSGNO_S *msgmap, SortOrder new_sort,
+! int new_rev, unsigned int flags)
+ {
+ long raw_current, i, j;
+ unsigned long *sort = NULL;
+--- 90,96 ----
+ ----*/
+ void
+ sort_folder(MAILSTREAM *stream, MSGNO_S *msgmap, SortOrder new_sort,
+! int new_rev, unsigned int flags, int first)
+ {
+ long raw_current, i, j;
+ unsigned long *sort = NULL;
+***************
+*** 100,105 ****
+--- 100,114 ----
+ int current_rev;
+ MESSAGECACHE *mc;
+
++ if (first){
++ if (new_sort == SortThread)
++ find_msgmap(stream, msgmap, flags,
++ ps_global->thread_cur_sort, new_rev);
++ else
++ sort_folder(stream, msgmap, new_sort, new_rev, flags, 0);
++ return;
++ }
++
+ dprint((2, "Sorting by %s%s\n",
+ sort_name(new_sort), new_rev ? "/reverse" : ""));
+
+***************
+*** 529,548 ****
+ * argument also means arrival/reverse.
+ */
+ int
+! decode_sort(char *sort_spec, SortOrder *def_sort, int *def_sort_rev)
+ {
+ char *sep;
+ char *fix_this = NULL;
+! int x, reverse;
+
+ if(!sort_spec || !*sort_spec){
+! *def_sort = SortArrival;
+ *def_sort_rev = 0;
+ return(0);
+ }
+
+ if(struncmp(sort_spec, "reverse", strlen(sort_spec)) == 0){
+! *def_sort = SortArrival;
+ *def_sort_rev = 1;
+ return(0);
+ }
+--- 538,557 ----
+ * argument also means arrival/reverse.
+ */
+ int
+! decode_sort(char *sort_spec, SortOrder *def_sort, int *def_sort_rev, int thread)
+ {
+ char *sep;
+ char *fix_this = NULL;
+! int x = 0, reverse;
+
+ if(!sort_spec || !*sort_spec){
+! *def_sort = thread ? SortThread : SortArrival;
+ *def_sort_rev = 0;
+ return(0);
+ }
+
+ if(struncmp(sort_spec, "reverse", strlen(sort_spec)) == 0){
+! *def_sort = thread ? SortThread : SortArrival;
+ *def_sort_rev = 1;
+ return(0);
+ }
+***************
+*** 571,577 ****
+ if(ps_global->sort_types[x] == EndofList)
+ return(-1);
+
+! *def_sort = ps_global->sort_types[x];
+ *def_sort_rev = reverse;
+ return(0);
+ }
+--- 580,586 ----
+ if(ps_global->sort_types[x] == EndofList)
+ return(-1);
+
+! *def_sort = ps_global->sort_types[x];
+ *def_sort_rev = reverse;
+ return(0);
+ }
+***************
+*** 685,694 ****
+ PAT_S *pat;
+ SortOrder the_sort_order;
+ int sort_is_rev;
+!
+ /* set default order */
+ the_sort_order = ps_global->def_sort;
+! sort_is_rev = ps_global->def_sort_rev;
+
+ if(ps_global->mail_stream && nonempty_patterns(rflags, &pstate)){
+ for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)){
+--- 694,719 ----
+ PAT_S *pat;
+ SortOrder the_sort_order;
+ int sort_is_rev;
+! char *rule_result;
+! SortOrder new_sort = EndofList;
+! int is_rev;
+!
+! rule_result = get_rule_result(FOR_SORT, ps_global->cur_folder, V_SORT_RULES);
+! if (rule_result && *rule_result){
+! new_sort = (SortOrder) translate(rule_result, 1);
+! is_rev = (SortOrder) translate(rule_result, 0) == EndofList ? 0 : 1;
+! fs_give((void **)&rule_result);
+! }
+! if (new_sort != EndofList){
+! the_sort_order = new_sort;
+! sort_is_rev = is_rev;
+! }
+! else{
+ /* set default order */
+ the_sort_order = ps_global->def_sort;
+! sort_is_rev = the_sort_order == SortThread
+! ? (ps_global->thread_def_sort_rev + ps_global->def_sort_rev) % 2
+! : ps_global->def_sort_rev;
+
+ if(ps_global->mail_stream && nonempty_patterns(rflags, &pstate)){
+ for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)){
+***************
+*** 701,709 ****
+ && pat->action->sort_is_set){
+ the_sort_order = pat->action->sortorder;
+ sort_is_rev = pat->action->revsort;
+ }
+ }
+
+ sort_folder(ps_global->mail_stream, ps_global->msgmap,
+! the_sort_order, sort_is_rev, flags);
+ }
+--- 726,776 ----
+ && pat->action->sort_is_set){
+ the_sort_order = pat->action->sortorder;
+ sort_is_rev = pat->action->revsort;
++ sort_is_rev = the_sort_order == SortThread
++ ? (ps_global->thread_def_sort_rev + pat->action->revsort) % 2
++ : pat->action->revsort;
+ }
+ }
++ }
++ if(the_sort_order == SortThread && !(flags & SRT_MAN))
++ ps_global->thread_cur_sort = ps_global->thread_def_sort;
+
+ sort_folder(ps_global->mail_stream, ps_global->msgmap,
+! the_sort_order, sort_is_rev, flags, 1);
+! }
+!
+! SortOrder translate(char *order, int is_rev)
+! {
+! int rev = 0;
+! if (!strncmp(order,"tHread", 6)
+! || (rev = !strncmp(order,"Reverse tHread", 14)))
+! return is_rev || rev ? SortThread : EndofList;
+! if (!strncmp(order,"OrderedSubj", 11)
+! || (rev = !strncmp(order,"Reverse OrderedSubj", 19)))
+! return is_rev || rev ? SortSubject2 : EndofList;
+! if (!strncmp(order,"Subject", 7)
+! || (rev = !strncmp(order,"Reverse SortSubject", 15)))
+! return is_rev || rev ? SortSubject : EndofList;
+! if (!strncmp(order,"Arrival", 7)
+! || (rev = !strncmp(order,"Reverse Arrival", 15)))
+! return is_rev || rev ? SortArrival : EndofList;
+! if (!strncmp(order,"From", 4)
+! || (rev = !strncmp(order,"Reverse From", 12)))
+! return is_rev || rev ? SortFrom : EndofList;
+! if (!strncmp(order,"To", 2)
+! || (rev = !strncmp(order,"Reverse To", 10)))
+! return is_rev || rev ? SortTo : EndofList;
+! if (!strncmp(order,"Cc", 2)
+! || (rev = !strncmp(order,"Reverse Cc", 10)))
+! return is_rev || rev ? SortCc : EndofList;
+! if (!strncmp(order,"Date", 4)
+! || (rev = !strncmp(order,"Reverse Date", 12)))
+! return is_rev || rev ? SortDate : EndofList;
+! if (!strncmp(order,"siZe", 4)
+! || (rev = !strncmp(order,"Reverse siZe", 12)))
+! return is_rev || rev ? SortSize : EndofList;
+! if (!strncmp(order,"scorE", 5)
+! || (rev = !strncmp(order,"Reverse scorE", 13)))
+! return is_rev || rev ? SortScore : EndofList;
+! return EndofList;
+ }
+diff -rc alpine-2.00/pith/sort.h alpine-2.00.I.USE/pith/sort.h
+*** alpine-2.00/pith/sort.h 2006-09-22 13:06:05.000000000 -0700
+--- alpine-2.00.I.USE/pith/sort.h 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 22,28 ****
+
+
+ #define refresh_sort(S,M,F) sort_folder((S), (M), mn_get_sort(M), \
+! mn_get_revsort(M), (F))
+
+ struct global_sort_data {
+ MSGNO_S *msgmap;
+--- 22,28 ----
+
+
+ #define refresh_sort(S,M,F) sort_folder((S), (M), mn_get_sort(M), \
+! mn_get_revsort(M), (F), 1)
+
+ struct global_sort_data {
+ MSGNO_S *msgmap;
+***************
+*** 41,49 ****
+
+ /* exported protoypes */
+ char *sort_name(SortOrder);
+! void sort_folder(MAILSTREAM *, MSGNO_S *, SortOrder, int, unsigned);
+! int decode_sort(char *, SortOrder *, int *);
+ void reset_sort_order(unsigned);
+!
+
+ #endif /* PITH_SORT_INCLUDED */
+--- 41,49 ----
+
+ /* exported protoypes */
+ char *sort_name(SortOrder);
+! void sort_folder(MAILSTREAM *, MSGNO_S *, SortOrder, int, unsigned, int);
+! int decode_sort(char *, SortOrder *, int *, int);
+ void reset_sort_order(unsigned);
+! SortOrder translate(char *, int);
+
+ #endif /* PITH_SORT_INCLUDED */
+diff -rc alpine-2.00/pith/state.c alpine-2.00.I.USE/pith/state.c
+*** alpine-2.00/pith/state.c 2008-06-03 15:31:05.000000000 -0700
+--- alpine-2.00.I.USE/pith/state.c 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 32,38 ****
+ #include "../pith/remote.h"
+ #include "../pith/list.h"
+ #include "../pith/smime.h"
+!
+
+ /*
+ * Globals referenced throughout pine...
+--- 32,38 ----
+ #include "../pith/remote.h"
+ #include "../pith/list.h"
+ #include "../pith/smime.h"
+! #include "../pith/rules.h"
+
+ /*
+ * Globals referenced throughout pine...
+***************
+*** 73,78 ****
+--- 73,79 ----
+
+ p = (struct pine *)fs_get(sizeof (struct pine));
+ memset((void *) p, 0, sizeof(struct pine));
++ p->thread_def_sort = SortDate;
+ p->def_sort = SortArrival;
+ p->sort_types[0] = SortSubject;
+ p->sort_types[1] = SortArrival;
+***************
+*** 115,120 ****
+--- 116,124 ----
+ if(!(pps && (*pps)))
+ return;
+
++ if((*pps)->subject != NULL)
++ fs_give((void **)&(*pps)->subject);
++
+ if((*pps)->hostname != NULL)
+ fs_give((void **)&(*pps)->hostname);
+
+***************
+*** 130,135 ****
+--- 134,142 ----
+ if((*pps)->folders_dir != NULL)
+ fs_give((void **)&(*pps)->folders_dir);
+
++ if((*pps)->paterror == 0)
++ regfree(&(*pps)->colorpat);
++
+ if((*pps)->ui.homedir)
+ fs_give((void **)&(*pps)->ui.homedir);
+
+***************
+*** 182,187 ****
+--- 189,197 ----
+ if((*pps)->hdr_colors)
+ free_spec_colors(&(*pps)->hdr_colors);
+
++ if((*pps)->index_token_colors)
++ free_spec_colors(&(*pps)->index_token_colors);
++
+ if((*pps)->keywords)
+ free_keyword_list(&(*pps)->keywords);
+
+***************
+*** 202,207 ****
+--- 212,220 ----
+ if((*pps)->msgmap)
+ msgno_give(&(*pps)->msgmap);
+
++ if((*pps)->rule_list)
++ free_parsed_rule_list(&(*pps)->rule_list);
++
+ free_vars(*pps);
+
+ fs_give((void **) pps);
+diff -rc alpine-2.00/pith/state.h alpine-2.00.I.USE/pith/state.h
+*** alpine-2.00/pith/state.h 2008-06-03 08:54:15.000000000 -0700
+--- alpine-2.00.I.USE/pith/state.h 2011-02-07 20:33:47.000000000 -0800
+***************
+*** 32,38 ****
+ #include "../pith/stream.h"
+ #include "../pith/color.h"
+ #include "../pith/user.h"
+!
+
+ /*
+ * Printing control structure
+--- 32,38 ----
+ #include "../pith/stream.h"
+ #include "../pith/color.h"
+ #include "../pith/user.h"
+! #include "../pith/rulestype.h"
+
+ /*
+ * Printing control structure
+***************
+*** 104,112 ****
+--- 104,118 ----
+ MAILSTREAM *mail_stream; /* ptr to current folder stream */
+ MSGNO_S *msgmap; /* ptr to current message map */
+
++ char screen_name[10]; /* name of current screen */
++ char *role; /* role used when composing */
++ char *procid; /* procedure id when needed */
++ int exiting;
++
+ unsigned read_predicted:1;
+
+ char cur_folder[MAXPATH+1];
++ QUOTALIST *quota;
+ char last_unambig_folder[MAXPATH+1];
+ char last_save_folder[MAXPATH+1];
+ CONTEXT_S *last_save_context;
+***************
+*** 122,127 ****
+--- 128,134 ----
+ unsigned mangled_header:1; /* header needs repainting */
+ unsigned mangled_body:1; /* body of screen needs repainting */
+ unsigned mangled_screen:1; /* whole screen needs repainting */
++ unsigned resize_for_pico:1; /* screen needs repainting due to resizing */
+
+ unsigned in_init_seq:1; /* executing initial cmd list */
+ unsigned save_in_init_seq:1;
+***************
+*** 135,140 ****
+--- 142,149 ----
+ unsigned unseen_in_view:1;
+ unsigned start_in_context:1; /* start fldr_scrn in current cntxt */
+ unsigned def_sort_rev:1; /* true if reverse sort is default */
++ unsigned thread_def_sort_rev:1; /* true if reverse sort is default in thread screen */
++ unsigned msgmap_thread_def_sort_rev:1; /* true if reverse sort is being used in thread screen */
+ unsigned restricted:1;
+
+ unsigned save_msg_rule:5;
+***************
+*** 168,173 ****
+--- 177,183 ----
+ unsigned intr_pending:1; /* received SIGINT and haven't acted */
+ unsigned expunge_in_progress:1; /* don't want to re-enter c-client */
+ unsigned never_allow_changing_from:1; /* not even for roles */
++ unsigned newthread:1; /* start a new thread on composing */
+
+ unsigned readonly_pinerc:1;
+ unsigned view_all_except:1;
+***************
+*** 239,249 ****
+--- 249,272 ----
+ char **feat_list_back_compat;
+
+ SPEC_COLOR_S *hdr_colors; /* list of configed colors for view */
++ SPEC_COLOR_S *index_token_colors; /* list of configed colors for index */
+
++ char *prefix; /* prefix for fillpara */
+ short init_context;
+
++ struct {
++ ACTION_S *role_chosen;
++ int attach;
++ int strip;
++ int no_send_flowed;
++ int inchdr;
++ } reply;
++
+ int *initial_cmds; /* cmds to execute on startup */
+ int *free_initial_cmds; /* used to free when done */
++ int *initial_cmds_backup; /* keep a copy in case they are freed */
++ int *free_initial_cmds_backup; /* free the copy */
++ int initial_cmds_offset; /* how many commands we have executed */
+
+ char c_client_error[300]; /* when nowhow_error is set and PARSE */
+
+***************
+*** 281,288 ****
+--- 304,316 ----
+ EditWhich ew_for_srch_take;
+
+ SortOrder def_sort, /* Default sort type */
++ thread_def_sort, /* Default Sort Type in Thread Screen */
++ thread_cur_sort, /* current sort style for threads */
++ msgmap_thread_sort,
+ sort_types[22];
+
++ int preserve;
++
+ int last_expire_year, last_expire_month;
+
+ int printer_category;
+***************
+*** 295,300 ****
+--- 323,332 ----
+
+ int nmw_width;
+
++ char *subject;
++ int send_immediately;
++ int failed_read;
++
+ int hours_to_timeout;
+
+ int tcp_query_timeout;
+***************
+*** 317,322 ****
+--- 349,356 ----
+ char *display_charmap; /* needs to be freed */
+ char *keyboard_charmap; /* needs to be freed */
+ void *input_cs;
++ regex_t colorpat;
++ int paterror;
+
+ char *posting_charmap; /* needs to be freed */
+
+***************
+*** 328,333 ****
+--- 362,368 ----
+ struct {
+ char *(*display_filter)(char *, STORE_S *, gf_io_t, FILTLIST_S *);
+ char *(*display_filter_trigger)(BODY *, char *, size_t);
++ char *(*exec_rule)(char *, gf_io_t, gf_io_t);
+ } tools;
+
+ KEYWORD_S *keywords;
+***************
+*** 338,343 ****
+--- 373,381 ----
+ char last_error[500];
+ INIT_ERR_S *init_errs;
+
++ PRULELIST_S *rule_list;
++ char *pressed_key;
++
+ PRINT_S *print;
+
+ #ifdef SMIME
+diff -rc alpine-2.00/pith/store.c alpine-2.00.I.USE/pith/store.c
+*** alpine-2.00/pith/store.c 2008-06-03 12:27:23.000000000 -0700
+--- alpine-2.00.I.USE/pith/store.c 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 170,175 ****
+--- 170,183 ----
+ if(source == TmpFileStar)
+ our_unlink(so->name);
+
++ if (ps_global->send_immediately){
++ ps_global->failed_read++;
++ if(ps_global->failed_read == 5){
++ printf("No configurationf file found. Where is your .pinerc file?\n");
++ exit(1);
++ }
++ }
++
+ fs_give((void **)&so->name);
+ fs_give((void **)&so); /* so freed & set to NULL */
+ }
+diff -rc alpine-2.00/pith/stream.c alpine-2.00.I.USE/pith/stream.c
+*** alpine-2.00/pith/stream.c 2008-03-25 11:57:53.000000000 -0700
+--- alpine-2.00.I.USE/pith/stream.c 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 3318,3323 ****
+--- 3318,3342 ----
+ }
+
+
++ /* Some stream is locked checks to see if there is any stream for which we
++ * are in a callback from c-client
++ */
++
++ int
++ some_stream_is_locked(void)
++ {
++ int rv = 0, i;
++ MAILSTREAM *m;
++
++ for(i = 0; rv == 0 && i < ps_global->s_pool.nstream; i++){
++ m = ps_global->s_pool.streams[i];
++ if(m && m->lock)
++ rv++;
++ }
++
++ return(rv);
++ }
++
+ /*
+ * Very simple version of appenduid_cb until we need something
+ * more complex.
+diff -rc alpine-2.00/pith/stream.h alpine-2.00.I.USE/pith/stream.h
+*** alpine-2.00/pith/stream.h 2007-06-15 16:23:02.000000000 -0700
+--- alpine-2.00.I.USE/pith/stream.h 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 460,465 ****
+--- 460,466 ----
+ int is_imap_stream(MAILSTREAM *);
+ int modern_imap_stream(MAILSTREAM *);
+ int streams_died(void);
++ int some_stream_is_locked(void);
+ void appenduid_cb(char *mailbox,unsigned long uidvalidity, SEARCHSET *set);
+ imapuid_t get_last_append_uid(void);
+ MAILSTREAM *mail_cmd_stream(CONTEXT_S *, int *);
+diff -rc alpine-2.00/pith/string.c alpine-2.00.I.USE/pith/string.c
+*** alpine-2.00/pith/string.c 2008-01-09 12:45:31.000000000 -0800
+--- alpine-2.00.I.USE/pith/string.c 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 19,24 ****
+--- 19,25 ----
+ string.c
+ Misc extra and useful string functions
+ - rplstr replace a substring with another string
++ - collspaces consecutive spaces are reduced to one space.
+ - sqzspaces Squeeze out the extra blanks in a string
+ - sqznewlines Squeeze out \n and \r.
+ - removing_trailing_white_space
+***************
+*** 131,136 ****
+--- 132,162 ----
+ return(x3);
+ }
+
++ /*----------------------------------------------------------------------
++ collapse blank space
++ ----------------------------------------------------------------------*/
++ void
++ collspaces(char *string)
++ {
++ char *p = string;
++ int only_one_space = 0;
++
++ if(!string)
++ return;
++
++ for(;isspace(*p); p++);
++
++ while(*string = *p++)
++ if(!isspace((unsigned char)*string)){
++ only_one_space = 0;
++ string++;
++ }
++ else if(!only_one_space){
++ string++;
++ only_one_space++;
++ }
++ *string = '\0';
++ }
+
+
+ /*----------------------------------------------------------------------
+***************
+*** 2859,2861 ****
+--- 2885,2919 ----
+ fs_give((void **) strp);
+ }
+ }
++
++
++ void
++ removing_extra_stuff(string)
++ char *string;
++ {
++ char *p = NULL;
++ int change = 0, length = 0;
++
++
++ if(!string)
++ return;
++
++ for(; *string; string++, length++)
++ p = ((unsigned char)*string != ',') ? NULL : (!p) ? string : p;
++
++ if(p)
++ *p = '\0';
++
++ string -= length;
++ for (; *string; string++){
++ if (change){
++ *string = ' ';
++ change = 0;
++ }
++ if ((((unsigned char)*string == ' ') ||
++ ((unsigned char)*string == ',')) &&
++ ((unsigned char)*(string + 1) == ','))
++ change++;
++ }
++ }
++
+diff -rc alpine-2.00/pith/string.h alpine-2.00.I.USE/pith/string.h
+*** alpine-2.00/pith/string.h 2007-08-15 13:28:09.000000000 -0700
+--- alpine-2.00.I.USE/pith/string.h 2011-02-07 20:33:42.000000000 -0800
+***************
+*** 85,96 ****
+--- 85,98 ----
+
+ /* exported protoypes */
+ char *rplstr(char *, size_t, int, char *);
++ void collspaces(char *);
+ void sqzspaces(char *);
+ void sqznewlines(char *);
+ void removing_leading_white_space(char *);
+ void removing_trailing_white_space(char *);
+ void removing_leading_and_trailing_white_space(char *);
+ int removing_double_quotes(char *);
++ void removing_extra_stuff (char *);
+ char *skip_white_space(char *);
+ char *skip_to_white_space(char *);
+ char *removing_quotes(char *);
+diff -rc alpine-2.00/pith/text.c alpine-2.00.I.USE/pith/text.c
+*** alpine-2.00/pith/text.c 2008-03-18 10:24:31.000000000 -0700
+--- alpine-2.00.I.USE/pith/text.c 2011-02-07 20:33:43.000000000 -0800
+***************
+*** 91,97 ****
+ char *err, *charset;
+ int filtcnt = 0, error_found = 0, column, wrapit;
+ int is_in_sig = OUT_SIG_BLOCK;
+! int is_flowed_msg = 0;
+ int is_delsp_yes = 0;
+ int filt_only_c0 = 0;
+ char *parmval;
+--- 91,97 ----
+ char *err, *charset;
+ int filtcnt = 0, error_found = 0, column, wrapit;
+ int is_in_sig = OUT_SIG_BLOCK;
+! int is_flowed_msg = 0, add_me = 1, doraw = RAWSTRING;
+ int is_delsp_yes = 0;
+ int filt_only_c0 = 0;
+ char *parmval;
+***************
+*** 170,175 ****
+--- 170,184 ----
+ gf_url_hilite_opt(&uh,handlesp,0));
+ }
+
++ if((flags & FM_DISPLAY)
++ && !(flags & FM_NOCOLOR)
++ && pico_usingcolor()
++ && VAR_SPECIAL_TEXT_FORE_COLOR
++ && VAR_SPECIAL_TEXT_BACK_COLOR){
++ filters[filtcnt].filter = gf_line_test;
++ filters[filtcnt++].data = gf_line_test_opt(color_this_text, NULL);
++ }
++
+ /*
+ * First, paint the signature.
+ * Disclaimers noted below for coloring quotes apply here as well.
+***************
+*** 179,185 ****
+ && pico_usingcolor()
+ && VAR_SIGNATURE_FORE_COLOR
+ && VAR_SIGNATURE_BACK_COLOR){
+! filters[filtcnt].filter = gf_line_test;
+ filters[filtcnt++].data = gf_line_test_opt(color_signature,
+ &is_in_sig);
+ }
+--- 188,194 ----
+ && pico_usingcolor()
+ && VAR_SIGNATURE_FORE_COLOR
+ && VAR_SIGNATURE_BACK_COLOR){
+! filters[filtcnt].filter = gf_quote_test;
+ filters[filtcnt++].data = gf_line_test_opt(color_signature,
+ &is_in_sig);
+ }
+***************
+*** 197,205 ****
+ && pico_usingcolor()
+ && VAR_QUOTE1_FORE_COLOR
+ && VAR_QUOTE1_BACK_COLOR){
+! filters[filtcnt].filter = gf_line_test;
+! filters[filtcnt++].data = gf_line_test_opt(color_a_quote,
+! &is_flowed_msg);
+ }
+ }
+ else if(!strucmp(att->body->subtype, "richtext")){
+--- 206,214 ----
+ && pico_usingcolor()
+ && VAR_QUOTE1_FORE_COLOR
+ && VAR_QUOTE1_BACK_COLOR){
+! add_me = 0;
+! filters[filtcnt].filter = gf_quote_test;
+! filters[filtcnt++].data = gf_line_test_opt(color_a_quote, &is_flowed_msg);
+ }
+ }
+ else if(!strucmp(att->body->subtype, "richtext")){
+***************
+*** 280,285 ****
+--- 289,299 ----
+ }
+ }
+
++ if (add_me){
++ filters[filtcnt].filter = gf_quote_test;
++ filters[filtcnt++].data = gf_line_test_opt(select_quote, &doraw);
++ }
++
+ /*
+ * If the message is not flowed, we do the quote suppression before
+ * the wrapping, because the wrapping does not preserve the quote
+***************
+*** 304,310 ****
+ dq.handlesp = handlesp;
+ dq.do_color = (!(flags & FM_NOCOLOR) && pico_usingcolor());
+
+! filters[filtcnt].filter = gf_line_test;
+ filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq);
+ }
+ if(ps_global->VAR_QUOTE_REPLACE_STRING
+--- 318,324 ----
+ dq.handlesp = handlesp;
+ dq.do_color = (!(flags & FM_NOCOLOR) && pico_usingcolor());
+
+! filters[filtcnt].filter = gf_quote_test;
+ filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq);
+ }
+ if(ps_global->VAR_QUOTE_REPLACE_STRING
+***************
+*** 363,369 ****
+ dq.handlesp = handlesp;
+ dq.do_color = (!(flags & FM_NOCOLOR) && pico_usingcolor());
+
+! filters[filtcnt].filter = gf_line_test;
+ filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq);
+ }
+
+--- 377,383 ----
+ dq.handlesp = handlesp;
+ dq.do_color = (!(flags & FM_NOCOLOR) && pico_usingcolor());
+
+! filters[filtcnt].filter = gf_quote_test;
+ filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq);
+ }
+
+***************
+*** 568,574 ****
+ {
+ DELQ_S *dq;
+ char *lp;
+! int i, lines, not_a_quote = 0;
+ size_t len;
+
+ dq = (DELQ_S *) local;
+--- 582,588 ----
+ {
+ DELQ_S *dq;
+ char *lp;
+! int i, lines, not_a_quote = 0, code;
+ size_t len;
+
+ dq = (DELQ_S *) local;
+***************
+*** 588,593 ****
+--- 602,609 ----
+ for(i = dq->indent_length; i > 0 && !not_a_quote && *lp; i--)
+ if(*lp++ != SPACE)
+ not_a_quote++;
++ while(isspace((unsigned char) *lp))
++ lp++;
+
+ /* skip over leading tags */
+ while(!not_a_quote
+***************
+*** 627,639 ****
+ }
+ }
+
+! /* skip over whitespace */
+! if(!dq->is_flowed)
+! while(isspace((unsigned char) *lp))
+! lp++;
+!
+! /* check first character to see if it is a quote */
+! if(!not_a_quote && *lp != '>')
+ not_a_quote++;
+
+ if(not_a_quote){
+--- 643,654 ----
+ }
+ }
+
+! len = lp - line;
+! if(strlen(tmp_20k_buf) > len)
+! strcpy(tmp_20k_buf, tmp_20k_buf+len);
+! code = (dq->is_flowed ? IS_FLOWED : NO_FLOWED) | DELETEQUO;
+! select_quote(linenum, lp, ins, &code);
+! if (!not_a_quote && !tmp_20k_buf[0])
+ not_a_quote++;
+
+ if(not_a_quote){
+diff -rc alpine-2.00/pith/thread.c alpine-2.00.I.USE/pith/thread.c
+*** alpine-2.00/pith/thread.c 2008-03-03 09:52:11.000000000 -0800
+--- alpine-2.00.I.USE/pith/thread.c 2011-02-07 20:33:41.000000000 -0800
+***************
+*** 29,40 ****
+ #include "../pith/mailcmd.h"
+ #include "../pith/ablookup.h"
+
+
+ /*
+ * Internal prototypes
+ */
+ long *sort_thread_flatten(THREADNODE *, MAILSTREAM *, long *,
+! char *, long, PINETHRD_S *, unsigned);
+ void make_thrdflags_consistent(MAILSTREAM *, MSGNO_S *, PINETHRD_S *, int);
+ THREADNODE *collapse_threadnode_tree(THREADNODE *);
+ THREADNODE *collapse_threadnode_tree_sorted(THREADNODE *);
+--- 29,41 ----
+ #include "../pith/mailcmd.h"
+ #include "../pith/ablookup.h"
+
++ static int erase_thread_info = 1;
+
+ /*
+ * Internal prototypes
+ */
+ long *sort_thread_flatten(THREADNODE *, MAILSTREAM *, long *,
+! char *, long, PINETHRD_S *, unsigned, int, long, long);
+ void make_thrdflags_consistent(MAILSTREAM *, MSGNO_S *, PINETHRD_S *, int);
+ THREADNODE *collapse_threadnode_tree(THREADNODE *);
+ THREADNODE *collapse_threadnode_tree_sorted(THREADNODE *);
+***************
+*** 94,113 ****
+ set_flags_for_thread(MAILSTREAM *stream, MSGNO_S *msgmap, int f, PINETHRD_S *thrd, int v)
+ {
+ PINETHRD_S *nthrd, *bthrd;
+
+ if(!(stream && thrd && msgmap))
+ return;
+
+ set_lflag(stream, msgmap, mn_raw2m(msgmap, thrd->rawno), f, v);
+
+! if(thrd->next){
+! nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ set_flags_for_thread(stream, msgmap, f, nthrd, v);
+ }
+
+! if(thrd->branch){
+! bthrd = fetch_thread(stream, thrd->branch);
+ if(bthrd)
+ set_flags_for_thread(stream, msgmap, f, bthrd, v);
+ }
+--- 95,116 ----
+ set_flags_for_thread(MAILSTREAM *stream, MSGNO_S *msgmap, int f, PINETHRD_S *thrd, int v)
+ {
+ PINETHRD_S *nthrd, *bthrd;
++ unsigned long next = 0L, branch = 0L;
+
+ if(!(stream && thrd && msgmap))
+ return;
+
+ set_lflag(stream, msgmap, mn_raw2m(msgmap, thrd->rawno), f, v);
+
+! if(next = get_next(stream,thrd)){
+! nthrd = fetch_thread(stream, next);
+ if(nthrd)
+ set_flags_for_thread(stream, msgmap, f, nthrd, v);
+ }
+
+!
+! if(branch = get_branch(stream, thrd)){
+! bthrd = fetch_thread(stream, branch);
+ if(bthrd)
+ set_flags_for_thread(stream, msgmap, f, bthrd, v);
+ }
+***************
+*** 121,127 ****
+ MESSAGECACHE *mc;
+ PINELT_S *peltp;
+
+! if(!(stream && stream->spare))
+ return;
+
+ ps_global->view_skipped_index = 0;
+--- 124,130 ----
+ MESSAGECACHE *mc;
+ PINELT_S *peltp;
+
+! if(!(stream && stream->spare) || !erase_thread_info)
+ return;
+
+ ps_global->view_skipped_index = 0;
+***************
+*** 154,160 ****
+ PINETHRD_S *thrd = NULL;
+ unsigned long msgno, rawno;
+ int un_view_thread = 0;
+! long raw_current;
+ char *dup_chk = NULL;
+
+
+--- 157,163 ----
+ PINETHRD_S *thrd = NULL;
+ unsigned long msgno, rawno;
+ int un_view_thread = 0;
+! long raw_current, branch;
+ char *dup_chk = NULL;
+
+
+***************
+*** 167,176 ****
+ * way. If the dummy node is at the top-level, then its children are
+ * promoted to the top-level as separate threads.
+ */
+! if(F_ON(F_THREAD_SORTS_BY_ARRIVAL, ps_global))
+! collapsed_tree = collapse_threadnode_tree_sorted(tree);
+! else
+! collapsed_tree = collapse_threadnode_tree(tree);
+
+ /* dup_chk is like sort with an origin of 1 */
+ dup_chk = (char *) fs_get((mn_get_nmsgs(g_sort.msgmap)+1) * sizeof(char));
+--- 170,180 ----
+ * way. If the dummy node is at the top-level, then its children are
+ * promoted to the top-level as separate threads.
+ */
+! collapsed_tree = F_ON(F_ENHANCED_THREAD, ps_global)
+! ? copy_tree(tree)
+! : (F_ON(F_THREAD_SORTS_BY_ARRIVAL, ps_global)
+! ? collapse_threadnode_tree_sorted(tree)
+! : collapse_threadnode_tree(tree));
+
+ /* dup_chk is like sort with an origin of 1 */
+ dup_chk = (char *) fs_get((mn_get_nmsgs(g_sort.msgmap)+1) * sizeof(char));
+***************
+*** 181,187 ****
+ (void) sort_thread_flatten(collapsed_tree, stream,
+ &g_sort.msgmap->sort[1],
+ dup_chk, mn_get_nmsgs(g_sort.msgmap),
+! NULL, THD_TOP);
+
+ /* reset the inverse array */
+ msgno_reset_isort(g_sort.msgmap);
+--- 185,191 ----
+ (void) sort_thread_flatten(collapsed_tree, stream,
+ &g_sort.msgmap->sort[1],
+ dup_chk, mn_get_nmsgs(g_sort.msgmap),
+! NULL, THD_TOP, 0, 1L, 0L);
+
+ /* reset the inverse array */
+ msgno_reset_isort(g_sort.msgmap);
+***************
+*** 339,350 ****
+ else{
+ thrd = fetch_head_thread(stream);
+ while(thrd){
+ /*
+ * The top-level threads aren't hidden by collapse.
+ */
+ msgno = mn_raw2m(g_sort.msgmap, thrd->rawno);
+! if(msgno)
+! set_lflag(stream, g_sort.msgmap, msgno, MN_CHID, 0);
+
+ if(thrd->next){
+ PINETHRD_S *nthrd;
+--- 343,356 ----
+ else{
+ thrd = fetch_head_thread(stream);
+ while(thrd){
++ unsigned long raw = thrd->rawno;
++ unsigned long top = top_thread(stream, raw);
+ /*
+ * The top-level threads aren't hidden by collapse.
+ */
+ msgno = mn_raw2m(g_sort.msgmap, thrd->rawno);
+! if(msgno && !get_lflag(stream, NULL,thrd->rawno, MN_COLL))
+! set_lflag(stream, g_sort.msgmap, msgno, MN_CHID, 0);
+
+ if(thrd->next){
+ PINETHRD_S *nthrd;
+***************
+*** 358,366 ****
+ MN_COLL));
+ }
+
+! if(thrd->nextthd)
+! thrd = fetch_thread(stream, thrd->nextthd);
+! else
+ thrd = NULL;
+ }
+ }
+--- 364,373 ----
+ MN_COLL));
+ }
+
+! while (thrd && top_thread(stream, thrd->rawno) == top
+! && thrd->nextthd)
+! thrd = fetch_thread(stream, thrd->nextthd);
+! if (!(thrd && thrd->nextthd))
+ thrd = NULL;
+ }
+ }
+***************
+*** 411,417 ****
+ int a_parent_is_collapsed)
+ {
+ PINETHRD_S *nthrd, *bthrd;
+! unsigned long msgno;
+
+ if(!thrd)
+ return;
+--- 418,424 ----
+ int a_parent_is_collapsed)
+ {
+ PINETHRD_S *nthrd, *bthrd;
+! unsigned long msgno, next, branch;
+
+ if(!thrd)
+ return;
+***************
+*** 429,436 ****
+ set_lflag(stream, msgmap, msgno, MN_CHID, 0);
+ }
+
+! if(thrd->next){
+! nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ make_thrdflags_consistent(stream, msgmap, nthrd,
+ a_parent_is_collapsed
+--- 436,443 ----
+ set_lflag(stream, msgmap, msgno, MN_CHID, 0);
+ }
+
+! if(next = get_next(stream, thrd)){
+! nthrd = fetch_thread(stream, next);
+ if(nthrd)
+ make_thrdflags_consistent(stream, msgmap, nthrd,
+ a_parent_is_collapsed
+***************
+*** 439,446 ****
+ MN_COLL));
+ }
+
+! if(thrd->branch){
+! bthrd = fetch_thread(stream, thrd->branch);
+ if(bthrd)
+ make_thrdflags_consistent(stream, msgmap, bthrd,
+ a_parent_is_collapsed);
+--- 446,453 ----
+ MN_COLL));
+ }
+
+! if(branch = get_branch(stream, thrd)){
+! bthrd = fetch_thread(stream, branch);
+ if(bthrd)
+ make_thrdflags_consistent(stream, msgmap, bthrd,
+ a_parent_is_collapsed);
+***************
+*** 487,495 ****
+ long *
+ sort_thread_flatten(THREADNODE *node, MAILSTREAM *stream,
+ long *entry, char *dup_chk, long maxno,
+! PINETHRD_S *thrd, unsigned int flags)
+ {
+! PINETHRD_S *newthrd = NULL;
+
+ if(node){
+ if(node->num > 0L && node->num <= maxno){ /* holes happen */
+--- 494,503 ----
+ long *
+ sort_thread_flatten(THREADNODE *node, MAILSTREAM *stream,
+ long *entry, char *dup_chk, long maxno,
+! PINETHRD_S *thrd, unsigned int flags,
+! int adopted, long top, long threadno)
+ {
+! PINETHRD_S *newthrd = NULL, *save_thread = NULL;
+
+ if(node){
+ if(node->num > 0L && node->num <= maxno){ /* holes happen */
+***************
+*** 497,502 ****
+--- 505,513 ----
+ *entry = node->num;
+ dup_chk[node->num] = 1;
+
++ if(adopted == 2)
++ top = node->num;
++
+ /*
+ * Build a richer threading structure that will help us paint
+ * and operate on threads and subthreads.
+***************
+*** 505,524 ****
+ if(newthrd){
+ entry++;
+
+ if(node->next)
+ entry = sort_thread_flatten(node->next, stream,
+ entry, dup_chk, maxno,
+! newthrd, THD_NEXT);
+
+ if(node->branch)
+ entry = sort_thread_flatten(node->branch, stream,
+ entry, dup_chk, maxno,
+ newthrd,
+! (flags == THD_TOP) ? THD_TOP
+! : THD_BRANCH);
+ }
+ }
+ }
+ }
+
+ return(entry);
+--- 516,566 ----
+ if(newthrd){
+ entry++;
+
++ if(adopted == 2)
++ threadno = newthrd->thrdno;
++ if(adopted){
++ newthrd->toploose = top;
++ newthrd->thrdno = threadno;
++ }
++ adopted = adopted ? 1 : 0;
+ if(node->next)
+ entry = sort_thread_flatten(node->next, stream,
+ entry, dup_chk, maxno,
+! newthrd, THD_NEXT, adopted, top, threadno);
+
+ if(node->branch)
+ entry = sort_thread_flatten(node->branch, stream,
+ entry, dup_chk, maxno,
+ newthrd,
+! ((flags == THD_TOP) ? THD_TOP
+! : THD_BRANCH),
+! adopted, top, threadno);
+ }
+ }
+ }
++ else{
++ adopted = 2;
++ if(node->next)
++ entry = sort_thread_flatten(node->next, stream, entry, dup_chk,
++ maxno, thrd, THD_TOP, adopted, top, threadno);
++ adopted = 0;
++ if(node->branch){
++ if(entry){
++ long *last_entry = entry;
++
++ do{
++ last_entry--;
++ save_thread = ((PINELT_S *)mail_elt(stream, *last_entry)->sparep)->pthrd;
++ } while (save_thread->parent != 0L);
++ entry = sort_thread_flatten(node->branch, stream, entry, dup_chk,
++ maxno, save_thread, (flags == THD_TOP ? THD_TOP : THD_BRANCH),
++ adopted, top, threadno);
++ }
++ else
++ entry = sort_thread_flatten(node->branch, stream, entry, dup_chk,
++ maxno, NULL, THD_TOP, adopted, top, threadno);
++ }
++ }
+ }
+
+ return(entry);
+***************
+*** 787,793 ****
+ */
+ void
+ collapse_or_expand(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap,
+! long unsigned int msgno)
+ {
+ int collapsed, adjust_current = 0;
+ PINETHRD_S *thrd = NULL, *nthrd;
+--- 829,835 ----
+ */
+ void
+ collapse_or_expand(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap,
+! long unsigned int msgno, int display)
+ {
+ int collapsed, adjust_current = 0;
+ PINETHRD_S *thrd = NULL, *nthrd;
+***************
+*** 840,846 ****
+ if(!thrd)
+ return;
+
+! collapsed = get_lflag(stream, NULL, thrd->rawno, MN_COLL) && thrd->next;
+
+ if(collapsed){
+ msgno = mn_raw2m(msgmap, thrd->rawno);
+--- 882,888 ----
+ if(!thrd)
+ return;
+
+! collapsed = this_thread_is_kolapsed(ps_global, stream, msgmap, thrd->rawno);
+
+ if(collapsed){
+ msgno = mn_raw2m(msgmap, thrd->rawno);
+***************
+*** 858,870 ****
+ msgno = mn_raw2m(msgmap, thrd->rawno);
+ if(msgno > 0L && msgno <= mn_get_total(msgmap)){
+ set_lflag(stream, msgmap, msgno, MN_COLL, 1);
+! if((nthrd = fetch_thread(stream, thrd->next)) != NULL)
+ set_thread_subtree(stream, nthrd, msgmap, 1, MN_CHID);
+
+ clear_index_cache_ent(stream, msgno, 0);
+ }
+ }
+! else
+ q_status_message(SM_ORDER, 0, 1,
+ _("No thread to collapse or expand on this line"));
+
+--- 900,912 ----
+ msgno = mn_raw2m(msgmap, thrd->rawno);
+ if(msgno > 0L && msgno <= mn_get_total(msgmap)){
+ set_lflag(stream, msgmap, msgno, MN_COLL, 1);
+! if((thrd->next) && ((nthrd = fetch_thread(stream, thrd->next)) != NULL))
+ set_thread_subtree(stream, nthrd, msgmap, 1, MN_CHID);
+
+ clear_index_cache_ent(stream, msgno, 0);
+ }
+ }
+! else if(display)
+ q_status_message(SM_ORDER, 0, 1,
+ _("No thread to collapse or expand on this line"));
+
+***************
+*** 951,968 ****
+ unsigned long count = 0;
+ PINETHRD_S *nthrd, *bthrd;
+ MESSAGECACHE *mc;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+ return count;
+
+! if(thrd->next){
+! nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ count += count_flags_in_thread(stream, nthrd, flags);
+ }
+
+! if(thrd->branch){
+! bthrd = fetch_thread(stream, thrd->branch);
+ if(bthrd)
+ count += count_flags_in_thread(stream, bthrd, flags);
+ }
+--- 993,1011 ----
+ unsigned long count = 0;
+ PINETHRD_S *nthrd, *bthrd;
+ MESSAGECACHE *mc;
++ unsigned long next = 0L, branch = 0L;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+ return count;
+
+! if(next = get_next(stream, thrd)){
+! nthrd = fetch_thread(stream, next);
+ if(nthrd)
+ count += count_flags_in_thread(stream, nthrd, flags);
+ }
+
+! if(branch = get_branch(stream, thrd)){
+! bthrd = fetch_thread(stream, branch);
+ if(bthrd)
+ count += count_flags_in_thread(stream, bthrd, flags);
+ }
+***************
+*** 1050,1069 ****
+ mark_msgs_in_thread(MAILSTREAM *stream, PINETHRD_S *thrd, MSGNO_S *msgmap)
+ {
+ int count = 0;
+ PINETHRD_S *nthrd, *bthrd;
+ MESSAGECACHE *mc;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+ return count;
+
+! if(thrd->next){
+! nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ count += mark_msgs_in_thread(stream, nthrd, msgmap);
+ }
+
+! if(thrd->branch){
+! bthrd = fetch_thread(stream, thrd->branch);
+ if(bthrd)
+ count += mark_msgs_in_thread(stream, bthrd, msgmap);
+ }
+--- 1093,1113 ----
+ mark_msgs_in_thread(MAILSTREAM *stream, PINETHRD_S *thrd, MSGNO_S *msgmap)
+ {
+ int count = 0;
++ long next, branch;
+ PINETHRD_S *nthrd, *bthrd;
+ MESSAGECACHE *mc;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+ return count;
+
+! if(next = get_next(stream, thrd)){
+! nthrd = fetch_thread(stream, next);
+ if(nthrd)
+ count += mark_msgs_in_thread(stream, nthrd, msgmap);
+ }
+
+! if(branch = get_branch(stream, thrd)){
+! bthrd = fetch_thread(stream, branch);
+ if(bthrd)
+ count += mark_msgs_in_thread(stream, bthrd, msgmap);
+ }
+***************
+*** 1097,1103 ****
+ /* flags to set or clear */
+ /* set or clear? */
+ {
+! unsigned long msgno;
+ PINETHRD_S *nthrd, *bthrd;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+--- 1141,1147 ----
+ /* flags to set or clear */
+ /* set or clear? */
+ {
+! unsigned long msgno, next, branch;
+ PINETHRD_S *nthrd, *bthrd;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+***************
+*** 1121,1134 ****
+ if(msgno > 0L && flags == MN_CHID2 && v == 1)
+ clear_index_cache_ent(stream, msgno, 0);
+
+! if(thrd->next){
+! nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ set_thread_lflags(stream, nthrd, msgmap, flags, v);
+ }
+
+! if(thrd->branch){
+! bthrd = fetch_thread(stream, thrd->branch);
+ if(bthrd)
+ set_thread_lflags(stream, bthrd, msgmap, flags, v);
+ }
+--- 1165,1178 ----
+ if(msgno > 0L && flags == MN_CHID2 && v == 1)
+ clear_index_cache_ent(stream, msgno, 0);
+
+! if(next = get_next(stream, thrd)){
+! nthrd = fetch_thread(stream, next);
+ if(nthrd)
+ set_thread_lflags(stream, nthrd, msgmap, flags, v);
+ }
+
+! if(branch = get_branch(stream,thrd)){
+! bthrd = fetch_thread(stream, branch);
+ if(bthrd)
+ set_thread_lflags(stream, bthrd, msgmap, flags, v);
+ }
+***************
+*** 1217,1235 ****
+ char to_us = ' ';
+ char branch_to_us = ' ';
+ PINETHRD_S *nthrd, *bthrd;
+ MESSAGECACHE *mc;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+ return to_us;
+
+! if(thrd->next){
+! nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ to_us = to_us_symbol_for_thread(stream, nthrd, consider_flagged);
+ }
+
+ if(((consider_flagged && to_us != '*') || (!consider_flagged && to_us != '+'))
+! && thrd->branch){
+ bthrd = fetch_thread(stream, thrd->branch);
+ if(bthrd)
+ branch_to_us = to_us_symbol_for_thread(stream, bthrd, consider_flagged);
+--- 1261,1280 ----
+ char to_us = ' ';
+ char branch_to_us = ' ';
+ PINETHRD_S *nthrd, *bthrd;
++ unsigned long next = 0L, branch = 0L;
+ MESSAGECACHE *mc;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+ return to_us;
+
+! if(next = get_next(stream,thrd)){
+! nthrd = fetch_thread(stream, next);
+ if(nthrd)
+ to_us = to_us_symbol_for_thread(stream, nthrd, consider_flagged);
+ }
+
+ if(((consider_flagged && to_us != '*') || (!consider_flagged && to_us != '+'))
+! && (branch = get_branch(stream, thrd))){
+ bthrd = fetch_thread(stream, thrd->branch);
+ if(bthrd)
+ branch_to_us = to_us_symbol_for_thread(stream, bthrd, consider_flagged);
+***************
+*** 1279,1285 ****
+ break;
+ }
+
+! if(to_us != '+' && resent_to_us(&idata))
+ to_us = '+';
+
+ if(to_us == ' ' && F_ON(F_MARK_FOR_CC,ps_global))
+--- 1324,1330 ----
+ break;
+ }
+
+! if(to_us != '+' && !idata.bogus && resent_to_us(&idata))
+ to_us = '+';
+
+ if(to_us == ' ' && F_ON(F_MARK_FOR_CC,ps_global))
+***************
+*** 1327,1333 ****
+
+ set_lflag(stream, msgmap, msgno, flags, v);
+
+! if(thrd->next && (hiding || !get_lflag(stream,NULL,thrd->rawno,MN_COLL))){
+ nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ set_thread_subtree(stream, nthrd, msgmap, v, flags);
+--- 1372,1379 ----
+
+ set_lflag(stream, msgmap, msgno, flags, v);
+
+! if(thrd->next
+! && (hiding || !get_lflag(stream,NULL,thrd->rawno,MN_COLL))){
+ nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ set_thread_subtree(stream, nthrd, msgmap, v, flags);
+***************
+*** 1367,1374 ****
+ if(rawno)
+ thrd = fetch_thread(stream, rawno);
+
+! if(thrd && thrd->top && thrd->top != thrd->rawno)
+! thrd = fetch_thread(stream, thrd->top);
+
+ if(!thrd)
+ return 0;
+--- 1413,1420 ----
+ if(rawno)
+ thrd = fetch_thread(stream, rawno);
+
+! if(thrd && thrd->top && top_thread(stream,thrd->top) != thrd->rawno)
+! thrd = fetch_thread(stream, top_thread(stream,thrd->top));
+
+ if(!thrd)
+ return 0;
+***************
+*** 1432,1438 ****
+ thrd = fetch_thread(stream, rawno);
+
+ if(thrd && thrd->top)
+! topthrd = fetch_thread(stream, thrd->top);
+
+ if(!topthrd)
+ return 0;
+--- 1478,1484 ----
+ thrd = fetch_thread(stream, rawno);
+
+ if(thrd && thrd->top)
+! topthrd = fetch_thread(stream, top_thread(stream,thrd->top));
+
+ if(!topthrd)
+ return 0;
+***************
+*** 1538,1543 ****
+--- 1584,1590 ----
+ set_search_bit_for_thread(MAILSTREAM *stream, PINETHRD_S *thrd, SEARCHSET **msgset)
+ {
+ PINETHRD_S *nthrd, *bthrd;
++ unsigned long next, branch;
+
+ if(!(stream && thrd))
+ return;
+***************
+*** 1546,1560 ****
+ && (!(msgset && *msgset) || in_searchset(*msgset, thrd->rawno)))
+ mm_searched(stream, thrd->rawno);
+
+! if(thrd->next){
+! nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ set_search_bit_for_thread(stream, nthrd, msgset);
+ }
+
+! if(thrd->branch){
+! bthrd = fetch_thread(stream, thrd->branch);
+ if(bthrd)
+ set_search_bit_for_thread(stream, bthrd, msgset);
+ }
+ }
+--- 1593,2185 ----
+ && (!(msgset && *msgset) || in_searchset(*msgset, thrd->rawno)))
+ mm_searched(stream, thrd->rawno);
+
+! if(next= get_next(stream, thrd)){
+! nthrd = fetch_thread(stream, next);
+ if(nthrd)
+ set_search_bit_for_thread(stream, nthrd, msgset);
+ }
+
+! if(branch = get_branch(stream, thrd)){
+! bthrd = fetch_thread(stream, branch);
+ if(bthrd)
+ set_search_bit_for_thread(stream, bthrd, msgset);
+ }
+ }
++
++ /*
++ * Make a copy of c-client's THREAD tree
++ */
++ THREADNODE *
++ copy_tree(THREADNODE *tree)
++ {
++ THREADNODE *newtree = NULL;
++
++ if(tree){
++ newtree = mail_newthreadnode(NULL);
++ newtree->num = tree->num;
++ if(tree->next)
++ newtree->next = copy_tree(tree->next);
++
++ if(tree->branch)
++ newtree->branch = copy_tree(tree->branch);
++ }
++ return(newtree);
++ }
++
++ long
++ top_thread(MAILSTREAM *stream, long rawmsgno)
++ {
++ PINETHRD_S *thrd = NULL;
++ unsigned long rawno;
++
++ if(!stream)
++ return -1L;
++
++ if(rawmsgno)
++ thrd = fetch_thread(stream, rawmsgno);
++
++ if(!thrd)
++ return -1L;
++
++ return F_ON(F_ENHANCED_THREAD, ps_global)
++ ? (thrd->toploose ? thrd->toploose : thrd->top)
++ : thrd->top;
++ }
++
++ void
++ move_top_thread(MAILSTREAM *stream, MSGNO_S *msgmap, long rawmsgno)
++ {
++ mn_set_cur(msgmap,mn_raw2m(msgmap, top_thread(stream, rawmsgno)));
++ }
++
++ long
++ top_this_thread(MAILSTREAM *stream, long rawmsgno)
++ {
++ PINETHRD_S *thrd = NULL;
++ unsigned long rawno;
++
++ if(!stream)
++ return -1L;
++
++ if(rawmsgno)
++ thrd = fetch_thread(stream, rawmsgno);
++
++ if(!thrd)
++ return -1L;
++
++ return thrd->top;
++ }
++
++ void
++ move_top_this_thread(MAILSTREAM *stream, MSGNO_S *msgmap, long rawmsgno)
++ {
++ mn_set_cur(msgmap,mn_raw2m(msgmap, top_this_thread(stream, rawmsgno)));
++ }
++
++ int
++ thread_is_kolapsed(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, long rawmsgno)
++ {
++ int collapsed;
++ PINETHRD_S *thrd = NULL;
++ unsigned long rawno, orig, orig_rawno;
++
++ if(!stream)
++ return -1;
++
++ orig = mn_get_cur(msgmap);
++ move_top_thread(stream, msgmap, rawmsgno);
++ rawno = orig_rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ if(rawno)
++ thrd = fetch_thread(stream, rawno);
++
++ if(!thrd)
++ return -1;
++
++ while(collapsed = this_thread_is_kolapsed(state, stream, msgmap, rawno))
++ if (F_OFF(F_ENHANCED_THREAD, state)
++ || (move_next_this_thread(state, stream, msgmap, 0) <= 0)
++ || !(rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)))
++ || (orig_rawno != top_thread(stream, rawno)))
++ break;
++
++ mn_set_cur(msgmap,orig); /* return home */
++
++ return collapsed;
++ }
++
++ /* this function tells us if the thread (or branch in the case of loose threads)
++ * is collapsed
++ */
++
++ int
++ this_thread_is_kolapsed(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, long rawmsgno)
++ {
++ int collapsed;
++ PINETHRD_S *thrd = NULL;
++ unsigned long rawno, orig;
++
++ if(!stream)
++ return -1;
++
++ rawno = rawmsgno;
++ if(rawno)
++ thrd = fetch_thread(stream, rawno);
++
++ if(!thrd)
++ return -1;
++
++ collapsed = get_lflag(stream, NULL, rawno, MN_COLL | MN_CHID);
++
++ if (!thrd->next){
++ if (thrd->rawno != top_thread(stream, thrd->rawno))
++ collapsed = get_lflag(stream, NULL, rawno, MN_CHID);
++ else
++ collapsed = get_lflag(stream, NULL, rawno, MN_COLL);
++ }
++
++ return collapsed;
++ }
++
++ /*
++ * This function assumes that it is called at a top of a thread in its
++ * first call
++ */
++
++ int
++ count_this_thread(MAILSTREAM *stream, unsigned long rawno)
++ {
++ unsigned long top, orig_top, topnxt;
++ PINETHRD_S *thrd = NULL;
++ int count = 1;
++
++ if(!stream)
++ return 0;
++
++ if(rawno)
++ thrd = fetch_thread(stream, rawno);
++
++ if(!thrd)
++ return 0;
++
++ if (thrd->next)
++ count += count_this_thread(stream, thrd->next);
++
++ if (thrd->branch)
++ count += count_this_thread(stream, thrd->branch);
++
++ return count;
++ }
++
++ int
++ count_thread(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, long rawno)
++ {
++ unsigned long top, orig, orig_top;
++ PINETHRD_S *thrd = NULL;
++ int done = 0, count = 0;
++
++ if(!stream)
++ return 0;
++
++ orig = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ move_top_thread(stream, msgmap,rawno);
++ top = orig_top = top_thread(stream, rawno);
++ if(top)
++ thrd = fetch_thread(stream, top);
++
++ if(!thrd)
++ return 0;
++
++ while (!done){
++ count += count_this_thread(stream, top);
++ 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));
++ return count;
++ }
++
++ unsigned long
++ get_branch(MAILSTREAM *stream, PINETHRD_S *thrd)
++ {
++ PINETHRD_S *nthrd = NULL;
++ unsigned long top;
++
++ if (thrd->toploose && thrd->nextthd)
++ nthrd = fetch_thread(stream, thrd->nextthd);
++ if (!nthrd)
++ return thrd->branch;
++ top = top_thread(stream, thrd->rawno);
++ return thrd->branch
++ ? thrd->branch
++ : (F_ON(F_ENHANCED_THREAD, ps_global)
++ ? (top == top_thread(stream, nthrd->rawno) ? thrd->nextthd : 0L)
++ : 0L);
++ }
++
++ unsigned long
++ get_next(MAILSTREAM *stream, PINETHRD_S *thrd)
++ {
++ return thrd->next;
++ }
++
++ long
++ get_length_branch(MAILSTREAM *stream, long rawno)
++ {
++ int branchp = 0, done = 0;
++ long top, count = 1L, raw;
++ PINETHRD_S *thrd, *pthrd = NULL, *nthrd;
++
++ thrd = fetch_thread(stream, rawno);
++
++ if (!thrd)
++ return -1L;
++
++ top = thrd->top;
++
++ if (thrd->parent)
++ pthrd = fetch_thread(stream, thrd->parent);
++
++ if (thrd->rawno == top)
++ branchp++;
++
++ if (!branchp && !pthrd){ /* what!!?? */
++ raw = top;
++ while (!done){
++ pthrd = fetch_thread(stream, raw);
++ if ((pthrd->next == rawno) || (pthrd->branch == rawno))
++ done++;
++ else{
++ if (pthrd->next)
++ raw = pthrd->next;
++ else if (pthrd->branch)
++ raw = pthrd->branch;
++ }
++ }
++ }
++
++ if (pthrd && pthrd->next == thrd->rawno && thrd->branch)
++ branchp++;
++
++ if (pthrd && pthrd->next && pthrd->next != thrd->rawno){
++ nthrd = fetch_thread(stream, pthrd->next);
++ while (nthrd && nthrd->branch && nthrd->branch != thrd->rawno)
++ nthrd = fetch_thread(stream, nthrd->branch);
++ if(nthrd && nthrd->branch && nthrd->branch == thrd->rawno)
++ branchp++;
++ }
++
++ if(branchp){
++ int entry = 0;
++ while(thrd && thrd->next){
++ entry = 1;
++ count++;
++ thrd = fetch_thread(stream, thrd->next);
++ if (thrd->branch)
++ break;
++ }
++ if (entry && thrd->branch)
++ count--;
++ }
++ return branchp ? (count ? count : 1L) : 0L;
++ }
++
++ void
++ find_msgmap(MAILSTREAM *stream, MSGNO_S *msgmap, int flags, SortOrder ordersort, unsigned is_rev)
++ {
++ int we_cancel;
++ long *old_arrival,*new_arrival;
++ long init_thread, end_thread, current;
++ long k = 1L, j, last_thread = 0L;
++ long i, tmsg, ntmsg, nthreads;
++ char sort_msg[MAX_SCREEN_COLS+1] = {'\0'};
++ PINETHRD_S *thrd, *tthrd, *nthrd;
++
++ erase_thread_info = 0;
++ current = mn_m2raw(msgmap, mn_get_cur(msgmap));
++
++ sort_folder(stream, msgmap, ordersort, 0, SRT_VRB, 0);
++
++ tmsg = mn_get_total(msgmap) + 1;
++
++ if (tmsg <= 1)
++ return;
++
++ old_arrival = (long *) fs_get(tmsg * sizeof(long));
++ memset(old_arrival, 0, tmsg*sizeof(long));
++ for (i= 1L;(i <= mn_get_total(msgmap)) && (old_arrival[i] = msgmap->sort[i]); i++);
++
++ /* now sort by thread */
++ sort_folder(stream, msgmap, SortThread, 0, SRT_VRB, 0);
++ ntmsg = mn_get_total(msgmap) + 1;
++
++ if (tmsg != ntmsg){ /* oh oh, something happened,we better try again */
++ fs_give((void **)&old_arrival);
++ find_msgmap(stream, msgmap, flags, ordersort, is_rev);
++ return;
++ }
++
++ /* reconstruct the msgmap */
++
++ new_arrival = (long *) fs_get(tmsg * sizeof(long));
++ memset(new_arrival, 0, tmsg*sizeof(long));
++ i = mn_get_total(msgmap);
++ while (new_arrival[1] == 0){ /* think of this as (tmsg > 0) */
++ int done = 0;
++ long n = mn_get_total(msgmap);
++
++ init_thread = top_thread(stream, old_arrival[i]);
++ thrd = fetch_thread(stream, init_thread);
++ while ((new_arrival[n] != 0) && !done){ /* compare raw numbers */
++ done = (new_arrival[n] == init_thread);
++ n--;
++ }
++ if (!done){
++ k = 1L;
++ mn_set_cur(msgmap, mn_raw2m(msgmap, init_thread));
++ if (move_next_thread(ps_global, stream, msgmap, 0) <= 0)
++ j = mn_get_total(msgmap) - mn_raw2m(msgmap, init_thread) + 1;
++ else
++ j = mn_get_cur(msgmap) - mn_raw2m(msgmap, init_thread);
++ end_thread = mn_raw2m(msgmap, init_thread) + j;
++ while (k <= j){
++ new_arrival[tmsg - k] = msgmap->sort[end_thread - k];
++ k++;
++ }
++ tmsg -= j;
++ }
++ i--;
++ }
++ relink_threads(stream, msgmap, new_arrival);
++ for (i = 1; (i <= mn_get_total(msgmap))
++ && (msgmap->sort[i] = new_arrival[i]); i++);
++ msgno_reset_isort(msgmap);
++
++ fs_give((void **)&new_arrival);
++ fs_give((void **)&old_arrival);
++
++
++ if(is_rev && (mn_get_total(msgmap) > 1L)){
++ long *rev_sort;
++ long i = 1L, l = mn_get_total(msgmap);
++
++ rev_sort = (long *) fs_get((mn_get_total(msgmap)+1L) * sizeof(long));
++ memset(rev_sort, 0, (mn_get_total(msgmap)+1L)*sizeof(long));
++ while (l > 0L){
++ if (top_thread(stream, msgmap->sort[l]) == msgmap->sort[l]){
++ long init_thread = msgmap->sort[l];
++ long j, k;
++
++ mn_set_cur(msgmap, mn_raw2m(msgmap, init_thread));
++ if (move_next_thread(ps_global, stream, msgmap, 0) <= 0)
++ j = mn_get_total(msgmap) - mn_raw2m(msgmap, init_thread) + 1;
++ else
++ j = mn_get_cur(msgmap) - mn_raw2m(msgmap, init_thread);
++ for (k = 0L; (k < j) && (rev_sort[i+k] = msgmap->sort[l+k]); k++);
++ i += j;
++ }
++ l--;
++ }
++ relink_threads(stream, msgmap, rev_sort);
++ for (i = 1L; i <= mn_get_total(msgmap); i++)
++ msgmap->sort[i] = rev_sort[i];
++ msgno_reset_isort(msgmap);
++ fs_give((void **)&rev_sort);
++ }
++ mn_reset_cur(msgmap, first_sorted_flagged(is_rev ? F_NONE : F_SRCHBACK,
++ stream, mn_raw2m(msgmap, current), FSF_SKIP_CHID));
++ msgmap->top = -1L;
++
++ sp_set_unsorted_newmail(ps_global->mail_stream, 0);
++
++ for(i = 1L; i <= ps_global->mail_stream->nmsgs; i++)
++ mail_elt(ps_global->mail_stream, i)->spare7 = 0;
++
++ mn_set_sort(msgmap, SortThread);
++ mn_set_revsort(msgmap, is_rev);
++ erase_thread_info = 1;
++ clear_index_cache(stream, 0);
++ }
++
++ void
++ move_thread(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, int direction)
++ {
++ long new_cursor, old_cursor = mn_get_cur(msgmap);
++ int rv;
++ PINETHRD_S *thrd;
++
++ rv = direction > 0 ? move_next_thread(state, stream, msgmap, 1):
++ move_prev_thread(state, stream, msgmap, 1);
++ if (rv > 0 && THRD_INDX_ENABLED()){
++ new_cursor = mn_get_cur(msgmap);
++ mn_set_cur(msgmap, old_cursor);
++ unview_thread(state, stream, msgmap);
++ thrd = fetch_thread(stream,mn_m2raw(msgmap, new_cursor));
++ mn_set_cur(msgmap, new_cursor);
++ view_thread(state, stream, msgmap, 1);
++ state->next_screen = SCREEN_FUN_NULL;
++ }
++ }
++
++ void
++ relink_threads(MAILSTREAM *stream, MSGNO_S *msgmap, long *new_arrival)
++ {
++ long last_thread = 0L;
++ long i = 0L, j = 1L, k;
++ PINETHRD_S *thrd, *nthrd;
++
++ while (j <= mn_get_total(msgmap)){
++ i++;
++ thrd = fetch_thread(stream, new_arrival[j]);
++ if (!thrd) /* sort failed!, better leave from here now!!! */
++ break;
++ thrd->prevthd = last_thread;
++ thrd->thrdno = i;
++ thrd->head = new_arrival[1];
++ last_thread = thrd->rawno;
++ mn_set_cur(msgmap, mn_raw2m(msgmap,thrd->top));
++ k = mn_get_cur(msgmap);
++ if (move_next_thread(ps_global, stream, msgmap, 0) <= 0)
++ j += mn_get_total(msgmap) + 1 - k;
++ else
++ j += mn_get_cur(msgmap) - k;
++ if (!thrd->toploose)
++ thrd->nextthd = (j <= mn_get_total(msgmap)) ? new_arrival[j] : 0L;
++ else{
++ int done = 0;
++ while(thrd->nextthd && !done){
++ thrd->thrdno = i;
++ thrd->head = new_arrival[1];
++ if (thrd->nextthd)
++ nthrd = fetch_thread(stream, thrd->nextthd);
++ else
++ done++;
++ if(top_thread(stream, thrd->rawno) == top_thread(stream, nthrd->rawno))
++ thrd = nthrd;
++ else
++ done++;
++ }
++ thrd->nextthd = (j <= mn_get_total(msgmap)) ? new_arrival[j] : 0L;
++ last_thread = thrd->rawno;
++ }
++ }
++ }
++
++ int
++ move_next_this_thread(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, int display)
++ {
++ PINETHRD_S *thrd = NULL, *thrdnxt;
++ unsigned long rawno, top;
++ int rv = 1;
++
++ if(!stream)
++ return -1;
++
++ rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ if(rawno)
++ thrd = fetch_thread(stream, rawno);
++
++ if(!thrd)
++ return -1;
++
++ top = top_thread(stream, rawno);
++
++ thrdnxt = (top == rawno) ? fetch_thread(stream, top) : thrd;
++ if (thrdnxt->nextthd)
++ mn_set_cur(msgmap,mn_raw2m(msgmap, thrdnxt->nextthd));
++ else{
++ rv = 0;
++ if (display)
++ q_status_message(SM_ORDER, 0, 1, "No more Threads to advance");
++ }
++ return rv;
++ }
++
++ int
++ move_next_thread(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 0;
++
++ 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 0;
++
++ while (rv > 0 && !done){
++ rv = move_next_this_thread(state, stream, msgmap, display);
++ if (F_OFF(F_ENHANCED_THREAD, state)
++ || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap)))
++ || (orig_top != top_thread(stream, top)))
++ done++;
++ }
++ if (display){
++ if (rv > 0 && SEP_THRDINDX())
++ q_status_message(SM_ORDER, 0, 2, "Viewing next thread");
++ if (!rv)
++ q_status_message(SM_ORDER, 0, 2, "No more threads to advance");
++ }
++ if(rv <= 0){
++ rv = 0;
++ mn_set_cur(msgmap, mn_raw2m(msgmap, orig));
++ }
++
++ return rv;
++ }
++
++ int
++ move_prev_thread(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, int display)
++ {
++ PINETHRD_S *thrd = NULL;
++ unsigned long rawno, top;
++ int rv = 1;
++
++ if(!stream)
++ return -1;
++
++ rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ if(rawno)
++ thrd = fetch_thread(stream, rawno);
++
++ if(!thrd)
++ return -1;
++
++ top = top_thread(stream, rawno);
++
++ if (top != rawno)
++ mn_set_cur(msgmap,mn_raw2m(msgmap, top));
++ else if (thrd->prevthd)
++ mn_set_cur(msgmap,mn_raw2m(msgmap, top_thread(stream,thrd->prevthd)));
++ else
++ rv = 0;
++ if (display){
++ if (rv && SEP_THRDINDX())
++ q_status_message(SM_ORDER, 0, 2, "Viewing previous thread");
++ if (!rv)
++ q_status_message(SM_ORDER, 0, 2, "No more threads to go back");
++ }
++
++ return rv;
++ }
++
++ /* add more keys to this list */
++ int
++ allowed_thread_key(SortOrder sort)
++ {
++ return sort == SortArrival
++ || sort == SortDate
++ || sort == SortScore
++ || sort == SortThread;
++ }
++
+diff -rc alpine-2.00/pith/thread.h alpine-2.00.I.USE/pith/thread.h
+*** alpine-2.00/pith/thread.h 2006-09-22 13:06:05.000000000 -0700
+--- alpine-2.00.I.USE/pith/thread.h 2011-02-07 20:33:41.000000000 -0800
+***************
+*** 37,42 ****
+--- 37,43 ----
+ unsigned long nextthd; /* next thread, only tops have this */
+ unsigned long prevthd; /* previous thread, only tops have this */
+ unsigned long top; /* top of this thread */
++ unsigned long toploose; /* top of this thread, if is loose */
+ unsigned long head; /* head of the whole thread list */
+ } PINETHRD_S;
+
+***************
+*** 92,98 ****
+ void sort_thread_callback(MAILSTREAM *, THREADNODE *);
+ void collapse_threads(MAILSTREAM *, MSGNO_S *, PINETHRD_S *);
+ PINETHRD_S *msgno_thread_info(MAILSTREAM *, unsigned long, PINETHRD_S *, unsigned);
+! void collapse_or_expand(struct pine *, MAILSTREAM *, MSGNO_S *, unsigned long);
+ void select_thread_stmp(struct pine *, MAILSTREAM *, MSGNO_S *);
+ unsigned long count_flags_in_thread(MAILSTREAM *, PINETHRD_S *, long);
+ unsigned long count_lflags_in_thread(MAILSTREAM *, PINETHRD_S *, MSGNO_S *, int);
+--- 93,99 ----
+ void sort_thread_callback(MAILSTREAM *, THREADNODE *);
+ void collapse_threads(MAILSTREAM *, MSGNO_S *, PINETHRD_S *);
+ PINETHRD_S *msgno_thread_info(MAILSTREAM *, unsigned long, PINETHRD_S *, unsigned);
+! void collapse_or_expand(struct pine *, MAILSTREAM *, MSGNO_S *, unsigned long, int);
+ void select_thread_stmp(struct pine *, MAILSTREAM *, MSGNO_S *);
+ unsigned long count_flags_in_thread(MAILSTREAM *, PINETHRD_S *, long);
+ unsigned long count_lflags_in_thread(MAILSTREAM *, PINETHRD_S *, MSGNO_S *, int);
+***************
+*** 106,111 ****
+ int unview_thread(struct pine *, MAILSTREAM *, MSGNO_S *);
+ PINETHRD_S *find_thread_by_number(MAILSTREAM *, MSGNO_S *, long, PINETHRD_S *);
+ void set_search_bit_for_thread(MAILSTREAM *, PINETHRD_S *, SEARCHSET **);
+!
+
+ #endif /* PITH_THREAD_INCLUDED */
+--- 107,130 ----
+ int unview_thread(struct pine *, MAILSTREAM *, MSGNO_S *);
+ PINETHRD_S *find_thread_by_number(MAILSTREAM *, MSGNO_S *, long, PINETHRD_S *);
+ void set_search_bit_for_thread(MAILSTREAM *, PINETHRD_S *, SEARCHSET **);
+! void find_msgmap(MAILSTREAM *, MSGNO_S *, int, SortOrder, unsigned);
+! void move_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int);
+! void relink_threads(MAILSTREAM *, MSGNO_S *, long *);
+! long top_thread(MAILSTREAM *, long);
+! long top_this_thread(MAILSTREAM *, long);
+! long get_length_branch(MAILSTREAM *, long);
+! unsigned long get_next(MAILSTREAM *,PINETHRD_S *);
+! unsigned long get_branch(MAILSTREAM *,PINETHRD_S *);
+! int count_thread(struct pine *, MAILSTREAM *, MSGNO_S *, long);
+! int count_this_thread(MAILSTREAM *, unsigned long);
+! int this_thread_is_kolapsed(struct pine *, MAILSTREAM *, MSGNO_S *, long);
+! int thread_is_kolapsed(struct pine *, MAILSTREAM *, MSGNO_S *, long);
+! int move_prev_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int);
+! int move_next_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int);
+! int move_next_this_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int);
+! void move_top_thread(MAILSTREAM *, MSGNO_S *, long);
+! void move_top_this_thread(MAILSTREAM *, MSGNO_S *, long);
+! THREADNODE *copy_tree(THREADNODE *);
+! int allowed_thread_key(SortOrder sort);
+
+ #endif /* PITH_THREAD_INCLUDED */
+diff -rc alpine-2.00/pith/url.c alpine-2.00.I.USE/pith/url.c
+*** alpine-2.00/pith/url.c 2007-08-29 15:31:51.000000000 -0700
+--- alpine-2.00.I.USE/pith/url.c 2011-02-07 20:33:45.000000000 -0800
+***************
+*** 52,58 ****
+ rfc1738_scan(char *line, int *len)
+ {
+ char *colon, *start, *end;
+! int n;
+
+ /* process each : in the line */
+ for(; (colon = strindex(line, ':')) != NULL; line = end){
+--- 52,58 ----
+ rfc1738_scan(char *line, int *len)
+ {
+ char *colon, *start, *end;
+! int n, delim;
+
+ /* process each : in the line */
+ for(; (colon = strindex(line, ':')) != NULL; line = end){
+***************
+*** 113,119 ****
+ && !struncmp(start + 1, "elnet", 5))))
+ || (n == 8
+ && (*start == 'P' || *start == 'p')
+! && !struncmp(start + 1, "rospero", 7)))
+ || url_external_specific_handler(start, n))){
+ /*
+ * Second, make sure that everything to the right of the
+--- 113,125 ----
+ && !struncmp(start + 1, "elnet", 5))))
+ || (n == 8
+ && (*start == 'P' || *start == 'p')
+! && !struncmp(start + 1, "rospero", 7))
+! || (n == 11
+! && (*start == 'x' || *start == 'X')
+! && !struncmp(start + 1, "-pine-help", 10))
+! || (n == 13
+! && (*start == 'x' || *start == 'X')
+! && !struncmp(start + 1, "-alpine-help", 12)))
+ || url_external_specific_handler(start, n))){
+ /*
+ * Second, make sure that everything to the right of the
+***************
+*** 130,135 ****
+--- 136,142 ----
+
+ if(i != j){
+ *len = end - start;
++ delim = start > line && *(start - 1) == '<';
+
+ /*
+ * Special case handling for comma.
+***************
+*** 139,146 ****
+ * In most cases any way, that's why we have the
+ * exception.
+ */
+! if(*(end - 1) == ','
+! || (*(end - 1) == '.' && (!*end || *end == ' ')))
+ (*len)--;
+
+ if(*len - (colon - start) > 0)
+--- 146,153 ----
+ * In most cases any way, that's why we have the
+ * exception.
+ */
+! if(delim == 0 && (*(end - 1) == ','
+! || (*(end - 1) == '.' && (!*end || *end == ' '))))
+ (*len)--;
+
+ if(*len - (colon - start) > 0)
+diff -rc alpine-2.00/README.maildir alpine-2.00.I.USE/README.maildir
+*** alpine-2.00/README.maildir 2011-02-07 20:34:02.000000000 -0800
+--- alpine-2.00.I.USE/README.maildir 2011-02-07 20:33:41.000000000 -0800
+***************
+*** 0 ****
+--- 1,153 ----
++ ---------------------------------------
++
++ Maildir Driver for Alpine 1.0
++ By Eduardo Chappa <chappa@washington.edu>
++ http://staff.washington.edu/chappa/alpine/
++
++ ---------------------------------------
++ 1. General Information About This Patch
++ ---------------------------------------
++
++ This patch adds support for the maildir format to Alpine. We take the
++ approach that this patch is one more driver among the number of formats
++ supported by Alpine (more generally c-client). This approach differs from
++ older versions of similar patches, in that once a maildir patch was
++ applied, it was assumed that all your folders would be created in the
++ maildir format.
++
++ This patch does not assume that maildir is a preferred format, instead
++ puts maildir in equal footing with other formats (mbox, mbx, mix, etc),
++ and so a maildir folder in the mail/ collection is treated in the same way
++ as any other folder in any other format. In other words, just by reading
++ the name of a folder, or opening it, or doing any operation with it, you
++ can not know in which format the folder is.
++
++ This implies that if you want to add a folder in the maildir format to the
++ mail/ collection, then you must add by pressing "A" in the folder list
++ collection and enter "#driver.md/mail/name_maildir_folder".
++
++ If you only want to use maildir, however, you can do so too. In this case,
++ you must create a maildir collection. In that collection, only maildir
++ folders will be listed. If there is any folder in any other format, that
++ folder will be ignored. In another words, any folder listed there is in
++ maildir format and can be accessed through that collection, conversely,
++ any folder not listed there is not in maildir format and there is no way
++ to access it using this collection.
++
++ In order to create a maildir collection, you could press M S L, and "A" to
++ add a collection. Fill in the required fields as follows:
++
++ Nickname : Anything
++ Server :
++ Path : #md/relative/path/to/maildir/collection/
++ View :
++
++ For example, if "path" is set to "#md/mail/", then Alpine will look for your
++ maildir folders that are in ~/mail/.
++
++ The code in this patch is mostly based in code for the unix driver plus
++ some combinations of the mh, mbx and nntp drivers for the c-client
++ library. Those drivers were designed by Mark Crispin, and bugs in this
++ code are not his bugs, but my own.
++
++ I got all the specification for this patch from
++ http://cr.yp.to/proto/maildir.html. If you know of a place with a better
++ specification for maildir format please let me know. The method this patch
++ uses to create a unique filename for a message is one of the "old
++ fashioned" methods. I realize that this is old fashioned, but it is
++ portable, and portability is the main reason why I decided to use an old
++ fashioned method (most methods are not portable. See the word
++ "Unfortunately" in that document).
++
++ --------------
++ 2. Other Goals
++ --------------
++
++ It is intended that this code will work well with any application
++ written using the c-client library. Of paramount importance is to make the
++ associated imap server work well when the server accesses a folder in
++ Maildir format. The program mailutil should also work flawlessly with this
++ implemetation of the driver.
++
++ It is intended that this driver be fast and stable. We intend not to
++ patch Alpine to make this driver do its work, unless such patching is for
++ fixing bugs in Alpine or to pass parameters to the driver.
++
++ ------------------------------------------------------------------------
++ 3. What are the known bugs of this implementation of the Maildir driver?
++ ------------------------------------------------------------------------
++
++ I don't know any at this time. There have been bugs before, though, but
++ I try to fix bugs as soon as they are reported. A complete list of updates
++ for this patch, which includes bug fixes, improvements and addition of new
++ features can be found at
++
++ http://staff.washington.edu/chappa/alpine/updates/maildir.html
++
++ ----------
++ 4. On UIDs
++ ----------
++
++ This patch keeps uids in the name of the file that contains the message,
++ by adding a ",u=" string to the file name to save the uid of a message. A
++ file is kept between sessions to save information on the last uid assigned
++ and its time of validity. Only one session with writing access can write
++ uids, all others must wait for the other session to assign them. The
++ session assigning uids creates a ".uidtemp" file which other sessions must
++ not disturb.
++
++ Uid support appeared in Alpine 1.00 (snapshot 925), and is experimental,
++ please report any problems.
++
++ --------------------------------------------
++ 5. Configuring Alpine and Setting up a Maildir
++ --------------------------------------------
++
++ Once this approach was chosen, it implied the following:
++
++ * This patch assumes that your INBOX is located at "$HOME/Maildir".
++ This is a directory which should have three subdirectories "cur",
++ "tmp" and "new". Mail is delivered to 'new' and read from 'cur'. I
++ have added a configuration option "maildir-location" which can be
++ used to tell Alpine where your Maildir inbox is, in case your system
++ do not use the above directory (e.g. your system may use
++ "~/.maildir"). In this case define that variable to be the name of
++ the directory where your e-mail is being delivered (e.g.
++ ".maildir").
++
++ * If you want to use the above configuration as your inbox, you must
++ define your inbox-path as "#md/inbox" (no quotes). You can define
++ the inbox-path like above even if you have changed the
++ maildir-location variable. That's the whole point of that variable.
++
++ -----------------------------------
++ 6. What about Courier file systems?
++ -----------------------------------
++
++ In a courier file system all folders are subfolders of a root folder
++ called INBOX. Normally INBOX is located at ~/Maildir and subfolders are
++ "dot" directories in ~/Maildir. For example ~/Maildir/.Trash is a
++ subfolder of INBOX and is accessed with the nickname "INBOX.Trash".
++
++ You can not access folders in this way unless you preceed them with the
++ string "#mc/". The purpose of the string "#mc/" is to warn Alpine that a
++ collection in the Courier format is going to be accessed, so you can
++ SELECT a folder like "#mc/INBOX.Trash", but not "INBOX.Trash"
++
++ You can access a collection through a server, but if you want to access a
++ collection of folders created using the Courier server, you MUST edit your
++ ".pinerc" file and enter the definition of the collection as follows:
++
++ folder-collections="Anything you want" #mc/INBOX.[]
++
++ You can replace the string "#mc/INBOX." by something different, for example
++ "#mc/Courier/." will make Alpine search for your collection in ~/Courier.
++
++ You can not add this directly into Alpine because Alpine fails to accept this
++ value from its input, but it takes it correctly when it is added through
++ the ".pinerc" file.
++
++ You can access your inbox as "#mc/INBOX" or "#md/INBOX". Both definitions
++ point to the same place.
++
++ Last Updated February 9, 2008
+diff -rc alpine-2.00/web/src/alpined.d/alpined.c alpine-2.00.I.USE/web/src/alpined.d/alpined.c
+*** alpine-2.00/web/src/alpined.d/alpined.c 2008-08-22 13:41:37.000000000 -0700
+--- alpine-2.00.I.USE/web/src/alpined.d/alpined.c 2011-02-07 20:33:43.000000000 -0800
+***************
+*** 2795,2801 ****
+ init_save_defaults();
+ break;
+ case V_SORT_KEY:
+! decode_sort(ps_global->VAR_SORT_KEY, &ps_global->def_sort, &def_sort_rev);
+ break;
+ case V_VIEW_HDR_COLORS :
+ set_custom_spec_colors(ps_global);
+--- 2795,2801 ----
+ init_save_defaults();
+ break;
+ case V_SORT_KEY:
+! decode_sort(ps_global->VAR_SORT_KEY, &ps_global->def_sort, &def_sort_rev, 0);
+ break;
+ case V_VIEW_HDR_COLORS :
+ set_custom_spec_colors(ps_global);
+***************
+*** 6271,6277 ****
+ && mn_get_revsort(sp_msgmap(ps_global->mail_stream)) == reversed))
+ sort_folder(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream),
+ ps_global->sort_types[i],
+! reversed, 0);
+
+ break;
+ }
+--- 6271,6277 ----
+ && mn_get_revsort(sp_msgmap(ps_global->mail_stream)) == reversed))
+ sort_folder(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream),
+ ps_global->sort_types[i],
+! reversed, 0, 1);
+
+ break;
+ }
+***************
+*** 6848,6854 ****
+ /* BUG: fix charset not to be NULL below */
+ if(agg_text_select(ps_global->mail_stream,
+ sp_msgmap(ps_global->mail_stream),
+! field, not, 0, text, NULL, NULL))
+ /* BUG: plug in "charset" above? */
+ return(peSelectError(interp, "programmer botch"));
+ }
+--- 6848,6854 ----
+ /* BUG: fix charset not to be NULL below */
+ if(agg_text_select(ps_global->mail_stream,
+ sp_msgmap(ps_global->mail_stream),
+! field, NULL, not, 0, text, NULL, NULL))
+ /* BUG: plug in "charset" above? */
+ return(peSelectError(interp, "programmer botch"));
+ }
+diff -rc alpine-2.00/web/src/alpined.d/Makefile.am alpine-2.00.I.USE/web/src/alpined.d/Makefile.am
+*** alpine-2.00/web/src/alpined.d/Makefile.am 2008-08-12 13:47:04.000000000 -0700
+--- alpine-2.00.I.USE/web/src/alpined.d/Makefile.am 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 50,52 ****
+--- 50,53 ----
+ debug.c status.c stubs.c alpined.h color.h ldap.h
+ echo "char datestamp[]="\"`date`\"";" > local.c
+ echo "char hoststamp[]="\"`hostname`\"";" >> local.c
++ cat ../../../patchlevel >> local.c
+diff -rc alpine-2.00/web/src/alpined.d/Makefile.in alpine-2.00.I.USE/web/src/alpined.d/Makefile.in
+*** alpine-2.00/web/src/alpined.d/Makefile.in 2008-08-13 08:44:42.000000000 -0700
+--- alpine-2.00.I.USE/web/src/alpined.d/Makefile.in 2011-02-07 20:33:46.000000000 -0800
+***************
+*** 619,624 ****
+--- 619,625 ----
+ debug.c status.c stubs.c alpined.h color.h ldap.h
+ echo "char datestamp[]="\"`date`\"";" > local.c
+ echo "char hoststamp[]="\"`hostname`\"";" >> local.c
++ cat ../../../patchlevel >> local.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.
+ .NOEXPORT: