From 40c0502f90bc089a61fc11d23fc9c53f49e042a35ac21bafde5e1e8cabc2b9d9 Mon Sep 17 00:00:00 2001 From: OBS User buildservice-autocommit Date: Tue, 12 May 2020 20:34:54 +0000 Subject: [PATCH] Updating link to change in openSUSE:Factory/alpine revision 46.0 OBS-URL: https://build.opensuse.org/package/show/server:mail/alpine?expand=0&rev=29d0789f4220d751d698099644a6c9a8 --- UPDATING.txt | 12 + alpine-2.21.tar.xz | 3 - alpine-2.22.tar.xz | 3 + alpine-pinepw.patch | 20 - alpine-timestamp.patch | 35 +- alpine.changes | 28 + alpine.spec | 25 +- chappa-WrtAcc.patch | 40 +- chappa-WrtAcc.txt | 9 + chappa-colortext.patch | 142 +- chappa-colortext.txt | 7 + chappa-fancy.patch | 439 +- chappa-fancy.txt | 42 + chappa-fillpara.patch | 323 +- chappa-fillpara.txt | 10 + chappa-fromheader.patch | 68 +- chappa-fromheader.txt | 5 + chappa-insertpat.patch | 12 +- chappa-insertpat.txt | 7 + chappa-maildir.patch | 605 +- chappa-maildir.txt | 11 + chappa-rules.patch | 12087 ++++++++++++------------ chappa-rules.txt | 16 + pico-fix-spurious-undef-warnings.diff | 115 +- 24 files changed, 6921 insertions(+), 7143 deletions(-) create mode 100644 UPDATING.txt delete mode 100644 alpine-2.21.tar.xz create mode 100644 alpine-2.22.tar.xz delete mode 100644 alpine-pinepw.patch create mode 100644 chappa-WrtAcc.txt create mode 100644 chappa-colortext.txt create mode 100644 chappa-fancy.txt create mode 100644 chappa-fillpara.txt create mode 100644 chappa-fromheader.txt create mode 100644 chappa-insertpat.txt create mode 100644 chappa-maildir.txt create mode 100644 chappa-rules.txt diff --git a/UPDATING.txt b/UPDATING.txt new file mode 100644 index 0000000..d207ad8 --- /dev/null +++ b/UPDATING.txt @@ -0,0 +1,12 @@ +Update procedure: + +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. + + 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; + done + +These do not necessarily apply cleanly, so they also need to be +quilt-refreshed as needed. diff --git a/alpine-2.21.tar.xz b/alpine-2.21.tar.xz deleted file mode 100644 index 098ecee..0000000 --- a/alpine-2.21.tar.xz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6030b6881b8168546756ab3a5e43628d8d564539b0476578e287775573a77438 -size 4720856 diff --git a/alpine-2.22.tar.xz b/alpine-2.22.tar.xz new file mode 100644 index 0000000..45f6051 --- /dev/null +++ b/alpine-2.22.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:849567c1b6f71fde3aaa1c97cf0577b12a525d9e22c0ea47797c4bf1cd2bbfdb +size 6336604 diff --git a/alpine-pinepw.patch b/alpine-pinepw.patch deleted file mode 100644 index 2c15d01..0000000 --- a/alpine-pinepw.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -rc alpine-2.21/alpine/imap.c alpine-2.21.pwdfilebug/alpine/imap.c -*** alpine-2.21/alpine/imap.c 2017-02-05 17:06:22.523218671 -0700 ---- alpine-2.21.pwdfilebug/alpine/imap.c 2019-04-27 16:48:22.433116057 -0600 -*************** -*** 2636,2642 **** - if(ps_global->pwdcert == NULL){ - q_status_message(SM_ORDER, 3, 3, "Attempting to encrypt password file"); - i = setup_pwdcert(&ps_global->pwdcert); -! if(i == 0 && ps_global->pwdcert == NULL) - ps_global->pwdcert = (void *) ALPINE_self_signed_certificate(NULL, 0, ps_global->pwdcertdir, MASTERNAME); - } - if(ps_global->pwdcert == NULL){ /* we tried but failed */ ---- 2636,2642 ---- - if(ps_global->pwdcert == NULL){ - q_status_message(SM_ORDER, 3, 3, "Attempting to encrypt password file"); - i = setup_pwdcert(&ps_global->pwdcert); -! if((i == 0 || i == -5) && ps_global->pwdcert == NULL) - ps_global->pwdcert = (void *) ALPINE_self_signed_certificate(NULL, 0, ps_global->pwdcertdir, MASTERNAME); - } - if(ps_global->pwdcert == NULL){ /* we tried but failed */ diff --git a/alpine-timestamp.patch b/alpine-timestamp.patch index 98c3756..1f58744 100644 --- a/alpine-timestamp.patch +++ b/alpine-timestamp.patch @@ -1,27 +1,16 @@ -Index: alpine-2.20/alpine/Makefile.am +--- + alpine/Makefile.am | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: alpine-2.22/alpine/Makefile.am =================================================================== ---- alpine-2.20.orig/alpine/Makefile.am -+++ alpine-2.20/alpine/Makefile.am -@@ -48,5 +48,5 @@ AM_LDFLAGS = `cat @top_srcdir@/c-client/ +--- alpine-2.22.orig/alpine/Makefile.am ++++ alpine-2.22/alpine/Makefile.am +@@ -50,5 +50,5 @@ AM_LDFLAGS = `cat @top_srcdir@/c-client/ CLEANFILES = date.c date.c: -- echo "char datestamp[]="\"`date`\"";" > date.c -- echo "char hoststamp[]="\"`hostname`\"";" >> date.c -+ echo 'char datestamp[]="today";' > date.c -+ echo 'char hoststamp[]="sand";' >> date.c -Index: alpine-2.20/alpine/Makefile.in -=================================================================== ---- alpine-2.20.orig/alpine/Makefile.in -+++ alpine-2.20/alpine/Makefile.in -@@ -888,8 +888,8 @@ uninstall-am: uninstall-binPROGRAMS - - - date.c: -- echo "char datestamp[]="\"`date`\"";" > date.c -- echo "char hoststamp[]="\"`hostname`\"";" >> date.c -+ echo 'char datestamp[]="today";' > date.c -+ echo 'char hoststamp[]="sand";' >> date.c - - # Tell versions [3.59,3.63) of GNU make to not export all variables. - # Otherwise a system limit (for SysV at least) may be exceeded. +- echo "char datestamp[]="\"$(ALPINE_DATESTAMP)\"";" > date.c +- echo "char hoststamp[]="\"$(ALPINE_HOSTSTAMP)\"";" >> date.c ++ echo "char datestamp[]="\"today\"";" > date.c ++ echo "char hoststamp[]="\"sand\"";" >> date.c diff --git a/alpine.changes b/alpine.changes index 912b26b..c1015be 100644 --- a/alpine.changes +++ b/alpine.changes @@ -1,3 +1,31 @@ +------------------------------------------------------------------- +Thu May 7 20:32:03 UTC 2020 - Jan Engelhardt + +- Update to release 2.22 + * Support for XOAUTH2 authentication method in Gmail. + * NTLM authentication support with the ntlm library. + * Added the "/tls1_3" flag for servers that support it. + * Add the "g" option to the select command that works in IMAP + servers that implement the X-GM-EXT-1 capability (such as the + one offered by Gmail). + * Added "/auth=XYZ" to the way to define a server. This allows + users to select the method to authenticate to an IMAP, SMTP + or POP3 server. Examples are /auth=plain, or /auth=gssapi, + etc. + * When a message is of type multipart/mixed, and its first part + is multipart/signed, Alpine will include the text of the + original message in a reply message, instead of including a + multipart attachment. + * Added backward search in the index screen. + * pico: Add -dict option to Pico, which allows users to choose a + dictionary when spelling. +- Drop /usr/bin/mailutil, it is not built by default anymore. +- Remove alpine-pinepw.patch (merged upstream) +- Add description files for patches 600-616. These live in a + separate file because (a) upstream does not offer the description + as part of the patch file, (b) redownloading the patches would + nuke any added description due to . + ------------------------------------------------------------------- Mon Aug 26 08:33:31 UTC 2019 - Jan Engelhardt diff --git a/alpine.spec b/alpine.spec index bb859f7..15c76c4 100644 --- a/alpine.spec +++ b/alpine.spec @@ -1,7 +1,7 @@ # # spec file for package alpine # -# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2020 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -22,7 +22,7 @@ Name: alpine Summary: Mail User Agent License: Apache-2.0 Group: Productivity/Networking/Email/Clients -Version: 2.21 +Version: 2.22 Release: 0 URL: http://alpine.x10host.com/alpine/ @@ -31,12 +31,12 @@ URL: http://alpine.x10host.com/alpine/ Source: %name-%version.tar.xz Source1: %name.png Source2: %name.desktop +Source9: UPDATING.txt Patch2: make-use-of-strncat-safer.diff Patch3: operation-may-be-undefined-warning.diff Patch4: fix-implicit.patch Patch5: alpine-gcc44.diff Patch6: alpine-timestamp.patch -Patch7: alpine-pinepw.patch Patch10: pico-fix-spurious-undef-warnings.diff Patch20: pine-expression-warnings.diff Patch60: signal-and-panic-improvements.diff @@ -45,13 +45,21 @@ Patch61: return-values.diff # Eduardo Chappa's patches. # http://patches.freeiz.com/alpine/ # +Source600: chappa-colortext.txt Patch600: chappa-colortext.patch +Source601: chappa-fancy.txt Patch601: chappa-fancy.patch +Source603: chappa-insertpat.txt Patch603: chappa-insertpat.patch +Source604: chappa-maildir.txt Patch604: chappa-maildir.patch +Source605: chappa-WrtAcc.txt Patch605: chappa-WrtAcc.patch +Source614: chappa-fillpara.txt Patch614: chappa-fillpara.patch +Source615: chappa-fromheader.txt Patch615: chappa-fromheader.patch +Source616: chappa-rules.txt Patch616: chappa-rules.patch BuildRequires: autoconf >= 2.69 BuildRequires: krb5-devel @@ -132,7 +140,6 @@ fi %patch4 -p1 %patch5 -p1 %patch6 -p1 -%patch7 -p1 %patch10 -p1 %patch20 -p1 %patch60 -p1 @@ -196,13 +203,11 @@ perl -i -pe 's{(define SYSTYPE) "LNX"}{$1 "'"$tag"'"}g' include/config.h make %{?_smp_mflags} EXTRACFLAGS="$CFLAGS" EXTRALDFLAGS="$EXTRALDFLAGS" %install -make install DESTDIR=%buildroot +%make_install # # When called as alpinef, alpine uses function keys instead of Control keys: # ln %{buildroot}/%{_bindir}/alpine %{buildroot}/%{_bindir}/alpinef -install -m755 imap/mailutil/mailutil %{buildroot}/%{_bindir} -install -m644 imap/src/mailutil/mailutil.1 %{buildroot}/%{_mandir}/man1/ install -D -m644 %{SOURCE1} %{buildroot}/%{_datadir}/pixmaps/%name.png install -D -m644 %{SOURCE2} %{buildroot}/%{_datadir}/applications/%name.desktop %suse_update_desktop_file %name @@ -213,8 +218,8 @@ install -m755 pico/{pico,pilot} %{buildroot}/%{_bindir} install -m644 doc/man1/{pico.1,pilot.1} %{buildroot}/%{_mandir}/man1/ %check -#since where are no logs in the package at the moment, there are no checks, -#but the warning logs can be recreated for regresstion tracking in warnings: +#since there are no logs in the package at the moment, there are no checks, +#but the warning logs can be recreated for regression tracking in warnings: if [ -s %{_sourcedir}/compile-warnings-%{suse_version}-%{_arch}.log ]; then grep -e '^[a-z0-9_]*.[cho]:' -e 'Entering directory' make.log | sed "s/^make\[.\]: //;/Entering directory/s/[\`']//g;" \ @@ -269,13 +274,11 @@ fi %doc %{_mandir}/man1/alpine.* %doc %{_mandir}/man1/rpdump.* %doc %{_mandir}/man1/rpload.* -%doc %{_mandir}/man1/mailutil.* %doc README NOTICE LICENSE %doc doc/mailcap.unx doc/mime.types doc/tech-notes/tech-notes.txt doc/tech-notes/*.html %{_bindir}/*pine %{_bindir}/alpinef %{_bindir}/rp* -%{_bindir}/mailutil %{_datadir}/applications/%name.desktop %{_datadir}/pixmaps/%name.png diff --git a/chappa-WrtAcc.patch b/chappa-WrtAcc.patch index 3eda2b8..c60cd36 100644 --- a/chappa-WrtAcc.patch +++ b/chappa-WrtAcc.patch @@ -1,6 +1,6 @@ -diff -rc alpine-2.21/pico/basic.c alpine-2.21.WrtAcc/pico/basic.c -*** alpine-2.21/pico/basic.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.WrtAcc/pico/basic.c Sun Feb 5 16:15:24 2017 +diff -rc alpine-2.22/pico/basic.c alpine-2.22.WrtAcc/pico/basic.c +*** alpine-2.22/pico/basic.c 2020-01-19 01:32:18.272513938 -0700 +--- alpine-2.22.WrtAcc/pico/basic.c 2020-01-19 01:34:53.223471368 -0700 *************** *** 342,347 **** --- 342,530 ---- @@ -193,9 +193,9 @@ diff -rc alpine-2.21/pico/basic.c alpine-2.21.WrtAcc/pico/basic.c /* * go forword to the end of the current paragraph -diff -rc alpine-2.21/pico/composer.c alpine-2.21.WrtAcc/pico/composer.c -*** alpine-2.21/pico/composer.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.WrtAcc/pico/composer.c Sun Feb 5 16:15:24 2017 +diff -rc alpine-2.22/pico/composer.c alpine-2.22.WrtAcc/pico/composer.c +*** alpine-2.22/pico/composer.c 2020-01-19 01:32:18.262514139 -0700 +--- alpine-2.22.WrtAcc/pico/composer.c 2020-01-19 01:34:53.224471360 -0700 *************** *** 2015,2021 **** tbufp = &strng[ods.p_len]; @@ -229,9 +229,9 @@ diff -rc alpine-2.21/pico/composer.c alpine-2.21.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.21/pico/display.c alpine-2.21.WrtAcc/pico/display.c -*** alpine-2.21/pico/display.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.WrtAcc/pico/display.c Sun Feb 5 16:15:24 2017 +diff -rc alpine-2.22/pico/display.c alpine-2.22.WrtAcc/pico/display.c +*** alpine-2.22/pico/display.c 2020-01-19 01:32:18.428510798 -0700 +--- alpine-2.22.WrtAcc/pico/display.c 2020-01-19 01:34:53.225471353 -0700 *************** *** 2196,2201 **** --- 2196,2206 ---- @@ -263,9 +263,9 @@ diff -rc alpine-2.21/pico/display.c alpine-2.21.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.21/pico/ebind.h alpine-2.21.WrtAcc/pico/ebind.h -*** alpine-2.21/pico/ebind.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.WrtAcc/pico/ebind.h Sun Feb 5 16:15:24 2017 +diff -rc alpine-2.22/pico/ebind.h alpine-2.22.WrtAcc/pico/ebind.h +*** alpine-2.22/pico/ebind.h 2020-01-19 01:32:18.369511986 -0700 +--- alpine-2.22.WrtAcc/pico/ebind.h 2020-01-19 01:34:53.226471345 -0700 *************** *** 61,67 **** #ifdef MOUSE @@ -319,9 +319,9 @@ diff -rc alpine-2.21/pico/ebind.h alpine-2.21.WrtAcc/pico/ebind.h #endif #endif {CTRL|'A', gotobol}, -diff -rc alpine-2.21/pico/efunc.h alpine-2.21.WrtAcc/pico/efunc.h -*** alpine-2.21/pico/efunc.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.WrtAcc/pico/efunc.h Sun Feb 5 16:15:24 2017 +diff -rc alpine-2.22/pico/efunc.h alpine-2.22.WrtAcc/pico/efunc.h +*** alpine-2.22/pico/efunc.h 2020-01-19 01:32:18.308513213 -0700 +--- alpine-2.22.WrtAcc/pico/efunc.h 2020-01-19 01:34:53.226471345 -0700 *************** *** 54,59 **** --- 54,62 ---- @@ -334,12 +334,12 @@ diff -rc alpine-2.21/pico/efunc.h alpine-2.21.WrtAcc/pico/efunc.h extern int forwpage(int, int); extern int backpage(int, int); extern int scrollupline(int, int); -diff -rc alpine-2.21/pico/main.c alpine-2.21.WrtAcc/pico/main.c -*** alpine-2.21/pico/main.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.WrtAcc/pico/main.c Sun Feb 5 16:15:24 2017 +diff -rc alpine-2.22/pico/main.c alpine-2.22.WrtAcc/pico/main.c +*** alpine-2.22/pico/main.c 2020-01-19 01:32:18.322512932 -0700 +--- alpine-2.22.WrtAcc/pico/main.c 2020-01-19 01:34:53.226471345 -0700 *************** -*** 451,456 **** ---- 451,462 ---- +*** 458,463 **** +--- 458,469 ---- emlwrite(_("You may possibly have new mail."), NULL); } diff --git a/chappa-WrtAcc.txt b/chappa-WrtAcc.txt new file mode 100644 index 0000000..90a46be --- /dev/null +++ b/chappa-WrtAcc.txt @@ -0,0 +1,9 @@ +From: http://alpine.x10host.com/alpine/info/WrtAcc.html +Upstream: constitutes upstream source, delivered in non-tarball form + +This patch allows you to write many kind of accents in Alpine and pico. You can +write characters like á. Each character is introduced using a consistent +combination of keystrokes. The first keystroke is always "^\". Then you write +the kind of accent you want to write and finally the letter over which you want +the accent to be written, so á would be written ^\'a. Other special characters +such as ß, ø and £ can be input too using special combinations described below. diff --git a/chappa-colortext.patch b/chappa-colortext.patch index 3e4adec..a48871d 100644 --- a/chappa-colortext.patch +++ b/chappa-colortext.patch @@ -1,9 +1,9 @@ -diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.colortext/alpine/confscroll.c -*** alpine-2.21/alpine/confscroll.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.colortext/alpine/confscroll.c Sun Feb 5 16:15:26 2017 +diff -rc alpine-2.22/alpine/confscroll.c alpine-2.22.colortext/alpine/confscroll.c +*** alpine-2.22/alpine/confscroll.c 2020-01-19 01:32:20.190475483 -0700 +--- alpine-2.22.colortext/alpine/confscroll.c 2020-01-19 01:34:56.906444203 -0700 *************** -*** 5222,5227 **** ---- 5222,5230 ---- +*** 5228,5233 **** +--- 5228,5236 ---- clear_index_cache(ps->mail_stream, 0); } @@ -13,12 +13,12 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.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.21/pith/conf.c alpine-2.21.colortext/pith/conf.c -*** alpine-2.21/pith/conf.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.colortext/pith/conf.c Sun Feb 5 16:15:26 2017 +diff -rc alpine-2.22/pith/conf.c alpine-2.22.colortext/pith/conf.c +*** alpine-2.22/pith/conf.c 2020-01-19 01:32:18.678505766 -0700 +--- alpine-2.22.colortext/pith/conf.c 2020-01-19 01:34:56.908444189 -0700 *************** -*** 232,237 **** ---- 232,239 ---- +*** 231,236 **** +--- 231,238 ---- CONF_TXT_T cf_text_fillcol[] = "Specifies the column of the screen where the composer should wrap."; @@ -28,8 +28,8 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.colortext/pith/conf.c CONF_TXT_T cf_text_quotereplstr[] = "Specifies the string to replace quotes with when viewing a message."; *************** -*** 572,577 **** ---- 574,581 ---- +*** 577,582 **** +--- 579,586 ---- #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.21/pith/conf.c alpine-2.21.colortext/pith/conf.c NULL, cf_text_replystr}, {"reply-leadin", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, *************** -*** 833,838 **** ---- 837,844 ---- +*** 844,849 **** +--- 848,855 ---- {"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.21/pith/conf.c alpine-2.21.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}, *************** -*** 2021,2026 **** ---- 2027,2034 ---- +*** 2035,2040 **** +--- 2041,2048 ---- 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.21/pith/conf.c alpine-2.21.colortext/pith/conf.c set_current_val(&vars[V_HISTORY], TRUE, TRUE); set_current_val(&vars[V_SMTP_SERVER], TRUE, TRUE); *************** -*** 6567,6572 **** ---- 6575,6581 ---- +*** 6599,6604 **** +--- 6607,6613 ---- 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.21/pith/conf.c alpine-2.21.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); *************** -*** 7755,7760 **** ---- 7764,7771 ---- +*** 7787,7792 **** +--- 7796,7803 ---- return(h_config_scroll_margin); case V_DEADLETS : return(h_config_deadlets); @@ -82,8 +82,8 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.colortext/pith/conf.c return(h_config_composer_wrap_column); case V_TCPOPENTIMEO : *************** -*** 7922,7927 **** ---- 7933,7941 ---- +*** 7956,7961 **** +--- 7967,7975 ---- case V_SIGNATURE_FORE_COLOR : case V_SIGNATURE_BACK_COLOR : return(h_config_signature_color); @@ -93,9 +93,9 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.colortext/pith/conf.c case V_PROMPT_FORE_COLOR : case V_PROMPT_BACK_COLOR : return(h_config_prompt_color); -diff -rc alpine-2.21/pith/conf.h alpine-2.21.colortext/pith/conf.h -*** alpine-2.21/pith/conf.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.colortext/pith/conf.h Sun Feb 5 16:15:26 2017 +diff -rc alpine-2.22/pith/conf.h alpine-2.22.colortext/pith/conf.h +*** alpine-2.22/pith/conf.h 2020-01-19 01:32:19.489489496 -0700 +--- alpine-2.22.colortext/pith/conf.h 2020-01-19 01:34:56.909444181 -0700 *************** *** 165,170 **** --- 165,172 ---- @@ -108,8 +108,8 @@ diff -rc alpine-2.21/pith/conf.h alpine-2.21.colortext/pith/conf.h #define GLO_FILLCOL vars[V_FILLCOL].global_val.p #define VAR_DEADLETS vars[V_DEADLETS].current_val.p *************** -*** 463,468 **** ---- 465,472 ---- +*** 466,471 **** +--- 468,475 ---- #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.21/pith/conf.h alpine-2.21.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.21/pith/conftype.h alpine-2.21.colortext/pith/conftype.h -*** alpine-2.21/pith/conftype.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.colortext/pith/conftype.h Sun Feb 5 16:15:26 2017 +diff -rc alpine-2.22/pith/conftype.h alpine-2.22.colortext/pith/conftype.h +*** alpine-2.22/pith/conftype.h 2020-01-19 01:32:18.702505283 -0700 +--- alpine-2.22.colortext/pith/conftype.h 2020-01-19 01:34:56.910444174 -0700 *************** *** 83,88 **** --- 83,89 ---- @@ -132,8 +132,8 @@ diff -rc alpine-2.21/pith/conftype.h alpine-2.21.colortext/pith/conftype.h , V_REPLY_INTRO , V_QUOTE_REPLACE_STRING *************** -*** 235,240 **** ---- 236,243 ---- +*** 238,243 **** +--- 239,246 ---- , V_INCUNSEEN_BACK_COLOR , V_SIGNATURE_FORE_COLOR , V_SIGNATURE_BACK_COLOR @@ -142,12 +142,12 @@ diff -rc alpine-2.21/pith/conftype.h alpine-2.21.colortext/pith/conftype.h , V_PROMPT_FORE_COLOR , V_PROMPT_BACK_COLOR , V_HEADER_GENERAL_FORE_COLOR -diff -rc alpine-2.21/pith/mailview.c alpine-2.21.colortext/pith/mailview.c -*** alpine-2.21/pith/mailview.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.colortext/pith/mailview.c Sun Feb 5 16:15:26 2017 +diff -rc alpine-2.22/pith/mailview.c alpine-2.22.colortext/pith/mailview.c +*** alpine-2.22/pith/mailview.c 2020-01-19 01:32:18.803503250 -0700 +--- alpine-2.22.colortext/pith/mailview.c 2020-01-19 01:34:56.911444167 -0700 *************** -*** 282,287 **** ---- 282,295 ---- +*** 638,643 **** +--- 638,651 ---- if((flgs & FM_DISPLAY) && !(flgs & FM_NOCOLOR) && pico_usingcolor() @@ -163,8 +163,8 @@ diff -rc alpine-2.21/pith/mailview.c alpine-2.21.colortext/pith/mailview.c && ps_global->VAR_SIGNATURE_BACK_COLOR){ gf_link_filter(gf_line_test, gf_line_test_opt(color_signature, &is_in_sig)); *************** -*** 2503,2508 **** ---- 2511,2700 ---- +*** 2870,2875 **** +--- 2878,3067 ---- return(color_pair); } @@ -355,9 +355,9 @@ diff -rc alpine-2.21/pith/mailview.c alpine-2.21.colortext/pith/mailview.c /* * The argument fieldname is something like "Subject:..." or "Subject". -diff -rc alpine-2.21/pith/mailview.h alpine-2.21.colortext/pith/mailview.h -*** alpine-2.21/pith/mailview.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.colortext/pith/mailview.h Sun Feb 5 16:15:26 2017 +diff -rc alpine-2.22/pith/mailview.h alpine-2.22.colortext/pith/mailview.h +*** alpine-2.22/pith/mailview.h 2020-01-19 01:32:19.614486993 -0700 +--- alpine-2.22.colortext/pith/mailview.h 2020-01-19 01:34:56.911444167 -0700 *************** *** 30,35 **** --- 30,41 ---- @@ -374,8 +374,8 @@ diff -rc alpine-2.21/pith/mailview.h alpine-2.21.colortext/pith/mailview.h #define FM_DISPLAY 0x0001 /* result is headed for display */ #define FM_NEW_MESS 0x0002 /* a new message so zero out attachment descrip */ *************** -*** 126,131 **** ---- 132,146 ---- +*** 130,135 **** +--- 136,150 ---- int url_hilite(long, char *, LT_INS_S **, void *); int handle_start_color(char *, size_t, int *, int); int handle_end_color(char *, size_t, int *); @@ -391,12 +391,12 @@ diff -rc alpine-2.21/pith/mailview.h alpine-2.21.colortext/pith/mailview.h /* * BUG: BELOW IS UNIX/PC ONLY since config'd browser means nothing to webpine -diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.colortext/pith/pine.hlp -*** alpine-2.21/pith/pine.hlp Sun Feb 5 16:02:36 2017 ---- alpine-2.21.colortext/pith/pine.hlp Sun Feb 5 16:15:26 2017 +diff -rc alpine-2.22/pith/pine.hlp alpine-2.22.colortext/pith/pine.hlp +*** alpine-2.22/pith/pine.hlp 2020-01-19 01:32:19.035498584 -0700 +--- alpine-2.22.colortext/pith/pine.hlp 2020-01-19 01:34:56.924444072 -0700 *************** -*** 4227,4232 **** ---- 4227,4233 ---- +*** 4601,4606 **** +--- 4601,4607 ----
  • OPTION:
  • OPTION:
  • OPTION: @@ -405,8 +405,8 @@ diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.colortext/pith/pine.hlp
  • OPTION: Print-Font-Char-Set
  • OPTION: Print-Font-Name *************** -*** 4255,4260 **** ---- 4256,4262 ---- +*** 4629,4634 **** +--- 4630,4636 ----
  • OPTION:
  • OPTION:
  • OPTION: Signature Color @@ -415,8 +415,8 @@ diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.colortext/pith/pine.hlp
  • OPTION:
  • OPTION: *************** -*** 23729,23734 **** ---- 23731,23773 ---- +*** 24262,24267 **** +--- 24264,24306 ---- <End of help on this topic> @@ -461,11 +461,12 @@ diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.colortext/pith/pine.hlp *************** -*** 32340,32345 **** ---- 32379,32408 ---- +*** 32864,32869 **** +--- 32903,32932 ---- +

    Descriptions of the available commands -

    ++

    + Look here + to see the available Editing and Navigation commands. +

    @@ -489,16 +490,15 @@ diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.colortext/pith/pine.hlp + +

    + Descriptions of the available commands -+

    +

    Look here to see the available Editing and Navigation commands. -

    -diff -rc alpine-2.21/pith/state.c alpine-2.21.colortext/pith/state.c -*** alpine-2.21/pith/state.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.colortext/pith/state.c Sun Feb 5 16:15:26 2017 +diff -rc alpine-2.22/pith/state.c alpine-2.22.colortext/pith/state.c +*** alpine-2.22/pith/state.c 2020-01-19 01:32:18.700505323 -0700 +--- alpine-2.22.colortext/pith/state.c 2020-01-19 01:34:56.926444057 -0700 *************** -*** 134,139 **** ---- 134,142 ---- +*** 138,143 **** +--- 138,146 ---- if((*pps)->folders_dir != NULL) fs_give((void **)&(*pps)->folders_dir); @@ -508,12 +508,12 @@ diff -rc alpine-2.21/pith/state.c alpine-2.21.colortext/pith/state.c if((*pps)->ui.homedir) fs_give((void **)&(*pps)->ui.homedir); -diff -rc alpine-2.21/pith/state.h alpine-2.21.colortext/pith/state.h -*** alpine-2.21/pith/state.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.colortext/pith/state.h Sun Feb 5 16:15:26 2017 +diff -rc alpine-2.22/pith/state.h alpine-2.22.colortext/pith/state.h +*** alpine-2.22/pith/state.h 2020-01-19 01:32:18.561508121 -0700 +--- alpine-2.22.colortext/pith/state.h 2020-01-19 01:34:56.926444057 -0700 *************** -*** 338,343 **** ---- 338,345 ---- +*** 340,345 **** +--- 340,347 ---- 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.21/pith/state.h alpine-2.21.colortext/pith/state.h char *posting_charmap; /* needs to be freed */ -diff -rc alpine-2.21/pith/text.c alpine-2.21.colortext/pith/text.c -*** alpine-2.21/pith/text.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.colortext/pith/text.c Sun Feb 5 16:15:26 2017 +diff -rc alpine-2.22/pith/text.c alpine-2.22.colortext/pith/text.c +*** alpine-2.22/pith/text.c 2020-01-19 01:32:19.317492939 -0700 +--- alpine-2.22.colortext/pith/text.c 2020-01-19 01:34:56.927444050 -0700 *************** *** 171,176 **** --- 171,185 ---- diff --git a/chappa-colortext.txt b/chappa-colortext.txt new file mode 100644 index 0000000..b8b6b15 --- /dev/null +++ b/chappa-colortext.txt @@ -0,0 +1,7 @@ +From: http://alpine.x10host.com/alpine/info/WrtAcc.html +Upstream: constitutes upstream source, delivered in non-tarball form + +This patch allows you to define special custom text that will be seen in a +different color than normal text. This can be used in different ways, one can +use it to emphasize important keywords in a message, or to erase offensive +language. diff --git a/chappa-fancy.patch b/chappa-fancy.patch index 73ebd77..4abb240 100644 --- a/chappa-fancy.patch +++ b/chappa-fancy.patch @@ -1,6 +1,6 @@ -diff -rc alpine-2.21/alpine/arg.c alpine-2.21.fancy/alpine/arg.c -*** alpine-2.21/alpine/arg.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/alpine/arg.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/alpine/arg.c alpine-2.22.fancy/alpine/arg.c +*** alpine-2.22/alpine/arg.c 2020-01-19 01:32:20.509469132 -0700 +--- alpine-2.22.fancy/alpine/arg.c 2020-01-19 01:34:41.241565376 -0700 *************** *** 68,73 **** --- 68,74 ---- @@ -12,8 +12,8 @@ diff -rc alpine-2.21/alpine/arg.c alpine-2.21.fancy/alpine/arg.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\""); *************** -*** 111,116 **** ---- 112,118 ---- +*** 114,119 **** +--- 115,121 ---- 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,18 +22,18 @@ diff -rc alpine-2.21/alpine/arg.c alpine-2.21.fancy/alpine/arg.c N_("\t\t\tfrom, size, score, to, cc, /reverse"), N_(" -i\t\tIndex - Go directly to index, bypassing main menu"), *************** -*** 208,213 **** ---- 210,216 ---- +*** 215,220 **** +--- 217,223 ---- char *cmd_list = NULL; char *debug_str = NULL; char *sort = NULL; + char *threadsort = NULL; char *pinerc_file = NULL; char *lc = NULL; - int do_help = 0; + char *xoauth2_server = NULL; *************** -*** 429,434 **** ---- 432,448 ---- +*** 439,444 **** +--- 442,458 ---- goto Loop; } @@ -51,9 +51,9 @@ diff -rc alpine-2.21/alpine/arg.c alpine-2.21.fancy/alpine/arg.c else if(strcmp(*av, "url") == 0){ if(args->action == aaFolder && !args->data.folder){ args->action = aaURL; -diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/alpine/confscroll.c -*** alpine-2.21/alpine/confscroll.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/alpine/confscroll.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/alpine/confscroll.c alpine-2.22.fancy/alpine/confscroll.c +*** alpine-2.22/alpine/confscroll.c 2020-01-19 01:32:20.190475483 -0700 +--- alpine-2.22.fancy/alpine/confscroll.c 2020-01-19 01:34:41.248565318 -0700 *************** *** 139,145 **** char *radio_pretty_value(struct pine *, CONF_S *); @@ -90,7 +90,7 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/alpine/confscroll.c (*cl)->var == startup_ptr))) return; *************** -*** 2932,2938 **** +*** 2938,2944 **** } set_current_val((*cl)->var, TRUE, TRUE); @@ -98,7 +98,7 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/alpine/confscroll.c ps->def_sort = def_sort; ps->def_sort_rev = def_sort_rev; } ---- 2933,2939 ---- +--- 2939,2945 ---- } set_current_val((*cl)->var, TRUE, TRUE); @@ -107,8 +107,8 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/alpine/confscroll.c ps->def_sort_rev = def_sort_rev; } *************** -*** 2941,2946 **** ---- 2942,2978 ---- +*** 2947,2952 **** +--- 2948,2984 ---- ps->mangled_body = 1; /* BUG: redraw it all for now? */ rv = 1; } @@ -147,7 +147,7 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/alpine/confscroll.c q_status_message(SM_ORDER | SM_DING, 3, 6, "Programmer botch! Unknown radiobutton type."); *************** -*** 3804,3810 **** +*** 3810,3816 **** else if(standard_radio_var(ps, v) || v == startup_ptr) return(radio_pretty_value(ps, cl)); else if(v == &ps->vars[V_SORT_KEY]) @@ -155,7 +155,7 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/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]) ---- 3836,3844 ---- +--- 3842,3850 ---- else if(standard_radio_var(ps, v) || v == startup_ptr) return(radio_pretty_value(ps, cl)); else if(v == &ps->vars[V_SORT_KEY]) @@ -166,7 +166,7 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/alpine/confscroll.c return(sigfile_pretty_value(ps, cl)); else if(v == &ps->vars[V_USE_ONLY_DOMAIN_NAME]) *************** -*** 4335,4348 **** +*** 4341,4354 **** char * @@ -181,7 +181,7 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/alpine/confscroll.c { char tmp[6*MAXPATH]; char *pvalnorm, *pvalexc, *pval; ---- 4369,4382 ---- +--- 4375,4388 ---- char * @@ -197,7 +197,7 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/alpine/confscroll.c char tmp[6*MAXPATH]; char *pvalnorm, *pvalexc, *pval; *************** -*** 4392,4398 **** +*** 4398,4404 **** } else if(fixed){ pval = v->fixed_val.p; @@ -205,7 +205,7 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/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", ---- 4426,4432 ---- +--- 4432,4438 ---- } else if(fixed){ pval = v->fixed_val.p; @@ -214,7 +214,7 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/alpine/confscroll.c utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s", *************** -*** 4403,4411 **** +*** 4409,4417 **** is_the_one ? " (value is fixed)" : ""); } else if(is_set_for_this_level){ @@ -224,7 +224,7 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/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", ---- 4437,4445 ---- +--- 4443,4451 ---- is_the_one ? " (value is fixed)" : ""); } else if(is_set_for_this_level){ @@ -235,7 +235,7 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/alpine/confscroll.c exc_sort_rev == line_sort_rev && exc_sort == line_sort); utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s", *************** -*** 4423,4429 **** +*** 4429,4435 **** } else{ if(pvalexc){ @@ -243,7 +243,7 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/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", ---- 4457,4463 ---- +--- 4463,4469 ---- } else{ if(pvalexc){ @@ -252,7 +252,7 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/alpine/confscroll.c exc_sort == line_sort); utf8_snprintf(tmp, sizeof(tmp), "( ) %s%-*w%*s%s", *************** -*** 4434,4440 **** +*** 4440,4446 **** } else{ pval = v->current_val.p; @@ -260,7 +260,7 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/alpine/confscroll.c is_the_one = ((pval || default_ok) && var_sort_rev == line_sort_rev && var_sort == line_sort); ---- 4468,4474 ---- +--- 4474,4480 ---- } else{ pval = v->current_val.p; @@ -269,7 +269,7 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/alpine/confscroll.c var_sort_rev == line_sort_rev && var_sort == line_sort); *************** -*** 5594,5602 **** +*** 5606,5614 **** else if(revert && var == &ps->vars[V_SORT_KEY]){ int def_sort_rev; @@ -279,7 +279,7 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/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]){ ---- 5628,5642 ---- +--- 5640,5654 ---- else if(revert && var == &ps->vars[V_SORT_KEY]){ int def_sort_rev; @@ -295,9 +295,9 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.fancy/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]){ -diff -rc alpine-2.21/alpine/confscroll.h alpine-2.21.fancy/alpine/confscroll.h -*** alpine-2.21/alpine/confscroll.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/alpine/confscroll.h Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/alpine/confscroll.h alpine-2.22.fancy/alpine/confscroll.h +*** alpine-2.22/alpine/confscroll.h 2020-01-19 01:32:20.190475483 -0700 +--- alpine-2.22.fancy/alpine/confscroll.h 2020-01-19 01:34:41.249565310 -0700 *************** *** 97,103 **** int radiobutton_tool(struct pine *, int, CONF_S **, unsigned); @@ -315,11 +315,11 @@ diff -rc alpine-2.21/alpine/confscroll.h alpine-2.21.fancy/alpine/confscroll.h int exclude_config_var(struct pine *, struct variable *, int); int config_exit_cmd(unsigned); int simple_exit_cmd(unsigned); -diff -rc alpine-2.21/alpine/keymenu.c alpine-2.21.fancy/alpine/keymenu.c -*** alpine-2.21/alpine/keymenu.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/alpine/keymenu.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/alpine/keymenu.c alpine-2.22.fancy/alpine/keymenu.c +*** alpine-2.22/alpine/keymenu.c 2020-01-19 01:32:20.360472098 -0700 +--- alpine-2.22.fancy/alpine/keymenu.c 2020-01-19 01:34:41.255565261 -0700 *************** -*** 650,659 **** +*** 665,674 **** RCOMPOSE_MENU, HOMEKEY_MENU, ENDKEY_MENU, @@ -330,7 +330,7 @@ diff -rc alpine-2.21/alpine/keymenu.c alpine-2.21.fancy/alpine/keymenu.c {"@", N_("Quota"), {MC_QUOTA,1,{'@'}}, KS_NONE}, NULL_MENU}; INST_KEY_MENU(index_keymenu, index_keys); ---- 650,674 ---- +--- 665,689 ---- RCOMPOSE_MENU, HOMEKEY_MENU, ENDKEY_MENU, @@ -357,7 +357,7 @@ diff -rc alpine-2.21/alpine/keymenu.c alpine-2.21.fancy/alpine/keymenu.c NULL_MENU}; INST_KEY_MENU(index_keymenu, index_keys); *************** -*** 728,736 **** +*** 743,751 **** RCOMPOSE_MENU, HOMEKEY_MENU, ENDKEY_MENU, @@ -367,7 +367,7 @@ diff -rc alpine-2.21/alpine/keymenu.c alpine-2.21.fancy/alpine/keymenu.c NULL_MENU}; INST_KEY_MENU(thread_keymenu, thread_keys); ---- 743,764 ---- +--- 758,779 ---- RCOMPOSE_MENU, HOMEKEY_MENU, ENDKEY_MENU, @@ -391,7 +391,7 @@ diff -rc alpine-2.21/alpine/keymenu.c alpine-2.21.fancy/alpine/keymenu.c INST_KEY_MENU(thread_keymenu, thread_keys); *************** -*** 898,904 **** +*** 913,919 **** NULL_MENU, NULL_MENU, NULL_MENU, @@ -399,7 +399,7 @@ diff -rc alpine-2.21/alpine/keymenu.c alpine-2.21.fancy/alpine/keymenu.c INST_KEY_MENU(view_keymenu, view_keys); ---- 926,945 ---- +--- 941,960 ---- NULL_MENU, NULL_MENU, NULL_MENU, @@ -420,36 +420,43 @@ diff -rc alpine-2.21/alpine/keymenu.c alpine-2.21.fancy/alpine/keymenu.c INST_KEY_MENU(view_keymenu, view_keys); -diff -rc alpine-2.21/alpine/keymenu.h alpine-2.21.fancy/alpine/keymenu.h -*** alpine-2.21/alpine/keymenu.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/alpine/keymenu.h Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/alpine/keymenu.h alpine-2.22.fancy/alpine/keymenu.h +*** alpine-2.22/alpine/keymenu.h 2020-01-19 01:32:20.263474030 -0700 +--- alpine-2.22.fancy/alpine/keymenu.h 2020-01-19 01:34:41.257565244 -0700 *************** -*** 215,220 **** ---- 215,233 ---- - #define MC_DECRYPT 802 +*** 216,222 **** #define MC_QUOTA 803 #define MC_ADDHEADER 804 -+ #define MC_DELTHREAD 805 -+ #define MC_UNDTHREAD 806 -+ #define MC_SELTHREAD 807 -+ #define MC_SSUTHREAD 808 -+ #define MC_DSUTHREAD 809 -+ #define MC_USUTHREAD 810 -+ #define MC_SORTHREAD 811 -+ #define MC_NEXTHREAD 812 -+ #define MC_KOLAPSE 813 -+ #define MC_EXPTHREAD 814 -+ #define MC_PRETHREAD 815 -+ #define MC_CTHREAD 816 -+ #define MC_OTHREAD 817 - + #define MC_XOAUTH2 805 +! /* Commands for S/MIME screens */ -diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c -*** alpine-2.21/alpine/mailcmd.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/alpine/mailcmd.c Sun Feb 5 16:15:20 2017 + #define MC_TRUST 900 +--- 216,234 ---- + #define MC_QUOTA 803 + #define MC_ADDHEADER 804 + #define MC_XOAUTH2 805 +! #define MC_DELTHREAD 806 +! #define MC_UNDTHREAD 807 +! #define MC_SELTHREAD 808 +! #define MC_SSUTHREAD 809 +! #define MC_DSUTHREAD 810 +! #define MC_USUTHREAD 811 +! #define MC_SORTHREAD 812 +! #define MC_NEXTHREAD 813 +! #define MC_KOLAPSE 814 +! #define MC_EXPTHREAD 815 +! #define MC_PRETHREAD 816 +! #define MC_CTHREAD 817 +! #define MC_OTHREAD 818 + + /* Commands for S/MIME screens */ + #define MC_TRUST 900 +diff -rc alpine-2.22/alpine/mailcmd.c alpine-2.22.fancy/alpine/mailcmd.c +*** alpine-2.22/alpine/mailcmd.c 2020-01-19 01:32:20.165475981 -0700 +--- alpine-2.22.fancy/alpine/mailcmd.c 2020-01-19 01:34:41.269565146 -0700 *************** -*** 113,119 **** +*** 114,120 **** char *choose_a_rule(int); int select_by_keyword(MAILSTREAM *, SEARCHSET **); char *choose_a_keyword(void); @@ -457,7 +464,7 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c int print_index(struct pine *, MSGNO_S *, int); /* ---- 113,119 ---- +--- 114,120 ---- char *choose_a_rule(int); int select_by_keyword(MAILSTREAM *, SEARCHSET **); char *choose_a_keyword(void); @@ -466,7 +473,7 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c /* *************** -*** 1383,1389 **** +*** 1434,1440 **** if(any_messages(msgmap, NULL, NULL)){ if(any_lflagged(msgmap, MN_SLCT) > 0L){ if(apply_command(state, stream, msgmap, 0, @@ -474,7 +481,7 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c if(F_ON(F_AUTO_UNSELECT, state)){ agg_select_all(stream, msgmap, NULL, 0); unzoom_index(state, stream, msgmap); ---- 1383,1389 ---- +--- 1434,1440 ---- if(any_messages(msgmap, NULL, NULL)){ if(any_lflagged(msgmap, MN_SLCT) > 0L){ if(apply_command(state, stream, msgmap, 0, @@ -483,7 +490,7 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c agg_select_all(stream, msgmap, NULL, 0); unzoom_index(state, stream, msgmap); *************** -*** 1401,1423 **** +*** 1452,1474 **** /*-------- Sort command -------*/ case MC_SORT : @@ -507,7 +514,7 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c } state->mangled_footer = 1; ---- 1401,1435 ---- +--- 1452,1486 ---- /*-------- Sort command -------*/ case MC_SORT : @@ -544,8 +551,8 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c state->mangled_footer = 1; *************** -*** 3262,3267 **** ---- 3274,3283 ---- +*** 3313,3318 **** +--- 3325,3334 ---- if(SORT_IS_THREADED(msgmap)) refresh_sort(stream, msgmap, SRT_NON); @@ -557,8 +564,8 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c state->mangled_header = 1; q_status_message2(SM_ORDER, 0, 4, *************** -*** 3363,3368 **** ---- 3379,3387 ---- +*** 3414,3419 **** +--- 3430,3438 ---- */ if(SORT_IS_THREADED(msgmap)) refresh_sort(stream, msgmap, SRT_NON); @@ -569,7 +576,7 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c else{ if(del_count){ *************** -*** 7222,7228 **** +*** 7307,7313 **** * Maybe it makes sense to zoom after a select but not after a colon * command even though they are very similar. */ @@ -577,7 +584,7 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c } else{ if((all_selected = ---- 7241,7247 ---- +--- 7326,7332 ---- * Maybe it makes sense to zoom after a select but not after a colon * command even though they are very similar. */ @@ -586,7 +593,7 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c else{ if((all_selected = *************** -*** 7278,7284 **** +*** 7363,7369 **** ----*/ int apply_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, @@ -594,7 +601,7 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c { int i = 8, /* number of static entries in sel_opts3 */ rv = 0, ---- 7297,7303 ---- +--- 7382,7388 ---- ----*/ int apply_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, @@ -603,7 +610,7 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c int i = 8, /* number of static entries in sel_opts3 */ rv = 0, *************** -*** 7445,7453 **** +*** 7530,7538 **** collapse_or_expand(state, stream, msgmap, F_ON(F_SLASH_COLL_ENTIRE, ps_global) ? 0L @@ -613,7 +620,7 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c case ':' : select_thread_stmp(state, stream, msgmap); break; ---- 7464,7482 ---- +--- 7549,7567 ---- collapse_or_expand(state, stream, msgmap, F_ON(F_SLASH_COLL_ENTIRE, ps_global) ? 0L @@ -634,7 +641,7 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c select_thread_stmp(state, stream, msgmap); break; *************** -*** 9426,9435 **** +*** 9586,9595 **** Returns 0 if it was cancelled, 1 otherwise. ----*/ int @@ -645,7 +652,7 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c int deefault = 'a', retval = 1; HelpType help; ESCKEY_S sorts[14]; ---- 9455,9464 ---- +--- 9615,9624 ---- Returns 0 if it was cancelled, 1 otherwise. ----*/ int @@ -657,7 +664,7 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c HelpType help; ESCKEY_S sorts[14]; *************** -*** 9462,9478 **** +*** 9622,9638 **** strncpy(prompt, _("Choose type of sort, or 'R' to reverse current sort : "), sizeof(prompt)); @@ -669,13 +676,13 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c ! ! sorts[i].ch = tolower((unsigned char)(tmp[0] = *p)); ! sorts[i].name = cpystr(tmp); -! + ! if(mn_get_sort(state->msgmap) == state->sort_types[i]) ! deefault = sorts[i].rval; } sorts[i].ch = 'r'; ---- 9491,9516 ---- +--- 9651,9676 ---- strncpy(prompt, _("Choose type of sort, or 'R' to reverse current sort : "), sizeof(prompt)); @@ -691,7 +698,7 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c ! sorts[j].ch = tolower((unsigned char)(tmp[0] = *p)); ! sorts[j++].name = cpystr(tmp); ! } -! + ! if (thread){ ! if (state->thread_def_sort == state->sort_types[i]) ! deefault = sorts[j-1].rval; @@ -703,7 +710,7 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c sorts[i].ch = 'r'; *************** -*** 9496,9503 **** +*** 9656,9663 **** state->mangled_body = 1; /* signal screen's changed */ if(s == 'r') *rev = !mn_get_revsort(state->msgmap); @@ -712,7 +719,7 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c if(F_ON(F_SHOW_SORT, ps_global)) ps_global->mangled_header = 1; ---- 9534,9550 ---- +--- 9694,9710 ---- state->mangled_body = 1; /* signal screen's changed */ if(s == 'r') *rev = !mn_get_revsort(state->msgmap); @@ -731,8 +738,8 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c if(F_ON(F_SHOW_SORT, ps_global)) ps_global->mangled_header = 1; *************** -*** 9882,9884 **** ---- 9929,10306 ---- +*** 10041,10043 **** +--- 10088,10465 ---- } #endif /* _WINDOWS */ @@ -1111,9 +1118,9 @@ diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.fancy/alpine/mailcmd.c + expand_thread(state, stream, msgmap, 0); + } + -diff -rc alpine-2.21/alpine/mailcmd.h alpine-2.21.fancy/alpine/mailcmd.h -*** alpine-2.21/alpine/mailcmd.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/alpine/mailcmd.h Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/alpine/mailcmd.h alpine-2.22.fancy/alpine/mailcmd.h +*** alpine-2.22/alpine/mailcmd.h 2020-01-19 01:32:20.370471899 -0700 +--- alpine-2.22.fancy/alpine/mailcmd.h 2020-01-19 01:34:41.271565130 -0700 *************** *** 90,96 **** int ask_mailbox_reopen(struct pine *, int *); @@ -1155,9 +1162,9 @@ diff -rc alpine-2.21/alpine/mailcmd.h alpine-2.21.fancy/alpine/mailcmd.h ! int expand_this_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int, int); #endif /* PINE_MAILCMD_INCLUDED */ -diff -rc alpine-2.21/alpine/mailindx.c alpine-2.21.fancy/alpine/mailindx.c -*** alpine-2.21/alpine/mailindx.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/alpine/mailindx.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/alpine/mailindx.c alpine-2.22.fancy/alpine/mailindx.c +*** alpine-2.22/alpine/mailindx.c 2020-01-19 01:32:20.584467638 -0700 +--- alpine-2.22.fancy/alpine/mailindx.c 2020-01-19 01:34:41.276565089 -0700 *************** *** 564,569 **** --- 564,570 ---- @@ -1421,7 +1428,7 @@ diff -rc alpine-2.21/alpine/mailindx.c alpine-2.21.fancy/alpine/mailindx.c /* restore the original flags */ copy_lflags(stream, msgmap, MN_STMP, MN_SLCT); *************** -*** 3415,3421 **** +*** 3438,3444 **** if(set){ sort_folder(ps_global->mail_stream, ps_global->msgmap, order & 0x000000ff, @@ -1429,7 +1436,7 @@ diff -rc alpine-2.21/alpine/mailindx.c alpine-2.21.fancy/alpine/mailindx.c mswin_beginupdate(); update_titlebar_message(); update_titlebar_status(); ---- 3515,3521 ---- +--- 3538,3544 ---- if(set){ sort_folder(ps_global->mail_stream, ps_global->msgmap, order & 0x000000ff, @@ -1437,9 +1444,9 @@ diff -rc alpine-2.21/alpine/mailindx.c alpine-2.21.fancy/alpine/mailindx.c mswin_beginupdate(); update_titlebar_message(); update_titlebar_status(); -diff -rc alpine-2.21/alpine/mailindx.h alpine-2.21.fancy/alpine/mailindx.h -*** alpine-2.21/alpine/mailindx.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/alpine/mailindx.h Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/alpine/mailindx.h alpine-2.22.fancy/alpine/mailindx.h +*** alpine-2.22/alpine/mailindx.h 2020-01-19 01:32:19.927480727 -0700 +--- alpine-2.22.fancy/alpine/mailindx.h 2020-01-19 01:34:41.277565080 -0700 *************** *** 103,109 **** void paint_index_hline(MAILSTREAM *, long, ICE_S *); @@ -1457,12 +1464,12 @@ diff -rc alpine-2.21/alpine/mailindx.h alpine-2.21.fancy/alpine/mailindx.h COLOR_PAIR *apply_rev_color(COLOR_PAIR *, int); #ifdef _WINDOWS int index_sort_callback(int, long); -diff -rc alpine-2.21/alpine/mailview.c alpine-2.21.fancy/alpine/mailview.c -*** alpine-2.21/alpine/mailview.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/alpine/mailview.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/alpine/mailview.c alpine-2.22.fancy/alpine/mailview.c +*** alpine-2.22/alpine/mailview.c 2020-01-19 01:32:20.102477235 -0700 +--- alpine-2.22.fancy/alpine/mailview.c 2020-01-19 01:34:41.284565023 -0700 *************** -*** 3369,3374 **** ---- 3369,3420 ---- +*** 3380,3385 **** +--- 3380,3431 ---- print_to_printer(sparms); break; @@ -1515,9 +1522,9 @@ diff -rc alpine-2.21/alpine/mailview.c alpine-2.21.fancy/alpine/mailview.c /* ------- First handle on Line ------ */ case MC_GOTOBOL : -diff -rc alpine-2.21/alpine/roleconf.c alpine-2.21.fancy/alpine/roleconf.c -*** alpine-2.21/alpine/roleconf.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/alpine/roleconf.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/alpine/roleconf.c alpine-2.22.fancy/alpine/roleconf.c +*** alpine-2.22/alpine/roleconf.c 2020-01-19 01:32:20.509469132 -0700 +--- alpine-2.22.fancy/alpine/roleconf.c 2020-01-19 01:34:41.293564949 -0700 *************** *** 4478,4488 **** ctmp->tool = role_sort_tool; @@ -1594,9 +1601,9 @@ diff -rc alpine-2.21/alpine/roleconf.c alpine-2.21.fancy/alpine/roleconf.c (*result)->action->sort_is_set = 1; (*result)->action->sortorder = def_sort; (*result)->action->revsort = (def_sort_rev ? 1 : 0); -diff -rc alpine-2.21/alpine/setup.c alpine-2.21.fancy/alpine/setup.c -*** alpine-2.21/alpine/setup.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/alpine/setup.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/alpine/setup.c alpine-2.22.fancy/alpine/setup.c +*** alpine-2.22/alpine/setup.c 2020-01-19 01:32:19.970479867 -0700 +--- alpine-2.22.fancy/alpine/setup.c 2020-01-19 01:34:41.295564933 -0700 *************** *** 262,268 **** ctmpa->flags |= CF_NOSELECT; @@ -1690,12 +1697,12 @@ diff -rc alpine-2.21/alpine/setup.c alpine-2.21.fancy/alpine/setup.c treat_color_vars_as_text = 0; free_saved_config(ps, &vsave, expose_hidden_config); #ifdef _WINDOWS -diff -rc alpine-2.21/pith/conf.c alpine-2.21.fancy/pith/conf.c -*** alpine-2.21/pith/conf.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/pith/conf.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/conf.c alpine-2.22.fancy/pith/conf.c +*** alpine-2.22/pith/conf.c 2020-01-19 01:32:18.678505766 -0700 +--- alpine-2.22.fancy/pith/conf.c 2020-01-19 01:34:41.307564835 -0700 *************** -*** 206,211 **** ---- 206,213 ---- +*** 205,210 **** +--- 205,212 ---- CONF_TXT_T cf_text_sort_key[] = "Sets presentation order of messages in Index. Choices:\n# Subject, From, Arrival, Date, Size, To, Cc, OrderedSubj, Score, and Thread.\n# Order may be reversed by appending /Reverse. Default: \"Arrival\"."; @@ -1705,8 +1712,8 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.fancy/pith/conf.c 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\"."; *************** -*** 528,533 **** ---- 530,537 ---- +*** 533,538 **** +--- 535,542 ---- NULL, cf_text_fcc_name_rule}, {"sort-key", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, NULL, cf_text_sort_key}, @@ -1716,7 +1723,7 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.fancy/pith/conf.c "Address Book Sort Rule", cf_text_addrbook_sort_rule}, {"folder-sort-rule", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, *************** -*** 1582,1588 **** +*** 1593,1599 **** register struct variable *vars = ps->vars; int obs_header_in_reply = 0, /* the obs_ variables are to */ obs_old_style_reply = 0, /* support backwards compatibility */ @@ -1724,7 +1731,7 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.fancy/pith/conf.c long rvl; PINERC_S *fixedprc = NULL; FeatureLevel obs_feature_level; ---- 1586,1592 ---- +--- 1597,1603 ---- register struct variable *vars = ps->vars; int obs_header_in_reply = 0, /* the obs_ variables are to */ obs_old_style_reply = 0, /* support backwards compatibility */ @@ -1733,8 +1740,8 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.fancy/pith/conf.c PINERC_S *fixedprc = NULL; FeatureLevel obs_feature_level; *************** -*** 1607,1612 **** ---- 1611,1617 ---- +*** 1621,1626 **** +--- 1625,1631 ---- GLO_FEATURE_LEVEL = cpystr("sappling"); GLO_OLD_STYLE_REPLY = cpystr(DF_OLD_STYLE_REPLY); GLO_SORT_KEY = cpystr(DF_SORT_KEY); @@ -1743,7 +1750,7 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.fancy/pith/conf.c GLO_FCC_RULE = cpystr(DF_FCC_RULE); GLO_AB_SORT_RULE = cpystr(DF_AB_SORT_RULE); *************** -*** 2540,2546 **** +*** 2564,2570 **** 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); @@ -1751,7 +1758,7 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.fancy/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; ---- 2545,2551 ---- +--- 2569,2575 ---- 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); @@ -1760,8 +1767,8 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.fancy/pith/conf.c init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf); ps->def_sort = SortArrival; *************** -*** 2549,2554 **** ---- 2554,2570 ---- +*** 2573,2578 **** +--- 2578,2594 ---- else ps->def_sort_rev = def_sort_rev; @@ -1780,8 +1787,8 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.fancy/pith/conf.c {NAMEVAL_S *v; int i; for(i = 0; (v = save_msg_rules(i)); i++) *************** -*** 2974,2979 **** ---- 2990,2997 ---- +*** 2998,3003 **** +--- 3014,3021 ---- 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}, @@ -1791,8 +1798,8 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.fancy/pith/conf.c /* Viewer prefs */ {"enable-msg-view-addresses", "Enable Message View Address Links", *************** -*** 7695,7700 **** ---- 7713,7720 ---- +*** 7727,7732 **** +--- 7745,7752 ---- return(h_config_fcc_rule); case V_SORT_KEY : return(h_config_sort_key); @@ -1801,9 +1808,9 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.fancy/pith/conf.c case V_AB_SORT_RULE : return(h_config_ab_sort_rule); case V_FLD_SORT_RULE : -diff -rc alpine-2.21/pith/conf.h alpine-2.21.fancy/pith/conf.h -*** alpine-2.21/pith/conf.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/pith/conf.h Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/conf.h alpine-2.22.fancy/pith/conf.h +*** alpine-2.22/pith/conf.h 2020-01-19 01:32:19.489489496 -0700 +--- alpine-2.22.fancy/pith/conf.h 2020-01-19 01:34:41.310564810 -0700 *************** *** 144,149 **** --- 144,152 ---- @@ -1816,9 +1823,9 @@ diff -rc alpine-2.21/pith/conf.h alpine-2.21.fancy/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 -diff -rc alpine-2.21/pith/conftype.h alpine-2.21.fancy/pith/conftype.h -*** alpine-2.21/pith/conftype.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/pith/conftype.h Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/conftype.h alpine-2.22.fancy/pith/conftype.h +*** alpine-2.22/pith/conftype.h 2020-01-19 01:32:18.702505283 -0700 +--- alpine-2.22.fancy/pith/conftype.h 2020-01-19 01:34:41.314564777 -0700 *************** *** 59,64 **** --- 59,65 ---- @@ -1830,8 +1837,8 @@ diff -rc alpine-2.21/pith/conftype.h alpine-2.21.fancy/pith/conftype.h , V_FLD_SORT_RULE , V_GOTO_DEFAULT_RULE *************** -*** 514,519 **** ---- 515,521 ---- +*** 519,524 **** +--- 520,526 ---- F_QUELL_TIMEZONE, F_QUELL_USERAGENT, F_COLOR_LINE_IMPORTANT, @@ -1840,17 +1847,17 @@ diff -rc alpine-2.21/pith/conftype.h alpine-2.21.fancy/pith/conftype.h F_ENABLE_FULL_HDR_AND_TEXT, F_QUELL_FULL_HDR_RESET, *************** -*** 779,783 **** ---- 781,786 ---- +*** 784,788 **** +--- 786,791 ---- - /* exported protoypes */ + /* exported prototypes */ + #define DF_THREAD_SORT_KEY "thread" #endif /* PITH_CONFTYPE_INCLUDED */ -diff -rc alpine-2.21/pith/flag.c alpine-2.21.fancy/pith/flag.c -*** alpine-2.21/pith/flag.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/pith/flag.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/flag.c alpine-2.22.fancy/pith/flag.c +*** alpine-2.22/pith/flag.c 2020-01-19 01:32:18.569507960 -0700 +--- alpine-2.22.fancy/pith/flag.c 2020-01-19 01:34:41.316564761 -0700 *************** *** 594,607 **** @@ -1884,9 +1891,9 @@ diff -rc alpine-2.21/pith/flag.c alpine-2.21.fancy/pith/flag.c } if(topthrd){ -diff -rc alpine-2.21/pith/indxtype.h alpine-2.21.fancy/pith/indxtype.h -*** alpine-2.21/pith/indxtype.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/pith/indxtype.h Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/indxtype.h alpine-2.22.fancy/pith/indxtype.h +*** alpine-2.22/pith/indxtype.h 2020-01-19 01:32:18.655506229 -0700 +--- alpine-2.22.fancy/pith/indxtype.h 2020-01-19 01:34:41.317564753 -0700 *************** *** 78,84 **** iKey, iKeyInit, @@ -1904,12 +1911,12 @@ diff -rc alpine-2.21/pith/indxtype.h alpine-2.21.fancy/pith/indxtype.h iNewsAndTo, iToAndNews, iNewsAndRecips, iRecipsAndNews, iFromTo, iFromToNotNews, iFrom, iTo, iSender, iCc, iNews, iRecips, iCurNews, iArrow, -diff -rc alpine-2.21/pith/mailindx.c alpine-2.21.fancy/pith/mailindx.c -*** alpine-2.21/pith/mailindx.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/pith/mailindx.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/mailindx.c alpine-2.22.fancy/pith/mailindx.c +*** alpine-2.22/pith/mailindx.c 2020-01-19 01:32:19.552488235 -0700 +--- alpine-2.22.fancy/pith/mailindx.c 2020-01-19 01:34:41.326564679 -0700 *************** -*** 228,233 **** ---- 228,234 ---- +*** 229,234 **** +--- 229,235 ---- case iSTime: case iKSize: case iSize: @@ -1918,8 +1925,8 @@ diff -rc alpine-2.21/pith/mailindx.c alpine-2.21.fancy/pith/mailindx.c (*answer)[column].req_width = 7; break; *************** -*** 455,460 **** ---- 456,462 ---- +*** 456,461 **** +--- 457,463 ---- {"FROMORTONOTNEWS", iFromToNotNews, FOR_INDEX}, {"SIZE", iSize, FOR_INDEX}, {"SIZECOMMA", iSizeComma, FOR_INDEX}, @@ -1928,7 +1935,7 @@ diff -rc alpine-2.21/pith/mailindx.c alpine-2.21.fancy/pith/mailindx.c {"KSIZE", iKSize, FOR_INDEX}, {"SUBJECT", iSubject, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, *************** -*** 953,959 **** +*** 954,960 **** iSDateTimeS1, iSDateTimeS2, iSDateTimeS3, iSDateTimeS4, iSDateTimeIso24, iSDateTimeIsoS24, iSDateTimeS124, iSDateTimeS224, iSDateTimeS324, iSDateTimeS424, @@ -1936,7 +1943,7 @@ diff -rc alpine-2.21/pith/mailindx.c alpine-2.21.fancy/pith/mailindx.c iPrio, iPrioBang, iPrioAlpha, iInit, iAtt, iTime24, iTime12, iTimezone, iMonAbb, iYear, iYear2Digit, iDay2Digit, iMon2Digit, iDayOfWeekAbb, iScore, iMonLong, iDayOfWeek ---- 955,961 ---- +--- 956,962 ---- iSDateTimeS1, iSDateTimeS2, iSDateTimeS3, iSDateTimeS4, iSDateTimeIso24, iSDateTimeIsoS24, iSDateTimeS124, iSDateTimeS224, iSDateTimeS324, iSDateTimeS424, @@ -1945,8 +1952,8 @@ diff -rc alpine-2.21/pith/mailindx.c alpine-2.21.fancy/pith/mailindx.c iAtt, iTime24, iTime12, iTimezone, iMonAbb, iYear, iYear2Digit, iDay2Digit, iMon2Digit, iDayOfWeekAbb, iScore, iMonLong, iDayOfWeek *************** -*** 1146,1151 **** ---- 1148,1154 ---- +*** 1147,1152 **** +--- 1149,1155 ---- case iTime12: case iSize: case iKSize: @@ -1955,7 +1962,7 @@ diff -rc alpine-2.21/pith/mailindx.c alpine-2.21.fancy/pith/mailindx.c cdesc->adjustment = Right; break; *************** -*** 1240,1246 **** +*** 1241,1247 **** cdesc->ctype != iNothing; cdesc++) if(cdesc->ctype == iSize || cdesc->ctype == iKSize || @@ -1963,7 +1970,7 @@ diff -rc alpine-2.21/pith/mailindx.c alpine-2.21.fancy/pith/mailindx.c cdesc->ctype == iSizeComma || cdesc->ctype == iDescripSize){ if(cdesc->actual_length == 0){ if((fix=cdesc->width) > 0){ /* had this reserved */ ---- 1243,1249 ---- +--- 1244,1250 ---- cdesc->ctype != iNothing; cdesc++) if(cdesc->ctype == iSize || cdesc->ctype == iKSize || @@ -1972,7 +1979,7 @@ diff -rc alpine-2.21/pith/mailindx.c alpine-2.21.fancy/pith/mailindx.c if(cdesc->actual_length == 0){ if((fix=cdesc->width) > 0){ /* had this reserved */ *************** -*** 1626,1635 **** +*** 1627,1636 **** /* find next thread which is visible */ do{ @@ -1983,7 +1990,7 @@ diff -rc alpine-2.21/pith/mailindx.c alpine-2.21.fancy/pith/mailindx.c else thrd = NULL; } while(thrd ---- 1629,1640 ---- +--- 1630,1641 ---- /* find next thread which is visible */ do{ @@ -1997,7 +2004,7 @@ diff -rc alpine-2.21/pith/mailindx.c alpine-2.21.fancy/pith/mailindx.c thrd = NULL; } while(thrd *************** -*** 2041,2053 **** +*** 2042,2054 **** */ ice = copy_ice(ice); @@ -2011,7 +2018,7 @@ diff -rc alpine-2.21/pith/mailindx.c alpine-2.21.fancy/pith/mailindx.c /* calculate contents of the required fields */ for(cdesc = ps_global->index_disp_format; cdesc->ctype != iNothing; cdesc++) ---- 2046,2055 ---- +--- 2047,2056 ---- */ ice = copy_ice(ice); @@ -2023,8 +2030,8 @@ diff -rc alpine-2.21/pith/mailindx.c alpine-2.21.fancy/pith/mailindx.c /* calculate contents of the required fields */ for(cdesc = ps_global->index_disp_format; cdesc->ctype != iNothing; cdesc++) *************** -*** 2549,2555 **** ---- 2551,2580 ---- +*** 2550,2556 **** +--- 2552,2581 ---- break; @@ -2056,7 +2063,7 @@ diff -rc alpine-2.21/pith/mailindx.c alpine-2.21.fancy/pith/mailindx.c if((l = fetch_size(idata)) < 10*1000L) snprintf(str, sizeof(str), "(%lu)", l); *************** -*** 5555,5564 **** +*** 5582,5591 **** if(pith_opt_condense_thread_cue) width = (*pith_opt_condense_thread_cue)(thd, ice, &str, &strsize, width, @@ -2067,7 +2074,7 @@ diff -rc alpine-2.21/pith/mailindx.c alpine-2.21.fancy/pith/mailindx.c /* * width is < available strsize and ---- 5580,5587 ---- +--- 5607,5614 ---- if(pith_opt_condense_thread_cue) width = (*pith_opt_condense_thread_cue)(thd, ice, &str, &strsize, width, @@ -2077,7 +2084,7 @@ diff -rc alpine-2.21/pith/mailindx.c alpine-2.21.fancy/pith/mailindx.c /* * width is < available strsize and *************** -*** 6186,6196 **** +*** 6213,6223 **** border = str + width; if(pith_opt_condense_thread_cue) width = (*pith_opt_condense_thread_cue)(thd, ice, &str, &strsize, width, @@ -2089,7 +2096,7 @@ diff -rc alpine-2.21/pith/mailindx.c alpine-2.21.fancy/pith/mailindx.c fptr = str; if(thd) ---- 6209,6216 ---- +--- 6236,6243 ---- border = str + width; if(pith_opt_condense_thread_cue) width = (*pith_opt_condense_thread_cue)(thd, ice, &str, &strsize, width, @@ -2098,9 +2105,9 @@ diff -rc alpine-2.21/pith/mailindx.c alpine-2.21.fancy/pith/mailindx.c fptr = str; if(thd) -diff -rc alpine-2.21/pith/pattern.c alpine-2.21.fancy/pith/pattern.c -*** alpine-2.21/pith/pattern.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/pith/pattern.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/pattern.c alpine-2.22.fancy/pith/pattern.c +*** alpine-2.22/pith/pattern.c 2020-01-19 01:32:19.260494080 -0700 +--- alpine-2.22.fancy/pith/pattern.c 2020-01-19 01:34:41.335564605 -0700 *************** *** 1756,1762 **** SortOrder def_sort; @@ -2118,12 +2125,12 @@ diff -rc alpine-2.21/pith/pattern.c alpine-2.21.fancy/pith/pattern.c action->sort_is_set = 1; action->sortorder = def_sort; action->revsort = (def_sort_rev ? 1 : 0); -diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.fancy/pith/pine.hlp -*** alpine-2.21/pith/pine.hlp Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/pith/pine.hlp Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/pine.hlp alpine-2.22.fancy/pith/pine.hlp +*** alpine-2.22/pith/pine.hlp 2020-01-19 01:32:19.035498584 -0700 +--- alpine-2.22.fancy/pith/pine.hlp 2020-01-19 01:34:41.394564121 -0700 *************** -*** 4258,4263 **** ---- 4258,4264 ---- +*** 4632,4637 **** +--- 4632,4638 ----

  • OPTION:
  • OPTION:
  • OPTION: @@ -2132,8 +2139,8 @@ diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.fancy/pith/pine.hlp
  • OPTION:
  • OPTION: *************** -*** 6198,6203 **** ---- 6199,6361 ---- +*** 6572,6577 **** +--- 6573,6735 ---- <End of help on this topic> @@ -2298,8 +2305,8 @@ diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.fancy/pith/pine.hlp *************** -*** 19638,19643 **** ---- 19796,19809 ---- +*** 20075,20080 **** +--- 20233,20246 ----

    @@ -2315,8 +2322,8 @@ diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.fancy/pith/pine.hlp

    This token represents the total size, in bytes, of the message. *************** -*** 23126,23131 **** ---- 23292,23336 ---- +*** 23659,23664 **** +--- 23825,23869 ---- <End of help on this topic> @@ -2363,8 +2370,8 @@ diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.fancy/pith/pine.hlp *************** -*** 31051,31056 **** ---- 31256,31278 ---- +*** 31641,31646 **** +--- 31846,31868 ---- <End of help on this topic> @@ -2388,9 +2395,9 @@ diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.fancy/pith/pine.hlp ====== h_config_news_cross_deletes ===== -diff -rc alpine-2.21/pith/sort.c alpine-2.21.fancy/pith/sort.c -*** alpine-2.21/pith/sort.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/pith/sort.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/sort.c alpine-2.22.fancy/pith/sort.c +*** alpine-2.22/pith/sort.c 2020-01-19 01:32:19.149496302 -0700 +--- alpine-2.22.fancy/pith/sort.c 2020-01-19 01:34:41.412563974 -0700 *************** *** 91,97 **** ----*/ @@ -2532,9 +2539,9 @@ diff -rc alpine-2.21/pith/sort.c alpine-2.21.fancy/pith/sort.c sort_folder(ps_global->mail_stream, ps_global->msgmap, ! the_sort_order, sort_is_rev, flags, 1); } -diff -rc alpine-2.21/pith/sort.h alpine-2.21.fancy/pith/sort.h -*** alpine-2.21/pith/sort.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/pith/sort.h Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/sort.h alpine-2.22.fancy/pith/sort.h +*** alpine-2.22/pith/sort.h 2020-01-19 01:32:18.784503633 -0700 +--- alpine-2.22.fancy/pith/sort.h 2020-01-19 01:34:41.421563900 -0700 *************** *** 23,29 **** @@ -2555,7 +2562,7 @@ diff -rc alpine-2.21/pith/sort.h alpine-2.21.fancy/pith/sort.h *************** *** 42,49 **** - /* exported protoypes */ + /* exported prototypes */ char *sort_name(SortOrder); ! void sort_folder(MAILSTREAM *, MSGNO_S *, SortOrder, int, unsigned); ! int decode_sort(char *, SortOrder *, int *); @@ -2564,19 +2571,19 @@ diff -rc alpine-2.21/pith/sort.h alpine-2.21.fancy/pith/sort.h --- 42,49 ---- - /* exported protoypes */ + /* exported prototypes */ 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); -diff -rc alpine-2.21/pith/state.c alpine-2.21.fancy/pith/state.c -*** alpine-2.21/pith/state.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/pith/state.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/state.c alpine-2.22.fancy/pith/state.c +*** alpine-2.22/pith/state.c 2020-01-19 01:32:18.700505323 -0700 +--- alpine-2.22.fancy/pith/state.c 2020-01-19 01:34:41.428563843 -0700 *************** -*** 74,79 **** ---- 74,80 ---- +*** 75,80 **** +--- 75,81 ---- p = (struct pine *)fs_get(sizeof (struct pine)); memset((void *) p, 0, sizeof(struct pine)); @@ -2584,9 +2591,9 @@ diff -rc alpine-2.21/pith/state.c alpine-2.21.fancy/pith/state.c p->def_sort = SortArrival; p->sort_types[0] = SortSubject; p->sort_types[1] = SortArrival; -diff -rc alpine-2.21/pith/state.h alpine-2.21.fancy/pith/state.h -*** alpine-2.21/pith/state.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/pith/state.h Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/state.h alpine-2.22.fancy/pith/state.h +*** alpine-2.22/pith/state.h 2020-01-19 01:32:18.561508121 -0700 +--- alpine-2.22.fancy/pith/state.h 2020-01-19 01:34:41.487563359 -0700 *************** *** 139,144 **** --- 139,146 ---- @@ -2599,8 +2606,8 @@ diff -rc alpine-2.21/pith/state.h alpine-2.21.fancy/pith/state.h unsigned tcptimeout:1; /* a tcp timeout is in progress */ *************** -*** 300,305 **** ---- 302,310 ---- +*** 302,307 **** +--- 304,312 ---- EditWhich ew_for_srch_take; SortOrder def_sort, /* Default sort type */ @@ -2610,9 +2617,9 @@ diff -rc alpine-2.21/pith/state.h alpine-2.21.fancy/pith/state.h sort_types[22]; int last_expire_year, last_expire_month; -diff -rc alpine-2.21/pith/thread.c alpine-2.21.fancy/pith/thread.c -*** alpine-2.21/pith/thread.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/pith/thread.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/thread.c alpine-2.22.fancy/pith/thread.c +*** alpine-2.22/pith/thread.c 2020-01-19 01:32:18.556508222 -0700 +--- alpine-2.22.fancy/pith/thread.c 2020-01-19 01:34:41.503563228 -0700 *************** *** 30,41 **** #include "../pith/mailcmd.h" @@ -3948,9 +3955,9 @@ diff -rc alpine-2.21/pith/thread.c alpine-2.21.fancy/pith/thread.c + || sort == SortSize; + } + -diff -rc alpine-2.21/pith/thread.h alpine-2.21.fancy/pith/thread.h -*** alpine-2.21/pith/thread.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/pith/thread.h Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/thread.h alpine-2.22.fancy/pith/thread.h +*** alpine-2.22/pith/thread.h 2020-01-19 01:32:19.516488955 -0700 +--- alpine-2.22.fancy/pith/thread.h 2020-01-19 01:34:41.504563220 -0700 *************** *** 38,43 **** --- 38,44 ---- @@ -4011,9 +4018,9 @@ diff -rc alpine-2.21/pith/thread.h alpine-2.21.fancy/pith/thread.h ! int allowed_thread_key(SortOrder sort); #endif /* PITH_THREAD_INCLUDED */ -diff -rc alpine-2.21/web/src/alpined.d/alpined.c alpine-2.21.fancy/web/src/alpined.d/alpined.c -*** alpine-2.21/web/src/alpined.d/alpined.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fancy/web/src/alpined.d/alpined.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/web/src/alpined.d/alpined.c alpine-2.22.fancy/web/src/alpined.d/alpined.c +*** alpine-2.22/web/src/alpined.d/alpined.c 2020-01-19 01:32:21.762444266 -0700 +--- alpine-2.22.fancy/web/src/alpined.d/alpined.c 2020-01-19 01:34:41.530563007 -0700 *************** *** 2755,2761 **** init_save_defaults(); diff --git a/chappa-fancy.txt b/chappa-fancy.txt new file mode 100644 index 0000000..8d74f61 --- /dev/null +++ b/chappa-fancy.txt @@ -0,0 +1,42 @@ +From: http://alpine.x10host.com/alpine/info/fancy.html +Upstream: constitutes upstream source, delivered in non-tarball form + +You can use this patch to add functionality to the thread interface offered by +Alpine. It adds commands and options that control several aspects of the way +threads are presented. + + + * You can delete a thread, by pressing ^R (to remove), you can undelete it by + pressing ^U (without this patch, you would have to collapse the thread + before you can delete it). + + * You can select and unselect a thread, by pressing ^T. This is useful if you + want to make aggregate operations on a thread, like saving it. + + * You can collapse or expand a particular thread by pressing [ or ] + respectively. If you want to collapse or expand ALL threads, use the + commands { and } respectively. These last two commands work only if you + have selected any of the options (*) + regular-index-with-expanded/collapsed-threads. + + * You can move to the next or previous thread by pressing ) or ( respectively. + + * You can sort threads by arrival, in order to do this press k a. There are + other sorts for threads by Date and by Score. If you want to have threads + permanently sorted by arrival, say, then set the variable thread-sort-key + to be arrival. You can also start Alpine with the option -threadsort + arrival to accomplish the same. + + * Similarly, you can sort threads by their length. In order to do this press + k z. Small threads appear at the beginning of the listing, while long + threads appear at the bottom. Threads of the same length are sorted + according to the date of their first message. In particular, single message + threads are sorted by date. + + * A new configuration option was added: + [X] enhanced-fancy-thread-support + if you enable this configuration option, then all of the above commands + will act on loose threads, which are threads without parents. + + * The SIZETHREAD index token was added, which tells you the size of a thread, + instead of the size of the individual messages in the thread. diff --git a/chappa-fillpara.patch b/chappa-fillpara.patch index aa0af4c..5f49676 100644 --- a/chappa-fillpara.patch +++ b/chappa-fillpara.patch @@ -1,6 +1,6 @@ -diff -rc alpine-2.21/alpine/mailview.c alpine-2.21.fillpara/alpine/mailview.c -*** alpine-2.21/alpine/mailview.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/alpine/mailview.c Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/alpine/mailview.c alpine-2.22.fillpara/alpine/mailview.c +*** alpine-2.22/alpine/mailview.c 2020-01-19 01:32:20.102477235 -0700 +--- alpine-2.22.fillpara/alpine/mailview.c 2020-05-07 16:46:16.683304031 -0600 *************** *** 204,210 **** --- 204,218 ---- @@ -50,9 +50,9 @@ diff -rc alpine-2.21/alpine/mailview.c alpine-2.21.fillpara/alpine/mailview.c if(we_cancel) cancel_busy_cue(-1); -diff -rc alpine-2.21/pico/basic.c alpine-2.21.fillpara/pico/basic.c -*** alpine-2.21/pico/basic.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pico/basic.c Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pico/basic.c alpine-2.22.fillpara/pico/basic.c +*** alpine-2.22/pico/basic.c 2020-01-19 01:32:18.272513938 -0700 +--- alpine-2.22.fillpara/pico/basic.c 2020-05-07 16:46:16.691304036 -0600 *************** *** 26,34 **** * framing, are hard. @@ -323,11 +323,11 @@ diff -rc alpine-2.21/pico/basic.c alpine-2.21.fillpara/pico/basic.c curwp->w_dotp = lforw(curwp->w_dotp); curwp->w_doto = llength(curwp->w_dotp); -diff -rc alpine-2.21/pico/efunc.h alpine-2.21.fillpara/pico/efunc.h -*** alpine-2.21/pico/efunc.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pico/efunc.h Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pico/efunc.h alpine-2.22.fillpara/pico/efunc.h +*** alpine-2.22/pico/efunc.h 2020-01-19 01:32:18.308513213 -0700 +--- alpine-2.22.fillpara/pico/efunc.h 2020-05-07 16:46:16.691304036 -0600 *************** -*** 251,260 **** +*** 253,262 **** extern int fillpara(int, int); extern int fillbuf(int, int); extern int inword(void); @@ -338,7 +338,7 @@ diff -rc alpine-2.21/pico/efunc.h alpine-2.21.fillpara/pico/efunc.h extern int ucs4_ispunct(UCS); #endif /* EFUNC_H */ ---- 251,266 ---- +--- 253,268 ---- extern int fillpara(int, int); extern int fillbuf(int, int); extern int inword(void); @@ -355,11 +355,11 @@ diff -rc alpine-2.21/pico/efunc.h alpine-2.21.fillpara/pico/efunc.h #endif /* EFUNC_H */ + -diff -rc alpine-2.21/pico/line.c alpine-2.21.fillpara/pico/line.c -*** alpine-2.21/pico/line.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pico/line.c Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pico/line.c alpine-2.22.fillpara/pico/line.c +*** alpine-2.22/pico/line.c 2020-01-19 01:32:18.308513213 -0700 +--- alpine-2.22.fillpara/pico/line.c 2020-05-07 16:46:16.691304036 -0600 *************** -*** 611,626 **** +*** 612,627 **** lisblank(LINE *line) { int n = 0; @@ -376,7 +376,7 @@ diff -rc alpine-2.21/pico/line.c alpine-2.21.fillpara/pico/line.c return(FALSE); return(TRUE); ---- 611,622 ---- +--- 612,623 ---- lisblank(LINE *line) { int n = 0; @@ -389,9 +389,9 @@ diff -rc alpine-2.21/pico/line.c alpine-2.21.fillpara/pico/line.c return(FALSE); return(TRUE); -diff -rc alpine-2.21/pico/osdep/color.h alpine-2.21.fillpara/pico/osdep/color.h -*** alpine-2.21/pico/osdep/color.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pico/osdep/color.h Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pico/osdep/color.h alpine-2.22.fillpara/pico/osdep/color.h +*** alpine-2.22/pico/osdep/color.h 2020-01-19 01:32:18.174515911 -0700 +--- alpine-2.22.fillpara/pico/osdep/color.h 2020-05-07 16:46:16.695304038 -0600 *************** *** 33,38 **** --- 33,39 ---- @@ -402,9 +402,9 @@ diff -rc alpine-2.21/pico/osdep/color.h alpine-2.21.fillpara/pico/osdep/color.h #endif /* PICO_OSDEP_COLOR_INCLUDED */ -diff -rc alpine-2.21/pico/search.c alpine-2.21.fillpara/pico/search.c -*** alpine-2.21/pico/search.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pico/search.c Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pico/search.c alpine-2.22.fillpara/pico/search.c +*** alpine-2.22/pico/search.c 2020-01-19 01:32:18.347512428 -0700 +--- alpine-2.22.fillpara/pico/search.c 2020-05-07 16:46:16.695304038 -0600 *************** *** 36,41 **** --- 36,42 ---- @@ -456,8 +456,8 @@ diff -rc alpine-2.21/pico/search.c alpine-2.21.fillpara/pico/search.c flags &= ~SR_FORWARD; flags |= SR_BACKWRD; *************** -*** 1418,1420 **** ---- 1421,1445 ---- +*** 1420,1422 **** +--- 1423,1447 ---- if(bsearch) reverse_ucs4(orig); return utf8; } @@ -483,9 +483,9 @@ diff -rc alpine-2.21/pico/search.c alpine-2.21.fillpara/pico/search.c + return(TRUE); + } + -diff -rc alpine-2.21/pico/word.c alpine-2.21.fillpara/pico/word.c -*** alpine-2.21/pico/word.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pico/word.c Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pico/word.c alpine-2.22.fillpara/pico/word.c +*** alpine-2.22/pico/word.c 2020-01-19 01:32:18.244514502 -0700 +--- alpine-2.22.fillpara/pico/word.c 2020-05-07 16:46:16.695304038 -0600 *************** *** 25,34 **** */ @@ -1229,12 +1229,12 @@ diff -rc alpine-2.21/pico/word.c alpine-2.21.fillpara/pico/word.c + return get_indent_raw_line(q, GLine, buf, buflen, k, plb); + } + -diff -rc alpine-2.21/pith/charconv/utf8.c alpine-2.21.fillpara/pith/charconv/utf8.c -*** alpine-2.21/pith/charconv/utf8.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pith/charconv/utf8.c Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pith/charconv/utf8.c alpine-2.22.fillpara/pith/charconv/utf8.c +*** alpine-2.22/pith/charconv/utf8.c 2020-01-19 01:32:19.323492819 -0700 +--- alpine-2.22.fillpara/pith/charconv/utf8.c 2020-05-07 16:46:16.699304041 -0600 *************** -*** 1061,1066 **** ---- 1061,1116 ---- +*** 1066,1071 **** +--- 1066,1121 ---- /* @@ -1291,9 +1291,9 @@ diff -rc alpine-2.21/pith/charconv/utf8.c alpine-2.21.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.21/pith/charconv/utf8.h alpine-2.21.fillpara/pith/charconv/utf8.h -*** alpine-2.21/pith/charconv/utf8.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pith/charconv/utf8.h Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pith/charconv/utf8.h alpine-2.22.fillpara/pith/charconv/utf8.h +*** alpine-2.22/pith/charconv/utf8.h 2020-01-19 01:32:19.323492819 -0700 +--- alpine-2.22.fillpara/pith/charconv/utf8.h 2020-05-07 16:46:16.703304044 -0600 *************** *** 81,86 **** --- 81,87 ---- @@ -1304,9 +1304,9 @@ diff -rc alpine-2.21/pith/charconv/utf8.h alpine-2.21.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.21/pith/color.c alpine-2.21.fillpara/pith/color.c -*** alpine-2.21/pith/color.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pith/color.c Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pith/color.c alpine-2.22.fillpara/pith/color.c +*** alpine-2.22/pith/color.c 2020-01-19 01:32:19.372491838 -0700 +--- alpine-2.22.fillpara/pith/color.c 2020-05-07 16:46:16.707304046 -0600 *************** *** 21,27 **** #include "../pith/state.h" @@ -1517,9 +1517,9 @@ diff -rc alpine-2.21/pith/color.c alpine-2.21.fillpara/pith/color.c } -diff -rc alpine-2.21/pith/color.h alpine-2.21.fillpara/pith/color.h -*** alpine-2.21/pith/color.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pith/color.h Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pith/color.h alpine-2.22.fillpara/pith/color.h +*** alpine-2.22/pith/color.h 2020-01-19 01:32:19.396491358 -0700 +--- alpine-2.22.fillpara/pith/color.h 2020-05-07 16:46:16.707304046 -0600 *************** *** 22,27 **** --- 22,45 ---- @@ -1550,16 +1550,16 @@ diff -rc alpine-2.21/pith/color.h alpine-2.21.fillpara/pith/color.h *************** *** 81,86 **** --- 99,105 ---- - /* exported protoypes */ + /* exported prototypes */ char *color_embed(char *, char *); int colorcmp(char *, char *); + int next_level_quote(char *, char **, int, int); int color_a_quote(long, char *, LT_INS_S **, void *); void free_spec_colors(SPEC_COLOR_S **); -diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c -*** alpine-2.21/pith/filter.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pith/filter.c Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pith/filter.c alpine-2.22.fillpara/pith/filter.c +*** alpine-2.22/pith/filter.c 2020-01-19 01:32:19.192495441 -0700 +--- alpine-2.22.fillpara/pith/filter.c 2020-05-07 16:46:16.711304048 -0600 *************** *** 46,51 **** --- 46,52 ---- @@ -1571,8 +1571,8 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c #include "../pith/pipe.h" #include "../pith/status.h" *************** -*** 9269,9274 **** ---- 9270,9280 ---- +*** 9270,9275 **** +--- 9271,9281 ---- margin_r, indent; char special[256]; @@ -1585,8 +1585,8 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c #define WRAP_MARG_L(F) (((WRAP_S *)(F)->opt)->margin_l) *************** -*** 9310,9315 **** ---- 9316,9327 ---- +*** 9311,9316 **** +--- 9317,9328 ---- #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.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c if((F)->linep == WRAP_LASTC(F)){ \ size_t offset = (F)->linep - (F)->line; \ *************** -*** 9387,9392 **** ---- 9399,9406 ---- +*** 9388,9393 **** +--- 9400,9407 ---- case CCR : /* CRLF or CR in text ? */ state = BOL; /* either way, handle start */ @@ -1611,7 +1611,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c /* wrapped line? */ if(f->f2 == 0 && WRAP_SPC_LEN(f) && WRAP_TRL_SPC(f)){ *************** -*** 9480,9486 **** +*** 9481,9487 **** case BOL : if(WRAP_FLOW(f)){ @@ -1619,7 +1619,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c WRAP_FL_QC(f) = 1; /* init it */ state = FL_QLEV; /* go collect it */ } ---- 9494,9504 ---- +--- 9495,9505 ---- case BOL : if(WRAP_FLOW(f)){ @@ -1632,7 +1632,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c state = FL_QLEV; /* go collect it */ } *************** -*** 9494,9500 **** +*** 9495,9501 **** } /* quote level change implies new paragraph */ @@ -1640,7 +1640,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c WRAP_FL_QD(f) = 0; if(WRAP_HARD(f) == 0){ WRAP_HARD(f) = 1; ---- 9512,9527 ---- +--- 9513,9528 ---- } /* quote level change implies new paragraph */ @@ -1658,7 +1658,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c if(WRAP_HARD(f) == 0){ WRAP_HARD(f) = 1; *************** -*** 9546,9553 **** +*** 9547,9554 **** break; case FL_QLEV : @@ -1667,7 +1667,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c } else { /* if EMBEDed, process it and return here */ ---- 9573,9584 ---- +--- 9574,9585 ---- break; case FL_QLEV : @@ -1681,7 +1681,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c else { /* if EMBEDed, process it and return here */ *************** -*** 9559,9565 **** +*** 9560,9566 **** } /* quote level change signals new paragraph */ @@ -1689,7 +1689,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.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 */ ---- 9590,9605 ---- +--- 9591,9606 ---- } /* quote level change signals new paragraph */ @@ -1707,8 +1707,8 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c if(WRAP_HARD(f) == 0){ /* add hard newline */ WRAP_HARD(f) = 1; /* hard newline */ *************** -*** 9616,9621 **** ---- 9656,9668 ---- +*** 9617,9622 **** +--- 9657,9669 ---- state = FL_SIG; break; @@ -1723,7 +1723,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c state = DFL; goto case_dfl; /* handle c like DFL */ *************** -*** 9632,9638 **** +*** 9633,9639 **** &eob); /* note any embedded*/ wrap_eol(f, 1, &ip, &eib, &op, &eob); /* plunk down newline */ @@ -1731,7 +1731,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c &op, &eob); /* write any prefix */ } ---- 9679,9685 ---- +--- 9680,9686 ---- &eob); /* note any embedded*/ wrap_eol(f, 1, &ip, &eib, &op, &eob); /* plunk down newline */ @@ -1740,7 +1740,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c } *************** -*** 10129,10135 **** +*** 10130,10136 **** 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.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c &eob); /* write any prefix */ } ---- 10176,10182 ---- +--- 10177,10183 ---- 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.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c } *************** -*** 10202,10207 **** ---- 10249,10261 ---- +*** 10203,10208 **** +--- 10250,10262 ---- if(WRAP_COLOR(f)) free_color_pair(&WRAP_COLOR(f)); @@ -1773,7 +1773,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c so_give(&WRAP_SPACES(f)); fs_give((void **) &f->opt); /* free wrap widths struct */ *************** -*** 10552,10558 **** +*** 10553,10559 **** { int j, i; COLOR_PAIR *col = NULL; @@ -1781,7 +1781,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c if(ps_global->VAR_QUOTE_REPLACE_STRING){ get_pair(ps_global->VAR_QUOTE_REPLACE_STRING, &prefix, &last_prefix, 0, 0); ---- 10606,10613 ---- +--- 10607,10614 ---- { int j, i; COLOR_PAIR *col = NULL; @@ -1791,7 +1791,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c if(ps_global->VAR_QUOTE_REPLACE_STRING){ get_pair(ps_global->VAR_QUOTE_REPLACE_STRING, &prefix, &last_prefix, 0, 0); *************** -*** 10561,10570 **** +*** 10562,10571 **** last_prefix = NULL; } } @@ -1802,7 +1802,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.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, ---- 10616,10637 ---- +--- 10617,10638 ---- last_prefix = NULL; } } @@ -1826,7 +1826,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c && ps_global->VAR_QUOTE1_BACK_COLOR && (col = new_color_pair(ps_global->VAR_QUOTE1_FORE_COLOR, *************** -*** 10572,10578 **** +*** 10573,10579 **** && pico_is_good_colorpair(col)){ GF_COLOR_PUTC(f, col); } @@ -1834,7 +1834,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.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, ---- 10639,10645 ---- +--- 10640,10646 ---- && pico_is_good_colorpair(col)){ GF_COLOR_PUTC(f, col); } @@ -1843,7 +1843,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c && ps_global->VAR_QUOTE2_BACK_COLOR && (col = new_color_pair(ps_global->VAR_QUOTE2_FORE_COLOR, *************** -*** 10580,10586 **** +*** 10581,10587 **** && pico_is_good_colorpair(col)){ GF_COLOR_PUTC(f, col); } @@ -1851,7 +1851,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.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, ---- 10647,10653 ---- +--- 10648,10654 ---- && pico_is_good_colorpair(col)){ GF_COLOR_PUTC(f, col); } @@ -1860,7 +1860,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c && ps_global->VAR_QUOTE3_BACK_COLOR && (col = new_color_pair(ps_global->VAR_QUOTE3_FORE_COLOR, *************** -*** 10594,10636 **** +*** 10595,10637 **** } } @@ -1904,7 +1904,7 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c return 0; } ---- 10661,10707 ---- +--- 10662,10708 ---- } } @@ -1953,8 +1953,8 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c return 0; } *************** -*** 10662,10667 **** ---- 10733,10744 ---- +*** 10663,10668 **** +--- 10734,10745 ---- 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.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c return((void *) wrap); } *************** -*** 11105,11111 **** ---- 11182,11396 ---- +*** 11106,11112 **** +--- 11183,11397 ---- } \ } @@ -2185,9 +2185,9 @@ diff -rc alpine-2.21/pith/filter.c alpine-2.21.fillpara/pith/filter.c /* * this simple filter accumulates characters until a newline, offers it -diff -rc alpine-2.21/pith/filter.h alpine-2.21.fillpara/pith/filter.h -*** alpine-2.21/pith/filter.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pith/filter.h Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pith/filter.h alpine-2.22.fillpara/pith/filter.h +*** alpine-2.22/pith/filter.h 2020-01-19 01:32:19.683485612 -0700 +--- alpine-2.22.fillpara/pith/filter.h 2020-05-07 16:46:16.715304052 -0600 *************** *** 216,221 **** --- 216,222 ---- @@ -2196,11 +2196,11 @@ diff -rc alpine-2.21/pith/filter.h alpine-2.21.fillpara/pith/filter.h void gf_local_nvtnl(FILTER_S *, int); + void gf_quote_test(FILTER_S *, int); void *gf_url_hilite_opt(URL_HILITE_S *, HANDLE_S **, int); + void free_filter_module_globals(void); - -diff -rc alpine-2.21/pith/filttype.h alpine-2.21.fillpara/pith/filttype.h -*** alpine-2.21/pith/filttype.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pith/filttype.h Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pith/filttype.h alpine-2.22.fillpara/pith/filttype.h +*** alpine-2.22/pith/filttype.h 2020-01-19 01:32:19.531488655 -0700 +--- alpine-2.22.fillpara/pith/filttype.h 2020-05-07 16:46:16.715304052 -0600 *************** *** 36,41 **** --- 36,43 ---- @@ -2212,11 +2212,11 @@ diff -rc alpine-2.21/pith/filttype.h alpine-2.21.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.21/pith/mailview.c alpine-2.21.fillpara/pith/mailview.c -*** alpine-2.21/pith/mailview.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pith/mailview.c Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pith/mailview.c alpine-2.22.fillpara/pith/mailview.c +*** alpine-2.22/pith/mailview.c 2020-01-19 01:32:18.803503250 -0700 +--- alpine-2.22.fillpara/pith/mailview.c 2020-05-07 16:46:16.715304052 -0600 *************** -*** 52,58 **** +*** 55,61 **** #include "../pith/escapes.h" #include "../pith/keyword.h" #include "../pith/smime.h" @@ -2224,7 +2224,7 @@ diff -rc alpine-2.21/pith/mailview.c alpine-2.21.fillpara/pith/mailview.c #define FBUF_LEN (50) ---- 52,62 ---- +--- 55,65 ---- #include "../pith/escapes.h" #include "../pith/keyword.h" #include "../pith/smime.h" @@ -2237,7 +2237,7 @@ diff -rc alpine-2.21/pith/mailview.c alpine-2.21.fillpara/pith/mailview.c #define FBUF_LEN (50) *************** -*** 284,290 **** +*** 640,646 **** && pico_usingcolor() && ps_global->VAR_SIGNATURE_FORE_COLOR && ps_global->VAR_SIGNATURE_BACK_COLOR){ @@ -2245,7 +2245,7 @@ diff -rc alpine-2.21/pith/mailview.c alpine-2.21.fillpara/pith/mailview.c } if((flgs & FM_DISPLAY) ---- 288,294 ---- +--- 644,650 ---- && pico_usingcolor() && ps_global->VAR_SIGNATURE_FORE_COLOR && ps_global->VAR_SIGNATURE_BACK_COLOR){ @@ -2254,7 +2254,7 @@ diff -rc alpine-2.21/pith/mailview.c alpine-2.21.fillpara/pith/mailview.c if((flgs & FM_DISPLAY) *************** -*** 292,299 **** +*** 648,655 **** && pico_usingcolor() && ps_global->VAR_QUOTE1_FORE_COLOR && ps_global->VAR_QUOTE1_BACK_COLOR){ @@ -2263,7 +2263,7 @@ diff -rc alpine-2.21/pith/mailview.c alpine-2.21.fillpara/pith/mailview.c if(!(flgs & FM_NOWRAP)){ wrapflags = (flgs & FM_DISPLAY) ? (GFW_HANDLES|GFW_SOFTHYPHEN) : GFW_NONE; ---- 296,305 ---- +--- 652,661 ---- && pico_usingcolor() && ps_global->VAR_QUOTE1_FORE_COLOR && ps_global->VAR_QUOTE1_BACK_COLOR){ @@ -2275,7 +2275,7 @@ diff -rc alpine-2.21/pith/mailview.c alpine-2.21.fillpara/pith/mailview.c if(!(flgs & FM_NOWRAP)){ wrapflags = (flgs & FM_DISPLAY) ? (GFW_HANDLES|GFW_SOFTHYPHEN) : GFW_NONE; *************** -*** 1098,1124 **** +*** 1465,1491 **** color_signature(long int linenum, char *line, LT_INS_S **ins, void *is_in_sig) { struct variable *vars = ps_global->vars; @@ -2303,7 +2303,7 @@ diff -rc alpine-2.21/pith/mailview.c alpine-2.21.fillpara/pith/mailview.c if(*in_sig_block != OUT_SIG_BLOCK && VAR_SIGNATURE_FORE_COLOR && VAR_SIGNATURE_BACK_COLOR && (col = new_color_pair(VAR_SIGNATURE_FORE_COLOR, ---- 1104,1191 ---- +--- 1471,1558 ---- color_signature(long int linenum, char *line, LT_INS_S **ins, void *is_in_sig) { struct variable *vars = ps_global->vars; @@ -2393,8 +2393,8 @@ diff -rc alpine-2.21/pith/mailview.c alpine-2.21.fillpara/pith/mailview.c && VAR_SIGNATURE_FORE_COLOR && VAR_SIGNATURE_BACK_COLOR && (col = new_color_pair(VAR_SIGNATURE_FORE_COLOR, *************** -*** 1678,1683 **** ---- 1745,1821 ---- +*** 2045,2050 **** +--- 2112,2188 ---- } @@ -2472,12 +2472,12 @@ diff -rc alpine-2.21/pith/mailview.c alpine-2.21.fillpara/pith/mailview.c #define UES_LEN 12 #define UES_MAX 32 -diff -rc alpine-2.21/pith/mailview.h alpine-2.21.fillpara/pith/mailview.h -*** alpine-2.21/pith/mailview.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pith/mailview.h Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pith/mailview.h alpine-2.22.fillpara/pith/mailview.h +*** alpine-2.22/pith/mailview.h 2020-01-19 01:32:19.614486993 -0700 +--- alpine-2.22.fillpara/pith/mailview.h 2020-05-07 16:46:16.719304053 -0600 *************** -*** 142,147 **** ---- 142,148 ---- +*** 146,151 **** +--- 146,152 ---- char *display_parameters(PARAMETER *); char *pine_fetch_header(MAILSTREAM *, long, char *, char **, long); int color_signature(long, char *, LT_INS_S **, void *); @@ -2485,9 +2485,9 @@ diff -rc alpine-2.21/pith/mailview.h alpine-2.21.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.21/pith/osdep/color.c alpine-2.21.fillpara/pith/osdep/color.c -*** alpine-2.21/pith/osdep/color.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pith/osdep/color.c Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pith/osdep/color.c alpine-2.22.fillpara/pith/osdep/color.c +*** alpine-2.22/pith/osdep/color.c 2020-01-19 01:32:18.620506934 -0700 +--- alpine-2.22.fillpara/pith/osdep/color.c 2020-05-07 23:52:12.301348731 -0600 *************** *** 32,38 **** @@ -2509,7 +2509,7 @@ diff -rc alpine-2.21/pith/osdep/color.c alpine-2.21.fillpara/pith/osdep/color.c /* *************** *** 92,94 **** ---- 94,1368 ---- +--- 94,1375 ---- { return(pico_set_colors(col ? col->fg : NULL, col ? col->bg : NULL, flags)); } @@ -2861,6 +2861,8 @@ diff -rc alpine-2.21/pith/osdep/color.c alpine-2.21.fillpara/pith/osdep/color.c + c = count_levels_qstring(cl); + n = same_qstring(cl,nl); + ++ /* by the definition of n and c above we have n <= c */ ++ + if (!n){ /* no next line or no agreement with next line */ + int p = same_qstring(pl, cl); /* number of agreements between pl and cl */ + QSTRING_S *tl; /* test line */ @@ -2873,16 +2875,16 @@ diff -rc alpine-2.21/pith/osdep/color.c alpine-2.21.fillpara/pith/osdep/color.c + * case we can only return p levels of cl. + */ + -+ if (p == c) ++ if (p == c) + tl = cqstring; -+ else{ -+ if (p){ ++ else{ ++ if (p){ + for (c = 1; c < p; c++) + cl = cl->next; + free_qs(&(cl->next)); + tl = cqstring; -+ } -+ else{ ++ } ++ else{ + int done = 0; + QSTRING_S *al = cl; /* another line */ + /* @@ -2891,15 +2893,15 @@ diff -rc alpine-2.21/pith/osdep/color.c alpine-2.21.fillpara/pith/osdep/color.c + * that we may want to accept the not-normal part, so we better + * make an extra test to determine what needs to be freed + */ -+ while (pl && cl && cl->qstype == pl->qstype ++ while (pl && cl && cl->qstype == pl->qstype + && !strucmp(cl->value, pl->value)){ + cl = cl->next; + pl = pl->next; -+ } -+ if (pl && cl && cl->qstype == pl->qstype ++ } ++ if (pl && cl && cl->qstype == pl->qstype + && strcmp_qs(pl->value, cl->value)) + cl = cl->next; /* next level differs only in spaces */ -+ while (!done){ ++ while (!done){ + while (cl && cl->qstype == qsNormal) + cl = cl->next; + if (cl){ @@ -2909,23 +2911,29 @@ diff -rc alpine-2.21/pith/osdep/color.c alpine-2.21.fillpara/pith/osdep/color.c + else done++; + } + else done++; -+ } -+ if (al == cl){ ++ } ++ if (al == cl){ + free_qs(&(cl)); + tl = cl; -+ } -+ else { ++ } ++ else { + while (al && (al->next != cl)) + al = al->next; + cl = al; + if (cl && cl->next) + free_qs(&(cl->next)); + tl = cqstring; -+ } -+ } ++ } ++ } + } + return tl; + } ++ ++ /* so n <= c (see above) hence n < c or n = c. If n < c then n+1 <= c, so we ++ * either have n == c or n + 1 < c or n + 1 == c. We analyze each case in the ++ * following code ++ */ ++ + if (n + 1 < c){ /* if there are not enough agreements */ + int p = same_qstring(pl, cl); /* number of agreement between pl and cl */ + QSTRING_S *tl; /* test line */ @@ -2987,9 +2995,8 @@ diff -rc alpine-2.21/pith/osdep/color.c alpine-2.21.fillpara/pith/osdep/color.c + } + return tl; + } -+ if (n == c) /* Yeah!!! */ -+ return cqstring; -+ return 0; ++ /* else n == c, Yeah!!! */ ++ return cqstring; + } + + QSTRING_S * @@ -3785,9 +3792,9 @@ diff -rc alpine-2.21/pith/osdep/color.c alpine-2.21.fillpara/pith/osdep/color.c + return allowed_qstr; + } + -diff -rc alpine-2.21/pith/osdep/color.h alpine-2.21.fillpara/pith/osdep/color.h -*** alpine-2.21/pith/osdep/color.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pith/osdep/color.h Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pith/osdep/color.h alpine-2.22.fillpara/pith/osdep/color.h +*** alpine-2.22/pith/osdep/color.h 2020-01-19 01:32:18.622506893 -0700 +--- alpine-2.22.fillpara/pith/osdep/color.h 2020-05-07 16:46:16.723304056 -0600 *************** *** 17,22 **** --- 17,40 ---- @@ -3838,12 +3845,12 @@ diff -rc alpine-2.21/pith/osdep/color.h alpine-2.21.fillpara/pith/osdep/color.h ! void record_quote_string (QSTRING_S *); #endif /* PITH_OSDEP_COLOR_INCLUDED */ -diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.fillpara/pith/pine.hlp -*** alpine-2.21/pith/pine.hlp Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pith/pine.hlp Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pith/pine.hlp alpine-2.22.fillpara/pith/pine.hlp +*** alpine-2.22/pith/pine.hlp 2020-01-19 01:32:19.035498584 -0700 +--- alpine-2.22.fillpara/pith/pine.hlp 2020-05-07 16:46:16.739304066 -0600 *************** -*** 7446,7451 **** ---- 7446,7491 ---- +*** 7820,7825 **** +--- 7820,7865 ---- "type the character ^".

    @@ -3890,12 +3897,12 @@ diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.fillpara/pith/pine.hlp <End of help on this topic> -diff -rc alpine-2.21/pith/reply.c alpine-2.21.fillpara/pith/reply.c -*** alpine-2.21/pith/reply.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pith/reply.c Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pith/reply.c alpine-2.22.fillpara/pith/reply.c +*** alpine-2.22/pith/reply.c 2020-01-19 01:32:19.475489776 -0700 +--- alpine-2.22.fillpara/pith/reply.c 2020-05-07 16:46:16.763304080 -0600 *************** -*** 2735,2740 **** ---- 2735,2743 ---- +*** 2838,2843 **** +--- 2838,2846 ---- if(flow_res && ps_global->reply.use_flowed) wrapflags |= GFW_FLOW_RESULT; @@ -3906,7 +3913,7 @@ diff -rc alpine-2.21/pith/reply.c alpine-2.21.fillpara/pith/reply.c /* * The 80 will cause longer lines than what is likely *************** -*** 2828,2834 **** +*** 2931,2937 **** dq.do_color = 0; dq.delete_all = 1; @@ -3914,7 +3921,7 @@ diff -rc alpine-2.21/pith/reply.c alpine-2.21.fillpara/pith/reply.c filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq); } ---- 2831,2837 ---- +--- 2934,2940 ---- dq.do_color = 0; dq.delete_all = 1; @@ -3922,12 +3929,12 @@ diff -rc alpine-2.21/pith/reply.c alpine-2.21.fillpara/pith/reply.c filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq); } -diff -rc alpine-2.21/pith/state.c alpine-2.21.fillpara/pith/state.c -*** alpine-2.21/pith/state.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pith/state.c Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pith/state.c alpine-2.22.fillpara/pith/state.c +*** alpine-2.22/pith/state.c 2020-01-19 01:32:18.700505323 -0700 +--- alpine-2.22.fillpara/pith/state.c 2020-05-07 16:46:16.767304083 -0600 *************** -*** 225,230 **** ---- 225,232 ---- +*** 229,234 **** +--- 229,236 ---- if((*pps)->kw_colors) free_spec_colors(&(*pps)->kw_colors); @@ -3936,23 +3943,23 @@ diff -rc alpine-2.21/pith/state.c alpine-2.21.fillpara/pith/state.c if((*pps)->atmts){ int i; -diff -rc alpine-2.21/pith/state.h alpine-2.21.fillpara/pith/state.h -*** alpine-2.21/pith/state.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pith/state.h Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pith/state.h alpine-2.22.fillpara/pith/state.h +*** alpine-2.22/pith/state.h 2020-01-19 01:32:18.561508121 -0700 +--- alpine-2.22.fillpara/pith/state.h 2020-05-07 16:46:16.767304083 -0600 *************** -*** 249,254 **** ---- 249,256 ---- - SPEC_COLOR_S *hdr_colors; /* list of configed colors for view */ - SPEC_COLOR_S *index_token_colors; /* list of configed colors for index */ +*** 251,256 **** +--- 251,258 ---- + SPEC_COLOR_S *hdr_colors; /* list of configured colors for view */ + SPEC_COLOR_S *index_token_colors; /* list of configured colors for index */ + char *prefix; /* prefix for fillpara */ + char **list_qstr; /* list of known quote strings */ short init_context; struct { -diff -rc alpine-2.21/pith/text.c alpine-2.21.fillpara/pith/text.c -*** alpine-2.21/pith/text.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fillpara/pith/text.c Sun Feb 5 16:15:23 2017 +diff -rc alpine-2.22/pith/text.c alpine-2.22.fillpara/pith/text.c +*** alpine-2.22/pith/text.c 2020-01-19 01:32:19.317492939 -0700 +--- alpine-2.22.fillpara/pith/text.c 2020-05-07 16:46:16.767304083 -0600 *************** *** 92,98 **** char *err, *charset; diff --git a/chappa-fillpara.txt b/chappa-fillpara.txt new file mode 100644 index 0000000..5bcc967 --- /dev/null +++ b/chappa-fillpara.txt @@ -0,0 +1,10 @@ +From: http://alpine.x10host.com/alpine/info/fillpara.html +Upstream: constitutes upstream source, delivered in non-tarball form + +When you reply to a message, which has been quoted by several people and you +justify a paragraph, Alpine may not notice any other quote strings and justify +the paragraph as if there was no other quote strings in it. This patch will +help Alpine recognize extra levels of quoting, so that justifying will still +make the text readable. This is important because the purpose of justification +is to make the text more readable, and an incorrect justification may make the +text impossible to read. diff --git a/chappa-fromheader.patch b/chappa-fromheader.patch index 88aa6f7..bb0f321 100644 --- a/chappa-fromheader.patch +++ b/chappa-fromheader.patch @@ -1,8 +1,8 @@ -diff -rc alpine-2.21/alpine/send.c alpine-2.21.fromheader/alpine/send.c -*** alpine-2.21/alpine/send.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fromheader/alpine/send.c Sun Feb 5 16:15:24 2017 +diff -rc alpine-2.22/alpine/send.c alpine-2.22.fromheader/alpine/send.c +*** alpine-2.22/alpine/send.c 2020-01-19 01:32:20.126476758 -0700 +--- alpine-2.22.fromheader/alpine/send.c 2020-01-19 01:34:53.915466200 -0700 *************** -*** 913,919 **** +*** 909,915 **** 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.21/alpine/send.c alpine-2.21.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}, ---- 913,919 ---- +--- 909,915 ---- 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.21/alpine/send.c alpine-2.21.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}, *************** -*** 2367,2372 **** ---- 2367,2377 ---- +*** 2364,2369 **** +--- 2364,2374 ---- he->rich_header = 0; } } @@ -33,7 +33,7 @@ diff -rc alpine-2.21/alpine/send.c alpine-2.21.fromheader/alpine/send.c he_from = he; break; *************** -*** 3104,3110 **** +*** 3101,3107 **** if(outgoing->return_path) mail_free_address(&outgoing->return_path); @@ -41,7 +41,7 @@ diff -rc alpine-2.21/alpine/send.c alpine-2.21.fromheader/alpine/send.c /* * Don't ever believe the sender that is there. ---- 3109,3117 ---- +--- 3106,3114 ---- if(outgoing->return_path) mail_free_address(&outgoing->return_path); @@ -51,12 +51,12 @@ diff -rc alpine-2.21/alpine/send.c alpine-2.21.fromheader/alpine/send.c /* * Don't ever believe the sender that is there. -diff -rc alpine-2.21/pith/conf.c alpine-2.21.fromheader/pith/conf.c -*** alpine-2.21/pith/conf.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fromheader/pith/conf.c Sun Feb 5 16:15:24 2017 +diff -rc alpine-2.22/pith/conf.c alpine-2.22.fromheader/pith/conf.c +*** alpine-2.22/pith/conf.c 2020-01-19 01:32:18.678505766 -0700 +--- alpine-2.22.fromheader/pith/conf.c 2020-01-19 01:34:53.918466178 -0700 *************** -*** 2884,2889 **** ---- 2884,2891 ---- +*** 2908,2913 **** +--- 2908,2915 ---- 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,12 +65,12 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.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.21/pith/conftype.h alpine-2.21.fromheader/pith/conftype.h -*** alpine-2.21/pith/conftype.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fromheader/pith/conftype.h Sun Feb 5 16:15:24 2017 +diff -rc alpine-2.22/pith/conftype.h alpine-2.22.fromheader/pith/conftype.h +*** alpine-2.22/pith/conftype.h 2020-01-19 01:32:18.702505283 -0700 +--- alpine-2.22.fromheader/pith/conftype.h 2020-01-19 01:34:53.919466170 -0700 *************** -*** 399,404 **** ---- 399,405 ---- +*** 404,409 **** +--- 404,410 ---- F_AUTO_REPLY_TO, F_VERBOSE_POST, F_FCC_ON_BOUNCE, @@ -78,12 +78,12 @@ diff -rc alpine-2.21/pith/conftype.h alpine-2.21.fromheader/pith/conftype.h F_SEND_WO_CONFIRM, F_USE_SENDER_NOT_X, F_BLANK_KEYMENU, -diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.fromheader/pith/pine.hlp -*** alpine-2.21/pith/pine.hlp Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fromheader/pith/pine.hlp Sun Feb 5 16:15:24 2017 +diff -rc alpine-2.22/pith/pine.hlp alpine-2.22.fromheader/pith/pine.hlp +*** alpine-2.22/pith/pine.hlp 2020-01-19 01:32:19.035498584 -0700 +--- alpine-2.22.fromheader/pith/pine.hlp 2020-01-19 01:34:53.931466081 -0700 *************** -*** 28940,28945 **** ---- 28940,28961 ---- +*** 29530,29535 **** +--- 29530,29551 ---- <End of help on this topic> @@ -106,9 +106,9 @@ diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.fromheader/pith/pine.hlp ====== h_config_use_sender_not_x ===== -diff -rc alpine-2.21/pith/send.c alpine-2.21.fromheader/pith/send.c -*** alpine-2.21/pith/send.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fromheader/pith/send.c Sun Feb 5 16:15:24 2017 +diff -rc alpine-2.22/pith/send.c alpine-2.22.fromheader/pith/send.c +*** alpine-2.22/pith/send.c 2020-01-19 01:32:18.956500171 -0700 +--- alpine-2.22.fromheader/pith/send.c 2020-01-19 01:34:53.934466058 -0700 *************** *** 53,59 **** /* name::type::canedit::writehdr::localcopy::rcptto */ @@ -127,25 +127,25 @@ diff -rc alpine-2.21/pith/send.c alpine-2.21.fromheader/pith/send.c {TONAME, Address, 1, 1, 1, 1}, {CCNAME, Address, 1, 1, 1, 1}, *************** -*** 1232,1238 **** - *p = *(p+4); +*** 1227,1233 **** + } pf->type = pf_template[i].type; ! pf->canedit = pf_template[i].canedit; pf->rcptto = pf_template[i].rcptto; pf->writehdr = pf_template[i].writehdr; pf->localcopy = pf_template[i].localcopy; ---- 1232,1238 ---- - *p = *(p+4); +--- 1227,1233 ---- + } pf->type = pf_template[i].type; ! pf->canedit = (i == N_FROM) ? CAN_EDIT(ps_global) : pf_template[i].canedit; pf->rcptto = pf_template[i].rcptto; pf->writehdr = pf_template[i].writehdr; pf->localcopy = pf_template[i].localcopy; -diff -rc alpine-2.21/pith/send.h alpine-2.21.fromheader/pith/send.h -*** alpine-2.21/pith/send.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.fromheader/pith/send.h Sun Feb 5 16:15:24 2017 +diff -rc alpine-2.22/pith/send.h alpine-2.22.fromheader/pith/send.h +*** alpine-2.22/pith/send.h 2020-01-19 01:32:19.354492198 -0700 +--- alpine-2.22.fromheader/pith/send.h 2020-01-19 01:34:53.934466058 -0700 *************** *** 159,164 **** --- 159,166 ---- diff --git a/chappa-fromheader.txt b/chappa-fromheader.txt new file mode 100644 index 0000000..06706ae --- /dev/null +++ b/chappa-fromheader.txt @@ -0,0 +1,5 @@ +From: http://alpine.x10host.com/alpine/info/fromheader.html +Upstream: constitutes upstream source, delivered in non-tarball form + +This patch allows you to change the From header without you having to configure +anything. The From header will always be available to you. diff --git a/chappa-insertpat.patch b/chappa-insertpat.patch index 32cea62..ae38de0 100644 --- a/chappa-insertpat.patch +++ b/chappa-insertpat.patch @@ -1,6 +1,6 @@ -diff -rc alpine-2.21/pico/display.c alpine-2.21.insertpat/pico/display.c -*** alpine-2.21/pico/display.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.insertpat/pico/display.c Sun Feb 5 16:15:26 2017 +diff -rc alpine-2.22/pico/display.c alpine-2.22.insertpat/pico/display.c +*** alpine-2.22/pico/display.c 2020-01-19 01:32:18.428510798 -0700 +--- alpine-2.22.insertpat/pico/display.c 2020-01-19 01:34:56.194449394 -0700 *************** *** 2205,2210 **** --- 2205,2222 ---- @@ -22,9 +22,9 @@ diff -rc alpine-2.21/pico/display.c alpine-2.21.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.21/pico/search.c alpine-2.21.insertpat/pico/search.c -*** alpine-2.21/pico/search.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.insertpat/pico/search.c Sun Feb 5 16:15:26 2017 +diff -rc alpine-2.22/pico/search.c alpine-2.22.insertpat/pico/search.c +*** alpine-2.22/pico/search.c 2020-01-19 01:32:18.347512428 -0700 +--- alpine-2.22.insertpat/pico/search.c 2020-01-19 01:34:56.195449387 -0700 *************** *** 122,127 **** --- 122,131 ---- diff --git a/chappa-insertpat.txt b/chappa-insertpat.txt new file mode 100644 index 0000000..8caf4e0 --- /dev/null +++ b/chappa-insertpat.txt @@ -0,0 +1,7 @@ +From: http://alpine.x10host.com/alpine/info/insertpat.html +Upstream: constitutes upstream source, delivered in non-tarball form + +This patch allows you to insert the pattern that you searched last to be +edited. Say for example you wanted to look for "foo_bar", but wrote mistakenly +"foo-bar" instead, then pressing ^W to search and then ^N you will make appear +in your input "foo-bar" from where you can now easily switch "-" to "_". diff --git a/chappa-maildir.patch b/chappa-maildir.patch index feaf3fe..620fbc0 100644 --- a/chappa-maildir.patch +++ b/chappa-maildir.patch @@ -1,164 +1,9 @@ -diff -rc alpine-2.21/README.maildir alpine-2.21.maildir/README.maildir -*** alpine-2.21/README.maildir Sun Feb 5 16:15:21 2017 ---- alpine-2.21.maildir/README.maildir Sun Feb 5 16:15:21 2017 +diff -rc alpine-2.22/alpine/alpine.c alpine-2.22.maildir/alpine/alpine.c +*** alpine-2.22/alpine/alpine.c 2020-01-19 01:32:20.090477474 -0700 +--- alpine-2.22.maildir/alpine/alpine.c 2020-01-19 01:34:47.848512457 -0700 *************** -*** 0 **** ---- 1,149 ---- -+ --------------------------------------- -+ -+ Maildir Driver for Alpine 2.0 -+ By Eduardo Chappa -+ -+ -+ --------------------------------------- -+ 1. General Information About This Patch -+ --------------------------------------- -+ -+ This patch adds support for the maildir format to Alpine. We take the -+ approach that this patch is one more driver among the number of formats -+ supported by Alpine (more generally c-client). This approach differs from -+ older versions of similar patches, in that once a maildir patch was -+ applied, it was assumed that all your folders would be created in the -+ maildir format. -+ -+ This patch does not assume that maildir is a preferred format, instead -+ puts maildir in equal footing with other formats (mbox, mbx, mix, etc), -+ and so a maildir folder in the mail/ collection is treated in the same way -+ as any other folder in any other format. In other words, just by reading -+ the name of a folder, or opening it, or doing any operation with it, you -+ can not know in which format the folder is. -+ -+ This implies that if you want to add a folder in the maildir format to the -+ mail/ collection, then you must add by pressing "A" in the folder list -+ collection and enter "#driver.md/mail/name_maildir_folder". -+ -+ If you only want to use maildir, however, you can do so too. In this case, -+ you must create a maildir collection. In that collection, only maildir -+ folders will be listed. If there is any folder in any other format, that -+ folder will be ignored. In another words, any folder listed there is in -+ maildir format and can be accessed through that collection, conversely, -+ any folder not listed there is not in maildir format and there is no way -+ to access it using this collection. -+ -+ In order to create a maildir collection, you could press M S L, and "A" to -+ add a collection. Fill in the required fields as follows: -+ -+ Nickname : Anything -+ Server : -+ Path : #md/relative/path/to/maildir/collection/ -+ View : -+ -+ For example, if "path" is set to "#md/mail/", then Alpine will look for your -+ maildir folders that are in ~/mail/. -+ -+ The code in this patch is mostly based in code for the unix driver plus -+ some combinations of the mh, mbx and nntp drivers for the c-client -+ library. Those drivers were designed by Mark Crispin, and bugs in this -+ code are not his bugs, but my own. -+ -+ I got all the specification for this patch from -+ http://cr.yp.to/proto/maildir.html. If you know of a place with a better -+ specification for maildir format please let me know. The method this patch -+ uses to create a unique filename for a message is one of the "old -+ fashioned" methods. I realize that this is old fashioned, but it is -+ portable, and portability is the main reason why I decided to use an old -+ fashioned method (most methods are not portable. See the word -+ "Unfortunately" in that document). -+ -+ -------------- -+ 2. Other Goals -+ -------------- -+ -+ It is intended that this code will work well with any application -+ written using the c-client library. Of paramount importance is to make the -+ associated imap server work well when the server accesses a folder in -+ Maildir format. The program mailutil should also work flawlessly with this -+ implemetation of the driver. -+ -+ It is intended that this driver be fast and stable. We intend not to -+ patch Alpine to make this driver do its work, unless such patching is for -+ fixing bugs in Alpine or to pass parameters to the driver. -+ -+ ------------------------------------------------------------------------ -+ 3. What are the known bugs of this implementation of the Maildir driver? -+ ------------------------------------------------------------------------ -+ -+ I don't know any at this time. There have been bugs before, though, but -+ I try to fix bugs as soon as they are reported. -+ -+ ---------- -+ 4. On UIDs -+ ---------- -+ -+ This patch keeps uids in the name of the file that contains the message, -+ by adding a ",u=" string to the file name to save the uid of a message. A -+ file is kept between sessions to save information on the last uid assigned -+ and its time of validity. Only one session with writing access can write -+ uids, all others must wait for the other session to assign them. The -+ session assigning uids creates a ".uidtemp" file which other sessions must -+ not disturb. -+ -+ Uid support appeared in Alpine 1.00 (snapshot 925), and is experimental, -+ please report any problems. -+ -+ ---------------------------------------------- -+ 5. Configuring Alpine and Setting up a Maildir -+ ---------------------------------------------- -+ -+ Once this approach was chosen, it implied the following: -+ -+ * This patch assumes that your INBOX is located at "$HOME/Maildir". -+ This is a directory which should have three subdirectories "cur", -+ "tmp" and "new". Mail is delivered to 'new' and read from 'cur'. I -+ have added a configuration option "maildir-location" which can be -+ used to tell Alpine where your Maildir inbox is, in case your system -+ does not use the above directory (e.g. your system may use -+ "~/.maildir"). In this case define that variable to be the name of -+ the directory where your e-mail is being delivered (e.g. -+ ".maildir"). -+ -+ * If you want to use the above configuration as your inbox, you must -+ define your inbox-path as "#md/inbox" (no quotes). You can define -+ the inbox-path like above even if you have changed the -+ maildir-location variable. That's the whole point of that variable. -+ -+ ------------------------------------------- -+ 6. What about Courier/Dovecot file systems? -+ ------------------------------------------- -+ -+ In a courier file system all folders are subfolders of a root folder -+ called INBOX. Normally INBOX is located at ~/Maildir and subfolders are -+ "dot" directories in ~/Maildir. For example ~/Maildir/.Trash is a -+ subfolder of INBOX and is accessed with the nickname "INBOX.Trash". -+ -+ You can not access folders in this way unless you preceed them with the -+ string "#mc/". The purpose of the string "#mc/" is to warn Alpine that a -+ collection in the Courier format is going to be accessed. Therefore, you -+ can SELECT a folder like "#mc/INBOX.Trash", but not "INBOX.Trash" -+ -+ You can access a collection through a server, but if you want to access a -+ collection of folders created using the Courier server, you MUST edit your -+ ".pinerc" file and enter the definition of the collection as follows: -+ -+ folder-collections="Anything you want" #mc/INBOX.[] -+ -+ You can replace the string "#mc/INBOX." by something different, for example -+ "#mc/Courier/." will make Alpine search for your collection in ~/Courier. -+ -+ You can not add this setting directly into Alpine because Alpine fails to -+ accept this value from its input, but it takes it correctly when it is -+ added through the ".pinerc" file. -+ -+ You can access your inbox as "#mc/INBOX" or "#md/INBOX". Both definitions -+ point to the same place. -+ -+ Last Updated May 28, 2011 -diff -rc alpine-2.21/alpine/alpine.c alpine-2.21.maildir/alpine/alpine.c -*** alpine-2.21/alpine/alpine.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.maildir/alpine/alpine.c Sun Feb 5 16:15:20 2017 -*************** -*** 576,581 **** ---- 576,586 ---- +*** 591,596 **** +--- 591,601 ---- if(F_ON(F_MAILDROPS_PRESERVE_STATE, ps_global)) mail_parameters(NULL, SET_SNARFPRESERVE, (void *) TRUE); @@ -170,12 +15,12 @@ diff -rc alpine-2.21/alpine/alpine.c alpine-2.21.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.21/alpine/confscroll.c alpine-2.21.maildir/alpine/confscroll.c -*** alpine-2.21/alpine/confscroll.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.maildir/alpine/confscroll.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/alpine/confscroll.c alpine-2.22.maildir/alpine/confscroll.c +*** alpine-2.22/alpine/confscroll.c 2020-01-19 01:32:20.190475483 -0700 +--- alpine-2.22.maildir/alpine/confscroll.c 2020-01-19 01:34:47.850512441 -0700 *************** -*** 5545,5550 **** ---- 5545,5556 ---- +*** 5557,5562 **** +--- 5557,5568 ---- (void *)var->current_val.p); } #endif @@ -188,11 +33,11 @@ diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.maildir/alpine/confscroll.c else if(revert && standard_radio_var(ps, var)){ cur_rule_value(var, TRUE, FALSE); -diff -rc alpine-2.21/imap/src/c-client/mail.c alpine-2.21.maildir/imap/src/c-client/mail.c -*** alpine-2.21/imap/src/c-client/mail.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.maildir/imap/src/c-client/mail.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/imap/src/c-client/mail.c alpine-2.22.maildir/imap/src/c-client/mail.c +*** alpine-2.22/imap/src/c-client/mail.c 2020-01-19 01:32:23.162416684 -0700 +--- alpine-2.22.maildir/imap/src/c-client/mail.c 2020-01-19 01:34:48.243509380 -0700 *************** -*** 1017,1023 **** +*** 1046,1052 **** MAILSTREAM *ts; char *s,*t,tmp[MAILTMPLEN]; size_t i; @@ -200,7 +45,7 @@ diff -rc alpine-2.21/imap/src/c-client/mail.c alpine-2.21.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); ---- 1017,1023 ---- +--- 1046,1052 ---- MAILSTREAM *ts; char *s,*t,tmp[MAILTMPLEN]; size_t i; @@ -209,8 +54,8 @@ diff -rc alpine-2.21/imap/src/c-client/mail.c alpine-2.21.maildir/imap/src/c-cli if ((s = strpbrk (mailbox,"\015\012")) != NULL) { MM_LOG ("Can't create mailbox with such a name",ERROR); *************** -*** 1041,1046 **** ---- 1041,1048 ---- +*** 1070,1075 **** +--- 1070,1077 ---- return NIL; } @@ -220,8 +65,8 @@ diff -rc alpine-2.21/imap/src/c-client/mail.c alpine-2.21.maildir/imap/src/c-cli if ((mailbox[0] == '#') && ((mailbox[1] == 'd') || (mailbox[1] == 'D')) && ((mailbox[2] == 'r') || (mailbox[2] == 'R')) && *************** -*** 1071,1076 **** ---- 1073,1085 ---- +*** 1100,1105 **** +--- 1102,1114 ---- (((*mailbox == '{') || (*mailbox == '#')) && (stream = mail_open (NIL,mailbox,OP_PROTOTYPE | OP_SILENT)))) d = stream->dtb; @@ -235,12 +80,12 @@ diff -rc alpine-2.21/imap/src/c-client/mail.c alpine-2.21.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.21/imap/src/c-client/mail.h alpine-2.21.maildir/imap/src/c-client/mail.h -*** alpine-2.21/imap/src/c-client/mail.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.maildir/imap/src/c-client/mail.h Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/imap/src/c-client/mail.h alpine-2.22.maildir/imap/src/c-client/mail.h +*** alpine-2.22/imap/src/c-client/mail.h 2020-01-19 01:32:23.166416605 -0700 +--- alpine-2.22.maildir/imap/src/c-client/mail.h 2020-01-19 01:34:48.244509372 -0700 *************** -*** 366,371 **** ---- 366,375 ---- +*** 374,379 **** +--- 374,383 ---- #define SET_SCANCONTENTS (long) 573 #define GET_MHALLOWINBOX (long) 574 #define SET_MHALLOWINBOX (long) 575 @@ -251,80 +96,9 @@ diff -rc alpine-2.21/imap/src/c-client/mail.h alpine-2.21.maildir/imap/src/c-cli /* Driver flags */ -diff -rc alpine-2.21/imap/src/osdep/unix/Makefile alpine-2.21.maildir/imap/src/osdep/unix/Makefile -*** alpine-2.21/imap/src/osdep/unix/Makefile Sun Feb 5 16:02:36 2017 ---- alpine-2.21.maildir/imap/src/osdep/unix/Makefile Sun Feb 5 16:15:20 2017 -*************** -*** 147,153 **** - # However, mh needs to be before any sysinbox formats (such as mmdf or unix) - # since otherwise INBOX won't work correctly when mh_allow_inbox is set. - # -! DEFAULTDRIVERS=imap nntp pop3 mix mx mbx tenex mtx mh mmdf unix news phile - CHUNKSIZE=65536 - - # Normally no need to change any of these ---- 147,153 ---- - # However, mh needs to be before any sysinbox formats (such as mmdf or unix) - # since otherwise INBOX won't work correctly when mh_allow_inbox is set. - # -! DEFAULTDRIVERS=maildir courier imap nntp pop3 mix mx mbx tenex mtx mh mmdf unix news phile - CHUNKSIZE=65536 - - # Normally no need to change any of these -*************** -*** 156,162 **** - BINARIES=osdep.o mail.o misc.o newsrc.o smanager.o utf8.o utf8aux.o siglocal.o \ - dummy.o pseudo.o netmsg.o flstring.o fdstring.o \ - rfc822.o nntp.o smtp.o imap4r1.o pop3.o \ -! unix.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o mix.o - CFLAGS=-g - - CAT=cat ---- 156,162 ---- - BINARIES=osdep.o mail.o misc.o newsrc.o smanager.o utf8.o utf8aux.o siglocal.o \ - dummy.o pseudo.o netmsg.o flstring.o fdstring.o \ - rfc822.o nntp.o smtp.o imap4r1.o pop3.o \ -! unix.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o mix.o maildir.o - CFLAGS=-g - - CAT=cat -*************** -*** 293,299 **** - - cyg: # Cygwin - note that most local file drivers don't work!! - $(BUILD) `$(CAT) SPECIALS` OS=$@ \ -! DEFAULTDRIVERS="imap nntp pop3 mbx unix phile" \ - SIGTYPE=psx CHECKPW=cyg LOGINPW=cyg CRXTYPE=std \ - SPOOLDIR=/var \ - ACTIVEFILE=/usr/local/news/lib/active \ ---- 293,299 ---- - - cyg: # Cygwin - note that most local file drivers don't work!! - $(BUILD) `$(CAT) SPECIALS` OS=$@ \ -! DEFAULTDRIVERS="imap nntp pop3 mbx unix maildir phile" \ - SIGTYPE=psx CHECKPW=cyg LOGINPW=cyg CRXTYPE=std \ - SPOOLDIR=/var \ - ACTIVEFILE=/usr/local/news/lib/active \ -*************** -*** 911,917 **** - unix.o: mail.h misc.h osdep.h unix.h pseudo.h dummy.h - utf8.o: mail.h misc.h osdep.h utf8.h tmap.c widths.c - utf8aux.o: mail.h misc.h osdep.h utf8.h -! - - # OS-dependent - ---- 911,917 ---- - unix.o: mail.h misc.h osdep.h unix.h pseudo.h dummy.h - utf8.o: mail.h misc.h osdep.h utf8.h tmap.c widths.c - utf8aux.o: mail.h misc.h osdep.h utf8.h -! maildir.o: mail.h misc.h osdep.h maildir.h dummy.h - - # OS-dependent - -diff -rc alpine-2.21/imap/src/osdep/unix/dummy.c alpine-2.21.maildir/imap/src/osdep/unix/dummy.c -*** alpine-2.21/imap/src/osdep/unix/dummy.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.maildir/imap/src/osdep/unix/dummy.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/imap/src/osdep/unix/dummy.c alpine-2.22.maildir/imap/src/osdep/unix/dummy.c +*** alpine-2.22/imap/src/osdep/unix/dummy.c 2020-01-19 01:32:22.660426553 -0700 +--- alpine-2.22.maildir/imap/src/osdep/unix/dummy.c 2020-01-19 01:34:48.245509364 -0700 *************** *** 103,115 **** * Accepts: mailbox name @@ -479,16 +253,16 @@ diff -rc alpine-2.21/imap/src/osdep/unix/dummy.c alpine-2.21.maildir/imap/src/os return T; /* return success */ } -diff -rc alpine-2.21/imap/src/osdep/unix/maildir.c alpine-2.21.maildir/imap/src/osdep/unix/maildir.c -*** alpine-2.21/imap/src/osdep/unix/maildir.c Sun Feb 5 16:15:21 2017 ---- alpine-2.21.maildir/imap/src/osdep/unix/maildir.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/imap/src/osdep/unix/maildir.c alpine-2.22.maildir/imap/src/osdep/unix/maildir.c +*** alpine-2.22/imap/src/osdep/unix/maildir.c 2020-01-19 01:34:48.437507873 -0700 +--- alpine-2.22.maildir/imap/src/osdep/unix/maildir.c 2020-01-19 01:34:48.249509333 -0700 *************** *** 0 **** --- 1,2671 ---- + /* + * Maildir driver for Alpine 2.20 + * -+ * Written by Eduardo Chappa ++ * Written by Eduardo Chappa + * Last Update: June 10, 2014 + * + */ @@ -3156,9 +2930,9 @@ diff -rc alpine-2.21/imap/src/osdep/unix/maildir.c alpine-2.21.maildir/imap/src/ + LOCAL->uidtempfile = cpystr(tmp); + } + } -diff -rc alpine-2.21/imap/src/osdep/unix/maildir.h alpine-2.21.maildir/imap/src/osdep/unix/maildir.h -*** alpine-2.21/imap/src/osdep/unix/maildir.h Sun Feb 5 16:15:21 2017 ---- alpine-2.21.maildir/imap/src/osdep/unix/maildir.h Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/imap/src/osdep/unix/maildir.h alpine-2.22.maildir/imap/src/osdep/unix/maildir.h +*** alpine-2.22/imap/src/osdep/unix/maildir.h 2020-01-19 01:34:48.439507857 -0700 +--- alpine-2.22.maildir/imap/src/osdep/unix/maildir.h 2020-01-19 01:34:48.250509325 -0700 *************** *** 0 **** --- 1,226 ---- @@ -3388,9 +3162,73 @@ diff -rc alpine-2.21/imap/src/osdep/unix/maildir.h alpine-2.21.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.21/imap/src/osdep/unix/os_cyg.h alpine-2.21.maildir/imap/src/osdep/unix/os_cyg.h -*** alpine-2.21/imap/src/osdep/unix/os_cyg.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.maildir/imap/src/osdep/unix/os_cyg.h Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/imap/src/osdep/unix/Makefile alpine-2.22.maildir/imap/src/osdep/unix/Makefile +*** alpine-2.22/imap/src/osdep/unix/Makefile 2020-01-19 01:32:22.615427440 -0700 +--- alpine-2.22.maildir/imap/src/osdep/unix/Makefile 2020-01-19 01:34:48.250509325 -0700 +*************** +*** 147,153 **** + # However, mh needs to be before any sysinbox formats (such as mmdf or unix) + # since otherwise INBOX won't work correctly when mh_allow_inbox is set. + # +! DEFAULTDRIVERS=imap nntp pop3 mix mx mbx tenex mtx mh mmdf unix news phile + CHUNKSIZE=65536 + + # Normally no need to change any of these +--- 147,153 ---- + # However, mh needs to be before any sysinbox formats (such as mmdf or unix) + # since otherwise INBOX won't work correctly when mh_allow_inbox is set. + # +! DEFAULTDRIVERS=maildir courier imap nntp pop3 mix mx mbx tenex mtx mh mmdf unix news phile + CHUNKSIZE=65536 + + # Normally no need to change any of these +*************** +*** 156,162 **** + BINARIES=osdep.o mail.o misc.o newsrc.o smanager.o utf8.o utf8aux.o siglocal.o \ + dummy.o pseudo.o netmsg.o flstring.o fdstring.o \ + rfc822.o nntp.o smtp.o imap4r1.o http.o json.o pop3.o \ +! unix.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o mix.o + CFLAGS=-g + + CAT=cat +--- 156,162 ---- + BINARIES=osdep.o mail.o misc.o newsrc.o smanager.o utf8.o utf8aux.o siglocal.o \ + dummy.o pseudo.o netmsg.o flstring.o fdstring.o \ + rfc822.o nntp.o smtp.o imap4r1.o http.o json.o pop3.o \ +! unix.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o mix.o maildir.o + CFLAGS=-g + + CAT=cat +*************** +*** 293,299 **** + + cyg: # Cygwin - note that most local file drivers don't work!! + $(BUILD) `$(CAT) SPECIALS` OS=$@ \ +! DEFAULTDRIVERS="imap nntp pop3 mbx unix phile" \ + SIGTYPE=psx CHECKPW=cyg LOGINPW=cyg CRXTYPE=std \ + SPOOLDIR=/var \ + ACTIVEFILE=/usr/local/news/lib/active \ +--- 293,299 ---- + + cyg: # Cygwin - note that most local file drivers don't work!! + $(BUILD) `$(CAT) SPECIALS` OS=$@ \ +! DEFAULTDRIVERS="imap nntp pop3 mbx unix maildir phile" \ + SIGTYPE=psx CHECKPW=cyg LOGINPW=cyg CRXTYPE=std \ + SPOOLDIR=/var \ + ACTIVEFILE=/usr/local/news/lib/active \ +*************** +*** 922,927 **** +--- 922,928 ---- + utf8aux.o: mail.h misc.h osdep.h utf8.h + json.o: mail.h misc.h osdep.h utf8.h json.h + http.o: mail.h misc.h osdep.h utf8.h http.h json.h ++ maildir.o: mail.h misc.h osdep.h maildir.h dummy.h + + # OS-dependent + +diff -rc alpine-2.22/imap/src/osdep/unix/os_cyg.h alpine-2.22.maildir/imap/src/osdep/unix/os_cyg.h +*** alpine-2.22/imap/src/osdep/unix/os_cyg.h 2020-01-19 01:32:22.664426475 -0700 +--- alpine-2.22.maildir/imap/src/osdep/unix/os_cyg.h 2020-01-19 01:34:48.251509318 -0700 *************** *** 47,52 **** --- 47,53 ---- @@ -3401,12 +3239,12 @@ diff -rc alpine-2.21/imap/src/osdep/unix/os_cyg.h alpine-2.21.maildir/imap/src/o #define geteuid Geteuid uid_t Geteuid (void); -diff -rc alpine-2.21/pith/conf.c alpine-2.21.maildir/pith/conf.c -*** alpine-2.21/pith/conf.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.maildir/pith/conf.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/conf.c alpine-2.22.maildir/pith/conf.c +*** alpine-2.22/pith/conf.c 2020-01-19 01:32:18.678505766 -0700 +--- alpine-2.22.maildir/pith/conf.c 2020-01-19 01:34:48.253509302 -0700 *************** -*** 438,443 **** ---- 438,446 ---- +*** 443,448 **** +--- 443,451 ---- CONF_TXT_T cf_text_newsrc_path[] = "Full path and name of NEWSRC file"; @@ -3417,8 +3255,8 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.maildir/pith/conf.c /*---------------------------------------------------------------------- These are the variables that control a number of pine functions. They *************** -*** 644,649 **** ---- 647,656 ---- +*** 649,654 **** +--- 652,661 ---- NULL, cf_text_news_active}, {"news-spool-directory", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, NULL, cf_text_news_spooldir}, @@ -3430,8 +3268,8 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.maildir/pith/conf.c NULL, cf_text_upload_cmd}, {"upload-command-prefix", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, *************** -*** 2301,2306 **** ---- 2308,2319 ---- +*** 2322,2327 **** +--- 2329,2340 ---- mail_parameters(NULL, SET_NEWSSPOOL, (void *)VAR_NEWS_SPOOL_DIR); @@ -3445,8 +3283,8 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.maildir/pith/conf.c set_current_val(&vars[V_DEFAULT_SAVE_FOLDER], TRUE, TRUE); if(!VAR_DEFAULT_SAVE_FOLDER || !VAR_DEFAULT_SAVE_FOLDER[0]) *************** -*** 2930,2935 **** ---- 2943,2952 ---- +*** 2954,2959 **** +--- 2967,2976 ---- 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}, @@ -3458,7 +3296,7 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.maildir/pith/conf.c /* Addr book */ {"combined-addrbook-display", "Combined Address Book Display", *************** -*** 7036,7042 **** +*** 7068,7074 **** int just_flip_value, EditWhich ew) { char **vp, *p, **lval, ***alval; @@ -3466,7 +3304,7 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.maildir/pith/conf.c char *err; long l; ---- 7053,7059 ---- +--- 7085,7091 ---- int just_flip_value, EditWhich ew) { char **vp, *p, **lval, ***alval; @@ -3475,8 +3313,8 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.maildir/pith/conf.c long l; *************** -*** 7089,7094 **** ---- 7106,7118 ---- +*** 7121,7126 **** +--- 7138,7150 ---- break; @@ -3491,8 +3329,8 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.maildir/pith/conf.c case F_DATES_TO_LOCAL : clear_index_cache(ps->mail_stream, 0); *************** -*** 7877,7882 **** ---- 7901,7910 ---- +*** 7911,7916 **** +--- 7935,7944 ---- return(h_config_newmailwidth); case V_NEWSRC_PATH : return(h_config_newsrc_path); @@ -3503,9 +3341,9 @@ diff -rc alpine-2.21/pith/conf.c alpine-2.21.maildir/pith/conf.c case V_BROWSER : return(h_config_browser); case V_HISTORY : -diff -rc alpine-2.21/pith/conf.h alpine-2.21.maildir/pith/conf.h -*** alpine-2.21/pith/conf.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.maildir/pith/conf.h Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/conf.h alpine-2.22.maildir/pith/conf.h +*** alpine-2.22/pith/conf.h 2020-01-19 01:32:19.489489496 -0700 +--- alpine-2.22.maildir/pith/conf.h 2020-01-19 01:34:48.277509116 -0700 *************** *** 256,261 **** --- 256,265 ---- @@ -3519,9 +3357,9 @@ diff -rc alpine-2.21/pith/conf.h alpine-2.21.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.21/pith/conftype.h alpine-2.21.maildir/pith/conftype.h -*** alpine-2.21/pith/conftype.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.maildir/pith/conftype.h Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/conftype.h alpine-2.22.maildir/pith/conftype.h +*** alpine-2.22/pith/conftype.h 2020-01-19 01:32:18.702505283 -0700 +--- alpine-2.22.maildir/pith/conftype.h 2020-01-19 01:34:48.278509108 -0700 *************** *** 119,124 **** --- 119,127 ---- @@ -3535,8 +3373,8 @@ diff -rc alpine-2.21/pith/conftype.h alpine-2.21.maildir/pith/conftype.h , V_UPLOAD_CMD_PREFIX , V_DOWNLOAD_CMD *************** -*** 395,400 **** ---- 398,406 ---- +*** 400,405 **** +--- 403,411 ---- F_PASS_C1_CONTROL_CHARS, F_SINGLE_FOLDER_LIST, F_VERTICAL_FOLDER_LIST, @@ -3546,9 +3384,9 @@ diff -rc alpine-2.21/pith/conftype.h alpine-2.21.maildir/pith/conftype.h F_TAB_CHK_RECENT, F_AUTO_REPLY_TO, F_VERBOSE_POST, -diff -rc alpine-2.21/pith/init.c alpine-2.21.maildir/pith/init.c -*** alpine-2.21/pith/init.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.maildir/pith/init.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/init.c alpine-2.22.maildir/pith/init.c +*** alpine-2.22/pith/init.c 2020-01-19 01:32:18.764504035 -0700 +--- alpine-2.22.maildir/pith/init.c 2020-01-19 01:34:48.278509108 -0700 *************** *** 408,413 **** --- 408,416 ---- @@ -3561,9 +3399,9 @@ diff -rc alpine-2.21/pith/init.c alpine-2.21.maildir/pith/init.c && strcmp(filename, folder_base)){ #endif #endif -diff -rc alpine-2.21/pith/pattern.c alpine-2.21.maildir/pith/pattern.c -*** alpine-2.21/pith/pattern.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.maildir/pith/pattern.c Sun Feb 5 16:15:20 2017 +diff -rc alpine-2.22/pith/pattern.c alpine-2.22.maildir/pith/pattern.c +*** alpine-2.22/pith/pattern.c 2020-01-19 01:32:19.260494080 -0700 +--- alpine-2.22.maildir/pith/pattern.c 2020-01-19 01:34:48.281509085 -0700 *************** *** 49,55 **** #include "../pith/icache.h" @@ -3651,12 +3489,12 @@ diff -rc alpine-2.21/pith/pattern.c alpine-2.21.maildir/pith/pattern.c return(buf[0] != '\0'); } -diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.maildir/pith/pine.hlp -*** alpine-2.21/pith/pine.hlp Sun Feb 5 16:02:36 2017 ---- alpine-2.21.maildir/pith/pine.hlp Sun Feb 5 16:15:21 2017 +diff -rc alpine-2.22/pith/pine.hlp alpine-2.22.maildir/pith/pine.hlp +*** alpine-2.22/pith/pine.hlp 2020-01-19 01:32:19.035498584 -0700 +--- alpine-2.22.maildir/pith/pine.hlp 2020-01-19 01:34:48.306508890 -0700 *************** -*** 22364,22369 **** ---- 22364,22465 ---- +*** 22897,22902 **** +--- 22897,22998 ---- <End of help on this topic> @@ -3760,8 +3598,8 @@ diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.maildir/pith/pine.hlp *************** -*** 30446,30451 **** ---- 30542,30590 ---- +*** 31036,31041 **** +--- 31132,31180 ----

    <End of help on this topic> @@ -3811,9 +3649,9 @@ diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.maildir/pith/pine.hlp ====== h_config_verbose_post ===== -diff -rc alpine-2.21/pith/send.c alpine-2.21.maildir/pith/send.c -*** alpine-2.21/pith/send.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.maildir/pith/send.c Sun Feb 5 16:15:21 2017 +diff -rc alpine-2.22/pith/send.c alpine-2.22.maildir/pith/send.c +*** alpine-2.22/pith/send.c 2020-01-19 01:32:18.956500171 -0700 +--- alpine-2.22.maildir/pith/send.c 2020-01-19 01:34:48.420508005 -0700 *************** *** 47,52 **** --- 47,55 ---- @@ -3827,8 +3665,8 @@ diff -rc alpine-2.21/pith/send.c alpine-2.21.maildir/pith/send.c /* this is used in pine_send and pine_simple_send */ *************** -*** 257,262 **** ---- 260,272 ---- +*** 250,255 **** +--- 253,265 ---- if(exists & FEX_ISFILE){ context_apply(tmp, p_cntxt, mbox, sizeof(tmp)); @@ -3842,3 +3680,158 @@ diff -rc alpine-2.21/pith/send.c alpine-2.21.maildir/pith/send.c if(!(IS_REMOTE(tmp) || is_absolute_path(tmp))){ /* * The mbox is relative to the home directory. +diff -rc alpine-2.22/README.maildir alpine-2.22.maildir/README.maildir +*** alpine-2.22/README.maildir 2020-01-19 01:34:48.441507842 -0700 +--- alpine-2.22.maildir/README.maildir 2020-01-19 01:34:48.421507997 -0700 +*************** +*** 0 **** +--- 1,149 ---- ++ --------------------------------------- ++ ++ Maildir Driver for Alpine 2.0 ++ By Eduardo Chappa ++ ++ ++ --------------------------------------- ++ 1. General Information About This Patch ++ --------------------------------------- ++ ++ This patch adds support for the maildir format to Alpine. We take the ++ approach that this patch is one more driver among the number of formats ++ supported by Alpine (more generally c-client). This approach differs from ++ older versions of similar patches, in that once a maildir patch was ++ applied, it was assumed that all your folders would be created in the ++ maildir format. ++ ++ This patch does not assume that maildir is a preferred format, instead ++ puts maildir in equal footing with other formats (mbox, mbx, mix, etc), ++ and so a maildir folder in the mail/ collection is treated in the same way ++ as any other folder in any other format. In other words, just by reading ++ the name of a folder, or opening it, or doing any operation with it, you ++ can not know in which format the folder is. ++ ++ This implies that if you want to add a folder in the maildir format to the ++ mail/ collection, then you must add by pressing "A" in the folder list ++ collection and enter "#driver.md/mail/name_maildir_folder". ++ ++ If you only want to use maildir, however, you can do so too. In this case, ++ you must create a maildir collection. In that collection, only maildir ++ folders will be listed. If there is any folder in any other format, that ++ folder will be ignored. In another words, any folder listed there is in ++ maildir format and can be accessed through that collection, conversely, ++ any folder not listed there is not in maildir format and there is no way ++ to access it using this collection. ++ ++ In order to create a maildir collection, you could press M S L, and "A" to ++ add a collection. Fill in the required fields as follows: ++ ++ Nickname : Anything ++ Server : ++ Path : #md/relative/path/to/maildir/collection/ ++ View : ++ ++ For example, if "path" is set to "#md/mail/", then Alpine will look for your ++ maildir folders that are in ~/mail/. ++ ++ The code in this patch is mostly based in code for the unix driver plus ++ some combinations of the mh, mbx and nntp drivers for the c-client ++ library. Those drivers were designed by Mark Crispin, and bugs in this ++ code are not his bugs, but my own. ++ ++ I got all the specification for this patch from ++ http://cr.yp.to/proto/maildir.html. If you know of a place with a better ++ specification for maildir format please let me know. The method this patch ++ uses to create a unique filename for a message is one of the "old ++ fashioned" methods. I realize that this is old fashioned, but it is ++ portable, and portability is the main reason why I decided to use an old ++ fashioned method (most methods are not portable. See the word ++ "Unfortunately" in that document). ++ ++ -------------- ++ 2. Other Goals ++ -------------- ++ ++ It is intended that this code will work well with any application ++ written using the c-client library. Of paramount importance is to make the ++ associated imap server work well when the server accesses a folder in ++ Maildir format. The program mailutil should also work flawlessly with this ++ implemetation of the driver. ++ ++ It is intended that this driver be fast and stable. We intend not to ++ patch Alpine to make this driver do its work, unless such patching is for ++ fixing bugs in Alpine or to pass parameters to the driver. ++ ++ ------------------------------------------------------------------------ ++ 3. What are the known bugs of this implementation of the Maildir driver? ++ ------------------------------------------------------------------------ ++ ++ I don't know any at this time. There have been bugs before, though, but ++ I try to fix bugs as soon as they are reported. ++ ++ ---------- ++ 4. On UIDs ++ ---------- ++ ++ This patch keeps uids in the name of the file that contains the message, ++ by adding a ",u=" string to the file name to save the uid of a message. A ++ file is kept between sessions to save information on the last uid assigned ++ and its time of validity. Only one session with writing access can write ++ uids, all others must wait for the other session to assign them. The ++ session assigning uids creates a ".uidtemp" file which other sessions must ++ not disturb. ++ ++ Uid support appeared in Alpine 1.00 (snapshot 925), and is experimental, ++ please report any problems. ++ ++ ---------------------------------------------- ++ 5. Configuring Alpine and Setting up a Maildir ++ ---------------------------------------------- ++ ++ Once this approach was chosen, it implied the following: ++ ++ * This patch assumes that your INBOX is located at "$HOME/Maildir". ++ This is a directory which should have three subdirectories "cur", ++ "tmp" and "new". Mail is delivered to 'new' and read from 'cur'. I ++ have added a configuration option "maildir-location" which can be ++ used to tell Alpine where your Maildir inbox is, in case your system ++ does not use the above directory (e.g. your system may use ++ "~/.maildir"). In this case define that variable to be the name of ++ the directory where your e-mail is being delivered (e.g. ++ ".maildir"). ++ ++ * If you want to use the above configuration as your inbox, you must ++ define your inbox-path as "#md/inbox" (no quotes). You can define ++ the inbox-path like above even if you have changed the ++ maildir-location variable. That's the whole point of that variable. ++ ++ ------------------------------------------- ++ 6. What about Courier/Dovecot file systems? ++ ------------------------------------------- ++ ++ In a courier file system all folders are subfolders of a root folder ++ called INBOX. Normally INBOX is located at ~/Maildir and subfolders are ++ "dot" directories in ~/Maildir. For example ~/Maildir/.Trash is a ++ subfolder of INBOX and is accessed with the nickname "INBOX.Trash". ++ ++ You can not access folders in this way unless you preceed them with the ++ string "#mc/". The purpose of the string "#mc/" is to warn Alpine that a ++ collection in the Courier format is going to be accessed. Therefore, you ++ can SELECT a folder like "#mc/INBOX.Trash", but not "INBOX.Trash" ++ ++ You can access a collection through a server, but if you want to access a ++ collection of folders created using the Courier server, you MUST edit your ++ ".pinerc" file and enter the definition of the collection as follows: ++ ++ folder-collections="Anything you want" #mc/INBOX.[] ++ ++ You can replace the string "#mc/INBOX." by something different, for example ++ "#mc/Courier/." will make Alpine search for your collection in ~/Courier. ++ ++ You can not add this setting directly into Alpine because Alpine fails to ++ accept this value from its input, but it takes it correctly when it is ++ added through the ".pinerc" file. ++ ++ You can access your inbox as "#mc/INBOX" or "#md/INBOX". Both definitions ++ point to the same place. ++ ++ Last Updated May 28, 2011 diff --git a/chappa-maildir.txt b/chappa-maildir.txt new file mode 100644 index 0000000..3bb4d57 --- /dev/null +++ b/chappa-maildir.txt @@ -0,0 +1,11 @@ +From: http://alpine.x10host.com/alpine/info/maildir.html +Upstream: constitutes upstream source, delivered in non-tarball form + +I have added support for the Courier/Cyrus/Dovecot file system, read the configuration instructions. + +This patch assumes that your INBOX is located at "$HOME/Maildir". This is a +directory which should have three subdirectories "cur", "tmp" and "new". If you +read maildir from another directory in your $HOME directory (e.g. .maildir), +then set the variable maildir-location to reflect this fact (e.g. +maildir-location=.maildir). This is the best way to change the path of the +inbox. Set Inbox Path = #md/INBOX. diff --git a/chappa-rules.patch b/chappa-rules.patch index 90eadd8..cd1b8e6 100644 --- a/chappa-rules.patch +++ b/chappa-rules.patch @@ -1,6242 +1,5877 @@ -diff -rc alpine-2.21/alpine/adrbkcmd.c alpine-2.21.rules/alpine/adrbkcmd.c -*** alpine-2.21/alpine/adrbkcmd.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/alpine/adrbkcmd.c Sun Feb 5 16:15:21 2017 -*************** -*** 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{ -*************** -*** 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); -diff -rc alpine-2.21/alpine/alpine.c alpine-2.21.rules/alpine/alpine.c -*** alpine-2.21/alpine/alpine.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/alpine/alpine.c Sun Feb 5 16:15:21 2017 -*************** -*** 485,490 **** ---- 485,491 ---- - /* 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){ -*************** -*** 3162,3167 **** ---- 3163,3171 ---- - extern KBESC_T *kbesc; - - dprint((2, "goodnight_gracey:\n")); -+ strncpy(pine_state->cur_folder, pine_state->inbox_name, -+ sizeof(pine_state->cur_folder)); -+ pine_state->cur_folder[sizeof(pine_state->cur_folder) - 1] = '\0'; - - /* We want to do this here before we close up the streams */ - trim_remote_adrbks(); -diff -rc alpine-2.21/alpine/confscroll.c alpine-2.21.rules/alpine/confscroll.c -*** alpine-2.21/alpine/confscroll.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/alpine/confscroll.c Sun Feb 5 16:15:21 2017 -*************** -*** 51,56 **** ---- 51,57 ---- - #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") -*************** -*** 2436,2441 **** ---- 2437,2445 ---- - * 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); - -*************** -*** 5200,5205 **** ---- 5204,5233 ---- - var == &ps->vars[V_ABOOK_FORMATS]){ - addrbook_reset(); - } -+ else if(var == &ps->vars[V_INDEX_RULES]){ -+ if(ps_global->rule_list) -+ free_parsed_rule_list(&ps_global->rule_list); -+ create_rule_list(ps->vars); -+ reset_index_format(); -+ clear_index_cache(ps->mail_stream, 0); -+ } -+ else if(var == &ps->vars[V_COMPOSE_RULES] || -+ var == &ps->vars[V_FORWARD_RULES] || -+ var == &ps->vars[V_KEY_RULES] || -+ var == &ps->vars[V_REPLACE_RULES] || -+ var == &ps->vars[V_REPLY_INDENT_RULES] || -+ var == &ps->vars[V_REPLY_LEADIN_RULES] || -+ var == &ps->vars[V_RESUB_RULES] || -+ var == &ps->vars[V_SAVE_RULES] || -+ var == &ps->vars[V_SMTP_RULES] || -+ var == &ps->vars[V_SORT_RULES] || -+ var == &ps->vars[V_STARTUP_RULES] || -+ var == &ps->vars[V_THREAD_DISP_STYLE_RULES] || -+ var == &ps->vars[V_THREAD_INDEX_STYLE_RULES]){ -+ if(ps_global->rule_list) -+ free_parsed_rule_list(&ps_global->rule_list); -+ create_rule_list(ps->vars); -+ } - else if(var == &ps->vars[V_INDEX_FORMAT]){ - reset_index_format(); - clear_index_cache(ps->mail_stream, 0); -diff -rc alpine-2.21/alpine/dispfilt.c alpine-2.21.rules/alpine/dispfilt.c -*** alpine-2.21/alpine/dispfilt.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/alpine/dispfilt.c Sun Feb 5 16:15:21 2017 -*************** -*** 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); -+ } -diff -rc alpine-2.21/alpine/dispfilt.h alpine-2.21.rules/alpine/dispfilt.h -*** alpine-2.21/alpine/dispfilt.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/alpine/dispfilt.h Sun Feb 5 16:15:21 2017 -*************** -*** 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 */ -diff -rc alpine-2.21/alpine/folder.c alpine-2.21.rules/alpine/folder.c -*** alpine-2.21/alpine/folder.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/alpine/folder.c Sun Feb 5 16:15:21 2017 -*************** -*** 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; -*************** -*** 345,350 **** ---- 345,351 ---- - pine_mail_close(*fs.cache_streamp); - - ps->prev_screen = folder_screen; -+ strcpy(ps->screen_name, "unknown"); - } - - -diff -rc alpine-2.21/alpine/mailcmd.c alpine-2.21.rules/alpine/mailcmd.c -*** alpine-2.21/alpine/mailcmd.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/alpine/mailcmd.c Sun Feb 5 16:15:21 2017 -*************** -*** 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 -*************** -*** 2657,2662 **** ---- 2658,2666 ---- - 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': -*************** -*** 2707,2718 **** - 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; ---- 2711,2722 ---- - 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; -*************** -*** 2720,2725 **** ---- 2724,2730 ---- - 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"); -*************** -*** 2729,2734 **** ---- 2734,2748 ---- - 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)) -diff -rc alpine-2.21/alpine/mailindx.c alpine-2.21.rules/alpine/mailindx.c -*** alpine-2.21/alpine/mailindx.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/alpine/mailindx.c Sun Feb 5 16:15:21 2017 -*************** -*** 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 -*************** -*** 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"); - } - - -diff -rc alpine-2.21/alpine/mailview.c alpine-2.21.rules/alpine/mailview.c -*** alpine-2.21/alpine/mailview.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/alpine/mailview.c Sun Feb 5 16:15:21 2017 -*************** -*** 243,248 **** ---- 243,250 ---- - 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")); -*************** -*** 479,484 **** ---- 481,488 ---- - } - while(ps->next_screen == SCREEN_FUN_NULL); - -+ strcpy(ps->screen_name, "unknown"); -+ - if (prefix && *prefix) - fs_give((void **)&prefix); - if(we_cancel) -diff -rc alpine-2.21/alpine/osdep/termin.gen.c alpine-2.21.rules/alpine/osdep/termin.gen.c -*** alpine-2.21/alpine/osdep/termin.gen.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/alpine/osdep/termin.gen.c Sun Feb 5 16:15:21 2017 -*************** -*** 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" -*************** -*** 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 -*************** -*** 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(); - -*************** -*** 1158,1163 **** ---- 1196,1202 ---- - if(!*ps_global->initial_cmds && ps_global->free_initial_cmds){ - fs_give((void **) &ps_global->free_initial_cmds); - ps_global->initial_cmds = NULL; -+ firsttime = (char) 1; - } - - return(ret); -diff -rc alpine-2.21/alpine/reply.c alpine-2.21.rules/alpine/reply.c -*** alpine-2.21/alpine/reply.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/alpine/reply.c Sun Feb 5 16:15:21 2017 -*************** -*** 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 -*************** -*** 109,119 **** - 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 ---- 110,121 ---- - 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 -*************** -*** 139,144 **** ---- 141,209 ---- - && 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... -*************** -*** 287,294 **** - outgoing->subject = cpystr("Re: several messages"); - } - } -! else -! outgoing->subject = reply_subject(env->subject, NULL, 0); - } - - /* fill reply header */ ---- 352,369 ---- - 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 */ -*************** -*** 307,319 **** - 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 */ ---- 382,388 ---- - 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 */ -*************** -*** 724,729 **** ---- 793,801 ---- - if(prefix) - fs_give((void **)&prefix); - -+ if (ps_global->role) -+ fs_give((void **)&ps_global->role); -+ - if(fcc) - fs_give((void **) &fcc); - -*************** -*** 1598,1606 **** - } - } - -! if(role) - q_status_message1(SM_ORDER, 3, 4, - _("Forwarding using role \"%s\""), role->nick); - - if(role && role->template){ - char *filtered; ---- 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); -+ } - - if(role && role->template){ - char *filtered; -*************** -*** 1832,1837 **** ---- 1909,1915 ---- - #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); -diff -rc alpine-2.21/alpine/roleconf.c alpine-2.21.rules/alpine/roleconf.c -*** alpine-2.21/alpine/roleconf.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/alpine/roleconf.c Sun Feb 5 16:15:21 2017 -*************** -*** 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)); - -diff -rc alpine-2.21/alpine/send.c alpine-2.21.rules/alpine/send.c -*** alpine-2.21/alpine/send.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/alpine/send.c Sun Feb 5 16:15:21 2017 -*************** -*** 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; -*************** -*** 240,245 **** ---- 240,250 ---- - 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); -*************** -*** 449,456 **** - - ps_global->next_screen = prev_screen; - ps_global->redrawer = redraw; -! if(role) - role = combine_inherited_role(role); - } - break; - ---- 454,465 ---- - - 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; - -*************** -*** 645,653 **** - } - } - -! if(role) - q_status_message1(SM_ORDER, 3, 4, _("Composing using role \"%s\""), - role->nick); - - /* - * The type of storage object allocated below is vitally ---- 654,667 ---- - } - } - -! if (ps_global->role) -! fs_give((void **)&ps_global->role); -! -! if(role){ - q_status_message1(SM_ORDER, 3, 4, _("Composing using role \"%s\""), - role->nick); -+ ps_global->role = cpystr(role->nick); -+ } - - /* - * The type of storage object allocated below is vitally -*************** -*** 2476,2481 **** ---- 2490,2515 ---- - 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); -diff -rc alpine-2.21/pith/Makefile.am alpine-2.21.rules/pith/Makefile.am -*** alpine-2.21/pith/Makefile.am Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/Makefile.am Sun Feb 5 16:15:21 2017 -*************** -*** 26,32 **** - filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c imap.c init.c \ - keyword.c ldap.c list.c mailcap.c mailcmd.c mailindx.c maillist.c mailview.c \ - margin.c mimedesc.c mimetype.c msgno.c newmail.c news.c pattern.c pipe.c \ -! readfile.c remote.c reply.c rfc2231.c save.c search.c sequence.c send.c sort.c \ - state.c status.c store.c stream.c string.c strlst.c takeaddr.c tempfile.c text.c \ - thread.c adjtime.c url.c util.c helptext.c smkeys.c smime.c - ---- 26,32 ---- - filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c imap.c init.c \ - keyword.c ldap.c list.c mailcap.c mailcmd.c mailindx.c maillist.c mailview.c \ - margin.c mimedesc.c mimetype.c msgno.c newmail.c news.c pattern.c pipe.c \ -! readfile.c remote.c reply.c rfc2231.c rules.c save.c search.c sequence.c send.c sort.c \ - state.c status.c store.c stream.c string.c strlst.c takeaddr.c tempfile.c text.c \ - thread.c adjtime.c url.c util.c helptext.c smkeys.c smime.c - -diff -rc alpine-2.21/pith/Makefile.in alpine-2.21.rules/pith/Makefile.in -*** alpine-2.21/pith/Makefile.in Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/Makefile.in Sun Feb 5 16:15:21 2017 -*************** -*** 147,153 **** - margin.$(OBJEXT) mimedesc.$(OBJEXT) mimetype.$(OBJEXT) \ - msgno.$(OBJEXT) newmail.$(OBJEXT) news.$(OBJEXT) \ - pattern.$(OBJEXT) pipe.$(OBJEXT) readfile.$(OBJEXT) \ -! remote.$(OBJEXT) reply.$(OBJEXT) rfc2231.$(OBJEXT) \ - save.$(OBJEXT) search.$(OBJEXT) sequence.$(OBJEXT) \ - send.$(OBJEXT) sort.$(OBJEXT) state.$(OBJEXT) status.$(OBJEXT) \ - store.$(OBJEXT) stream.$(OBJEXT) string.$(OBJEXT) \ ---- 147,153 ---- - margin.$(OBJEXT) mimedesc.$(OBJEXT) mimetype.$(OBJEXT) \ - msgno.$(OBJEXT) newmail.$(OBJEXT) news.$(OBJEXT) \ - pattern.$(OBJEXT) pipe.$(OBJEXT) readfile.$(OBJEXT) \ -! remote.$(OBJEXT) reply.$(OBJEXT) rfc2231.$(OBJEXT) rules.$(OBJEXT) \ - save.$(OBJEXT) search.$(OBJEXT) sequence.$(OBJEXT) \ - send.$(OBJEXT) sort.$(OBJEXT) state.$(OBJEXT) status.$(OBJEXT) \ - store.$(OBJEXT) stream.$(OBJEXT) string.$(OBJEXT) \ -*************** -*** 442,448 **** - filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c imap.c init.c \ - keyword.c ldap.c list.c mailcap.c mailcmd.c mailindx.c maillist.c mailview.c \ - margin.c mimedesc.c mimetype.c msgno.c newmail.c news.c pattern.c pipe.c \ -! readfile.c remote.c reply.c rfc2231.c save.c search.c sequence.c send.c sort.c \ - state.c status.c store.c stream.c string.c strlst.c takeaddr.c tempfile.c text.c \ - thread.c adjtime.c url.c util.c helptext.c smkeys.c smime.c - ---- 442,448 ---- - filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c imap.c init.c \ - keyword.c ldap.c list.c mailcap.c mailcmd.c mailindx.c maillist.c mailview.c \ - margin.c mimedesc.c mimetype.c msgno.c newmail.c news.c pattern.c pipe.c \ -! readfile.c remote.c reply.c rfc2231.c rules.c save.c search.c sequence.c send.c sort.c \ - state.c status.c store.c stream.c string.c strlst.c takeaddr.c tempfile.c text.c \ - thread.c adjtime.c url.c util.c helptext.c smkeys.c smime.c - -*************** -*** 574,579 **** ---- 574,580 ---- - @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 $@ $< -diff -rc alpine-2.21/pith/adrbklib.c alpine-2.21.rules/pith/adrbklib.c -*** alpine-2.21/pith/adrbklib.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/adrbklib.c Sun Feb 5 16:15:21 2017 -*************** -*** 5136,5143 **** - 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; ---- 5136,5149 ---- - if(as.cur >= as.how_many_personals) - pab->type |= GLOBAL; - -! if(ps_global->mail_stream && -! ps_global->mail_stream->lock && (pab->type & REMOTE_VIA_IMAP)){ -! as.initialized = 0; -! pab->access = NoAccess; -! } -! else{ -! pab->access = adrbk_access(pab); -! } - /* global address books are forced readonly */ - if(pab->type & GLOBAL && pab->access != NoAccess) - pab->access = ReadOnly; -diff -rc alpine-2.21/pith/conf.c alpine-2.21.rules/pith/conf.c -*** alpine-2.21/pith/conf.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/conf.c Sun Feb 5 16:15:21 2017 -*************** -*** 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" -*************** -*** 222,227 **** ---- 223,258 ---- - - 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 -*************** -*** 550,555 **** ---- 581,614 ---- - NULL, cf_text_thread_exp_char}, - {"threading-lastreply-character", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, - "Threading Last Reply Character", cf_text_thread_lastreply_char}, -+ {"threading-display-style-rule", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, -+ "Threading Display Style Rule", cf_text_thread_displaystyle_rule}, -+ {"threading-index-style-rule", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, -+ "Threading Index Style Rule", cf_text_thread_indexstyle_rule}, -+ {"compose-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, -+ "Compose Rules", cf_text_compose_rules}, -+ {"forward-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, -+ "Forward Rules", cf_text_forward_rules}, -+ {"index-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, -+ "Index Rules", cf_text_index_rules}, -+ {"key-definition-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, -+ "Key Definition Rules", cf_text_key_def_rules}, -+ {"replace-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, -+ "Replace Rules", cf_text_replace_rules}, -+ {"reply-indent-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, -+ "Reply Indent Rules", cf_text_reply_indent_rules}, -+ {"reply-leadin-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, -+ "Reply Leadin Rules", cf_text_reply_leadin_rules}, -+ {"reply-subject-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, -+ "Reply Subject Rules", cf_text_reply_subject_rules}, -+ {"save-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, -+ "Save Rules", cf_text_save_rules}, -+ {"smtp-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, -+ "Smtp Rules", cf_text_smtp_rules}, -+ {"sort-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, -+ "Sort Rules", cf_text_sort_rules}, -+ {"startup-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, -+ "Startup Rules", cf_text_startup_rules}, - #ifndef _WINDOWS - {"display-character-set", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, - NULL, cf_text_disp_char_set}, -*************** -*** 2635,2640 **** ---- 2694,2700 ---- - 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 */ -*************** -*** 3081,3086 **** ---- 3141,3148 ---- - 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, -*************** -*** 7699,7704 **** ---- 7761,7794 ---- - 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 : -diff -rc alpine-2.21/pith/conf.h alpine-2.21.rules/pith/conf.h -*** alpine-2.21/pith/conf.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/conf.h Sun Feb 5 16:15:21 2017 -*************** -*** 148,153 **** ---- 148,193 ---- - #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 -diff -rc alpine-2.21/pith/conftype.h alpine-2.21.rules/pith/conftype.h -*** alpine-2.21/pith/conftype.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/conftype.h Sun Feb 5 16:15:21 2017 -*************** -*** 70,75 **** ---- 70,89 ---- - , V_THREAD_MORE_CHAR - , V_THREAD_EXP_CHAR - , V_THREAD_LASTREPLY_CHAR -+ , V_THREAD_DISP_STYLE_RULES -+ , V_THREAD_INDEX_STYLE_RULES -+ , V_COMPOSE_RULES -+ , V_FORWARD_RULES -+ , V_INDEX_RULES -+ , V_KEY_RULES -+ , V_REPLACE_RULES -+ , V_REPLY_INDENT_RULES -+ , V_REPLY_LEADIN_RULES -+ , V_RESUB_RULES -+ , V_SAVE_RULES -+ , V_SMTP_RULES -+ , V_SORT_RULES -+ , V_STARTUP_RULES - #ifndef _WINDOWS - , V_CHAR_SET - , V_OLD_CHAR_SET -*************** -*** 332,337 **** ---- 346,352 ---- - 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, -diff -rc alpine-2.21/pith/detoken.c alpine-2.21.rules/pith/detoken.c -*** alpine-2.21/pith/detoken.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/detoken.c Sun Feb 5 16:15:21 2017 -*************** -*** 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 -*************** -*** 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; -*************** -*** 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; -*************** -*** 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); - -diff -rc alpine-2.21/pith/indxtype.h alpine-2.21.rules/pith/indxtype.h -*** alpine-2.21/pith/indxtype.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/indxtype.h Sun Feb 5 16:15:21 2017 -*************** -*** 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, -*************** -*** 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" - -diff -rc alpine-2.21/pith/mailcmd.c alpine-2.21.rules/pith/mailcmd.c -*** alpine-2.21/pith/mailcmd.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/mailcmd.c Sun Feb 5 16:15:21 2017 -*************** -*** 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" -*************** -*** 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! */ -*************** -*** 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 -*************** -*** 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) -*************** -*** 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)){ - /* -*************** -*** 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 */ -*************** -*** 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; -*************** -*** 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'; -*************** -*** 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; -*************** -*** 2755,2757 **** ---- 2652,2946 ---- - - 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; -+ -+ } -+ } -diff -rc alpine-2.21/pith/mailcmd.h alpine-2.21.rules/pith/mailcmd.h -*** alpine-2.21/pith/mailcmd.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/mailcmd.h Sun Feb 5 16:15:21 2017 -*************** -*** 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 -*************** -*** 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 *); -diff -rc alpine-2.21/pith/mailindx.c alpine-2.21.rules/pith/mailindx.c -*** alpine-2.21/pith/mailindx.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/mailindx.c Sun Feb 5 16:15:21 2017 -*************** -*** 40,45 **** ---- 40,46 ---- - #include "../pith/send.h" - #include "../pith/options.h" - #include "../pith/ablookup.h" -+ #include "../pith/rules.h" - #ifdef _WINDOWS - #include "../pico/osdep/mswin.h" - #endif -*************** -*** 377,382 **** ---- 378,390 ---- - 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/adrbkcmd.c | 3 + alpine/alpine.c | 4 + alpine/confscroll.c | 33 + alpine/dispfilt.c | 60 + + alpine/dispfilt.h | 2 + alpine/folder.c | 3 + alpine/mailcmd.c | 18 + alpine/mailindx.c | 6 + alpine/mailview.c | 2 + alpine/osdep/termin.gen.c | 41 + + alpine/reply.c | 102 ++ + alpine/roleconf.c | 5 + alpine/send.c | 40 + + pith/Makefile.am | 2 + pith/Makefile.in | 5 + pith/adrbklib.c | 10 + pith/conf.c | 90 ++ + pith/conf.h | 40 + + pith/conftype.h | 15 + pith/detoken.c | 33 + pith/indxtype.h | 34 + pith/mailcmd.c | 435 +++++++++--- + pith/mailcmd.h | 8 + pith/mailindx.c | 336 +++++++-- + pith/mailindx.h | 3 + pith/makefile.wnt | 5 + pith/pine.hlp | 1150 +++++++++++++++++++++++++++++++++ + pith/reply.c | 277 +++++++- + pith/rules.c | 1565 ++++++++++++++++++++++++++++++++++++++++++++++ + pith/rules.h | 154 ++++ + pith/rulestype.h | 94 ++ + pith/save.c | 2 + pith/send.c | 58 + + pith/sort.c | 56 + + pith/sort.h | 2 + pith/state.c | 4 + pith/state.h | 11 + pith/string.c | 58 + + pith/string.h | 2 + 39 files changed, 4473 insertions(+), 295 deletions(-) + +Index: alpine-2.22/alpine/adrbkcmd.c +=================================================================== +--- alpine-2.22.orig/alpine/adrbkcmd.c ++++ alpine-2.22/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.22/alpine/alpine.c +=================================================================== +--- alpine-2.22.orig/alpine/alpine.c ++++ alpine-2.22/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){ +@@ -3270,6 +3271,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.22/alpine/confscroll.c +=================================================================== +--- alpine-2.22.orig/alpine/confscroll.c ++++ alpine-2.22/alpine/confscroll.c +@@ -51,6 +51,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") +@@ -2443,6 +2444,9 @@ delete: + * Now go and set the current_val based on user_val changes + * above. Turn off command line settings... + */ ++ set_current_val((*cl)->var, ++ (strcmp((*cl)->var->name,"key-definition-rules") ? TRUE : FALSE), ++ FALSE); + set_current_val((*cl)->var, TRUE, FALSE); + fix_side_effects(ps, (*cl)->var, 0); + +@@ -5240,6 +5244,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.22/alpine/dispfilt.c +=================================================================== +--- alpine-2.22.orig/alpine/dispfilt.c ++++ alpine-2.22/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.22/alpine/dispfilt.h +=================================================================== +--- alpine-2.22.orig/alpine/dispfilt.h ++++ alpine-2.22/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.22/alpine/folder.c +=================================================================== +--- alpine-2.22.orig/alpine/folder.c ++++ alpine-2.22/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.22/alpine/mailcmd.c +=================================================================== +--- alpine-2.22.orig/alpine/mailcmd.c ++++ alpine-2.22/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 +@@ -2720,6 +2721,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': +@@ -2770,12 +2774,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; +@@ -2783,6 +2787,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"); +@@ -2792,6 +2797,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)){ -*************** -*** 450,464 **** - static INDEX_PARSE_T itokens[] = { - {"STATUS", iStatus, FOR_INDEX}, - {"MSGNO", iMessNo, FOR_INDEX}, -! {"DATE", iDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"FROMORTO", iFromTo, FOR_INDEX}, - {"FROMORTONOTNEWS", iFromToNotNews, FOR_INDEX}, - {"SIZE", iSize, FOR_INDEX}, - {"SIZECOMMA", iSizeComma, FOR_INDEX}, - {"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}, ---- 458,472 ---- - static INDEX_PARSE_T itokens[] = { - {"STATUS", iStatus, FOR_INDEX}, - {"MSGNO", iMessNo, FOR_INDEX}, -! {"DATE", iDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE}, - {"FROMORTO", iFromTo, FOR_INDEX}, - {"FROMORTONOTNEWS", iFromToNotNews, FOR_INDEX}, - {"SIZE", iSize, FOR_INDEX}, - {"SIZECOMMA", iSizeComma, FOR_INDEX}, - {"SIZETHREAD", iSizeThread, FOR_INDEX}, - {"SIZENARROW", iSizeNarrow, FOR_INDEX}, - {"KSIZE", iKSize, FOR_INDEX}, -! {"SUBJECT", iSubject, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_TRIM}, - {"SHORTSUBJECT", iShortSubject, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"FULLSTATUS", iFStatus, FOR_INDEX}, - {"IMAPSTATUS", iIStatus, FOR_INDEX}, -*************** -*** 469,524 **** - {"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}, ---- 477,536 ---- - {"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}, -*************** -*** 527,582 **** - {"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} - }; - ---- 539,609 ---- - {"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} - }; - -*************** -*** 2483,2488 **** ---- 2510,2533 ---- - 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" -*************** -*** 3833,3839 **** ---- 3878,3894 ---- - - 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)); -*************** -*** 5407,5416 **** - { - 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; ---- 5462,5471 ---- - { - 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; -*************** -*** 5466,5471 **** ---- 5521,5534 ---- - * 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); - -*************** -*** 5908,5913 **** ---- 5971,5979 ---- - - if(free_subj) - fs_give((void **) &free_subj); -+ -+ if (we_clear && origsubj) -+ fs_give((void **)&origsubj); - } - - -*************** -*** 6276,6291 **** - ? "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; - } - ---- 6342,6374 ---- - ? "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; - } - -*************** -*** 6298,6304 **** - break; - - case iFrom: -! set_index_addr(idata, "From", fetch_from(idata), NULL, strsize-1, fptr); - break; - - case iAddress: ---- 6381,6395 ---- - 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: -*************** -*** 6596,6598 **** ---- 6687,6750 ---- - } - } - } -+ -+ 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.22/alpine/mailindx.c +=================================================================== +--- alpine-2.22.orig/alpine/mailindx.c ++++ alpine-2.22/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.22/alpine/mailview.c +=================================================================== +--- alpine-2.22.orig/alpine/mailview.c ++++ alpine-2.22/alpine/mailview.c +@@ -251,6 +251,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")); +Index: alpine-2.22/alpine/osdep/termin.gen.c +=================================================================== +--- alpine-2.22.orig/alpine/osdep/termin.gen.c ++++ alpine-2.22/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; -+ } -diff -rc alpine-2.21/pith/mailindx.h alpine-2.21.rules/pith/mailindx.h -*** alpine-2.21/pith/mailindx.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/mailindx.h Sun Feb 5 16:15:21 2017 -*************** -*** 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 *); -diff -rc alpine-2.21/pith/makefile.wnt alpine-2.21.rules/pith/makefile.wnt -*** alpine-2.21/pith/makefile.wnt Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/makefile.wnt Sun Feb 5 16:15:21 2017 -*************** -*** 45,51 **** - init.h keyword.h ldap.h list.h mailcap.h mailcmd.h mailindx.h maillist.h \ - mailpart.h mailview.h margin.h mimedesc.h mimetype.h msgno.h newmail.h news.h \ - options.h pattern.h pineelt.h pipe.h readfile.h remote.h remtype.h repltype.h reply.h \ -! rfc2231.h save.h savetype.h search.h send.h sequence.h signal.h sort.h sorttype.h \ - state.h status.h store.h stream.h string.h strlst.h takeaddr.h tempfile.h text.h \ - thread.h url.h user.h util.h - ---- 45,51 ---- - init.h keyword.h ldap.h list.h mailcap.h mailcmd.h mailindx.h maillist.h \ - mailpart.h mailview.h margin.h mimedesc.h mimetype.h msgno.h newmail.h news.h \ - options.h pattern.h pineelt.h pipe.h readfile.h remote.h remtype.h repltype.h reply.h \ -! rfc2231.h rules.h save.h savetype.h search.h send.h sequence.h signal.h sort.h sorttype.h \ - state.h status.h store.h stream.h string.h strlst.h takeaddr.h tempfile.h text.h \ - thread.h url.h user.h util.h - -*************** -*** 54,60 **** - filter.obj flag.obj folder.obj handle.obj help.obj helptext.obj hist.obj icache.obj imap.obj init.obj \ - keyword.obj ldap.obj list.obj mailcap.obj mailcmd.obj mailindx.obj maillist.obj mailview.obj \ - margin.obj mimedesc.obj mimetype.obj msgno.obj newmail.obj news.obj pattern.obj pipe.obj \ -! readfile.obj remote.obj reply.obj rfc2231.obj save.obj search.obj sequence.obj send.obj sort.obj state.obj \ - status.obj store.obj stream.obj string.obj strlst.obj takeaddr.obj tempfile.obj text.obj \ - thread.obj adjtime.obj url.obj util.obj - ---- 54,60 ---- - filter.obj flag.obj folder.obj handle.obj help.obj helptext.obj hist.obj icache.obj imap.obj init.obj \ - keyword.obj ldap.obj list.obj mailcap.obj mailcmd.obj mailindx.obj maillist.obj mailview.obj \ - margin.obj mimedesc.obj mimetype.obj msgno.obj newmail.obj news.obj pattern.obj pipe.obj \ -! readfile.obj remote.obj reply.obj rfc2231.obj rules.obj save.obj search.obj sequence.obj send.obj sort.obj state.obj \ - status.obj store.obj stream.obj string.obj strlst.obj takeaddr.obj tempfile.obj text.obj \ - thread.obj adjtime.obj url.obj util.obj - -diff -rc alpine-2.21/pith/pine.hlp alpine-2.21.rules/pith/pine.hlp -*** alpine-2.21/pith/pine.hlp Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/pine.hlp Sun Feb 5 16:15:21 2017 -*************** -*** 3855,3860 **** ---- 3855,3861 ---- -

  • FEATURE: -
  • FEATURE: -
  • FEATURE: -+
  • FEATURE: -
  • FEATURE: -
  • FEATURE: -
  • FEATURE: -*************** -*** 19045,19050 **** ---- 19046,19052 ---- - "" 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. -*************** -*** 19057,19063 **** -

    -

    - -!

    Tokens Available for all Cases (except Filter Rules)

    - -
    -
    SUBJECT
    ---- 19059,19065 ---- -

    -

    - -!

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

    - -
    -
    SUBJECT
    -*************** -*** 19091,19096 **** ---- 19093,19114 ---- - 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 -*************** -*** 19138,19143 **** ---- 19156,19170 ---- - 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 -*************** -*** 19146,19151 **** ---- 19173,19186 ---- - 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 -*************** -*** 20270,20275 **** ---- 20305,20414 ---- - - -

    -+

    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

    - -
    -*************** -*** 23397,23402 **** ---- 23536,24432 ---- - <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_ and _REXTRIM_. -+ -+

    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_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) and the screen where the list of -+ folders is displayed (FOLDER LIST). The -+ internal names of these screens for this patch are "index", -+ "text" and -+ "folder" 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 13 functions already defined for -+ you. These are: _EXEC_, _INDEX_, _REPLACE_, _REPLY_, _RESUB_, _SAVE_, -+ _SIGNATURE_, _SORT_, _STARTUP_, _TRIM_, _REXTRIM_, _THREADSTYLE and -+ _THREADINDEX_. The parameter of a function has to be enclosed between -+ "{" 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. -+
       
      -+
    • _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 ===== - - -*************** -*** 27005,27010 **** ---- 28035,28110 ---- - <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 ===== - - -*************** -*** 30595,30600 **** ---- 31695,31723 ---- - 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. -+

    -

    -diff -rc alpine-2.21/pith/reply.c alpine-2.21.rules/pith/reply.c -*** alpine-2.21/pith/reply.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/reply.c Sun Feb 5 16:15:22 2017 -*************** -*** 47,52 **** ---- 47,54 ---- - #include "../pith/mailcmd.h" - #include "../pith/margin.h" - #include "../pith/smime.h" -+ #include "../pith/copyaddr.h" -+ #include "../pith/rules.h" - - - /* -*************** -*** 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 */ -*************** -*** 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))); - } - - -*************** -*** 1385,1390 **** ---- 1425,1434 ---- - buf[0] = '\0'; - - switch(type){ -+ case iFfrom: -+ addr = env && env->sparep ? env->sparep : NULL; -+ break; -+ - case iFrom: - addr = env ? env->from : NULL; - break; -*************** -*** 1797,1818 **** - - 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); ---- 1841,2034 ---- - - 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); -*************** -*** 1840,1845 **** ---- 2056,2066 ---- - - 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); -*************** -*** 1889,1894 **** ---- 2110,2123 ---- - - 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){ -*************** -*** 1951,1957 **** - 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)){ ---- 2180,2197 ---- - 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)){ -*************** -*** 2210,2215 **** ---- 2450,2456 ---- - { - size_t l; - char *p, buftmp[MAILTMPLEN]; -+ RULE_RESULT *rule; - - if(!env) - return(NULL); -*************** -*** 2217,2225 **** - 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) ---- 2458,2476 ---- - 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) -diff -rc alpine-2.21/pith/rules.c alpine-2.21.rules/pith/rules.c -*** alpine-2.21/pith/rules.c Sun Feb 5 16:15:22 2017 ---- alpine-2.21.rules/pith/rules.c Sun Feb 5 16:15:22 2017 -*************** -*** 0 **** ---- 1,1416 ---- -+ /* This module was written by -+ * -+ * Eduardo Chappa (chappa@washington.edu) -+ * http://patches.freeiz.com/alpine/ -+ * -+ * Original Version: November 1999 -+ * Last Modified : September 14, 2013 -+ * -+ * 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 *raw_value (RULEACTION_S *, int, ENVELOPE *); -+ char *extended_value (RULEACTION_S *, int, ENVELOPE *); -+ char *exec_fcn (RULEACTION_S *, int, ENVELOPE *); -+ char *expand (char *, void *); -+ char *get_name_token (char *); -+ char *advance_to_char (char *, char, int, int *); -+ char **functions_for_token (char *); -+ char *canonicalize_condition (char *, 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 free_alloc_rule (void **, int); -+ void *alloc_mem (size_t); -+ void add_rule (int, int); -+ void set_rule_list (struct variable *); -+ void parse_patterns_into_action(TOKEN_VALUE **); -+ void free_parsed_value(TOKEN_VALUE **value); -+ RULE_S *parse_rule (char *, int); -+ RULELIST *get_rule_list (char **, int, int); -+ TOKEN_VALUE *parse_group_data (char *,int *); -+ TOKEN_VALUE *copy_parsed_value (TOKEN_VALUE *, int, ENVELOPE *); -+ 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, extended_value, FOR_SAVE|FOR_COMPOSE}, -+ {SAVE_FCN, extended_value, FOR_SAVE}, -+ {EXEC_FCN, exec_fcn, FOR_REPLACE|FOR_TRIM|FOR_RESUB|FOR_COMPOSE}, -+ {REPLY_FCN, extended_value, FOR_REPLY_INTRO}, -+ {TRIM_FCN, trim, FOR_TRIM|FOR_RESUB|FOR_COMPOSE}, -+ {REPLACE_FCN, extended_value, FOR_REPLACE}, -+ {SORT_FCN, raw_value, FOR_SORT}, -+ {INDEX_FCN, raw_value, FOR_INDEX}, -+ {COMMAND_FCN, raw_value, FOR_KEY}, -+ {REPLYSTR_FCN, raw_value, FOR_COMPOSE}, -+ {SIGNATURE_FCN, raw_value, FOR_COMPOSE}, -+ {RESUB_FCN, extended_value, FOR_RESUB}, -+ {STARTUP_FCN, raw_value, FOR_STARTUP}, -+ {REXTRIM_FCN, rextrim, FOR_TRIM|FOR_RESUB|FOR_COMPOSE}, -+ {THRDSTYLE_FCN, raw_value, FOR_THREAD}, -+ {THRDINDEX_FCN, raw_value, FOR_THREAD}, -+ {SMTP_FCN, raw_value, FOR_COMPOSE}, -+ {NULL, 0, FOR_NOTHING} -+ }; -+ -+ char* token_rules[] = { -+ FROM_TOKEN, -+ NICK_TOKEN, -+ 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, EXEC_FCN}; -+ char *from_fcn[] = {FROM_TOKEN, REPLACE_FCN, TRIM_FCN, REXTRIM_FCN, EXEC_FCN}; -+ char *otext_fcn[] = {OTEXT_TOKEN, REPLACE_FCN, TRIM_FCN, REXTRIM_FCN, EXEC_FCN}; -+ char *otextnq_fcn[] = {OTEXTNQ_TOKEN, REPLACE_FCN, TRIM_FCN, REXTRIM_FCN, EXEC_FCN}; -+ -+ char *adto_fcn[] = {ADDTO_TOKEN, EXEC_FCN, NULL, NULL, NULL}; -+ -+ char **fcns_for_index[] = {subj_fcn, from_fcn, otext_fcn, otextnq_fcn}; -+ -+ #define NFCNFI (sizeof(fcns_for_index)/sizeof(fcns_for_index[0])) /*for idx*/ -+ #define NFPT (sizeof(fcns_for_index[0])) /* functions pert token */ -+ -+ SPAREP_S * -+ get_sparep_for_rule(char *value, int flag) -+ { -+ SPAREP_S *rv; -+ rv = (SPAREP_S *) alloc_mem(sizeof(SPAREP_S)); -+ rv->flag = flag; -+ rv->value = value ? cpystr(value) : NULL; -+ return rv; -+ } -+ -+ void free_sparep_for_rule(void **sparep) -+ { -+ SPAREP_S *spare = (SPAREP_S *) *sparep; -+ if(!spare) return; -+ if(spare->value) -+ fs_give((void **)&spare->value); -+ fs_give((void **)sparep); -+ } -+ -+ -+ int context_for_function(char *name) -+ { -+ int i, j; -+ for (i = 0; i < NFCN && strcmp(rule_fcns[i].name, name); i++); -+ return i == NFCN ? 0 : rule_fcns[i].what_for; -+ -+ } -+ -+ char **functions_for_token(char *name) -+ { -+ int i; -+ for (i = 0; i < NFCNFI && strcmp(fcns_for_index[i][0], name); i++); -+ return i == NFCNFI ? NULL : fcns_for_index[i]; -+ } -+ -+ void -+ free_alloc_rule (void **voidtext, int code) -+ { -+ switch(code){ -+ case FREEREGEX : regfree((regex_t *)*voidtext); -+ break; -+ default: break; -+ } -+ } -+ -+ -+ -+ void free_token_value(TOKEN_VALUE **token) -+ { -+ if(token && *token){ -+ if ((*token)->testxt) -+ fs_give((void **)&(*token)->testxt); -+ free_alloc_rule (&(*token)->voidtxt, (*token)->codefcn); -+ if((*token)->next) -+ free_token_value(&(*token)->next); -+ fs_give((void **)token); -+ } -+ } -+ -+ void -+ free_condition_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 * -+ alloc_mem (size_t amount) -+ { -+ void *genmem; -+ memset(genmem = fs_get(amount), 0, amount); -+ return genmem; -+ } -+ -+ -+ void -+ parse_patterns_into_action(TOKEN_VALUE **tokenp) -+ { -+ if(!*tokenp) -+ return; -+ -+ if((*tokenp)->testxt){ -+ regex_t preg; -+ -+ (*tokenp)->voidtxt = NULL; -+ (*tokenp)->voidtxt = fs_get(sizeof(regex_t)); -+ if (regcomp((regex_t *)(*tokenp)->voidtxt, -+ (*tokenp)->testxt, REG_EXTENDED) != 0){ -+ regfree((regex_t *)(*tokenp)->voidtxt); -+ (*tokenp)->voidtxt = NULL; -+ } -+ } -+ if((*tokenp)->voidtxt) -+ (*tokenp)->codefcn = FREEREGEX; -+ if((*tokenp)->next) -+ parse_patterns_into_action(&(*tokenp)->next); -+ } -+ -+ -+ int -+ isolate_condition (char *data, char **cvalue, int *len) -+ { -+ char *p = data; -+ int done = 0, error = 0, next_condition = 0, l; -+ -+ if(*p == '"' && p[strlen(p) - 1] == '"'){ -+ p[strlen(p) - 1] = '\0'; -+ p++; -+ } -+ *cvalue = NULL; -+ while (*p && !done){ -+ switch (*p){ -+ case '_': *cvalue = advance_to_char(p,'}', STRICTLY, NULL); -+ if(*cvalue){ -+ strcat(*cvalue,"}"); -+ p += strlen(*cvalue); -+ } -+ else -+ error++; -+ done++; -+ case ' ': p++; -+ break; -+ case '&': -+ 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 *) 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 = alloc_mem(sizeof(CONDVALUE_S)); -+ condition->tname = cpystr(token_rules[--i]); -+ data += strlen(token_rules[i]); -+ } -+ else if (*data == '_') { -+ char *itokname; -+ for (i = 0, done = 0; done == 0 && (itokname = itoken(i)->name) != NULL; i++) -+ done = strncmp(data+1, itokname, strlen(itokname)) -+ ? 0 : data[strlen(itokname) + 1] == '_'; -+ if (done){ -+ condition = (CONDVALUE_S *) 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 *) 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 *) alloc_mem(sizeof(RULEACTION_S)); -+ raction->function = cpystr("_SAVE_"); -+ raction->value = (TOKEN_VALUE *) alloc_mem(sizeof(TOKEN_VALUE)); -+ raction->context |= FOR_SAVE; -+ raction->exec = extended_value; -+ raction->value->testxt = cpystr(p); -+ return raction; -+ } -+ for (i = 0, done = 0; !done && (i < NFCN); i++) -+ done = (strstr(p,rule_fcns[i].name) == p); -+ p += done ? strlen(rule_fcns[--i].name) + 1 : 0; -+ if(!*p || (rule_fcns[i].what_for && !(rule_fcns[i].what_for & context))) -+ return NULL; -+ if (done){ -+ raction = alloc_mem(sizeof(RULEACTION_S)); -+ /* We assign raction->token to be subject. This is not necessary for -+ most rules. It is done only for rules that need it and will not -+ make any difference in rules that do not need it. It will hopefully -+ reduce complexity in the language -+ */ -+ raction->token = cpystr(SUBJ_TOKEN); -+ raction->function = cpystr(rule_fcns[i].name); -+ raction->context = rule_fcns[i].what_for; -+ raction->exec = rule_fcns[i].execute; -+ raction->value = (TOKEN_VALUE *) alloc_mem(sizeof(TOKEN_VALUE)); -+ raction->value->testxt = advance_to_char(p,'}', STRICTLY, NULL); -+ if(!raction->value->testxt) -+ free_ruleaction(&raction); -+ return raction; -+ } -+ -+ done = (((function = strstr(p, "_TRIM_")) != NULL) -+ ? 1 : ((function = strstr(p, "_COPY_")) != NULL) -+ ? 2 : ((function = strstr(p, "_EXEC_")) != NULL) -+ ? 3 : ((function = strstr(p, "_REXTRIM_")) != NULL) -+ ? 4 : ((function = strstr(p, "_REPLACE_")) != NULL) -+ ? 5 : 0); -+ -+ if(!function) -+ return (RULEACTION_S *) NULL; -+ -+ *function = '\0'; -+ raction = (RULEACTION_S *) alloc_mem(sizeof(RULEACTION_S)); -+ raction->token = get_name_token(p); -+ *function = '_'; -+ p += strlen(raction->token) + 1; -+ for (; *p && *p == ' '; p++); -+ if (!strncmp(p, ":=", 2)) -+ p += 2; -+ else{ -+ free_ruleaction(&raction); -+ return NULL; -+ } -+ for (; *p && *p == ' '; p++); -+ if (p != function){ -+ free_ruleaction(&raction); -+ return NULL; -+ } -+ p += done <= 3 ? 6 : 9; /* 6 = strlen("_EXEC_"), 9 = strlen("_REPLACE_") */ -+ if (*p != '{'){ -+ free_ruleaction(&raction); -+ return NULL; -+ } -+ *p = '\0'; -+ for(i = 0; i < NFCN && strcmp(function, rule_fcns[i].name);i++); -+ raction->function = cpystr(function); -+ raction->is_trim = strcmp(function,"_TRIM_") ? 0 : 1; -+ raction->is_rextrim = strcmp(function,"_REXTRIM_") ? 0 : 1; -+ raction->is_replace = strcmp(function,"_REPLACE_") ? 0 : 1; -+ raction->context = rule_fcns[i].what_for; -+ raction->exec = rule_fcns[i].execute; -+ *p++ = '{'; -+ if((raction->value = parse_group_data(p, NULL)) == NULL -+ || raction->value->testxt == NULL) -+ free_ruleaction(&raction); -+ if(raction && raction->is_rextrim) -+ parse_patterns_into_action(&raction->value); -+ return raction; -+ } -+ -+ RULE_S * -+ parse_rule (char *data, int context) -+ { -+ RULE_S *prule; /*parsed rule */ -+ int len = 0; -+ -+ if (!(prule = (RULE_S *) alloc_mem(sizeof(RULE_S))) || -+ !(prule->condition = parse_condition(data, &len)) || -+ !(prule->action = parse_action(data+len, context))) -+ free_rule(&prule); -+ -+ return prule; -+ } -+ -+ RULELIST * -+ get_rule_list(char **list, int context, int i) -+ { -+ RULE_S *rule; -+ RULELIST *trulelist = NULL; -+ -+ if (list[i] && *list[i]){ -+ if(rule = parse_rule(list[i], context)){ -+ trulelist = (RULELIST *)alloc_mem(sizeof(RULELIST)); -+ trulelist->prule = rule; -+ trulelist->next = get_rule_list(list, context, i+1); -+ } -+ else -+ trulelist = get_rule_list(list, context, i+1); -+ } -+ return trulelist; -+ } -+ -+ PRULELIST_S * -+ add_prule(PRULELIST_S *rule_list, PRULELIST_S *rule) -+ { -+ if (!rule_list) -+ rule_list = (PRULELIST_S *) alloc_mem(sizeof(PRULELIST_S)); -+ -+ if(rule_list->next) -+ rule_list->next = add_prule(rule_list->next, rule); -+ else{ -+ if (rule_list->rlist) -+ rule_list->next = rule; -+ else -+ rule_list = rule; -+ } -+ return rule_list; -+ } -+ -+ void -+ add_rule(int code, int context) -+ { -+ char **list = ps_global->vars[code].current_val.l; -+ PRULELIST_S *prulelist, *trulelist, *orulelist; -+ -+ if (list && *list && **list){ -+ trulelist = (PRULELIST_S *)alloc_mem(sizeof(PRULELIST_S)); -+ trulelist->varnum = code; -+ if (trulelist->rlist = get_rule_list(list, context, 0)) -+ ps_global->rule_list = add_prule(ps_global->rule_list, trulelist); -+ else -+ free_parsed_rule_list(&trulelist); -+ } -+ } -+ -+ /* see create_rule_list below */ -+ void -+ set_rule_list(struct variable *vars) -+ { -+ set_current_val(&vars[V_THREAD_DISP_STYLE_RULES], TRUE, TRUE); -+ set_current_val(&vars[V_THREAD_INDEX_STYLE_RULES], TRUE, TRUE); -+ set_current_val(&vars[V_COMPOSE_RULES], TRUE, TRUE); -+ set_current_val(&vars[V_FORWARD_RULES], TRUE, TRUE); -+ set_current_val(&vars[V_INDEX_RULES], TRUE, TRUE); -+ set_current_val(&vars[V_KEY_RULES], FALSE, TRUE); -+ set_current_val(&vars[V_REPLACE_RULES], TRUE, TRUE); -+ set_current_val(&vars[V_REPLY_INDENT_RULES], TRUE, TRUE); -+ set_current_val(&vars[V_REPLY_LEADIN_RULES], TRUE, TRUE); -+ set_current_val(&vars[V_RESUB_RULES], TRUE, TRUE); -+ set_current_val(&vars[V_SAVE_RULES], TRUE, TRUE); -+ set_current_val(&vars[V_SMTP_RULES], TRUE, TRUE); -+ set_current_val(&vars[V_SORT_RULES], TRUE, TRUE); -+ set_current_val(&vars[V_STARTUP_RULES], TRUE, TRUE); -+ } -+ -+ /* see set_rule_list above */ -+ void -+ create_rule_list(struct variable *vars) -+ { -+ set_rule_list(vars); -+ add_rule(V_THREAD_DISP_STYLE_RULES, FOR_THREAD); -+ add_rule(V_THREAD_INDEX_STYLE_RULES, FOR_THREAD); -+ add_rule(V_COMPOSE_RULES, FOR_COMPOSE); -+ add_rule(V_FORWARD_RULES, FOR_COMPOSE); -+ add_rule(V_INDEX_RULES, FOR_INDEX); -+ add_rule(V_KEY_RULES, FOR_KEY); -+ add_rule(V_REPLACE_RULES, FOR_REPLACE); -+ add_rule(V_REPLY_INDENT_RULES, FOR_COMPOSE); -+ add_rule(V_REPLY_LEADIN_RULES, FOR_REPLY_INTRO); -+ add_rule(V_RESUB_RULES, FOR_RESUB|FOR_TRIM); -+ add_rule(V_SAVE_RULES, FOR_SAVE); -+ add_rule(V_SMTP_RULES, FOR_COMPOSE); -+ add_rule(V_SORT_RULES, FOR_SORT); -+ add_rule(V_STARTUP_RULES, FOR_STARTUP); -+ } -+ -+ int -+ condition_contains_token(CONDITION_S *condition, char *token) -+ { -+ 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.22/alpine/reply.c +=================================================================== +--- alpine-2.22.orig/alpine/reply.c ++++ alpine-2.22/alpine/reply.c +@@ -62,7 +62,8 @@ The evolution continues... + #include "../pith/tempfile.h" + #include "../pith/busy.h" + #include "../pith/ablookup.h" +- ++#include "../pith/copyaddr.h" ++#include "../pith/rules.h" + + /* + * Internal Prototypes +@@ -109,11 +110,12 @@ reply(struct pine *pine_state, ACTION_S + long msgno, j, totalm, rflags, *seq = NULL; + int i, include_text = 0, times = -1, warned = 0, rv = 0, + flags = RSF_QUERY_REPLY_ALL, reply_raw_body = 0; +- int rolemsg = 0, copytomsg = 0; ++ int rolemsg = 0, copytomsg = 0, do_role_early = 0; + gf_io_t pc; + PAT_STATE dummy; + REDRAFT_POS_S *redraft_pos = NULL; + ACTION_S *role = NULL, *nrole; ++ RULE_RESULT *rule; + #if defined(DOS) && !defined(_WINDOWS) + char *reserve; + #endif +@@ -139,6 +141,69 @@ reply(struct pine *pine_state, ACTION_S + && 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... +@@ -287,8 +352,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 */ +@@ -307,13 +382,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 */ +@@ -724,6 +793,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); ++ } + + if(role && role->template){ + char *filtered; +@@ -1832,6 +1909,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.22/alpine/roleconf.c +=================================================================== +--- alpine-2.22.orig/alpine/roleconf.c ++++ alpine-2.22/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.22/alpine/send.c +=================================================================== +--- alpine-2.22.orig/alpine/send.c ++++ alpine-2.22/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; + +@@ -641,9 +650,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); ++ } + + /* + * The type of storage object allocated below is vitally +@@ -2478,6 +2492,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.22/pith/Makefile.am +=================================================================== +--- alpine-2.22.orig/pith/Makefile.am ++++ alpine-2.22/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.22/pith/Makefile.in +=================================================================== +--- alpine-2.22.orig/pith/Makefile.in ++++ alpine-2.22/pith/Makefile.in +@@ -134,7 +134,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) \ +@@ -438,7 +438,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 + +@@ -581,6 +581,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.22/pith/adrbklib.c +=================================================================== +--- alpine-2.22.orig/pith/adrbklib.c ++++ alpine-2.22/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.22/pith/conf.c +=================================================================== +--- alpine-2.22.orig/pith/conf.c ++++ alpine-2.22/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" +@@ -223,6 +224,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 +@@ -564,6 +595,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}, +@@ -2696,6 +2755,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 */ +@@ -3150,6 +3210,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, +@@ -7786,6 +7848,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.22/pith/conf.h +=================================================================== +--- alpine-2.22.orig/pith/conf.h ++++ alpine-2.22/pith/conf.h +@@ -151,6 +151,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.22/pith/conftype.h +=================================================================== +--- alpine-2.22.orig/pith/conftype.h ++++ alpine-2.22/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 +@@ -342,6 +356,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.22/pith/detoken.c +=================================================================== +--- alpine-2.22.orig/pith/detoken.c ++++ alpine-2.22/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.22/pith/indxtype.h +=================================================================== +--- alpine-2.22.orig/pith/indxtype.h ++++ alpine-2.22/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.22/pith/mailcmd.c +=================================================================== +--- alpine-2.22.orig/pith/mailcmd.c ++++ alpine-2.22/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.22/pith/mailcmd.h +=================================================================== +--- alpine-2.22.orig/pith/mailcmd.h ++++ alpine-2.22/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.22/pith/mailindx.c +=================================================================== +--- alpine-2.22.orig/pith/mailindx.c ++++ alpine-2.22/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)){ +@@ -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); + +@@ -5958,6 +6021,9 @@ subj_str(INDEXDATA_S *idata, char *str, + + if(free_subj) + fs_give((void **) &free_subj); ++ ++ if (we_clear && origsubj) ++ fs_give((void **)&origsubj); + } + + +@@ -6323,16 +6389,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; + } + +@@ -6345,7 +6428,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: +@@ -6643,3 +6734,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.22/pith/mailindx.h +=================================================================== +--- alpine-2.22.orig/pith/mailindx.h ++++ alpine-2.22/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.22/pith/makefile.wnt +=================================================================== +--- alpine-2.22.orig/pith/makefile.wnt ++++ alpine-2.22/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.22/pith/pine.hlp +=================================================================== +--- alpine-2.22.orig/pith/pine.hlp ++++ alpine-2.22/pith/pine.hlp +@@ -4228,6 +4228,7 @@ There are also additional details on +

  • FEATURE: +
  • FEATURE: +
  • FEATURE: ++
  • FEATURE: +
  • FEATURE: +
  • FEATURE: +
  • FEATURE: +@@ -19682,6 +19683,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. +@@ -19694,7 +19696,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
    +@@ -19728,6 +19730,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 +@@ -19775,6 +19793,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 +@@ -19783,6 +19810,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 +@@ -20915,6 +20950,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

    + +
    +@@ -24273,6 +24412,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) and the screen where the list of ++folders is displayed (FOLDER LIST). The ++internal names of these screens for this patch are "index", ++"text" and ++"folder" 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 ===== + + +@@ -27975,6 +29030,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 ===== + + +@@ -31624,6 +32749,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.22/pith/reply.c +=================================================================== +--- alpine-2.22.orig/pith/reply.c ++++ alpine-2.22/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))); + } + + +@@ -1485,6 +1525,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; +@@ -1897,22 +1941,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); +@@ -1940,6 +2156,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); +@@ -1989,6 +2210,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){ +@@ -2051,7 +2280,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)){ +@@ -2310,6 +2550,7 @@ forward_subject(ENVELOPE *env, int flags + { + size_t l; + char *p, buftmp[MAILTMPLEN]; ++ RULE_RESULT *rule; + + if(!env) + return(NULL); +@@ -2317,9 +2558,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.22/pith/rules.c +=================================================================== +--- /dev/null ++++ alpine-2.22/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; ++ rule_context |= FOR_RULE; ++ rlist = get_rulelist_from_code(code, ps_global->rule_list); ++ if (rlist){ ++ rule_result = test_rule(rlist, rule_context, env, &n); ++ if (rule_result && *rule_result){ ++ rule = (RULE_RESULT *) fs_get (sizeof(RULE_RESULT)); ++ rule->result = rule_result; ++ rule->number = n; ++ } ++ } ++ return rule; ++} ++ ++char * ++get_rule_result(int rule_context, char *newfolder, int code) ++{ ++ char *rule_result = NULL; ++ ENVELOPE *news_envelope; ++ RULE_RESULT *rule; ++ ++ if (IS_NEWS(ps_global->mail_stream)){ ++ news_envelope = mail_newenvelope(); ++ news_envelope->newsgroups = cpystr(newfolder); ++ } ++ else ++ news_envelope = NULL; ++ ++ rule = get_result_rule(code, rule_context, news_envelope); ++ ++ if (news_envelope) ++ mail_free_envelope (&news_envelope); ++ ++ if (rule){ ++ rule_result = cpystr(rule->result); ++ if (rule->result) ++ fs_give((void **)&rule->result); ++ fs_give((void **)&rule); ++ } ++ return rule_result; ++} ++ ++/* process_rule: ++ Parameters: 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; ++ ++ 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 ')': 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; ++} ++ ++/* 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); + } -+ -+ TOKEN_VALUE * -+ copy_parsed_value(TOKEN_VALUE *value, int ctxt, ENVELOPE *env) -+ { -+ TOKEN_VALUE *tval = NULL; -+ -+ if(!value) ++ 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; ++ } ++ ++ return do_trim(test, tval->next); ++} ++ ++char * ++trim (RULEACTION_S *action, int context, ENVELOPE *env) ++{ ++ char *begin_text, *test; ++ RULEACTION_S *taction = action; ++ int offset; ++ ++ if (taction->context & context){ ++ if (test = detoken_src(taction->token, context, env, NULL, NULL, NULL)) ++ test = do_trim(test, taction->value); ++ return test; ++ } ++ return NULL; ++} ++ ++char * ++do_rextrim (char *test, TOKEN_VALUE *tval) ++{ ++ char *begin_text, *trim_text; ++ int 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; ++ 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 * ++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; -+ -+ if(value->testxt){ -+ tval = (TOKEN_VALUE *) alloc_mem(sizeof(TOKEN_VALUE)); -+ tval->testxt = detoken_src(value->testxt, ctxt, env, NULL, NULL, NULL); -+ tval->voidtxt = value->voidtxt; -+ tval->codefcn = value->codefcn; -+ } -+ if(value->next) -+ tval->next = copy_parsed_value(value->next, ctxt, env); -+ -+ return tval; -+ } -+ -+ void -+ free_parsed_value(TOKEN_VALUE **value) -+ { -+ TOKEN_VALUE *tval = NULL; -+ -+ if(!*value) -+ return; -+ -+ if((*value)->testxt) -+ fs_give((void **)&(*value)->testxt); -+ -+ if((*value)->next) -+ free_parsed_value(&(*value)->next); -+ -+ fs_give((void **)value); -+ } -+ -+ int -+ test_condition_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 ')': 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 = NULL, *q, *s; -+ -+ if ((q = strchr(condition,'_')) && (s = strchr(q+1,'_'))){ -+ char c = *++s; -+ *s = '\0'; -+ p = cpystr(q); -+ *s = c; -+ } -+ return p; -+ } -+ -+ /* This function tests if a string contained in the variable "group" is -+ * in the "condition" -+ */ -+ int test_in (CONDITION_S *condition, TOKEN_VALUE *group, ENVELOPE *env, -+ int context) -+ { -+ int rv = 0; -+ char *test; -+ TOKEN_VALUE *test_group = group; -+ -+ test = env && env->sparep && ((SPAREP_S *)env->sparep)->flag & USE_RAW_SP -+ ? cpystr(((SPAREP_S *)env->sparep)->value) -+ : detoken_src(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); -+ } -+ 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)); -+ offset = begin_text - test; -+ } -+ -+ return do_trim(test, tval->next); -+ } -+ -+ char * -+ trim (RULEACTION_S *action, int context, ENVELOPE *env) -+ { -+ char *begin_text, *test; -+ RULEACTION_S *taction = action; -+ int offset; -+ -+ if (taction->context & context){ -+ if (test = detoken_src(taction->token, context, env, NULL, NULL, NULL)) -+ test = do_trim(test, taction->value); -+ return test; -+ } -+ return NULL; -+ } -+ -+ -+ char * -+ do_rextrim (char *test, TOKEN_VALUE *tval) -+ { -+ char *begin_text, *trim_text; -+ int offset = 0; -+ -+ if (!tval) -+ return test; -+ -+ trim_text = expand(test, tval->voidtxt); -+ while(trim_text && (begin_text = strstr(test+offset,trim_text))){ -+ strcpy(begin_text, begin_text+strlen(trim_text)); -+ offset = begin_text - test; -+ } -+ -+ return do_rextrim(test, tval->next); -+ } -+ -+ char * -+ rextrim (RULEACTION_S *action, int context, ENVELOPE *env) -+ { -+ char *test = NULL; -+ RULEACTION_S *taction = action; -+ -+ if (taction->context & context && -+ (test = detoken_src(taction->token, context, env, NULL, NULL, NULL))) -+ test = do_rextrim(test, taction->value); -+ return test; -+ } -+ -+ char * -+ raw_value (RULEACTION_S *action, int context, ENVELOPE *env) -+ { -+ return (action->context & context) ? cpystr(action->value->testxt) : NULL; -+ } -+ -+ char * -+ extended_value (RULEACTION_S *action, int ctxt, ENVELOPE *env) -+ { -+ return (action->context & ctxt) -+ ? detoken_src(action->value->testxt, ctxt, env, NULL, NULL, NULL) -+ : NULL; -+ } -+ -+ /* advances given_string until it finds given_char, 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){ ++ ++ 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); -+ err = -1; -+ } -+ -+ if (error) -+ *error = err; -+ -+ return b; -+ } -+ -+ /* Regular Expressions Support */ -+ char * -+ expand (char *string, void *pattern) -+ { ++ 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; -+ -+ if((regex_t *)pattern == NULL) -+ return NULL; -+ -+ if(regexec((regex_t *)pattern, string , 1, &pmatch, 0) == 0 -+ && pmatch.rm_so < pmatch.rm_eo){ -+ c = string[pmatch.rm_eo]; -+ string[pmatch.rm_eo] = '\0'; -+ ret_string = cpystr(string+pmatch.rm_so); -+ string[pmatch.rm_eo] = c; -+ } -+ return ret_string; -+ } -+ -+ -+ char * -+ exec_fcn (RULEACTION_S *action, int ctxt, ENVELOPE *env) -+ { -+ STORE_S *output_so; -+ gf_io_t gc, pc; -+ char *status, *rv, *cmd, *test; -+ -+ if(!(action->context & ctxt)) ++ regex_t preg; ++ ++ if(pattern == NULL || regcomp(&preg, pattern, REG_EXTENDED) != 0) + 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(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.22/pith/rules.h +=================================================================== +--- /dev/null ++++ alpine-2.22/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.22/pith/rulestype.h +=================================================================== +--- /dev/null ++++ alpine-2.22/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.22/pith/save.c +=================================================================== +--- alpine-2.22.orig/pith/save.c ++++ alpine-2.22/pith/save.c +@@ -954,7 +954,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.22/pith/send.c +=================================================================== +--- alpine-2.22.orig/pith/send.c ++++ alpine-2.22/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.22/pith/sort.c +=================================================================== +--- alpine-2.22.orig/pith/sort.c ++++ alpine-2.22/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(we_clear) -+ *we_clear = 0; -+ env = pine_mail_fetchenvelope(idata->stream, idata->rawno); -+ return env; -+ } -diff -rc alpine-2.21/pith/rules.h alpine-2.21.rules/pith/rules.h -*** alpine-2.21/pith/rules.h Sun Feb 5 16:15:22 2017 ---- alpine-2.21.rules/pith/rules.h Sun Feb 5 16:15:22 2017 -*************** -*** 0 **** ---- 1,151 ---- -+ /* Included file rules.h */ -+ -+ #ifndef PITH_RULES_INCLUDED -+ #define PITH_RULES_INCLUDED -+ -+ #include "../pith/conftype.h" -+ #include "../pith/detoken.h" -+ #include "../pith/indxtype.h" -+ #include "../pith/rulestype.h" -+ -+ /* 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; -+ char* (*execute)(); -+ int what_for; -+ } RULE_FCN; -+ -+ #define COMMAND_FCN "_COMMAND_" -+ #define COPY_FCN "_COPY_" -+ #define EXEC_FCN "_EXEC_" -+ #define INDEX_FCN "_INDEX_" -+ #define REPLACE_FCN "_REPLACE_" -+ #define REPLYSTR_FCN "_RESTR_" -+ #define REPLY_FCN "_REPLY_" -+ #define RESUB_FCN "_RESUB_" -+ #define REXTRIM_FCN "_REXTRIM_" -+ #define SAVE_FCN "_SAVE_" -+ #define SIGNATURE_FCN "_SIGNATURE_" -+ #define SMTP_FCN "_SMTP_" -+ #define SORT_FCN "_SORT_" -+ #define STARTUP_FCN "_STARTUP_" -+ #define THRDSTYLE_FCN "_THREADSTYLE_" -+ #define THRDINDEX_FCN "_THREADINDEX_" -+ #define TRIM_FCN "_TRIM_" -+ -+ #define STRICTLY 0x1 -+ #define RELAXED 0x2 -+ -+ #endif /* PITH_RULES_INCLUDED */ -diff -rc alpine-2.21/pith/rulestype.h alpine-2.21.rules/pith/rulestype.h -*** alpine-2.21/pith/rulestype.h Sun Feb 5 16:15:22 2017 ---- alpine-2.21.rules/pith/rulestype.h Sun Feb 5 16:15:22 2017 -*************** -*** 0 **** ---- 1,85 ---- -+ #ifndef PITH_RULESTYPE_INCLUDED -+ #define PITH_RULESTYPE_INCLUDED -+ -+ typedef struct rule { -+ char *result; /* The result of the rule */ -+ int number; /* The number of the rule that succeded, -1 if not */ -+ } RULE_RESULT; -+ -+ typedef struct { -+ char *value; -+ int type; -+ } RULE_ACTION; -+ -+ -+ #define TOKEN_VALUE struct tokenvalue_s -+ #define CONDITION_S struct condition_s -+ #define RULEACTION_S struct ruleaction_s -+ #define RULE_S struct rule_s -+ #define RULELIST struct rulelist_s -+ #define PRULELIST_S struct parsedrulelist_s -+ -+ #define FREEREGEX 1 -+ -+ TOKEN_VALUE { -+ char *testxt; -+ void *voidtxt; -+ int codefcn; -+ TOKEN_VALUE *next; -+ }; -+ -+ typedef enum {Equal, Subset, Includes, NotEqual, NotSubset, NotIncludes, EndTypes} TestType; -+ -+ 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)(); -+ unsigned int is_trim:1; -+ unsigned int is_rextrim:1; -+ unsigned int is_replace:1; -+ }; -+ -+ RULE_S { -+ CONDITION_S *condition; -+ RULEACTION_S *action; -+ }; -+ -+ RULELIST { -+ RULE_S *prule; -+ RULELIST *next; -+ }; -+ -+ PRULELIST_S { -+ int varnum; /* number associated to the variable */ -+ RULELIST *rlist; -+ PRULELIST_S *next; -+ }; -+ -+ #define USE_RAW_SP 0x001 -+ #define PROCESS_SP 0x010 -+ -+ typedef struct sparep { -+ int flag; -+ char *value; -+ } SPAREP_S; -+ -+ -+ #endif /* PITH_RULESTYPE_INCLUDED */ -diff -rc alpine-2.21/pith/save.c alpine-2.21.rules/pith/save.c -*** alpine-2.21/pith/save.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/save.c Sun Feb 5 16:15:22 2017 -*************** -*** 954,960 **** - *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) ---- 954,960 ---- - *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) -diff -rc alpine-2.21/pith/send.c alpine-2.21.rules/pith/send.c -*** alpine-2.21/pith/send.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/send.c Sun Feb 5 16:15:22 2017 -*************** -*** 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" -*************** -*** 1742,1750 **** - 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; ---- 1743,1751 ---- - 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; -*************** -*** 1899,1918 **** - * OK, who posts what? We tried an mta_handoff above, but there - * was either none specified or we decided not to use it. So, - * if there's an smtp-server defined anywhere, - */ -! if(alt_smtp_servers && alt_smtp_servers[0] && alt_smtp_servers[0][0]){ -! /*---------- SMTP ----------*/ -! dprint((4, "call_mailer: via TCP (%s)\n", -! alt_smtp_servers[0])); -! TIME_STAMP("smtp-open start (tcp)", 1); -! sending_stream = smtp_open(alt_smtp_servers, smtp_opts); - } -! else if(ps_global->VAR_SMTP_SERVER && ps_global->VAR_SMTP_SERVER[0] -! && ps_global->VAR_SMTP_SERVER[0][0]){ -! /*---------- SMTP ----------*/ -! dprint((4, "call_mailer: via TCP\n")); -! TIME_STAMP("smtp-open start (tcp)", 1); -! sending_stream = smtp_open(ps_global->VAR_SMTP_SERVER, smtp_opts); - } - else if((postcmd = smtp_command(ps_global->c_client_error, sizeof(ps_global->c_client_error))) != NULL){ - char *cmdlist[2]; ---- 1900,1948 ---- - * OK, who posts what? We tried an mta_handoff above, but there - * was either none specified or we decided not to use it. So, - * if there's an smtp-server defined anywhere, -+ * First we check for rules and make a list using the rules. - */ -! if(ps_global->VAR_SMTP_RULES && ps_global->VAR_SMTP_RULES[0] -! && ps_global->VAR_SMTP_RULES[0][0]) -! while (ps_global->VAR_SMTP_RULES[num_rules]) num_rules++; -! -! if(num_rules){ -! int i, j; -! -! added_rules = 0; -! smtp_list = (char **) fs_get ((num_rules + 1)*sizeof(char*)); -! for (i = 0, j = 0; i < num_rules; i++){ -! RULELIST *rule = get_rulelist_from_code(V_SMTP_RULES, -! ps_global->rule_list); -! RULE_S *prule = get_rule(rule, i); -! if(prule){ -! char *rule_result = process_rule(prule, FOR_COMPOSE, header->env); -! if(rule_result && *rule_result){ -! smtp_list[j++] = cpystr(rule_result); -! added_rules++; -! } -! } -! } -! } -! -! if (added_rules < 0){ -! smtp_list = (char **) fs_get (sizeof(char*)); -! added_rules = 0; - } -! smtp_list[added_rules] = NULL; -! -! choice = smtp_list && smtp_list[0] && smtp_list[0][0] ? 3 : -! (alt_smtp_servers && alt_smtp_servers[0] && alt_smtp_servers[0][0] ? 2 : -! (ps_global->VAR_SMTP_SERVER && ps_global->VAR_SMTP_SERVER[0] -! && ps_global->VAR_SMTP_SERVER[0][0] ? 1 : -1)); -! -! if(choice > 0){ -! /*---------- SMTP ----------*/ -! dprint((4, "call_mailer: via TCP (%s)\n",smtp_list[0])); -! TIME_STAMP("smtp-open start (tcp)", 1); -! sending_stream = smtp_open(choice == 3 ? smtp_list -! : (choice == 2 ? alt_smtp_servers -! : ps_global->VAR_SMTP_SERVER), smtp_opts); - } - else if((postcmd = smtp_command(ps_global->c_client_error, sizeof(ps_global->c_client_error))) != NULL){ - char *cmdlist[2]; -diff -rc alpine-2.21/pith/sort.c alpine-2.21.rules/pith/sort.c -*** alpine-2.21/pith/sort.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/sort.c Sun Feb 5 16:15:22 2017 -*************** -*** 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 -*************** -*** 686,692 **** - 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 ---- 686,706 ---- - 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 -*************** -*** 704,713 **** - : pat->action->revsort; - } - } -! - if(the_sort_order == SortThread && !(flags & SRT_MAN)) - ps_global->thread_cur_sort = ps_global->thread_def_sort; - - sort_folder(ps_global->mail_stream, ps_global->msgmap, - the_sort_order, sort_is_rev, flags, 1); - } ---- 718,763 ---- - : pat->action->revsort; - } - } -! } - if(the_sort_order == SortThread && !(flags & SRT_MAN)) - ps_global->thread_cur_sort = ps_global->thread_def_sort; - - sort_folder(ps_global->mail_stream, ps_global->msgmap, - the_sort_order, sort_is_rev, flags, 1); - } -+ -+ SortOrder translate(char *order, int is_rev) -+ { -+ int rev = 0; -+ if (!strncmp(order,"tHread", 6) -+ || (rev = !strncmp(order,"Reverse tHread", 14))) -+ return is_rev || rev ? SortThread : EndofList; -+ if (!strncmp(order,"OrderedSubj", 11) -+ || (rev = !strncmp(order,"Reverse OrderedSubj", 19))) -+ return is_rev || rev ? SortSubject2 : EndofList; -+ if (!strncmp(order,"Subject", 7) -+ || (rev = !strncmp(order,"Reverse SortSubject", 15))) -+ return is_rev || rev ? SortSubject : EndofList; -+ if (!strncmp(order,"Arrival", 7) -+ || (rev = !strncmp(order,"Reverse Arrival", 15))) -+ return is_rev || rev ? SortArrival : EndofList; -+ if (!strncmp(order,"From", 4) -+ || (rev = !strncmp(order,"Reverse From", 12))) -+ return is_rev || rev ? SortFrom : EndofList; -+ if (!strncmp(order,"To", 2) -+ || (rev = !strncmp(order,"Reverse To", 10))) -+ return is_rev || rev ? SortTo : EndofList; -+ if (!strncmp(order,"Cc", 2) -+ || (rev = !strncmp(order,"Reverse Cc", 10))) -+ return is_rev || rev ? SortCc : EndofList; -+ if (!strncmp(order,"Date", 4) -+ || (rev = !strncmp(order,"Reverse Date", 12))) -+ return is_rev || rev ? SortDate : EndofList; -+ if (!strncmp(order,"siZe", 4) -+ || (rev = !strncmp(order,"Reverse siZe", 12))) -+ return is_rev || rev ? SortSize : EndofList; -+ if (!strncmp(order,"scorE", 5) -+ || (rev = !strncmp(order,"Reverse scorE", 13))) -+ return is_rev || rev ? SortScore : EndofList; -+ return EndofList; -+ } -diff -rc alpine-2.21/pith/sort.h alpine-2.21.rules/pith/sort.h -*** alpine-2.21/pith/sort.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/sort.h Sun Feb 5 16:15:22 2017 -*************** -*** 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 */ -diff -rc alpine-2.21/pith/state.c alpine-2.21.rules/pith/state.c -*** alpine-2.21/pith/state.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/state.c Sun Feb 5 16:15:22 2017 -*************** -*** 33,39 **** - #include "../pith/remote.h" - #include "../pith/list.h" - #include "../pith/smime.h" -! - - /* - * Globals referenced throughout pine... ---- 33,39 ---- - #include "../pith/remote.h" - #include "../pith/list.h" - #include "../pith/smime.h" -! #include "../pith/rules.h" - - /* - * Globals referenced throughout pine... -*************** -*** 239,244 **** ---- 239,247 ---- - if((*pps)->msgmap) - msgno_give(&(*pps)->msgmap); - -+ if((*pps)->rule_list) -+ free_parsed_rule_list(&(*pps)->rule_list); -+ - free_vars(*pps); - - fs_give((void **) pps); -diff -rc alpine-2.21/pith/state.h alpine-2.21.rules/pith/state.h -*** alpine-2.21/pith/state.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/state.h Sun Feb 5 16:15:22 2017 -*************** -*** 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 -*************** -*** 105,110 **** ---- 105,115 ---- - MAILSTREAM *mail_stream; /* ptr to current folder stream */ - MSGNO_S *msgmap; /* ptr to current message map */ - -+ char screen_name[10]; /* name of current screen */ -+ char *role; /* role used when composing */ -+ char *procid; /* procedure id when needed */ -+ int exiting; -+ - unsigned read_predicted:1; - - char cur_folder[MAXPATH+1]; -*************** -*** 349,354 **** ---- 354,360 ---- - 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; -*************** -*** 359,364 **** ---- 365,373 ---- - char last_error[500]; - INIT_ERR_S *init_errs; - -+ PRULELIST_S *rule_list; -+ char *pressed_key; -+ - PRINT_S *print; - - #ifdef SMIME -diff -rc alpine-2.21/pith/string.c alpine-2.21.rules/pith/string.c -*** alpine-2.21/pith/string.c Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/string.c Sun Feb 5 16:15:22 2017 -*************** -*** 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 -*************** -*** 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'; -+ } - - - /*---------------------------------------------------------------------- -*************** -*** 2983,2985 **** ---- 3009,3043 ---- - 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++; -+ } -+ } -+ -diff -rc alpine-2.21/pith/string.h alpine-2.21.rules/pith/string.h -*** alpine-2.21/pith/string.h Sun Feb 5 16:02:36 2017 ---- alpine-2.21.rules/pith/string.h Sun Feb 5 16:15:22 2017 -*************** -*** 87,92 **** ---- 87,93 ---- - - /* exported protoypes */ - char *rplstr(char *, size_t, int, char *); -+ void collspaces(char *); - void sqzspaces(char *); - void sqznewlines(char *); - void removing_leading_white_space(char *); -*************** -*** 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 *); ++ 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 +@@ -721,7 +735,43 @@ reset_sort_order(unsigned int flags) + + if(the_sort_order == SortThread && !(flags & SRT_MAN)) + ps_global->thread_cur_sort = ps_global->thread_def_sort; +- ++} + sort_folder(ps_global->mail_stream, ps_global->msgmap, + the_sort_order, sort_is_rev, flags, 1); + } ++ ++SortOrder translate(char *order, int is_rev) ++{ ++ int rev = 0; ++ if (!strncmp(order,"tHread", 6) ++ || (rev = !strncmp(order,"Reverse tHread", 14))) ++ return is_rev || rev ? SortThread : EndofList; ++ if (!strncmp(order,"OrderedSubj", 11) ++ || (rev = !strncmp(order,"Reverse OrderedSubj", 19))) ++ return is_rev || rev ? SortSubject2 : EndofList; ++ if (!strncmp(order,"Subject", 7) ++ || (rev = !strncmp(order,"Reverse SortSubject", 15))) ++ return is_rev || rev ? SortSubject : EndofList; ++ if (!strncmp(order,"Arrival", 7) ++ || (rev = !strncmp(order,"Reverse Arrival", 15))) ++ return is_rev || rev ? SortArrival : EndofList; ++ if (!strncmp(order,"From", 4) ++ || (rev = !strncmp(order,"Reverse From", 12))) ++ return is_rev || rev ? SortFrom : EndofList; ++ if (!strncmp(order,"To", 2) ++ || (rev = !strncmp(order,"Reverse To", 10))) ++ return is_rev || rev ? SortTo : EndofList; ++ if (!strncmp(order,"Cc", 2) ++ || (rev = !strncmp(order,"Reverse Cc", 10))) ++ return is_rev || rev ? SortCc : EndofList; ++ if (!strncmp(order,"Date", 4) ++ || (rev = !strncmp(order,"Reverse Date", 12))) ++ return is_rev || rev ? SortDate : EndofList; ++ if (!strncmp(order,"siZe", 4) ++ || (rev = !strncmp(order,"Reverse siZe", 12))) ++ return is_rev || rev ? SortSize : EndofList; ++ if (!strncmp(order,"scorE", 5) ++ || (rev = !strncmp(order,"Reverse scorE", 13))) ++ return is_rev || rev ? SortScore : EndofList; ++ return EndofList; ++} +Index: alpine-2.22/pith/sort.h +=================================================================== +--- alpine-2.22.orig/pith/sort.h ++++ alpine-2.22/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.22/pith/state.c +=================================================================== +--- alpine-2.22.orig/pith/state.c ++++ alpine-2.22/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... +@@ -249,6 +250,9 @@ free_pine_struct(struct pine **pps) + 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.22/pith/state.h +=================================================================== +--- alpine-2.22.orig/pith/state.h ++++ alpine-2.22/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 +@@ -105,6 +105,11 @@ struct pine { + MAILSTREAM *mail_stream; /* ptr to current folder stream */ + MSGNO_S *msgmap; /* ptr to current message map */ + ++ char screen_name[10]; /* name of current screen */ ++ char *role; /* role used when composing */ ++ char *procid; /* procedure id when needed */ ++ int exiting; ++ + unsigned read_predicted:1; + + char cur_folder[MAXPATH+1]; +@@ -360,6 +365,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; +@@ -370,6 +376,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.22/pith/string.c +=================================================================== +--- alpine-2.22.orig/pith/string.c ++++ alpine-2.22/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.22/pith/string.h +=================================================================== +--- alpine-2.22.orig/pith/string.h ++++ alpine-2.22/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 *); diff --git a/chappa-rules.txt b/chappa-rules.txt new file mode 100644 index 0000000..672a0de --- /dev/null +++ b/chappa-rules.txt @@ -0,0 +1,16 @@ +From: http://alpine.x10host.com/alpine/info/rules.html +Upstream: constitutes upstream source, delivered in non-tarball form + +This patch allows you to create specific hooks, so that operations that would normally be global in nature can be customized on a per message/folder/person +basis. + +[...] + +[For example:] + + * Compose Rules + This option can be used to generate signatures in cases when setting up a + role does not work. Examples are + + _TO_ >> {Peter Flinstones} => _SIGNATURE_{~/.petersignature} + _COLLECTION_ >> {Mail} => _SIGNATURE_{~/ll} diff --git a/pico-fix-spurious-undef-warnings.diff b/pico-fix-spurious-undef-warnings.diff index dc19091..5162580 100644 --- a/pico-fix-spurious-undef-warnings.diff +++ b/pico-fix-spurious-undef-warnings.diff @@ -1,26 +1,50 @@ ---- alpine-0.999/pico/osdep/shell.c 2007/08/02 12:09:33 1.1 -+++ alpine-0.999/pico/osdep/shell.c 2007/08/02 12:10:03 -@@ -90,7 +90,6 @@ bktoshell(void) /* suspend MicroEMACS a +--- + imap/src/c-client/mail.h | 8 ++++++++ + imap/src/osdep/unix/os_slx.h | 8 ++++++++ + include/system.h | 8 ++++++++ + pico/osdep/shell.c | 3 +-- + 4 files changed, 25 insertions(+), 2 deletions(-) + +Index: alpine-2.22/imap/src/c-client/mail.h +=================================================================== +--- alpine-2.22.orig/imap/src/c-client/mail.h ++++ alpine-2.22/imap/src/c-client/mail.h +@@ -1914,6 +1914,14 @@ long INWAIT (long seconds); + int PSOUT (char *s); + int PSOUTR (SIZEDTEXT *s); + int PFLUSH (void); ++/* ++ * Shuts up spurious ++ * "warning: suggest parentheses around assignment used as truth value" ++ * which occurs in gcc4.2.1 and older when an assigment is used in a ++ * if, which works just fine and is not interpreted as always true: ++ */ ++#define if(x) if((x)) ++#define while(x) while((x)) - if(gmode&MDSPWN){ - char *shell; -- int dummy; + /* XOAUTH Client-Side Support */ - vttidy(); - movecursor(0, 0); -@@ -98,7 +97,7 @@ bktoshell(void) /* suspend MicroEMACS a - printf("\n\n\nUse \"exit\" to return to Pi%s\n", - (gmode & MDBRONLY) ? "lot" : "co"); - system((shell = (char *)getenv("SHELL")) ? shell : "/bin/csh"); -- rtfrmshell(dummy); /* fixup tty */ -+ rtfrmshell(0); /* fixup tty */ - } - else { - movecursor(term.t_nrow-1, 0); -// Those may be obsolete now: ---- alpine-0.999/include/system.h 2007/08/03 13:16:15 1.1 -+++ alpine-0.999/include/system.h 2007/08/03 13:19:03 -@@ -381,4 +381,12 @@ +Index: alpine-2.22/imap/src/osdep/unix/os_slx.h +=================================================================== +--- alpine-2.22.orig/imap/src/osdep/unix/os_slx.h ++++ alpine-2.22/imap/src/osdep/unix/os_slx.h +@@ -69,3 +69,11 @@ int portable_utime (char *file,time_t ti + #include "ftl.h" + #include "nl.h" + #include "tcp.h" ++/* ++ * Shuts up spurious ++ * "warning: suggest parentheses around assignment used as truth value" ++ * which occurs ing gcc4.2.1 and older when an assigment is used in a ++ * if, which works just fine and is not iterpreted as always true: ++ */ ++#define if(x) if((x)) ++#define while(x) while((x)) +Index: alpine-2.22/include/system.h +=================================================================== +--- alpine-2.22.orig/include/system.h ++++ alpine-2.22/include/system.h +@@ -389,4 +389,12 @@ typedef int gid_t; # define LOCAL_PASSWD_CACHE #endif @@ -33,31 +57,24 @@ +#define if(x) if((x)) +#define while(x) while((x)) #endif /* _SYSTEM_INCLUDED */ ---- alpine-0.999/imap/src/c-client/mail.h 2007/08/03 13:42:06 1.1 -+++ alpine-0.999/imap/src/c-client/mail.h 2007/08/03 13:42:57 -@@ -1829,3 +1829,11 @@ - int PSOUT (char *s); - int PSOUTR (SIZEDTEXT *s); - int PFLUSH (void); -+/* -+ * Shuts up spurious -+ * "warning: suggest parentheses around assignment used as truth value" -+ * which occurs ing gcc4.2.1 and older when an assigment is used in a -+ * if, which works just fine and is not iterpreted as always true: -+ */ -+#define if(x) if((x)) -+#define while(x) while((x)) ---- alpine-0.999/imap/src/osdep/unix/os_slx.h 2007/08/03 13:54:41 1.1 -+++ alpine-0.999/imap/src/osdep/unix/os_slx.h 2007/08/03 13:55:38 -@@ -65,3 +65,11 @@ - #include "ftl.h" - #include "nl.h" - #include "tcp.h" -+/* -+ * Shuts up spurious -+ * "warning: suggest parentheses around assignment used as truth value" -+ * which occurs ing gcc4.2.1 and older when an assigment is used in a -+ * if, which works just fine and is not iterpreted as always true: -+ */ -+#define if(x) if((x)) -+#define while(x) while((x)) +Index: alpine-2.22/pico/osdep/shell.c +=================================================================== +--- alpine-2.22.orig/pico/osdep/shell.c ++++ alpine-2.22/pico/osdep/shell.c +@@ -98,7 +98,6 @@ bktoshell(int f, int n) + + if(gmode&MDSPWN){ + char *shell; +- int dummy; + + vttidy(); + movecursor(0, 0); +@@ -106,7 +105,7 @@ bktoshell(int f, int n) + printf("\n\n\nUse \"exit\" to return to Pi%s\n", + (gmode & MDBRONLY) ? "lot" : "co"); + system((shell = (char *)getenv("SHELL")) ? shell : "/bin/csh"); +- rtfrmshell(dummy); /* fixup tty */ ++ rtfrmshell(0); /* fixup tty */ + } + else { + movecursor(term.t_nrow-1, 0);