diff --git a/UPDATING.txt b/UPDATING.txt index d207ad8..6dfe74e 100644 --- a/UPDATING.txt +++ b/UPDATING.txt @@ -4,8 +4,9 @@ Some features of Alpine do not exist in the release tarball but are only provided as patches (but by the same author..). So when there is a new release, the OOT patches on the website get updated too. + version="2.24" for i in WrtAcc colortext fancy fillpara fromheader insertpat maildir rules; do - wget -O- http://alpine.x10host.com/alpine/patches/alpine-2.22/$i.patch.gz | gzip -cd >chappa-$i.patch; + wget -O- "http://alpine.x10host.com/alpine/patches/alpine-$version/$i.patch.gz" | gzip -cd >"chappa-$i.patch"; done These do not necessarily apply cleanly, so they also need to be diff --git a/alpine-2.23.2.tar.xz b/alpine-2.23.2.tar.xz deleted file mode 100644 index fdeee28..0000000 --- a/alpine-2.23.2.tar.xz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:927e170473bb060ccb11a37e30d44bb10aaca50c4aafa974d5741ae593a95694 -size 5151416 diff --git a/alpine-2.24.tar.xz b/alpine-2.24.tar.xz new file mode 100644 index 0000000..dc32021 --- /dev/null +++ b/alpine-2.24.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:651a9ffa0a29e2b646a0a6e0d5a2c8c50f27a07a26a61640b7c783d06d0abcef +size 7341676 diff --git a/alpine-2.24.tar.xz.sig b/alpine-2.24.tar.xz.sig new file mode 100644 index 0000000..7e5b03b Binary files /dev/null and b/alpine-2.24.tar.xz.sig differ diff --git a/alpine-timestamp.patch b/alpine-timestamp.patch index 1f58744..848324d 100644 --- a/alpine-timestamp.patch +++ b/alpine-timestamp.patch @@ -2,11 +2,11 @@ alpine/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) -Index: alpine-2.22/alpine/Makefile.am +Index: alpine-2.24/alpine/Makefile.am =================================================================== ---- alpine-2.22.orig/alpine/Makefile.am -+++ alpine-2.22/alpine/Makefile.am -@@ -50,5 +50,5 @@ AM_LDFLAGS = `cat @top_srcdir@/c-client/ +--- alpine-2.24.orig/alpine/Makefile.am ++++ alpine-2.24/alpine/Makefile.am +@@ -50,6 +50,6 @@ AM_LDFLAGS = `cat @top_srcdir@/c-client/ CLEANFILES = date.c date.c: @@ -14,3 +14,4 @@ Index: alpine-2.22/alpine/Makefile.am - echo "char hoststamp[]="\"$(ALPINE_HOSTSTAMP)\"";" >> date.c + echo "char datestamp[]="\"today\"";" > date.c + echo "char hoststamp[]="\"sand\"";" >> date.c + echo "char configoptions[]="\"`../config.status --config`\"";" >> date.c diff --git a/alpine.changes b/alpine.changes index 1c12f20..baac758 100644 --- a/alpine.changes +++ b/alpine.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Fri Jan 15 12:04:04 UTC 2021 - Jan Engelhardt + +- Update to release 2.24 + * A few crash fixes + * Implementation of XOAUTH2 for Yahoo! Mail. + ------------------------------------------------------------------- Fri Oct 2 20:43:57 UTC 2020 - Jan Engelhardt @@ -8,6 +15,10 @@ Fri Oct 2 20:43:57 UTC 2020 - Jan Engelhardt to generate a message-id and suppresses all information about Alpine, version, revision, and time of generation of the message-id from this header. + * Alpine does not generate Sender or X-X-Sender by default by + enabling [X] Disable Sender as the default. + * Alpine does not disclose User Agent by default by enabling + [X] Suppress User Agent by default. * When messages are selected, pressing the ';' command to broaden or narrow a search, now offers the possibility to completely replace the search, and is almost equivalent to diff --git a/alpine.spec b/alpine.spec index 1aad30e..7c83be2 100644 --- a/alpine.spec +++ b/alpine.spec @@ -1,7 +1,7 @@ # # spec file for package alpine # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,7 +19,7 @@ Name: alpine # For debugging only: %define build_vanilla 0 -Version: 2.23.2 +Version: 2.24 Release: 0 Summary: Mail User Agent License: Apache-2.0 @@ -27,10 +27,10 @@ Group: Productivity/Networking/Email/Clients URL: http://alpine.x10host.com/alpine/ #Git-Clone: https://repo.or.cz/alpine.git -#Source: http://alpine.x10host.com/alpine/release/src/%name-%version.tar.xz -Source: %name-%version.tar.xz -Source1: %name.png -Source2: %name.desktop +Source: http://alpine.x10host.com/alpine/release/src/alpine-%version.tar.xz +Source2: http://alpine.x10host.com/alpine/release/src/sig/alpine-%version.tar.xz.sig +Source3: %name.png +Source4: %name.desktop Source9: UPDATING.txt Patch2: make-use-of-strncat-safer.diff Patch3: operation-may-be-undefined-warning.diff @@ -208,8 +208,8 @@ perl -i -pe 's{(define SYSTYPE) "LNX"}{$1 "'"$tag"'"}g' include/config.h # When called as alpinef, alpine uses function keys instead of Control keys: # ln %{buildroot}/%{_bindir}/alpine %{buildroot}/%{_bindir}/alpinef -install -D -m644 %{SOURCE1} %{buildroot}/%{_datadir}/pixmaps/%name.png -install -D -m644 %{SOURCE2} %{buildroot}/%{_datadir}/applications/%name.desktop +install -D -m644 %{SOURCE3} %{buildroot}/%{_datadir}/pixmaps/%name.png +install -D -m644 %{SOURCE4} %{buildroot}/%{_datadir}/applications/%name.desktop %suse_update_desktop_file %name : ln -sf alpine %{buildroot}/%{_bindir}/pine diff --git a/chappa-WrtAcc.patch b/chappa-WrtAcc.patch index 52270e6..196d404 100644 --- a/chappa-WrtAcc.patch +++ b/chappa-WrtAcc.patch @@ -1,6 +1,6 @@ -diff -rc alpine-2.23/pico/basic.c alpine-2.23.WrtAcc/pico/basic.c -*** alpine-2.23/pico/basic.c 2020-06-18 15:19:23.437319046 -0600 ---- alpine-2.23.WrtAcc/pico/basic.c 2020-06-18 16:08:12.541589518 -0600 +diff -rc alpine-2.24/pico/basic.c alpine-2.24.WrtAcc/pico/basic.c +*** alpine-2.24/pico/basic.c 2020-10-10 00:24:28.180553991 -0600 +--- alpine-2.24.WrtAcc/pico/basic.c 2020-10-10 00:26:57.220352202 -0600 *************** *** 342,347 **** --- 342,530 ---- @@ -193,9 +193,9 @@ diff -rc alpine-2.23/pico/basic.c alpine-2.23.WrtAcc/pico/basic.c /* * go forword to the end of the current paragraph -diff -rc alpine-2.23/pico/composer.c alpine-2.23.WrtAcc/pico/composer.c -*** alpine-2.23/pico/composer.c 2020-06-18 15:19:23.437319046 -0600 ---- alpine-2.23.WrtAcc/pico/composer.c 2020-06-18 16:08:12.545589528 -0600 +diff -rc alpine-2.24/pico/composer.c alpine-2.24.WrtAcc/pico/composer.c +*** alpine-2.24/pico/composer.c 2020-10-10 00:24:28.180553991 -0600 +--- alpine-2.24.WrtAcc/pico/composer.c 2020-10-10 00:26:57.220352202 -0600 *************** *** 2015,2021 **** tbufp = &strng[ods.p_len]; @@ -229,9 +229,9 @@ diff -rc alpine-2.23/pico/composer.c alpine-2.23.WrtAcc/pico/composer.c case (CTRL|KEY_LEFT): /* word skip left */ if(ods.p_ind > 0) /* Scoot one char left if possible */ ods.p_ind--; -diff -rc alpine-2.23/pico/display.c alpine-2.23.WrtAcc/pico/display.c -*** alpine-2.23/pico/display.c 2020-06-18 15:19:23.437319046 -0600 ---- alpine-2.23.WrtAcc/pico/display.c 2020-06-18 16:08:12.545589528 -0600 +diff -rc alpine-2.24/pico/display.c alpine-2.24.WrtAcc/pico/display.c +*** alpine-2.24/pico/display.c 2020-10-10 00:24:28.180553991 -0600 +--- alpine-2.24.WrtAcc/pico/display.c 2020-10-10 00:26:57.220352202 -0600 *************** *** 2196,2201 **** --- 2196,2206 ---- @@ -263,9 +263,9 @@ diff -rc alpine-2.23/pico/display.c alpine-2.23.WrtAcc/pico/display.c /* look for match in extra_v */ for(i = 0; i < 12; i++) if(c && c == extra_v[i]){ -diff -rc alpine-2.23/pico/ebind.h alpine-2.23.WrtAcc/pico/ebind.h -*** alpine-2.23/pico/ebind.h 2020-06-18 15:19:23.437319046 -0600 ---- alpine-2.23.WrtAcc/pico/ebind.h 2020-06-18 16:08:12.545589528 -0600 +diff -rc alpine-2.24/pico/ebind.h alpine-2.24.WrtAcc/pico/ebind.h +*** alpine-2.24/pico/ebind.h 2020-10-10 00:24:28.184554092 -0600 +--- alpine-2.24.WrtAcc/pico/ebind.h 2020-10-10 00:26:57.228352405 -0600 *************** *** 61,67 **** #ifdef MOUSE @@ -319,9 +319,9 @@ diff -rc alpine-2.23/pico/ebind.h alpine-2.23.WrtAcc/pico/ebind.h #endif #endif {CTRL|'A', gotobol}, -diff -rc alpine-2.23/pico/efunc.h alpine-2.23.WrtAcc/pico/efunc.h -*** alpine-2.23/pico/efunc.h 2020-06-18 15:19:23.437319046 -0600 ---- alpine-2.23.WrtAcc/pico/efunc.h 2020-06-18 16:08:12.545589528 -0600 +diff -rc alpine-2.24/pico/efunc.h alpine-2.24.WrtAcc/pico/efunc.h +*** alpine-2.24/pico/efunc.h 2020-10-10 00:24:28.180553991 -0600 +--- alpine-2.24.WrtAcc/pico/efunc.h 2020-10-10 00:26:57.240352712 -0600 *************** *** 54,59 **** --- 54,62 ---- @@ -334,9 +334,9 @@ diff -rc alpine-2.23/pico/efunc.h alpine-2.23.WrtAcc/pico/efunc.h extern int forwpage(int, int); extern int backpage(int, int); extern int scrollupline(int, int); -diff -rc alpine-2.23/pico/main.c alpine-2.23.WrtAcc/pico/main.c -*** alpine-2.23/pico/main.c 2020-06-18 15:19:23.437319046 -0600 ---- alpine-2.23.WrtAcc/pico/main.c 2020-06-18 16:08:12.545589528 -0600 +diff -rc alpine-2.24/pico/main.c alpine-2.24.WrtAcc/pico/main.c +*** alpine-2.24/pico/main.c 2020-10-10 00:24:28.180553991 -0600 +--- alpine-2.24.WrtAcc/pico/main.c 2020-10-10 00:26:57.280353731 -0600 *************** *** 458,463 **** --- 458,469 ---- diff --git a/chappa-colortext.patch b/chappa-colortext.patch index b6c157b..b776b25 100644 --- a/chappa-colortext.patch +++ b/chappa-colortext.patch @@ -1,9 +1,9 @@ -diff -rc alpine-2.23/alpine/confscroll.c alpine-2.23.colortext/alpine/confscroll.c -*** alpine-2.23/alpine/confscroll.c 2020-06-18 15:19:23.465318999 -0600 ---- alpine-2.23.colortext/alpine/confscroll.c 2020-06-18 16:08:14.821595407 -0600 +diff -rc alpine-2.24/alpine/confscroll.c alpine-2.24.colortext/alpine/confscroll.c +*** alpine-2.24/alpine/confscroll.c 2020-10-10 00:24:28.216554908 -0600 +--- alpine-2.24.colortext/alpine/confscroll.c 2020-10-10 00:27:00.384432838 -0600 *************** -*** 5227,5232 **** ---- 5227,5235 ---- +*** 5248,5253 **** +--- 5248,5256 ---- clear_index_cache(ps->mail_stream, 0); } @@ -13,9 +13,9 @@ diff -rc alpine-2.23/alpine/confscroll.c alpine-2.23.colortext/alpine/confscroll else if(var == &ps->vars[V_INIT_CMD_LIST]){ if(!revert) q_status_message(SM_ASYNC, 0, 3, -diff -rc alpine-2.23/pith/conf.c alpine-2.23.colortext/pith/conf.c -*** alpine-2.23/pith/conf.c 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.colortext/pith/conf.c 2020-06-18 16:08:14.821595407 -0600 +diff -rc alpine-2.24/pith/conf.c alpine-2.24.colortext/pith/conf.c +*** alpine-2.24/pith/conf.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.colortext/pith/conf.c 2020-10-10 00:27:00.388432939 -0600 *************** *** 233,238 **** --- 233,240 ---- @@ -28,8 +28,8 @@ diff -rc alpine-2.23/pith/conf.c alpine-2.23.colortext/pith/conf.c CONF_TXT_T cf_text_quotereplstr[] = "Specifies the string to replace quotes with when viewing a message."; *************** -*** 583,588 **** ---- 585,592 ---- +*** 587,592 **** +--- 589,596 ---- #endif /* _WINDOWS */ {"composer-wrap-column", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, NULL, cf_text_fillcol}, @@ -39,8 +39,8 @@ diff -rc alpine-2.23/pith/conf.c alpine-2.23.colortext/pith/conf.c NULL, cf_text_replystr}, {"reply-leadin", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, *************** -*** 856,861 **** ---- 860,867 ---- +*** 862,867 **** +--- 866,873 ---- {"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}, @@ -50,8 +50,8 @@ diff -rc alpine-2.23/pith/conf.c alpine-2.23.colortext/pith/conf.c {"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}, *************** -*** 2057,2062 **** ---- 2063,2070 ---- +*** 2111,2116 **** +--- 2117,2124 ---- set_current_val(&vars[V_DICTIONARY], TRUE, TRUE); #endif /* _WINDOWS */ set_current_val(&vars[V_IMAGE_VIEWER], TRUE, TRUE); @@ -61,8 +61,8 @@ diff -rc alpine-2.23/pith/conf.c alpine-2.23.colortext/pith/conf.c set_current_val(&vars[V_HISTORY], TRUE, TRUE); set_current_val(&vars[V_SMTP_SERVER], TRUE, TRUE); *************** -*** 6623,6628 **** ---- 6631,6637 ---- +*** 6677,6682 **** +--- 6685,6691 ---- 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); @@ -71,8 +71,8 @@ diff -rc alpine-2.23/pith/conf.c alpine-2.23.colortext/pith/conf.c set_current_val(&ps->vars[V_INDEX_TOKEN_COLORS], TRUE, TRUE); set_current_val(&ps->vars[V_VIEW_HDR_COLORS], TRUE, TRUE); *************** -*** 7841,7846 **** ---- 7850,7857 ---- +*** 7926,7931 **** +--- 7935,7942 ---- return(h_config_scroll_margin); case V_DEADLETS : return(h_config_deadlets); @@ -82,8 +82,8 @@ diff -rc alpine-2.23/pith/conf.c alpine-2.23.colortext/pith/conf.c return(h_config_composer_wrap_column); case V_TCPOPENTIMEO : *************** -*** 8020,8025 **** ---- 8031,8039 ---- +*** 8107,8112 **** +--- 8118,8126 ---- case V_SIGNATURE_FORE_COLOR : case V_SIGNATURE_BACK_COLOR : return(h_config_signature_color); @@ -93,12 +93,12 @@ diff -rc alpine-2.23/pith/conf.c alpine-2.23.colortext/pith/conf.c case V_PROMPT_FORE_COLOR : case V_PROMPT_BACK_COLOR : return(h_config_prompt_color); -diff -rc alpine-2.23/pith/conf.h alpine-2.23.colortext/pith/conf.h -*** alpine-2.23/pith/conf.h 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.colortext/pith/conf.h 2020-06-18 16:08:14.821595407 -0600 +diff -rc alpine-2.24/pith/conf.h alpine-2.24.colortext/pith/conf.h +*** alpine-2.24/pith/conf.h 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.colortext/pith/conf.h 2020-10-10 00:27:00.388432939 -0600 *************** -*** 171,176 **** ---- 171,178 ---- +*** 175,180 **** +--- 175,182 ---- #define VAR_DICTIONARY vars[V_DICTIONARY].current_val.l #define GLO_DICTIONARY vars[V_DICTIONARY].global_val.l #endif /* _WINDOWS */ @@ -108,8 +108,8 @@ diff -rc alpine-2.23/pith/conf.h alpine-2.23.colortext/pith/conf.h #define GLO_FILLCOL vars[V_FILLCOL].global_val.p #define VAR_DEADLETS vars[V_DEADLETS].current_val.p *************** -*** 472,477 **** ---- 474,481 ---- +*** 474,479 **** +--- 476,483 ---- #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 @@ -118,9 +118,9 @@ diff -rc alpine-2.23/pith/conf.h alpine-2.23.colortext/pith/conf.h #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 -diff -rc alpine-2.23/pith/conftype.h alpine-2.23.colortext/pith/conftype.h -*** alpine-2.23/pith/conftype.h 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.colortext/pith/conftype.h 2020-06-18 16:08:14.821595407 -0600 +diff -rc alpine-2.24/pith/conftype.h alpine-2.24.colortext/pith/conftype.h +*** alpine-2.24/pith/conftype.h 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.colortext/pith/conftype.h 2020-10-10 00:27:00.388432939 -0600 *************** *** 83,88 **** --- 83,89 ---- @@ -142,9 +142,9 @@ diff -rc alpine-2.23/pith/conftype.h alpine-2.23.colortext/pith/conftype.h , V_PROMPT_FORE_COLOR , V_PROMPT_BACK_COLOR , V_HEADER_GENERAL_FORE_COLOR -diff -rc alpine-2.23/pith/mailview.c alpine-2.23.colortext/pith/mailview.c -*** alpine-2.23/pith/mailview.c 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.colortext/pith/mailview.c 2020-06-18 16:08:14.821595407 -0600 +diff -rc alpine-2.24/pith/mailview.c alpine-2.24.colortext/pith/mailview.c +*** alpine-2.24/pith/mailview.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.colortext/pith/mailview.c 2020-10-10 00:27:00.388432939 -0600 *************** *** 638,643 **** --- 638,651 ---- @@ -355,9 +355,9 @@ diff -rc alpine-2.23/pith/mailview.c alpine-2.23.colortext/pith/mailview.c /* * The argument fieldname is something like "Subject:..." or "Subject". -diff -rc alpine-2.23/pith/mailview.h alpine-2.23.colortext/pith/mailview.h -*** alpine-2.23/pith/mailview.h 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.colortext/pith/mailview.h 2020-06-18 16:08:14.821595407 -0600 +diff -rc alpine-2.24/pith/mailview.h alpine-2.24.colortext/pith/mailview.h +*** alpine-2.24/pith/mailview.h 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.colortext/pith/mailview.h 2020-10-10 00:27:00.388432939 -0600 *************** *** 30,35 **** --- 30,41 ---- @@ -391,12 +391,12 @@ diff -rc alpine-2.23/pith/mailview.h alpine-2.23.colortext/pith/mailview.h /* * BUG: BELOW IS UNIX/PC ONLY since config'd browser means nothing to webpine -diff -rc alpine-2.23/pith/pine.hlp alpine-2.23.colortext/pith/pine.hlp -*** alpine-2.23/pith/pine.hlp 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.colortext/pith/pine.hlp 2020-06-18 16:08:14.825595417 -0600 +diff -rc alpine-2.24/pith/pine.hlp alpine-2.24.colortext/pith/pine.hlp +*** alpine-2.24/pith/pine.hlp 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.colortext/pith/pine.hlp 2020-10-10 00:27:00.408433449 -0600 *************** -*** 4683,4688 **** ---- 4683,4689 ---- +*** 4975,4980 **** +--- 4975,4981 ----
  • OPTION:
  • OPTION:
  • OPTION: @@ -405,8 +405,8 @@ diff -rc alpine-2.23/pith/pine.hlp alpine-2.23.colortext/pith/pine.hlp
  • OPTION: Print-Font-Char-Set
  • OPTION: Print-Font-Name *************** -*** 4711,4716 **** ---- 4712,4718 ---- +*** 5003,5008 **** +--- 5004,5010 ----
  • OPTION:
  • OPTION:
  • OPTION: Signature Color @@ -415,8 +415,8 @@ diff -rc alpine-2.23/pith/pine.hlp alpine-2.23.colortext/pith/pine.hlp
  • OPTION:
  • OPTION: *************** -*** 24379,24384 **** ---- 24381,24423 ---- +*** 24817,24822 **** +--- 24819,24861 ---- <End of help on this topic> @@ -461,8 +461,8 @@ diff -rc alpine-2.23/pith/pine.hlp alpine-2.23.colortext/pith/pine.hlp *************** -*** 33000,33005 **** ---- 33039,33068 ---- +*** 33438,33443 **** +--- 33477,33506 ----

    Descriptions of the available commands @@ -493,9 +493,9 @@ diff -rc alpine-2.23/pith/pine.hlp alpine-2.23.colortext/pith/pine.hlp

    Look here to see the available Editing and Navigation commands. -diff -rc alpine-2.23/pith/state.c alpine-2.23.colortext/pith/state.c -*** alpine-2.23/pith/state.c 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.colortext/pith/state.c 2020-06-18 16:08:14.825595417 -0600 +diff -rc alpine-2.24/pith/state.c alpine-2.24.colortext/pith/state.c +*** alpine-2.24/pith/state.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.colortext/pith/state.c 2020-10-10 00:27:00.408433449 -0600 *************** *** 144,149 **** --- 144,152 ---- @@ -508,12 +508,12 @@ diff -rc alpine-2.23/pith/state.c alpine-2.23.colortext/pith/state.c if((*pps)->ui.homedir) fs_give((void **)&(*pps)->ui.homedir); -diff -rc alpine-2.23/pith/state.h alpine-2.23.colortext/pith/state.h -*** alpine-2.23/pith/state.h 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.colortext/pith/state.h 2020-06-18 16:08:14.825595417 -0600 +diff -rc alpine-2.24/pith/state.h alpine-2.24.colortext/pith/state.h +*** alpine-2.24/pith/state.h 2020-10-10 00:24:28.208554703 -0600 +--- alpine-2.24.colortext/pith/state.h 2020-10-10 00:27:00.420433755 -0600 *************** -*** 347,352 **** ---- 347,354 ---- +*** 348,353 **** +--- 348,355 ---- char *display_charmap; /* needs to be freed */ char *keyboard_charmap; /* needs to be freed */ void *input_cs; @@ -522,9 +522,9 @@ diff -rc alpine-2.23/pith/state.h alpine-2.23.colortext/pith/state.h char *posting_charmap; /* needs to be freed */ -diff -rc alpine-2.23/pith/text.c alpine-2.23.colortext/pith/text.c -*** alpine-2.23/pith/text.c 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.colortext/pith/text.c 2020-06-18 16:08:14.825595417 -0600 +diff -rc alpine-2.24/pith/text.c alpine-2.24.colortext/pith/text.c +*** alpine-2.24/pith/text.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.colortext/pith/text.c 2020-10-10 00:27:00.420433755 -0600 *************** *** 171,176 **** --- 171,185 ---- diff --git a/chappa-fancy.patch b/chappa-fancy.patch index 3700211..0a018bd 100644 --- a/chappa-fancy.patch +++ b/chappa-fancy.patch @@ -1,10 +1,9 @@ -Index: alpine-2.23.2/alpine/arg.c -=================================================================== -*** alpine-2.23.2.orig/alpine/arg.c ---- alpine-2.23.2/alpine/arg.c -*************** static char args_err_non_abs_pwdcertdir[ -*** 68,73 **** ---- 68,74 ---- +diff -rc alpine-2.24/alpine/arg.c alpine-2.24.fancy/alpine/arg.c +*** alpine-2.24/alpine/arg.c 2020-10-10 00:24:28.212554806 -0600 +--- alpine-2.24.fancy/alpine/arg.c 2020-10-10 00:26:49.208148014 -0600 +*************** +*** 70,75 **** +--- 70,76 ---- #endif /* SMIME inside PASSFILE */ #endif static char args_err_missing_sort[] = N_("missing argument for option \"-sort\""); @@ -12,9 +11,9 @@ Index: alpine-2.23.2/alpine/arg.c 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\""); -*************** N_(" -k \t\tKeys - Force use of function -*** 116,121 **** ---- 117,123 ---- +*************** +*** 118,123 **** +--- 119,125 ---- N_(" -z \t\tSuspend - allow use of ^Z suspension"), N_(" -r \t\tRestricted - can only send mail to oneself"), N_(" -sort \tSort - Specify sort order of folder:"), @@ -22,9 +21,9 @@ Index: alpine-2.23.2/alpine/arg.c 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"), -*************** pine_args(struct pine *pine_state, int a -*** 217,222 **** ---- 219,225 ---- +*************** +*** 280,285 **** +--- 282,288 ---- char *cmd_list = NULL; char *debug_str = NULL; char *sort = NULL; @@ -32,9 +31,9 @@ Index: alpine-2.23.2/alpine/arg.c char *pinerc_file = NULL; char *lc = NULL; XOAUTH2_INFO_S x; -*************** Loop: while(--ac > 0) -*** 440,445 **** ---- 443,459 ---- +*************** +*** 503,508 **** +--- 506,522 ---- goto Loop; } @@ -52,11 +51,10 @@ Index: alpine-2.23.2/alpine/arg.c else if(strcmp(*av, "url") == 0){ if(args->action == aaFolder && !args->data.folder){ args->action = aaURL; -Index: alpine-2.23.2/alpine/confscroll.c -=================================================================== -*** alpine-2.23.2.orig/alpine/confscroll.c ---- alpine-2.23.2/alpine/confscroll.c -*************** char *yesno_pretty_value(struct pine +diff -rc alpine-2.24/alpine/confscroll.c alpine-2.24.fancy/alpine/confscroll.c +*** alpine-2.24/alpine/confscroll.c 2020-10-10 00:24:28.216554908 -0600 +--- alpine-2.24.fancy/alpine/confscroll.c 2020-10-10 00:26:49.212148118 -0600 +*************** *** 140,146 **** char *radio_pretty_value(struct pine *, CONF_S *); char *sigfile_pretty_value(struct pine *, CONF_S *); @@ -73,7 +71,7 @@ Index: alpine-2.23.2/alpine/confscroll.c int longest_feature_name(void); COLOR_PAIR *sample_color(struct pine *, struct variable *); COLOR_PAIR *sampleexc_color(struct pine *, struct variable *); -*************** set_radio_pretty_vals(struct pine *ps, C +*************** *** 288,294 **** CONF_S *ctmp; @@ -91,8 +89,8 @@ Index: alpine-2.23.2/alpine/confscroll.c standard_radio_var(ps, (*cl)->var) || (*cl)->var == startup_ptr))) return; -*************** radiobutton_tool(struct pine *ps, int cm -*** 2960,2966 **** +*************** +*** 2958,2964 **** } set_current_val((*cl)->var, TRUE, TRUE); @@ -100,7 +98,7 @@ Index: alpine-2.23.2/alpine/confscroll.c ps->def_sort = def_sort; ps->def_sort_rev = def_sort_rev; } ---- 2961,2967 ---- +--- 2959,2965 ---- } set_current_val((*cl)->var, TRUE, TRUE); @@ -108,9 +106,9 @@ Index: alpine-2.23.2/alpine/confscroll.c ps->def_sort = def_sort; ps->def_sort_rev = def_sort_rev; } -*************** radiobutton_tool(struct pine *ps, int cm -*** 2969,2974 **** ---- 2970,3006 ---- +*************** +*** 2967,2972 **** +--- 2968,3004 ---- ps->mangled_body = 1; /* BUG: redraw it all for now? */ rv = 1; } @@ -148,8 +146,8 @@ Index: alpine-2.23.2/alpine/confscroll.c else q_status_message(SM_ORDER | SM_DING, 3, 6, "Programmer botch! Unknown radiobutton type."); -*************** pretty_value(struct pine *ps, CONF_S *cl -*** 3832,3838 **** +*************** +*** 3830,3836 **** else if(standard_radio_var(ps, v) || v == startup_ptr) return(radio_pretty_value(ps, cl)); else if(v == &ps->vars[V_SORT_KEY]) @@ -157,7 +155,7 @@ Index: alpine-2.23.2/alpine/confscroll.c else if(v == &ps->vars[V_SIGNATURE_FILE]) return(sigfile_pretty_value(ps, cl)); else if(v == &ps->vars[V_USE_ONLY_DOMAIN_NAME]) ---- 3864,3872 ---- +--- 3862,3870 ---- else if(standard_radio_var(ps, v) || v == startup_ptr) return(radio_pretty_value(ps, cl)); else if(v == &ps->vars[V_SORT_KEY]) @@ -167,8 +165,8 @@ Index: alpine-2.23.2/alpine/confscroll.c else if(v == &ps->vars[V_SIGNATURE_FILE]) return(sigfile_pretty_value(ps, cl)); else if(v == &ps->vars[V_USE_ONLY_DOMAIN_NAME]) -*************** color_pretty_value(struct pine *ps, CONF -*** 4363,4376 **** +*************** +*** 4361,4374 **** char * @@ -183,7 +181,7 @@ Index: alpine-2.23.2/alpine/confscroll.c { char tmp[6*MAXPATH]; char *pvalnorm, *pvalexc, *pval; ---- 4397,4410 ---- +--- 4395,4408 ---- char * @@ -198,8 +196,8 @@ Index: alpine-2.23.2/alpine/confscroll.c { char tmp[6*MAXPATH]; char *pvalnorm, *pvalexc, *pval; -*************** generalized_sort_pretty_value(struct pin -*** 4420,4426 **** +*************** +*** 4418,4424 **** } else if(fixed){ pval = v->fixed_val.p; @@ -207,7 +205,7 @@ Index: alpine-2.23.2/alpine/confscroll.c is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort); utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s", ---- 4454,4460 ---- +--- 4452,4458 ---- } else if(fixed){ pval = v->fixed_val.p; @@ -215,8 +213,8 @@ Index: alpine-2.23.2/alpine/confscroll.c is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort); utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s", -*************** generalized_sort_pretty_value(struct pin -*** 4431,4439 **** +*************** +*** 4429,4437 **** is_the_one ? " (value is fixed)" : ""); } else if(is_set_for_this_level){ @@ -226,7 +224,7 @@ Index: alpine-2.23.2/alpine/confscroll.c 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", ---- 4465,4473 ---- +--- 4463,4471 ---- is_the_one ? " (value is fixed)" : ""); } else if(is_set_for_this_level){ @@ -236,8 +234,8 @@ Index: alpine-2.23.2/alpine/confscroll.c 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", -*************** generalized_sort_pretty_value(struct pin -*** 4451,4457 **** +*************** +*** 4449,4455 **** } else{ if(pvalexc){ @@ -245,7 +243,7 @@ Index: alpine-2.23.2/alpine/confscroll.c is_the_one = (exc_sort_rev == line_sort_rev && exc_sort == line_sort); utf8_snprintf(tmp, sizeof(tmp), "( ) %s%-*w%*s%s", ---- 4485,4491 ---- +--- 4483,4489 ---- } else{ if(pvalexc){ @@ -253,8 +251,8 @@ Index: alpine-2.23.2/alpine/confscroll.c is_the_one = (exc_sort_rev == line_sort_rev && exc_sort == line_sort); utf8_snprintf(tmp, sizeof(tmp), "( ) %s%-*w%*s%s", -*************** generalized_sort_pretty_value(struct pin -*** 4462,4468 **** +*************** +*** 4460,4466 **** } else{ pval = v->current_val.p; @@ -262,7 +260,7 @@ Index: alpine-2.23.2/alpine/confscroll.c is_the_one = ((pval || default_ok) && var_sort_rev == line_sort_rev && var_sort == line_sort); ---- 4496,4502 ---- +--- 4494,4500 ---- } else{ pval = v->current_val.p; @@ -270,8 +268,8 @@ Index: alpine-2.23.2/alpine/confscroll.c is_the_one = ((pval || default_ok) && var_sort_rev == line_sort_rev && var_sort == line_sort); -*************** fix_side_effects(struct pine *ps, struct -*** 5621,5629 **** +*************** +*** 5616,5624 **** else if(revert && var == &ps->vars[V_SORT_KEY]){ int def_sort_rev; @@ -281,7 +279,7 @@ Index: alpine-2.23.2/alpine/confscroll.c else if(var == &ps->vars[V_THREAD_MORE_CHAR] || var == &ps->vars[V_THREAD_EXP_CHAR] || var == &ps->vars[V_THREAD_LASTREPLY_CHAR]){ ---- 5655,5669 ---- +--- 5650,5664 ---- else if(revert && var == &ps->vars[V_SORT_KEY]){ int def_sort_rev; @@ -297,11 +295,10 @@ Index: alpine-2.23.2/alpine/confscroll.c else if(var == &ps->vars[V_THREAD_MORE_CHAR] || var == &ps->vars[V_THREAD_EXP_CHAR] || var == &ps->vars[V_THREAD_LASTREPLY_CHAR]){ -Index: alpine-2.23.2/alpine/confscroll.h -=================================================================== -*** alpine-2.23.2.orig/alpine/confscroll.h ---- alpine-2.23.2/alpine/confscroll.h -*************** int checkbox_tool(struct pine *, int, C +diff -rc alpine-2.24/alpine/confscroll.h alpine-2.24.fancy/alpine/confscroll.h +*** alpine-2.24/alpine/confscroll.h 2020-10-10 00:24:28.208554703 -0600 +--- alpine-2.24.fancy/alpine/confscroll.h 2020-10-10 00:26:49.212148118 -0600 +*************** *** 97,103 **** int radiobutton_tool(struct pine *, int, CONF_S **, unsigned); int yesno_tool(struct pine *, int, CONF_S **, unsigned); @@ -318,11 +315,10 @@ Index: alpine-2.23.2/alpine/confscroll.h int exclude_config_var(struct pine *, struct variable *, int); int config_exit_cmd(unsigned); int simple_exit_cmd(unsigned); -Index: alpine-2.23.2/alpine/keymenu.c -=================================================================== -*** alpine-2.23.2.orig/alpine/keymenu.c ---- alpine-2.23.2/alpine/keymenu.c -*************** struct key index_keys[] = +diff -rc alpine-2.24/alpine/keymenu.c alpine-2.24.fancy/alpine/keymenu.c +*** alpine-2.24/alpine/keymenu.c 2020-10-10 00:24:28.216554908 -0600 +--- alpine-2.24.fancy/alpine/keymenu.c 2020-10-10 00:26:49.212148118 -0600 +*************** *** 679,688 **** RCOMPOSE_MENU, HOMEKEY_MENU, @@ -360,7 +356,7 @@ Index: alpine-2.23.2/alpine/keymenu.c {"@", N_("Quota"), {MC_QUOTA,1,{'@'}}, KS_NONE}, NULL_MENU}; INST_KEY_MENU(index_keymenu, index_keys); -*************** struct key thread_keys[] = +*************** *** 757,765 **** RCOMPOSE_MENU, HOMEKEY_MENU, @@ -394,7 +390,7 @@ Index: alpine-2.23.2/alpine/keymenu.c NULL_MENU}; INST_KEY_MENU(thread_keymenu, thread_keys); -*************** struct key view_keys[] = +*************** *** 927,933 **** NULL_MENU, NULL_MENU, @@ -424,49 +420,35 @@ Index: alpine-2.23.2/alpine/keymenu.c INST_KEY_MENU(view_keymenu, view_keys); -Index: alpine-2.23.2/alpine/keymenu.h -=================================================================== -*** alpine-2.23.2.orig/alpine/keymenu.h ---- alpine-2.23.2/alpine/keymenu.h -*************** struct key_menu { -*** 217,225 **** - #define MC_ADDHEADER 804 - #define MC_XOAUTH2 805 - #define MC_EXTERNAL 806 -! #define MC_XSADD 807 -! #define MC_XSDELETE 808 -! #define MC_XSHELP 809 +diff -rc alpine-2.24/alpine/keymenu.h alpine-2.24.fancy/alpine/keymenu.h +*** alpine-2.24/alpine/keymenu.h 2020-10-10 00:24:28.216554908 -0600 +--- alpine-2.24.fancy/alpine/keymenu.h 2020-10-10 00:26:49.212148118 -0600 +*************** +*** 220,225 **** +--- 220,238 ---- + #define MC_XSADD 807 + #define MC_XSDELETE 808 + #define MC_XSHELP 809 ++ #define MC_DELTHREAD 810 ++ #define MC_UNDTHREAD 811 ++ #define MC_SELTHREAD 812 ++ #define MC_SSUTHREAD 813 ++ #define MC_DSUTHREAD 814 ++ #define MC_USUTHREAD 815 ++ #define MC_SORTHREAD 816 ++ #define MC_NEXTHREAD 817 ++ #define MC_KOLAPSE 818 ++ #define MC_EXPTHREAD 819 ++ #define MC_PRETHREAD 820 ++ #define MC_CTHREAD 821 ++ #define MC_OTHREAD 822 /* Commands for S/MIME screens */ #define MC_TRUST 900 ---- 217,238 ---- - #define MC_ADDHEADER 804 - #define MC_XOAUTH2 805 - #define MC_EXTERNAL 806 -! #define MC_DELTHREAD 807 -! #define MC_UNDTHREAD 808 -! #define MC_SELTHREAD 809 -! #define MC_SSUTHREAD 810 -! #define MC_DSUTHREAD 811 -! #define MC_USUTHREAD 812 -! #define MC_SORTHREAD 813 -! #define MC_NEXTHREAD 814 -! #define MC_KOLAPSE 815 -! #define MC_EXPTHREAD 816 -! #define MC_PRETHREAD 817 -! #define MC_CTHREAD 818 -! #define MC_OTHREAD 819 -! #define MC_XSADD 820 -! #define MC_XSDELETE 821 -! #define MC_XSHELP 822 - - /* Commands for S/MIME screens */ - #define MC_TRUST 900 -Index: alpine-2.23.2/alpine/mailcmd.c -=================================================================== -*** alpine-2.23.2.orig/alpine/mailcmd.c ---- alpine-2.23.2/alpine/mailcmd.c -*************** int select_by_thread(MAILSTREAM *, MSG +diff -rc alpine-2.24/alpine/mailcmd.c alpine-2.24.fancy/alpine/mailcmd.c +*** alpine-2.24/alpine/mailcmd.c 2020-10-10 00:24:28.212554806 -0600 +--- alpine-2.24.fancy/alpine/mailcmd.c 2020-10-10 00:26:49.224148423 -0600 +*************** *** 114,120 **** char *choose_a_rule(int); int select_by_keyword(MAILSTREAM *, SEARCHSET **); @@ -483,7 +465,7 @@ Index: alpine-2.23.2/alpine/mailcmd.c int print_index(struct pine *, MSGNO_S *, int); /* -*************** get_out: +*************** *** 1435,1441 **** if(any_messages(msgmap, NULL, NULL)){ if(any_lflagged(msgmap, MN_SLCT) > 0L){ @@ -500,7 +482,7 @@ Index: alpine-2.23.2/alpine/mailcmd.c if(F_ON(F_AUTO_UNSELECT, state)){ agg_select_all(stream, msgmap, NULL, 0); unzoom_index(state, stream, msgmap); -*************** get_out: +*************** *** 1453,1475 **** /*-------- Sort command -------*/ @@ -561,7 +543,7 @@ Index: alpine-2.23.2/alpine/mailcmd.c } state->mangled_footer = 1; -*************** cmd_expunge(struct pine *state, MAILSTRE +*************** *** 3314,3319 **** --- 3326,3335 ---- if(SORT_IS_THREADED(msgmap)) @@ -574,7 +556,7 @@ Index: alpine-2.23.2/alpine/mailcmd.c state->mangled_body = 1; state->mangled_header = 1; q_status_message2(SM_ORDER, 0, 4, -*************** cmd_expunge(struct pine *state, MAILSTRE +*************** *** 3415,3420 **** --- 3431,3439 ---- */ @@ -586,7 +568,7 @@ Index: alpine-2.23.2/alpine/mailcmd.c } else{ if(del_count){ -*************** select_by_current(struct pine *state, MS +*************** *** 7324,7330 **** * Maybe it makes sense to zoom after a select but not after a colon * command even though they are very similar. @@ -603,7 +585,7 @@ Index: alpine-2.23.2/alpine/mailcmd.c } else{ if((all_selected = -*************** select_by_current(struct pine *state, MS +*************** *** 7380,7386 **** ----*/ int @@ -620,7 +602,7 @@ Index: alpine-2.23.2/alpine/mailcmd.c { int i = 8, /* number of static entries in sel_opts3 */ rv = 0, -*************** apply_command(struct pine *state, MAILST +*************** *** 7547,7555 **** collapse_or_expand(state, stream, msgmap, F_ON(F_SLASH_COLL_ENTIRE, ps_global) @@ -651,7 +633,7 @@ Index: alpine-2.23.2/alpine/mailcmd.c case ':' : select_thread_stmp(state, stream, msgmap); break; -*************** Args: state -- pine state pointer +*************** *** 9595,9604 **** Returns 0 if it was cancelled, 1 otherwise. ----*/ @@ -674,7 +656,7 @@ Index: alpine-2.23.2/alpine/mailcmd.c int deefault = 'a', retval = 1; HelpType help; ESCKEY_S sorts[14]; -*************** select_sort(struct pine *state, int ql, +*************** *** 9631,9647 **** strncpy(prompt, _("Choose type of sort, or 'R' to reverse current sort : "), sizeof(prompt)); @@ -720,7 +702,7 @@ Index: alpine-2.23.2/alpine/mailcmd.c } sorts[i].ch = 'r'; -*************** select_sort(struct pine *state, int ql, +*************** *** 9665,9672 **** state->mangled_body = 1; /* signal screen's changed */ if(s == 'r') @@ -748,7 +730,7 @@ Index: alpine-2.23.2/alpine/mailcmd.c if(F_ON(F_SHOW_SORT, ps_global)) ps_global->mangled_header = 1; -*************** flag_submenu(mc) +*************** *** 10050,10052 **** --- 10097,10474 ---- } @@ -1129,11 +1111,10 @@ Index: alpine-2.23.2/alpine/mailcmd.c + expand_thread(state, stream, msgmap, 0); + } + -Index: alpine-2.23.2/alpine/mailcmd.h -=================================================================== -*** alpine-2.23.2.orig/alpine/mailcmd.h ---- alpine-2.23.2/alpine/mailcmd.h -*************** char *broach_folder(int, int, int *, +diff -rc alpine-2.24/alpine/mailcmd.h alpine-2.24.fancy/alpine/mailcmd.h +*** alpine-2.24/alpine/mailcmd.h 2020-10-10 00:24:28.208554703 -0600 +--- alpine-2.24.fancy/alpine/mailcmd.h 2020-10-10 00:26:49.240148831 -0600 +*************** *** 90,96 **** int ask_mailbox_reopen(struct pine *, int *); void visit_folder(struct pine *, char *, CONTEXT_S *, MAILSTREAM *, unsigned long); @@ -1150,7 +1131,7 @@ Index: alpine-2.23.2/alpine/mailcmd.h char **choose_list_of_keywords(void); char *choose_a_charset(int); char **choose_list_of_charsets(void); -*************** int any_selected_callback(int, long) +*************** *** 108,113 **** int flag_callback(int, long); MPopup *flag_submenu(MESSAGECACHE *); @@ -1174,11 +1155,10 @@ Index: alpine-2.23.2/alpine/mailcmd.h ! int expand_this_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int, int); #endif /* PINE_MAILCMD_INCLUDED */ -Index: alpine-2.23.2/alpine/mailindx.c -=================================================================== -*** alpine-2.23.2.orig/alpine/mailindx.c ---- alpine-2.23.2/alpine/mailindx.c -*************** index_lister(struct pine *state, CONTEXT +diff -rc alpine-2.24/alpine/mailindx.c alpine-2.24.fancy/alpine/mailindx.c +*** alpine-2.24/alpine/mailindx.c 2020-10-10 00:24:28.212554806 -0600 +--- alpine-2.24.fancy/alpine/mailindx.c 2020-10-10 00:26:49.248149033 -0600 +*************** *** 564,569 **** --- 564,570 ---- @@ -1188,7 +1168,7 @@ Index: alpine-2.23.2/alpine/mailindx.c (void) process_cmd(state, stream, msgmap, MC_PREVITEM, (style == MsgIndex || style == MultiMsgIndex -*************** index_lister(struct pine *state, CONTEXT +*************** *** 581,586 **** --- 582,588 ---- @@ -1198,7 +1178,7 @@ Index: alpine-2.23.2/alpine/mailindx.c /* * Special Page framing handling here. If we * did something that should scroll-by-a-line, frame -*************** view_a_thread: +*************** *** 798,803 **** --- 800,806 ---- @@ -1208,7 +1188,7 @@ Index: alpine-2.23.2/alpine/mailindx.c if(any_lflagged(msgmap, MN_SLCT)){ PINETHRD_S *thrd, *topthrd; for(i = 1L; i > 0L && i <= mn_get_total(msgmap);){ -*************** view_a_thread: +*************** *** 863,869 **** && mp.col == id.plus_col && style != ThreadIndex){ @@ -1225,7 +1205,7 @@ Index: alpine-2.23.2/alpine/mailindx.c } else if (mp.doubleclick){ if(mp.button == M_BUTTON_LEFT){ -*************** view_a_thread: +*************** *** 972,980 **** @@ -1342,7 +1322,7 @@ Index: alpine-2.23.2/alpine/mailindx.c case MC_DELETE : case MC_UNDELETE : case MC_REPLY : -*************** view_a_thread: +*************** *** 995,1007 **** if(rawno) thrd = fetch_thread(stream, rawno); @@ -1370,7 +1350,7 @@ Index: alpine-2.23.2/alpine/mailindx.c /* increment current */ if(cmd == MC_DELETE){ advance_cur_after_delete(state, stream, msgmap, -*************** top_ent_calc(MAILSTREAM *stream, MSGNO_S +*************** *** 2692,2697 **** --- 2790,2796 ---- n = mn_raw2m(msgs, thrd->rawno); @@ -1380,7 +1360,7 @@ Index: alpine-2.23.2/alpine/mailindx.c if(!msgline_hidden(stream, msgs, n, 0) && (++m % lines_per_page) == 1L) t = n; -*************** top_ent_calc(MAILSTREAM *stream, MSGNO_S +*************** *** 2760,2770 **** /* n is the end of this thread */ @@ -1406,7 +1386,7 @@ Index: alpine-2.23.2/alpine/mailindx.c else thrd = NULL; } -*************** warn_other_cmds(void) +*************** *** 2872,2878 **** void @@ -1423,7 +1403,7 @@ Index: alpine-2.23.2/alpine/mailindx.c { PINETHRD_S *thrd = NULL; unsigned long rawno, save_branch; -*************** thread_command(struct pine *state, MAILS +*************** *** 2921,2927 **** cancel_busy_cue(0); @@ -1440,7 +1420,7 @@ Index: alpine-2.23.2/alpine/mailindx.c /* restore the original flags */ copy_lflags(stream, msgmap, MN_STMP, MN_SLCT); -*************** index_sort_callback(set, order) +*************** *** 3438,3444 **** if(set){ sort_folder(ps_global->mail_stream, ps_global->msgmap, @@ -1457,11 +1437,10 @@ Index: alpine-2.23.2/alpine/mailindx.c mswin_beginupdate(); update_titlebar_message(); update_titlebar_status(); -Index: alpine-2.23.2/alpine/mailindx.h -=================================================================== -*** alpine-2.23.2.orig/alpine/mailindx.h ---- alpine-2.23.2/alpine/mailindx.h -*************** int truncate_subj_and_from_strings(voi +diff -rc alpine-2.24/alpine/mailindx.h alpine-2.24.fancy/alpine/mailindx.h +*** alpine-2.24/alpine/mailindx.h 2020-10-10 00:24:28.212554806 -0600 +--- alpine-2.24.fancy/alpine/mailindx.h 2020-10-10 00:26:49.256149239 -0600 +*************** *** 103,109 **** void paint_index_hline(MAILSTREAM *, long, ICE_S *); void setup_index_state(int); @@ -1478,13 +1457,12 @@ Index: alpine-2.23.2/alpine/mailindx.h COLOR_PAIR *apply_rev_color(COLOR_PAIR *, int); #ifdef _WINDOWS int index_sort_callback(int, long); -Index: alpine-2.23.2/alpine/mailview.c -=================================================================== -*** alpine-2.23.2.orig/alpine/mailview.c ---- alpine-2.23.2/alpine/mailview.c -*************** scrolltool(SCROLL_S *sparms) -*** 3495,3500 **** ---- 3495,3546 ---- +diff -rc alpine-2.24/alpine/mailview.c alpine-2.24.fancy/alpine/mailview.c +*** alpine-2.24/alpine/mailview.c 2020-10-10 00:24:28.216554908 -0600 +--- alpine-2.24.fancy/alpine/mailview.c 2020-10-10 00:26:49.264149441 -0600 +*************** +*** 3496,3501 **** +--- 3496,3547 ---- print_to_printer(sparms); break; @@ -1537,11 +1515,10 @@ Index: alpine-2.23.2/alpine/mailview.c /* ------- First handle on Line ------ */ case MC_GOTOBOL : -Index: alpine-2.23.2/alpine/roleconf.c -=================================================================== -*** alpine-2.23.2.orig/alpine/roleconf.c ---- alpine-2.23.2/alpine/roleconf.c -*************** role_config_edit_screen(struct pine *ps, +diff -rc alpine-2.24/alpine/roleconf.c alpine-2.24.fancy/alpine/roleconf.c +*** alpine-2.24/alpine/roleconf.c 2020-10-10 00:24:28.212554806 -0600 +--- alpine-2.24.fancy/alpine/roleconf.c 2020-10-10 00:26:49.268149545 -0600 +*************** *** 4478,4488 **** ctmp->tool = role_sort_tool; ctmp->valoffset = rindent; @@ -1566,7 +1543,7 @@ Index: alpine-2.23.2/alpine/roleconf.c /* allow user to set their default sort order */ new_confline(&ctmp)->var = &sort_act_var; -*************** role_config_edit_screen(struct pine *ps, +*************** *** 4492,4498 **** ctmp->tool = role_sort_tool; ctmp->valoffset = rindent; @@ -1583,7 +1560,7 @@ Index: alpine-2.23.2/alpine/roleconf.c for(j = 0; j < 2; j++){ for(i = 0; ps->sort_types[i] != EndofList; i++){ -*************** role_config_edit_screen(struct pine *ps, +*************** *** 4504,4510 **** ctmp->valoffset = rindent; ctmp->varmem = i + (j * EndofList); @@ -1600,7 +1577,7 @@ Index: alpine-2.23.2/alpine/roleconf.c } } -*************** role_config_edit_screen(struct pine *ps, +*************** *** 5437,5443 **** (*result)->patgrp->stat_boy = PAT_STAT_EITHER; @@ -1617,11 +1594,10 @@ Index: alpine-2.23.2/alpine/roleconf.c (*result)->action->sort_is_set = 1; (*result)->action->sortorder = def_sort; (*result)->action->revsort = (def_sort_rev ? 1 : 0); -Index: alpine-2.23.2/alpine/setup.c -=================================================================== -*** alpine-2.23.2.orig/alpine/setup.c ---- alpine-2.23.2/alpine/setup.c -*************** option_screen(struct pine *ps, int edit_ +diff -rc alpine-2.24/alpine/setup.c alpine-2.24.fancy/alpine/setup.c +*** alpine-2.24/alpine/setup.c 2020-10-10 00:24:28.208554703 -0600 +--- alpine-2.24.fancy/alpine/setup.c 2020-10-10 00:26:49.272149646 -0600 +*************** *** 262,268 **** ctmpa->flags |= CF_NOSELECT; ctmpa->value = cpystr("--- ----------------------"); @@ -1638,7 +1614,7 @@ Index: alpine-2.23.2/alpine/setup.c for(j = 0; j < 2; j++){ for(i = 0; ps->sort_types[i] != EndofList; i++){ -*************** option_screen(struct pine *ps, int edit_ +*************** *** 277,282 **** --- 277,331 ---- } @@ -1696,7 +1672,7 @@ Index: alpine-2.23.2/alpine/setup.c else if(vtmp == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){ /* yesno case */ ctmpa->keymenu = &config_yesno_keymenu; ctmpa->tool = yesno_tool; -*************** option_screen(struct pine *ps, int edit_ +*************** *** 469,474 **** --- 518,532 ---- } @@ -1714,11 +1690,10 @@ Index: alpine-2.23.2/alpine/setup.c treat_color_vars_as_text = 0; free_saved_config(ps, &vsave, expose_hidden_config); #ifdef _WINDOWS -Index: alpine-2.23.2/pith/conf.c -=================================================================== -*** alpine-2.23.2.orig/pith/conf.c ---- alpine-2.23.2/pith/conf.c -*************** CONF_TXT_T cf_text_fcc_name_rule[] = "De +diff -rc alpine-2.24/pith/conf.c alpine-2.24.fancy/pith/conf.c +*** alpine-2.24/pith/conf.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fancy/pith/conf.c 2020-10-10 00:26:49.280149850 -0600 +*************** *** 207,212 **** --- 207,214 ---- @@ -1729,9 +1704,9 @@ Index: alpine-2.23.2/pith/conf.c 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\"."; -*************** static struct variable variables[] = { -*** 541,546 **** ---- 543,550 ---- +*************** +*** 543,548 **** +--- 545,552 ---- NULL, cf_text_fcc_name_rule}, {"sort-key", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, NULL, cf_text_sort_key}, @@ -1740,7 +1715,7 @@ Index: alpine-2.23.2/pith/conf.c {"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, -*************** init_vars(struct pine *ps, void (*cmds_f +*************** *** 1613,1619 **** register struct variable *vars = ps->vars; int obs_header_in_reply = 0, /* the obs_ variables are to */ @@ -1757,9 +1732,9 @@ Index: alpine-2.23.2/pith/conf.c long rvl; PINERC_S *fixedprc = NULL; FeatureLevel obs_feature_level; -*************** init_vars(struct pine *ps, void (*cmds_f -*** 1641,1646 **** ---- 1645,1651 ---- +*************** +*** 1639,1644 **** +--- 1643,1649 ---- GLO_FEATURE_LEVEL = cpystr("sappling"); GLO_OLD_STYLE_REPLY = cpystr(DF_OLD_STYLE_REPLY); GLO_SORT_KEY = cpystr(DF_SORT_KEY); @@ -1767,8 +1742,8 @@ Index: alpine-2.23.2/pith/conf.c 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); -*************** init_vars(struct pine *ps, void (*cmds_f -*** 2594,2600 **** +*************** +*** 2640,2646 **** 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); @@ -1776,7 +1751,7 @@ Index: alpine-2.23.2/pith/conf.c 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; ---- 2599,2605 ---- +--- 2645,2651 ---- 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); @@ -1784,9 +1759,9 @@ Index: alpine-2.23.2/pith/conf.c 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; -*************** init_vars(struct pine *ps, void (*cmds_f -*** 2603,2608 **** ---- 2608,2624 ---- +*************** +*** 2649,2654 **** +--- 2654,2670 ---- else ps->def_sort_rev = def_sort_rev; @@ -1804,9 +1779,9 @@ Index: alpine-2.23.2/pith/conf.c 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++) -*************** feature_list(int index) -*** 3028,3033 **** ---- 3044,3051 ---- +*************** +*** 3074,3079 **** +--- 3090,3097 ---- 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}, @@ -1815,9 +1790,9 @@ Index: alpine-2.23.2/pith/conf.c /* Viewer prefs */ {"enable-msg-view-addresses", "Enable Message View Address Links", -*************** config_help(int var, int feature) -*** 7792,7797 **** ---- 7810,7817 ---- +*************** +*** 7868,7873 **** +--- 7886,7893 ---- return(h_config_fcc_rule); case V_SORT_KEY : return(h_config_sort_key); @@ -1826,13 +1801,12 @@ Index: alpine-2.23.2/pith/conf.c case V_AB_SORT_RULE : return(h_config_ab_sort_rule); case V_FLD_SORT_RULE : -Index: alpine-2.23.2/pith/conf.h -=================================================================== -*** alpine-2.23.2.orig/pith/conf.h ---- alpine-2.23.2/pith/conf.h +diff -rc alpine-2.24/pith/conf.h alpine-2.24.fancy/pith/conf.h +*** alpine-2.24/pith/conf.h 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fancy/pith/conf.h 2020-10-10 00:26:49.280149850 -0600 *************** -*** 150,155 **** ---- 150,158 ---- +*** 154,159 **** +--- 154,162 ---- #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 @@ -1842,11 +1816,10 @@ Index: alpine-2.23.2/pith/conf.h #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 -Index: alpine-2.23.2/pith/conftype.h -=================================================================== -*** alpine-2.23.2.orig/pith/conftype.h ---- alpine-2.23.2/pith/conftype.h -*************** typedef enum { V_PERSONAL_NAME = 0 +diff -rc alpine-2.24/pith/conftype.h alpine-2.24.fancy/pith/conftype.h +*** alpine-2.24/pith/conftype.h 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fancy/pith/conftype.h 2020-10-10 00:26:49.280149850 -0600 +*************** *** 59,64 **** --- 59,65 ---- , V_SAVED_MSG_NAME_RULE @@ -1856,9 +1829,9 @@ Index: alpine-2.23.2/pith/conftype.h , V_AB_SORT_RULE , V_FLD_SORT_RULE , V_GOTO_DEFAULT_RULE -*************** typedef enum { -*** 529,534 **** ---- 530,536 ---- +*************** +*** 526,531 **** +--- 527,533 ---- F_QUELL_TIMEZONE, F_QUELL_USERAGENT, F_COLOR_LINE_IMPORTANT, @@ -1866,20 +1839,19 @@ Index: alpine-2.23.2/pith/conftype.h F_SLASH_COLL_ENTIRE, F_ENABLE_FULL_HDR_AND_TEXT, F_QUELL_FULL_HDR_RESET, -*************** typedef struct smime_stuff { -*** 794,798 **** ---- 796,801 ---- +*************** +*** 791,795 **** +--- 793,798 ---- /* exported prototypes */ + #define DF_THREAD_SORT_KEY "thread" #endif /* PITH_CONFTYPE_INCLUDED */ -Index: alpine-2.23.2/pith/flag.c -=================================================================== -*** alpine-2.23.2.orig/pith/flag.c ---- alpine-2.23.2/pith/flag.c -*************** set_lflag(MAILSTREAM *stream, MSGNO_S *m +diff -rc alpine-2.24/pith/flag.c alpine-2.24.fancy/pith/flag.c +*** alpine-2.24/pith/flag.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fancy/pith/flag.c 2020-10-10 00:26:49.284149951 -0600 +*************** *** 594,607 **** was_invisible = (pelt->hidden || pelt->colhid) ? 1 : 0; @@ -1912,11 +1884,10 @@ Index: alpine-2.23.2/pith/flag.c } if(topthrd){ -Index: alpine-2.23.2/pith/indxtype.h -=================================================================== -*** alpine-2.23.2.orig/pith/indxtype.h ---- alpine-2.23.2/pith/indxtype.h -*************** typedef enum {iNothing, iStatus, iFStatu +diff -rc alpine-2.24/pith/indxtype.h alpine-2.24.fancy/pith/indxtype.h +*** alpine-2.24/pith/indxtype.h 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fancy/pith/indxtype.h 2020-10-10 00:26:49.292150156 -0600 +*************** *** 78,84 **** iKey, iKeyInit, iPrefDate, iPrefTime, iPrefDateTime, @@ -1933,11 +1904,10 @@ Index: alpine-2.23.2/pith/indxtype.h iNewsAndTo, iToAndNews, iNewsAndRecips, iRecipsAndNews, iFromTo, iFromToNotNews, iFrom, iTo, iSender, iCc, iNews, iRecips, iCurNews, iArrow, -Index: alpine-2.23.2/pith/mailindx.c -=================================================================== -*** alpine-2.23.2.orig/pith/mailindx.c ---- alpine-2.23.2/pith/mailindx.c -*************** init_index_format(char *format, INDEX_CO +diff -rc alpine-2.24/pith/mailindx.c alpine-2.24.fancy/pith/mailindx.c +*** alpine-2.24/pith/mailindx.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fancy/pith/mailindx.c 2020-10-10 00:26:49.300150359 -0600 +*************** *** 229,234 **** --- 229,235 ---- case iSTime: @@ -1947,7 +1917,7 @@ Index: alpine-2.23.2/pith/mailindx.c case iPrioAlpha: (*answer)[column].req_width = 7; break; -*************** static INDEX_PARSE_T itokens[] = { +*************** *** 456,461 **** --- 457,463 ---- {"FROMORTONOTNEWS", iFromToNotNews, FOR_INDEX}, @@ -1957,7 +1927,7 @@ Index: alpine-2.23.2/pith/mailindx.c {"SIZENARROW", iSizeNarrow, FOR_INDEX}, {"KSIZE", iKSize, FOR_INDEX}, {"SUBJECT", iSubject, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, -*************** static IndexColType fixed_ctypes[] = { +*************** *** 954,960 **** iSDateTimeS1, iSDateTimeS2, iSDateTimeS3, iSDateTimeS4, iSDateTimeIso24, iSDateTimeIsoS24, @@ -1974,7 +1944,7 @@ Index: alpine-2.23.2/pith/mailindx.c iPrio, iPrioBang, iPrioAlpha, iInit, iAtt, iTime24, iTime12, iTimezone, iMonAbb, iYear, iYear2Digit, iDay2Digit, iMon2Digit, iDayOfWeekAbb, iScore, iMonLong, iDayOfWeek -*************** setup_index_header_widths(MAILSTREAM *st +*************** *** 1147,1152 **** --- 1149,1155 ---- case iTime12: @@ -1984,7 +1954,7 @@ Index: alpine-2.23.2/pith/mailindx.c cdesc->actual_length = 7; cdesc->adjustment = Right; break; -*************** setup_index_header_widths(MAILSTREAM *st +*************** *** 1241,1247 **** cdesc->ctype != iNothing; cdesc++) @@ -2001,7 +1971,7 @@ Index: alpine-2.23.2/pith/mailindx.c cdesc->ctype == iSizeComma || cdesc->ctype == iDescripSize){ if(cdesc->actual_length == 0){ if((fix=cdesc->width) > 0){ /* had this reserved */ -*************** build_header_work(struct pine *state, MA +*************** *** 1627,1636 **** /* find next thread which is visible */ @@ -2026,7 +1996,7 @@ Index: alpine-2.23.2/pith/mailindx.c else thrd = NULL; } while(thrd -*************** format_index_index_line(INDEXDATA_S *ida +*************** *** 2042,2054 **** */ ice = copy_ice(ice); @@ -2052,7 +2022,7 @@ Index: alpine-2.23.2/pith/mailindx.c /* calculate contents of the required fields */ for(cdesc = ps_global->index_disp_format; cdesc->ctype != iNothing; cdesc++) -*************** format_index_index_line(INDEXDATA_S *ida +*************** *** 2550,2556 **** --- 2552,2581 ---- @@ -2085,7 +2055,7 @@ Index: alpine-2.23.2/pith/mailindx.c /* 0 ... 9999 */ if((l = fetch_size(idata)) < 10*1000L) snprintf(str, sizeof(str), "(%lu)", l); -*************** subj_str(INDEXDATA_S *idata, char *str, +*************** *** 5582,5591 **** if(pith_opt_condense_thread_cue) @@ -2106,7 +2076,7 @@ Index: alpine-2.23.2/pith/mailindx.c /* * width is < available strsize and -*************** from_str(IndexColType ctype, INDEXDATA_S +*************** *** 6211,6221 **** border = str + width; if(pith_opt_condense_thread_cue) @@ -2128,11 +2098,10 @@ Index: alpine-2.23.2/pith/mailindx.c fptr = str; if(thd) -Index: alpine-2.23.2/pith/pattern.c -=================================================================== -*** alpine-2.23.2.orig/pith/pattern.c ---- alpine-2.23.2/pith/pattern.c -*************** parse_action_slash(char *str, ACTION_S * +diff -rc alpine-2.24/pith/pattern.c alpine-2.24.fancy/pith/pattern.c +*** alpine-2.24/pith/pattern.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fancy/pith/pattern.c 2020-10-10 00:26:49.308150564 -0600 +*************** *** 1756,1762 **** SortOrder def_sort; int def_sort_rev; @@ -2149,13 +2118,12 @@ Index: alpine-2.23.2/pith/pattern.c action->sort_is_set = 1; action->sortorder = def_sort; action->revsort = (def_sort_rev ? 1 : 0); -Index: alpine-2.23.2/pith/pine.hlp -=================================================================== -*** alpine-2.23.2.orig/pith/pine.hlp ---- alpine-2.23.2/pith/pine.hlp -*************** There are also additional details on -*** 4839,4844 **** ---- 4839,4845 ---- +diff -rc alpine-2.24/pith/pine.hlp alpine-2.24.fancy/pith/pine.hlp +*** alpine-2.24/pith/pine.hlp 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fancy/pith/pine.hlp 2020-10-10 00:26:49.316150767 -0600 +*************** +*** 5006,5011 **** +--- 5006,5012 ----

  • OPTION:
  • OPTION:
  • OPTION: @@ -2163,9 +2131,9 @@ Index: alpine-2.23.2/pith/pine.hlp
  • OPTION:
  • OPTION:
  • OPTION: -*************** the names of the carbon copy addresses o -*** 6780,6785 **** ---- 6781,6943 ---- +*************** +*** 6947,6952 **** +--- 6948,7110 ---- <End of help on this topic> @@ -2329,9 +2297,9 @@ Index: alpine-2.23.2/pith/pine.hlp ======= h_index_cmd_whereis ======= -*************** The progression of sizes used looks like -*** 20325,20330 **** ---- 20483,20496 ---- +*************** +*** 20526,20531 **** +--- 20684,20697 ----

    @@ -2346,9 +2314,9 @@ Index: alpine-2.23.2/pith/pine.hlp

    SIZENARROW
    This token represents the total size, in bytes, of the message. -*************** command, then it will not be re-sorted u -*** 23948,23953 **** ---- 24114,24158 ---- +*************** +*** 24214,24219 **** +--- 24380,24424 ---- <End of help on this topic> @@ -2394,9 +2362,9 @@ Index: alpine-2.23.2/pith/pine.hlp ====== h_config_other_startup ===== -*************** Reply Use, Forward Use, and Compose Use. -*** 32059,32064 **** ---- 32264,32286 ---- +*************** +*** 32288,32293 **** +--- 32493,32515 ---- <End of help on this topic> @@ -2420,11 +2388,10 @@ Index: alpine-2.23.2/pith/pine.hlp ====== h_config_news_cross_deletes ===== -Index: alpine-2.23.2/pith/sort.c -=================================================================== -*** alpine-2.23.2.orig/pith/sort.c ---- alpine-2.23.2/pith/sort.c -*************** Args: msgmap -- +diff -rc alpine-2.24/pith/sort.c alpine-2.24.fancy/pith/sort.c +*** alpine-2.24/pith/sort.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fancy/pith/sort.c 2020-10-10 00:26:49.316150767 -0600 +*************** *** 91,97 **** ----*/ void @@ -2441,7 +2408,7 @@ Index: alpine-2.23.2/pith/sort.c { long raw_current, i, j; unsigned long *sort = NULL; -*************** sort_folder(MAILSTREAM *stream, MSGNO_S +*************** *** 101,106 **** --- 101,115 ---- int current_rev; @@ -2459,7 +2426,7 @@ Index: alpine-2.23.2/pith/sort.c dprint((2, "Sorting by %s%s\n", sort_name(new_sort), new_rev ? "/reverse" : "")); -*************** percent_sorted(void) +*************** *** 530,549 **** * argument also means arrival/reverse. */ @@ -2502,7 +2469,7 @@ Index: alpine-2.23.2/pith/sort.c *def_sort_rev = 1; return(0); } -*************** decode_sort(char *sort_spec, SortOrder * +*************** *** 572,578 **** if(ps_global->sort_types[x] == EndofList) return(-1); @@ -2519,7 +2486,7 @@ Index: alpine-2.23.2/pith/sort.c *def_sort_rev = reverse; return(0); } -*************** reset_sort_order(unsigned int flags) +*************** *** 689,695 **** /* set default order */ @@ -2538,7 +2505,7 @@ Index: alpine-2.23.2/pith/sort.c if(ps_global->mail_stream && nonempty_patterns(rflags, &pstate)){ for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)){ -*************** reset_sort_order(unsigned int flags) +*************** *** 702,710 **** && pat->action->sort_is_set){ the_sort_order = pat->action->sortorder; @@ -2565,10 +2532,9 @@ Index: alpine-2.23.2/pith/sort.c sort_folder(ps_global->mail_stream, ps_global->msgmap, ! the_sort_order, sort_is_rev, flags, 1); } -Index: alpine-2.23.2/pith/sort.h -=================================================================== -*** alpine-2.23.2.orig/pith/sort.h ---- alpine-2.23.2/pith/sort.h +diff -rc alpine-2.24/pith/sort.h alpine-2.24.fancy/pith/sort.h +*** alpine-2.24/pith/sort.h 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fancy/pith/sort.h 2020-10-10 00:26:49.316150767 -0600 *************** *** 23,29 **** @@ -2586,7 +2552,7 @@ Index: alpine-2.23.2/pith/sort.h struct global_sort_data { MSGNO_S *msgmap; -*************** extern struct global_sort_data g_sort; +*************** *** 42,49 **** /* exported prototypes */ @@ -2605,11 +2571,10 @@ Index: alpine-2.23.2/pith/sort.h void reset_sort_order(unsigned); -Index: alpine-2.23.2/pith/state.c -=================================================================== -*** alpine-2.23.2.orig/pith/state.c ---- alpine-2.23.2/pith/state.c -*************** new_pine_struct(void) +diff -rc alpine-2.24/pith/state.c alpine-2.24.fancy/pith/state.c +*** alpine-2.24/pith/state.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fancy/pith/state.c 2020-10-10 00:26:49.324150972 -0600 +*************** *** 75,80 **** --- 75,81 ---- @@ -2619,13 +2584,12 @@ Index: alpine-2.23.2/pith/state.c p->def_sort = SortArrival; p->sort_types[0] = SortSubject; p->sort_types[1] = SortArrival; -Index: alpine-2.23.2/pith/state.h -=================================================================== -*** alpine-2.23.2.orig/pith/state.h ---- alpine-2.23.2/pith/state.h -*************** struct pine { -*** 148,153 **** ---- 148,155 ---- +diff -rc alpine-2.24/pith/state.h alpine-2.24.fancy/pith/state.h +*** alpine-2.24/pith/state.h 2020-10-10 00:24:28.208554703 -0600 +--- alpine-2.24.fancy/pith/state.h 2020-10-10 00:26:49.324150972 -0600 +*************** +*** 149,154 **** +--- 149,156 ---- 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 */ @@ -2634,9 +2598,9 @@ Index: alpine-2.23.2/pith/state.h unsigned restricted:1; unsigned tcptimeout:1; /* a tcp timeout is in progress */ -*************** struct pine { -*** 311,316 **** ---- 313,321 ---- +*************** +*** 312,317 **** +--- 314,322 ---- EditWhich ew_for_srch_take; SortOrder def_sort, /* Default sort type */ @@ -2646,11 +2610,10 @@ Index: alpine-2.23.2/pith/state.h sort_types[22]; int last_expire_year, last_expire_month; -Index: alpine-2.23.2/pith/thread.c -=================================================================== -*** alpine-2.23.2.orig/pith/thread.c ---- alpine-2.23.2/pith/thread.c -*************** static char rcsid[] = "$Id: thread.c 942 +diff -rc alpine-2.24/pith/thread.c alpine-2.24.fancy/pith/thread.c +*** alpine-2.24/pith/thread.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fancy/pith/thread.c 2020-10-10 00:26:49.324150972 -0600 +*************** *** 30,41 **** #include "../pith/mailcmd.h" #include "../pith/ablookup.h" @@ -2683,7 +2646,7 @@ Index: alpine-2.23.2/pith/thread.c void make_thrdflags_consistent(MAILSTREAM *, MSGNO_S *, PINETHRD_S *, int); THREADNODE *collapse_threadnode_tree(THREADNODE *); THREADNODE *collapse_threadnode_tree_sorted(THREADNODE *); -*************** THREADNODE *sort_threads_and_collapse( +*************** *** 43,48 **** --- 49,55 ---- THREADNODE *insert_tree_in_place(THREADNODE *, THREADNODE *); @@ -2693,7 +2656,7 @@ Index: alpine-2.23.2/pith/thread.c PINETHRD_S * -*************** void +*************** *** 95,114 **** set_flags_for_thread(MAILSTREAM *stream, MSGNO_S *msgmap, int f, PINETHRD_S *thrd, int v) { @@ -2738,7 +2701,7 @@ Index: alpine-2.23.2/pith/thread.c if(bthrd) set_flags_for_thread(stream, msgmap, f, bthrd, v); } -*************** erase_threading_info(MAILSTREAM *stream, +*************** *** 122,128 **** MESSAGECACHE *mc; PINELT_S *peltp; @@ -2755,7 +2718,7 @@ Index: alpine-2.23.2/pith/thread.c return; ps_global->view_skipped_index = 0; -*************** sort_thread_callback(MAILSTREAM *stream, +*************** *** 155,161 **** PINETHRD_S *thrd = NULL; unsigned long msgno, rawno; @@ -2772,7 +2735,7 @@ Index: alpine-2.23.2/pith/thread.c char *dup_chk = NULL; -*************** sort_thread_callback(MAILSTREAM *stream, +*************** *** 168,177 **** * way. If the dummy node is at the top-level, then its children are * promoted to the top-level as separate threads. @@ -2796,7 +2759,7 @@ Index: alpine-2.23.2/pith/thread.c /* dup_chk is like sort with an origin of 1 */ dup_chk = (char *) fs_get((mn_get_nmsgs(g_sort.msgmap)+1) * sizeof(char)); -*************** sort_thread_callback(MAILSTREAM *stream, +*************** *** 182,188 **** (void) sort_thread_flatten(collapsed_tree, stream, &g_sort.msgmap->sort[1], @@ -2813,7 +2776,7 @@ Index: alpine-2.23.2/pith/thread.c /* reset the inverse array */ msgno_reset_isort(g_sort.msgmap); -*************** sort_thread_callback(MAILSTREAM *stream, +*************** *** 340,351 **** else{ thrd = fetch_head_thread(stream); @@ -2842,7 +2805,7 @@ Index: alpine-2.23.2/pith/thread.c if(thrd->next){ PINETHRD_S *nthrd; -*************** sort_thread_callback(MAILSTREAM *stream, +*************** *** 359,367 **** MN_COLL)); } @@ -2864,7 +2827,7 @@ Index: alpine-2.23.2/pith/thread.c thrd = NULL; } } -*************** make_thrdflags_consistent(MAILSTREAM *st +*************** *** 412,418 **** int a_parent_is_collapsed) { @@ -2881,7 +2844,7 @@ Index: alpine-2.23.2/pith/thread.c if(!thrd) return; -*************** make_thrdflags_consistent(MAILSTREAM *st +*************** *** 430,437 **** set_lflag(stream, msgmap, msgno, MN_CHID, 0); } @@ -2900,7 +2863,7 @@ Index: alpine-2.23.2/pith/thread.c if(nthrd) make_thrdflags_consistent(stream, msgmap, nthrd, a_parent_is_collapsed -*************** make_thrdflags_consistent(MAILSTREAM *st +*************** *** 440,447 **** MN_COLL)); } @@ -2919,7 +2882,7 @@ Index: alpine-2.23.2/pith/thread.c if(bthrd) make_thrdflags_consistent(stream, msgmap, bthrd, a_parent_is_collapsed); -*************** calculate_visible_threads(MAILSTREAM *st +*************** *** 488,496 **** long * sort_thread_flatten(THREADNODE *node, MAILSTREAM *stream, @@ -2941,7 +2904,7 @@ Index: alpine-2.23.2/pith/thread.c if(node){ if(node->num > 0L && node->num <= maxno){ /* holes happen */ -*************** sort_thread_flatten(THREADNODE *node, MA +*************** *** 498,503 **** --- 512,520 ---- *entry = node->num; @@ -2953,7 +2916,7 @@ Index: alpine-2.23.2/pith/thread.c /* * Build a richer threading structure that will help us paint * and operate on threads and subthreads. -*************** sort_thread_flatten(THREADNODE *node, MA +*************** *** 506,525 **** if(newthrd){ entry++; @@ -3027,7 +2990,7 @@ Index: alpine-2.23.2/pith/thread.c } return(entry); -*************** msgno_thread_info(MAILSTREAM *stream, lo +*************** *** 788,794 **** */ void @@ -3044,7 +3007,7 @@ Index: alpine-2.23.2/pith/thread.c { int collapsed, adjust_current = 0; PINETHRD_S *thrd = NULL, *nthrd; -*************** collapse_or_expand(struct pine *state, M +*************** *** 841,847 **** if(!thrd) return; @@ -3061,7 +3024,7 @@ Index: alpine-2.23.2/pith/thread.c if(collapsed){ msgno = mn_raw2m(msgmap, thrd->rawno); -*************** collapse_or_expand(struct pine *state, M +*************** *** 859,871 **** msgno = mn_raw2m(msgmap, thrd->rawno); if(msgno > 0L && msgno <= mn_get_total(msgmap)){ @@ -3090,7 +3053,7 @@ Index: alpine-2.23.2/pith/thread.c q_status_message(SM_ORDER, 0, 1, _("No thread to collapse or expand on this line")); -*************** count_flags_in_thread(MAILSTREAM *stream +*************** *** 952,969 **** unsigned long count = 0; PINETHRD_S *nthrd, *bthrd; @@ -3130,7 +3093,7 @@ Index: alpine-2.23.2/pith/thread.c if(bthrd) count += count_flags_in_thread(stream, bthrd, flags); } -*************** int +*************** *** 1051,1070 **** mark_msgs_in_thread(MAILSTREAM *stream, PINETHRD_S *thrd, MSGNO_S *msgmap) { @@ -3174,7 +3137,7 @@ Index: alpine-2.23.2/pith/thread.c if(bthrd) count += mark_msgs_in_thread(stream, bthrd, msgmap); } -*************** set_thread_lflags(MAILSTREAM *stream, PI +*************** *** 1098,1104 **** /* flags to set or clear */ /* set or clear? */ @@ -3191,7 +3154,7 @@ Index: alpine-2.23.2/pith/thread.c PINETHRD_S *nthrd, *bthrd; if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs) -*************** set_thread_lflags(MAILSTREAM *stream, PI +*************** *** 1122,1135 **** if(msgno > 0L && flags == MN_CHID2 && v == 1) clear_index_cache_ent(stream, msgno, 0); @@ -3222,7 +3185,7 @@ Index: alpine-2.23.2/pith/thread.c if(bthrd) set_thread_lflags(stream, bthrd, msgmap, flags, v); } -*************** to_us_symbol_for_thread(MAILSTREAM *stre +*************** *** 1218,1236 **** char to_us = ' '; char branch_to_us = ' '; @@ -3264,7 +3227,7 @@ Index: alpine-2.23.2/pith/thread.c bthrd = fetch_thread(stream, thrd->branch); if(bthrd) branch_to_us = to_us_symbol_for_thread(stream, bthrd, consider_flagged); -*************** to_us_symbol_for_thread(MAILSTREAM *stre +*************** *** 1280,1286 **** break; } @@ -3281,7 +3244,7 @@ Index: alpine-2.23.2/pith/thread.c to_us = '+'; if(to_us == ' ' && F_ON(F_MARK_FOR_CC,ps_global)) -*************** set_thread_subtree(MAILSTREAM *stream, P +*************** *** 1328,1334 **** set_lflag(stream, msgmap, msgno, flags, v); @@ -3299,7 +3262,7 @@ Index: alpine-2.23.2/pith/thread.c nthrd = fetch_thread(stream, thrd->next); if(nthrd) set_thread_subtree(stream, nthrd, msgmap, v, flags); -*************** view_thread(struct pine *state, MAILSTRE +*************** *** 1368,1375 **** if(rawno) thrd = fetch_thread(stream, rawno); @@ -3318,7 +3281,7 @@ Index: alpine-2.23.2/pith/thread.c if(!thrd) return 0; -*************** unview_thread(struct pine *state, MAILST +*************** *** 1433,1439 **** thrd = fetch_thread(stream, rawno); @@ -3335,7 +3298,7 @@ Index: alpine-2.23.2/pith/thread.c if(!topthrd) return 0; -*************** void +*************** *** 1539,1544 **** --- 1591,1597 ---- set_search_bit_for_thread(MAILSTREAM *stream, PINETHRD_S *thrd, SEARCHSET **msgset) @@ -3345,7 +3308,7 @@ Index: alpine-2.23.2/pith/thread.c if(!(stream && thrd)) return; -*************** set_search_bit_for_thread(MAILSTREAM *st +*************** *** 1547,1561 **** && (!(msgset && *msgset) || in_searchset(*msgset, thrd->rawno))) mm_searched(stream, thrd->rawno); @@ -3985,11 +3948,10 @@ Index: alpine-2.23.2/pith/thread.c + || sort == SortSize; + } + -Index: alpine-2.23.2/pith/thread.h -=================================================================== -*** alpine-2.23.2.orig/pith/thread.h ---- alpine-2.23.2/pith/thread.h -*************** typedef struct pine_thrd { +diff -rc alpine-2.24/pith/thread.h alpine-2.24.fancy/pith/thread.h +*** alpine-2.24/pith/thread.h 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fancy/pith/thread.h 2020-10-10 00:26:49.328151074 -0600 +*************** *** 38,43 **** --- 38,44 ---- unsigned long nextthd; /* next thread, only tops have this */ @@ -3999,7 +3961,7 @@ Index: alpine-2.23.2/pith/thread.h unsigned long head; /* head of the whole thread list */ } PINETHRD_S; -*************** void erase_threading_info(MAILSTRE +*************** *** 93,99 **** void sort_thread_callback(MAILSTREAM *, THREADNODE *); void collapse_threads(MAILSTREAM *, MSGNO_S *, PINETHRD_S *); @@ -4016,7 +3978,7 @@ Index: alpine-2.23.2/pith/thread.h 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); -*************** int view_thread(struct pine *, MAI +*************** *** 107,112 **** int unview_thread(struct pine *, MAILSTREAM *, MSGNO_S *); PINETHRD_S *find_thread_by_number(MAILSTREAM *, MSGNO_S *, long, PINETHRD_S *); @@ -4049,11 +4011,10 @@ Index: alpine-2.23.2/pith/thread.h ! int allowed_thread_key(SortOrder sort); #endif /* PITH_THREAD_INCLUDED */ -Index: alpine-2.23.2/web/src/alpined.d/alpined.c -=================================================================== -*** alpine-2.23.2.orig/web/src/alpined.d/alpined.c ---- alpine-2.23.2/web/src/alpined.d/alpined.c -*************** PEConfigCmd(ClientData clientData, Tcl_I +diff -rc alpine-2.24/web/src/alpined.d/alpined.c alpine-2.24.fancy/web/src/alpined.d/alpined.c +*** alpine-2.24/web/src/alpined.d/alpined.c 2020-10-10 00:24:28.248555724 -0600 +--- alpine-2.24.fancy/web/src/alpined.d/alpined.c 2020-10-10 00:26:49.336151277 -0600 +*************** *** 2755,2761 **** init_save_defaults(); break; @@ -4070,7 +4031,7 @@ Index: alpine-2.23.2/web/src/alpined.d/alpined.c break; case V_VIEW_HDR_COLORS : set_custom_spec_colors(wps_global); -*************** PEMailboxCmd(ClientData clientData, Tcl_ +*************** *** 6331,6337 **** && mn_get_revsort(sp_msgmap(wps_global->mail_stream)) == reversed)) sort_folder(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), diff --git a/chappa-fillpara.patch b/chappa-fillpara.patch index be54ea0..8228985 100644 --- a/chappa-fillpara.patch +++ b/chappa-fillpara.patch @@ -1,6 +1,6 @@ -diff -rc alpine-2.23/alpine/mailview.c alpine-2.23.fillpara/alpine/mailview.c -*** alpine-2.23/alpine/mailview.c 2020-06-18 15:19:23.469318992 -0600 ---- alpine-2.23.fillpara/alpine/mailview.c 2020-06-18 16:08:12.153588516 -0600 +diff -rc alpine-2.24/alpine/mailview.c alpine-2.24.fillpara/alpine/mailview.c +*** alpine-2.24/alpine/mailview.c 2020-10-10 00:24:28.216554908 -0600 +--- alpine-2.24.fillpara/alpine/mailview.c 2020-10-10 00:26:56.228326921 -0600 *************** *** 205,211 **** --- 205,219 ---- @@ -50,9 +50,9 @@ diff -rc alpine-2.23/alpine/mailview.c alpine-2.23.fillpara/alpine/mailview.c if(we_cancel) cancel_busy_cue(-1); -diff -rc alpine-2.23/pico/basic.c alpine-2.23.fillpara/pico/basic.c -*** alpine-2.23/pico/basic.c 2020-06-18 15:19:23.437319046 -0600 ---- alpine-2.23.fillpara/pico/basic.c 2020-06-18 16:08:12.153588516 -0600 +diff -rc alpine-2.24/pico/basic.c alpine-2.24.fillpara/pico/basic.c +*** alpine-2.24/pico/basic.c 2020-10-10 00:24:28.180553991 -0600 +--- alpine-2.24.fillpara/pico/basic.c 2020-10-10 00:26:56.228326921 -0600 *************** *** 26,34 **** * framing, are hard. @@ -323,9 +323,9 @@ diff -rc alpine-2.23/pico/basic.c alpine-2.23.fillpara/pico/basic.c curwp->w_dotp = lforw(curwp->w_dotp); curwp->w_doto = llength(curwp->w_dotp); -diff -rc alpine-2.23/pico/efunc.h alpine-2.23.fillpara/pico/efunc.h -*** alpine-2.23/pico/efunc.h 2020-06-18 15:19:23.437319046 -0600 ---- alpine-2.23.fillpara/pico/efunc.h 2020-06-18 16:08:12.153588516 -0600 +diff -rc alpine-2.24/pico/efunc.h alpine-2.24.fillpara/pico/efunc.h +*** alpine-2.24/pico/efunc.h 2020-10-10 00:24:28.180553991 -0600 +--- alpine-2.24.fillpara/pico/efunc.h 2020-10-10 00:26:56.228326921 -0600 *************** *** 253,262 **** extern int fillpara(int, int); @@ -355,9 +355,9 @@ diff -rc alpine-2.23/pico/efunc.h alpine-2.23.fillpara/pico/efunc.h #endif /* EFUNC_H */ + -diff -rc alpine-2.23/pico/line.c alpine-2.23.fillpara/pico/line.c -*** alpine-2.23/pico/line.c 2020-06-18 15:19:23.437319046 -0600 ---- alpine-2.23.fillpara/pico/line.c 2020-06-18 16:08:12.153588516 -0600 +diff -rc alpine-2.24/pico/line.c alpine-2.24.fillpara/pico/line.c +*** alpine-2.24/pico/line.c 2020-10-10 00:24:28.180553991 -0600 +--- alpine-2.24.fillpara/pico/line.c 2020-10-10 00:26:56.280328247 -0600 *************** *** 612,627 **** lisblank(LINE *line) @@ -389,9 +389,9 @@ diff -rc alpine-2.23/pico/line.c alpine-2.23.fillpara/pico/line.c return(FALSE); return(TRUE); -diff -rc alpine-2.23/pico/osdep/color.h alpine-2.23.fillpara/pico/osdep/color.h -*** alpine-2.23/pico/osdep/color.h 2020-06-18 15:19:23.437319046 -0600 ---- alpine-2.23.fillpara/pico/osdep/color.h 2020-06-18 16:08:12.153588516 -0600 +diff -rc alpine-2.24/pico/osdep/color.h alpine-2.24.fillpara/pico/osdep/color.h +*** alpine-2.24/pico/osdep/color.h 2020-10-10 00:24:28.180553991 -0600 +--- alpine-2.24.fillpara/pico/osdep/color.h 2020-10-10 00:26:56.292328552 -0600 *************** *** 33,38 **** --- 33,39 ---- @@ -402,9 +402,9 @@ diff -rc alpine-2.23/pico/osdep/color.h alpine-2.23.fillpara/pico/osdep/color.h #endif /* PICO_OSDEP_COLOR_INCLUDED */ -diff -rc alpine-2.23/pico/search.c alpine-2.23.fillpara/pico/search.c -*** alpine-2.23/pico/search.c 2020-06-18 15:19:23.437319046 -0600 ---- alpine-2.23.fillpara/pico/search.c 2020-06-18 16:08:12.153588516 -0600 +diff -rc alpine-2.24/pico/search.c alpine-2.24.fillpara/pico/search.c +*** alpine-2.24/pico/search.c 2020-10-10 00:24:28.180553991 -0600 +--- alpine-2.24.fillpara/pico/search.c 2020-10-10 00:26:56.304328858 -0600 *************** *** 36,41 **** --- 36,42 ---- @@ -483,9 +483,9 @@ diff -rc alpine-2.23/pico/search.c alpine-2.23.fillpara/pico/search.c + return(TRUE); + } + -diff -rc alpine-2.23/pico/word.c alpine-2.23.fillpara/pico/word.c -*** alpine-2.23/pico/word.c 2020-06-18 15:19:23.437319046 -0600 ---- alpine-2.23.fillpara/pico/word.c 2020-06-18 16:08:12.153588516 -0600 +diff -rc alpine-2.24/pico/word.c alpine-2.24.fillpara/pico/word.c +*** alpine-2.24/pico/word.c 2020-10-10 00:24:28.180553991 -0600 +--- alpine-2.24.fillpara/pico/word.c 2020-10-10 00:26:56.316329164 -0600 *************** *** 25,34 **** */ @@ -1229,9 +1229,9 @@ diff -rc alpine-2.23/pico/word.c alpine-2.23.fillpara/pico/word.c + return get_indent_raw_line(q, GLine, buf, buflen, k, plb); + } + -diff -rc alpine-2.23/pith/charconv/utf8.c alpine-2.23.fillpara/pith/charconv/utf8.c -*** alpine-2.23/pith/charconv/utf8.c 2020-06-18 15:19:23.465318999 -0600 ---- alpine-2.23.fillpara/pith/charconv/utf8.c 2020-06-18 16:08:12.153588516 -0600 +diff -rc alpine-2.24/pith/charconv/utf8.c alpine-2.24.fillpara/pith/charconv/utf8.c +*** alpine-2.24/pith/charconv/utf8.c 2020-10-10 00:24:28.208554703 -0600 +--- alpine-2.24.fillpara/pith/charconv/utf8.c 2020-10-10 00:26:56.320329266 -0600 *************** *** 1066,1071 **** --- 1066,1121 ---- @@ -1291,9 +1291,9 @@ diff -rc alpine-2.23/pith/charconv/utf8.c alpine-2.23.fillpara/pith/charconv/utf * 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.23/pith/charconv/utf8.h alpine-2.23.fillpara/pith/charconv/utf8.h -*** alpine-2.23/pith/charconv/utf8.h 2020-06-18 15:19:23.465318999 -0600 ---- alpine-2.23.fillpara/pith/charconv/utf8.h 2020-06-18 16:08:12.153588516 -0600 +diff -rc alpine-2.24/pith/charconv/utf8.h alpine-2.24.fillpara/pith/charconv/utf8.h +*** alpine-2.24/pith/charconv/utf8.h 2020-10-10 00:24:28.208554703 -0600 +--- alpine-2.24.fillpara/pith/charconv/utf8.h 2020-10-10 00:26:56.328329469 -0600 *************** *** 81,86 **** --- 81,87 ---- @@ -1304,9 +1304,9 @@ diff -rc alpine-2.23/pith/charconv/utf8.h alpine-2.23.fillpara/pith/charconv/utf 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.23/pith/color.c alpine-2.23.fillpara/pith/color.c -*** alpine-2.23/pith/color.c 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.fillpara/pith/color.c 2020-06-18 16:08:12.153588516 -0600 +diff -rc alpine-2.24/pith/color.c alpine-2.24.fillpara/pith/color.c +*** alpine-2.24/pith/color.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fillpara/pith/color.c 2020-10-10 00:26:56.344329877 -0600 *************** *** 21,27 **** #include "../pith/state.h" @@ -1517,9 +1517,9 @@ diff -rc alpine-2.23/pith/color.c alpine-2.23.fillpara/pith/color.c } -diff -rc alpine-2.23/pith/color.h alpine-2.23.fillpara/pith/color.h -*** alpine-2.23/pith/color.h 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.fillpara/pith/color.h 2020-06-18 16:08:12.153588516 -0600 +diff -rc alpine-2.24/pith/color.h alpine-2.24.fillpara/pith/color.h +*** alpine-2.24/pith/color.h 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fillpara/pith/color.h 2020-10-10 00:26:56.364330387 -0600 *************** *** 22,27 **** --- 22,45 ---- @@ -1557,9 +1557,9 @@ diff -rc alpine-2.23/pith/color.h alpine-2.23.fillpara/pith/color.h int color_a_quote(long, char *, LT_INS_S **, void *); void free_spec_colors(SPEC_COLOR_S **); -diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c -*** alpine-2.23/pith/filter.c 2020-06-18 15:19:23.465318999 -0600 ---- alpine-2.23.fillpara/pith/filter.c 2020-06-18 16:08:12.157588526 -0600 +diff -rc alpine-2.24/pith/filter.c alpine-2.24.fillpara/pith/filter.c +*** alpine-2.24/pith/filter.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fillpara/pith/filter.c 2020-10-10 00:26:56.380330795 -0600 *************** *** 46,51 **** --- 46,52 ---- @@ -1571,8 +1571,8 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c #include "../pith/pipe.h" #include "../pith/status.h" *************** -*** 9453,9458 **** ---- 9454,9464 ---- +*** 9454,9459 **** +--- 9455,9465 ---- margin_r, indent; char special[256]; @@ -1585,8 +1585,8 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c #define WRAP_MARG_L(F) (((WRAP_S *)(F)->opt)->margin_l) *************** -*** 9494,9499 **** ---- 9500,9511 ---- +*** 9495,9500 **** +--- 9501,9512 ---- #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) @@ -1600,8 +1600,8 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c if((F)->linep == WRAP_LASTC(F)){ \ size_t offset = (F)->linep - (F)->line; \ *************** -*** 9571,9576 **** ---- 9583,9590 ---- +*** 9572,9577 **** +--- 9584,9591 ---- case CCR : /* CRLF or CR in text ? */ state = BOL; /* either way, handle start */ @@ -1611,7 +1611,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c /* wrapped line? */ if(f->f2 == 0 && WRAP_SPC_LEN(f) && WRAP_TRL_SPC(f)){ *************** -*** 9664,9670 **** +*** 9665,9671 **** case BOL : if(WRAP_FLOW(f)){ @@ -1619,7 +1619,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c WRAP_FL_QC(f) = 1; /* init it */ state = FL_QLEV; /* go collect it */ } ---- 9678,9688 ---- +--- 9679,9689 ---- case BOL : if(WRAP_FLOW(f)){ @@ -1632,7 +1632,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c state = FL_QLEV; /* go collect it */ } *************** -*** 9678,9684 **** +*** 9679,9685 **** } /* quote level change implies new paragraph */ @@ -1640,7 +1640,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c WRAP_FL_QD(f) = 0; if(WRAP_HARD(f) == 0){ WRAP_HARD(f) = 1; ---- 9696,9711 ---- +--- 9697,9712 ---- } /* quote level change implies new paragraph */ @@ -1658,7 +1658,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c if(WRAP_HARD(f) == 0){ WRAP_HARD(f) = 1; *************** -*** 9730,9737 **** +*** 9731,9738 **** break; case FL_QLEV : @@ -1667,7 +1667,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c } else { /* if EMBEDed, process it and return here */ ---- 9757,9768 ---- +--- 9758,9769 ---- break; case FL_QLEV : @@ -1681,7 +1681,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c else { /* if EMBEDed, process it and return here */ *************** -*** 9743,9749 **** +*** 9744,9750 **** } /* quote level change signals new paragraph */ @@ -1689,7 +1689,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c WRAP_FL_QD(f) = WRAP_FL_QC(f); if(WRAP_HARD(f) == 0){ /* add hard newline */ WRAP_HARD(f) = 1; /* hard newline */ ---- 9774,9789 ---- +--- 9775,9790 ---- } /* quote level change signals new paragraph */ @@ -1707,8 +1707,8 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c if(WRAP_HARD(f) == 0){ /* add hard newline */ WRAP_HARD(f) = 1; /* hard newline */ *************** -*** 9800,9805 **** ---- 9840,9852 ---- +*** 9801,9806 **** +--- 9841,9853 ---- state = FL_SIG; break; @@ -1723,7 +1723,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c state = DFL; goto case_dfl; /* handle c like DFL */ *************** -*** 9816,9822 **** +*** 9817,9823 **** &eob); /* note any embedded*/ wrap_eol(f, 1, &ip, &eib, &op, &eob); /* plunk down newline */ @@ -1731,7 +1731,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c &op, &eob); /* write any prefix */ } ---- 9863,9869 ---- +--- 9864,9870 ---- &eob); /* note any embedded*/ wrap_eol(f, 1, &ip, &eib, &op, &eob); /* plunk down newline */ @@ -1740,7 +1740,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c } *************** -*** 10313,10319 **** +*** 10314,10320 **** wrap_flush_embed(f, &ip, &eib, &op, &eob); wrap_eol(f, 1, &ip, &eib, &op, &eob); /* plunk down newline */ @@ -1748,7 +1748,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c &eob); /* write any prefix */ } ---- 10360,10366 ---- +--- 10361,10367 ---- wrap_flush_embed(f, &ip, &eib, &op, &eob); wrap_eol(f, 1, &ip, &eib, &op, &eob); /* plunk down newline */ @@ -1757,8 +1757,8 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c } *************** -*** 10386,10391 **** ---- 10433,10445 ---- +*** 10387,10392 **** +--- 10434,10446 ---- if(WRAP_COLOR(f)) free_color_pair(&WRAP_COLOR(f)); @@ -1773,7 +1773,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c so_give(&WRAP_SPACES(f)); fs_give((void **) &f->opt); /* free wrap widths struct */ *************** -*** 10736,10742 **** +*** 10737,10743 **** { int j, i; COLOR_PAIR *col = NULL; @@ -1781,7 +1781,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c if(ps_global->VAR_QUOTE_REPLACE_STRING){ get_pair(ps_global->VAR_QUOTE_REPLACE_STRING, &prefix, &last_prefix, 0, 0); ---- 10790,10797 ---- +--- 10791,10798 ---- { int j, i; COLOR_PAIR *col = NULL; @@ -1791,7 +1791,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c if(ps_global->VAR_QUOTE_REPLACE_STRING){ get_pair(ps_global->VAR_QUOTE_REPLACE_STRING, &prefix, &last_prefix, 0, 0); *************** -*** 10745,10754 **** +*** 10746,10755 **** last_prefix = NULL; } } @@ -1802,7 +1802,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c && ps_global->VAR_QUOTE1_FORE_COLOR && ps_global->VAR_QUOTE1_BACK_COLOR && (col = new_color_pair(ps_global->VAR_QUOTE1_FORE_COLOR, ---- 10800,10821 ---- +--- 10801,10822 ---- last_prefix = NULL; } } @@ -1826,7 +1826,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c && ps_global->VAR_QUOTE1_BACK_COLOR && (col = new_color_pair(ps_global->VAR_QUOTE1_FORE_COLOR, *************** -*** 10756,10762 **** +*** 10757,10763 **** && pico_is_good_colorpair(col)){ GF_COLOR_PUTC(f, col); } @@ -1834,7 +1834,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c && ps_global->VAR_QUOTE2_FORE_COLOR && ps_global->VAR_QUOTE2_BACK_COLOR && (col = new_color_pair(ps_global->VAR_QUOTE2_FORE_COLOR, ---- 10823,10829 ---- +--- 10824,10830 ---- && pico_is_good_colorpair(col)){ GF_COLOR_PUTC(f, col); } @@ -1843,7 +1843,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c && ps_global->VAR_QUOTE2_BACK_COLOR && (col = new_color_pair(ps_global->VAR_QUOTE2_FORE_COLOR, *************** -*** 10764,10770 **** +*** 10765,10771 **** && pico_is_good_colorpair(col)){ GF_COLOR_PUTC(f, col); } @@ -1851,7 +1851,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c && ps_global->VAR_QUOTE3_FORE_COLOR && ps_global->VAR_QUOTE3_BACK_COLOR && (col = new_color_pair(ps_global->VAR_QUOTE3_FORE_COLOR, ---- 10831,10837 ---- +--- 10832,10838 ---- && pico_is_good_colorpair(col)){ GF_COLOR_PUTC(f, col); } @@ -1860,7 +1860,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c && ps_global->VAR_QUOTE3_BACK_COLOR && (col = new_color_pair(ps_global->VAR_QUOTE3_FORE_COLOR, *************** -*** 10778,10820 **** +*** 10779,10821 **** } } @@ -1904,7 +1904,7 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c return 0; } ---- 10845,10891 ---- +--- 10846,10892 ---- } } @@ -1953,8 +1953,8 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c return 0; } *************** -*** 10846,10851 **** ---- 10917,10928 ---- +*** 10847,10852 **** +--- 10918,10929 ---- 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; @@ -1968,8 +1968,8 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c return((void *) wrap); } *************** -*** 11289,11295 **** ---- 11366,11580 ---- +*** 11290,11296 **** +--- 11367,11581 ---- } \ } @@ -2185,9 +2185,9 @@ diff -rc alpine-2.23/pith/filter.c alpine-2.23.fillpara/pith/filter.c /* * this simple filter accumulates characters until a newline, offers it -diff -rc alpine-2.23/pith/filter.h alpine-2.23.fillpara/pith/filter.h -*** alpine-2.23/pith/filter.h 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.fillpara/pith/filter.h 2020-06-18 16:08:12.157588526 -0600 +diff -rc alpine-2.24/pith/filter.h alpine-2.24.fillpara/pith/filter.h +*** alpine-2.24/pith/filter.h 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fillpara/pith/filter.h 2020-10-10 00:26:56.380330795 -0600 *************** *** 217,222 **** --- 217,223 ---- @@ -2198,9 +2198,9 @@ diff -rc alpine-2.23/pith/filter.h alpine-2.23.fillpara/pith/filter.h void *gf_url_hilite_opt(URL_HILITE_S *, HANDLE_S **, int); void free_filter_module_globals(void); -diff -rc alpine-2.23/pith/filttype.h alpine-2.23.fillpara/pith/filttype.h -*** alpine-2.23/pith/filttype.h 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.fillpara/pith/filttype.h 2020-06-18 16:08:12.157588526 -0600 +diff -rc alpine-2.24/pith/filttype.h alpine-2.24.fillpara/pith/filttype.h +*** alpine-2.24/pith/filttype.h 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fillpara/pith/filttype.h 2020-10-10 00:26:56.384330897 -0600 *************** *** 36,41 **** --- 36,43 ---- @@ -2212,9 +2212,9 @@ diff -rc alpine-2.23/pith/filttype.h alpine-2.23.fillpara/pith/filttype.h void *opt; /* optional per instance data */ void *data; /* misc internal data pointer */ unsigned char queue[1 + GF_MAXBUF]; -diff -rc alpine-2.23/pith/mailview.c alpine-2.23.fillpara/pith/mailview.c -*** alpine-2.23/pith/mailview.c 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.fillpara/pith/mailview.c 2020-06-18 16:08:12.157588526 -0600 +diff -rc alpine-2.24/pith/mailview.c alpine-2.24.fillpara/pith/mailview.c +*** alpine-2.24/pith/mailview.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fillpara/pith/mailview.c 2020-10-10 00:26:56.396331203 -0600 *************** *** 55,61 **** #include "../pith/escapes.h" @@ -2472,9 +2472,9 @@ diff -rc alpine-2.23/pith/mailview.c alpine-2.23.fillpara/pith/mailview.c #define UES_LEN 12 #define UES_MAX 32 -diff -rc alpine-2.23/pith/mailview.h alpine-2.23.fillpara/pith/mailview.h -*** alpine-2.23/pith/mailview.h 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.fillpara/pith/mailview.h 2020-06-18 16:08:12.157588526 -0600 +diff -rc alpine-2.24/pith/mailview.h alpine-2.24.fillpara/pith/mailview.h +*** alpine-2.24/pith/mailview.h 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fillpara/pith/mailview.h 2020-10-10 00:26:56.404331406 -0600 *************** *** 146,151 **** --- 146,152 ---- @@ -2485,9 +2485,9 @@ diff -rc alpine-2.23/pith/mailview.h alpine-2.23.fillpara/pith/mailview.h 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.23/pith/osdep/color.c alpine-2.23.fillpara/pith/osdep/color.c -*** alpine-2.23/pith/osdep/color.c 2020-06-18 15:19:23.465318999 -0600 ---- alpine-2.23.fillpara/pith/osdep/color.c 2020-06-18 16:08:12.157588526 -0600 +diff -rc alpine-2.24/pith/osdep/color.c alpine-2.24.fillpara/pith/osdep/color.c +*** alpine-2.24/pith/osdep/color.c 2020-10-10 00:24:28.208554703 -0600 +--- alpine-2.24.fillpara/pith/osdep/color.c 2020-10-10 00:26:56.416331712 -0600 *************** *** 32,38 **** @@ -3792,9 +3792,9 @@ diff -rc alpine-2.23/pith/osdep/color.c alpine-2.23.fillpara/pith/osdep/color.c + return allowed_qstr; + } + -diff -rc alpine-2.23/pith/osdep/color.h alpine-2.23.fillpara/pith/osdep/color.h -*** alpine-2.23/pith/osdep/color.h 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.fillpara/pith/osdep/color.h 2020-06-18 16:08:12.157588526 -0600 +diff -rc alpine-2.24/pith/osdep/color.h alpine-2.24.fillpara/pith/osdep/color.h +*** alpine-2.24/pith/osdep/color.h 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fillpara/pith/osdep/color.h 2020-10-10 00:26:56.436332222 -0600 *************** *** 17,22 **** --- 17,40 ---- @@ -3845,12 +3845,12 @@ diff -rc alpine-2.23/pith/osdep/color.h alpine-2.23.fillpara/pith/osdep/color.h ! void record_quote_string (QSTRING_S *); #endif /* PITH_OSDEP_COLOR_INCLUDED */ -diff -rc alpine-2.23/pith/pine.hlp alpine-2.23.fillpara/pith/pine.hlp -*** alpine-2.23/pith/pine.hlp 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.fillpara/pith/pine.hlp 2020-06-18 16:08:12.161588536 -0600 +diff -rc alpine-2.24/pith/pine.hlp alpine-2.24.fillpara/pith/pine.hlp +*** alpine-2.24/pith/pine.hlp 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fillpara/pith/pine.hlp 2020-10-10 00:26:56.460332833 -0600 *************** -*** 7903,7908 **** ---- 7903,7948 ---- +*** 8195,8200 **** +--- 8195,8240 ---- "type the character ^".

    @@ -3897,12 +3897,12 @@ diff -rc alpine-2.23/pith/pine.hlp alpine-2.23.fillpara/pith/pine.hlp <End of help on this topic> -diff -rc alpine-2.23/pith/reply.c alpine-2.23.fillpara/pith/reply.c -*** alpine-2.23/pith/reply.c 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.fillpara/pith/reply.c 2020-06-18 16:08:12.161588536 -0600 +diff -rc alpine-2.24/pith/reply.c alpine-2.24.fillpara/pith/reply.c +*** alpine-2.24/pith/reply.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fillpara/pith/reply.c 2020-10-10 00:26:56.460332833 -0600 *************** -*** 2839,2844 **** ---- 2839,2847 ---- +*** 2838,2843 **** +--- 2838,2846 ---- if(flow_res && ps_global->reply.use_flowed) wrapflags |= GFW_FLOW_RESULT; @@ -3913,7 +3913,7 @@ diff -rc alpine-2.23/pith/reply.c alpine-2.23.fillpara/pith/reply.c /* * The 80 will cause longer lines than what is likely *************** -*** 2932,2938 **** +*** 2931,2937 **** dq.do_color = 0; dq.delete_all = 1; @@ -3921,7 +3921,7 @@ diff -rc alpine-2.23/pith/reply.c alpine-2.23.fillpara/pith/reply.c filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq); } ---- 2935,2941 ---- +--- 2934,2940 ---- dq.do_color = 0; dq.delete_all = 1; @@ -3929,9 +3929,9 @@ diff -rc alpine-2.23/pith/reply.c alpine-2.23.fillpara/pith/reply.c filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq); } -diff -rc alpine-2.23/pith/state.c alpine-2.23.fillpara/pith/state.c -*** alpine-2.23/pith/state.c 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.fillpara/pith/state.c 2020-06-18 16:08:12.161588536 -0600 +diff -rc alpine-2.24/pith/state.c alpine-2.24.fillpara/pith/state.c +*** alpine-2.24/pith/state.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fillpara/pith/state.c 2020-10-10 00:26:56.464332936 -0600 *************** *** 235,240 **** --- 235,242 ---- @@ -3943,12 +3943,12 @@ diff -rc alpine-2.23/pith/state.c alpine-2.23.fillpara/pith/state.c if((*pps)->atmts){ int i; -diff -rc alpine-2.23/pith/state.h alpine-2.23.fillpara/pith/state.h -*** alpine-2.23/pith/state.h 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.fillpara/pith/state.h 2020-06-18 16:08:12.161588536 -0600 +diff -rc alpine-2.24/pith/state.h alpine-2.24.fillpara/pith/state.h +*** alpine-2.24/pith/state.h 2020-10-10 00:24:28.208554703 -0600 +--- alpine-2.24.fillpara/pith/state.h 2020-10-10 00:26:56.468333038 -0600 *************** -*** 260,265 **** ---- 260,267 ---- +*** 261,266 **** +--- 261,268 ---- SPEC_COLOR_S *hdr_colors; /* list of configured colors for view */ SPEC_COLOR_S *index_token_colors; /* list of configured colors for index */ @@ -3957,9 +3957,9 @@ diff -rc alpine-2.23/pith/state.h alpine-2.23.fillpara/pith/state.h short init_context; struct { -diff -rc alpine-2.23/pith/text.c alpine-2.23.fillpara/pith/text.c -*** alpine-2.23/pith/text.c 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.fillpara/pith/text.c 2020-06-18 16:08:12.161588536 -0600 +diff -rc alpine-2.24/pith/text.c alpine-2.24.fillpara/pith/text.c +*** alpine-2.24/pith/text.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fillpara/pith/text.c 2020-10-10 00:26:56.468333038 -0600 *************** *** 92,98 **** char *err, *charset; diff --git a/chappa-fromheader.patch b/chappa-fromheader.patch index d3bff19..50aac01 100644 --- a/chappa-fromheader.patch +++ b/chappa-fromheader.patch @@ -1,8 +1,8 @@ -diff -rc alpine-2.23/alpine/send.c alpine-2.23.fromheader/alpine/send.c -*** alpine-2.23/alpine/send.c 2020-06-18 15:19:23.465318999 -0600 ---- alpine-2.23.fromheader/alpine/send.c 2020-06-18 16:08:13.005590716 -0600 +diff -rc alpine-2.24/alpine/send.c alpine-2.24.fromheader/alpine/send.c +*** alpine-2.24/alpine/send.c 2020-10-10 00:24:28.212554806 -0600 +--- alpine-2.24.fromheader/alpine/send.c 2020-10-10 00:26:58.004372183 -0600 *************** -*** 909,915 **** +*** 908,914 **** 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, @@ -10,7 +10,7 @@ diff -rc alpine-2.23/alpine/send.c alpine-2.23.fromheader/alpine/send.c {"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}, ---- 909,915 ---- +--- 908,914 ---- 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, @@ -19,8 +19,8 @@ diff -rc alpine-2.23/alpine/send.c alpine-2.23.fromheader/alpine/send.c 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}, *************** -*** 2368,2373 **** ---- 2368,2378 ---- +*** 2372,2377 **** +--- 2372,2382 ---- he->rich_header = 0; } } @@ -33,7 +33,7 @@ diff -rc alpine-2.23/alpine/send.c alpine-2.23.fromheader/alpine/send.c he_from = he; break; *************** -*** 3105,3111 **** +*** 3109,3115 **** if(outgoing->return_path) mail_free_address(&outgoing->return_path); @@ -41,7 +41,7 @@ diff -rc alpine-2.23/alpine/send.c alpine-2.23.fromheader/alpine/send.c /* * Don't ever believe the sender that is there. ---- 3110,3118 ---- +--- 3114,3122 ---- if(outgoing->return_path) mail_free_address(&outgoing->return_path); @@ -51,12 +51,12 @@ diff -rc alpine-2.23/alpine/send.c alpine-2.23.fromheader/alpine/send.c /* * Don't ever believe the sender that is there. -diff -rc alpine-2.23/pith/conf.c alpine-2.23.fromheader/pith/conf.c -*** alpine-2.23/pith/conf.c 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.fromheader/pith/conf.c 2020-06-18 16:08:13.005590716 -0600 +diff -rc alpine-2.24/pith/conf.c alpine-2.24.fromheader/pith/conf.c +*** alpine-2.24/pith/conf.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fromheader/pith/conf.c 2020-10-10 00:26:58.004372183 -0600 *************** -*** 2930,2935 **** ---- 2930,2937 ---- +*** 2984,2989 **** +--- 2984,2991 ---- 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}, @@ -65,9 +65,9 @@ diff -rc alpine-2.23/pith/conf.c alpine-2.23.fromheader/pith/conf.c {"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", -diff -rc alpine-2.23/pith/conftype.h alpine-2.23.fromheader/pith/conftype.h -*** alpine-2.23/pith/conftype.h 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.fromheader/pith/conftype.h 2020-06-18 16:08:13.009590727 -0600 +diff -rc alpine-2.24/pith/conftype.h alpine-2.24.fromheader/pith/conftype.h +*** alpine-2.24/pith/conftype.h 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fromheader/pith/conftype.h 2020-10-10 00:26:58.004372183 -0600 *************** *** 410,415 **** --- 410,416 ---- @@ -78,12 +78,12 @@ diff -rc alpine-2.23/pith/conftype.h alpine-2.23.fromheader/pith/conftype.h F_SEND_WO_CONFIRM, F_USE_SENDER_NOT_X, F_BLANK_KEYMENU, -diff -rc alpine-2.23/pith/pine.hlp alpine-2.23.fromheader/pith/pine.hlp -*** alpine-2.23/pith/pine.hlp 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.fromheader/pith/pine.hlp 2020-06-18 16:08:13.017590747 -0600 +diff -rc alpine-2.24/pith/pine.hlp alpine-2.24.fromheader/pith/pine.hlp +*** alpine-2.24/pith/pine.hlp 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fromheader/pith/pine.hlp 2020-10-10 00:26:58.016372489 -0600 *************** -*** 29697,29702 **** ---- 29697,29718 ---- +*** 30135,30140 **** +--- 30135,30156 ---- <End of help on this topic> @@ -106,9 +106,9 @@ diff -rc alpine-2.23/pith/pine.hlp alpine-2.23.fromheader/pith/pine.hlp ====== h_config_use_sender_not_x ===== -diff -rc alpine-2.23/pith/send.c alpine-2.23.fromheader/pith/send.c -*** alpine-2.23/pith/send.c 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.fromheader/pith/send.c 2020-06-18 16:08:13.017590747 -0600 +diff -rc alpine-2.24/pith/send.c alpine-2.24.fromheader/pith/send.c +*** alpine-2.24/pith/send.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fromheader/pith/send.c 2020-10-10 00:26:58.016372489 -0600 *************** *** 53,59 **** /* name::type::canedit::writehdr::localcopy::rcptto */ @@ -143,9 +143,9 @@ diff -rc alpine-2.23/pith/send.c alpine-2.23.fromheader/pith/send.c pf->rcptto = pf_template[i].rcptto; pf->writehdr = pf_template[i].writehdr; pf->localcopy = pf_template[i].localcopy; -diff -rc alpine-2.23/pith/send.h alpine-2.23.fromheader/pith/send.h -*** alpine-2.23/pith/send.h 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.fromheader/pith/send.h 2020-06-18 16:08:13.017590747 -0600 +diff -rc alpine-2.24/pith/send.h alpine-2.24.fromheader/pith/send.h +*** alpine-2.24/pith/send.h 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.fromheader/pith/send.h 2020-10-10 00:26:58.016372489 -0600 *************** *** 159,164 **** --- 159,166 ---- diff --git a/chappa-insertpat.patch b/chappa-insertpat.patch index 0a6001a..b6c1c0b 100644 --- a/chappa-insertpat.patch +++ b/chappa-insertpat.patch @@ -1,6 +1,6 @@ -diff -rc alpine-2.23/pico/display.c alpine-2.23.insertpat/pico/display.c -*** alpine-2.23/pico/display.c 2020-06-18 15:19:23.437319046 -0600 ---- alpine-2.23.insertpat/pico/display.c 2020-06-18 16:08:14.569594756 -0600 +diff -rc alpine-2.24/pico/display.c alpine-2.24.insertpat/pico/display.c +*** alpine-2.24/pico/display.c 2020-10-10 00:24:28.180553991 -0600 +--- alpine-2.24.insertpat/pico/display.c 2020-10-10 00:26:59.856419380 -0600 *************** *** 2205,2210 **** --- 2205,2222 ---- @@ -22,9 +22,9 @@ diff -rc alpine-2.23/pico/display.c alpine-2.23.insertpat/pico/display.c case (CTRL|'G') : /* CTRL-G help */ if(term.t_mrow == 0 && km_popped == 0){ movecursor(term.t_nrow-2, 0); -diff -rc alpine-2.23/pico/search.c alpine-2.23.insertpat/pico/search.c -*** alpine-2.23/pico/search.c 2020-06-18 15:19:23.437319046 -0600 ---- alpine-2.23.insertpat/pico/search.c 2020-06-18 16:08:14.569594756 -0600 +diff -rc alpine-2.24/pico/search.c alpine-2.24.insertpat/pico/search.c +*** alpine-2.24/pico/search.c 2020-10-10 00:24:28.180553991 -0600 +--- alpine-2.24.insertpat/pico/search.c 2020-10-10 00:26:59.856419380 -0600 *************** *** 122,127 **** --- 122,131 ---- diff --git a/chappa-maildir.patch b/chappa-maildir.patch index 35ee191..f639a60 100644 --- a/chappa-maildir.patch +++ b/chappa-maildir.patch @@ -1,9 +1,9 @@ -diff -rc alpine-2.23/alpine/alpine.c alpine-2.23.maildir/alpine/alpine.c -*** alpine-2.23/alpine/alpine.c 2020-06-18 15:19:23.469318992 -0600 ---- alpine-2.23.maildir/alpine/alpine.c 2020-06-18 16:08:07.725577079 -0600 +diff -rc alpine-2.24/alpine/alpine.c alpine-2.24.maildir/alpine/alpine.c +*** alpine-2.24/alpine/alpine.c 2020-10-10 00:24:28.216554908 -0600 +--- alpine-2.24.maildir/alpine/alpine.c 2020-10-10 00:26:49.964167282 -0600 *************** -*** 597,602 **** ---- 597,607 ---- +*** 591,596 **** +--- 591,601 ---- if(F_ON(F_MAILDROPS_PRESERVE_STATE, ps_global)) mail_parameters(NULL, SET_SNARFPRESERVE, (void *) TRUE); @@ -15,12 +15,12 @@ diff -rc alpine-2.23/alpine/alpine.c alpine-2.23.maildir/alpine/alpine.c rvl = 0L; if(pine_state->VAR_NNTPRANGE){ if(!SVAR_NNTPRANGE(pine_state, rvl, tmp_20k_buf, SIZEOF_20KBUF)) -diff -rc alpine-2.23/alpine/confscroll.c alpine-2.23.maildir/alpine/confscroll.c -*** alpine-2.23/alpine/confscroll.c 2020-06-18 15:19:23.465318999 -0600 ---- alpine-2.23.maildir/alpine/confscroll.c 2020-06-18 16:08:07.729577089 -0600 +diff -rc alpine-2.24/alpine/confscroll.c alpine-2.24.maildir/alpine/confscroll.c +*** alpine-2.24/alpine/confscroll.c 2020-10-10 00:24:28.216554908 -0600 +--- alpine-2.24.maildir/alpine/confscroll.c 2020-10-10 00:26:49.968167384 -0600 *************** -*** 5546,5551 **** ---- 5546,5557 ---- +*** 5567,5572 **** +--- 5567,5578 ---- (void *)var->current_val.p); } #endif @@ -33,11 +33,11 @@ diff -rc alpine-2.23/alpine/confscroll.c alpine-2.23.maildir/alpine/confscroll.c else if(revert && standard_radio_var(ps, var)){ cur_rule_value(var, TRUE, FALSE); -diff -rc alpine-2.23/imap/src/c-client/mail.c alpine-2.23.maildir/imap/src/c-client/mail.c -*** alpine-2.23/imap/src/c-client/mail.c 2020-06-18 15:19:23.457319012 -0600 ---- alpine-2.23.maildir/imap/src/c-client/mail.c 2020-06-18 16:08:07.729577089 -0600 +diff -rc alpine-2.24/imap/src/c-client/mail.c alpine-2.24.maildir/imap/src/c-client/mail.c +*** alpine-2.24/imap/src/c-client/mail.c 2020-10-10 00:24:28.200554500 -0600 +--- alpine-2.24.maildir/imap/src/c-client/mail.c 2020-10-10 00:26:49.968167384 -0600 *************** -*** 1053,1059 **** +*** 1063,1069 **** MAILSTREAM *ts; char *s,*t,tmp[MAILTMPLEN]; size_t i; @@ -45,7 +45,7 @@ diff -rc alpine-2.23/imap/src/c-client/mail.c alpine-2.23.maildir/imap/src/c-cli /* never allow names with newlines */ if ((s = strpbrk (mailbox,"\015\012")) != NULL) { MM_LOG ("Can't create mailbox with such a name",ERROR); ---- 1053,1059 ---- +--- 1063,1069 ---- MAILSTREAM *ts; char *s,*t,tmp[MAILTMPLEN]; size_t i; @@ -54,8 +54,8 @@ diff -rc alpine-2.23/imap/src/c-client/mail.c alpine-2.23.maildir/imap/src/c-cli if ((s = strpbrk (mailbox,"\015\012")) != NULL) { MM_LOG ("Can't create mailbox with such a name",ERROR); *************** -*** 1077,1082 **** ---- 1077,1084 ---- +*** 1087,1092 **** +--- 1087,1094 ---- return NIL; } @@ -65,8 +65,8 @@ diff -rc alpine-2.23/imap/src/c-client/mail.c alpine-2.23.maildir/imap/src/c-cli if ((mailbox[0] == '#') && ((mailbox[1] == 'd') || (mailbox[1] == 'D')) && ((mailbox[2] == 'r') || (mailbox[2] == 'R')) && *************** -*** 1107,1112 **** ---- 1109,1121 ---- +*** 1117,1122 **** +--- 1119,1131 ---- (((*mailbox == '{') || (*mailbox == '#')) && (stream = mail_open (NIL,mailbox,OP_PROTOTYPE | OP_SILENT)))) d = stream->dtb; @@ -80,12 +80,12 @@ diff -rc alpine-2.23/imap/src/c-client/mail.c alpine-2.23.maildir/imap/src/c-cli else if ((*mailbox != '{') && (ts = default_proto (NIL))) d = ts->dtb; else { /* failed utterly */ sprintf (tmp,"Can't create mailbox %.80s: indeterminate format",mailbox); -diff -rc alpine-2.23/imap/src/c-client/mail.h alpine-2.23.maildir/imap/src/c-client/mail.h -*** alpine-2.23/imap/src/c-client/mail.h 2020-06-18 15:19:23.457319012 -0600 ---- alpine-2.23.maildir/imap/src/c-client/mail.h 2020-06-18 16:08:07.729577089 -0600 +diff -rc alpine-2.24/imap/src/c-client/mail.h alpine-2.24.maildir/imap/src/c-client/mail.h +*** alpine-2.24/imap/src/c-client/mail.h 2020-10-10 00:24:28.200554500 -0600 +--- alpine-2.24.maildir/imap/src/c-client/mail.h 2020-10-10 00:26:49.968167384 -0600 *************** -*** 379,384 **** ---- 379,388 ---- +*** 383,388 **** +--- 383,392 ---- #define SET_SCANCONTENTS (long) 573 #define GET_MHALLOWINBOX (long) 574 #define SET_MHALLOWINBOX (long) 575 @@ -96,11 +96,11 @@ diff -rc alpine-2.23/imap/src/c-client/mail.h alpine-2.23.maildir/imap/src/c-cli /* Driver flags */ -diff -rc alpine-2.23/imap/src/osdep/unix/dummy.c alpine-2.23.maildir/imap/src/osdep/unix/dummy.c -*** alpine-2.23/imap/src/osdep/unix/dummy.c 2020-06-18 15:19:23.449319026 -0600 ---- alpine-2.23.maildir/imap/src/osdep/unix/dummy.c 2020-06-18 16:08:07.729577089 -0600 +diff -rc alpine-2.24/imap/src/osdep/unix/dummy.c alpine-2.24.maildir/imap/src/osdep/unix/dummy.c +*** alpine-2.24/imap/src/osdep/unix/dummy.c 2020-10-10 00:24:28.192554297 -0600 +--- alpine-2.24.maildir/imap/src/osdep/unix/dummy.c 2020-10-10 00:26:49.972167485 -0600 *************** -*** 103,115 **** +*** 104,116 **** * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ @@ -114,7 +114,7 @@ diff -rc alpine-2.23/imap/src/osdep/unix/dummy.c alpine-2.23.maildir/imap/src/os /* indeterminate clearbox INBOX */ if (!*s) return &dummydriver; else if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) { ---- 103,121 ---- +--- 104,122 ---- * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ @@ -135,7 +135,7 @@ diff -rc alpine-2.23/imap/src/osdep/unix/dummy.c alpine-2.23.maildir/imap/src/os if (!*s) return &dummydriver; else if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) { *************** -*** 118,125 **** +*** 119,126 **** return &dummydriver; } /* blackbox INBOX does not exist yet */ @@ -144,7 +144,7 @@ diff -rc alpine-2.23/imap/src/osdep/unix/dummy.c alpine-2.23.maildir/imap/src/os return NIL; } ---- 124,132 ---- +--- 125,133 ---- return &dummydriver; } /* blackbox INBOX does not exist yet */ @@ -155,8 +155,8 @@ diff -rc alpine-2.23/imap/src/osdep/unix/dummy.c alpine-2.23.maildir/imap/src/os } *************** -*** 452,457 **** ---- 459,466 ---- +*** 453,458 **** +--- 460,467 ---- { char *s,tmp[MAILTMPLEN]; long ret = NIL; @@ -166,8 +166,8 @@ diff -rc alpine-2.23/imap/src/osdep/unix/dummy.c alpine-2.23.maildir/imap/src/os if (!(compare_cstring (mailbox,"INBOX") && (s = dummy_file (tmp,mailbox)))) { sprintf (tmp,"Can't create %.80s: invalid name",mailbox); *************** -*** 517,522 **** ---- 526,539 ---- +*** 518,523 **** +--- 527,540 ---- { struct stat sbuf; char *s,tmp[MAILTMPLEN]; @@ -183,7 +183,7 @@ diff -rc alpine-2.23/imap/src/osdep/unix/dummy.c alpine-2.23.maildir/imap/src/os sprintf (tmp,"Can't delete - invalid name: %.80s",s); MM_LOG (tmp,ERROR); *************** -*** 542,553 **** +*** 543,554 **** long dummy_rename (MAILSTREAM *stream,char *old,char *newname) { struct stat sbuf; @@ -196,7 +196,7 @@ diff -rc alpine-2.23/imap/src/osdep/unix/dummy.c alpine-2.23.maildir/imap/src/os MM_LOG (mbx,ERROR); return NIL; } ---- 559,581 ---- +--- 560,582 ---- long dummy_rename (MAILSTREAM *stream,char *old,char *newname) { struct stat sbuf; @@ -221,7 +221,7 @@ diff -rc alpine-2.23/imap/src/osdep/unix/dummy.c alpine-2.23.maildir/imap/src/os return NIL; } *************** -*** 563,576 **** +*** 564,577 **** } } /* rename of non-ex INBOX creates dest */ @@ -236,7 +236,7 @@ diff -rc alpine-2.23/imap/src/osdep/unix/dummy.c alpine-2.23.maildir/imap/src/os return T; /* return success */ } ---- 591,606 ---- +--- 592,607 ---- } } /* rename of non-ex INBOX creates dest */ @@ -253,9 +253,9 @@ diff -rc alpine-2.23/imap/src/osdep/unix/dummy.c alpine-2.23.maildir/imap/src/os return T; /* return success */ } -diff -rc alpine-2.23/imap/src/osdep/unix/maildir.c alpine-2.23.maildir/imap/src/osdep/unix/maildir.c -*** alpine-2.23/imap/src/osdep/unix/maildir.c 2020-06-18 16:08:07.773577203 -0600 ---- alpine-2.23.maildir/imap/src/osdep/unix/maildir.c 2020-06-18 16:08:07.733577099 -0600 +diff -rc alpine-2.24/imap/src/osdep/unix/maildir.c alpine-2.24.maildir/imap/src/osdep/unix/maildir.c +*** alpine-2.24/imap/src/osdep/unix/maildir.c 2020-10-10 00:26:50.012168504 -0600 +--- alpine-2.24.maildir/imap/src/osdep/unix/maildir.c 2020-10-10 00:26:49.972167485 -0600 *************** *** 0 **** --- 1,2671 ---- @@ -2930,9 +2930,9 @@ diff -rc alpine-2.23/imap/src/osdep/unix/maildir.c alpine-2.23.maildir/imap/src/ + LOCAL->uidtempfile = cpystr(tmp); + } + } -diff -rc alpine-2.23/imap/src/osdep/unix/maildir.h alpine-2.23.maildir/imap/src/osdep/unix/maildir.h -*** alpine-2.23/imap/src/osdep/unix/maildir.h 2020-06-18 16:08:07.777577213 -0600 ---- alpine-2.23.maildir/imap/src/osdep/unix/maildir.h 2020-06-18 16:08:07.733577099 -0600 +diff -rc alpine-2.24/imap/src/osdep/unix/maildir.h alpine-2.24.maildir/imap/src/osdep/unix/maildir.h +*** alpine-2.24/imap/src/osdep/unix/maildir.h 2020-10-10 00:26:50.012168504 -0600 +--- alpine-2.24.maildir/imap/src/osdep/unix/maildir.h 2020-10-10 00:26:49.972167485 -0600 *************** *** 0 **** --- 1,226 ---- @@ -3162,9 +3162,9 @@ diff -rc alpine-2.23/imap/src/osdep/unix/maildir.h alpine-2.23.maildir/imap/src/ + void maildir_assign_uid(MAILSTREAM *stream, unsigned long msgno, unsigned long uid); + void maildir_uid_renew_tempfile(MAILSTREAM *stream); + -diff -rc alpine-2.23/imap/src/osdep/unix/Makefile alpine-2.23.maildir/imap/src/osdep/unix/Makefile -*** alpine-2.23/imap/src/osdep/unix/Makefile 2020-06-18 15:19:23.453319019 -0600 ---- alpine-2.23.maildir/imap/src/osdep/unix/Makefile 2020-06-18 16:08:07.733577099 -0600 +diff -rc alpine-2.24/imap/src/osdep/unix/Makefile alpine-2.24.maildir/imap/src/osdep/unix/Makefile +*** alpine-2.24/imap/src/osdep/unix/Makefile 2020-10-10 00:24:28.196554399 -0600 +--- alpine-2.24.maildir/imap/src/osdep/unix/Makefile 2020-10-10 00:26:49.976167588 -0600 *************** *** 146,152 **** # However, mh needs to be before any sysinbox formats (such as mmdf or unix) @@ -3226,9 +3226,9 @@ diff -rc alpine-2.23/imap/src/osdep/unix/Makefile alpine-2.23.maildir/imap/src/o # OS-dependent -diff -rc alpine-2.23/imap/src/osdep/unix/os_cyg.h alpine-2.23.maildir/imap/src/osdep/unix/os_cyg.h -*** alpine-2.23/imap/src/osdep/unix/os_cyg.h 2020-06-18 15:19:23.449319026 -0600 ---- alpine-2.23.maildir/imap/src/osdep/unix/os_cyg.h 2020-06-18 16:08:07.733577099 -0600 +diff -rc alpine-2.24/imap/src/osdep/unix/os_cyg.h alpine-2.24.maildir/imap/src/osdep/unix/os_cyg.h +*** alpine-2.24/imap/src/osdep/unix/os_cyg.h 2020-10-10 00:24:28.192554297 -0600 +--- alpine-2.24.maildir/imap/src/osdep/unix/os_cyg.h 2020-10-10 00:26:49.976167588 -0600 *************** *** 47,52 **** --- 47,53 ---- @@ -3239,12 +3239,12 @@ diff -rc alpine-2.23/imap/src/osdep/unix/os_cyg.h alpine-2.23.maildir/imap/src/o #define geteuid Geteuid uid_t Geteuid (void); -diff -rc alpine-2.23/pith/conf.c alpine-2.23.maildir/pith/conf.c -*** alpine-2.23/pith/conf.c 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.maildir/pith/conf.c 2020-06-18 16:08:07.737577110 -0600 +diff -rc alpine-2.24/pith/conf.c alpine-2.24.maildir/pith/conf.c +*** alpine-2.24/pith/conf.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.maildir/pith/conf.c 2020-10-10 00:26:49.976167588 -0600 *************** -*** 449,454 **** ---- 449,457 ---- +*** 453,458 **** +--- 453,461 ---- CONF_TXT_T cf_text_newsrc_path[] = "Full path and name of NEWSRC file"; @@ -3255,8 +3255,8 @@ diff -rc alpine-2.23/pith/conf.c alpine-2.23.maildir/pith/conf.c /*---------------------------------------------------------------------- These are the variables that control a number of pine functions. They *************** -*** 653,658 **** ---- 656,665 ---- +*** 657,662 **** +--- 660,669 ---- NULL, cf_text_news_active}, {"news-spool-directory", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, NULL, cf_text_news_spooldir}, @@ -3268,8 +3268,8 @@ diff -rc alpine-2.23/pith/conf.c alpine-2.23.maildir/pith/conf.c NULL, cf_text_upload_cmd}, {"upload-command-prefix", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, *************** -*** 2338,2343 **** ---- 2345,2356 ---- +*** 2392,2397 **** +--- 2399,2410 ---- mail_parameters(NULL, SET_NEWSSPOOL, (void *)VAR_NEWS_SPOOL_DIR); @@ -3283,8 +3283,8 @@ diff -rc alpine-2.23/pith/conf.c alpine-2.23.maildir/pith/conf.c set_current_val(&vars[V_DEFAULT_SAVE_FOLDER], TRUE, TRUE); if(!VAR_DEFAULT_SAVE_FOLDER || !VAR_DEFAULT_SAVE_FOLDER[0]) *************** -*** 2976,2981 **** ---- 2989,2998 ---- +*** 3030,3035 **** +--- 3043,3052 ---- 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}, @@ -3296,7 +3296,7 @@ diff -rc alpine-2.23/pith/conf.c alpine-2.23.maildir/pith/conf.c /* Addr book */ {"combined-addrbook-display", "Combined Address Book Display", *************** -*** 7124,7130 **** +*** 7209,7215 **** int just_flip_value, EditWhich ew) { char **vp, *p, **lval, ***alval; @@ -3304,7 +3304,7 @@ diff -rc alpine-2.23/pith/conf.c alpine-2.23.maildir/pith/conf.c char *err; long l; ---- 7141,7147 ---- +--- 7226,7232 ---- int just_flip_value, EditWhich ew) { char **vp, *p, **lval, ***alval; @@ -3313,8 +3313,8 @@ diff -rc alpine-2.23/pith/conf.c alpine-2.23.maildir/pith/conf.c long l; *************** -*** 7177,7182 **** ---- 7194,7206 ---- +*** 7262,7267 **** +--- 7279,7291 ---- break; @@ -3329,8 +3329,8 @@ diff -rc alpine-2.23/pith/conf.c alpine-2.23.maildir/pith/conf.c case F_DATES_TO_LOCAL : clear_index_cache(ps->mail_stream, 0); *************** -*** 7975,7980 **** ---- 7999,8008 ---- +*** 8062,8067 **** +--- 8086,8095 ---- return(h_config_newmailwidth); case V_NEWSRC_PATH : return(h_config_newsrc_path); @@ -3341,12 +3341,12 @@ diff -rc alpine-2.23/pith/conf.c alpine-2.23.maildir/pith/conf.c case V_BROWSER : return(h_config_browser); case V_HISTORY : -diff -rc alpine-2.23/pith/conf.h alpine-2.23.maildir/pith/conf.h -*** alpine-2.23/pith/conf.h 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.maildir/pith/conf.h 2020-06-18 16:08:07.737577110 -0600 +diff -rc alpine-2.24/pith/conf.h alpine-2.24.maildir/pith/conf.h +*** alpine-2.24/pith/conf.h 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.maildir/pith/conf.h 2020-10-10 00:26:49.976167588 -0600 *************** -*** 260,265 **** ---- 260,269 ---- +*** 264,269 **** +--- 264,273 ---- #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 @@ -3357,9 +3357,9 @@ diff -rc alpine-2.23/pith/conf.h alpine-2.23.maildir/pith/conf.h #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 -diff -rc alpine-2.23/pith/conftype.h alpine-2.23.maildir/pith/conftype.h -*** alpine-2.23/pith/conftype.h 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.maildir/pith/conftype.h 2020-06-18 16:08:07.737577110 -0600 +diff -rc alpine-2.24/pith/conftype.h alpine-2.24.maildir/pith/conftype.h +*** alpine-2.24/pith/conftype.h 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.maildir/pith/conftype.h 2020-10-10 00:26:49.980167690 -0600 *************** *** 118,123 **** --- 118,126 ---- @@ -3384,9 +3384,9 @@ diff -rc alpine-2.23/pith/conftype.h alpine-2.23.maildir/pith/conftype.h F_TAB_CHK_RECENT, F_AUTO_REPLY_TO, F_VERBOSE_POST, -diff -rc alpine-2.23/pith/init.c alpine-2.23.maildir/pith/init.c -*** alpine-2.23/pith/init.c 2020-06-18 15:19:23.465318999 -0600 ---- alpine-2.23.maildir/pith/init.c 2020-06-18 16:08:07.737577110 -0600 +diff -rc alpine-2.24/pith/init.c alpine-2.24.maildir/pith/init.c +*** alpine-2.24/pith/init.c 2020-10-10 00:24:28.208554703 -0600 +--- alpine-2.24.maildir/pith/init.c 2020-10-10 00:26:49.980167690 -0600 *************** *** 408,413 **** --- 408,416 ---- @@ -3399,9 +3399,9 @@ diff -rc alpine-2.23/pith/init.c alpine-2.23.maildir/pith/init.c && strcmp(filename, folder_base)){ #endif #endif -diff -rc alpine-2.23/pith/pattern.c alpine-2.23.maildir/pith/pattern.c -*** alpine-2.23/pith/pattern.c 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.maildir/pith/pattern.c 2020-06-18 16:08:07.741577120 -0600 +diff -rc alpine-2.24/pith/pattern.c alpine-2.24.maildir/pith/pattern.c +*** alpine-2.24/pith/pattern.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.maildir/pith/pattern.c 2020-10-10 00:26:49.984167792 -0600 *************** *** 49,55 **** #include "../pith/icache.h" @@ -3489,12 +3489,12 @@ diff -rc alpine-2.23/pith/pattern.c alpine-2.23.maildir/pith/pattern.c return(buf[0] != '\0'); } -diff -rc alpine-2.23/pith/pine.hlp alpine-2.23.maildir/pith/pine.hlp -*** alpine-2.23/pith/pine.hlp 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.maildir/pith/pine.hlp 2020-06-18 16:08:07.749577141 -0600 +diff -rc alpine-2.24/pith/pine.hlp alpine-2.24.maildir/pith/pine.hlp +*** alpine-2.24/pith/pine.hlp 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.maildir/pith/pine.hlp 2020-10-10 00:26:49.996168098 -0600 *************** -*** 23014,23019 **** ---- 23014,23115 ---- +*** 23452,23457 **** +--- 23452,23553 ---- <End of help on this topic> @@ -3598,8 +3598,8 @@ diff -rc alpine-2.23/pith/pine.hlp alpine-2.23.maildir/pith/pine.hlp *************** -*** 31245,31250 **** ---- 31341,31389 ---- +*** 31683,31688 **** +--- 31779,31827 ----

    <End of help on this topic> @@ -3649,9 +3649,9 @@ diff -rc alpine-2.23/pith/pine.hlp alpine-2.23.maildir/pith/pine.hlp ====== h_config_verbose_post ===== -diff -rc alpine-2.23/pith/send.c alpine-2.23.maildir/pith/send.c -*** alpine-2.23/pith/send.c 2020-06-18 15:19:23.461319005 -0600 ---- alpine-2.23.maildir/pith/send.c 2020-06-18 16:08:07.761577172 -0600 +diff -rc alpine-2.24/pith/send.c alpine-2.24.maildir/pith/send.c +*** alpine-2.24/pith/send.c 2020-10-10 00:24:28.204554602 -0600 +--- alpine-2.24.maildir/pith/send.c 2020-10-10 00:26:49.996168098 -0600 *************** *** 47,52 **** --- 47,55 ---- @@ -3680,9 +3680,9 @@ diff -rc alpine-2.23/pith/send.c alpine-2.23.maildir/pith/send.c if(!(IS_REMOTE(tmp) || is_absolute_path(tmp))){ /* * The mbox is relative to the home directory. -diff -rc alpine-2.23/README.maildir alpine-2.23.maildir/README.maildir -*** alpine-2.23/README.maildir 2020-06-18 16:08:07.777577213 -0600 ---- alpine-2.23.maildir/README.maildir 2020-06-18 16:08:07.761577172 -0600 +diff -rc alpine-2.24/README.maildir alpine-2.24.maildir/README.maildir +*** alpine-2.24/README.maildir 2020-10-10 00:26:50.012168504 -0600 +--- alpine-2.24.maildir/README.maildir 2020-10-10 00:26:49.996168098 -0600 *************** *** 0 **** --- 1,149 ---- diff --git a/chappa-rules.patch b/chappa-rules.patch index 9b0e593..e93ffcb 100644 --- a/chappa-rules.patch +++ b/chappa-rules.patch @@ -8,7 +8,7 @@ alpine/mailcmd.c | 18 alpine/mailindx.c | 6 alpine/mailpart.c | 12 - alpine/mailview.c | 4 + alpine/mailview.c | 3 alpine/osdep/termin.gen.c | 41 + alpine/reply.c | 102 ++ alpine/roleconf.c | 5 @@ -33,7 +33,7 @@ pith/rulestype.h | 94 ++ pith/save.c | 2 pith/send.c | 58 + - pith/sort.c | 54 + + pith/sort.c | 55 + pith/sort.h | 2 pith/state.c | 4 pith/state.h | 11 @@ -41,6514 +41,5904 @@ pith/string.h | 2 40 files changed, 4487 insertions(+), 297 deletions(-) -Index: alpine-2.23.2/alpine/adrbkcmd.c +Index: alpine-2.24/alpine/adrbkcmd.c =================================================================== -*** alpine-2.23.2.orig/alpine/adrbkcmd.c ---- alpine-2.23.2/alpine/adrbkcmd.c -*************** ab_compose_internal(BuildTo bldto, int a -*** 4128,4133 **** ---- 4128,4135 ---- - * 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{ -*************** ab_compose_internal(BuildTo bldto, int a -*** 4135,4140 **** ---- 4137,4143 ---- - memset((void *)role, 0, sizeof(*role)); - role->nick = cpystr("Default Role"); - } -+ ps_global->role = cpystr(role->nick); - } - - compose_mail(addr, fcc, role, NULL, NULL); -Index: alpine-2.23.2/alpine/alpine.c +--- alpine-2.24.orig/alpine/adrbkcmd.c ++++ alpine-2.24/alpine/adrbkcmd.c +@@ -4128,6 +4128,8 @@ ab_compose_internal(BuildTo bldto, int a + * won't do anything, but will cause compose_mail to think there's + * already a role so that it won't try to confirm the default. + */ ++ if (ps_global->role) ++ fs_give((void **)&ps_global->role); + if(role) + role = copy_action(role); + else{ +@@ -4135,6 +4137,7 @@ ab_compose_internal(BuildTo bldto, int a + memset((void *)role, 0, sizeof(*role)); + role->nick = cpystr("Default Role"); + } ++ ps_global->role = cpystr(role->nick); + } + + compose_mail(addr, fcc, role, NULL, NULL); +Index: alpine-2.24/alpine/alpine.c =================================================================== -*** alpine-2.23.2.orig/alpine/alpine.c ---- alpine-2.23.2/alpine/alpine.c -*************** main(int argc, char **argv) -*** 506,511 **** ---- 506,512 ---- - /* 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){ -*************** goodnight_gracey(struct pine *pine_state -*** 3274,3279 **** ---- 3275,3283 ---- - 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(); -Index: alpine-2.23.2/alpine/confscroll.c +--- alpine-2.24.orig/alpine/alpine.c ++++ alpine-2.24/alpine/alpine.c +@@ -500,6 +500,7 @@ main(int argc, char **argv) + /* Set up optional for user-defined display filtering */ + pine_state->tools.display_filter = dfilter; + pine_state->tools.display_filter_trigger = dfilter_trigger; ++ pine_state->tools.exec_rule = exec_function_rule; + + #ifdef _WINDOWS + if(ps_global->install_flag){ +@@ -3267,6 +3268,9 @@ goodnight_gracey(struct pine *pine_state + 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(); +Index: alpine-2.24/alpine/confscroll.c =================================================================== -*** alpine-2.23.2.orig/alpine/confscroll.c ---- alpine-2.23.2/alpine/confscroll.c -*************** static char rcsid[] = "$Id: confscroll.c -*** 52,57 **** ---- 52,58 ---- - #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") -*************** delete: -*** 2465,2470 **** ---- 2466,2474 ---- - * 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); - -*************** fix_side_effects(struct pine *ps, struct -*** 5262,5267 **** ---- 5266,5300 ---- - 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); -+ if(var == &ps->vars[V_REPLACE_RULES] || -+ var == &ps->vars[V_RESUB_RULES]){ -+ reset_index_format(); -+ clear_index_cache(ps->mail_stream, 0); -+ } -+ } - else if(var == &ps->vars[V_INDEX_FORMAT]){ - reset_index_format(); - clear_index_cache(ps->mail_stream, 0); -Index: alpine-2.23.2/alpine/dispfilt.c +--- alpine-2.24.orig/alpine/confscroll.c ++++ alpine-2.24/alpine/confscroll.c +@@ -52,6 +52,7 @@ static char rcsid[] = "$Id: confscroll.c + #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") +@@ -2463,6 +2464,9 @@ delete: + * Now go and set the current_val based on user_val changes + * above. Turn off command line settings... + */ ++ set_current_val((*cl)->var, ++ (strcmp((*cl)->var->name,"key-definition-rules") ? TRUE : FALSE), ++ FALSE); + set_current_val((*cl)->var, TRUE, FALSE); + fix_side_effects(ps, (*cl)->var, 0); + +@@ -5260,6 +5264,35 @@ fix_side_effects(struct pine *ps, struct + 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); ++ if(var == &ps->vars[V_REPLACE_RULES] || ++ var == &ps->vars[V_RESUB_RULES]){ ++ reset_index_format(); ++ clear_index_cache(ps->mail_stream, 0); ++ } ++ } + else if(var == &ps->vars[V_INDEX_FORMAT]){ + reset_index_format(); + clear_index_cache(ps->mail_stream, 0); +Index: alpine-2.24/alpine/dispfilt.c =================================================================== -*** alpine-2.23.2.orig/alpine/dispfilt.c ---- alpine-2.23.2/alpine/dispfilt.c -*************** df_valid_test(struct mail_bodystruct *bo -*** 461,463 **** ---- 461,523 ---- - - 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); -+ } -Index: alpine-2.23.2/alpine/dispfilt.h +--- alpine-2.24.orig/alpine/dispfilt.c ++++ alpine-2.24/alpine/dispfilt.c +@@ -461,3 +461,63 @@ df_valid_test(struct mail_bodystruct *bo + + 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); ++} +Index: alpine-2.24/alpine/dispfilt.h =================================================================== -*** alpine-2.23.2.orig/alpine/dispfilt.h ---- alpine-2.23.2/alpine/dispfilt.h -*************** char *dfilter_trigger(BODY *, char *, si -*** 25,31 **** - char *expand_filter_tokens(char *, ENVELOPE *, char **, char **, char **, int *, int *, int *); - char *filter_session_key(void); - char *filter_data_file(int); -! - - - #endif /* PINE_DISPFILT_INCLUDED */ ---- 25,31 ---- - 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 */ -Index: alpine-2.23.2/alpine/folder.c +--- alpine-2.24.orig/alpine/dispfilt.h ++++ alpine-2.24/alpine/dispfilt.h +@@ -25,7 +25,7 @@ char *dfilter_trigger(BODY *, char *, si + 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 */ +Index: alpine-2.24/alpine/folder.c =================================================================== -*** alpine-2.23.2.orig/alpine/folder.c ---- alpine-2.23.2/alpine/folder.c -*************** folder_screen(struct pine *ps) -*** 248,254 **** - 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; ---- 248,254 ---- - 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; -*************** folder_screen(struct pine *ps) -*** 345,350 **** ---- 345,351 ---- - pine_mail_close(*fs.cache_streamp); - - ps->prev_screen = folder_screen; -+ strcpy(ps->screen_name, "unknown"); - } - - -Index: alpine-2.23.2/alpine/mailcmd.c +--- alpine-2.24.orig/alpine/folder.c ++++ alpine-2.24/alpine/folder.c +@@ -248,7 +248,7 @@ folder_screen(struct pine *ps) + dprint((1, "=== folder_screen called ====\n")); + mailcap_free(); /* free resources we won't be using for a while */ + ps->next_screen = SCREEN_FUN_NULL; +- ++ strcpy(ps->screen_name, "folder"); + /* Initialize folder state and dispatches */ + memset(&fs, 0, sizeof(FSTATE_S)); + fs.context = cntxt; +@@ -345,6 +345,7 @@ folder_screen(struct pine *ps) + pine_mail_close(*fs.cache_streamp); + + ps->prev_screen = folder_screen; ++ strcpy(ps->screen_name, "unknown"); + } + + +Index: alpine-2.24/alpine/mailcmd.c =================================================================== -*** alpine-2.23.2.orig/alpine/mailcmd.c ---- alpine-2.23.2/alpine/mailcmd.c -*************** static char rcsid[] = "$Id: mailcmd.c 12 -*** 73,78 **** ---- 73,79 ---- - #include "../pith/tempfile.h" - #include "../pith/search.h" - #include "../pith/margin.h" -+ #include "../pith/rules.h" - #ifdef _WINDOWS - #include "../pico/osdep/mswin.h" - #endif -*************** role_compose(struct pine *state) -*** 2721,2726 **** ---- 2722,2730 ---- - 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': -*************** save_prompt(struct pine *state, CONTEXT_ -*** 2771,2782 **** - 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; ---- 2775,2786 ---- - 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; -*************** save_prompt(struct pine *state, CONTEXT_ -*** 2784,2789 **** ---- 2788,2794 ---- - static HISTORY_S *history = NULL; - CONTEXT_S *tc; - ESCKEY_S ekey[10]; -+ RULE_RESULT *rule; - - if(!cntxt) - alpine_panic("no context ptr in save_prompt"); -*************** save_prompt(struct pine *state, CONTEXT_ -*** 2793,2798 **** ---- 2798,2812 ---- - 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)) -Index: alpine-2.23.2/alpine/mailindx.c -=================================================================== -*** alpine-2.23.2.orig/alpine/mailindx.c ---- alpine-2.23.2/alpine/mailindx.c -*************** mail_index_screen(struct pine *state) -*** 229,234 **** ---- 229,236 ---- - 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 -*************** mail_index_screen(struct pine *state) -*** 240,249 **** ---- 242,255 ---- - - 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"); - } - - -Index: alpine-2.23.2/alpine/mailpart.c -=================================================================== -*** alpine-2.23.2.orig/alpine/mailpart.c ---- alpine-2.23.2/alpine/mailpart.c -*************** attachment_screen(struct pine *ps) -*** 182,188 **** - maxnumwid = 0, maxsizewid = 0, old_cols = -1, km_popped = 0, expbits, - last_type = TYPEOTHER; - long msgno; -! char *q, *last_subtype = NULL, backtag[64], *utf8str; - OtherMenu what; - ATTACH_S *a; - ATDISP_S *current = NULL, *ctmp = NULL; ---- 182,188 ---- - maxnumwid = 0, maxsizewid = 0, old_cols = -1, km_popped = 0, expbits, - last_type = TYPEOTHER; - long msgno; -! char *q, *last_subtype = NULL, backtag[64], *utf8str, *screen_name; - OtherMenu what; - ATTACH_S *a; - ATDISP_S *current = NULL, *ctmp = NULL; -*************** attachment_screen(struct pine *ps) -*** 191,196 **** ---- 191,200 ---- - ps->prev_screen = attachment_screen; - ps->next_screen = SCREEN_FUN_NULL; - -+ screen_name = ps->screen_name[0] ? cpystr(ps->screen_name) : NULL; -+ strncpy(ps->screen_name, "attachment", sizeof(ps->screen_name)); -+ ps->screen_name[sizeof(ps->screen_name)-1] = '\0'; -+ - ps->some_quoting_was_suppressed = 0; - - if(ps->ttyo->screen_rows - HEADER_ROWS(ps) - FOOTER_ROWS(ps) < 1){ -*************** attachment_screen(struct pine *ps) -*** 911,916 **** ---- 915,926 ---- - - if(screen.titlecolor) - free_color_pair(&screen.titlecolor); -+ -+ if(screen_name){ -+ strncpy(ps->screen_name, screen_name, sizeof(ps->screen_name)); -+ ps->screen_name[sizeof(ps->screen_name)-1] = '\0'; -+ fs_give((void **) &screen_name); -+ } - } - - -Index: alpine-2.23.2/alpine/mailview.c -=================================================================== -*** alpine-2.23.2.orig/alpine/mailview.c ---- alpine-2.23.2/alpine/mailview.c -*************** mail_view_screen(struct pine *ps) -*** 252,257 **** ---- 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")); -*************** mail_view_screen(struct pine *ps) -*** 499,504 **** ---- 501,508 ---- - } - while(ps->next_screen == SCREEN_FUN_NULL); - -+ strcpy(ps->screen_name, "unknown"); -+ - if (prefix && *prefix) - fs_give((void **)&prefix); - if(we_cancel) -Index: alpine-2.23.2/alpine/osdep/termin.gen.c -=================================================================== -*** alpine-2.23.2.orig/alpine/osdep/termin.gen.c ---- alpine-2.23.2/alpine/osdep/termin.gen.c -*************** static char rcsid[] = "$Id: termin.gen.c -*** 33,38 **** ---- 33,40 ---- - #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" -*************** int pcpine_oe_cursor(int, long); -*** 72,78 **** - * Generic tty input routines - */ - -! - /*---------------------------------------------------------------------- - Read a character from keyboard with timeout - Input: none ---- 74,81 ---- - * 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 -*************** read_command(char **utf8str) -*** 114,119 **** ---- 117,157 ---- - *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(); - -*************** process_config_input(UCS *ch) -*** 1158,1163 **** ---- 1196,1202 ---- - if(ps_global->initial_cmds && !*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); -Index: alpine-2.23.2/alpine/reply.c -=================================================================== -*** alpine-2.23.2.orig/alpine/reply.c ---- alpine-2.23.2/alpine/reply.c -*************** The evolution continues... -*** 62,68 **** - #include "../pith/tempfile.h" - #include "../pith/busy.h" - #include "../pith/ablookup.h" -! - - /* - * Internal Prototypes ---- 62,69 ---- - #include "../pith/tempfile.h" - #include "../pith/busy.h" - #include "../pith/ablookup.h" -! #include "../pith/copyaddr.h" -! #include "../pith/rules.h" - - /* - * Internal Prototypes -*************** reply(struct pine *pine_state, ACTION_S -*** 110,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; - 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 ---- 111,122 ---- - 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 -*************** reply(struct pine *pine_state, ACTION_S -*** 140,145 **** ---- 142,210 ---- - && F_ON(F_ENABLE_FULL_HDR_AND_TEXT, ps_global)) - reply_raw_body = 1; - -+ /* Setup possible role */ -+ if(role_arg) -+ role = copy_action(role_arg); -+ -+ if(!role && F_ON(F_ENABLE_EDIT_REPLY_INDENT, pine_state)){ -+ for(msgno = mn_first_cur(pine_state->msgmap); -+ msgno > 0L; msgno = mn_next_cur(pine_state->msgmap)){ -+ -+ env = pine_mail_fetchstructure(pine_state->mail_stream, -+ mn_m2raw(pine_state->msgmap, msgno), -+ NULL); -+ if(!env) { -+ q_status_message1(SM_ORDER,3,4, -+ _("Error fetching message %s. Can't reply to it."), -+ long2string(msgno)); -+ goto done_early; -+ } -+ -+ if(rule = get_result_rule(V_REPLY_INDENT_RULES, FOR_COMPOSE , env)){ -+ RULELIST *list = get_rulelist_from_code(V_REPLY_INDENT_RULES, -+ ps_global->rule_list); -+ RULE_S *prule = get_rule(list, rule->number); -+ if(condition_contains_token(prule->condition, ROLE_TOKEN)) -+ do_role_early++; -+ if(rule->result) -+ fs_give((void **)&rule->result); -+ fs_give((void **)&rule); -+ } -+ } -+ } -+ -+ if(do_role_early){ -+ rflags = ROLE_REPLY; -+ if(nonempty_patterns(rflags, &dummy)){ -+ /* setup default role */ -+ nrole = NULL; -+ j = mn_first_cur(pine_state->msgmap); -+ do { -+ role = nrole; -+ nrole = set_role_from_msg(pine_state, rflags, -+ mn_m2raw(pine_state->msgmap, j), -+ NULL); -+ } while(nrole && (!role || nrole == role) -+ && (j=mn_next_cur(pine_state->msgmap)) > 0L); -+ -+ if(!role || nrole == role) -+ role = nrole; -+ else -+ role = NULL; -+ -+ if(confirm_role(rflags, &role)) -+ role = combine_inherited_role(role); -+ else{ /* cancel reply */ -+ role = NULL; -+ cmd_cancelled("Reply"); -+ goto done_early; -+ } -+ } -+ } -+ -+ if (role) -+ ps_global->role = cpystr(role->nick); /* remember the role */ -+ - /* - * We may have to loop through first to figure out what default - * reply-indent-string to offer... -*************** reply(struct pine *pine_state, ACTION_S -*** 288,295 **** - outgoing->subject = cpystr("Re: several messages"); - } - } -! else -! outgoing->subject = reply_subject(env->subject, NULL, 0); - } - - /* fill reply header */ ---- 353,370 ---- - 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 */ -*************** reply(struct pine *pine_state, ACTION_S -*** 308,320 **** - if(sp_expunge_count(pine_state->mail_stream)) /* cur msg expunged */ - goto done_early; - -! /* Setup possible role */ -! if (ps_global->reply.role_chosen) -! role = ps_global->reply.role_chosen; -! else if(role_arg) -! role = copy_action(role_arg); -! -! if(!role){ - rflags = ROLE_REPLY; - if(!ps_global->reply.role_chosen && nonempty_patterns(rflags, &dummy)){ - /* setup default role */ ---- 383,389 ---- - if(sp_expunge_count(pine_state->mail_stream)) /* cur msg expunged */ - goto done_early; - -! if(!do_role_early){ - rflags = ROLE_REPLY; - if(!ps_global->reply.role_chosen && nonempty_patterns(rflags, &dummy)){ - /* setup default role */ -*************** reply(struct pine *pine_state, ACTION_S -*** 725,730 **** ---- 794,802 ---- - if(prefix) - fs_give((void **)&prefix); - -+ if (ps_global->role) -+ fs_give((void **)&ps_global->role); -+ - if(fcc) - fs_give((void **) &fcc); - -*************** forward(struct pine *ps, ACTION_S *role_ -*** 1598,1606 **** - } - } - -! if(role) - q_status_message1(SM_ORDER, 3, 4, - _("Forwarding using role \"%s\""), role->nick); - - outgoing->message_id = generate_message_id(role); - ---- 1670,1683 ---- - } - } - -! 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); -+ } - - outgoing->message_id = generate_message_id(role); - -*************** forward(struct pine *ps, ACTION_S *role_ -*** 1834,1839 **** ---- 1911,1917 ---- - #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); -Index: alpine-2.23.2/alpine/roleconf.c -=================================================================== -*** alpine-2.23.2.orig/alpine/roleconf.c ---- alpine-2.23.2/alpine/roleconf.c -*************** role_text_tool_inick(struct pine *ps, in -*** 7706,7711 **** ---- 7706,7716 ---- - 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)); - -Index: alpine-2.23.2/alpine/send.c -=================================================================== -*** alpine-2.23.2.orig/alpine/send.c ---- alpine-2.23.2/alpine/send.c -*************** static char rcsid[] = "$Id: send.c 1142 -*** 63,69 **** - #include "../pith/mimetype.h" - #include "../pith/send.h" - #include "../pith/smime.h" -! - - typedef struct body_particulars { - unsigned short type, encoding, had_csp; ---- 63,69 ---- - #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; -*************** alt_compose_screen(struct pine *pine_sta -*** 236,241 **** ---- 236,246 ---- - 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); -*************** compose_mail(char *given_to, char *fcc_a -*** 445,452 **** - - ps_global->next_screen = prev_screen; - ps_global->redrawer = redraw; -! if(role) - role = combine_inherited_role(role); - } - break; - ---- 450,461 ---- - - 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; - -*************** compose_mail(char *given_to, char *fcc_a -*** 640,648 **** - } - } - -! if(role) - q_status_message1(SM_ORDER, 3, 4, _("Composing using role \"%s\""), - role->nick); - - /* - * set ps_global->hostname to something sensible, if possible, ---- 649,662 ---- - } - } - -! 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); -+ } - - /* - * set ps_global->hostname to something sensible, if possible, -*************** pine_send(ENVELOPE *outgoing, struct mai -*** 2504,2509 **** ---- 2518,2543 ---- - 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); -Index: alpine-2.23.2/pith/Makefile.am -=================================================================== -*** alpine-2.23.2.orig/pith/Makefile.am ---- alpine-2.23.2/pith/Makefile.am -*************** libpith_a_SOURCES = ablookup.c abdlc.c a -*** 26,32 **** - filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c ical.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 - ---- 26,32 ---- - filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c ical.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 - -Index: alpine-2.23.2/pith/Makefile.in -=================================================================== -*** alpine-2.23.2.orig/pith/Makefile.in ---- alpine-2.23.2/pith/Makefile.in -*************** am_libpith_a_OBJECTS = ablookup.$(OBJEXT -*** 142,148 **** - 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) \ ---- 142,148 ---- - 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) \ -*************** libpith_a_SOURCES = ablookup.c abdlc.c a -*** 441,447 **** - filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c ical.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 - ---- 441,447 ---- - filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c ical.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 - -*************** distclean-compile: -*** 575,580 **** ---- 575,581 ---- - @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@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -Index: alpine-2.23.2/pith/adrbklib.c -=================================================================== -*** alpine-2.23.2.orig/pith/adrbklib.c ---- alpine-2.23.2/pith/adrbklib.c -*************** init_addrbooks(OpenStatus want_status, i -*** 5138,5145 **** - 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; ---- 5138,5151 ---- - 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; -Index: alpine-2.23.2/pith/conf.c -=================================================================== -*** alpine-2.23.2.orig/pith/conf.c ---- alpine-2.23.2/pith/conf.c -*************** static char rcsid[] = "$Id: conf.c 1266 -*** 29,34 **** ---- 29,35 ---- - #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" -*************** CONF_TXT_T cf_text_unk_character_set[] = -*** 225,230 **** ---- 226,261 ---- - - 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."; - - #ifdef _WINDOWS -*************** static struct variable variables[] = { -*** 570,575 **** ---- 601,634 ---- - 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}, -*************** init_vars(struct pine *ps, void (*cmds_f -*** 2718,2723 **** ---- 2777,2783 ---- - 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 */ -*************** feature_list(int index) -*** 3174,3179 **** ---- 3234,3241 ---- - 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, -*************** config_help(int var, int feature) -*** 7842,7847 **** ---- 7904,7937 ---- - 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 : -Index: alpine-2.23.2/pith/conf.h -=================================================================== -*** alpine-2.23.2.orig/pith/conf.h ---- alpine-2.23.2/pith/conf.h -*************** -*** 157,162 **** ---- 157,202 ---- - #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 -Index: alpine-2.23.2/pith/conftype.h -=================================================================== -*** alpine-2.23.2.orig/pith/conftype.h ---- alpine-2.23.2/pith/conftype.h -*************** typedef enum { V_PERSONAL_NAME = 0 -*** 71,76 **** ---- 71,90 ---- - , 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 -*************** typedef enum { -*** 348,353 **** ---- 362,368 ---- - 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, -Index: alpine-2.23.2/pith/detoken.c -=================================================================== -*** alpine-2.23.2.orig/pith/detoken.c ---- alpine-2.23.2/pith/detoken.c -*************** static char rcsid[] = "$Id: detoken.c 76 -*** 25,31 **** - #include "../pith/reply.h" - #include "../pith/mailindx.h" - #include "../pith/options.h" -! - - /* - * Hook to read signature from local file ---- 25,31 ---- - #include "../pith/reply.h" - #include "../pith/mailindx.h" - #include "../pith/options.h" -! #include "../pith/rules.h" - - /* - * Hook to read signature from local file -*************** detoken(ACTION_S *role, ENVELOPE *env, i -*** 91,96 **** ---- 91,98 ---- - - 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; -*************** detoken(ACTION_S *role, ENVELOPE *env, i -*** 104,117 **** - * 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; ---- 106,130 ---- - * 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; -*************** top: -*** 302,308 **** - } - } - } -! else if(pt->what_for & FOR_REPLY_INTRO) - repl = get_reply_data(env, role, pt->ctype, - subbuf, sizeof(subbuf)-1); - ---- 315,321 ---- - } - } - } -! else if(pt->what_for & (FOR_REPLY_INTRO | FOR_RULE)) - repl = get_reply_data(env, role, pt->ctype, - subbuf, sizeof(subbuf)-1); - -Index: alpine-2.23.2/pith/indxtype.h -=================================================================== -*** alpine-2.23.2.orig/pith/indxtype.h ---- alpine-2.23.2/pith/indxtype.h -*************** typedef enum {iNothing, iStatus, iFStatu -*** 84,89 **** ---- 84,94 ---- - iCurNews, iArrow, - iMailbox, iAddress, iInit, iCursorPos, - iDay2Digit, iMon2Digit, iYear2Digit, -+ iFolder, iFlag, iCollection, iRole, iProcid, iScreen, iPkey, -+ iNick, iFccFrom, iFccSender, iAltAddress, -+ iAddressTo, iAddressCc, iAddressRecip, iAddressSender, -+ iBcc, iLcc, -+ iFfrom, iFadd, - iSTime, iSTime24, iKSize, - iRoleNick, iNewLine, - iHeader, iText, -*************** typedef struct index_parse_tokens { -*** 105,119 **** - - - /* 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" - ---- 110,135 ---- - - - /* 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" - -Index: alpine-2.23.2/pith/mailcmd.c -=================================================================== -*** alpine-2.23.2.orig/pith/mailcmd.c ---- alpine-2.23.2/pith/mailcmd.c -*************** static char rcsid[] = "$Id: mailcmd.c 11 -*** 39,44 **** ---- 39,45 ---- - #include "../pith/ablookup.h" - #include "../pith/search.h" - #include "../pith/charconv/utf8.h" -+ #include "../pith/rules.h" - - #ifdef _WINDOWS - #include "../pico/osdep/mswin.h" -*************** do_broach_folder(char *newfolder, CONTEX -*** 665,670 **** ---- 666,672 ---- - 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! */ -*************** do_broach_folder(char *newfolder, CONTEX -*** 991,996 **** ---- 993,999 ---- - - 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 -*************** do_broach_folder(char *newfolder, CONTEX -*** 1114,1120 **** - - 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) ---- 1117,1126 ---- - - 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) -*************** do_broach_folder(char *newfolder, CONTEX -*** 1136,1259 **** - 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: -! alpine_panic("Unexpected incoming startup case"); -! break; -! -! } - } - else if(IS_NEWS(ps_global->mail_stream)){ - /* ---- 1142,1148 ---- - 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)){ - /* -*************** expunge_and_close(MAILSTREAM *stream, ch -*** 1431,1439 **** - /* 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 */ ---- 1320,1330 ---- - /* 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 */ -*************** move_read_msgs(MAILSTREAM *stream, char -*** 1716,1721 **** ---- 1607,1615 ---- - 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; -*************** move_read_msgs(MAILSTREAM *stream, char -*** 1755,1762 **** - 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'; ---- 1649,1657 ---- - 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'; -*************** move_read_incoming(MAILSTREAM *stream, C -*** 1794,1800 **** - && ((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; ---- 1689,1697 ---- - && ((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; -*************** get_uname(char *mailbox, char *target, i -*** 2761,2763 **** ---- 2658,2952 ---- - - 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; -+ -+ 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; -+ } -+ -+ 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: -+ alpine_panic("Unexpected incoming startup case"); -+ break; -+ -+ } -+ } -Index: alpine-2.23.2/pith/mailcmd.h -=================================================================== -*** alpine-2.23.2.orig/pith/mailcmd.h ---- alpine-2.23.2/pith/mailcmd.h -*************** -*** 42,47 **** ---- 42,49 ---- - #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 -*************** int do_broach_folder(char *, CONTEXT_ -*** 63,69 **** ---- 65,77 ---- - 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); -+ 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 *); -Index: alpine-2.23.2/pith/mailindx.c -=================================================================== -*** alpine-2.23.2.orig/pith/mailindx.c ---- alpine-2.23.2/pith/mailindx.c -*************** static char rcsid[] = "$Id: mailindx.c 1 -*** 41,46 **** ---- 41,47 ---- - #include "../pith/send.h" - #include "../pith/options.h" - #include "../pith/ablookup.h" -+ #include "../pith/rules.h" - #ifdef _WINDOWS - #include "../pico/osdep/mswin.h" - #endif -*************** reset_index_format(void) -*** 379,384 **** ---- 380,392 ---- - 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); +--- alpine-2.24.orig/alpine/mailcmd.c ++++ alpine-2.24/alpine/mailcmd.c +@@ -73,6 +73,7 @@ static char rcsid[] = "$Id: mailcmd.c 12 + #include "../pith/tempfile.h" + #include "../pith/search.h" + #include "../pith/margin.h" ++#include "../pith/rules.h" + #ifdef _WINDOWS + #include "../pico/osdep/mswin.h" + #endif +@@ -2721,6 +2722,9 @@ role_compose(struct pine *state) + role->nick = cpystr("Default Role"); + } + ++ if(state->role) ++ fs_give((void **)&state->role); ++ state->role = cpystr(role->nick); /* remember the role */ + state->redrawer = NULL; + switch(action){ + case 'c': +@@ -2771,12 +2775,12 @@ save_prompt(struct pine *state, CONTEXT_ + char *nmsgs, ENVELOPE *env, long int rawmsgno, char *section, + SaveDel *dela, SavePreserveOrder *prea) + { +- int rc, ku = -1, n, flags, last_rc = 0, saveable_count = 0, done = 0; ++ int rc, ku = -1, n = 0, flags, last_rc = 0, saveable_count = 0, done = 0; + int delindex, preindex, r; + char prompt[6*MAX_SCREEN_COLS+1], *p, expanded[MAILTMPLEN]; + char *buf = tmp_20k_buf; + char shortbuf[200]; +- char *folder; ++ char *folder, folder2[MAXPATH]; + HelpType help; + SaveDel del = DontAsk; + SavePreserveOrder pre = DontAskPreserve; +@@ -2784,6 +2788,7 @@ save_prompt(struct pine *state, CONTEXT_ + static HISTORY_S *history = NULL; + CONTEXT_S *tc; + ESCKEY_S ekey[10]; ++ RULE_RESULT *rule; + + if(!cntxt) + alpine_panic("no context ptr in save_prompt"); +@@ -2793,6 +2798,15 @@ save_prompt(struct pine *state, CONTEXT_ + 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); -+ return; -+ } - - if(ps_global->mail_stream && nonempty_patterns(rflags, &pstate)){ - for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)){ -*************** free_hdrtok(HEADER_TOK_S **hdrtok) -*** 452,458 **** - 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}, ---- 460,466 ---- - 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}, -*************** static INDEX_PARSE_T itokens[] = { -*** 460,466 **** - {"SIZETHREAD", iSizeThread, FOR_INDEX}, - {"SIZENARROW", iSizeNarrow, FOR_INDEX}, - {"KSIZE", iKSize, FOR_INDEX}, -! {"SUBJECT", iSubject, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"SHORTSUBJECT", iShortSubject, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"FULLSTATUS", iFStatus, FOR_INDEX}, - {"IMAPSTATUS", iIStatus, FOR_INDEX}, ---- 468,474 ---- - {"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}, - {"SHORTSUBJECT", iShortSubject, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"FULLSTATUS", iFStatus, FOR_INDEX}, - {"IMAPSTATUS", iIStatus, FOR_INDEX}, -*************** static INDEX_PARSE_T itokens[] = { -*** 472,527 **** - {"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}, - {"SMARTTIME24", iSTime24, 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}, ---- 480,539 ---- - {"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}, - {"SMARTTIME24", iSTime24, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, -! {"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}, -! {"ADDRESSSENDER", iAddressSender, 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}, -*************** static INDEX_PARSE_T itokens[] = { -*** 530,585 **** - {"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} - }; - ---- 542,612 ---- - {"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}, -+ {"FCCFROM", iFccFrom, FOR_RULE|FOR_SAVE}, -+ {"FCCSENDER", iFccSender, FOR_RULE|FOR_SAVE}, -+ {"ALTADDRESS", iAltAddress, 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} - }; - -*************** format_index_index_line(INDEXDATA_S *ida -*** 2486,2491 **** ---- 2513,2536 ---- - 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" -*************** try_again: -*** 3880,3886 **** ---- 3925,3941 ---- - - if(p > buf){ - size_t l; -+ ENVELOPE *env; -+ char *rule_result; - -+ 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)); -*************** subj_str(INDEXDATA_S *idata, char *str, -*** 5459,5468 **** - { - 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; ---- 5514,5523 ---- - { - 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; -*************** subj_str(INDEXDATA_S *idata, char *str, -*** 5518,5523 **** ---- 5573,5586 ---- - * 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); -+ } -+ - if(shorten) - shorten_subject(origsubj); - -*************** subj_str(INDEXDATA_S *idata, char *str, -*** 5956,5961 **** ---- 6019,6027 ---- - - if(free_subj) - fs_give((void **) &free_subj); -+ -+ if (we_clear && origsubj) -+ fs_give((void **)&origsubj); - } - - -*************** from_str(IndexColType ctype, INDEXDATA_S -*** 6321,6336 **** - ? "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", (int)(strsize-1-4), (int)(strsize-1-4), -! newsgroups); - break; - } - ---- 6387,6419 ---- - ? "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; - } - -*************** from_str(IndexColType ctype, INDEXDATA_S -*** 6343,6349 **** - break; - - case iFrom: -! set_index_addr(idata, "From", fetch_from(idata), NULL, strsize-1, fptr); - break; - - case iAddress: ---- 6426,6440 ---- - 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: -*************** set_print_format(IELEM_S *ielem, int wid -*** 6641,6643 **** ---- 6732,6795 ---- - } - } - } -+ -+ 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; -+ } ++ } ++ + /* how many context's can be saved to... */ + for(tc = state->context_list; tc; tc = tc->next) + if(!NEWS_TEST(tc)) +Index: alpine-2.24/alpine/mailindx.c +=================================================================== +--- alpine-2.24.orig/alpine/mailindx.c ++++ alpine-2.24/alpine/mailindx.c +@@ -229,6 +229,8 @@ mail_index_screen(struct pine *state) + state->prev_screen = mail_index_screen; + state->next_screen = SCREEN_FUN_NULL; + ++ setup_threading_display_style(); ++ + if(THRD_AUTO_VIEW() + && sp_viewing_a_thread(state->mail_stream) + && state->view_skipped_index +@@ -240,10 +242,14 @@ mail_index_screen(struct pine *state) + + adjust_cur_to_visible(state->mail_stream, state->msgmap); + ++ strcpy(state->screen_name,"index"); ++ + if(THRD_INDX()) + thread_index_screen(state); + else + index_index_screen(state); ++ ++ strcpy(state->screen_name,"unknown"); + } + + +Index: alpine-2.24/alpine/mailpart.c +=================================================================== +--- alpine-2.24.orig/alpine/mailpart.c ++++ alpine-2.24/alpine/mailpart.c +@@ -182,7 +182,7 @@ attachment_screen(struct pine *ps) + maxnumwid = 0, maxsizewid = 0, old_cols = -1, km_popped = 0, expbits, + last_type = TYPEOTHER; + long msgno; +- char *q, *last_subtype = NULL, backtag[64], *utf8str; ++ char *q, *last_subtype = NULL, backtag[64], *utf8str, *screen_name; + OtherMenu what; + ATTACH_S *a; + ATDISP_S *current = NULL, *ctmp = NULL; +@@ -191,6 +191,10 @@ attachment_screen(struct pine *ps) + ps->prev_screen = attachment_screen; + ps->next_screen = SCREEN_FUN_NULL; + ++ screen_name = ps->screen_name[0] ? cpystr(ps->screen_name) : NULL; ++ strncpy(ps->screen_name, "attachment", sizeof(ps->screen_name)); ++ ps->screen_name[sizeof(ps->screen_name)-1] = '\0'; ++ + ps->some_quoting_was_suppressed = 0; + + if(ps->ttyo->screen_rows - HEADER_ROWS(ps) - FOOTER_ROWS(ps) < 1){ +@@ -911,6 +915,12 @@ attachment_screen(struct pine *ps) + + if(screen.titlecolor) + free_color_pair(&screen.titlecolor); ++ ++ if(screen_name){ ++ strncpy(ps->screen_name, screen_name, sizeof(ps->screen_name)); ++ ps->screen_name[sizeof(ps->screen_name)-1] = '\0'; ++ fs_give((void **) &screen_name); ++ } + } + + +Index: alpine-2.24/alpine/mailview.c +=================================================================== +--- alpine-2.24.orig/alpine/mailview.c ++++ alpine-2.24/alpine/mailview.c +@@ -252,6 +252,8 @@ mail_view_screen(struct pine *ps) + ps->prev_screen = mail_view_screen; + ps->force_prefer_plain = ps->force_no_prefer_plain = 0; + ++ strcpy(ps->screen_name, "text"); ++ + if(ps->ttyo->screen_rows - HEADER_ROWS(ps) - FOOTER_ROWS(ps) < 1){ + q_status_message(SM_ORDER | SM_DING, 0, 3, + _("Screen too small to view message")); +@@ -498,6 +500,7 @@ mail_view_screen(struct pine *ps) + #endif + } + while(ps->next_screen == SCREEN_FUN_NULL); ++ strcpy(ps->screen_name, "unknown"); + + if (prefix && *prefix) + fs_give((void **)&prefix); +Index: alpine-2.24/alpine/osdep/termin.gen.c +=================================================================== +--- alpine-2.24.orig/alpine/osdep/termin.gen.c ++++ alpine-2.24/alpine/osdep/termin.gen.c +@@ -33,6 +33,8 @@ static char rcsid[] = "$Id: termin.gen.c + #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" +@@ -72,7 +74,8 @@ int pcpine_oe_cursor(int, long); + * Generic tty input routines + */ + +- ++void process_init_cmds(struct pine *, char **); ++void queue_init_errors(struct pine *); + /*---------------------------------------------------------------------- + Read a character from keyboard with timeout + Input: none +@@ -114,6 +117,41 @@ read_command(char **utf8str) + *utf8str = NULL; + + ucs = read_char(tm); ++ if(!ps_global->initial_cmds){ ++ RULE_RESULT *rule; ++ char **list = NULL, *error = NULL; ++ int commas = 0, k; /* From args.c */ ++ ++ ps_global->pressed_key = cpystr(pretty_command(ucs)); ++ rule = (RULE_RESULT *)get_result_rule(V_KEY_RULES, FOR_KEY, NULL); ++ if(ps_global->pressed_key) ++ fs_give((void **)&ps_global->pressed_key); + if (rule){ -+ 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; -+ } -Index: alpine-2.23.2/pith/mailindx.h -=================================================================== -*** alpine-2.23.2.orig/pith/mailindx.h ---- alpine-2.23.2/pith/mailindx.h -*************** extern void (*setup_header_widths)(MAIL -*** 30,35 **** ---- 30,38 ---- - - - /* 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 *); -Index: alpine-2.23.2/pith/makefile.wnt -=================================================================== -*** alpine-2.23.2.orig/pith/makefile.wnt ---- alpine-2.23.2/pith/makefile.wnt -*************** HFILES= ../include/system.h ../include/g -*** 46,52 **** - 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 smime.h smkeys.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 - ---- 46,53 ---- - 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 rulestype.h save.h savetype.h search.h send.h sequence.h signal.h \ -! smime.h smkeys.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 - -*************** OFILES= ablookup.obj abdlc.obj addrbook. -*** 56,62 **** - ical.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 \ - smime.obj smkeys.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 - ---- 57,63 ---- - ical.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 \ - smime.obj smkeys.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 - -Index: alpine-2.23.2/pith/pine.hlp -=================================================================== -*** alpine-2.23.2.orig/pith/pine.hlp ---- alpine-2.23.2/pith/pine.hlp -*************** There are also additional details on -*** 4433,4438 **** ---- 4433,4439 ---- -

  • FEATURE: -
  • FEATURE: -
  • FEATURE: -+
  • FEATURE: -
  • FEATURE: -
  • FEATURE: -
  • FEATURE: -*************** This set of special tokens may be used i -*** 19930,19935 **** ---- 19931,19937 ---- - "" option, - in the "" option, - in signature files, -+ in the "new-rules" option, - in template files used in - "roles", and in the folder name - that is the target of a Filter Rule. -*************** and in the target of Filter Rules. -*** 19942,19948 **** -

    -

    - -!

    Tokens Available for all Cases (except Filter Rules)

    - -
    -
    SUBJECT
    ---- 19944,19950 ---- -

    -

    - -!

    Tokens Available for all Cases (except Filter Rules or in some cases for new-rules)

    - -
    -
    SUBJECT
    -*************** email address, never the personal name. -*** 19976,19981 **** ---- 19978,19999 ---- - For example, "mailbox@domain". -
  • - -+
    ADDRESSTO
    -+
    -+ This is similar to the "TO" 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, "mailbox@domain" when -+ the e-mail message contains only one person in the To: field, or -+ "peter@flintstones.com president@world.com". -+
    -+ -+
    ADDRESSSENDER
    -+
    -+ This is similar to the "sender" token, only it is always the -+ email address of all person listed in the Sender: field of the message. -+ Example: "mailbox@domain". -+
    -+ -
    MAILBOX
    -
    - This is the same as the "ADDRESS" except that the -*************** are unavailable) of the persons specifie -*** 20023,20028 **** ---- 20041,20055 ---- - message's "Cc:" header field. -
    - -+
    ADDRESSCC
    -+
    -+ This is similar to the "CC" 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: "mailbox@domain" when -+ the e-mail message contains only one person in the Cc: field, or -+ "peter@flintstones.com president@world.com". -+
    -+ -
    RECIPS
    -
    - This token represents the personal names (or email addresses if the names -*************** message's "To:" header field a -*** 20031,20036 **** ---- 20058,20071 ---- - the message's "Cc:" header field. -
    - -+
    ADDRESSRECIPS
    -+
    -+ 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. -+
    -+ -+ -
    NEWSANDRECIPS
    -
    - This token represents the newsgroups from the -*************** This is an end of line marker. -*** 21163,21168 **** ---- 21198,21307 ---- - - -

    -+

    Tokens Available Only for New-Rules

    -+ -+
    -+
    FCCFROM
    -+
    -+ The Fcc: folder assigned to the email address in the From: field in the -+ addressbook. -+
    -+
    -+ -+
    -+
    FCCSENDER
    -+
    -+ The Fcc: folder assigned to the email address in the Sender: field in the -+ addressbook. -+
    -+
    -+ -+
    -+
    ALTADDRESS
    -+
    -+ The value of your -+ -+ variable. At this time, no expansion of regular expressions is supported. -+
    -+
    -+ -+
    -+
    NICK
    -+
    -+ Nickname of the person in the From field in your addressbook. -+
    -+
    -+ -+
    -+
    FOLDER
    -+
    -+ Name of the folder where the rule will be applied. -+
    -+
    -+ -+
    -+
    COLLECTION
    -+
    -+ Name of the collection list where the rule will be applied. -+
    -+
    -+ -+
    -+
    ROLE
    -+
    -+ Name of the Role used to reply a message. -+
    -+
    -+ -+
    -+
    BCC
    -+
    -+ Not implemented yet, but it will be implemented in future versions. It will -+ be used for compose -+ reply -+ forward -+ rules. -+
    -+
    -+ -+
    -+
    LCC
    -+
    -+ This is the value of the Lcc: field at the moment that you start the composition. -+
    -+
    -+ -+
    -+
    FORWARDFROM
    -+
    -+ 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. -+
    -+
    -+ -+
    -+
    FORWARDADDRESS
    -+
    -+ This is the address of the person that sent the message that you -+ are forwarding. -+
    -+
    -+ -+ -+ -+ -+
    -+
    FLAG
    -+
    -+ 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 -+ new rules explanation and example help. -+
    -+
    -+ -+

    -

    Token Available Only for Templates and Signatures

    - -
    -*************** character sets Alpine knows about by usi -*** 24560,24565 **** ---- 24699,25620 ---- - <End of help on this topic> - - -+ ====== h_config_procid ===== -+ -+ -+ Token: PROCID -+ -+ -+

    TOKEN: PROCID explained

    -+ -+

    -+ 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. -+ -+

    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. -+ -+

    -+ Consider the following examples for forward-rules: -+ -+

    -+ _ROLE_ == {work} => _SUBJECT_ := _COPY_{[tag] _SUBJECT_} -+ -+

    -+ and -+ -+

    -+ _ROLE_ == {work} => _LCC_ := _TRIM_{_FORWARDFROM_ <_FORWARDADDRESS_>} -+ -+

    -+ 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 -+ -+

    -+ _PROCID_ == {fwd-subject} && _ROLE_ == {work} => _SUBJECT_ := _COPY_{[tag] _SUBJECT_} -+ -+

    -+ In this case, this rule will be tested fully only when we are determining -+ the subject line of a forwarded message, not otherwise. -+ -+

    -+ 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. -+ -+

    <End of help on this topic> -+ -+ -+ ====== h_config_compose_rules ===== -+ -+ -+ OPTION: <!--#echo var="VAR_compose-rules"--> -+ -+ -+

    OPTION:

    -+ -+

    At this time, this option is used to generate values for signature -+ files that is not possible to do with the use of -+ roles. -+ -+

    For example, you can have a rule like:
    -+ _TO_ >> {Peter Flintstones} => _SIGNATURE_{~/.petersignature} -+ -+

    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 link. -+ -+

    <End of help on this topic> -+ -+ -+ ====== h_config_forward_rules ===== -+ -+ -+ OPTION: <!--#echo var="VAR_forward-rules"--> -+ -+ -+

    OPTION:

    -+ -+

    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 this link. -+ -+

    If you want to edit the subject of a forwarded message, use the -+ PROCID fwd-subject. For example you could have a rule like -+ -+

    -+ _ROLE_ == {admin} && _SUBJECT_ !> {[tag] } => _COPY_{[tag] _SUBJECT_} -+ -+

    Another way in which this option can be used, is to trim the values of -+ some fields. For this application the PROCID is fwd-lcc. For -+ example it can be used in the following way: -+ -+

    -+ _ROLE_ == {work} => _LCC_ := _TRIM_{_FORWARDFROM_ <_FORWARDADDRESS_>} -+ -+

    Other functions that can be used in this option are _EXEC_, _REXTRIM_ and -+ _REXSUB_. -+ -+

    You can also use the _EXEC_ function. The documentation for this function -+ is in the -+ -+ help text. -+ -+

    Another function that can be used is the _REXSUB_ function which does -+ a substitution. This function takes three parameters: a pattern to search -+ for, the text to be substituted for when the pattern is matched, and the -+ number of times that the pattern will be replaced. Each of the parameters -+ is enclosed between "{" and "}". For example, to -+ delete only one ocurrence of the string "Re: " in a subject we -+ would write a rule such as -+ -+

    -+ _FOLDER_ >> {} => _SUBJECT_ := _REXSUB_{Re: }{}{1} -+ -+

    The last parameter of the rexsub function is optional. In the sense -+ that its omission is understood as if the third parameter was -+ "{1}". In order to make unlimited substitutions, use -+ "{g}" as the last parameter. -+ -+

    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 link. -+ -+

    <End of help on this topic> -+ -+ -+ ====== h_config_index_rules ===== -+ -+ -+ OPTION: <!--#echo var="VAR_index-rules"--> -+ -+ -+

    OPTION:

    -+ -+

    This option is used to supersede the value of the option for specific folders. In -+ this form you can have different index-formats for different folders. For -+ example an entry here may be: -+ -+

    -+ _FOLDER_ == {INBOX} => _INDEX_{IMAPSTATUS DATE FROM(33%) SIZE SUBJECT(67%)} -+ -+

    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 link. -+ -+

    <End of help on this topic> -+ -+ -+ ====== h_config_pretty_command ===== -+ -+ -+ Pretty-Command Explained -+ -+ -+

    Pretty Command Explained

    -+ -+

    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. -+ -+

    [Command "RETURN" not defined for this screen. Use ? for help] -+ -+

    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. -+ -+

    <End of help on this topic> -+ -+ -+ ====== h_config_key_macro_rules ===== -+ -+ -+ OPTION: <!--#echo var="VAR_key-definition-rules"--> -+ -+ -+

    OPTION:

    -+ -+

    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. -+ -+

    Always use the _SCREEN_ token as defined below.. You have been -+ warned! -+ -+

    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. -+ -+

    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. -+ -+

    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 (MESSAGE INDEX), the -+ screen where your message is displayed (MESSAGE -+ TEXT) the screen where the list of folders is displayed (FOLDER LIST) and the attachment index screen (ATTACHMENT INDEX). The internal names of -+ these screens for this patch are "index", "text", -+ "folder", and "attachment", respectively. Please note -+ that the internal names are all in lowercase and are case sensitive. -+ -+

    In order to define the screen, you use the _SCREEN_ token, so for -+ example, you can write _SCREEN_ == {index}. -+ -+

    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 "pressed key"). For -+ example you could use _PKEY_ == {~}, to designate the "~" -+ key to activate the command. Some keystrokes (like control, or -+ function keys) are encoded in special ways. You should read the -+ full explanation on how to find -+ out the encoding for each keystroke. -+ -+

    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 -+ "$" and "h". You use the _COMMAND_ function to specify -+ this. The syntax in this case is _COMMAND_{$,h}. -+ -+

    Observe that in the above example the different inputs are separated -+ by commas. This is the standard way in which the -+ 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. -+ -+

    -+ "_SCREEN_ == {index} && _PKEY_ == {~} => _COMMAND_{$,h}" -+ -+

    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 -+ -+

    -+ _SCREEN_ == {index} && _PKEY_ == {~} => _COMMAND_{"$h"} -+ -+

    For more information on how to define the argument of the _COMMAND_ -+ token see the help of -+ . -+ -+

    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. -+ -+

    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 link. -+ -+

    <End of help on this topic> -+ -+ -+ ====== h_config_replace_rules ===== -+ -+ -+ OPTION: <!--#echo var="VAR_replace-rules"--> -+ -+ -+

    OPTION:

    -+ -+

    This option is used to have Alpine print different values for specific -+ tokens in the . For example you -+ can replace strings like "To: newsgroup" by your name. -+ -+

    Here are examples of possible rules: -+ -+

    _FOLDER_ != {sent-mail} && _NICK_ != {} => _FROM_ := _REPLACE_{_FROM_ (_NICK_)} -+ -+

    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 -+ -+

    _FOLDER_ == {INBOX} => _SUBJECT_ := _REXTRIM_{\[some-tag-here #[0-9].*\]} -+ -+

    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.
    -+ -+

    _FOLDER_ == {some-folder} => _OPENINGTEXTNQ_ := _REXTRIM_{On.*wrote: } -+ -+

    You can also use the _EXEC_ function. The documentation for this function -+ is in the -+ -+ help text. -+ -+

    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 link. -+ -+

    <End of help on this topic> -+ -+ -+ ====== h_config_reply_leadin_rules ===== -+ -+ -+ OPTION: <!--#echo var="VAR_reply-leadin-rules"--> -+ -+ -+

    OPTION:

    -+ -+

    This option is used to have Alpine generate a different -+ string dependent either on -+ the person you are replying to, or the folder where the message is being -+ replied is in, or both. -+ -+

    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: -+

    -+ _FOLDER_ << {pine-info;_NEWS_} => _REPLY_{*** _FROM_ _ADDRESS_("_FROM_" "" "(_ADDRESS_) ")wrote in_NEWS_("" " the" "") _FOLDER_ _NEWS_("" "list " "")_SMARTDATE_("Today" "today" "on _LONGDATE_"):} -+ -+

    Here there is an example that one can use to change the reply indent string -+ to reply people that speak spanish. -+

    -+ _FROM_{Condorito;Quico} => _REPLY_{*** _FROM_ (_ADDRESS_) escribió _SMARTDATE_("Today" "hoy" "en _LONGDATE_"):} -+ -+

    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 link. -+ -+

    <End of help on this topic> -+ -+ -+ ====== h_config_resub_rules ===== -+ -+ -+ OPTION: <!--#echo var="VAR_reply-subject-rules"--> -+ -+ -+

    OPTION:

    -+ -+

    This option is used to have Alpine generate a different subject when -+ replying rather than the one Alpine would generate automatically. -+ -+

    Here there are a couple of examples about how to use this -+ configuration option: -+ -+

    In order to have messages with empty subject to be replied with the message -+ "your message" use the rule
    -+

    _SUBJECT_ == {} => _RESUB_{Re: your message}
    -+ -+

    If you want to trim some parts of the subject when you reply use the -+ rule
    -+

    _SUBJECT_ >> {[one];two} => _SUBJECT_ := _TRIM_{[;];two}
    -+ -+

    this rule removes the brackets "[" and "]" whenever the string "[one]" -+ appears in it, it also removes the word "two" from it. -+ -+

    Another example where you may want to use this rule is when you -+ correspond with people that change the reply string from "Re:" -+ to "AW:" or "Sv:". In this case a rule like
    -+

    _SUBJECT_ >> {Sv: ;AW: } => _SUBJECT_ := _TRIM_{Sv: ;AW: }
    -+

    -+ would eliminate undesired strings in replies. -+ -+

    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 "a" of a file. -+ -+

    -+ #!/bin/sh
    -+ sed 's/a//g' $1 > /tmp/mytest
    -+ mv /tmp/mytest $1
    -+ 
    -+ -+

    -+ As you can see this script took "$1" 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 "$1". This is the kind of behavior -+ that your program is expected to have. -+ -+

    -+ The content of the input file ("$1" above) is the value of a token -+ like _SUBJECT_. In order to indicate this, we use the notation -+ -+

    -+ _SUBJECT_ := _EXEC_{/path/to/script} -+ -+

    for the action. So for example -+ -+

    -+ _FOLDER_ := {sent-mail} => _SUBJECT_ := _EXEC_{/path/to/script} -+ -+

    is a valid rule. -+ -+

    You can also use this configuration option to customize reply subjects -+ according to the sender of the message. -+ -+

    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 link. -+ -+

    <End of help on this topic> -+ -+ -+ ====== h_config_sort_rules ===== -+ -+ -+ OPTION: <!--#echo var="VAR_sort-rules"--> -+ -+ -+

    OPTION:

    -+ -+

    This option is used to have Alpine sort different folders in different orders -+ and thus override the value already set in the -+ configuration option. -+ -+

    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. -+ -+

    -+ _COLLECTION_ >> {Incoming-Folders;News} && _FOLDER_ != {INBOX} => _SORT_{tHread} -+ -+

    Another example could be
    -+ _FOLDER_ == {Mailing List} => _SORT_{Reverse tHread} -+ -+

    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 link. -+ -+

    <End of help on this topic> -+ -+ -+ -+ ====== h_config_save_rules ===== -+ -+ -+ OPTION: <!--#echo var="VAR_save-rules"--> -+ -+ -+

    OPTION:

    -+ -+

    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). -+ -+

    If this option is set and the -+ configuration -+ option is also enabled then these definitions will be used to move messages -+ from your INBOX when exiting Alpine. -+ -+

    Here there are some examples
    -+ _FLAG_ >> {D} -> Trash
    -+ _FROM_ == {U2} -> Bono
    -+ _FOLDER_ == {comp.mail.pine} -> pine-stuff
    -+ _NICK_ != {} -> _NICK_/_NICK_
    -+ _DATEISO_ >> {02-10;02-11} -> archive-oct-nov-2002 -+ -+

    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 link. -+ -+

    <End of help on this topic> -+ -+ -+ -+ ====== h_config_reply_indent_rules ===== -+ -+ -+ OPTION: <!--#echo var="VAR_reply-indent-rules"--> -+ -+ -+

    OPTION:

    -+ -+

    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 -+ is used. -+ -+

    The associated function to this configuration option is called "RESTR" (for -+ REply STRing). Some examples of its use are:
    -+ _FROM_ == {Your Boss} => _RESTR_{"> "}
    -+ _FROM_ == {My Wife} => _RESTR_{":* "}
    -+ _FROM_ == {Perter Flintstone;Wilma Flintstone} => _RESTR_{"_INIT_ > "}
    -+ -+

    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 link. -+ -+

    <End of help on this topic> -+ -+ -+ -+ ====== h_config_smtp_rules ===== -+ -+ -+ OPTION: <!--#echo var="VAR_smtp-rules"--> -+ -+ -+

    OPTION:

    -+ -+

    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 -+ "" configuration -+ option according to the rules used in that variable. -+ -+

    The function associated to this configuration option is _SMTP_, an example -+ of the use of this function is
    -+ _ADDRESSTO_ == {peter@bedrock.com} => _SMTP_{smtp.bedrock.com} -+ -+

    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 link. -+ -+

    <End of help on this topic> -+ -+ -+ -+ ====== h_config_startup_rules ===== -+ -+ -+ OPTION: <!--#echo var="VAR_startup-rules"--> -+ -+ -+

    OPTION:

    -+ -+

    This option is used when a folder is being opened. You can use it to specify its and override -+ Alpine's global value set for all folders. -+ -+

    An example of the usage of this option is:
    -+ _FOLDER_ == {Lynx;pine-info;_NEWS_} => _STARTUP_{first-unseen} -+ -+

    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 link. -+ -+

    <End of help on this topic> -+ -+ -+ -+ ====== h_config_new_rules ===== -+ -+ -+ OPTION: New Rules Explained -+ -+ -+

    OPTION: New Rules Explained

    -+ -+ This is a quite powerful option. Here you can define rules that override -+ the values of any other option you have set in Alpine. -+ -+

    -+ 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 "rules" 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. -+ -+

    -+ 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 satisfied. -+ -+

    -+ Here is an example: -+ -+

    -+ _FROM_ == {Fred Flintstone} => _SAVE_{Fred} -+ -+

    -+ Here the separator is "=>". Whatever is to the left of the separator -+ is the condition (that is _FROM_ == {Fred Flintstone}) 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 "Fred -+ Flintstone", and the action will be that you will be offered to save -+ it in the folder "Fred", whenever you press the letter -+ "S" to save a message. -+ -+

    -+ The separator is always "=>", with one exception to be seen -+ later. But for the most part this will be the only one you will ever need. -+ -+

    -+ Now let us see how to do it. There are 14 functions already defined for -+ you. These are: _EXEC_, _INDEX_, _REPLACE_, _REPLY_, _RESUB_, _SAVE_, -+ _SIGNATURE_, _SORT_, _STARTUP_, _TRIM_, _REXTRIM_, _REXSUB_, _THREADSTYLE and -+ _THREADINDEX_. The parameter of a function has to be enclosed between -+ "{" and "}", so for example you can specify -+ _SAVE_{saved-messages} as a valid sentence. -+ -+

    -+ Later in the document you will find examples. Here is a short -+ description of what each function does: -+ -+

    -+

      -+
    • _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 -+ , -+ and -+ . -+ See the help of those options for examples of how to use this function -+ and configure these rules. -+
       
      -+
    • _INDEX_ : This function takes as an argument an index-format, and -+ makes that the index-format for the specified folder. -+
       
      -+
    • _REPLACE_ : This function replaces the subject/from of the given e-mail by -+ another subject/from only when displaying the index. -+
       
      -+
    • _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. -+
       
      -+
    • _RESTR_ : This function takes as an argument the value of the -+ reply-indent-string to be used to answer the message being replied to. -+
       
      -+
    • _RESUB_ : This function replaces the subject of the given e-mail by -+ another subject only when replying to a message. -+
       
      -+
    • _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. -+
       
      -+
    • _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. -+
       
      -+
    • _SMTP_ : This function takes as an argument the definition of a -+ SMTP server. -+
       
      -+
    • _SORT_ : This function takes as an argument a Sort Style, and sorts a -+ specified folder in that sort order. -+
       
      -+
    • _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_. -+
       
      -+
    • _REXTRIM_ : Same as _TRIM_ but its argument is one and -+ only one extended regular expression. -+
       
      -+
    • _REXSUB_ : This function takes three arguments. The structure -+ is _REXSUB_{pattern}{text}{number of times}. The "pattern" -+ to match is an extended regular expression. If the pattern is matched, -+ it will be replaced by "text" as many times as the "number -+ of times" argument specifies. If the last argument is -+ omitted (that is, there are only two arguments) then the last argument -+ is considered as "{1}". -+
       
      -+
    • _STARTUP_ : This function takes as an argument an -+ incoming-startup-rule, and open an specified folder using that rule. -+
       
      -+
    • _THREADSTYLE_ : This function takes as an argument a -+ threading-display-style and uses it to display threads in a folder. -+
       
      -+
    • _THREADINDEX_ : This function takes as an argument a -+ threading-index-style and uses it to display threads in a folder. -+
    -+ -+

    -+ 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: -+ -+

    -+ _FROM_ == {Fred Flintstone} => _SAVE_{Fred} -+ -+

    it will only be applied if the from is "Fred Flintstone". If -+ the From is "Wilma Flintstone" the rule will be skipped. -+ -+

    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 "{" and "}" in the condition, this part -+ of the condition is called the "condition set". The definition -+ of each token can be found here. -+ -+

    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 -+ this link. -+ -+

    There are two more tokens related to the option -+ key-definition-rules. Those tokens -+ are only specific to that option, and hence are not explained here. -+ -+

    You can also test in different ways, you can use the following -+ "test operands": <<, !<, >>, !>, == and !=. -+ All of them are two characters long. Here is the meaning of them: -+ -+

    -+

      -+
    • << : It tests if the value of the token is contained in -+ the condition set. Here for example if the condition set were equal to -+ "Freddy", then the condition: _NICK_ << {Freddy}, would be true if -+ the value of _NICK_ were "Fred", "red" or "Freddy". You are just looking -+ for substrings here. -+
    • >> : 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 -+ "Fred", then the condition: _FROM_ >> {Fred}, would be true if -+ the value of _FROM_ were "Fred Flintstone" or "Fred P. Flintstone" or "Freddy". -+
    • == : 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 "Freddy" or "red". -+
    • !< : This is true only when << is false and vice versa. -+
    • !> : This is true only when >> is false and vice versa. -+
    • != : This is true only when == is false and vice versa. -+
    -+ -+

    -+ Now let us say that you want the same action to be applied to more than -+ one person or folder, say you want "folder1" and "folder2" to be sorted by -+ Ordered Subject upon entering. Then you can list them all of them in the -+ condition part separting them by a ";". Here is the way to do it. -+ -+

    -+ _FOLDER_ << {folder1; folder2} => _SORT_{OrderedSubj} -+ -+

    -+ Here is the first subtlety about these definitions. Notice that the -+ following rule: -+ -+

    -+ _FOLDER_ == {folder1; folder2} => _SORT_{Reverse OrderedSubj} -+ -+

    works only for "folder1" but not for "folder2". This is because the -+ comparison of the name of the folder is done with whatever is in between -+ "{", ";" or "}", so in the above rule you would be testing
    -+ "folder2" == " folder2". The extra space makes the difference. -+ The reason why the first rule does not fail is because -+ "folder2" << " folder2" is actually -+ true. If something ever fails this may be something to look into. -+ -+

    -+ Here are a few examples of what we have talked about before. -+ -+

    -+ _NICK_ == {lisa;kika} => _SAVE_{_NICK_/_NICK_}
    -+ This means that if the nick is lisa, it will -+ save the message in the folder "lisa/lisa", and if the nick -+ is "kika", it will save the message in the folder "kika/kika" -+ -+

    -+ _FOLDER_ == {Lynx} -> lynx
    -+ This, is an abbreviation of the following rule:
    -+ _FOLDER_ == {Lynx} => _SAVE_{lynx}
    -+ (note the change in separator from "=>" to "->"). In the future -+ I will use that abbreviation. -+ -+

    _FOLDER_ << {comp.mail.pine; pine-info; pine-alpha} -> pine
    -+ Any message in the folders "comp.mail.pine", "pine-info" or "pine-alpha" -+ will be saved to the folder "pine". -+ -+

    _FROM_ << {Pine Master} -> pine
    -+ Any message whose From field contains -+ "Pine Master" will be saved in the folder pine. -+ -+

    _FOLDER_ << {Lynx; pine-info; comp.mail.pine} => -+ _INDEX_{IMAPSTATUS MSGNO DATE FROMORTO(33%) SUBJECT(66%)}
    Use a -+ different index-format for the folders "Lynx", "pine-info" and -+ "comp.mail.pine", where the size is not present. -+ -+

    _FOLDER_ == {Lynx;pine-info} => _REPLY_{*** _FROM_ (_ADDRESS_) -+ wrote in the _FOLDER_ list _SMARTDATE_("Today" "today" "on -+ _LONGDATE_"):}
    If a message is in one of the incoming folders "Lynx" -+ or "pine-info", create a reply-leadin-string that acknowledges that. Note -+ the absence of "," in the function _SMARTDATE_. For example answering to a -+ message in the pine-info list would look like: -+ -+

    -+ *** Steve Hubert (hubert@cac.washington.edu) wrote in the pine-info list today: -+ -+

    -+ However replying for a message in the Lynx list would look: -+ -+

    -+ *** mattack@area.com (mattack@area.com) wrote in the Lynx list today: -+ -+

    -+ If you write in more than one language you can use this feature to create -+ Reply-leadin-strings in different languages. -+ -+

    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. -+ -+

    _FOLDER_ << {Lynx; comp.mail.pine; pine_info; pine-alpha} => -+ _SORT_{OrderedSubj}
    This means upon opening, sort the folders "Lynx", -+ "comp.mail.pine", 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). -+ -+

    The last examples use the function _TRIM_ which has a special form. -+ This function can only be used in the index list. -+ -+

    _FOLDER_ << {Lynx} => _SUBJECT_ := _TRIM_{lynx-dev }
    In -+ the folder "Lynx" eliminate from the subject the string "lynx-dev " (with -+ the space at the end). For example a message whose subject is "Re: -+ lynx-dev unvisited Visited Links", would be shown in the index with -+ subject: "Re: unvisited Visited Links", making the subject shorter and -+ giving the same information. -+ -+

    _FROM_ >> {Name (Comment)} => _FROM_ := -+ _TRIM_{ (Comment)}
    Remove the part " (Comment)" -+ from the _FROM_, so when displaying in the index the real From "Name" -+ will appear. -+ -+

    _SUBJECT_ == {} => _RESUB_{Re: your mail without subject} -+ If there is no subject in the message, use the subject "Re: your mail -+ wiyhout subject" as a subject for the reply message. -+ -+

    You can add more complexity to your rules by checking more than one -+ conditions before a rule is executed. More than one condition can be -+ checked by separating different conditions by the && (and) separator, -+ or using the || (or) separator. For example we could have a rule that -+ saves all -+ messages in inbox from Rubye, to the Personal folder, as -+ -+

    _FOLDER_ == {INBOX} && _FROM_ >> {Rubye} => _SAVE_{Personal} -+ -+

    We could also have a rule that is triggered by an "or" -+ condition by, sat for messages from Andres or messages in the index -+ to trigger a specific reply leadin string. -+ -+

    _FOLDER_ == {INBOX} || _FROM_ >> {Andres} => _REPLY_{You wrote:} -+ -+

    Observe that the construction -+ -+

    _TOKEN_ == {value1} || _TOKEN_ == {value2} -+ -+

    can be shortened to -+ -+

    _TOKEN_ == {value1;value2} -+ -+

    Round parentheses can be used to group some conditions, for example -+ -+

    (_FROM_ >> {Andres} && _FOLDER_ == {INBOX}) || _FROM_ >> {Rubye} -+ -+ -+

    You can also list your index by nick, in the following way:
    -+ _NICK_ != {} => _FROM_ := _REPLACE_{_NICK_} -+ -+

    -+ If you want to open the folder "pine-info" in the first non-read message -+ use the rule:
    -+ _FOLDER_ == {pine-info} => _STARTUP_{first-unseen} -+ -+

    -+ If you want to move your deleted messages to a folder, called "Trash", use -+ the following rule:
    -+ _FLAG_ >> {D} -> Trash -+ -+

    -+ The reason why the above test is not "_FLAG_ == {D}" 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. -+ -+

    If you want to use a specific signature when you are in a specific collection -+ use the following rule:
    -+ _COLLECTION_ == {Mail} => _SIGNATURE_{/full/path/to/.signature} -+ -+

    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 "saving" rules do not compete with "sorting" rules. So the first -+ "saving" rule that matches will be executed in the case of saving and so -+ on. -+ -+

    -+

    -+ <End of help on this topic> -+ -+ - ====== h_config_char_set ===== - - -*************** the From field is used to show the relat -*** 28312,28317 **** ---- 29367,29442 ---- - <End of help on this topic> - - -+ ====== h_config_thread_display_style_rule ===== -+ -+ -+ OPTION: Threading-Display-Style-Rule -+ -+ -+

    OPTION: Threading-Display-Style-Rule

    -+ -+ This option is very similar to -+ , but it is a rule which specifies the -+ display styles for a thread that you want displayed in a specific -+ folder or collection. -+

    -+ The token to be used in this function is _THREADSTYLE_. Here there is -+ an example of its use -+

    -+ _FOLDER_ == {pine-info} => _THREADSTYLE_{mutt-like} -+

    -+ 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 threading-display-style -+ configuration option. -+ -+

    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 link. -+ -+

    -+

    -+ <End of help on this topic> -+ -+ -+ ====== h_config_thread_index_style_rule ===== -+ -+ -+ OPTION: Threading-Index-Style-Rule -+ -+ -+

    OPTION: Threading-Index-Style-Rule

    -+ -+ This option is very similar to -+ , but it is a rule which specifies the -+ index styles for a thread that you want displayed in a specific -+ folder or collection. -+

    -+ The token to be used in this function is _THREADINDEX_. Here there is -+ an example of its use -+

    -+ _FOLDER_ == {pine-info} => _THREADINDEX_{regular-index-with-expanded-threads} -+

    -+ 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 -+ configuration option. -+ -+

    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 link. -+ -+

    -+

    -+ <End of help on this topic> -+ -+ - ====== h_config_pruning_rule ===== - - -*************** automatically transfer all read messages -*** 32003,32008 **** ---- 33128,33156 ---- - them as deleted in the INBOX. Messages in the INBOX marked with an - "N" (meaning New, or unseen) are not affected. -

    -+

    -+ <End of help on this topic> -+ -+ -+ ====== h_config_auto_read_msgs_rules ===== -+ -+ -+ FEATURE: auto-move-read-msgs-using-rules -+ -+ -+

    FEATURE: auto-move-read-msgs-using-rules

    -+ This feature controls an aspect of Alpine's behavior upon quitting. If set, -+ and the -+ "" -+ 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 -+ "" and mark -+ them as deleted in the INBOX. Messages in the INBOX marked with an -+ "N" (meaning New, or unseen) are not affected. -+

    -

    -Index: alpine-2.23.2/pith/reply.c -=================================================================== -*** alpine-2.23.2.orig/pith/reply.c ---- alpine-2.23.2/pith/reply.c -*************** static char rcsid[] = "$Id: reply.c 1074 -*** 47,52 **** ---- 47,54 ---- - #include "../pith/mailcmd.h" - #include "../pith/margin.h" - #include "../pith/smime.h" -+ #include "../pith/copyaddr.h" -+ #include "../pith/rules.h" - - - /* -*************** char * -*** 864,871 **** - 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 */ ---- 866,892 ---- - 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 */ -*************** reply_quote_str(ENVELOPE *env) -*** 917,926 **** - 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))); - } - - ---- 938,966 ---- - 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))); - } - - -*************** get_addr_data(ENVELOPE *env, IndexColTyp -*** 1486,1491 **** ---- 1526,1535 ---- - buf[0] = '\0'; - - switch(type){ -+ case iFfrom: -+ addr = env && env->sparep ? env->sparep : NULL; -+ break; -+ - case iFrom: - addr = env ? env->from : NULL; - break; -*************** get_reply_data(ENVELOPE *env, ACTION_S * -*** 1898,1919 **** - - 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)){ - strncpy(buf, NEWLINE, maxlen); ---- 1942,2135 ---- - - 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 = ps_global->mail_stream; -! MSGNO_S *msgmap = NULL; -! long msgno; -! MESSAGECACHE *mc; -! strncpy(buf, "_FLAG_", maxlen); /* default value */ -! if (stream){ -! msgmap = sp_msgmap(stream); -! 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" : "" ); -! } -! buf[maxlen] = '\0'; -! } -! break; -! -! case iAltAddress: -! if(ps_global->VAR_ALT_ADDRS != NULL -! && ps_global->VAR_ALT_ADDRS[0] != NULL){ -! size_t len; -! int i, j; -! -! for(i = 0, len = 0; len < maxlen && ps_global->VAR_ALT_ADDRS[i]; i++){ -! for(j = 0; len < maxlen && ps_global->VAR_ALT_ADDRS[i][j] != '\0'; j++){ -! if(ps_global->VAR_ALT_ADDRS[i][j] == ';') -! buf[len++] = '\\'; -! buf[len++] = ps_global->VAR_ALT_ADDRS[i][j]; -! } -! if(len < maxlen){ -! if(ps_global->VAR_ALT_ADDRS[i+1] != NULL) -! buf[len++] = ';'; -! else -! buf[len++] = '\0'; -! } -! } -! buf[maxlen] = '\0'; -! } -! break; -! -! case iNick: -! case iFccFrom: -! case iFccSender: -! if (env){ -! ADDRESS *tmp_adr; -! -! switch(type){ -! case iNick: -! tmp_adr = env->from ? copyaddr(env->from) -! : env->sender ? copyaddr(env->sender) : NULL; -! break; -! case iFccFrom: -! tmp_adr = env->from ? copyaddr(env->from) : NULL; -! break; -! case iFccSender: -! tmp_adr = env->sender ? copyaddr(env->sender) : NULL; -! break; -! default: alpine_panic("Unhandled Rules case (01)"); -! } -! if(type == iNick) -! get_nickname_from_addr(tmp_adr, buf, maxlen); -! else -! get_fcc_from_addr(tmp_adr, buf, maxlen); -! mail_free_address(&tmp_adr); - } - break; - -+ case iAddressSender: -+ 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) -+ : (type == iAddressSender) -+ ? ((env && env->sender) -+ ? copyaddr(env->sender) -+ : 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)){ - strncpy(buf, NEWLINE, maxlen); -*************** get_reply_data(ENVELOPE *env, ACTION_S * -*** 1941,1946 **** ---- 2157,2167 ---- - - 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); -*************** get_reply_data(ENVELOPE *env, ACTION_S * -*** 1990,1995 **** ---- 2211,2224 ---- - - break; - -+ case iOpeningText: -+ case iOpeningTextNQ: -+ if(env && env->sparep){ -+ strncpy(buf, ((SPAREP_S *)env->sparep)->value, maxlen); -+ buf[maxlen] = '\0'; -+ } -+ break; -+ - case iSubject: - case iShortSubject: - if(env && env->subject){ -*************** reply_delimiter(ENVELOPE *env, ACTION_S -*** 2052,2058 **** - 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)){ ---- 2281,2298 ---- - 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)){ -*************** forward_subject(ENVELOPE *env, int flags -*** 2311,2316 **** ---- 2551,2557 ---- - { - size_t l; - char *p, buftmp[MAILTMPLEN]; -+ RULE_RESULT *rule; - - if(!env) - return(NULL); -*************** forward_subject(ENVELOPE *env, int flags -*** 2318,2326 **** - 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) ---- 2559,2577 ---- - 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)){ -! snprintf(buftmp, sizeof(buftmp), "%s", rule->result); -! fs_give((void **)&rule->result); -! fs_give((void **)&rule); -! } -! else if(env->subject) -! snprintf(buftmp, sizeof(buftmp), "%s", 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) -Index: alpine-2.23.2/pith/rules.c -=================================================================== -*** /dev/null ---- alpine-2.23.2/pith/rules.c -*************** -*** 0 **** ---- 1,1565 ---- -+ /* This module was written by -+ * -+ * Eduardo Chappa (chappa@washington.edu) -+ * http://alpine.x10host.com/alpine/ -+ * -+ * Original Version: November 1999 -+ * Last Modified : November 24, 2018 -+ * -+ * 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/mailindx.h" -+ #include "../pith/rules.h" -+ -+ #define CSEP_C ('\001') -+ #define CSEP_S ("\001") -+ -+ /* 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 *); -+ int sanity_check_condition (char *); -+ char *test_rule (RULELIST *, int, ENVELOPE *, int *); -+ char *trim (RULEACTION_S *, int, ENVELOPE *); -+ char *rextrim (RULEACTION_S *, int, ENVELOPE *); -+ char *rexsub (RULEACTION_S *, int, ENVELOPE *); -+ char *do_rextrim (char *, TOKEN_VALUE *); -+ char *do_rexsub (char *, TOKEN_VALUE *); -+ char *raw_value (RULEACTION_S *, int, ENVELOPE *); -+ char *extended_value (RULEACTION_S *, int, ENVELOPE *); -+ char *exec_fcn (RULEACTION_S *, int, ENVELOPE *); -+ char *expand (char *, char *); -+ char *get_name_token (char *); -+ char *advance_to_char (char *, char, int, int *); -+ char **functions_for_token (char *); -+ char *canonicalize_condition (char *, int *); -+ void free_rexsub (REXSUB_S **); -+ void free_void_token_value (void **, int); -+ void free_token_value (TOKEN_VALUE **); -+ void free_condition (CONDITION_S **); -+ void free_condition_value (CONDVALUE_S **); -+ void free_ruleaction (RULEACTION_S **); -+ void free_rule (RULE_S **); -+ void free_rule_list (RULELIST **); -+ void *rule_alloc_mem (size_t); -+ void add_rule (int, int); -+ void set_rule_list (struct variable *); -+ 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 *); -+ TOKEN_VALUE *parse_action_to_char(char *); -+ TOKEN_VALUE *parse_rexsub_action(char *); -+ CONDVALUE_S *fill_condition_value (char *); -+ 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, 6, 1, CHAR_TYPE, parse_action_to_char, extended_value, FOR_SAVE|FOR_COMPOSE}, -+ {REXTRIM_FCN, 9, 1, CHAR_TYPE, parse_action_to_char, rextrim, FOR_REPLACE|FOR_TRIM|FOR_RESUB|FOR_COMPOSE}, -+ {REXSUB_FCN, 8, 1, REXSUB_TYPE, parse_rexsub_action, rexsub, FOR_REPLACE|FOR_TRIM|FOR_RESUB|FOR_COMPOSE}, -+ {EXEC_FCN, 6, 1, CHAR_TYPE, parse_action_to_char, exec_fcn, FOR_REPLACE|FOR_TRIM|FOR_RESUB|FOR_COMPOSE}, -+ {TRIM_FCN, 6, 1, CHAR_TYPE, parse_action_to_char, trim, FOR_REPLACE|FOR_TRIM|FOR_RESUB|FOR_COMPOSE}, -+ {REPLACE_FCN, 7, 1, CHAR_TYPE, parse_action_to_char, extended_value, FOR_REPLACE}, -+ {SAVE_FCN, 6, 0, UNDEFINED_TYPE, NULL, extended_value, FOR_SAVE}, -+ {REPLY_FCN, 7, 0, UNDEFINED_TYPE, NULL, extended_value, FOR_REPLY_INTRO}, -+ {SORT_FCN, 6, 0, UNDEFINED_TYPE, NULL, raw_value, FOR_SORT}, -+ {INDEX_FCN, 7, 0, UNDEFINED_TYPE, NULL, raw_value, FOR_INDEX}, -+ {COMMAND_FCN, 9, 0, UNDEFINED_TYPE, NULL, raw_value, FOR_KEY}, -+ {REPLYSTR_FCN, 10, 0, UNDEFINED_TYPE, NULL, raw_value, FOR_COMPOSE}, -+ {SIGNATURE_FCN,11, 0, UNDEFINED_TYPE, NULL, raw_value, FOR_COMPOSE}, -+ {RESUB_FCN, 7, 0, UNDEFINED_TYPE, NULL, extended_value, FOR_RESUB}, -+ {STARTUP_FCN, 9, 0, UNDEFINED_TYPE, NULL, raw_value, FOR_STARTUP}, -+ {THRDSTYLE_FCN,11, 0, UNDEFINED_TYPE, NULL, raw_value, FOR_THREAD}, -+ {THRDINDEX_FCN,11, 0, UNDEFINED_TYPE, NULL, raw_value, FOR_THREAD}, -+ {SMTP_FCN, 6, 0, UNDEFINED_TYPE, NULL, raw_value, FOR_COMPOSE}, -+ {NULL, 0, 0, UNDEFINED_TYPE, 0, 0, FOR_NOTHING} -+ }; -+ -+ char* token_rules[] = { -+ FROM_TOKEN, -+ NICK_TOKEN, -+ FCCF_TOKEN, -+ FCCS_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, REXSUB_FCN, EXEC_FCN}; -+ char *from_fcn[] = {FROM_TOKEN, REPLACE_FCN, TRIM_FCN, REXTRIM_FCN, REXSUB_FCN, EXEC_FCN}; -+ char *otext_fcn[] = {OTEXT_TOKEN, REPLACE_FCN, TRIM_FCN, REXTRIM_FCN, REXSUB_FCN, EXEC_FCN}; -+ char *otextnq_fcn[] = {OTEXTNQ_TOKEN, REPLACE_FCN, TRIM_FCN, REXTRIM_FCN, REXSUB_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 *) rule_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; -+ 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_rexsub (REXSUB_S **rexsub) -+ { -+ if(rexsub == NULL || *rexsub == NULL) -+ return; -+ -+ if((*rexsub)->pattern) fs_give((void **) &(*rexsub)->pattern); -+ if((*rexsub)->text) fs_give((void **) &(*rexsub)->text); -+ fs_give((void **) rexsub); -+ } -+ -+ void -+ free_void_token_value(void **voidptr, int voidtype) -+ { -+ switch(voidtype){ -+ case CHAR_TYPE: fs_give(voidptr); -+ break; -+ case REXSUB_TYPE: free_rexsub ((REXSUB_S **) voidptr); -+ break; -+ default: break; /* do nothing */ -+ } -+ } -+ -+ void -+ free_token_value(TOKEN_VALUE **token) -+ { -+ if(token && *token){ -+ if ((*token)->testxt) -+ fs_give((void **)&(*token)->testxt); -+ if ((*token)->voidtxt) -+ free_void_token_value((void **) &(*token)->voidtxt, (*token)->voidtype); -+ if((*token)->next) -+ free_token_value(&(*token)->next); -+ fs_give((void **)token); -+ } -+ } -+ -+ void -+ free_condition_value(CONDVALUE_S **cvalue) -+ { -+ if(cvalue && *cvalue){ -+ if ((*cvalue)->tname) -+ fs_give((void **)&(*cvalue)->tname); -+ if ((*cvalue)->value) -+ free_token_value(&(*cvalue)->value); -+ fs_give((void **)cvalue); -+ } -+ } -+ -+ void -+ free_condition(CONDITION_S **condition) -+ { -+ if(condition && *condition){ -+ if((*condition)->cndtype == Condition) -+ free_condition_value((CONDVALUE_S **)&(*condition)->cndrule); -+ else if((*condition)->cndtype == ParOpen || (*condition)->cndtype == ParClose) -+ fs_give(&(*condition)->cndrule); -+ 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 * -+ rule_alloc_mem (size_t amount) -+ { -+ void *genmem; -+ memset(genmem = fs_get(amount), 0, amount); -+ return genmem; -+ } -+ -+ 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 '&': -+ case '|': if (*(p+1) == *p){ /* looking for && or ||*/ -+ p += 2; -+ next_condition++; -+ } -+ else{ -+ error++; -+ done++; -+ } -+ break; -+ case '=': /* looking for => or -> */ -+ case '-': if (*(p+1) != '>' || next_condition) -+ 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, *d; -+ int offset, err = 0, freeme = 0; -+ -+ if(error) -+ *error = 0; -+ -+ if (!data) -+ return (TOKEN_VALUE *) NULL; -+ -+ if(*data == '_'){ -+ d = detoken_src(data, FOR_RULE, NULL, NULL, NULL, NULL); -+ freeme++; -+ } -+ else -+ d = data; -+ -+ rvalue = (TOKEN_VALUE *) rule_alloc_mem(sizeof(TOKEN_VALUE)); -+ if (p = advance_to_char(d,';', STRICTLY, &offset)){ -+ rvalue->testxt = p; -+ rvalue->next = parse_group_data(d + strlen(p) + 1 + offset, error); -+ } -+ else if (p = advance_to_char(d,'}', STRICTLY, NULL)) -+ rvalue->testxt = p; -+ else if (d && *d == '}') -+ rvalue->testxt = cpystr(""); -+ else{ -+ err++; -+ free_token_value(&rvalue); -+ } -+ if (error) -+ *error += err; -+ if(freeme != 0 && d != NULL) -+ fs_give((void **)&d); -+ return(rvalue); -+ } -+ -+ CONDVALUE_S * -+ fill_condition_value(char *data) -+ { -+ CONDVALUE_S *condition; -+ int i, done, error = 0; -+ char *group; -+ -+ for (i = 0, done = 0; done == 0 && token_rules[i] != NULL; i++) -+ done = strncmp(data,token_rules[i], strlen(token_rules[i])) ? 0 : 1; -+ if (done){ -+ condition = rule_alloc_mem(sizeof(CONDVALUE_S)); -+ condition->tname = cpystr(token_rules[--i]); -+ data += strlen(token_rules[i]); -+ } -+ else if (*data == '_') { -+ INDEX_PARSE_T *token; -+ char *itokname; -+ for (i = 0, done = 0; -+ done == 0 && (token = itoken(i)) != NULL && (itokname = token->name) != NULL; i++) -+ done = strncmp(data+1, itokname, strlen(itokname)) -+ ? 0 : data[strlen(itokname) + 1] == '_'; -+ if (done){ -+ condition = (CONDVALUE_S *) rule_alloc_mem(sizeof(CONDVALUE_S)); -+ condition->tname = fs_get(strlen(itokname) + 3); -+ sprintf(condition->tname, "_%s_", itokname); -+ data += strlen(itokname) + 2; -+ } -+ else -+ return NULL; -+ } -+ else -+ return NULL; -+ -+ for (; *data && *data == ' '; data++); -+ if (*data){ -+ for (i = 0, done = 0; done == 0 && rel_rules_test[i].value != NULL; i++) -+ done = strncmp(data, rel_rules_test[i].value, 2) ? 0 : 1; -+ if (done) -+ condition->ttype = rel_rules_test[--i].ttype; -+ else{ -+ free_condition_value(&condition); -+ return NULL; -+ } -+ } -+ else{ -+ free_condition_value(&condition); -+ return NULL; -+ } -+ -+ data += 2; -+ for (; *data && *data == ' '; data++); -+ if (*data++ != '{'){ -+ free_condition_value(&condition); -+ return 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_value(&condition); -+ if(group) -+ fs_give((void **) &group); -+ } -+ else -+ free_condition_value(&condition); -+ return condition; -+ } -+ -+ char * -+ canonicalize_condition(char *data, int *eoc) -+ { -+ char *p = data, *s, *t, c; -+ char *q = fs_get((5*strlen(data)+1)*sizeof(char)); -+ char tmp[10]; -+ int level, done, error, i; -+ -+ if(eoc) *eoc = -1; /* assume error */ -+ *q = '\0'; -+ if(*p == '"'){ -+ if(p[strlen(p) - 1] == '"') -+ p[strlen(p) - 1] = '\0'; -+ p++; -+ } -+ for(level = done = error = 0; *p && !done && !error; ){ -+ switch(*p){ -+ case ' ' : p++; break; -+ case '(' : strcat(q, CSEP_S); strcat(q, "("); -+ sprintf(tmp, "%d ", level++); -+ strcat(q, tmp); -+ p++; -+ break; -+ case ')' : strcat(q, CSEP_S); strcat(q, ")"); -+ sprintf(tmp, "%d ", --level); -+ strcat(q, tmp); -+ p++; -+ if(level < 0) error++; -+ break; -+ case '_' : for(s = p+1; *s >= 'A' && *s <= 'Z'; s++); -+ for(i = 0; token_rules[i] != NULL; i++) -+ if(!strncmp(token_rules[i], p, s-p)) -+ break; -+ if(token_rules[i] == NULL) -+ error++; -+ else if(*s++ == '_'){ -+ for(; *s == ' '; s++); -+ if(*s && *(s+1)){ -+ for(i = 0; rel_rules_test[i].value != NULL; i++) -+ if(!strncmp(rel_rules_test[i].value, s, 2)) -+ break; -+ if (rel_rules_test[i].value == NULL) -+ error++; -+ else{ -+ s += 2; -+ for(; *s == ' '; s++); -+ if(*s == '{'){ -+ if(*(s+1) != '}') -+ t = advance_to_char(s+1,'}', STRICTLY, NULL); -+ else -+ t = cpystr(""); -+ if(t != NULL){ -+ for(i = 0; t[i] != '\0' && t[i] != CSEP_C; i++); -+ if(t[i] == CSEP_C) error++; -+ if(error == 0){ -+ strcat(q, CSEP_S); strcat(q, "C["); -+ s += strlen(t) + 1; /* get past '{' */ -+ *s = '\0'; -+ strcat(q, p); -+ strcat(q, "}] "); -+ *s++ = '}'; -+ p = s; -+ } -+ fs_give((void **) &t); -+ } -+ else error++; -+ } -+ else -+ error++; -+ } -+ } -+ } -+ else error++; -+ break; -+ case '|': -+ case '&': if(*(p+1) = *p){ -+ strcat(q, CSEP_S); strcat(q, *p == '|' ? "OR " : "AND "); -+ p += 2; -+ } else error++; -+ break; -+ case '-': -+ case '=': if (*(p+1) == '>'){ -+ if(eoc) *eoc = p - data; -+ done++; -+ } -+ else -+ error++; -+ break; -+ default : error++; -+ break; -+ } -+ } -+ if(error || level > 0) /*simplistic approach by now */ -+ fs_give((void **)&q); -+ else -+ q[strlen(q)-1] = '\0'; -+ return q; -+ } -+ -+ /* for a canonical condition, return if it is constructed according -+ * to logical rules such as AND or OR between conditions, etc. We assume -+ * we already canonicalized data, or else this will not work. -+ */ -+ int -+ sanity_check_condition(char *data) -+ { -+ int i, error; -+ char *s, *t, *d; -+ -+ if(data == NULL || *data == '\0') /* no data in, no data out */ -+ return 0; -+ -+ d = fs_get((strlen(data)+1)*sizeof(char)); -+ for(s = data,i = 0; (t = strchr(s, CSEP_C))!= NULL && (d[i] = *(t+1)); s = t+1, i++); -+ d[i] = '\0'; -+ for(i = 0, error = 0; d[i] != '\0' && error == 0; i++){ -+ switch(d[i]){ -+ case 'C': if((d[i+1] != '\0' && (d[i+1] == '(' || d[i+1] == 'C')) -+ || (i == 0 && d[1] != 'A' && d[1] != 'O' && d[1] != '\0')) -+ error++; -+ break; -+ case ')': if(i == 0 || (d[i+1] != '\0' && (d[i+1] == 'C' || d[i+1] == '('))) -+ error++; -+ break; -+ case '(': if(d[i+1] == '\0' || d[i+1] == ')' || d[i+1] == 'A' || d[i+1] == 'O') -+ error++; -+ break; -+ case 'O': -+ case 'A': if(i == 0 || d[i+1] == '\0' || d[i+1] == ')' || d[i+1] == 'A' || d[i+1] == 'O') -+ error++; -+ break; -+ default : error++; -+ } -+ } -+ if(d) fs_give((void **)&d); -+ return error ? 0 : 1; -+ } -+ -+ /* given a parsed data that satisfies sanity checks, parse it -+ * into a condition we can check later on. -+ */ -+ CONDITION_S * -+ fill_condition(char *data) -+ { -+ char *s, *t, *u; -+ CONDITION_S *rv = NULL; -+ CONDVALUE_S *cvalue; -+ int *i; -+ -+ if(data == NULL || *data == '\0' || (s = strchr(data, CSEP_C)) == NULL) -+ return NULL; -+ -+ rv = (CONDITION_S *) rule_alloc_mem(sizeof(CONDITION_S)); -+ switch(*++s){ -+ case ')': -+ case '(': i = fs_get(sizeof(int)); -+ *i = atoi(s+1); -+ rv->cndrule = (void *) i; -+ rv->cndtype = *s == '(' ? ParOpen : ParClose; -+ break; -+ -+ case 'C': if((u = strchr(s+2, CSEP_C)) != NULL){ -+ *u = '\0'; -+ t = strrchr(s, ']'); -+ t = '\0'; -+ *u = CSEP_C; -+ } else -+ s[strlen(s) - 1] = '\0'; -+ rv->cndrule = (void *) fill_condition_value(s+2); -+ rv->cndtype = Condition; -+ break; -+ -+ case 'A': -+ case 'O': rv->cndtype = *s == 'A' ? And : Or; -+ break; -+ -+ default : fs_give((void **)&rv); -+ break; -+ } -+ rv->next = fill_condition(strchr(s, CSEP_C)); -+ -+ return rv; -+ } -+ -+ /* eoc = end of condition, equal to -1 on error */ -+ CONDITION_S * -+ parse_condition (char *data, int *eoc) -+ { -+ CONDITION_S *condition = NULL; -+ char *pvalue; -+ -+ if((pvalue = canonicalize_condition(data, eoc)) != NULL -+ && sanity_check_condition(pvalue) > 0) -+ condition = fill_condition(pvalue); -+ -+ if(pvalue) -+ fs_give((void **)&pvalue); -+ -+ if (condition == NULL && eoc) -+ *eoc = -1; -+ -+ return condition; -+ } -+ -+ RULEACTION_S * -+ parse_action (char *data, int context) -+ { -+ int i, done, is_save; -+ RULEACTION_S *raction = NULL; -+ char *function, *p = data; -+ -+ if (p == NULL || *p == '\0') -+ return NULL; -+ -+ is_save = *p == '-'; -+ p += 2; -+ for (; *p == ' '; p++); -+ -+ if (is_save){ /* got "->", a save-rule separator */ -+ raction = (RULEACTION_S *) rule_alloc_mem(sizeof(RULEACTION_S)); -+ raction->function = cpystr("_SAVE_"); -+ raction->value = (TOKEN_VALUE *) rule_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 NULL; -+ if (done){ -+ raction = rule_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 *) rule_alloc_mem(sizeof(TOKEN_VALUE)); -+ raction->value->testxt = advance_to_char(p,'}', STRICTLY, NULL); -+ if(!raction->value->testxt) -+ free_ruleaction(&raction); -+ return raction; -+ } -+ -+ raction = (RULEACTION_S *) rule_alloc_mem(sizeof(RULEACTION_S)); -+ raction->token = get_name_token(p); -+ -+ p += strlen(raction->token) + 1; -+ for (; *p && *p == ' '; p++); -+ if (!strncmp(p, ":=", 2)) -+ p += 2; -+ else{ -+ free_ruleaction(&raction); -+ return NULL; -+ } -+ -+ for (; *p && *p == ' '; p++); -+ -+ for(i = 0; i < NFCN && strncmp(p, rule_fcns[i].name, rule_fcns[i].len); i++); -+ -+ if (!rule_fcns[i].is_assignment){ -+ free_ruleaction(&raction); -+ return NULL; -+ } -+ -+ raction->function = cpystr(rule_fcns[i].name); -+ raction->context = rule_fcns[i].what_for; -+ raction->exec = rule_fcns[i].execute; -+ p += rule_fcns[i].len; -+ -+ if(*p++ != '{'){ -+ free_ruleaction(&raction); -+ return NULL; -+ } -+ -+ if(rule_fcns[i].parse_action_value){ -+ raction->value = (rule_fcns[i].parse_action_value)(p); -+ if(raction->value) -+ raction->value->voidtype = rule_fcns[i].return_type; -+ } -+ -+ if(raction->value == NULL -+ || (raction->value->testxt == NULL && raction->value->voidtxt == NULL)) -+ free_ruleaction(&raction); -+ -+ return raction; -+ } -+ -+ TOKEN_VALUE * -+ parse_action_to_char(char *p) -+ { -+ return parse_group_data(p, NULL); -+ } -+ -+ TOKEN_VALUE * -+ parse_rexsub_action(char *data) -+ { -+ TOKEN_VALUE *rv; -+ REXSUB_S *rsv = NULL; /* rexsub value */ -+ char *d, *p, *t, *n; /* data, pattern, text, number */ -+ long number; -+ int offset, error; -+ -+ if (data == NULL || *data == '\0') -+ return NULL; -+ -+ rv = (TOKEN_VALUE *) rule_alloc_mem(sizeof(TOKEN_VALUE)); -+ -+ number = 0; -+ p = t = n = NULL; -+ -+ p = advance_to_char(data,'}', STRICTLY, NULL); -+ -+ error = (p == NULL) ? 1 : 0; -+ if(!error){ -+ offset = strlen(p) + 1; -+ d = data + offset; -+ if(*d++ != '{') error++; -+ } -+ -+ if(!error){ -+ n = advance_to_char(d,'}', STRICTLY, NULL); -+ if(n == NULL && *d == '}') -+ n = cpystr(""); -+ if(n == NULL) error++; -+ } -+ -+ if(!error){ -+ t = detoken_src(n, FOR_RULE, NULL, NULL, NULL, NULL); -+ offset += strlen(n) + 2; -+ d = data + offset; -+ if(*d == '\0') number = 1; -+ else if(*d++ != '{') error++; -+ } -+ -+ if(!error && number == 0){ -+ fs_give((void **) &n); -+ n = advance_to_char(d,'}', STRICTLY, NULL); -+ if(n == NULL){ -+ if(*d == '\0') -+ number = 1; -+ else -+ error++; -+ } -+ else if(strcmp(n, "g") == 0) -+ number = -1; -+ else{ -+ char *eon; -+ number = strtol(n, &eon, 10); -+ if((eon != NULL && *eon != '\0') || number <= 0) error++; -+ } -+ } -+ -+ if(error){ -+ if (p) fs_give((void **) &p); -+ if (t) fs_give((void **) &t); -+ } -+ if (n) fs_give((void **) &n); -+ -+ if(!error){ -+ rsv = fs_get(sizeof(REXSUB_S)); -+ rsv->pattern = p; -+ rsv->text = t; -+ rsv->times = number; -+ } -+ -+ rv->voidtxt = (void *) rsv; -+ return rv; -+ } -+ -+ RULE_S * -+ parse_rule (char *data, int context) -+ { -+ RULE_S *prule; /*parsed rule */ -+ int len = 0; -+ -+ if (!(prule = (RULE_S *) rule_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 *) rule_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; -+ } -+ -+ /* add parsed rule */ -+ PRULELIST_S * -+ add_prule(PRULELIST_S *rule_list, PRULELIST_S *rule) -+ { -+ PRULELIST_S *rlist; -+ -+ for(rlist = rule_list; rlist && rlist->next; rlist = rlist->next); -+ -+ if(rlist) -+ rlist->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 *) rule_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) -+ { -+ while(condition && condition->cndtype != Condition) -+ condition = condition->next; -+ -+ return condition -+ ? (!strcmp(COND(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) -+ : 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); ++ 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(); + +@@ -1158,6 +1196,7 @@ process_config_input(UCS *ch) + if(ps_global->initial_cmds && !*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); +Index: alpine-2.24/alpine/reply.c +=================================================================== +--- alpine-2.24.orig/alpine/reply.c ++++ alpine-2.24/alpine/reply.c +@@ -62,7 +62,8 @@ The evolution continues... + #include "../pith/tempfile.h" + #include "../pith/busy.h" + #include "../pith/ablookup.h" +- ++#include "../pith/copyaddr.h" ++#include "../pith/rules.h" + + /* + * Internal Prototypes +@@ -110,11 +111,12 @@ reply(struct pine *pine_state, ACTION_S + long msgno, j, totalm, rflags, *seq = NULL; + int i, include_text = 0, times = -1, warned = 0, rv = 0, + flags = RSF_QUERY_REPLY_ALL, reply_raw_body = 0; +- int rolemsg = 0, copytomsg = 0; ++ int rolemsg = 0, copytomsg = 0, do_role_early = 0; + gf_io_t pc; + PAT_STATE dummy; + REDRAFT_POS_S *redraft_pos = NULL; + ACTION_S *role = NULL, *nrole; ++ RULE_RESULT *rule; + #if defined(DOS) && !defined(_WINDOWS) + char *reserve; + #endif +@@ -140,6 +142,69 @@ reply(struct pine *pine_state, ACTION_S + && F_ON(F_ENABLE_FULL_HDR_AND_TEXT, ps_global)) + reply_raw_body = 1; + ++ /* Setup possible role */ ++ if(role_arg) ++ role = copy_action(role_arg); ++ ++ if(!role && F_ON(F_ENABLE_EDIT_REPLY_INDENT, pine_state)){ ++ for(msgno = mn_first_cur(pine_state->msgmap); ++ msgno > 0L; msgno = mn_next_cur(pine_state->msgmap)){ ++ ++ env = pine_mail_fetchstructure(pine_state->mail_stream, ++ mn_m2raw(pine_state->msgmap, msgno), ++ NULL); ++ if(!env) { ++ q_status_message1(SM_ORDER,3,4, ++ _("Error fetching message %s. Can't reply to it."), ++ long2string(msgno)); ++ goto done_early; ++ } ++ ++ if(rule = get_result_rule(V_REPLY_INDENT_RULES, FOR_COMPOSE , env)){ ++ RULELIST *list = get_rulelist_from_code(V_REPLY_INDENT_RULES, ++ ps_global->rule_list); ++ RULE_S *prule = get_rule(list, rule->number); ++ if(condition_contains_token(prule->condition, ROLE_TOKEN)) ++ do_role_early++; ++ if(rule->result) ++ fs_give((void **)&rule->result); ++ fs_give((void **)&rule); ++ } ++ } ++ } ++ ++ if(do_role_early){ ++ rflags = ROLE_REPLY; ++ if(nonempty_patterns(rflags, &dummy)){ ++ /* setup default role */ ++ nrole = NULL; ++ j = mn_first_cur(pine_state->msgmap); ++ do { ++ role = nrole; ++ nrole = set_role_from_msg(pine_state, rflags, ++ mn_m2raw(pine_state->msgmap, j), ++ NULL); ++ } while(nrole && (!role || nrole == role) ++ && (j=mn_next_cur(pine_state->msgmap)) > 0L); ++ ++ if(!role || nrole == role) ++ role = nrole; ++ else ++ role = NULL; ++ ++ if(confirm_role(rflags, &role)) ++ role = combine_inherited_role(role); ++ else{ /* cancel reply */ ++ role = NULL; ++ cmd_cancelled("Reply"); ++ goto done_early; ++ } ++ } ++ } ++ ++ if (role) ++ ps_global->role = cpystr(role->nick); /* remember the role */ ++ + /* + * We may have to loop through first to figure out what default + * reply-indent-string to offer... +@@ -288,8 +353,18 @@ reply(struct pine *pine_state, ACTION_S + outgoing->subject = cpystr("Re: several messages"); + } + } +- else +- outgoing->subject = reply_subject(env->subject, NULL, 0); ++ else{ ++ RULE_RESULT *rule; ++ rule = get_result_rule(V_RESUB_RULES,FOR_RESUB|FOR_TRIM , env); ++ if (rule){ ++ outgoing->subject = reply_subject(rule->result, NULL, 0); ++ if (rule->result) ++ fs_give((void **)&rule->result); ++ fs_give((void **)&rule); ++ } ++ else ++ outgoing->subject = reply_subject(env->subject, NULL, 0); ++ } + } + + /* fill reply header */ +@@ -308,13 +383,7 @@ reply(struct pine *pine_state, ACTION_S + if(sp_expunge_count(pine_state->mail_stream)) /* cur msg expunged */ + goto done_early; + +- /* Setup possible role */ +- if (ps_global->reply.role_chosen) +- role = ps_global->reply.role_chosen; +- else if(role_arg) +- role = copy_action(role_arg); +- +- if(!role){ ++ if(!do_role_early){ + rflags = ROLE_REPLY; + if(!ps_global->reply.role_chosen && nonempty_patterns(rflags, &dummy)){ + /* setup default role */ +@@ -725,6 +794,9 @@ reply(struct pine *pine_state, ACTION_S + if(prefix) + fs_give((void **)&prefix); + ++ if (ps_global->role) ++ fs_give((void **)&ps_global->role); ++ + if(fcc) + fs_give((void **) &fcc); + +@@ -1598,9 +1670,14 @@ forward(struct pine *ps, ACTION_S *role_ + } + } + +- if(role) ++ if (ps_global->role) ++ fs_give((void **)&ps_global->role); ++ ++ if(role){ + q_status_message1(SM_ORDER, 3, 4, + _("Forwarding using role \"%s\""), role->nick); ++ ps_global->role = cpystr(role->nick); ++ } + + outgoing->message_id = generate_message_id(role); + +@@ -1834,6 +1911,7 @@ forward(struct pine *ps, ACTION_S *role_ + #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); +Index: alpine-2.24/alpine/roleconf.c +=================================================================== +--- alpine-2.24.orig/alpine/roleconf.c ++++ alpine-2.24/alpine/roleconf.c +@@ -7706,6 +7706,11 @@ role_text_tool_inick(struct pine *ps, in + 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)); + +Index: alpine-2.24/alpine/send.c +=================================================================== +--- alpine-2.24.orig/alpine/send.c ++++ alpine-2.24/alpine/send.c +@@ -63,7 +63,7 @@ static char rcsid[] = "$Id: send.c 1142 + #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; +@@ -236,6 +236,11 @@ alt_compose_screen(struct pine *pine_sta + 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); +@@ -445,8 +450,12 @@ compose_mail(char *given_to, char *fcc_a + + ps_global->next_screen = prev_screen; + ps_global->redrawer = redraw; +- if(role) ++ if (ps_global->role) ++ fs_give((void **)&ps_global->role); ++ if(role){ + role = combine_inherited_role(role); ++ ps_global->role = cpystr(role->nick); ++ } + } + break; + +@@ -639,9 +648,14 @@ compose_mail(char *given_to, char *fcc_a + } + } + +- if(role) ++ if (ps_global->role) ++ fs_give((void **)&ps_global->role); ++ ++ if(role){ + q_status_message1(SM_ORDER, 3, 4, _("Composing using role \"%s\""), + role->nick); ++ ps_global->role = cpystr(role->nick); ++ } + + outgoing->message_id = generate_message_id(role); + /* +@@ -2486,6 +2500,26 @@ pine_send(ENVELOPE *outgoing, struct mai + 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); +Index: alpine-2.24/pith/Makefile.am +=================================================================== +--- alpine-2.24.orig/pith/Makefile.am ++++ alpine-2.24/pith/Makefile.am +@@ -26,7 +26,7 @@ libpith_a_SOURCES = ablookup.c abdlc.c a + filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c ical.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 \ ++ 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 + +Index: alpine-2.24/pith/Makefile.in +=================================================================== +--- alpine-2.24.orig/pith/Makefile.in ++++ alpine-2.24/pith/Makefile.in +@@ -142,7 +142,7 @@ am_libpith_a_OBJECTS = ablookup.$(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) \ ++ 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) \ +@@ -441,7 +441,7 @@ libpith_a_SOURCES = ablookup.c abdlc.c a + filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c ical.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 \ ++ 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 + +@@ -575,6 +575,7 @@ distclean-compile: + @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@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +Index: alpine-2.24/pith/adrbklib.c +=================================================================== +--- alpine-2.24.orig/pith/adrbklib.c ++++ alpine-2.24/pith/adrbklib.c +@@ -5138,8 +5138,14 @@ init_addrbooks(OpenStatus want_status, i + if(as.cur >= as.how_many_personals) + pab->type |= GLOBAL; + +- pab->access = adrbk_access(pab); +- ++ 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; +Index: alpine-2.24/pith/conf.c +=================================================================== +--- alpine-2.24.orig/pith/conf.c ++++ alpine-2.24/pith/conf.c +@@ -29,6 +29,7 @@ static char rcsid[] = "$Id: conf.c 1266 + #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" +@@ -225,6 +226,36 @@ CONF_TXT_T cf_text_unk_character_set[] = + + 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."; + + #ifdef _WINDOWS +@@ -574,6 +605,34 @@ static struct variable variables[] = { + 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}, +@@ -2772,6 +2831,7 @@ init_vars(struct pine *ps, void (*cmds_f + 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 */ +@@ -3228,6 +3288,8 @@ feature_list(int index) + 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, +@@ -7927,6 +7989,34 @@ config_help(int var, int feature) + 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 : +Index: alpine-2.24/pith/conf.h +=================================================================== +--- alpine-2.24.orig/pith/conf.h ++++ alpine-2.24/pith/conf.h +@@ -161,6 +161,46 @@ + #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 +Index: alpine-2.24/pith/conftype.h +=================================================================== +--- alpine-2.24.orig/pith/conftype.h ++++ alpine-2.24/pith/conftype.h +@@ -71,6 +71,20 @@ typedef enum { V_PERSONAL_NAME = 0 + , 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 +@@ -348,6 +362,7 @@ typedef enum { + 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, +Index: alpine-2.24/pith/detoken.c +=================================================================== +--- alpine-2.24.orig/pith/detoken.c ++++ alpine-2.24/pith/detoken.c +@@ -25,7 +25,7 @@ static char rcsid[] = "$Id: detoken.c 76 + #include "../pith/reply.h" + #include "../pith/mailindx.h" + #include "../pith/options.h" +- ++#include "../pith/rules.h" + + /* + * Hook to read signature from local file +@@ -91,6 +91,8 @@ detoken(ACTION_S *role, ENVELOPE *env, i + + 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; +@@ -104,14 +106,25 @@ detoken(ACTION_S *role, ENVELOPE *env, i + * 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; ++ { 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; +@@ -302,7 +315,7 @@ top: + } + } + } +- else if(pt->what_for & FOR_REPLY_INTRO) ++ else if(pt->what_for & (FOR_REPLY_INTRO | FOR_RULE)) + repl = get_reply_data(env, role, pt->ctype, + subbuf, sizeof(subbuf)-1); + +Index: alpine-2.24/pith/indxtype.h +=================================================================== +--- alpine-2.24.orig/pith/indxtype.h ++++ alpine-2.24/pith/indxtype.h +@@ -84,6 +84,11 @@ typedef enum {iNothing, iStatus, iFStatu + iCurNews, iArrow, + iMailbox, iAddress, iInit, iCursorPos, + iDay2Digit, iMon2Digit, iYear2Digit, ++ iFolder, iFlag, iCollection, iRole, iProcid, iScreen, iPkey, ++ iNick, iFccFrom, iFccSender, iAltAddress, ++ iAddressTo, iAddressCc, iAddressRecip, iAddressSender, ++ iBcc, iLcc, ++ iFfrom, iFadd, + iSTime, iSTime24, iKSize, + iRoleNick, iNewLine, + iHeader, iText, +@@ -105,15 +110,26 @@ typedef struct index_parse_tokens { + + + /* 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 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" + +Index: alpine-2.24/pith/mailcmd.c +=================================================================== +--- alpine-2.24.orig/pith/mailcmd.c ++++ alpine-2.24/pith/mailcmd.c +@@ -39,6 +39,7 @@ static char rcsid[] = "$Id: mailcmd.c 11 + #include "../pith/ablookup.h" + #include "../pith/search.h" + #include "../pith/charconv/utf8.h" ++#include "../pith/rules.h" + + #ifdef _WINDOWS + #include "../pico/osdep/mswin.h" +@@ -665,6 +666,7 @@ do_broach_folder(char *newfolder, CONTEX + 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! */ +@@ -991,6 +993,7 @@ do_broach_folder(char *newfolder, CONTEX + + 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 +@@ -1114,7 +1117,10 @@ do_broach_folder(char *newfolder, CONTEX + + if(!cur_already_set && mn_get_total(ps_global->msgmap) > 0L){ + +- perfolder_startup_rule = reset_startup_rule(ps_global->mail_stream); ++ 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) +@@ -1136,124 +1142,7 @@ do_broach_folder(char *newfolder, CONTEX + 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: +- alpine_panic("Unexpected incoming startup case"); +- break; +- +- } ++ find_startup_position(use_this_startup_rule, m, pc); + } + else if(IS_NEWS(ps_global->mail_stream)){ + /* +@@ -1431,9 +1320,11 @@ expunge_and_close(MAILSTREAM *stream, ch + /* 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))){ ++ && (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 */ +@@ -1716,6 +1607,9 @@ move_read_msgs(MAILSTREAM *stream, char + 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; +@@ -1755,8 +1649,9 @@ move_read_msgs(MAILSTREAM *stream, char + 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) ++ 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'; +@@ -1794,7 +1689,9 @@ move_read_incoming(MAILSTREAM *stream, C + && ((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))){ ++ && ((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; +@@ -2761,3 +2658,295 @@ get_uname(char *mailbox, char *target, i + + 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; ++ ++ 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; ++} ++ ++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); + } -+ return rule_result; ++ } ++} ++ ++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: ++ alpine_panic("Unexpected incoming startup case"); ++ break; ++ ++ } ++} +Index: alpine-2.24/pith/mailcmd.h +=================================================================== +--- alpine-2.24.orig/pith/mailcmd.h ++++ alpine-2.24/pith/mailcmd.h +@@ -42,6 +42,8 @@ + #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 +@@ -63,7 +65,13 @@ int do_broach_folder(char *, CONTEXT_ + 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); ++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 *); +Index: alpine-2.24/pith/mailindx.c +=================================================================== +--- alpine-2.24.orig/pith/mailindx.c ++++ alpine-2.24/pith/mailindx.c +@@ -41,6 +41,7 @@ static char rcsid[] = "$Id: mailindx.c 1 + #include "../pith/send.h" + #include "../pith/options.h" + #include "../pith/ablookup.h" ++#include "../pith/rules.h" + #ifdef _WINDOWS + #include "../pico/osdep/mswin.h" + #endif +@@ -379,6 +380,13 @@ reset_index_format(void) + 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)){ +@@ -452,7 +460,7 @@ free_hdrtok(HEADER_TOK_S **hdrtok) + static INDEX_PARSE_T itokens[] = { + {"STATUS", iStatus, FOR_INDEX}, + {"MSGNO", iMessNo, FOR_INDEX}, +- {"DATE", iDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, ++ {"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}, +@@ -460,7 +468,7 @@ static INDEX_PARSE_T itokens[] = { + {"SIZETHREAD", iSizeThread, FOR_INDEX}, + {"SIZENARROW", iSizeNarrow, FOR_INDEX}, + {"KSIZE", iKSize, FOR_INDEX}, +- {"SUBJECT", iSubject, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, ++ {"SUBJECT", iSubject, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_TRIM}, + {"SHORTSUBJECT", iShortSubject, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, + {"FULLSTATUS", iFStatus, FOR_INDEX}, + {"IMAPSTATUS", iIStatus, FOR_INDEX}, +@@ -472,56 +480,60 @@ static INDEX_PARSE_T itokens[] = { + {"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}, ++ {"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}, +- {"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}, ++ {"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}, + {"SMARTTIME24", iSTime24, 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}, ++ {"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}, ++ {"ADDRESSSENDER", iAddressSender, 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}, +@@ -530,56 +542,71 @@ static INDEX_PARSE_T itokens[] = { + {"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}, ++ {"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}, +- {"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}, ++ {"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}, +- {"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}, ++ 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}, +- {"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}, ++ 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}, +- {"LASTYEAR", iLstYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, +- {"LASTYEAR2DIGIT", iLstYear2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, ++ 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}, ++ {"FCCFROM", iFccFrom, FOR_RULE|FOR_SAVE}, ++ {"FCCSENDER", iFccSender, FOR_RULE|FOR_SAVE}, ++ {"ALTADDRESS", iAltAddress, 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} + }; + +@@ -2486,6 +2513,24 @@ format_index_index_line(INDEXDATA_S *ida + 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" +@@ -3880,7 +3925,17 @@ try_again: + + if(p > buf){ + size_t l; ++ ENVELOPE *env; ++ char *rule_result; + ++ 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)); +@@ -5459,10 +5514,10 @@ subj_str(INDEXDATA_S *idata, char *str, + { + char *subject, *origsubj, *origstr, *rawsubj, *sptr = NULL; + char *p, *border, *q = NULL, *free_subj = NULL; +- char *sp; ++ char *sp, *rule_result; + size_t len; + int width = -1; +- int depth = 0, mult = 2; ++ int depth = 0, mult = 2, collapsed, i, we_clear = 0; + int save; + int do_subj = 0, truncated_tree = 0; + PINETHRD_S *thd, *thdorig; +@@ -5518,6 +5573,14 @@ subj_str(INDEXDATA_S *idata, char *str, + * 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); ++ } ++ + if(shorten) + shorten_subject(origsubj); + +@@ -5956,6 +6019,9 @@ subj_str(INDEXDATA_S *idata, char *str, + + if(free_subj) + fs_give((void **) &free_subj); ++ ++ if (we_clear && origsubj) ++ fs_give((void **)&origsubj); + } + + +@@ -6321,16 +6387,33 @@ from_str(IndexColType ctype, INDEXDATA_S + ? "To" + : (addr = fetch_cc(idata)) + ? "Cc" +- : NULL)) +- && set_index_addr(idata, field, addr, "To: ", +- strsize-1, fptr)) +- break; ++ : 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){ +- snprintf(fptr, strsize, "To: %-*.*s", (int)(strsize-1-4), (int)(strsize-1-4), +- 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; + } + +@@ -6343,7 +6426,15 @@ from_str(IndexColType ctype, INDEXDATA_S + break; + + case iFrom: +- set_index_addr(idata, "From", fetch_from(idata), NULL, strsize-1, fptr); ++ { 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: +@@ -6641,3 +6732,64 @@ set_print_format(IELEM_S *ielem, int wid + } + } + } ++ ++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); ++ } ++ } ++ } + } -+ -+ /* process_rule: -+ Parameters: prule, a processed rule, ready to be tested -+ 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) -+ { -+ if(!prule) ++ return rule_result; ++} +Index: alpine-2.24/pith/mailindx.h +=================================================================== +--- alpine-2.24.orig/pith/mailindx.h ++++ alpine-2.24/pith/mailindx.h +@@ -30,6 +30,9 @@ extern void (*setup_header_widths)(MAIL + + + /* 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 *); +Index: alpine-2.24/pith/makefile.wnt +=================================================================== +--- alpine-2.24.orig/pith/makefile.wnt ++++ alpine-2.24/pith/makefile.wnt +@@ -46,7 +46,8 @@ HFILES= ../include/system.h ../include/g + 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 smime.h smkeys.h sort.h sorttype.h \ ++ rfc2231.h rules.h rulestype.h save.h savetype.h search.h send.h sequence.h signal.h \ ++ smime.h smkeys.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 + +@@ -56,7 +57,7 @@ OFILES= ablookup.obj abdlc.obj addrbook. + ical.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 \ ++ readfile.obj remote.obj reply.obj rfc2231.obj rules.obj save.obj search.obj sequence.obj send.obj \ + smime.obj smkeys.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 + +Index: alpine-2.24/pith/pine.hlp +=================================================================== +--- alpine-2.24.orig/pith/pine.hlp ++++ alpine-2.24/pith/pine.hlp +@@ -4602,6 +4602,7 @@ There are also additional details on +

  • FEATURE: +
  • FEATURE: +
  • FEATURE: ++
  • FEATURE: +
  • FEATURE: +
  • FEATURE: +
  • FEATURE: +@@ -20133,6 +20134,7 @@ This set of special tokens may be used i + "" option, + in the "" option, + in signature files, ++in the "new-rules" option, + in template files used in + "roles", and in the folder name + that is the target of a Filter Rule. +@@ -20145,7 +20147,7 @@ and in the target of Filter Rules. +

    +

    + +-

    Tokens Available for all Cases (except Filter Rules)

    ++

    Tokens Available for all Cases (except Filter Rules or in some cases for new-rules)

    + +
    +
    SUBJECT
    +@@ -20179,6 +20181,22 @@ email address, never the personal name. + For example, "mailbox@domain". +
  • + ++
    ADDRESSTO
    ++
    ++This is similar to the "TO" 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, "mailbox@domain" when ++the e-mail message contains only one person in the To: field, or ++"peter@flintstones.com president@world.com". ++
    ++ ++
    ADDRESSSENDER
    ++
    ++This is similar to the "sender" token, only it is always the ++email address of all person listed in the Sender: field of the message. ++Example: "mailbox@domain". ++
    ++ +
    MAILBOX
    +
    + This is the same as the "ADDRESS" except that the +@@ -20226,6 +20244,15 @@ are unavailable) of the persons specifie + message's "Cc:" header field. +
    + ++
    ADDRESSCC
    ++
    ++This is similar to the "CC" 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: "mailbox@domain" when ++the e-mail message contains only one person in the Cc: field, or ++"peter@flintstones.com president@world.com". ++
    ++ +
    RECIPS
    +
    + This token represents the personal names (or email addresses if the names +@@ -20234,6 +20261,14 @@ message's "To:" header field a + the message's "Cc:" header field. +
    + ++
    ADDRESSRECIPS
    ++
    ++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. ++
    ++ ++ +
    NEWSANDRECIPS
    +
    + This token represents the newsgroups from the +@@ -21366,6 +21401,110 @@ This is an end of line marker. + + +

    ++

    Tokens Available Only for New-Rules

    ++ ++
    ++
    FCCFROM
    ++
    ++The Fcc: folder assigned to the email address in the From: field in the ++addressbook. ++
    ++
    ++ ++
    ++
    FCCSENDER
    ++
    ++The Fcc: folder assigned to the email address in the Sender: field in the ++addressbook. ++
    ++
    ++ ++
    ++
    ALTADDRESS
    ++
    ++The value of your ++ ++variable. At this time, no expansion of regular expressions is supported. ++
    ++
    ++ ++
    ++
    NICK
    ++
    ++Nickname of the person in the From field in your addressbook. ++
    ++
    ++ ++
    ++
    FOLDER
    ++
    ++Name of the folder where the rule will be applied. ++
    ++
    ++ ++
    ++
    COLLECTION
    ++
    ++Name of the collection list where the rule will be applied. ++
    ++
    ++ ++
    ++
    ROLE
    ++
    ++Name of the Role used to reply a message. ++
    ++
    ++ ++
    ++
    BCC
    ++
    ++Not implemented yet, but it will be implemented in future versions. It will ++be used for compose ++reply ++forward ++rules. ++
    ++
    ++ ++
    ++
    LCC
    ++
    ++This is the value of the Lcc: field at the moment that you start the composition. ++
    ++
    ++ ++
    ++
    FORWARDFROM
    ++
    ++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. ++
    ++
    ++ ++
    ++
    FORWARDADDRESS
    ++
    ++This is the address of the person that sent the message that you ++are forwarding. ++
    ++
    ++ ++ ++ ++ ++
    ++
    FLAG
    ++
    ++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 ++new rules explanation and example help. ++
    ++
    ++ ++

    +

    Token Available Only for Templates and Signatures

    + +
    +@@ -24828,6 +24967,922 @@ character sets Alpine knows about by usi + <End of help on this topic> + + ++====== h_config_procid ===== ++ ++ ++Token: PROCID ++ ++ ++

    TOKEN: PROCID explained

    ++ ++

    ++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. ++ ++

    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. ++ ++

    ++Consider the following examples for forward-rules: ++ ++

    ++_ROLE_ == {work} => _SUBJECT_ := _COPY_{[tag] _SUBJECT_} ++ ++

    ++and ++ ++

    ++_ROLE_ == {work} => _LCC_ := _TRIM_{_FORWARDFROM_ <_FORWARDADDRESS_>} ++ ++

    ++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 ++ ++

    ++_PROCID_ == {fwd-subject} && _ROLE_ == {work} => _SUBJECT_ := _COPY_{[tag] _SUBJECT_} ++ ++

    ++In this case, this rule will be tested fully only when we are determining ++the subject line of a forwarded message, not otherwise. ++ ++

    ++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. ++ ++

    <End of help on this topic> ++ ++ ++====== h_config_compose_rules ===== ++ ++ ++OPTION: <!--#echo var="VAR_compose-rules"--> ++ ++ ++

    OPTION:

    ++ ++

    At this time, this option is used to generate values for signature ++files that is not possible to do with the use of ++roles. ++ ++

    For example, you can have a rule like:
    ++_TO_ >> {Peter Flintstones} => _SIGNATURE_{~/.petersignature} ++ ++

    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 link. ++ ++

    <End of help on this topic> ++ ++ ++====== h_config_forward_rules ===== ++ ++ ++OPTION: <!--#echo var="VAR_forward-rules"--> ++ ++ ++

    OPTION:

    ++ ++

    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 this link. ++ ++

    If you want to edit the subject of a forwarded message, use the ++PROCID fwd-subject. For example you could have a rule like ++ ++

    ++_ROLE_ == {admin} && _SUBJECT_ !> {[tag] } => _COPY_{[tag] _SUBJECT_} ++ ++

    Another way in which this option can be used, is to trim the values of ++some fields. For this application the PROCID is fwd-lcc. For ++example it can be used in the following way: ++ ++

    ++_ROLE_ == {work} => _LCC_ := _TRIM_{_FORWARDFROM_ <_FORWARDADDRESS_>} ++ ++

    Other functions that can be used in this option are _EXEC_, _REXTRIM_ and ++_REXSUB_. ++ ++

    You can also use the _EXEC_ function. The documentation for this function ++is in the ++ ++help text. ++ ++

    Another function that can be used is the _REXSUB_ function which does ++a substitution. This function takes three parameters: a pattern to search ++for, the text to be substituted for when the pattern is matched, and the ++number of times that the pattern will be replaced. Each of the parameters ++is enclosed between "{" and "}". For example, to ++delete only one ocurrence of the string "Re: " in a subject we ++would write a rule such as ++ ++

    ++_FOLDER_ >> {} => _SUBJECT_ := _REXSUB_{Re: }{}{1} ++ ++

    The last parameter of the rexsub function is optional. In the sense ++that its omission is understood as if the third parameter was ++"{1}". In order to make unlimited substitutions, use ++"{g}" as the last parameter. ++ ++

    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 link. ++ ++

    <End of help on this topic> ++ ++ ++====== h_config_index_rules ===== ++ ++ ++OPTION: <!--#echo var="VAR_index-rules"--> ++ ++ ++

    OPTION:

    ++ ++

    This option is used to supersede the value of the option for specific folders. In ++this form you can have different index-formats for different folders. For ++example an entry here may be: ++ ++

    ++_FOLDER_ == {INBOX} => _INDEX_{IMAPSTATUS DATE FROM(33%) SIZE SUBJECT(67%)} ++ ++

    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 link. ++ ++

    <End of help on this topic> ++ ++ ++====== h_config_pretty_command ===== ++ ++ ++Pretty-Command Explained ++ ++ ++

    Pretty Command Explained

    ++ ++

    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. ++ ++

    [Command "RETURN" not defined for this screen. Use ? for help] ++ ++

    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. ++ ++

    <End of help on this topic> ++ ++ ++====== h_config_key_macro_rules ===== ++ ++ ++OPTION: <!--#echo var="VAR_key-definition-rules"--> ++ ++ ++

    OPTION:

    ++ ++

    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. ++ ++

    Always use the _SCREEN_ token as defined below.. You have been ++warned! ++ ++

    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. ++ ++

    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. ++ ++

    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 (MESSAGE INDEX), the ++screen where your message is displayed (MESSAGE ++TEXT) the screen where the list of folders is displayed (FOLDER LIST) and the attachment index screen (ATTACHMENT INDEX). The internal names of ++these screens for this patch are "index", "text", ++"folder", and "attachment", respectively. Please note ++that the internal names are all in lowercase and are case sensitive. ++ ++

    In order to define the screen, you use the _SCREEN_ token, so for ++example, you can write _SCREEN_ == {index}. ++ ++

    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 "pressed key"). For ++example you could use _PKEY_ == {~}, to designate the "~" ++key to activate the command. Some keystrokes (like control, or ++function keys) are encoded in special ways. You should read the ++full explanation on how to find ++out the encoding for each keystroke. ++ ++

    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 ++"$" and "h". You use the _COMMAND_ function to specify ++this. The syntax in this case is _COMMAND_{$,h}. ++ ++

    Observe that in the above example the different inputs are separated ++by commas. This is the standard way in which the ++ 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. ++ ++

    ++"_SCREEN_ == {index} && _PKEY_ == {~} => _COMMAND_{$,h}" ++ ++

    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 ++ ++

    ++_SCREEN_ == {index} && _PKEY_ == {~} => _COMMAND_{"$h"} ++ ++

    For more information on how to define the argument of the _COMMAND_ ++token see the help of ++. ++ ++

    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. ++ ++

    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 link. ++ ++

    <End of help on this topic> ++ ++ ++====== h_config_replace_rules ===== ++ ++ ++OPTION: <!--#echo var="VAR_replace-rules"--> ++ ++ ++

    OPTION:

    ++ ++

    This option is used to have Alpine print different values for specific ++tokens in the . For example you ++can replace strings like "To: newsgroup" by your name. ++ ++

    Here are examples of possible rules: ++ ++

    _FOLDER_ != {sent-mail} && _NICK_ != {} => _FROM_ := _REPLACE_{_FROM_ (_NICK_)} ++ ++

    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 ++ ++

    _FOLDER_ == {INBOX} => _SUBJECT_ := _REXTRIM_{\[some-tag-here #[0-9].*\]} ++ ++

    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.
    ++ ++

    _FOLDER_ == {some-folder} => _OPENINGTEXTNQ_ := _REXTRIM_{On.*wrote: } ++ ++

    You can also use the _EXEC_ function. The documentation for this function ++is in the ++ ++help text. ++ ++

    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 link. ++ ++

    <End of help on this topic> ++ ++ ++====== h_config_reply_leadin_rules ===== ++ ++ ++OPTION: <!--#echo var="VAR_reply-leadin-rules"--> ++ ++ ++

    OPTION:

    ++ ++

    This option is used to have Alpine generate a different ++ string dependent either on ++the person you are replying to, or the folder where the message is being ++replied is in, or both. ++ ++

    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: ++

    ++_FOLDER_ << {pine-info;_NEWS_} => _REPLY_{*** _FROM_ _ADDRESS_("_FROM_" "" "(_ADDRESS_) ")wrote in_NEWS_("" " the" "") _FOLDER_ _NEWS_("" "list " "")_SMARTDATE_("Today" "today" "on _LONGDATE_"):} ++ ++

    Here there is an example that one can use to change the reply indent string ++to reply people that speak spanish. ++

    ++_FROM_{Condorito;Quico} => _REPLY_{*** _FROM_ (_ADDRESS_) escribió _SMARTDATE_("Today" "hoy" "en _LONGDATE_"):} ++ ++

    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 link. ++ ++

    <End of help on this topic> ++ ++ ++====== h_config_resub_rules ===== ++ ++ ++OPTION: <!--#echo var="VAR_reply-subject-rules"--> ++ ++ ++

    OPTION:

    ++ ++

    This option is used to have Alpine generate a different subject when ++replying rather than the one Alpine would generate automatically. ++ ++

    Here there are a couple of examples about how to use this ++configuration option: ++ ++

    In order to have messages with empty subject to be replied with the message ++"your message" use the rule
    ++

    _SUBJECT_ == {} => _RESUB_{Re: your message}
    ++ ++

    If you want to trim some parts of the subject when you reply use the ++rule
    ++

    _SUBJECT_ >> {[one];two} => _SUBJECT_ := _TRIM_{[;];two}
    ++ ++

    this rule removes the brackets "[" and "]" whenever the string "[one]" ++appears in it, it also removes the word "two" from it. ++ ++

    Another example where you may want to use this rule is when you ++correspond with people that change the reply string from "Re:" ++to "AW:" or "Sv:". In this case a rule like
    ++

    _SUBJECT_ >> {Sv: ;AW: } => _SUBJECT_ := _TRIM_{Sv: ;AW: }
    ++

    ++would eliminate undesired strings in replies. ++ ++

    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 "a" of a file. ++ ++

    ++#!/bin/sh
    ++sed 's/a//g' $1 > /tmp/mytest
    ++mv /tmp/mytest $1
    ++
    ++ ++

    ++As you can see this script took "$1" 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 "$1". This is the kind of behavior ++that your program is expected to have. ++ ++

    ++The content of the input file ("$1" above) is the value of a token ++like _SUBJECT_. In order to indicate this, we use the notation ++ ++

    ++_SUBJECT_ := _EXEC_{/path/to/script} ++ ++

    for the action. So for example ++ ++

    ++_FOLDER_ := {sent-mail} => _SUBJECT_ := _EXEC_{/path/to/script} ++ ++

    is a valid rule. ++ ++

    You can also use this configuration option to customize reply subjects ++according to the sender of the message. ++ ++

    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 link. ++ ++

    <End of help on this topic> ++ ++ ++====== h_config_sort_rules ===== ++ ++ ++OPTION: <!--#echo var="VAR_sort-rules"--> ++ ++ ++

    OPTION:

    ++ ++

    This option is used to have Alpine sort different folders in different orders ++and thus override the value already set in the ++ configuration option. ++ ++

    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. ++ ++

    ++_COLLECTION_ >> {Incoming-Folders;News} && _FOLDER_ != {INBOX} => _SORT_{tHread} ++ ++

    Another example could be
    ++_FOLDER_ == {Mailing List} => _SORT_{Reverse tHread} ++ ++

    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 link. ++ ++

    <End of help on this topic> ++ ++ ++ ++====== h_config_save_rules ===== ++ ++ ++OPTION: <!--#echo var="VAR_save-rules"--> ++ ++ ++

    OPTION:

    ++ ++

    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). ++ ++

    If this option is set and the ++ configuration ++option is also enabled then these definitions will be used to move messages ++from your INBOX when exiting Alpine. ++ ++

    Here there are some examples
    ++_FLAG_ >> {D} -> Trash
    ++_FROM_ == {U2} -> Bono
    ++_FOLDER_ == {comp.mail.pine} -> pine-stuff
    ++_NICK_ != {} -> _NICK_/_NICK_
    ++_DATEISO_ >> {02-10;02-11} -> archive-oct-nov-2002 ++ ++

    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 link. ++ ++

    <End of help on this topic> ++ ++ ++ ++====== h_config_reply_indent_rules ===== ++ ++ ++OPTION: <!--#echo var="VAR_reply-indent-rules"--> ++ ++ ++

    OPTION:

    ++ ++

    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 ++is used. ++ ++

    The associated function to this configuration option is called "RESTR" (for ++REply STRing). Some examples of its use are:
    ++_FROM_ == {Your Boss} => _RESTR_{"> "}
    ++_FROM_ == {My Wife} => _RESTR_{":* "}
    ++_FROM_ == {Perter Flintstone;Wilma Flintstone} => _RESTR_{"_INIT_ > "}
    ++ ++

    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 link. ++ ++

    <End of help on this topic> ++ ++ ++ ++====== h_config_smtp_rules ===== ++ ++ ++OPTION: <!--#echo var="VAR_smtp-rules"--> ++ ++ ++

    OPTION:

    ++ ++

    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 ++"" configuration ++option according to the rules used in that variable. ++ ++

    The function associated to this configuration option is _SMTP_, an example ++of the use of this function is
    ++_ADDRESSTO_ == {peter@bedrock.com} => _SMTP_{smtp.bedrock.com} ++ ++

    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 link. ++ ++

    <End of help on this topic> ++ ++ ++ ++====== h_config_startup_rules ===== ++ ++ ++OPTION: <!--#echo var="VAR_startup-rules"--> ++ ++ ++

    OPTION:

    ++ ++

    This option is used when a folder is being opened. You can use it to specify its and override ++Alpine's global value set for all folders. ++ ++

    An example of the usage of this option is:
    ++_FOLDER_ == {Lynx;pine-info;_NEWS_} => _STARTUP_{first-unseen} ++ ++

    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 link. ++ ++

    <End of help on this topic> ++ ++ ++ ++====== h_config_new_rules ===== ++ ++ ++OPTION: New Rules Explained ++ ++ ++

    OPTION: New Rules Explained

    ++ ++This is a quite powerful option. Here you can define rules that override ++the values of any other option you have set in Alpine. ++ ++

    ++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 "rules" 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. ++ ++

    ++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 satisfied. ++ ++

    ++ Here is an example: ++ ++

    ++ _FROM_ == {Fred Flintstone} => _SAVE_{Fred} ++ ++

    ++ Here the separator is "=>". Whatever is to the left of the separator ++is the condition (that is _FROM_ == {Fred Flintstone}) 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 "Fred ++Flintstone", and the action will be that you will be offered to save ++it in the folder "Fred", whenever you press the letter ++"S" to save a message. ++ ++

    ++ The separator is always "=>", with one exception to be seen ++later. But for the most part this will be the only one you will ever need. ++ ++

    ++ Now let us see how to do it. There are 14 functions already defined for ++you. These are: _EXEC_, _INDEX_, _REPLACE_, _REPLY_, _RESUB_, _SAVE_, ++_SIGNATURE_, _SORT_, _STARTUP_, _TRIM_, _REXTRIM_, _REXSUB_, _THREADSTYLE and ++_THREADINDEX_. The parameter of a function has to be enclosed between ++"{" and "}", so for example you can specify ++_SAVE_{saved-messages} as a valid sentence. ++ ++

    ++ Later in the document you will find examples. Here is a short ++description of what each function does: ++ ++

    ++

      ++
    • _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 ++, ++ and ++. ++See the help of those options for examples of how to use this function ++and configure these rules. ++
       
      ++
    • _INDEX_ : This function takes as an argument an index-format, and ++makes that the index-format for the specified folder. ++
       
      ++
    • _REPLACE_ : This function replaces the subject/from of the given e-mail by ++another subject/from only when displaying the index. ++
       
      ++
    • _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. ++
       
      ++
    • _RESTR_ : This function takes as an argument the value of the ++reply-indent-string to be used to answer the message being replied to. ++
       
      ++
    • _RESUB_ : This function replaces the subject of the given e-mail by ++another subject only when replying to a message. ++
       
      ++
    • _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. ++
       
      ++
    • _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. ++
       
      ++
    • _SMTP_ : This function takes as an argument the definition of a ++SMTP server. ++
       
      ++
    • _SORT_ : This function takes as an argument a Sort Style, and sorts a ++specified folder in that sort order. ++
       
      ++
    • _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_. ++
       
      ++
    • _REXTRIM_ : Same as _TRIM_ but its argument is one and ++only one extended regular expression. ++
       
      ++
    • _REXSUB_ : This function takes three arguments. The structure ++is _REXSUB_{pattern}{text}{number of times}. The "pattern" ++to match is an extended regular expression. If the pattern is matched, ++it will be replaced by "text" as many times as the "number ++of times" argument specifies. If the last argument is ++omitted (that is, there are only two arguments) then the last argument ++is considered as "{1}". ++
       
      ++
    • _STARTUP_ : This function takes as an argument an ++incoming-startup-rule, and open an specified folder using that rule. ++
       
      ++
    • _THREADSTYLE_ : This function takes as an argument a ++threading-display-style and uses it to display threads in a folder. ++
       
      ++
    • _THREADINDEX_ : This function takes as an argument a ++threading-index-style and uses it to display threads in a folder. ++
    ++ ++

    ++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: ++ ++

    ++ _FROM_ == {Fred Flintstone} => _SAVE_{Fred} ++ ++

    it will only be applied if the from is "Fred Flintstone". If ++the From is "Wilma Flintstone" the rule will be skipped. ++ ++

    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 "{" and "}" in the condition, this part ++of the condition is called the "condition set". The definition ++of each token can be found here. ++ ++

    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 ++this link. ++ ++

    There are two more tokens related to the option ++key-definition-rules. Those tokens ++are only specific to that option, and hence are not explained here. ++ ++

    You can also test in different ways, you can use the following ++"test operands": <<, !<, >>, !>, == and !=. ++All of them are two characters long. Here is the meaning of them: ++ ++

    ++

      ++
    • << : It tests if the value of the token is contained in ++the condition set. Here for example if the condition set were equal to ++"Freddy", then the condition: _NICK_ << {Freddy}, would be true if ++the value of _NICK_ were "Fred", "red" or "Freddy". You are just looking ++for substrings here. ++
    • >> : 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 ++"Fred", then the condition: _FROM_ >> {Fred}, would be true if ++the value of _FROM_ were "Fred Flintstone" or "Fred P. Flintstone" or "Freddy". ++
    • == : 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 "Freddy" or "red". ++
    • !< : This is true only when << is false and vice versa. ++
    • !> : This is true only when >> is false and vice versa. ++
    • != : This is true only when == is false and vice versa. ++
    ++ ++

    ++ Now let us say that you want the same action to be applied to more than ++one person or folder, say you want "folder1" and "folder2" to be sorted by ++Ordered Subject upon entering. Then you can list them all of them in the ++condition part separting them by a ";". Here is the way to do it. ++ ++

    ++ _FOLDER_ << {folder1; folder2} => _SORT_{OrderedSubj} ++ ++

    ++ Here is the first subtlety about these definitions. Notice that the ++following rule: ++ ++

    ++ _FOLDER_ == {folder1; folder2} => _SORT_{Reverse OrderedSubj} ++ ++

    works only for "folder1" but not for "folder2". This is because the ++comparison of the name of the folder is done with whatever is in between ++"{", ";" or "}", so in the above rule you would be testing
    ++"folder2" == " folder2". The extra space makes the difference. ++The reason why the first rule does not fail is because ++"folder2" << " folder2" is actually ++true. If something ever fails this may be something to look into. ++ ++

    ++ Here are a few examples of what we have talked about before. ++ ++

    ++_NICK_ == {lisa;kika} => _SAVE_{_NICK_/_NICK_}
    ++This means that if the nick is lisa, it will ++save the message in the folder "lisa/lisa", and if the nick ++is "kika", it will save the message in the folder "kika/kika" ++ ++

    ++_FOLDER_ == {Lynx} -> lynx
    ++This, is an abbreviation of the following rule:
    ++_FOLDER_ == {Lynx} => _SAVE_{lynx}
    ++(note the change in separator from "=>" to "->"). In the future ++I will use that abbreviation. ++ ++

    _FOLDER_ << {comp.mail.pine; pine-info; pine-alpha} -> pine
    ++Any message in the folders "comp.mail.pine", "pine-info" or "pine-alpha" ++will be saved to the folder "pine". ++ ++

    _FROM_ << {Pine Master} -> pine
    ++Any message whose From field contains ++"Pine Master" will be saved in the folder pine. ++ ++

    _FOLDER_ << {Lynx; pine-info; comp.mail.pine} => ++_INDEX_{IMAPSTATUS MSGNO DATE FROMORTO(33%) SUBJECT(66%)}
    Use a ++different index-format for the folders "Lynx", "pine-info" and ++"comp.mail.pine", where the size is not present. ++ ++

    _FOLDER_ == {Lynx;pine-info} => _REPLY_{*** _FROM_ (_ADDRESS_) ++wrote in the _FOLDER_ list _SMARTDATE_("Today" "today" "on ++_LONGDATE_"):}
    If a message is in one of the incoming folders "Lynx" ++or "pine-info", create a reply-leadin-string that acknowledges that. Note ++the absence of "," in the function _SMARTDATE_. For example answering to a ++message in the pine-info list would look like: ++ ++

    ++*** Steve Hubert (hubert@cac.washington.edu) wrote in the pine-info list today: ++ ++

    ++However replying for a message in the Lynx list would look: ++ ++

    ++*** mattack@area.com (mattack@area.com) wrote in the Lynx list today: ++ ++

    ++If you write in more than one language you can use this feature to create ++Reply-leadin-strings in different languages. ++ ++

    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. ++ ++

    _FOLDER_ << {Lynx; comp.mail.pine; pine_info; pine-alpha} => ++_SORT_{OrderedSubj}
    This means upon opening, sort the folders "Lynx", ++"comp.mail.pine", 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). ++ ++

    The last examples use the function _TRIM_ which has a special form. ++This function can only be used in the index list. ++ ++

    _FOLDER_ << {Lynx} => _SUBJECT_ := _TRIM_{lynx-dev }
    In ++the folder "Lynx" eliminate from the subject the string "lynx-dev " (with ++the space at the end). For example a message whose subject is "Re: ++lynx-dev unvisited Visited Links", would be shown in the index with ++subject: "Re: unvisited Visited Links", making the subject shorter and ++giving the same information. ++ ++

    _FROM_ >> {Name (Comment)} => _FROM_ := ++_TRIM_{ (Comment)}
    Remove the part " (Comment)" ++from the _FROM_, so when displaying in the index the real From "Name" ++will appear. ++ ++

    _SUBJECT_ == {} => _RESUB_{Re: your mail without subject} ++If there is no subject in the message, use the subject "Re: your mail ++wiyhout subject" as a subject for the reply message. ++ ++

    You can add more complexity to your rules by checking more than one ++conditions before a rule is executed. More than one condition can be ++checked by separating different conditions by the && (and) separator, ++or using the || (or) separator. For example we could have a rule that ++saves all ++messages in inbox from Rubye, to the Personal folder, as ++ ++

    _FOLDER_ == {INBOX} && _FROM_ >> {Rubye} => _SAVE_{Personal} ++ ++

    We could also have a rule that is triggered by an "or" ++condition by, sat for messages from Andres or messages in the index ++to trigger a specific reply leadin string. ++ ++

    _FOLDER_ == {INBOX} || _FROM_ >> {Andres} => _REPLY_{You wrote:} ++ ++

    Observe that the construction ++ ++

    _TOKEN_ == {value1} || _TOKEN_ == {value2} ++ ++

    can be shortened to ++ ++

    _TOKEN_ == {value1;value2} ++ ++

    Round parentheses can be used to group some conditions, for example ++ ++

    (_FROM_ >> {Andres} && _FOLDER_ == {INBOX}) || _FROM_ >> {Rubye} ++ ++ ++

    You can also list your index by nick, in the following way:
    ++_NICK_ != {} => _FROM_ := _REPLACE_{_NICK_} ++ ++

    ++ If you want to open the folder "pine-info" in the first non-read message ++use the rule:
    ++_FOLDER_ == {pine-info} => _STARTUP_{first-unseen} ++ ++

    ++ If you want to move your deleted messages to a folder, called "Trash", use ++the following rule:
    ++_FLAG_ >> {D} -> Trash ++ ++

    ++The reason why the above test is not "_FLAG_ == {D}" 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. ++ ++

    If you want to use a specific signature when you are in a specific collection ++use the following rule:
    ++_COLLECTION_ == {Mail} => _SIGNATURE_{/full/path/to/.signature} ++ ++

    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 "saving" rules do not compete with "sorting" rules. So the first ++"saving" rule that matches will be executed in the case of saving and so ++on. ++ ++

    ++

    ++<End of help on this topic> ++ ++ + ====== h_config_char_set ===== + + +@@ -28580,6 +29635,76 @@ the From field is used to show the relat + <End of help on this topic> + + ++====== h_config_thread_display_style_rule ===== ++ ++ ++OPTION: Threading-Display-Style-Rule ++ ++ ++

    OPTION: Threading-Display-Style-Rule

    ++ ++This option is very similar to ++, but it is a rule which specifies the ++display styles for a thread that you want displayed in a specific ++folder or collection. ++

    ++The token to be used in this function is _THREADSTYLE_. Here there is ++an example of its use ++

    ++_FOLDER_ == {pine-info} => _THREADSTYLE_{mutt-like} ++

    ++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 threading-display-style ++configuration option. ++ ++

    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 link. ++ ++

    ++

    ++<End of help on this topic> ++ ++ ++====== h_config_thread_index_style_rule ===== ++ ++ ++OPTION: Threading-Index-Style-Rule ++ ++ ++

    OPTION: Threading-Index-Style-Rule

    ++ ++This option is very similar to ++, but it is a rule which specifies the ++index styles for a thread that you want displayed in a specific ++folder or collection. ++

    ++The token to be used in this function is _THREADINDEX_. Here there is ++an example of its use ++

    ++_FOLDER_ == {pine-info} => _THREADINDEX_{regular-index-with-expanded-threads} ++

    ++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 ++configuration option. ++ ++

    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 link. ++ ++

    ++

    ++<End of help on this topic> ++ ++ + ====== h_config_pruning_rule ===== + + +@@ -32271,6 +33396,29 @@ automatically transfer all read messages + them as deleted in the INBOX. Messages in the INBOX marked with an + "N" (meaning New, or unseen) are not affected. +

    ++

    ++<End of help on this topic> ++ ++ ++====== h_config_auto_read_msgs_rules ===== ++ ++ ++FEATURE: auto-move-read-msgs-using-rules ++ ++ ++

    FEATURE: auto-move-read-msgs-using-rules

    ++This feature controls an aspect of Alpine's behavior upon quitting. If set, ++and the ++"" ++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 ++"" and mark ++them as deleted in the INBOX. Messages in the INBOX marked with an ++"N" (meaning New, or unseen) are not affected. ++

    +

    +Index: alpine-2.24/pith/reply.c +=================================================================== +--- alpine-2.24.orig/pith/reply.c ++++ alpine-2.24/pith/reply.c +@@ -47,6 +47,8 @@ static char rcsid[] = "$Id: reply.c 1074 + #include "../pith/mailcmd.h" + #include "../pith/margin.h" + #include "../pith/smime.h" ++#include "../pith/copyaddr.h" ++#include "../pith/rules.h" + + + /* +@@ -864,8 +866,27 @@ char * + reply_quote_str(ENVELOPE *env) + { + char *prefix, *repl, *p, buf[MAX_PREFIX+1], pbf[MAX_SUBSTITUTION+1]; ++ char reply_string[MAX_PREFIX+1]; + +- strncpy(buf, ps_global->VAR_REPLY_STRING, sizeof(buf)-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 */ +@@ -917,10 +938,29 @@ reply_quote_str(ENVELOPE *env) + 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))); ++ 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))); + } + + +@@ -1486,6 +1526,10 @@ get_addr_data(ENVELOPE *env, IndexColTyp + buf[0] = '\0'; + + switch(type){ ++ case iFfrom: ++ addr = env && env->sparep ? env->sparep : NULL; ++ break; ++ + case iFrom: + addr = env ? env->from : NULL; + break; +@@ -1898,22 +1942,194 @@ get_reply_data(ENVELOPE *env, ACTION_S * + + 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 iRoleNick: +- if(role && role->nick){ +- strncpy(buf, role->nick, maxlen); +- buf[maxlen] = '\0'; ++ 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 = ps_global->mail_stream; ++ MSGNO_S *msgmap = NULL; ++ long msgno; ++ MESSAGECACHE *mc; ++ strncpy(buf, "_FLAG_", maxlen); /* default value */ ++ if (stream){ ++ msgmap = sp_msgmap(stream); ++ 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" : "" ); ++ } ++ buf[maxlen] = '\0'; ++ } ++ break; ++ ++ case iAltAddress: ++ if(ps_global->VAR_ALT_ADDRS != NULL ++ && ps_global->VAR_ALT_ADDRS[0] != NULL){ ++ size_t len; ++ int i, j; ++ ++ for(i = 0, len = 0; len < maxlen && ps_global->VAR_ALT_ADDRS[i]; i++){ ++ for(j = 0; len < maxlen && ps_global->VAR_ALT_ADDRS[i][j] != '\0'; j++){ ++ if(ps_global->VAR_ALT_ADDRS[i][j] == ';') ++ buf[len++] = '\\'; ++ buf[len++] = ps_global->VAR_ALT_ADDRS[i][j]; ++ } ++ if(len < maxlen){ ++ if(ps_global->VAR_ALT_ADDRS[i+1] != NULL) ++ buf[len++] = ';'; ++ else ++ buf[len++] = '\0'; ++ } ++ } ++ buf[maxlen] = '\0'; ++ } ++ break; ++ ++ case iNick: ++ case iFccFrom: ++ case iFccSender: ++ if (env){ ++ ADDRESS *tmp_adr; ++ ++ switch(type){ ++ case iNick: ++ tmp_adr = env->from ? copyaddr(env->from) ++ : env->sender ? copyaddr(env->sender) : NULL; ++ break; ++ case iFccFrom: ++ tmp_adr = env->from ? copyaddr(env->from) : NULL; ++ break; ++ case iFccSender: ++ tmp_adr = env->sender ? copyaddr(env->sender) : NULL; ++ break; ++ default: alpine_panic("Unhandled Rules case (01)"); ++ } ++ if(type == iNick) ++ get_nickname_from_addr(tmp_adr, buf, maxlen); ++ else ++ get_fcc_from_addr(tmp_adr, buf, maxlen); ++ mail_free_address(&tmp_adr); + } + break; + ++ case iAddressSender: ++ 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) ++ : (type == iAddressSender) ++ ? ((env && env->sender) ++ ? copyaddr(env->sender) ++ : 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)){ + strncpy(buf, NEWLINE, maxlen); +@@ -1941,6 +2157,11 @@ get_reply_data(ENVELOPE *env, ACTION_S * + + 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); +@@ -1990,6 +2211,14 @@ get_reply_data(ENVELOPE *env, ACTION_S * + + break; + ++ case iOpeningText: ++ case iOpeningTextNQ: ++ if(env && env->sparep){ ++ strncpy(buf, ((SPAREP_S *)env->sparep)->value, maxlen); ++ buf[maxlen] = '\0'; ++ } ++ break; ++ + case iSubject: + case iShortSubject: + if(env && env->subject){ +@@ -2052,7 +2281,18 @@ reply_delimiter(ENVELOPE *env, ACTION_S + if(!env) + return; + +- strncpy(buf, ps_global->VAR_REPLY_INTRO, MAX_DELIM); ++ { 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)){ +@@ -2311,6 +2551,7 @@ forward_subject(ENVELOPE *env, int flags + { + size_t l; + char *p, buftmp[MAILTMPLEN]; ++ RULE_RESULT *rule; + + if(!env) + return(NULL); +@@ -2318,9 +2559,19 @@ forward_subject(ENVELOPE *env, int flags + 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'; ++ buftmp[0] = '\0'; ++ ps_global->procid = cpystr("fwd-subject"); ++ if (rule = get_result_rule(V_FORWARD_RULES,FOR_COMPOSE, env)){ ++ snprintf(buftmp, sizeof(buftmp), "%s", rule->result); ++ fs_give((void **)&rule->result); ++ fs_give((void **)&rule); ++ } ++ else if(env->subject) ++ snprintf(buftmp, sizeof(buftmp), "%s", 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) +Index: alpine-2.24/pith/rules.c +=================================================================== +--- /dev/null ++++ alpine-2.24/pith/rules.c +@@ -0,0 +1,1565 @@ ++/* This module was written by ++ * ++ * Eduardo Chappa (chappa@washington.edu) ++ * http://alpine.x10host.com/alpine/ ++ * ++ * Original Version: November 1999 ++ * Last Modified : November 24, 2018 ++ * ++ * 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/mailindx.h" ++#include "../pith/rules.h" ++ ++#define CSEP_C ('\001') ++#define CSEP_S ("\001") ++ ++/* 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 *); ++int sanity_check_condition (char *); ++char *test_rule (RULELIST *, int, ENVELOPE *, int *); ++char *trim (RULEACTION_S *, int, ENVELOPE *); ++char *rextrim (RULEACTION_S *, int, ENVELOPE *); ++char *rexsub (RULEACTION_S *, int, ENVELOPE *); ++char *do_rextrim (char *, TOKEN_VALUE *); ++char *do_rexsub (char *, TOKEN_VALUE *); ++char *raw_value (RULEACTION_S *, int, ENVELOPE *); ++char *extended_value (RULEACTION_S *, int, ENVELOPE *); ++char *exec_fcn (RULEACTION_S *, int, ENVELOPE *); ++char *expand (char *, char *); ++char *get_name_token (char *); ++char *advance_to_char (char *, char, int, int *); ++char **functions_for_token (char *); ++char *canonicalize_condition (char *, int *); ++void free_rexsub (REXSUB_S **); ++void free_void_token_value (void **, int); ++void free_token_value (TOKEN_VALUE **); ++void free_condition (CONDITION_S **); ++void free_condition_value (CONDVALUE_S **); ++void free_ruleaction (RULEACTION_S **); ++void free_rule (RULE_S **); ++void free_rule_list (RULELIST **); ++void *rule_alloc_mem (size_t); ++void add_rule (int, int); ++void set_rule_list (struct variable *); ++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 *); ++TOKEN_VALUE *parse_action_to_char(char *); ++TOKEN_VALUE *parse_rexsub_action(char *); ++CONDVALUE_S *fill_condition_value (char *); ++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, 6, 1, CHAR_TYPE, parse_action_to_char, extended_value, FOR_SAVE|FOR_COMPOSE}, ++{REXTRIM_FCN, 9, 1, CHAR_TYPE, parse_action_to_char, rextrim, FOR_REPLACE|FOR_TRIM|FOR_RESUB|FOR_COMPOSE}, ++{REXSUB_FCN, 8, 1, REXSUB_TYPE, parse_rexsub_action, rexsub, FOR_REPLACE|FOR_TRIM|FOR_RESUB|FOR_COMPOSE}, ++{EXEC_FCN, 6, 1, CHAR_TYPE, parse_action_to_char, exec_fcn, FOR_REPLACE|FOR_TRIM|FOR_RESUB|FOR_COMPOSE}, ++{TRIM_FCN, 6, 1, CHAR_TYPE, parse_action_to_char, trim, FOR_REPLACE|FOR_TRIM|FOR_RESUB|FOR_COMPOSE}, ++{REPLACE_FCN, 7, 1, CHAR_TYPE, parse_action_to_char, extended_value, FOR_REPLACE}, ++{SAVE_FCN, 6, 0, UNDEFINED_TYPE, NULL, extended_value, FOR_SAVE}, ++{REPLY_FCN, 7, 0, UNDEFINED_TYPE, NULL, extended_value, FOR_REPLY_INTRO}, ++{SORT_FCN, 6, 0, UNDEFINED_TYPE, NULL, raw_value, FOR_SORT}, ++{INDEX_FCN, 7, 0, UNDEFINED_TYPE, NULL, raw_value, FOR_INDEX}, ++{COMMAND_FCN, 9, 0, UNDEFINED_TYPE, NULL, raw_value, FOR_KEY}, ++{REPLYSTR_FCN, 10, 0, UNDEFINED_TYPE, NULL, raw_value, FOR_COMPOSE}, ++{SIGNATURE_FCN,11, 0, UNDEFINED_TYPE, NULL, raw_value, FOR_COMPOSE}, ++{RESUB_FCN, 7, 0, UNDEFINED_TYPE, NULL, extended_value, FOR_RESUB}, ++{STARTUP_FCN, 9, 0, UNDEFINED_TYPE, NULL, raw_value, FOR_STARTUP}, ++{THRDSTYLE_FCN,11, 0, UNDEFINED_TYPE, NULL, raw_value, FOR_THREAD}, ++{THRDINDEX_FCN,11, 0, UNDEFINED_TYPE, NULL, raw_value, FOR_THREAD}, ++{SMTP_FCN, 6, 0, UNDEFINED_TYPE, NULL, raw_value, FOR_COMPOSE}, ++{NULL, 0, 0, UNDEFINED_TYPE, 0, 0, FOR_NOTHING} ++}; ++ ++char* token_rules[] = { ++ FROM_TOKEN, ++ NICK_TOKEN, ++ FCCF_TOKEN, ++ FCCS_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, REXSUB_FCN, EXEC_FCN}; ++char *from_fcn[] = {FROM_TOKEN, REPLACE_FCN, TRIM_FCN, REXTRIM_FCN, REXSUB_FCN, EXEC_FCN}; ++char *otext_fcn[] = {OTEXT_TOKEN, REPLACE_FCN, TRIM_FCN, REXTRIM_FCN, REXSUB_FCN, EXEC_FCN}; ++char *otextnq_fcn[] = {OTEXTNQ_TOKEN, REPLACE_FCN, TRIM_FCN, REXTRIM_FCN, REXSUB_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 *) rule_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; ++ 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_rexsub (REXSUB_S **rexsub) ++{ ++ if(rexsub == NULL || *rexsub == NULL) ++ return; ++ ++ if((*rexsub)->pattern) fs_give((void **) &(*rexsub)->pattern); ++ if((*rexsub)->text) fs_give((void **) &(*rexsub)->text); ++ fs_give((void **) rexsub); ++} ++ ++void ++free_void_token_value(void **voidptr, int voidtype) ++{ ++ switch(voidtype){ ++ case CHAR_TYPE: fs_give(voidptr); ++ break; ++ case REXSUB_TYPE: free_rexsub ((REXSUB_S **) voidptr); ++ break; ++ default: break; /* do nothing */ ++ } ++} ++ ++void ++free_token_value(TOKEN_VALUE **token) ++{ ++ if(token && *token){ ++ if ((*token)->testxt) ++ fs_give((void **)&(*token)->testxt); ++ if ((*token)->voidtxt) ++ free_void_token_value((void **) &(*token)->voidtxt, (*token)->voidtype); ++ if((*token)->next) ++ free_token_value(&(*token)->next); ++ fs_give((void **)token); ++ } ++} ++ ++void ++free_condition_value(CONDVALUE_S **cvalue) ++{ ++ if(cvalue && *cvalue){ ++ if ((*cvalue)->tname) ++ fs_give((void **)&(*cvalue)->tname); ++ if ((*cvalue)->value) ++ free_token_value(&(*cvalue)->value); ++ fs_give((void **)cvalue); ++ } ++} ++ ++void ++free_condition(CONDITION_S **condition) ++{ ++ if(condition && *condition){ ++ if((*condition)->cndtype == Condition) ++ free_condition_value((CONDVALUE_S **)&(*condition)->cndrule); ++ else if((*condition)->cndtype == ParOpen || (*condition)->cndtype == ParClose) ++ fs_give(&(*condition)->cndrule); ++ 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 * ++rule_alloc_mem (size_t amount) ++{ ++ void *genmem; ++ memset(genmem = fs_get(amount), 0, amount); ++ return genmem; ++} ++ ++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 '&': ++ case '|': if (*(p+1) == *p){ /* looking for && or ||*/ ++ p += 2; ++ next_condition++; ++ } ++ else{ ++ error++; ++ done++; ++ } ++ break; ++ case '=': /* looking for => or -> */ ++ case '-': if (*(p+1) != '>' || next_condition) ++ 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, *d; ++ int offset, err = 0, freeme = 0; ++ ++ if(error) ++ *error = 0; ++ ++ if (!data) ++ return (TOKEN_VALUE *) NULL; ++ ++ if(*data == '_'){ ++ d = detoken_src(data, FOR_RULE, NULL, NULL, NULL, NULL); ++ freeme++; ++ } ++ else ++ d = data; ++ ++ rvalue = (TOKEN_VALUE *) rule_alloc_mem(sizeof(TOKEN_VALUE)); ++ if (p = advance_to_char(d,';', STRICTLY, &offset)){ ++ rvalue->testxt = p; ++ rvalue->next = parse_group_data(d + strlen(p) + 1 + offset, error); ++ } ++ else if (p = advance_to_char(d,'}', STRICTLY, NULL)) ++ rvalue->testxt = p; ++ else if (d && *d == '}') ++ rvalue->testxt = cpystr(""); ++ else{ ++ err++; ++ free_token_value(&rvalue); ++ } ++ if (error) ++ *error += err; ++ if(freeme != 0 && d != NULL) ++ fs_give((void **)&d); ++ return(rvalue); ++} ++ ++CONDVALUE_S * ++fill_condition_value(char *data) ++{ ++ CONDVALUE_S *condition; ++ int i, done, error = 0; ++ char *group; ++ ++ for (i = 0, done = 0; done == 0 && token_rules[i] != NULL; i++) ++ done = strncmp(data,token_rules[i], strlen(token_rules[i])) ? 0 : 1; ++ if (done){ ++ condition = rule_alloc_mem(sizeof(CONDVALUE_S)); ++ condition->tname = cpystr(token_rules[--i]); ++ data += strlen(token_rules[i]); ++ } ++ else if (*data == '_') { ++ INDEX_PARSE_T *token; ++ char *itokname; ++ for (i = 0, done = 0; ++ done == 0 && (token = itoken(i)) != NULL && (itokname = token->name) != NULL; i++) ++ done = strncmp(data+1, itokname, strlen(itokname)) ++ ? 0 : data[strlen(itokname) + 1] == '_'; ++ if (done){ ++ condition = (CONDVALUE_S *) rule_alloc_mem(sizeof(CONDVALUE_S)); ++ condition->tname = fs_get(strlen(itokname) + 3); ++ sprintf(condition->tname, "_%s_", itokname); ++ data += strlen(itokname) + 2; ++ } ++ else ++ return NULL; ++ } ++ else ++ return NULL; ++ ++ for (; *data && *data == ' '; data++); ++ if (*data){ ++ for (i = 0, done = 0; done == 0 && rel_rules_test[i].value != NULL; i++) ++ done = strncmp(data, rel_rules_test[i].value, 2) ? 0 : 1; ++ if (done) ++ condition->ttype = rel_rules_test[--i].ttype; ++ else{ ++ free_condition_value(&condition); ++ return NULL; ++ } ++ } ++ else{ ++ free_condition_value(&condition); ++ return NULL; ++ } ++ ++ data += 2; ++ for (; *data && *data == ' '; data++); ++ if (*data++ != '{'){ ++ free_condition_value(&condition); ++ return 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_value(&condition); ++ if(group) ++ fs_give((void **) &group); ++ } ++ else ++ free_condition_value(&condition); ++ return condition; ++} ++ ++char * ++canonicalize_condition(char *data, int *eoc) ++{ ++ char *p = data, *s, *t, c; ++ char *q = fs_get((5*strlen(data)+1)*sizeof(char)); ++ char tmp[10]; ++ int level, done, error, i; ++ ++ if(eoc) *eoc = -1; /* assume error */ ++ *q = '\0'; ++ if(*p == '"'){ ++ if(p[strlen(p) - 1] == '"') ++ p[strlen(p) - 1] = '\0'; ++ p++; ++ } ++ for(level = done = error = 0; *p && !done && !error; ){ ++ switch(*p){ ++ case ' ' : p++; break; ++ case '(' : strcat(q, CSEP_S); strcat(q, "("); ++ sprintf(tmp, "%d ", level++); ++ strcat(q, tmp); ++ p++; ++ break; ++ case ')' : strcat(q, CSEP_S); strcat(q, ")"); ++ sprintf(tmp, "%d ", --level); ++ strcat(q, tmp); ++ p++; ++ if(level < 0) error++; ++ break; ++ case '_' : for(s = p+1; *s >= 'A' && *s <= 'Z'; s++); ++ for(i = 0; token_rules[i] != NULL; i++) ++ if(!strncmp(token_rules[i], p, s-p)) ++ break; ++ if(token_rules[i] == NULL) ++ error++; ++ else if(*s++ == '_'){ ++ for(; *s == ' '; s++); ++ if(*s && *(s+1)){ ++ for(i = 0; rel_rules_test[i].value != NULL; i++) ++ if(!strncmp(rel_rules_test[i].value, s, 2)) ++ break; ++ if (rel_rules_test[i].value == NULL) ++ error++; ++ else{ ++ s += 2; ++ for(; *s == ' '; s++); ++ if(*s == '{'){ ++ if(*(s+1) != '}') ++ t = advance_to_char(s+1,'}', STRICTLY, NULL); ++ else ++ t = cpystr(""); ++ if(t != NULL){ ++ for(i = 0; t[i] != '\0' && t[i] != CSEP_C; i++); ++ if(t[i] == CSEP_C) error++; ++ if(error == 0){ ++ strcat(q, CSEP_S); strcat(q, "C["); ++ s += strlen(t) + 1; /* get past '{' */ ++ *s = '\0'; ++ strcat(q, p); ++ strcat(q, "}] "); ++ *s++ = '}'; ++ p = s; ++ } ++ fs_give((void **) &t); ++ } ++ else error++; ++ } ++ else ++ error++; ++ } ++ } ++ } ++ else error++; ++ break; ++ case '|': ++ case '&': if(*(p+1) = *p){ ++ strcat(q, CSEP_S); strcat(q, *p == '|' ? "OR " : "AND "); ++ p += 2; ++ } else error++; ++ break; ++ case '-': ++ case '=': if (*(p+1) == '>'){ ++ if(eoc) *eoc = p - data; ++ done++; ++ } ++ else ++ error++; ++ break; ++ default : error++; ++ break; ++ } ++ } ++ if(error || level > 0) /*simplistic approach by now */ ++ fs_give((void **)&q); ++ else ++ q[strlen(q)-1] = '\0'; ++ return q; ++} ++ ++/* for a canonical condition, return if it is constructed according ++ * to logical rules such as AND or OR between conditions, etc. We assume ++ * we already canonicalized data, or else this will not work. ++ */ ++int ++sanity_check_condition(char *data) ++{ ++ int i, error; ++ char *s, *t, *d; ++ ++ if(data == NULL || *data == '\0') /* no data in, no data out */ ++ return 0; ++ ++ d = fs_get((strlen(data)+1)*sizeof(char)); ++ for(s = data,i = 0; (t = strchr(s, CSEP_C))!= NULL && (d[i] = *(t+1)); s = t+1, i++); ++ d[i] = '\0'; ++ for(i = 0, error = 0; d[i] != '\0' && error == 0; i++){ ++ switch(d[i]){ ++ case 'C': if((d[i+1] != '\0' && (d[i+1] == '(' || d[i+1] == 'C')) ++ || (i == 0 && d[1] != 'A' && d[1] != 'O' && d[1] != '\0')) ++ error++; ++ break; ++ case ')': if(i == 0 || (d[i+1] != '\0' && (d[i+1] == 'C' || d[i+1] == '('))) ++ error++; ++ break; ++ case '(': if(d[i+1] == '\0' || d[i+1] == ')' || d[i+1] == 'A' || d[i+1] == 'O') ++ error++; ++ break; ++ case 'O': ++ case 'A': if(i == 0 || d[i+1] == '\0' || d[i+1] == ')' || d[i+1] == 'A' || d[i+1] == 'O') ++ error++; ++ break; ++ default : error++; ++ } ++ } ++ if(d) fs_give((void **)&d); ++ return error ? 0 : 1; ++} ++ ++/* given a parsed data that satisfies sanity checks, parse it ++ * into a condition we can check later on. ++ */ ++CONDITION_S * ++fill_condition(char *data) ++{ ++ char *s, *t, *u; ++ CONDITION_S *rv = NULL; ++ CONDVALUE_S *cvalue; ++ int *i; ++ ++ if(data == NULL || *data == '\0' || (s = strchr(data, CSEP_C)) == NULL) ++ return NULL; ++ ++ rv = (CONDITION_S *) rule_alloc_mem(sizeof(CONDITION_S)); ++ switch(*++s){ ++ case ')': ++ case '(': i = fs_get(sizeof(int)); ++ *i = atoi(s+1); ++ rv->cndrule = (void *) i; ++ rv->cndtype = *s == '(' ? ParOpen : ParClose; ++ break; ++ ++ case 'C': if((u = strchr(s+2, CSEP_C)) != NULL){ ++ *u = '\0'; ++ t = strrchr(s, ']'); ++ t = '\0'; ++ *u = CSEP_C; ++ } else ++ s[strlen(s) - 1] = '\0'; ++ rv->cndrule = (void *) fill_condition_value(s+2); ++ rv->cndtype = Condition; ++ break; ++ ++ case 'A': ++ case 'O': rv->cndtype = *s == 'A' ? And : Or; ++ break; ++ ++ default : fs_give((void **)&rv); ++ break; ++ } ++ rv->next = fill_condition(strchr(s, CSEP_C)); ++ ++ return rv; ++} ++ ++/* eoc = end of condition, equal to -1 on error */ ++CONDITION_S * ++parse_condition (char *data, int *eoc) ++{ ++ CONDITION_S *condition = NULL; ++ char *pvalue; ++ ++ if((pvalue = canonicalize_condition(data, eoc)) != NULL ++ && sanity_check_condition(pvalue) > 0) ++ condition = fill_condition(pvalue); ++ ++ if(pvalue) ++ fs_give((void **)&pvalue); ++ ++ if (condition == NULL && eoc) ++ *eoc = -1; ++ ++ return condition; ++} ++ ++RULEACTION_S * ++parse_action (char *data, int context) ++{ ++ int i, done, is_save; ++ RULEACTION_S *raction = NULL; ++ char *function, *p = data; ++ ++ if (p == NULL || *p == '\0') ++ return NULL; ++ ++ is_save = *p == '-'; ++ p += 2; ++ for (; *p == ' '; p++); ++ ++ if (is_save){ /* got "->", a save-rule separator */ ++ raction = (RULEACTION_S *) rule_alloc_mem(sizeof(RULEACTION_S)); ++ raction->function = cpystr("_SAVE_"); ++ raction->value = (TOKEN_VALUE *) rule_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 NULL; ++ if (done){ ++ raction = rule_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 *) rule_alloc_mem(sizeof(TOKEN_VALUE)); ++ raction->value->testxt = advance_to_char(p,'}', STRICTLY, NULL); ++ if(!raction->value->testxt) ++ free_ruleaction(&raction); ++ return raction; ++ } ++ ++ raction = (RULEACTION_S *) rule_alloc_mem(sizeof(RULEACTION_S)); ++ raction->token = get_name_token(p); ++ ++ p += strlen(raction->token) + 1; ++ for (; *p && *p == ' '; p++); ++ if (!strncmp(p, ":=", 2)) ++ p += 2; ++ else{ ++ free_ruleaction(&raction); + return NULL; -+ ++ } ++ ++ for (; *p && *p == ' '; p++); ++ ++ for(i = 0; i < NFCN && strncmp(p, rule_fcns[i].name, rule_fcns[i].len); i++); ++ ++ if (!rule_fcns[i].is_assignment){ ++ free_ruleaction(&raction); ++ return NULL; ++ } ++ ++ raction->function = cpystr(rule_fcns[i].name); ++ raction->context = rule_fcns[i].what_for; ++ raction->exec = rule_fcns[i].execute; ++ p += rule_fcns[i].len; ++ ++ if(*p++ != '{'){ ++ free_ruleaction(&raction); ++ return NULL; ++ } ++ ++ if(rule_fcns[i].parse_action_value){ ++ raction->value = (rule_fcns[i].parse_action_value)(p); ++ if(raction->value) ++ raction->value->voidtype = rule_fcns[i].return_type; ++ } ++ ++ if(raction->value == NULL ++ || (raction->value->testxt == NULL && raction->value->voidtxt == NULL)) ++ free_ruleaction(&raction); ++ ++ return raction; ++} ++ ++TOKEN_VALUE * ++parse_action_to_char(char *p) ++{ ++ return parse_group_data(p, NULL); ++} ++ ++TOKEN_VALUE * ++parse_rexsub_action(char *data) ++{ ++ TOKEN_VALUE *rv; ++ REXSUB_S *rsv = NULL; /* rexsub value */ ++ char *d, *p, *t, *n; /* data, pattern, text, number */ ++ long number; ++ int offset, error; ++ ++ if (data == NULL || *data == '\0') ++ return NULL; ++ ++ rv = (TOKEN_VALUE *) rule_alloc_mem(sizeof(TOKEN_VALUE)); ++ ++ number = 0; ++ p = t = n = NULL; ++ ++ p = advance_to_char(data,'}', STRICTLY, NULL); ++ ++ error = (p == NULL) ? 1 : 0; ++ if(!error){ ++ offset = strlen(p) + 1; ++ d = data + offset; ++ if(*d++ != '{') error++; ++ } ++ ++ if(!error){ ++ n = advance_to_char(d,'}', STRICTLY, NULL); ++ if(n == NULL && *d == '}') ++ n = cpystr(""); ++ if(n == NULL) error++; ++ } ++ ++ if(!error){ ++ t = detoken_src(n, FOR_RULE, NULL, NULL, NULL, NULL); ++ offset += strlen(n) + 2; ++ d = data + offset; ++ if(*d == '\0') number = 1; ++ else if(*d++ != '{') error++; ++ } ++ ++ if(!error && number == 0){ ++ fs_give((void **) &n); ++ n = advance_to_char(d,'}', STRICTLY, NULL); ++ if(n == NULL){ ++ if(*d == '\0') ++ number = 1; ++ else ++ error++; ++ } ++ else if(strcmp(n, "g") == 0) ++ number = -1; ++ else{ ++ char *eon; ++ number = strtol(n, &eon, 10); ++ if((eon != NULL && *eon != '\0') || number <= 0) error++; ++ } ++ } ++ ++ if(error){ ++ if (p) fs_give((void **) &p); ++ if (t) fs_give((void **) &t); ++ } ++ if (n) fs_give((void **) &n); ++ ++ if(!error){ ++ rsv = fs_get(sizeof(REXSUB_S)); ++ rsv->pattern = p; ++ rsv->text = t; ++ rsv->times = number; ++ } ++ ++ rv->voidtxt = (void *) rsv; ++ return rv; ++} ++ ++RULE_S * ++parse_rule (char *data, int context) ++{ ++ RULE_S *prule; /*parsed rule */ ++ int len = 0; ++ ++ if (!(prule = (RULE_S *) rule_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 *) rule_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; ++} ++ ++/* add parsed rule */ ++PRULELIST_S * ++add_prule(PRULELIST_S *rule_list, PRULELIST_S *rule) ++{ ++ PRULELIST_S *rlist; ++ ++ for(rlist = rule_list; rlist && rlist->next; rlist = rlist->next); ++ ++ if(rlist) ++ rlist->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 *) rule_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) ++{ ++ while(condition && condition->cndtype != Condition) ++ condition = condition->next; ++ ++ return condition ++ ? (!strcmp(COND(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) ++ : 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; -+ -+ return test_condition(prule->condition, rule_context, env) -+ ? (prule->action->exec)(prule->action, rule_context, env) -+ : NULL; -+ } -+ -+ 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 *) rule_alloc_mem(sizeof(TOKEN_VALUE)); -+ tval->testxt = detoken_src(value->testxt, ctxt, env, NULL, NULL, NULL); -+ tval->voidtxt = value->voidtxt; -+ tval->codefcn = value->codefcn; ++ 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; ++ } + } -+ 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_work(CONDITION_S *bc, CONDITION_S *ec, int rcntxt, ENVELOPE *env) -+ { -+ int rv,level; -+ TOKEN_VALUE *group; -+ CONDITION_S *cend; -+ -+ switch(bc->cndtype){ -+ case Condition: group = copy_parsed_value(COND(bc)->value, rcntxt, env); -+ rv = (*rel_rules_test[COND(bc)->ttype].execute)(bc, group, env, rcntxt); -+ free_parsed_value(&group); -+ if(bc == ec) -+ return rv; -+ if(bc->next == NULL) -+ return rv; -+ else -+ switch(bc->next->cndtype){ -+ case And: return rv ? test_condition_work(bc->next->next, ec, rcntxt, env) : 0; -+ break; -+ case Or : return rv ? 1 : test_condition_work(bc->next->next, ec, rcntxt, env); -+ break; -+ case ParClose: return rv; -+ default : rv = 0; break; /* fail, we should not be here */ -+ } -+ break; -+ -+ case ParOpen: level = ((int *)bc->cndrule)[0]; -+ for(cend = bc; cend->next && (cend->next->cndtype != ParClose -+ || ((int *)cend->next->cndrule)[0] != level); -+ cend = cend->next); -+ rv = test_condition_work(bc->next, cend, rcntxt, env); -+ cend = cend->next; /* here we are at ')' */ -+ if(cend->next == NULL) -+ return rv; -+ else{ -+ switch(cend->next->cndtype){ -+ case And: return rv ? test_condition_work(cend->next->next, ec, rcntxt, env) : 0; -+ break; -+ case Or : return rv ? 1 : test_condition_work(cend->next->next, ec, rcntxt, env); -+ break; -+ default : rv = 0; break; /* fail, we should not be here */ -+ } -+ } -+ break; -+ default: rv = 0; break; /* fail, we should not be here */ ++ 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); + } -+ return rv; /* we never ever get here */ -+ } -+ -+ -+ int -+ test_condition(CONDITION_S *condition, int rcntxt, ENVELOPE *env) -+ { -+ return test_condition_work(condition, NULL, rcntxt, env); -+ } -+ -+ /* 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, *q, c, *rv; -+ -+ if (condition == NULL) ++ 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: prule, a processed rule, ready to be tested ++ 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) ++{ ++ if(!prule) ++ return NULL; ++ ++ if(!(rule_context & FOR_RULE)) ++ rule_context |= FOR_RULE; ++ ++ return test_condition(prule->condition, rule_context, env) ++ ? (prule->action->exec)(prule->action, rule_context, env) ++ : NULL; ++} ++ ++TOKEN_VALUE * ++copy_parsed_value(TOKEN_VALUE *value, int ctxt, ENVELOPE *env) ++{ ++ TOKEN_VALUE *tval = NULL; ++ ++ if(!value) + return NULL; -+ -+ for(p = condition; *p != '\0' && (*p == ' '|| *p == '\t'); p++); -+ -+ if (*p != '_') return NULL; -+ -+ for (q = p+1; *q != '\0' && *q != '_'; q++); -+ -+ if (*q != '_') return NULL; -+ -+ c = *(q+1); -+ *(q+1) = '\0'; -+ rv = cpystr(p); -+ *(q+1) = c; -+ return rv; -+ } -+ -+ /* 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(COND(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); -+ } ++ ++ if(value->testxt){ ++ tval = (TOKEN_VALUE *) rule_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_work(CONDITION_S *bc, CONDITION_S *ec, int rcntxt, ENVELOPE *env) ++{ ++ int rv,level; ++ TOKEN_VALUE *group; ++ CONDITION_S *cend; ++ ++ switch(bc->cndtype){ ++ case Condition: group = copy_parsed_value(COND(bc)->value, rcntxt, env); ++ rv = (*rel_rules_test[COND(bc)->ttype].execute)(bc, group, env, rcntxt); ++ free_parsed_value(&group); ++ if(bc == ec) ++ return rv; ++ if(bc->next == NULL) ++ return rv; ++ else ++ switch(bc->next->cndtype){ ++ case And: return rv ? test_condition_work(bc->next->next, ec, rcntxt, env) : 0; ++ break; ++ case Or : return rv ? 1 : test_condition_work(bc->next->next, ec, rcntxt, env); ++ break; ++ case ParClose: return rv; ++ default : rv = 0; break; /* fail, we should not be here */ ++ } ++ break; ++ ++ case ParOpen: level = ((int *)bc->cndrule)[0]; ++ for(cend = bc; cend->next && (cend->next->cndtype != ParClose ++ || ((int *)cend->next->cndrule)[0] != level); ++ cend = cend->next); ++ rv = test_condition_work(bc->next, cend, rcntxt, env); ++ cend = cend->next; /* here we are at ')' */ ++ if(cend->next == NULL) ++ return rv; ++ else{ ++ switch(cend->next->cndtype){ ++ case And: return rv ? test_condition_work(cend->next->next, ec, rcntxt, env) : 0; ++ break; ++ case Or : return rv ? 1 : test_condition_work(cend->next->next, ec, rcntxt, env); ++ break; ++ default : rv = 0; break; /* fail, we should not be here */ ++ } ++ } ++ break; ++ default: rv = 0; break; /* fail, we should not be here */ ++ } ++ return rv; /* we never ever get here */ ++} ++ ++ ++int ++test_condition(CONDITION_S *condition, int rcntxt, ENVELOPE *env) ++{ ++ return test_condition_work(condition, NULL, rcntxt, env); ++} ++ ++/* 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, *q, c, *rv; ++ ++ if (condition == NULL) ++ return NULL; ++ ++ for(p = condition; *p != '\0' && (*p == ' '|| *p == '\t'); p++); ++ ++ if (*p != '_') return NULL; ++ ++ for (q = p+1; *q != '\0' && *q != '_'; q++); ++ ++ if (*q != '_') return NULL; ++ ++ c = *(q+1); ++ *(q+1) = '\0'; ++ rv = cpystr(p); ++ *(q+1) = c; + 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(COND(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(COND(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)){ -+ memmove(begin_text, begin_text+strlen(tval->testxt), strlen(begin_text) - strlen(tval->testxt) + 1); -+ offset = begin_text - test; ++} ++ ++/* 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(COND(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; + } -+ -+ return do_trim(test, tval->next); ++ fs_give((void **)&test); + } -+ -+ 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 i, offset = 0; -+ size_t len; -+ -+ if (!tval) -+ return test; -+ -+ if((trim_text = expand(test, tval->testxt)) != NULL){ -+ while(begin_text = strstr(test+offset, trim_text)){ -+ memmove(begin_text, begin_text+strlen(trim_text), strlen(begin_text) - strlen(trim_text) + 1); -+ offset = begin_text - 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(COND(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; + } -+ -+ return do_rextrim(test, tval->next); ++ fs_give((void **)&test); + } -+ -+ 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 * -+ do_rexsub (char *test, TOKEN_VALUE *tval) -+ { -+ REXSUB_S *rsv; -+ regmatch_t pmatch; -+ regex_t preg; -+ char *ret_string = cpystr(test ? test : ""); -+ -+ if (!tval) -+ return ret_string; -+ -+ rsv = (REXSUB_S *) tval->voidtxt; -+ -+ if (rsv == NULL /* this should not happen */ -+ || rsv->pattern == NULL /* neither should this */ -+ || rsv->text == NULL /* neither should this */ -+ || regcomp(&preg, rsv->pattern, REG_EXTENDED) != 0) /* but this could */ -+ return ret_string; -+ -+ /* can't use expand() to do the job here. This is because there -+ * is a variable number of hits in rsv->times. */ -+ -+ if(regexec((regex_t *) &preg, test, 1, &pmatch, 0) == 0){ -+ int offset = 0, n; -+ -+ n = rsv->times > 0 ? rsv->times : strlen(test); -+ fs_resize((void **) &ret_string, strlen(test) + n*strlen(rsv->text) + 1); -+ *ret_string = '\0'; -+ -+ do { -+ strncat(ret_string, test + offset, pmatch.rm_so); -+ strcat(ret_string, rsv->text); -+ offset += pmatch.rm_eo; -+ } while (--n && regexec(&preg, test + offset, 1, &pmatch, REG_NOTBOL) == 0); -+ strcat(ret_string, test + offset); ++ 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(COND(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_resize((void **) &ret_string, strlen(ret_string) + 1); -+ regfree(&preg); -+ -+ return ret_string; ++ fs_give((void **)&test); + } -+ -+ char * -+ rexsub (RULEACTION_S *action, int context, ENVELOPE *env) -+ { -+ char *test = NULL, *sub = NULL; -+ RULEACTION_S *taction = action; -+ -+ if ((taction->context & context) && -+ (test = detoken_src(taction->token, context, env, NULL, NULL, NULL))) -+ sub = do_rexsub(test, taction->value); -+ if (test) fs_give((void **) &test); -+ return sub; ++ 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)){ ++ memmove(begin_text, begin_text+strlen(tval->testxt), strlen(begin_text) - strlen(tval->testxt) + 1); ++ 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; + } -+ -+ 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, memory freed by caller */ -+ 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)){ -+ fs_give((void **)&b); -+ 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, char *pattern) -+ { -+ char c, *ret_string = NULL; ++ return NULL; ++} ++ ++char * ++do_rextrim (char *test, TOKEN_VALUE *tval) ++{ ++ char *begin_text, *trim_text; ++ int i, offset = 0; ++ size_t len; ++ ++ if (!tval) ++ return test; ++ ++ if((trim_text = expand(test, tval->testxt)) != NULL){ ++ while(begin_text = strstr(test+offset, trim_text)){ ++ memmove(begin_text, begin_text+strlen(trim_text), strlen(begin_text) - strlen(trim_text) + 1); ++ 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 * ++do_rexsub (char *test, TOKEN_VALUE *tval) ++{ ++ REXSUB_S *rsv; + regmatch_t pmatch; + regex_t preg; -+ -+ if(pattern == NULL || regcomp(&preg, pattern, REG_EXTENDED) != 0) -+ return NULL; -+ -+ if(regexec((regex_t *) &preg, 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; ++ char *ret_string = cpystr(test ? test : ""); ++ ++ if (!tval) ++ return ret_string; ++ ++ rsv = (REXSUB_S *) tval->voidtxt; ++ ++ if (rsv == NULL /* this should not happen */ ++ || rsv->pattern == NULL /* neither should this */ ++ || rsv->text == NULL /* neither should this */ ++ || regcomp(&preg, rsv->pattern, REG_EXTENDED) != 0) /* but this could */ ++ return ret_string; ++ ++ /* can't use expand() to do the job here. This is because there ++ * is a variable number of hits in rsv->times. */ ++ ++ if(regexec((regex_t *) &preg, test, 1, &pmatch, 0) == 0){ ++ int offset = 0, n; ++ ++ n = rsv->times > 0 ? rsv->times : strlen(test); ++ fs_resize((void **) &ret_string, strlen(test) + n*strlen(rsv->text) + 1); ++ *ret_string = '\0'; ++ ++ do { ++ strncat(ret_string, test + offset, pmatch.rm_so); ++ strcat(ret_string, rsv->text); ++ offset += pmatch.rm_eo; ++ } while (--n && regexec(&preg, test + offset, 1, &pmatch, REG_NOTBOL) == 0); ++ strcat(ret_string, test + offset); + } ++ fs_resize((void **) &ret_string, strlen(ret_string) + 1); + regfree(&preg); -+ ++ + 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; ++} ++ ++char * ++rexsub (RULEACTION_S *action, int context, ENVELOPE *env) ++{ ++ char *test = NULL, *sub = NULL; ++ RULEACTION_S *taction = action; ++ ++ if ((taction->context & context) && ++ (test = detoken_src(taction->token, context, env, NULL, NULL, NULL))) ++ sub = do_rexsub(test, taction->value); ++ if (test) fs_give((void **) &test); ++ return sub; ++} ++ ++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, memory freed by caller */ ++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; + } -+ if (we_clear) *we_clear = 0; -+ env = pine_mail_fetchenvelope(idata->stream, idata->rawno); -+ return env; -+ } -Index: alpine-2.23.2/pith/rules.h ++ b[i] = '\0'; ++ if (b && (strlen(b) == strlen(given_string)) && (flag & STRICTLY)){ ++ fs_give((void **)&b); ++ 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, char *pattern) ++{ ++ char c, *ret_string = NULL; ++ regmatch_t pmatch; ++ regex_t preg; ++ ++ if(pattern == NULL || regcomp(&preg, pattern, REG_EXTENDED) != 0) ++ return NULL; ++ ++ if(regexec((regex_t *) &preg, 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; ++ } ++ regfree(&preg); ++ ++ 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; ++} +Index: alpine-2.24/pith/rules.h =================================================================== -*** /dev/null ---- alpine-2.23.2/pith/rules.h -*************** -*** 0 **** ---- 1,154 ---- -+ /* 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" -+ -+ /* 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 FCCF_TOKEN "_FCCFROM_" -+ #define FCCS_TOKEN "_FCCSENDER_" -+ #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; -+ size_t len; -+ unsigned is_assignment:1; /* has structure _TOKEN_ := _FUNCTION_{} */ -+ int return_type; /* the type of data returned by the parser, when it fills voidtxt */ -+ TOKEN_VALUE *(*parse_action_value)(char *); -+ 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 REXSUB_FCN "_REXSUB_" -+ #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 */ -Index: alpine-2.23.2/pith/rulestype.h +--- /dev/null ++++ alpine-2.24/pith/rules.h +@@ -0,0 +1,154 @@ ++/* 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" ++ ++/* 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 FCCF_TOKEN "_FCCFROM_" ++#define FCCS_TOKEN "_FCCSENDER_" ++#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; ++ size_t len; ++ unsigned is_assignment:1; /* has structure _TOKEN_ := _FUNCTION_{} */ ++ int return_type; /* the type of data returned by the parser, when it fills voidtxt */ ++ TOKEN_VALUE *(*parse_action_value)(char *); ++ 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 REXSUB_FCN "_REXSUB_" ++#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 */ +Index: alpine-2.24/pith/rulestype.h =================================================================== -*** /dev/null ---- alpine-2.23.2/pith/rulestype.h -*************** -*** 0 **** ---- 1,94 ---- -+ #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 REXSUB_S struct rexsub_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 -+ -+ #define UNDEFINED_TYPE 0 -+ #define CHAR_TYPE 1 -+ #define REXSUB_TYPE 2 -+ -+ TOKEN_VALUE { -+ char *testxt; -+ void *voidtxt; -+ int voidtype; -+ int codefcn; -+ TOKEN_VALUE *next; -+ }; -+ -+ typedef enum {Equal, Subset, Includes, NotEqual, NotSubset, NotIncludes, EndTypes} TestType; -+ -+ typedef enum {And, Or, ParOpen, ParClose, Condition} CondType; -+ -+ typedef struct condvalue_s { -+ char *tname; /* tname ttype {value} */ -+ TestType ttype; /* type of rule */ -+ TOKEN_VALUE *value; /* value to check against */ -+ } CONDVALUE_S; -+ -+ CONDITION_S { -+ void *cndrule; /* text in condition */ -+ CondType cndtype; /* type of object */ -+ CONDITION_S *next; /* next condition to test */ -+ }; -+ -+ #define COND(C) ((CONDVALUE_S *)((C)->cndrule)) -+ -+ 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)(); -+ }; -+ -+ REXSUB_S { -+ char *pattern; /* pattern to use in the replacement */ -+ char *text; /* text to replace */ -+ int times; /* how many times to repeat the substitution */ -+ }; -+ -+ 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 */ -Index: alpine-2.23.2/pith/save.c +--- /dev/null ++++ alpine-2.24/pith/rulestype.h +@@ -0,0 +1,94 @@ ++#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 REXSUB_S struct rexsub_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 ++ ++#define UNDEFINED_TYPE 0 ++#define CHAR_TYPE 1 ++#define REXSUB_TYPE 2 ++ ++TOKEN_VALUE { ++ char *testxt; ++ void *voidtxt; ++ int voidtype; ++ int codefcn; ++ TOKEN_VALUE *next; ++}; ++ ++typedef enum {Equal, Subset, Includes, NotEqual, NotSubset, NotIncludes, EndTypes} TestType; ++ ++typedef enum {And, Or, ParOpen, ParClose, Condition} CondType; ++ ++typedef struct condvalue_s { ++ char *tname; /* tname ttype {value} */ ++ TestType ttype; /* type of rule */ ++ TOKEN_VALUE *value; /* value to check against */ ++} CONDVALUE_S; ++ ++CONDITION_S { ++ void *cndrule; /* text in condition */ ++ CondType cndtype; /* type of object */ ++ CONDITION_S *next; /* next condition to test */ ++}; ++ ++#define COND(C) ((CONDVALUE_S *)((C)->cndrule)) ++ ++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)(); ++}; ++ ++REXSUB_S { ++ char *pattern; /* pattern to use in the replacement */ ++ char *text; /* text to replace */ ++ int times; /* how many times to repeat the substitution */ ++}; ++ ++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 */ +Index: alpine-2.24/pith/save.c =================================================================== -*** alpine-2.23.2.orig/pith/save.c ---- alpine-2.23.2/pith/save.c -*************** save(struct pine *state, MAILSTREAM *str -*** 955,961 **** - *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) ---- 955,961 ---- - *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) -Index: alpine-2.23.2/pith/send.c +--- alpine-2.24.orig/pith/save.c ++++ alpine-2.24/pith/save.c +@@ -955,7 +955,7 @@ save(struct pine *state, MAILSTREAM *str + *date = '\0'; + + rv = save_fetch_append(stream, mn_m2raw(msgmap, i), +- NULL, save_stream, save_folder, context, ++ NULL, save_stream, folder, context, + mc ? mc->rfc822_size : 0L, flags, date, so); + + if(flags) +Index: alpine-2.24/pith/send.c =================================================================== -*** alpine-2.23.2.orig/pith/send.c ---- alpine-2.23.2/pith/send.c -*************** static char rcsid[] = "$Id: send.c 1204 -*** 44,49 **** ---- 44,50 ---- - #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" -*************** call_mailer(METAENV *header, struct mail -*** 1695,1703 **** - 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; ---- 1696,1704 ---- - 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; -*************** call_mailer(METAENV *header, struct mail -*** 1852,1871 **** - * 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]; ---- 1853,1901 ---- - * 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]; -Index: alpine-2.23.2/pith/sort.c +--- alpine-2.24.orig/pith/send.c ++++ alpine-2.24/pith/send.c +@@ -44,6 +44,7 @@ static char rcsid[] = "$Id: send.c 1204 + #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" +@@ -1695,9 +1696,9 @@ call_mailer(METAENV *header, struct mail + char error_buf[200], *error_mess = NULL, *postcmd; + ADDRESS *a; + ENVELOPE *fake_env = NULL; +- int addr_error_count, we_cancel = 0; ++ int addr_error_count, we_cancel = 0, choice, num_rules = 0, added_rules = -1; + long smtp_opts = 0L; +- char *verbose_file = NULL; ++ char *verbose_file = NULL, **smtp_list; + BODY *bp = NULL; + PINEFIELD *pf; + BODY *origBody = body; +@@ -1852,20 +1853,49 @@ call_mailer(METAENV *header, struct mail + * 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(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); ++ 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; + } +- 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); ++ 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]; +Index: alpine-2.24/pith/sort.c =================================================================== -*** alpine-2.23.2.orig/pith/sort.c ---- alpine-2.23.2/pith/sort.c -*************** static char rcsid[] = "$Id: sort.c 1142 -*** 30,36 **** - #include "../pith/signal.h" - #include "../pith/busy.h" - #include "../pith/icache.h" -! - - /* - * global place to store mail_sort and mail_thread results ---- 30,36 ---- - #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 -*************** pine_compare_scores(const qsort_t *a, co -*** 686,691 **** ---- 686,726 ---- - : ((mdiff = *mess_a - *mess_b) ? ((mdiff > 0) ? 1 : -1) : 0)); - } - -+ 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; -+ } - - void - reset_sort_order(unsigned int flags) -*************** reset_sort_order(unsigned int flags) -*** 695,701 **** - PAT_S *pat; - SortOrder the_sort_order; - int sort_is_rev; -! - /* set default order */ - the_sort_order = ps_global->def_sort; - sort_is_rev = the_sort_order == SortThread ---- 730,750 ---- - 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 -*************** reset_sort_order(unsigned int flags) -*** 721,726 **** ---- 770,776 ---- - - 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); -Index: alpine-2.23.2/pith/sort.h +--- alpine-2.24.orig/pith/sort.c ++++ alpine-2.24/pith/sort.c +@@ -30,7 +30,7 @@ static char rcsid[] = "$Id: sort.c 1142 + #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 +@@ -695,7 +695,21 @@ reset_sort_order(unsigned int flags) + 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 +@@ -718,6 +732,7 @@ reset_sort_order(unsigned int flags) + : pat->action->revsort; + } + } ++ } + + if(the_sort_order == SortThread && !(flags & SRT_MAN)) + ps_global->thread_cur_sort = ps_global->thread_def_sort; +@@ -725,3 +740,39 @@ reset_sort_order(unsigned int flags) + 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; ++} +Index: alpine-2.24/pith/sort.h =================================================================== -*** alpine-2.23.2.orig/pith/sort.h ---- alpine-2.23.2/pith/sort.h -*************** char *sort_name(SortOrder); -*** 45,50 **** - void sort_folder(MAILSTREAM *, MSGNO_S *, SortOrder, int, unsigned, int); - int decode_sort(char *, SortOrder *, int *, int); - void reset_sort_order(unsigned); -! - - #endif /* PITH_SORT_INCLUDED */ ---- 45,50 ---- - 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 */ -Index: alpine-2.23.2/pith/state.c +--- alpine-2.24.orig/pith/sort.h ++++ alpine-2.24/pith/sort.h +@@ -45,6 +45,6 @@ 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 */ +Index: alpine-2.24/pith/state.c =================================================================== -*** alpine-2.23.2.orig/pith/state.c ---- alpine-2.23.2/pith/state.c -*************** static char rcsid[] = "$Id: state.c 1074 -*** 35,40 **** ---- 35,41 ---- - #include "../pith/smime.h" - #include "../pith/ical.h" - #include "../pith/bldaddr.h" -+ #include "../pith/rules.h" - - /* - * Globals referenced throughout pine... -*************** free_pine_struct(struct pine **pps) -*** 255,260 **** ---- 256,264 ---- - 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); -Index: alpine-2.23.2/pith/state.h +--- alpine-2.24.orig/pith/state.c ++++ alpine-2.24/pith/state.c +@@ -35,6 +35,7 @@ static char rcsid[] = "$Id: state.c 1074 + #include "../pith/smime.h" + #include "../pith/ical.h" + #include "../pith/bldaddr.h" ++#include "../pith/rules.h" + + /* + * Globals referenced throughout pine... +@@ -258,6 +259,9 @@ free_pine_struct(struct pine **pps) + if((*pps)->id) + free_id(&(*pps)->id); + ++ if((*pps)->rule_list) ++ free_parsed_rule_list(&(*pps)->rule_list); ++ + free_vars(*pps); + + fs_give((void **) pps); +Index: alpine-2.24/pith/state.h =================================================================== -*** alpine-2.23.2.orig/pith/state.h ---- alpine-2.23.2/pith/state.h -*************** -*** 33,39 **** - #include "../pith/stream.h" - #include "../pith/color.h" - #include "../pith/user.h" -! - - /* - * Printing control structure ---- 33,39 ---- - #include "../pith/stream.h" - #include "../pith/color.h" - #include "../pith/user.h" -! #include "../pith/rulestype.h" - - /* - * Printing control structure -*************** struct pine { -*** 112,117 **** ---- 112,122 ---- - MAILSTREAM *mail_stream; /* ptr to current folder stream */ - MSGNO_S *msgmap; /* ptr to current message map */ - -+ char screen_name[16]; /* 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]; -*************** struct pine { -*** 367,372 **** ---- 372,378 ---- - 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; -*************** struct pine { -*** 377,382 **** ---- 383,391 ---- - char last_error[500]; - INIT_ERR_S *init_errs; - -+ PRULELIST_S *rule_list; -+ char *pressed_key; -+ - PRINT_S *print; - - #ifdef SMIME -Index: alpine-2.23.2/pith/string.c +--- alpine-2.24.orig/pith/state.h ++++ alpine-2.24/pith/state.h +@@ -33,7 +33,7 @@ + #include "../pith/stream.h" + #include "../pith/color.h" + #include "../pith/user.h" +- ++#include "../pith/rulestype.h" + + /* + * Printing control structure +@@ -112,6 +112,11 @@ struct pine { + MAILSTREAM *mail_stream; /* ptr to current folder stream */ + MSGNO_S *msgmap; /* ptr to current message map */ + ++ char screen_name[16]; /* 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]; +@@ -368,6 +373,7 @@ struct pine { + 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; +@@ -378,6 +384,9 @@ struct pine { + char last_error[500]; + INIT_ERR_S *init_errs; + ++ PRULELIST_S *rule_list; ++ char *pressed_key; ++ + PRINT_S *print; + + #ifdef SMIME +Index: alpine-2.24/pith/string.c =================================================================== -*** alpine-2.23.2.orig/pith/string.c ---- alpine-2.23.2/pith/string.c -*************** static char rcsid[] = "$Id: string.c 910 -*** 20,25 **** ---- 20,26 ---- - 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 -*************** rplstr(char *os, size_t oslen, int dl, c -*** 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'; -+ } - - - /*---------------------------------------------------------------------- -*************** convert_decimal_to_alpha (char *rn, size -*** 2997,2999 **** ---- 3023,3057 ---- - if(i < len) rn[i] = '\0'; - rn[len-1] = '\0'; - } -+ -+ -+ 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++; -+ } -+ } -+ -Index: alpine-2.23.2/pith/string.h +--- alpine-2.24.orig/pith/string.c ++++ alpine-2.24/pith/string.c +@@ -20,6 +20,7 @@ static char rcsid[] = "$Id: string.c 910 + 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,6 +132,31 @@ rplstr(char *os, size_t oslen, int dl, c + 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'; ++} + + + /*---------------------------------------------------------------------- +@@ -2997,3 +3023,35 @@ convert_decimal_to_alpha (char *rn, size + if(i < len) rn[i] = '\0'; + rn[len-1] = '\0'; + } ++ ++ ++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++; ++ } ++} ++ +Index: alpine-2.24/pith/string.h =================================================================== -*** alpine-2.23.2.orig/pith/string.h ---- alpine-2.23.2/pith/string.h -*************** struct date { -*** 87,92 **** ---- 87,93 ---- - - /* exported prototypes */ - 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(c -*** 94,99 **** ---- 95,101 ---- - void replace_tabs_by_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 *); +--- alpine-2.24.orig/pith/string.h ++++ alpine-2.24/pith/string.h +@@ -87,6 +87,7 @@ struct date { + + /* exported prototypes */ + char *rplstr(char *, size_t, int, char *); ++void collspaces(char *); + void sqzspaces(char *); + void sqznewlines(char *); + void removing_leading_white_space(char *); +@@ -94,6 +95,7 @@ void removing_trailing_white_space(c + void replace_tabs_by_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 *);