summaryrefslogtreecommitdiff
path: root/packages/pine
diff options
context:
space:
mode:
authorkolla <kolla@uninett.no>2005-08-02 15:11:20 +0000
committerOpenEmbedded Project <openembedded-devel@lists.openembedded.org>2005-08-02 15:11:20 +0000
commit2c2c957d5b8a09b6bbe1046d802eabf1fc621f59 (patch)
tree997f21b2ac599aca8ac34b0d66a33581d328efe5 /packages/pine
parenteea91968ada14180c77ade6d1a906fdb5ee73d90 (diff)
Pine - A tool for reading, sending and managing electronic messages.
With chappa-patches, transparent and more. LDAP- and SSL-support.
Diffstat (limited to 'packages/pine')
-rw-r--r--packages/pine/.mtn2git_empty0
-rw-r--r--packages/pine/pine-4.63/.mtn2git_empty0
-rw-r--r--packages/pine/pine-4.63/imap-2000-time.patch56
-rw-r--r--packages/pine/pine-4.63/pine-4.30-ldap.patch11
-rw-r--r--packages/pine/pine-4.63/pine-4.31-segfix.patch17
-rw-r--r--packages/pine/pine-4.63/pine-4.40-lockfile-perm.patch22
-rw-r--r--packages/pine/pine-4.63/pine-4.56-passfile.patch12
-rw-r--r--packages/pine/pine-4.63/pine-4.61-largeterminal.patch14
-rw-r--r--packages/pine/pine-4.63/pine-4.61-subjectlength.patch59
-rw-r--r--packages/pine/pine-4.63/pine-4.62-spooldir-permissions.patch12
-rw-r--r--packages/pine/pine-4.63/pine-4.63-r2-chappa-all.patch21900
-rw-r--r--packages/pine/pine-4.63/pine-ldap3.patch11
-rw-r--r--packages/pine/pine-4.63/transparency.patch14
-rw-r--r--packages/pine/pine_4.63.bb82
14 files changed, 22210 insertions, 0 deletions
diff --git a/packages/pine/.mtn2git_empty b/packages/pine/.mtn2git_empty
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/packages/pine/.mtn2git_empty
diff --git a/packages/pine/pine-4.63/.mtn2git_empty b/packages/pine/pine-4.63/.mtn2git_empty
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/packages/pine/pine-4.63/.mtn2git_empty
diff --git a/packages/pine/pine-4.63/imap-2000-time.patch b/packages/pine/pine-4.63/imap-2000-time.patch
new file mode 100644
index 0000000000..751d1ff506
--- /dev/null
+++ b/packages/pine/pine-4.63/imap-2000-time.patch
@@ -0,0 +1,56 @@
+--- pine4.33/imap/src/osdep/unix/os_lnx.c.time Wed Feb 14 12:25:06 2001
++++ pine4.33/imap/src/osdep/unix/os_lnx.c Wed Feb 14 12:25:16 2001
+@@ -23,6 +23,7 @@
+ #include "osdep.h"
+ #include <stdio.h>
+ #include <sys/time.h>
++#include <time.h>
+ #include <sys/stat.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+--- pine4.33/imap/src/osdep/unix/news.c.time Thu Jan 18 21:28:33 2001
++++ pine4.33/imap/src/osdep/unix/news.c Wed Feb 14 12:24:34 2001
+@@ -21,7 +21,7 @@
+ #include <stdio.h>
+ #include <ctype.h>
+ #include <errno.h>
+-extern int errno; /* just in case */
++#include <time.h>
+ #include "mail.h"
+ #include "osdep.h"
+ #include <sys/stat.h>
+--- pine4.33/imap/src/osdep/unix/phile.c.time Thu Jan 18 21:31:20 2001
++++ pine4.33/imap/src/osdep/unix/phile.c Wed Feb 14 12:24:34 2001
+@@ -21,8 +21,8 @@
+ #include <stdio.h>
+ #include <ctype.h>
+ #include <errno.h>
+-extern int errno; /* just in case */
+ #include <signal.h>
++#include <time.h>
+ #include "mail.h"
+ #include "osdep.h"
+ #include <pwd.h>
+--- pine4.33/imap/src/osdep/unix/mh.c.time Thu Jan 18 21:27:37 2001
++++ pine4.33/imap/src/osdep/unix/mh.c Wed Feb 14 12:24:34 2001
+@@ -21,7 +21,8 @@
+ #include <stdio.h>
+ #include <ctype.h>
+ #include <errno.h>
+-extern int errno; /* just in case */
++#include <time.h>
++
+ #include "mail.h"
+ #include "osdep.h"
+ #include <pwd.h>
+--- pine4.33/imap/src/osdep/unix/mx.c.time Thu Jan 18 21:28:09 2001
++++ pine4.33/imap/src/osdep/unix/mx.c Wed Feb 14 12:24:34 2001
+@@ -21,7 +21,7 @@
+ #include <stdio.h>
+ #include <ctype.h>
+ #include <errno.h>
+-extern int errno; /* just in case */
++#include <time.h>
+ #include "mail.h"
+ #include "osdep.h"
+ #include <pwd.h>
diff --git a/packages/pine/pine-4.63/pine-4.30-ldap.patch b/packages/pine/pine-4.63/pine-4.30-ldap.patch
new file mode 100644
index 0000000000..6b920ade51
--- /dev/null
+++ b/packages/pine/pine-4.63/pine-4.30-ldap.patch
@@ -0,0 +1,11 @@
+--- pine4.30/build.ldap Fri Oct 27 12:48:05 2000
++++ pine4.30/build Fri Oct 27 12:49:00 2000
+@@ -249,7 +249,7 @@
+ case "$?" in
+ 1) if [ "$LLIBS" != "1" ]
+ then
+- L1="'LDAPLIBS=../ldap/libraries/libldap.a ../ldap/libraries/liblber.a'"
++ L1="'LDAPLIBS=../ldap/libraries/libldap.so ../ldap/libraries/liblber.so ../ldap/libraries/libresolv.so'"
+ fi
+ if [ "$LFLAGS" != "1" ]
+ then
diff --git a/packages/pine/pine-4.63/pine-4.31-segfix.patch b/packages/pine/pine-4.63/pine-4.31-segfix.patch
new file mode 100644
index 0000000000..f65aa60294
--- /dev/null
+++ b/packages/pine/pine-4.63/pine-4.31-segfix.patch
@@ -0,0 +1,17 @@
+diff -urN pine4.31.orig/pine/osdep/lstcmpnt pine4.31/pine/osdep/lstcmpnt
+--- pine4.31.orig/pine/osdep/lstcmpnt Mon Oct 30 17:45:08 2000
++++ pine4.31/pine/osdep/lstcmpnt Tue Dec 12 06:33:53 2000
+@@ -9,10 +9,10 @@
+ last_cmpnt(filename)
+ char *filename;
+ {
+- register char *p = NULL, *q = filename;
++ char *p = NULL, *q = filename;
+
+- if(!q)
+- return(q);
++ if(filename == 0)
++ return 0;
+
+ while(q = strchr(q, '/'))
+ if(*++q)
diff --git a/packages/pine/pine-4.63/pine-4.40-lockfile-perm.patch b/packages/pine/pine-4.63/pine-4.40-lockfile-perm.patch
new file mode 100644
index 0000000000..f2cb434de2
--- /dev/null
+++ b/packages/pine/pine-4.63/pine-4.40-lockfile-perm.patch
@@ -0,0 +1,22 @@
+--- pine4.40/imap/src/osdep/unix/env_unix.h.lock_protection_fix Thu Oct 4 05:26:33 2001
++++ pine4.40/imap/src/osdep/unix/env_unix.h Thu Oct 4 05:30:33 2001
+@@ -46,12 +46,15 @@
+
+
+ /*
+- * Attention: all sorcerer's apprentices who think that 0666 is a mistake.
+- * You are wrong. Read the FAQ. Do not meddle in the affairs of wizards,
+- * for they are subtle and quick to anger.
++ * Attention: all people who do not care about OS security, and think that
++ * mode 0666 is a correct. You are wrong. In modern multiuser systems,
++ * both remote and local security is critically important. Allowing 0666
++ * lockfiles, allows all sorts of security problems to occur. Feel free to
++ * meddle with it however, if you do not care about local security.
+ */
+
+-#define MANDATORYLOCKPROT 0666 /* don't change this */
++/* Change this only if you do not want a secure multiuser system */
++#define MANDATORYLOCKPROT 0600
+
+ /* Function prototypes */
+
diff --git a/packages/pine/pine-4.63/pine-4.56-passfile.patch b/packages/pine/pine-4.63/pine-4.56-passfile.patch
new file mode 100644
index 0000000000..bb9813f7c6
--- /dev/null
+++ b/packages/pine/pine-4.63/pine-4.56-passfile.patch
@@ -0,0 +1,12 @@
+--- pine4.56/pine/osdep/os-lnx.h.orig 2003-07-23 07:23:26.000000000 -0700
++++ pine4.56/pine/osdep/os-lnx.h 2003-07-23 07:23:30.000000000 -0700
+@@ -295,5 +295,9 @@
+ #define MAX_ADDR_EXPN (1000) /* Longest expanded addr */
+ #define MAX_ADDR_FIELD (10000) /* Longest fully-expanded addr field */
+
++/*----------------------------------------------------------------------
++ Allow for caching of passwords between connections.
++ ----*/
++#define PASSFILE ".pinepw"
+
+ #endif /* _OS_INCLUDED */
diff --git a/packages/pine/pine-4.63/pine-4.61-largeterminal.patch b/packages/pine/pine-4.63/pine-4.61-largeterminal.patch
new file mode 100644
index 0000000000..c046546dba
--- /dev/null
+++ b/packages/pine/pine-4.63/pine-4.61-largeterminal.patch
@@ -0,0 +1,14 @@
+diff -Nur pine4.61.orig/pine/osdep/os-lnx.h pine4.61/pine/osdep/os-lnx.h
+--- pine4.61.orig/pine/osdep/os-lnx.h 2004-12-18 00:33:46.162401405 +0100
++++ pine4.61/pine/osdep/os-lnx.h 2004-12-18 00:34:14.473012057 +0100
+@@ -247,8 +247,8 @@
+
+
+ /*-- Max screen pine will display on. Used to define some array sizes --*/
+-#define MAX_SCREEN_COLS (170)
+-#define MAX_SCREEN_ROWS (200)
++#define MAX_SCREEN_COLS (340)
++#define MAX_SCREEN_ROWS (400)
+
+
+ /*----------------------------------------------------------------------
diff --git a/packages/pine/pine-4.63/pine-4.61-subjectlength.patch b/packages/pine/pine-4.63/pine-4.61-subjectlength.patch
new file mode 100644
index 0000000000..b7a9cdf7b7
--- /dev/null
+++ b/packages/pine/pine-4.63/pine-4.61-subjectlength.patch
@@ -0,0 +1,59 @@
+--- pine4.61/pine/strings.c_orig 2004-03-12 10:48:17.783992528 +0100
++++ pine4.61/pine/strings.c 2004-03-12 11:01:37.929351944 +0100
+@@ -2912,7 +2912,7 @@ int rfc1522_token PROTO((char *,
+ char **));
+ int rfc1522_valtok PROTO((int));
+ int rfc1522_valenc PROTO((int));
+-int rfc1522_valid PROTO((char *, char **, char **, char **,
++int rfc1522_valid PROTO((char *, int, char **, char **, char **,
+ char **));
+ char *rfc1522_8bit PROTO((void *, int));
+ char *rfc1522_binary PROTO((void *, int));
+@@ -2949,7 +2949,7 @@ rfc1522_decode(d, len, s, charset)
+
+ while(s && (sw = strstr(s, RFC1522_INIT))){
+ /* validate the rest of the encoded-word */
+- if(rfc1522_valid(sw, &cset, &enc, &txt, &ew)){
++ if(rfc1522_valid(sw, 1, &cset, &enc, &txt, &ew)){
+ if(!rv)
+ rv = d; /* remember start of dest */
+
+@@ -3222,10 +3222,15 @@ rfc1522_valenc(c)
+
+ /*
+ * rfc1522_valid - validate the given string as to it's rfc1522-ness
++ * if relaxchk is true, double the maximum length of an encoded word.
++ * this is necessary to decode overlong encoded words generated by
++ * numerous incompliant implementations of RFC 2047 (1522).
++
+ */
+ int
+-rfc1522_valid(s, charset, enc, txt, endp)
++rfc1522_valid(s, relaxchk, charset, enc, txt, endp)
+ char *s;
++ int relaxchk;
+ char **charset;
+ char **enc;
+ char **txt;
+@@ -3237,7 +3242,11 @@ rfc1522_valid(s, charset, enc, txt, endp
+ rv = rfc1522_token(c = s+RFC1522_INIT_L, rfc1522_valtok, RFC1522_DLIM, &e)
+ && rfc1522_token(++e, rfc1522_valtok, RFC1522_DLIM, &t)
+ && rfc1522_token(++t, rfc1522_valenc, RFC1522_TERM, &p)
+- && p - s <= RFC1522_MAXW;
++ && p - s <= RFC1522_MAXW * (relaxchk ? 2 : 1);
++ /*
++ * relax the length condition by doubling the max length of an
++ * encoded word. It's is needed for some longer encoded words.
++ */
+
+ if(charset)
+ *charset = c;
+@@ -3288,7 +3297,7 @@ rfc1522_encode(d, len, s, charset)
+ }
+ else if(*p == RFC1522_INIT[0]
+ && !strncmp((char *) p, RFC1522_INIT, RFC1522_INIT_L)){
+- if(rfc1522_valid((char *) p, NULL, NULL, NULL, (char **) &q))
++ if(rfc1522_valid((char *) p, 0, NULL, NULL, NULL, (char **) &q))
+ p = q + RFC1522_TERM_L - 1; /* advance past encoded gunk */
+ }
+ else if(*p == ESCAPE && match_escapes((char *)(p+1))){
diff --git a/packages/pine/pine-4.63/pine-4.62-spooldir-permissions.patch b/packages/pine/pine-4.63/pine-4.62-spooldir-permissions.patch
new file mode 100644
index 0000000000..eb8c2f3eee
--- /dev/null
+++ b/packages/pine/pine-4.63/pine-4.62-spooldir-permissions.patch
@@ -0,0 +1,12 @@
+diff -bur pine4.62/imap/src/osdep/unix/env_unix.c pine4.62-gentoo/imap/src/osdep/unix/env_unix.c
+--- pine4.62/imap/src/osdep/unix/env_unix.c 2004-09-13 23:32:11.000000000 +0200
++++ pine4.62-gentoo/imap/src/osdep/unix/env_unix.c 2005-03-24 23:38:13.000000000 +0100
+@@ -106,7 +106,7 @@
+ * on the mail spool, or install mlock.
+ */
+ /* disable warning if can't make .lock file */
+-static short disableLockWarning = NIL;
++static short disableLockWarning = 1;
+
+ /* UNIX namespaces */
+
diff --git a/packages/pine/pine-4.63/pine-4.63-r2-chappa-all.patch b/packages/pine/pine-4.63/pine-4.63-r2-chappa-all.patch
new file mode 100644
index 0000000000..313d4544ef
--- /dev/null
+++ b/packages/pine/pine-4.63/pine-4.63-r2-chappa-all.patch
@@ -0,0 +1,21900 @@
+diff -rc pine4.63/README.maildir pine4.63.I.USE/README.maildir
+*** pine4.63/README.maildir Thu May 19 19:59:15 2005
+--- pine4.63.I.USE/README.maildir Thu May 19 19:57:24 2005
+***************
+*** 0 ****
+--- 1,244 ----
++ -------------------------------------------------------------------------------
++
++ Maildir Driver for Pine4.63
++ By Eduardo Chappa <chappa@math.washington.edu>
++ http://www.math.washington.edu/~chappa/pine/
++
++ -------------------------------------------------------------------------------
++ 1. General Information About This Patch
++ ---------------------------------------
++
++ This patch adds support for the maildir format to Pine. We take the
++ approach that this patch is one more driver among the number of formats
++ supported by Pine (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, 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 another 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 Pine 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 Pine to make this driver do its work, unless such patching is for
++ fixing bugs in Pine or to pass parameters to the driver.
++
++ ----------------------------------------
++ 3. One sided comparison to other patches
++ ----------------------------------------
++
++ There are two other maildir patches that could be easily adapted for
++ version 4.63.
++
++ The first one is the patch distributed by SuSe which can be downloaded
++ from http://hico.fphil.uniba.sk/pine-patches.html. This patch was last
++ updated for version 4.58. Several hunks fail to be applied when you try to
++ apply it to Pine 4.63. Even if you apply those hunks manually there will
++ still be the following bugs:
++
++ * You can not save between any two storage systems. The old patch did
++ not do this well, because it had to modify the mailcmd.c file in order
++ to save messages to a unix style mailbox, and this is undesirable,
++ because the mailutil application associated to this patch would fail
++ to save messages.
++ * It corrupts messages when it saves them to a mbx format folder.
++ * It could not save messages to the INBOX folder.
++ * It crashes when two different clients are accessing the same mailbox:
++ For example, if a message is marked deleted in one session, then it
++ should be marked deleted in any other session too, but instead it
++ crashes the second session.
++ * Pine crashes when saving several messages to a maildir (not even the
++ prototype of the function is correctly defined).
++ * Pine crashes when checking for the STATUS of a maildir mailbox.
++ * Pine could not delete a maildir folder.
++ * Pine could not rename a maildir folder.
++
++ The other patch is available from Glue Logic (GL), was last updated for
++ version 4.61 and fails to apply a hunk in version 4.63, which must be
++ manually applied. There are, however, several problems and bugs. The patch
++ can be found at http://www.gluelogic.com/code/PINE-maildir/
++
++ * [Bug] It changes the default sort by arrival into sort by Date in
++ every folder. This makes Pine sort incorrectly any folder (no matter
++ in which format such folder is).
++
++ * [Missing Important Feature] Lacks support for dual folder use. You can
++ not create a directory with the same name than a given folder and use
++ it!
++
++ * [Bug] It confuses Unseen and Recent messages. Unseen messages are
++ reported as Recent. An Unseen message is a message that had not been
++ read the last time the folder was closed (or had been read but marked
++ Unseen in an earlier session). A Recent message is one which was not
++ in the folder the last time it was closed. Recent messages are your
++ real new messages, but Unseen are not. In GL patch, every Unseen
++ message is treated as Recent!.
++
++ * [Problem] Large folders take long time to be opened for the first
++ time.
++
++ * [Bug] Reported sizes are the number of bytes in the message and not
++ the "on the wire" size. If you were to manually edit a message and
++ either add or remove information from it, the size reported by Pine
++ would not be affected by this change.
++
++ * [Bug] Crashes when two sessions access the same mailbox and one
++ deletes and expunges a message while the other tries to read that
++ message. (explicitly, if session A uses the GL patch, and session B
++ uses my patch, then the following procedure crashes session A:
++
++ - In session B delete and expunge a message.
++ - Open that message in session A. Session A will notice it is gone
++ and will not crash.
++ - In session A delete and expunge a message.
++ - Open that message in session B. Session B will print a message
++ about no such message, then it will go back to the index screen
++ telling you that the message your were viewing was gone.
++ - Now in session B delete and expunge a message.
++ - Open that message in session A, Pine will crash).
++
++ * [Bug] The patch changes the name of a message-file by adding a place
++ for the size in the name of the message-file. By doing so it breaks
++ the maildir specification which only allows you to change the name by
++ changing flags. If there is another client reading that mailbox, there
++ is a chance that the other client will fail finding messages due to
++ changes made by the GL patch.
++
++ * [Bug] Any patch for Maildir support is NOT a patch for Pine (despite
++ the fact that you have read many times that the patch is for Pine),
++ but a patch for the C-Client library. As such it should work well with
++ any application that can be built with such library, like the UW-IMAP
++ server. The GL patch has a self proclaimed message stating not to use
++ the associated IMAP server to read Maildirs. This restriction does not
++ apply to my patch. I encourage you to use the server built with my
++ patch to access Maildirs.
++
++ ------------------------------------------------------------------------
++ 4. 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. All bugs of the other
++ patches have been reported but not fixed, either because there was no one
++ maintaining the patch, or the maintainer has not fixed them yet (all these
++ reports were made as late as November 2004). A very complete list of
++ updates for this patch, which includes bug fixes, improvements and
++ addition of new features can be found at
++
++ http://www.math.washington.edu/~chappa/pine/updates/maildir.html
++
++ ----------
++ 5. On UIDs
++ ----------
++
++ This patch does not keep UIDs between sessions, but hopefully it does
++ keep consistent UIDs during one session. This is not a bug of the driver,
++ instead it is a shortcoming of the maildir specification. The main point
++ of the maildir configuration is that you should never (read my lips) ever
++ edit the message, but edit the filename associated to the message. Well, I
++ could not find any single place in the web where it was told how to save
++ the UID of a message, if there is one please let me know and I will add
++ UID support for this driver.
++
++ --------------------------------------------
++ 6. Configuring Pine 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 Pine where your Maildir inbox is, in case your system
++ do not use the above directory (e.g. your system may use
++ "~/.maildir"). In this case define that variable to be the name of
++ the directory where your e-mail is being delivered (e.g.
++ ".maildir").
++
++ * If you want to use the above configuration as your inbox, you must
++ define your inbox-path as "#md/inbox" (no quotes). You can define
++ the inbox-path like above even if you have changed the
++ maildir-location variable. That's the whole point of that variable.
++
++ -----------------------------------
++ 7. What about Courier file systems?
++ -----------------------------------
++
++ In a courier file system all folders are subfolders of a root folder
++ called INBOX. Normally INBOX is located at ~/Maildir and subfolders are
++ "dot" directories in ~/Maildir. For example ~/Maildir/.Trash is a
++ subfolder of INBOX and is accessed with the nickname "INBOX.Trash".
++
++ You can not access folders in this way unless you preceed them with the
++ string "#mc/". The purpose of the string "#mc/" is to warn Pine that a
++ collection in the Courier format is going to be accessed, so you can
++ SELECT a folder like "#mc/INBOX.Trash", but not "INBOX.Trash"
++
++ You can access a collection through a server, but if you want to access a
++ collection of folders created using the Courier server, you MUST edit your
++ ".pinerc" file and enter the definition of the collection as follows:
++
++ folder-collections="Anything you want" #mc/INBOX.[]
++
++ You can replace the string "#mc/INBOX." by something different, for example
++ "#mc/Courier/." will make Pine search for your collection in ~/Courier.
++
++ You can not add this directly into Pine because Pine 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 April 29, 2005
+diff -rc pine4.63/imap/src/c-client/imap4r1.c pine4.63.I.USE/imap/src/c-client/imap4r1.c
+*** pine4.63/imap/src/c-client/imap4r1.c Fri Apr 8 16:44:01 2005
+--- pine4.63.I.USE/imap/src/c-client/imap4r1.c Thu May 19 19:57:33 2005
+***************
+*** 4396,4401 ****
+--- 4396,4402 ----
+ if (*env) { /* need to merge this header into envelope? */
+ if (!(*env)->newsgroups) { /* need Newsgroups? */
+ (*env)->newsgroups = nenv->newsgroups;
++ (*env)->ngpathexists = nenv->ngpathexists;
+ nenv->newsgroups = NIL;
+ }
+ if (!(*env)->followup_to) { /* need Followup-To? */
+***************
+*** 4450,4455 ****
+--- 4451,4457 ----
+ if (oenv) { /* need to merge old envelope? */
+ (*env)->newsgroups = oenv->newsgroups;
+ oenv->newsgroups = NIL;
++ (*env)->ngpathexists = oenv->ngpathexists;
+ (*env)->followup_to = oenv->followup_to;
+ oenv->followup_to = NIL;
+ (*env)->references = oenv->references;
+diff -rc pine4.63/imap/src/c-client/mail.c pine4.63.I.USE/imap/src/c-client/mail.c
+*** pine4.63/imap/src/c-client/mail.c Wed Mar 16 16:12:17 2005
+--- pine4.63.I.USE/imap/src/c-client/mail.c Thu May 19 19:57:24 2005
+***************
+*** 977,982 ****
+--- 977,983 ----
+ (((*mailbox == '{') || (*mailbox == '#')) &&
+ (stream = mail_open (NIL,mailbox,OP_PROTOTYPE | OP_SILENT))))
+ d = stream->dtb;
++ else if (maildir_valid_name(mailbox)) return maildir_create(stream, mailbox);
+ else if ((*mailbox != '{') && (ts = default_proto (NIL))) d = ts->dtb;
+ else { /* failed utterly */
+ sprintf (tmp,"Can't create mailbox %.80s: indeterminate format",mailbox);
+diff -rc pine4.63/imap/src/c-client/mail.h pine4.63.I.USE/imap/src/c-client/mail.h
+*** pine4.63/imap/src/c-client/mail.h Tue Feb 8 15:44:54 2005
+--- pine4.63.I.USE/imap/src/c-client/mail.h Thu May 19 19:57:33 2005
+***************
+*** 149,154 ****
+--- 149,156 ----
+ #define SET_LOGOUTHOOK (long) 226
+ #define GET_LOGOUTDATA (long) 227
+ #define SET_LOGOUTDATA (long) 228
++ #define SET_PASSWORDFILE 229
++ #define GET_PASSWORDFILE 230
+
+ /* 3xx: TCP/IP */
+ #define GET_OPENTIMEOUT (long) 300
+***************
+*** 311,316 ****
+--- 313,320 ----
+ #define SET_SNARFPRESERVE (long) 567
+ #define GET_INBOXPATH (long) 568
+ #define SET_INBOXPATH (long) 569
++ #define GET_COURIERSTYLE (long) 570
++ #define SET_COURIERSTYLE (long) 571
+
+ /* Driver flags */
+
+***************
+*** 622,627 ****
+--- 626,632 ----
+ /* Message envelope */
+
+ typedef struct mail_envelope {
++ unsigned int ngpathexists : 1; /* newsgroups may be bogus */
+ unsigned int incomplete : 1; /* envelope may be incomplete */
+ unsigned int imapenvonly : 1; /* envelope only has IMAP envelope */
+ char *remail; /* remail header if any */
+***************
+*** 790,795 ****
+--- 795,801 ----
+ unsigned int spare7 : 1; /* seventh spare bit */
+ unsigned int spare8 : 1; /* eighth spare bit */
+ void *sparep; /* spare pointer */
++ void *maildirp; /* for the Maildir driver, can't use sparep */
+ unsigned long user_flags; /* user-assignable flags */
+ } MESSAGECACHE;
+
+diff -rc pine4.63/imap/src/c-client/rfc822.c pine4.63.I.USE/imap/src/c-client/rfc822.c
+*** pine4.63/imap/src/c-client/rfc822.c Tue Jan 18 12:41:09 2005
+--- pine4.63.I.USE/imap/src/c-client/rfc822.c Thu May 19 19:57:33 2005
+***************
+*** 354,359 ****
+--- 354,360 ----
+ ENVELOPE *env = (*en = mail_newenvelope ());
+ BODY *body = bdy ? (*bdy = mail_newbody ()) : NIL;
+ long MIMEp = -1; /* flag that MIME semantics are in effect */
++ long PathP = NIL; /* flag that a Path: was seen */
+ parseline_t pl = (parseline_t) mail_parameters (NIL,GET_PARSELINE,NIL);
+ if (!host) host = BADHOST; /* make sure that host is non-null */
+ while (i && *s != '\n') { /* until end of header */
+***************
+*** 443,448 ****
+--- 444,452 ----
+ *t++ = '\0';
+ }
+ break;
++ case 'P': /* possible Path: */
++ if (!strcmp (tmp+1,"ATH")) env->ngpathexists = T;
++ break;
+ case 'R': /* possible Reply-To: */
+ if (!strcmp (tmp+1,"EPLY-TO"))
+ rfc822_parse_adrlist (&env->reply_to,d,host);
+diff -rc pine4.63/imap/src/mailutil/mailutil.c pine4.63.I.USE/imap/src/mailutil/mailutil.c
+*** pine4.63/imap/src/mailutil/mailutil.c Tue Feb 8 15:50:49 2005
+--- pine4.63.I.USE/imap/src/mailutil/mailutil.c Thu May 19 19:57:33 2005
+***************
+*** 29,34 ****
+--- 29,35 ----
+
+ /* Globals */
+
++ int passfile = NIL; /* password file supplied ? */
+ int debugp = NIL; /* flag saying debug */
+ int verbosep = NIL; /* flag saying verbose */
+ int rwcopyp = NIL; /* flag saying readwrite copy (for POP) */
+***************
+*** 159,164 ****
+--- 160,166 ----
+ for (nargs = argc ? argc - 1 : 0,args = argv + 1; nargs; args++,nargs--) {
+ if (*(s = *args) == '-') { /* parse switches */
+ if (!strcmp (s,"-debug") || !strcmp (s,"-d")) debugp = T;
++ else if (!strcmp (s,"-passfile")) passfile = T;
+ else if (!strcmp (s,"-verbose") || !strcmp (s,"-v")) verbosep = T;
+ else if (!strcmp (s,"-rwcopy") || !strcmp (s,"-rw")) rwcopyp = T;
+ else if ((nargs > 1) && (!strcmp (s,"-merge") || !strcmp (s,"-m"))) {
+***************
+*** 179,184 ****
+--- 181,190 ----
+ exit (ret);
+ }
+ }
++ else if (passfile) {
++ env_parameters(SET_PASSWORDFILE, (void *)s);
++ passfile = NIL;
++ }
+ else if (!cmd) cmd = s; /* first non-switch is command */
+ else if (!src) src = s; /* second non-switch is source */
+ else if (!dst) dst = s; /* third non-switch is destination */
+***************
+*** 665,671 ****
+ username[NETMAXUSER-1] = '\0';
+ if (s = strchr (username,'\n')) *s = '\0';
+ }
+! strcpy (password,getpass ("password: "));
+ }
+
+
+--- 671,679 ----
+ username[NETMAXUSER-1] = '\0';
+ if (s = strchr (username,'\n')) *s = '\0';
+ }
+! mm_userpwd(mb, &username, &password);
+! if (!password || !*password)
+! strcpy (password,getpass ("password: "));
+ }
+
+
+diff -rc pine4.63/imap/src/osdep/unix/Makefile pine4.63.I.USE/imap/src/osdep/unix/Makefile
+*** pine4.63/imap/src/osdep/unix/Makefile Wed Apr 20 17:49:08 2005
+--- pine4.63.I.USE/imap/src/osdep/unix/Makefile Thu May 19 19:57:24 2005
+***************
+*** 119,125 ****
+ # Standard distribution build parameters
+
+ DEFAULTAUTHENTICATORS=md5 pla log
+! DEFAULTDRIVERS=imap nntp pop3 mh mx mbx tenex mtx mmdf unix news phile
+
+
+ # Normally no need to change any of these
+--- 119,125 ----
+ # Standard distribution build parameters
+
+ DEFAULTAUTHENTICATORS=md5 pla log
+! DEFAULTDRIVERS=maildir courier imap nntp pop3 mh mx mbx tenex mtx mmdf unix news phile
+
+
+ # Normally no need to change any of these
+***************
+*** 128,134 ****
+ BINARIES=osdep.o mail.o misc.o newsrc.o smanager.o utf8.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
+ CFLAGS=-g
+
+ CAT=cat
+--- 128,134 ----
+ BINARIES=osdep.o mail.o misc.o newsrc.o smanager.o utf8.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 maildir.o
+ CFLAGS=-g
+
+ CAT=cat
+***************
+*** 257,263 ****
+
+ 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 \
+--- 257,263 ----
+
+ 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 \
+***************
+*** 846,852 ****
+ tenex.o: mail.h misc.h osdep.h dummy.h
+ unix.o: mail.h misc.h osdep.h unix.h pseudo.h dummy.h
+ utf8.o: mail.h misc.h osdep.h utf8.h
+!
+
+ # OS-dependent
+
+--- 846,852 ----
+ tenex.o: mail.h misc.h osdep.h dummy.h
+ unix.o: mail.h misc.h osdep.h unix.h pseudo.h dummy.h
+ utf8.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 pine4.63/imap/src/osdep/unix/dummy.c pine4.63.I.USE/imap/src/osdep/unix/dummy.c
+*** pine4.63/imap/src/osdep/unix/dummy.c Wed Nov 10 16:16:23 2004
+--- pine4.63.I.USE/imap/src/osdep/unix/dummy.c Thu May 19 19:57:24 2005
+***************
+*** 104,109 ****
+--- 104,110 ----
+ {
+ char *s,tmp[MAILTMPLEN];
+ struct stat sbuf;
++ maildir_remove_root(&name);
+ /* must be valid local mailbox */
+ if (name && *name && (*name != '{') && (s = mailboxfile (tmp,name))) {
+ /* indeterminate clearbox INBOX */
+***************
+*** 364,370 ****
+ char *s,tmp[MAILTMPLEN];
+ /* don't \NoSelect dir if it has a driver */
+ if ((attributes & LATT_NOSELECT) && (d = mail_valid (NIL,name,NIL)) &&
+! (d != &dummydriver)) attributes &= ~LATT_NOSELECT;
+ if (!contents || /* notify main program */
+ (!(attributes & LATT_NOSELECT) && (csiz = strlen (contents)) &&
+ (s = mailboxfile (tmp,name)) &&
+--- 365,374 ----
+ char *s,tmp[MAILTMPLEN];
+ /* don't \NoSelect dir if it has a driver */
+ if ((attributes & LATT_NOSELECT) && (d = mail_valid (NIL,name,NIL)) &&
+! (d != &dummydriver)){
+! attributes &= ~LATT_NOSELECT;
+! attributes |= LATT_NOINFERIORS;
+! }
+ if (!contents || /* notify main program */
+ (!(attributes & LATT_NOSELECT) && (csiz = strlen (contents)) &&
+ (s = mailboxfile (tmp,name)) &&
+***************
+*** 385,390 ****
+--- 389,396 ----
+ {
+ char *s,tmp[MAILTMPLEN];
+ long ret = NIL;
++ if(!strncmp(mailbox,"#md/",4) || !strncmp(mailbox,"#mc/", 4))
++ return maildir_create(stream, mailbox);
+ /* validate name */
+ if (!(compare_cstring (mailbox,"INBOX") && (s = dummy_file (tmp,mailbox)))) {
+ sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
+***************
+*** 450,455 ****
+--- 456,469 ----
+ {
+ struct stat sbuf;
+ char *s,tmp[MAILTMPLEN];
++ if (!strncmp(mailbox,"#md/",4) || !strncmp(mailbox,"#mc/", 4)
++ || is_valid_maildir(&mailbox)){
++ char tmp[MAILTMPLEN] = {'\0'};
++ strcpy(tmp, mailbox);
++ if(tmp[strlen(tmp) - 1] != '/')
++ tmp[strlen(tmp)] = '/';
++ return maildir_delete(stream, tmp);
++ }
+ if (!(s = dummy_file (tmp,mailbox))) {
+ sprintf (tmp,"Can't delete - invalid name: %.80s",s);
+ MM_LOG (tmp,ERROR);
+***************
+*** 476,481 ****
+--- 490,498 ----
+ {
+ struct stat sbuf;
+ char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN];
++
++ maildir_remove_root(&old);
++ maildir_remove_root(&newname);
+ /* no trailing / allowed */
+ if (!dummy_file (oldname,old) || !(s = dummy_file (mbx,newname)) ||
+ ((s = strrchr (s,'/')) && !s[1])) {
+diff -rc pine4.63/imap/src/osdep/unix/env_unix.c pine4.63.I.USE/imap/src/osdep/unix/env_unix.c
+*** pine4.63/imap/src/osdep/unix/env_unix.c Mon Sep 13 14:31:19 2004
+--- pine4.63.I.USE/imap/src/osdep/unix/env_unix.c Thu May 19 19:57:33 2005
+***************
+*** 24,29 ****
+--- 24,30 ----
+
+ /* c-client environment parameters */
+
++ static char *pwdfile = NIL; /* password file */
+ static char *myUserName = NIL; /* user name */
+ static char *myHomeDir = NIL; /* home directory name */
+ static char *myMailboxDir = NIL;/* mailbox directory name */
+***************
+*** 41,46 ****
+--- 42,48 ----
+ static char *blackBoxDir = NIL; /* black box directory name */
+ /* black box default home directory */
+ static char *blackBoxDefaultHome = NIL;
++ static int xlate_key; /* for password file support */
+ static short anonymous = NIL; /* is anonymous */
+ static short blackBox = NIL; /* is a black box */
+ static short closedBox = NIL; /* is a closed box */
+***************
+*** 215,220 ****
+--- 217,229 ----
+ case GET_SHAREDHOME:
+ ret = (void *) sharedHome;
+ break;
++ case SET_PASSWORDFILE:
++ if (pwdfile) fs_give ((void **) &pwdfile);
++ pwdfile = cpystr ((char *) value);
++ break;
++ case GET_PASSWORDFILE:
++ ret = (void *) pwdfile;
++ break;
+ case SET_SYSINBOX:
+ if (sysInbox) fs_give ((void **) &sysInbox);
+ sysInbox = cpystr ((char *) value);
+***************
+*** 1638,1640 ****
+--- 1647,1723 ----
+ }
+ return ret;
+ }
++
++ /*
++ *
++ * Module to add support for password file to a c-client application
++ *
++ * Written by Eduardo Chappa, based on password file support for Pine
++ *
++ */
++ #ifndef PWDFILE
++ #define PWDFILE 1
++ #endif
++
++ #define FIRSTCH 0x20
++ #define LASTCH 0x7e
++ #define TABSZ (LASTCH - FIRSTCH + 1)
++
++ char mm_xlate_out (char c);
++ void mm_userpwd (NETMBX *mb, char **username, char **password);
++
++ /* function that decodes passwords */
++
++ char mm_xlate_out (char c)
++ {
++ register int dti;
++ register int xch;
++
++ if((c >= FIRSTCH) && (c <= LASTCH)){
++ xch = c - (dti = xlate_key);
++ xch += (xch < FIRSTCH-TABSZ) ? 2*TABSZ : (xch < FIRSTCH) ? TABSZ : 0;
++ dti = (xch - FIRSTCH) + dti;
++ dti -= (dti >= 2*TABSZ) ? 2*TABSZ : (dti >= TABSZ) ? TABSZ : 0;
++ xlate_key = dti;
++ return(xch);
++ }
++ else
++ return(c);
++ }
++
++ void mm_userpwd (NETMBX *mb, char **username, char **password)
++ {
++ char *s;
++ char tmp[MAILTMPLEN], *ui[5];
++ FILE *fp;
++ int i, j, n;
++
++ if (!(pwdfile = env_parameters(GET_PASSWORDFILE, NULL)))
++ return;
++
++ if (fp = fopen(pwdfile, "r")){
++ for(n = 0; fgets(tmp, sizeof(tmp), fp); n++){
++ xlate_key = n;
++ for(i = 0; tmp[i]; i++)
++ tmp[i] = mm_xlate_out(tmp[i]);
++
++ if(i && tmp[i-1] == '\n')
++ tmp[i-1] = '\0';
++
++ ui[0] = ui[1] = ui[2] = ui[3] = ui[4] = NULL;
++ for(i = 0, j = 0; tmp[i] && j < 5; j++){
++ for(ui[j] = &tmp[i]; tmp[i] && tmp[i] != '\t'; i++);
++
++ if(tmp[i])
++ tmp[i++] = '\0';
++ }
++ if (*username && ui[1] && !strcmp(*username, ui[1]) && mb->host
++ && ((ui[2] && !strcmp(mb->host, ui[2]))
++ || (ui[4] && !strcmp(mb->host,ui[4]))
++ || (ui[2] && !strcmp(mb->orighost, ui[2]))
++ || (ui[4] && !strcmp(mb->orighost,ui[4]))))
++ strcpy (*password,ui[0]);
++ }
++ fclose(fp);
++ }
++ }
+diff -rc pine4.63/imap/src/osdep/unix/maildir.c pine4.63.I.USE/imap/src/osdep/unix/maildir.c
+*** pine4.63/imap/src/osdep/unix/maildir.c Thu May 19 19:59:15 2005
+--- pine4.63.I.USE/imap/src/osdep/unix/maildir.c Thu May 19 19:57:24 2005
+***************
+*** 0 ****
+--- 1,2031 ----
++ /*
++ * Maildir driver for Pine4.63
++ *
++ * Written by Eduardo Chappa <chappa@math.washington.edu>
++ * Last Update: May 04, 2005
++ *
++ * The IMAP toolkit provided in this Distribution is
++ * Copyright 2004 University of Washington.
++ * The full text of our legal notices is contained in the file called
++ * CPYRIGHT, included with this Distribution.
++ */
++
++ #include <stdio.h>
++ #include <ctype.h>
++ #include <errno.h>
++ extern int errno; /* just in case */
++ #include "mail.h"
++ #include "osdep.h"
++ #include <pwd.h>
++ #include <sys/stat.h>
++ #include <sys/time.h>
++ #include "maildir.h"
++ #include "rfc822.h"
++ #include "fdstring.h"
++ #include "misc.h"
++ #include "dummy.h"
++
++ /* Driver dispatch used by MAIL */
++ DRIVER maildirdriver = {
++ "md", /* driver name, yes it's md, not maildir */
++ /* driver flags */
++ DR_MAIL|DR_LOCAL|DR_NAMESPACE|DR_NOSTICKY,
++ (DRIVER *) NIL, /* next driver */
++ maildir_valid, /* mailbox is valid for us */
++ maildir_parameters, /* manipulate parameters */
++ NIL, /* scan mailboxes */
++ maildir_list, /* find mailboxes */
++ maildir_lsub, /* find subscribed mailboxes */
++ maildir_sub, /* subscribe to mailbox */
++ maildir_unsub, /* unsubscribe from mailbox */
++ maildir_create, /* create mailbox */
++ maildir_delete, /* delete mailbox */
++ maildir_rename, /* rename mailbox */
++ mail_status_default, /* status of mailbox */
++ maildir_open, /* open mailbox */
++ maildir_close, /* close mailbox */
++ maildir_fast, /* fetch message "fast" attributes */
++ NIL, /* fetch message flags */
++ NIL, /* fetch overview */
++ NIL, /* fetch message structure */
++ maildir_header, /* fetch message header */
++ maildir_text, /* fetch message body */
++ NIL, /* fetch partial message text */
++ NIL, /* unique identifier */
++ NIL, /* message number */
++ NIL, /* modify flags */
++ maildir_flagmsg, /* per-message modify flags */
++ NIL, /* search for message based on criteria */
++ NIL, /* sort messages */
++ NIL, /* thread messages */
++ maildir_ping, /* ping mailbox to see if still alive */
++ maildir_check, /* check for new messages */
++ maildir_expunge, /* expunge deleted messages */
++ maildir_copy, /* copy messages to another mailbox */
++ maildir_append, /* append string message to mailbox */
++ NIL /* garbage collect stream */
++ };
++
++
++ DRIVER courierdriver = {
++ "mc", /* Why a separate driver? So that
++ createproto will work */
++ /* driver flags */
++ DR_MAIL|DR_LOCAL|DR_NAMESPACE|DR_NOSTICKY,
++ (DRIVER *) NIL, /* next driver */
++ maildir_valid, /* mailbox is valid for us */
++ maildir_parameters, /* manipulate parameters */
++ NIL, /* scan mailboxes */
++ courier_list, /* find mailboxes */
++ maildir_lsub, /* find subscribed mailboxes */
++ maildir_sub, /* subscribe to mailbox */
++ maildir_unsub, /* unsubscribe from mailbox */
++ maildir_create, /* create mailbox */
++ maildir_delete, /* delete mailbox */
++ maildir_rename, /* rename mailbox */
++ mail_status_default, /* status of mailbox */
++ maildir_open, /* open mailbox */
++ maildir_close, /* close mailbox */
++ maildir_fast, /* fetch message "fast" attributes */
++ NIL, /* fetch message flags */
++ NIL, /* fetch overview */
++ NIL, /* fetch message structure */
++ maildir_header, /* fetch message header */
++ maildir_text, /* fetch message body */
++ NIL, /* fetch partial message text */
++ NIL, /* unique identifier */
++ NIL, /* message number */
++ NIL, /* modify flags */
++ maildir_flagmsg, /* per-message modify flags */
++ NIL, /* search for message based on criteria */
++ NIL, /* sort messages */
++ NIL, /* thread messages */
++ maildir_ping, /* ping mailbox to see if still alive */
++ maildir_check, /* check for new messages */
++ maildir_expunge, /* expunge deleted messages */
++ maildir_copy, /* copy messages to another mailbox */
++ maildir_append, /* append string message to mailbox */
++ NIL /* garbage collect stream */
++ };
++
++ MAILSTREAM maildirproto = {&maildirdriver}; /* prototype stream */
++ MAILSTREAM courierproto = {&courierdriver}; /* prototype stream */
++
++ void
++ md_domain_name(void)
++ {
++ int i;
++
++ strcpy(mdlocaldomain,mylocalhost ());
++ for (i = 0; mdlocaldomain[i] ; i++)
++ if(mdlocaldomain[i] == '/')
++ mdlocaldomain[i] = '\057';
++ else if (mdlocaldomain[i] == ':')
++ mdlocaldomain[i] = '\072';
++ }
++
++ /* remove the "#md/" or "#mc/" part from a folder name */
++ void maildir_remove_root (char **name)
++ {
++ int courier = IS_COURIER(*name);
++ char realname[MAILTMPLEN], *p;
++
++ if (maildir_valid_name(*name)){
++ (*name) += 3;
++ if (**name == '/')
++ (*name)++;
++ }
++ if(courier)
++ courier_realname(*name, realname);
++ else
++ strcpy(realname, *name);
++ *name = cpystr(realname);
++ }
++
++
++ /* Check validity of the name, we accept:
++ * a) #md/directory/folder
++ * b) #md/inbox
++ * A few considerations: We can only accept as valid
++ * a) names that start with #md/ and the directory exists or
++ * b) names that do not start with #md/ but are maildir directories (have
++ * the /cur, /tmp and /new structure)
++ */
++ int maildir_valid_name (char *name)
++ {
++ char tmpname[MAILTMPLEN] = {'\0'};
++
++ if (mdfpath)
++ fs_give((void **)&mdfpath);
++ if (name && (name[0] != '#'))
++ sprintf(tmpname,"%s%s",MDPREFIX(CCLIENT), name);
++ mdfpath = cpystr(tmpname[0] ? tmpname : name);
++
++ return IS_CCLIENT(name) || IS_COURIER(name);
++ }
++
++ /* Check if the directory whose path is given by name is a valid maildir
++ * directory (contains /cur, /tmp and /new)
++ */
++ int maildir_valid_dir (char *name)
++ {
++ int len;
++ DirNamesType i;
++ struct stat sbuf;
++ char tmp[MAILTMPLEN];
++
++ if(name[strlen(name) - 1] == '/')
++ name[strlen(name) - 1] = '\0';
++ len = strlen(name);
++ for (i = Cur; i != EndDir; i++){
++ MDFLD(tmp, name, i);
++ if (stat(tmp, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode))
++ break;
++ }
++ name[len] = '\0';
++ return i == EndDir ? T : NIL;
++ }
++
++ void courier_realname(char *name, char *realname)
++ {
++ int i,j;
++
++ if(!name)
++ return;
++
++ for (i = 0, j = 0; i < MAILTMPLEN && j < strlen(name); j++, i++){
++ realname[i] = name[j];
++ if(name[j] == '/' && name[j+1] != '.' && name[j+1] != '%'
++ && name[j+1] != '*')
++ realname[++i] = '.';
++ }
++ if(realname[i-1] == '.')
++ i--;
++ realname[i] = '\0';
++ }
++
++
++ /* given a maildir folder, return its path. Memory freed by caller. Directory
++ * does not contain the trailing slash "/". On error NULL is returned.
++ */
++ int maildir_file_path (char *name, char *tmp)
++ {
++ char *maildirpath = maildir_parameters(GET_INBOXPATH,NIL);
++ char realname[MAILTMPLEN];
++ int courier = IS_COURIER(name);
++
++ /* There are several ways in which the path can come, so we will handle
++ them here. First we deal with #mc/ or #md/ prefix by removing the
++ prefix, if any */
++
++ maildir_remove_root(&name);
++ tmp[0] = '\0'; /* just in case something fails */
++
++ if (strlen(myhomedir()) +
++ max(strlen(name), strlen(maildirpath
++ ? maildirpath : "Maildir")) > MAILTMPLEN){
++ errno = ENAMETOOLONG;
++ sprintf(tmp,"Error opening \"%s\": %s", name, strerror (errno));
++ mm_log(tmp,ERROR);
++ return NIL;
++ }
++
++ /* There are two ways in which the name can come here, either as a
++ full path or not. If it is not a full path it can come in two ways,
++ either as a file system path (Maildir/.Drafts) or as a maildir path
++ (INBOX.Drafts)
++ */
++
++ if(*name == '/') /* full path */
++ strcpy(tmp, name); /* do nothing */
++ else{
++ sprintf (tmp,"%s/%s%s%s", myhomedir (),
++ strncmp (ucase (strcpy (tmp, name)), "INBOX", 5)
++ ? name : (maildirpath ? maildirpath : "Maildir"),
++ strncmp (ucase (strcpy (tmp, name)), "INBOX", 5)
++ ? "" : (courier ? "/" : ""),
++ strncmp (ucase (strcpy (tmp, name)), "INBOX", 5)
++ ? "" : *(name+5) == MDSEPARATOR(courier) ? name+5 : "");
++ }
++
++ return tmp[0] ? T : NIL;
++ }
++
++ /* This function is given a full path for a mailbox and returns
++ * if it is a valid maildir transformed to canonical notation
++ */
++ int
++ is_valid_maildir (char **name)
++ {
++ if (!strncmp(*name, myhomedir (), strlen(myhomedir()))){
++ (*name) += strlen(myhomedir());
++ if (**name == '/') (*name)++;
++ }
++ return maildir_valid(*name) ? T : NIL;
++ }
++
++ /* Check validity of mailbox. This routine does not send errors to log, other
++ * routines calling this one may do so, though
++ */
++
++ DRIVER *maildir_valid (char *name)
++ {
++ char tmpname[MAILTMPLEN];
++
++ maildir_file_path(name, tmpname);
++
++ return maildir_valid_dir(tmpname)
++ ? (IS_COURIER(name) ? &courierdriver : &maildirdriver) : NIL;
++ }
++ /*maildir fast */
++ void maildir_fast (MAILSTREAM *stream,char *sequence,long flags)
++ {
++ unsigned long i;
++ MESSAGECACHE *elt;
++ /* get sequence */
++ if (stream && LOCAL && ((flags & FT_UID) ?
++ mail_uid_sequence (stream,sequence) :
++ mail_sequence (stream,sequence)))
++ for (i = 1; i <= stream->nmsgs; i++) {
++ if ((elt = mail_elt (stream,i))->sequence && (elt->valid = T) &&
++ !(elt->day && elt->rfc822_size)) {
++ ENVELOPE **env = NIL;
++ ENVELOPE *e = NIL;
++ if (!stream->scache) env = &elt->private.msg.env;
++ else if (stream->msgno == i) env = &stream->env;
++ else env = &e;
++ if (!*env || !elt->rfc822_size) {
++ STRING bs;
++ unsigned long hs;
++ char *ht = (*stream->dtb->header) (stream,i,&hs,NIL);
++
++ if (!*env) rfc822_parse_msg (env,NIL,ht,hs,NIL,BADHOST,
++ stream->dtb->flags);
++ if (!elt->rfc822_size) {
++ (*stream->dtb->text) (stream,i,&bs,FT_PEEK);
++ elt->rfc822_size = hs + SIZE (&bs) - GETPOS (&bs);
++ }
++ }
++
++ if (!elt->day && *env && (*env)->date)
++ mail_parse_date (elt,(*env)->date);
++
++ if (!elt->day) elt->day = elt->month = 1;
++ mail_free_envelope (&e);
++ }
++ }
++ }
++
++
++ /*
++ * return all files in a given directory. This is a separate call
++ * so that if there are warnings during compilation this only appears once.
++ */
++ unsigned long
++ maildir_scandir (char *name, struct direct ***flist,
++ unsigned long *nfiles, int *scand, int flag)
++ {
++ struct stat sbuf;
++
++ if (scand)
++ *scand = -1; /* assume error for safety */
++ stat(name,&sbuf); /* stat the containing directory */
++ if (scand)
++ *scand = scandir(name, flist,
++ flag == CCLIENT ? maildir_select : courier_dir_select,
++ flag == CCLIENT ? maildir_namesort : courier_dir_sort);
++ *nfiles = (scand && (*scand > 0)) ? (unsigned long) *scand : 0L;
++
++ return sbuf.st_ctime;
++ }
++
++ /* Does a message with given name exists (or was it removed)?
++ * Returns: 1 - yes, such message exist,
++ * 0 - No, that message does not exist anymore
++ *
++ * Parameters: stream, name of mailbox, new name if his message does not
++ * exist.
++ */
++
++ int maildir_message_exists(MAILSTREAM *stream, char *name, char *newfile)
++ {
++ char tmp[MAILTMPLEN];
++ int gotit = NIL;
++ DIR *dir;
++ struct direct *d;
++ struct stat sbuf;
++
++ /* First check directly if it exists, if not there, look for it */
++ sprintf(tmp,"%s/%s", LOCAL->curdir, name);
++ if ((stat(tmp, &sbuf) == 0) && ((sbuf.st_mode & S_IFMT) == S_IFREG))
++ return T;
++
++ if (!(dir = opendir (LOCAL->curdir)))
++ return NIL;
++
++ while ((d = readdir(dir)) && gotit == NIL){
++ if (d->d_name[0] == '.')
++ continue;
++ if (same_maildir_file(d->d_name, name)){
++ gotit = T;
++ strcpy(newfile, d->d_name);
++ }
++ }
++ closedir(dir);
++ return gotit;
++ }
++
++ /* Maildir open */
++
++ MAILSTREAM *maildir_open (MAILSTREAM *stream)
++ {
++ char tmp[MAILTMPLEN];
++ struct stat sbuf;
++
++ if (!stream) return &maildirproto;
++ if (stream->local) fatal ("maildir recycle stream");
++ md_domain_name(); /* get domain name for maildir files in mdlocaldomain */
++ stream->uid_last = stream->uid_validity = 0;
++ if (!stream->rdonly){
++ stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
++ stream->perm_answered = stream->perm_draft = T;
++ }
++ stream->uid_validity = time(0);
++ stream->local = (MAILDIRLOCAL *)fs_get (sizeof (MAILDIRLOCAL));
++ memset(LOCAL, 0, sizeof(MAILDIRLOCAL));
++ LOCAL->fd = -1;
++
++ LOCAL->courier = IS_COURIER(stream->mailbox);
++ strcpy(tmp, stream->mailbox);
++ if (maildir_file_path (stream->mailbox, tmp))
++ LOCAL->dir = cpystr (tmp);
++ if (LOCAL->dir){
++ MDFLD(tmp, LOCAL->dir, Cur);
++ LOCAL->curdir = cpystr (tmp);
++ if (stat (LOCAL->curdir,&sbuf) < 0) {
++ sprintf (tmp,"Can't open folder %s: %s",
++ stream->mailbox,strerror (errno));
++ mm_log (tmp,ERROR);
++ maildir_close(stream, 0);
++ return NIL;
++ }
++ }
++
++ if(maildir_file_path (stream->mailbox, tmp)){
++ fs_give ((void **) &stream->mailbox);
++ stream->mailbox = cpystr(tmp);
++ }
++
++ LOCAL->buf = (char *) fs_get ((LOCAL->buflen = MAXMESSAGESIZE) + 1);
++ stream->sequence++;
++ stream->nmsgs = stream->recent = 0;
++
++ maildir_parse_folder(stream, 1);
++
++ return stream;
++ }
++
++ /* Maildir initial parsing of the folder */
++ void
++ maildir_parse_folder (MAILSTREAM *stream, int full)
++ {
++ unsigned long total;
++
++ if (!stream) /* what??? */
++ return;
++
++ MM_CRITICAL(stream);
++
++ /* Scan old messages first, escoba! */
++ total = LOCAL ? maildir_parse_dir(stream, 0L, Cur, full)
++ : stream->nmsgs;
++ stream->nmsgs = LOCAL ? maildir_parse_dir(stream, total, New, full)
++ : stream->nmsgs;
++
++ MM_NOCRITICAL(stream);
++ }
++
++ /* Return the number of messages in the directory, while filling the
++ * elt structure.
++ */
++
++ unsigned long
++ maildir_parse_dir(MAILSTREAM *stream, unsigned long nmsgs,
++ DirNamesType dirtype, int full)
++ {
++ char tmp[MAILTMPLEN], tmp2[MAILTMPLEN], file[MAILTMPLEN],
++ newfile[MAILTMPLEN], *mdstr;
++ struct direct **names = NIL;
++ struct stat sbuf;
++ unsigned long i, j = 0L, nfiles, last_scan;
++ unsigned long recent = stream ? stream->recent : 0L;
++ int d = 0, f = 0, r = 0, s = 0, t = 0;
++ int k, we_compute, in_list, scan_err;
++ int silent = stream ? stream->silent : NIL;
++ MESSAGECACHE *elt;
++
++ MDFLD(tmp, LOCAL->dir, dirtype);
++ if (access (tmp, R_OK|W_OK|X_OK) != 0){
++ maildir_abort(stream);
++ return stream->nmsgs;
++ }
++
++ MDFLD(tmp, LOCAL->dir, Cur);
++ if (dirtype != New &&
++ (stat(tmp, &sbuf) < 0 || sbuf.st_ctime == LOCAL->scantime))
++ return stream->nmsgs;
++
++ MDFLD(tmp, LOCAL->dir, dirtype);
++ last_scan = maildir_scandir (tmp, &names, &nfiles, &scan_err, CCLIENT);
++ if (dirtype == Cur)
++ LOCAL->scantime = last_scan;
++
++ if (scan_err < 0){
++ maildir_abort(stream);
++ return nmsgs;
++ }
++
++ if (dirtype == Cur)
++ for (i = 1L; i <= stream->nmsgs;){
++ elt = mail_elt(stream, i);
++ in_list = elt && elt->maildirp && nfiles > 0L
++ ? (MDPOS(elt) < nfiles
++ ? same_maildir_file(MDFILE(elt), names[MDPOS(elt)]->d_name)
++ : NIL)
++ || maildir_message_in_list(MDFILE(elt), names, 0L,
++ nfiles - 1L, &MDPOS(elt))
++ : NIL;
++ if (!in_list){
++ if (elt->maildirp)
++ maildir_free_file ((void **) &elt->maildirp);
++
++ if (elt->recent) --recent;
++ mail_expunged(stream,i);
++ }
++ else i++;
++ }
++
++ stream->silent = T;
++ for (we_compute = 0, i = 1L; i <= nfiles; i++){
++ unsigned long pos, n;
++ mail_exists(stream, i + nmsgs);
++ elt = mail_elt(stream, i + nmsgs);
++ if (elt && elt->maildirp)
++ pos = MDPOS(elt); /* use data we found above */
++ else{
++ if (full)
++ pos = i - 1; /* first time, use sequence number */
++ else{
++ for (n = 0L ; (n < nfiles) && !names[n] ; n++);
++ pos = n; /* nfiles > stream->nmsgs!!, assign one */
++ }
++ }
++ if (dirtype == New) elt->recent = T;
++ if (!elt->private.uid){
++ elt->private.uid = stream->uid_last + 1;
++ stream->uid_validity = time(0);
++ }
++ if (stream->uid_last < elt->private.uid)
++ stream->uid_last = elt->private.uid;
++
++ maildir_getflag(names[pos]->d_name, &d, &f, &r ,&s, &t);
++ if (elt->maildirp)
++ maildir_free_file_only ((void **)&elt->maildirp);
++ else{
++ maildir_get_file((MAILDIRFILE **)&elt->maildirp);
++ we_compute++;
++ }
++ MDFILE(elt) = cpystr(names[pos]->d_name);
++ MDPOS(elt) = pos;
++
++ if (elt->draft != d || elt->flagged != f ||
++ elt->answered != r || elt->seen != s || elt->deleted != t){
++ elt->draft = d; elt->flagged = f; elt->answered = r;
++ elt->seen = s; elt->deleted = t;
++ if (!we_compute && !stream->rdonly)
++ MM_FLAGS(stream, i+nmsgs);
++ }
++ maildir_get_date(stream, i+nmsgs, dirtype);
++ elt->valid = T;
++ if (dirtype == New && !stream->rdonly){ /* move new messages to cur */
++ sprintf (file,"%s/%s", tmp, names[pos]->d_name);
++ if (stat (file,&sbuf) == 0 && S_ISREG (sbuf.st_mode)){
++ strcpy(tmp2,names[pos]->d_name);
++ if ((mdstr = strstr (names[pos]->d_name,MDSEP(3)))
++ || (mdstr = strstr (names[pos]->d_name,MDSEP(2)))){ /* Grrr */
++ *(mdstr+1) = '2';
++ sprintf (newfile,"%s/%s",LOCAL->curdir,names[pos]->d_name);
++ }
++ else{
++ sprintf (newfile,"%s/%s%s",LOCAL->curdir,names[pos]->d_name,MDSEP(2));
++ strcat(tmp2, MDSEP(2));
++ }
++ if (link (file,newfile) < 0){
++ mm_log("Unable to read new mail!",WARN);
++ }
++ else{
++ unlink (file);
++ j++; /* success!, count it! */
++ }
++ maildir_free_file_only((void **)&elt->maildirp);
++ MDFILE(elt) = cpystr(tmp2);
++ MDSIZE(elt) = sbuf.st_size;
++ MDMTIME(elt) = sbuf.st_mtime;
++ maildir_get_date(stream, i + nmsgs, New);
++ }
++ }
++ fs_give((void **)&names[pos]);
++ }
++ if(names)
++ fs_give((void **) &names);
++ stream->silent = silent;
++ if (dirtype == New && stream->rdonly)
++ j = nfiles;
++ mail_exists(stream, nmsgs + (dirtype == New ? j : nfiles));
++ mail_recent(stream, recent + (dirtype == New ? j : 0));
++
++ return (nmsgs + (dirtype == New ? j : nfiles));
++ }
++
++ long maildir_ping (MAILSTREAM *stream)
++ {
++ maildir_parse_folder(stream, 0);
++ return stream && LOCAL ? T : NIL;
++ }
++
++ int maildir_select (struct direct *name)
++ {
++ int rv = NIL, val;
++ val = name->d_name[0] - '0';
++ switch(val){
++ case 1: case 2: case 3: case 4: case 5:
++ case 6: case 7: case 8: case 9:
++ rv = T;
++ default: break;
++ }
++ return rv;
++ }
++
++ /*
++ * Unfortunately, there is no way to sort by arrival in this driver, this
++ * means that opening a folder in this driver using the scandir function
++ * will always make this driver slower than any driver that has a natural
++ * way of sorting by arrival (like a flat file format, "mbox", "mbx", etc).
++ */
++
++ int maildir_namesort (const void *d1,const void *d2)
++ {
++ const struct direct **e1, **e2;
++
++ e1 = (const struct direct **)d1;
++ e2 = (const struct direct **)d2;
++
++ return comp_maildir_file((char*)(*e1)->d_name, (char *)(*e2)->d_name);
++ }
++
++ /* Maildir close */
++
++ void maildir_close (MAILSTREAM *stream, long options)
++ {
++ MESSAGECACHE *elt;
++ unsigned long i;
++ int silent = stream ? stream->silent : 0;
++ mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
++
++ if (!stream) return;
++
++ for (i = 1; i <= stream->nmsgs; i++)
++ if ((elt = (MESSAGECACHE *) (*mc) (stream,i,CH_ELT)) && elt->maildirp)
++ maildir_free_file ((void **) &(elt->maildirp));
++ stream->silent = T;
++ if (options & CL_EXPUNGE) maildir_expunge (stream);
++ maildir_abort(stream);
++ if (mdfpath) fs_give((void **)&mdfpath);
++ stream->silent = silent;
++ }
++
++ void maildir_check (MAILSTREAM *stream)
++ {
++ if (maildir_ping (stream)) mm_log ("Check completed",(long) NIL);
++ }
++
++ long maildir_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs, long flags)
++ {
++ char tmp[MAILTMPLEN];
++ unsigned long i;
++ MESSAGECACHE *elt;
++ char *s;
++ /* UID call "impossible" */
++ if (flags & FT_UID || !LOCAL) return NIL;
++ elt = mail_elt (stream,msgno);
++ sprintf (tmp,"%s/%s",LOCAL->curdir, MDFILE(elt));
++ if (LOCAL->fd < 0) /* if file closed ? */
++ LOCAL->fd = open(tmp,O_RDONLY,NIL);
++
++ if (LOCAL->fd < 0 && (errno == EACCES || errno == ENOENT)){
++ INIT (bs, mail_string, "", 0);
++ elt->rfc822_size = 0L;
++ return NIL;
++ }
++
++ if (LOCAL->dirty == 0)
++ MM_FLAGS(stream, elt->msgno);
++
++ s = maildir_text_work(stream, elt, &i, flags);
++ INIT (bs, mail_string, s, i);
++ return T;
++ }
++
++ char *maildir_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
++ unsigned long *length,long flags)
++ {
++ FDDATA d;
++ STRING bs;
++ char *s,*t,*tl,tmp[CHUNK];
++ unsigned long msgno = elt->msgno;
++ static int try = 0;
++
++ if (length)
++ *length = 0L;
++ LOCAL->buf[0] = '\0';
++
++ sprintf (tmp,"%s/%s",LOCAL->curdir, MDFILE(elt));
++ if (LOCAL->fd < 0) /* if file closed ? */
++ LOCAL->fd = open(tmp,O_RDONLY,NIL);
++
++ if (LOCAL->fd < 0){ /* flag change? */
++ if (try < 5){
++ try++;
++ if (maildir_update_elt_maildirp(stream, msgno) > 0)
++ try = 0;
++ return maildir_text_work(stream, mail_elt(stream, msgno),length, flags);
++ }
++ try = 0;
++ return NULL;
++ }
++
++ lseek (LOCAL->fd, elt->private.msg.text.offset,L_SET);
++
++ if (flags & FT_INTERNAL) { /* initial data OK? */
++ if (elt->private.msg.text.text.size > LOCAL->buflen) {
++ fs_give ((void **) &LOCAL->buf);
++ LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
++ elt->private.msg.text.text.size) + 1);
++ }
++ read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size);
++ LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0';
++ }
++ else {
++ if (elt->rfc822_size > LOCAL->buflen) {
++ fs_give ((void **) &LOCAL->buf);
++ LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->rfc822_size) + 1);
++ }
++ d.fd = LOCAL->fd; /* yes, set up file descriptor */
++ d.pos = elt->private.msg.text.offset;
++ d.chunk = tmp; /* initial buffer chunk */
++ d.chunksize = CHUNK;
++ INIT (&bs,fd_string,&d,elt->private.msg.text.text.size);
++ for (s = LOCAL->buf; SIZE (&bs);) switch (CHR (&bs)) {
++ case '\r': /* carriage return seen */
++ *s++ = SNX (&bs); /* copy it and any succeeding LF */
++ if (SIZE (&bs) && (CHR (&bs) == '\n')) *s++ = SNX (&bs);
++ break;
++ case '\n':
++ *s++ = '\r'; /* insert a CR */
++ default:
++ *s++ = SNX (&bs); /* copy characters */
++ }
++ *s = '\0'; /* tie off buffer */
++ *length = s - (char *) LOCAL->buf; /* calculate length */
++ }
++ close(LOCAL->fd); LOCAL->fd = -1;
++ return LOCAL->buf;
++ }
++
++ /* maildir parse, fill the elt structure... well not all of it... */
++ unsigned long maildir_parse_message(MAILSTREAM *stream, unsigned long msgno,
++ DirNamesType dirtype)
++ {
++ char *b, *s, c;
++ char tmp[MAILTMPLEN];
++ struct stat sbuf;
++ unsigned long i, len;
++ int offset = 0, d, f, r, se, dt;
++ MESSAGECACHE *elt;
++
++ elt = mail_elt (stream,msgno);
++ MSGPATH(tmp, LOCAL->dir, MDFILE(elt), dirtype);
++ if(stat(tmp, &sbuf) == 0)
++ MDSIZE(elt) = sbuf.st_size;
++
++ maildir_get_date(stream, msgno, dirtype);
++ maildir_getflag(MDFILE(elt), &d, &f, &r ,&se, &dt);
++ elt->draft = d; elt->flagged = f; elt->answered = r; elt->seen = se;
++ elt->deleted = dt; elt->valid = T;
++ if (LOCAL->fd < 0) /* if file closed ? */
++ LOCAL->fd = open(tmp,O_RDONLY,NIL);
++
++ if (LOCAL->fd >= 0){
++ s = (char *) fs_get (MDSIZE(elt) + 1);
++ read (LOCAL->fd,s,MDSIZE(elt));
++ s[MDSIZE(elt)] = '\0';
++ for (i = 0, b = s; *b && !(i && (*b == '\n')); i = (*b++ == '\n'));
++ len = (*b ? ++b : b) - s;
++ elt->private.msg.header.text.size =
++ elt->private.msg.text.offset = len;
++ elt->private.msg.text.text.size = MDSIZE(elt) - len;
++ for (i = 0, b = s, c = *b; b && c &&
++ ((c < '\016') && (((c == '\012') && ++i) ||
++ ((c == '\015') && (*++b == '\012') && (i +=2)))
++ || c); i++, c= *++b);
++ elt->rfc822_size = i;
++ fs_give ((void **) &s);
++ close(LOCAL->fd); LOCAL->fd = -1;
++ }
++ return elt->rfc822_size;
++ }
++
++ int
++ maildir_update_elt_maildirp(MAILSTREAM *stream, unsigned long msgno)
++ {
++ char tmp[MAILTMPLEN];
++ struct direct **names = NIL;
++ unsigned long i, nfiles, pos;
++ int d = 0, f = 0 , r = 0, s = 0, t = 0, in_list, scan_err;
++ MESSAGECACHE *elt;
++
++ MDFLD(tmp, LOCAL->dir, Cur);
++
++ maildir_scandir (tmp, &names, &nfiles, &scan_err, CCLIENT);
++
++ elt = mail_elt (stream,msgno);
++
++ in_list = nfiles > 0L
++ ? maildir_message_in_list(MDFILE(elt), names, 0L,
++ nfiles - 1L, &pos)
++ : NIL;
++
++ if (in_list && pos >= 0L && pos < nfiles
++ && !strcmp(MDFILE(elt), names[pos]->d_name)){
++ in_list = NIL;
++ maildir_abort(stream);
++ }
++
++ if (in_list && pos >= 0L && pos < nfiles){
++ maildir_free_file_only((void **)&elt->maildirp);
++ MDFILE(elt) = cpystr(names[pos]->d_name);
++ maildir_getflag(MDFILE(elt), &d, &f, &r ,&s, &t);
++ if (elt->draft != d || elt->flagged != f ||
++ elt->answered != r || elt->seen != s || elt->deleted != t){
++ elt->draft = d; elt->flagged = f; elt->answered = r;
++ elt->seen = s; elt->deleted = t;
++ MM_FLAGS(stream, msgno);
++ }
++ }
++ for (i = 0L; i < nfiles; i++)
++ fs_give((void **) &names[i]);
++ if (names)
++ fs_give((void **) &names);
++ return in_list ? 1 : -1;
++ }
++
++ /* Maildir fetch message header */
++
++ char *maildir_header (MAILSTREAM *stream,unsigned long msgno,
++ unsigned long *length, long flags)
++ {
++ char tmp[MAILTMPLEN], *s;
++ MESSAGECACHE *elt;
++ static int try = 0;
++
++ if (length)
++ *length = 0;
++ if (flags & FT_UID || !LOCAL) return ""; /* UID call "impossible" */
++ elt = mail_elt (stream,msgno);
++ if(elt->private.msg.header.text.size == 0)
++ maildir_parse_message(stream, msgno, Cur);
++
++ sprintf (tmp,"%s/%s",LOCAL->curdir, MDFILE(elt));
++ if (LOCAL->fd < 0)
++ LOCAL->fd = open (tmp,O_RDONLY,NIL);
++
++ if (LOCAL->fd < 0 && errno == EACCES){
++ mm_log ("Message exists but can not be read. Envelope and body lost!",ERROR);
++ return NULL;
++ }
++
++ if (LOCAL->fd < 0){ /* flag change? */
++ if (try < 5){
++ try++;
++ if (maildir_update_elt_maildirp(stream, msgno) > 0)
++ try = 0;
++ return maildir_header(stream, msgno, length, flags);
++ }
++ try = 0;
++ return NULL;
++ }
++
++ if ((flags & FT_INTERNAL) &&
++ (elt->private.msg.header.text.size > LOCAL->buflen)){
++ fs_give ((void **) &LOCAL->buf);
++ LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
++ elt->private.msg.header.text.size) + 1);
++ }
++ else
++ s = (char *) fs_get(elt->private.msg.header.text.size+1);
++ if (LOCAL->fd >= 0){
++ read (LOCAL->fd, flags & FT_INTERNAL ? (void *)LOCAL->buf : (void *)s,
++ elt->private.msg.header.text.size);
++ if (flags & FT_INTERNAL)
++ LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0';
++ else{
++ s[*length = elt->private.msg.header.text.size] = '\0';
++ *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,
++ elt->private.msg.header.text.size);
++ fs_give ((void **) &s);
++ }
++ }
++ elt->private.msg.text.offset = elt->private.msg.header.text.size;
++ elt->private.msg.text.text.size = MDSIZE(elt) - elt->private.msg.text.offset;
++ if(s)
++ fs_give((void **)&s);
++ close(LOCAL->fd); LOCAL->fd = -1;
++ return LOCAL->buf;
++ }
++
++ /* Maildir find list of subscribed mailboxes
++ * Accepts: mail stream
++ * pattern to search
++ */
++
++ void maildir_list (MAILSTREAM *stream,char *ref, char *pat)
++ {
++ char *s,test[MAILTMPLEN],file[MAILTMPLEN];
++ long i = 0;
++
++ if((!pat || !*pat) && (maildir_canonicalize (test,ref,"*"))
++ && maildir_valid_name(test)){ /* there is a #md/ leading here */
++ for (i = 3; test[i] && test[i] != '/'; i++);
++ if (s = strchr (test+i+1,'/')) *++s = '\0';
++ else test[0] = '\0';
++ mm_list (stream,'/',test, LATT_NOSELECT);
++ }
++ else if (maildir_canonicalize (test,ref,pat)) {
++ if (test[3] == '/') { /* looking down levels? */
++ /* yes, found any wildcards? */
++ if (s = strpbrk (test,"%*")) {
++ /* yes, copy name up to that point */
++ strncpy (file,test+4,i = s - (test+4));
++ file[i] = '\0'; /* tie off */
++ }
++ else strcpy (file,test+4);/* use just that name then */
++ /* find directory name */
++ if (s = strrchr (file,'/')) {
++ *s = '\0'; /* found, tie off at that point */
++ s = file;
++ }
++ /* do the work */
++ if(IS_COURIER(test))
++ courier_list_work (stream,s,test,0);
++ else
++ maildir_list_work (stream,s,test,0);
++ }
++ /* always an INBOX */
++ if (!compare_cstring (test,"#MD/INBOX"))
++ mm_list (stream,NIL,"#MD/INBOX",LATT_NOINFERIORS);
++ if (!compare_cstring (test,"#MC/INBOX"))
++ mm_list (stream,NIL,"#MC/INBOX",LATT_NOINFERIORS);
++ }
++ }
++
++ void courier_list (MAILSTREAM *stream,char *ref, char *pat)
++ {
++ /* I am too lazy to do anything. Do you care to ask maildir list, please?
++ The real reason why this is a dummy function is because we do not want to
++ see the same folder listed twice.
++ */
++ }
++
++ /* For those that want to hide things, we give them a chance to do so */
++ void *maildir_parameters (long function, void *value)
++ {
++ void *ret = NIL;
++ switch ((int) function) {
++ case SET_INBOXPATH:
++ if (myMdInboxDir) fs_give ((void **) &myMdInboxDir);
++ myMdInboxDir = cpystr ((char *) value);
++ case GET_INBOXPATH:
++ if (!myMdInboxDir) myMdInboxDir = cpystr("Maildir");
++ ret = (void *) myMdInboxDir;
++ break;
++ case SET_COURIERSTYLE:
++ CourierStyle = (long) value;
++ case GET_COURIERSTYLE:
++ ret = (void *) CourierStyle;
++ break;
++ default:
++ break;
++ }
++ return ret;
++ }
++
++ int maildir_create_folder(char *mailbox)
++ {
++ char tmp[MAILTMPLEN], err[MAILTMPLEN];
++ int i;
++
++ for (i = Cur; i != EndDir; i++){
++ MDFLD(tmp, mailbox, i);
++ if (mkdir(tmp, 0700) && errno != EEXIST){ /* try to make new dir */
++ sprintf (err, "Can't create %s: %s", tmp, strerror(errno));
++ mm_log (err,ERROR);
++ return NIL;
++ }
++ }
++ return T;
++ }
++
++ int maildir_create_work(char *mailbox, int loop)
++ {
++ char *s, c, err[MAILTMPLEN], tmp[MAILTMPLEN], tmp2[MAILTMPLEN], mbx[MAILTMPLEN];
++ int fnlen, i, create_dir = 0, courier, mv;
++ struct stat sbuf;
++ long style = (long) maildir_parameters(GET_COURIERSTYLE, NIL);
++
++ courier = IS_COURIER(mailbox);
++ strcpy(mbx, mailbox);
++ mv = maildir_valid(mbx) ? 1 : 0;
++ maildir_file_path(mailbox, tmp);
++ if (mailbox[strlen(mailbox) - 1] == MDSEPARATOR(courier)){
++ create_dir++;
++ mailbox[strlen(mailbox) - 1] = '\0';
++ }
++
++ if(!loop && courier){
++ if(mv){
++ if(create_dir){
++ if(style == CCLIENT)
++ strcpy (err,"Can not create directory: folder exists. Create subfolder");
++ else
++ strcpy(err,"Folder and Directory already exist");
++ }
++ else
++ strcpy (err, "Can't create mailbox: mailbox already exists");
++ }
++ else{
++ if(create_dir)
++ strcpy(err, "Can not create directory. Cread folder instead");
++ else
++ err[0] = '\0';
++ }
++ if(err[0]){
++ mm_log (err,ERROR);
++ return NIL;
++ }
++ }
++
++ fnlen = strlen(tmp);
++ if (s = strrchr(mailbox,MDSEPARATOR(courier))){
++ c = *++s;
++ *s = '\0';
++ if ((stat(tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
++ !maildir_create_work (mailbox, ++loop))
++ return NIL;
++ *s = c;
++ }
++ tmp[fnlen] = '\0';
++
++ if (mkdir(tmp,0700) && errno != EEXIST)
++ return NIL;
++
++ if (create_dir)
++ mailbox[fnlen] = '/';
++
++ if (create_dir){
++ if(style == CCLIENT){
++ if(!courier){
++ FILE *fp = NULL;
++ sprintf(tmp2,"%s%s", tmp, MDDIR);
++ if ((fp = fopen(tmp2,"w")) == NULL){
++ sprintf (err,"Problem creating %s: %s", tmp2, strerror(errno));
++ mm_log (err,ERROR);
++ return NIL;
++ }
++ fclose(fp);
++ }
++ }
++ return T;
++ }
++ else
++ return maildir_create_folder(tmp);
++ }
++
++ long maildir_create (MAILSTREAM *stream,char *mailbox)
++ {
++ char tmp[MAILTMPLEN], err[MAILTMPLEN];
++ long rv;
++ int create_dir;
++
++ create_dir = mailbox ?
++ (mailbox[strlen(mailbox) - 1] ==
++ MDSEPARATOR(IS_COURIER(mailbox))) : 0;
++ maildir_file_path(mailbox, tmp);
++ strcpy(tmp, mailbox);
++ rv = maildir_create_work(mailbox, 0);
++ strcpy(mailbox, tmp);
++ if (rv == 0){
++ sprintf (err,"Can't create %s %s",
++ create_dir ? "directory" : "mailbox", mailbox);
++ mm_log (err,ERROR);
++ }
++ return rv ? 1L : 0L;
++ }
++
++ #define MAXTRY 10000
++ void maildir_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
++ {
++ char oldfile[MAILTMPLEN],newfile[MAILTMPLEN],fn[MAILTMPLEN];
++ char tmp[MAILTMPLEN];
++ char *s;
++ int ren, try = 0;
++
++ LOCAL->dirty = 0;
++ if (elt->valid){
++ for (try = 1; try > 0 && try < MAXTRY; try++){
++ /* build the new filename */
++ sprintf (oldfile,"%s/%s",LOCAL->curdir, MDFILE(elt));
++ fn[0] = '\0';
++ if ((ren = maildir_message_exists(stream, MDFILE(elt), fn)) == 0){
++ errno = ENOENT;
++ try = MAXTRY;
++ }
++ if (*fn) /* new oldfile! */
++ sprintf (oldfile,"%s/%s",LOCAL->curdir,fn);
++ if ((s = strchr (MDFILE(elt), FLAGSEP))) *s = '\0';
++ sprintf (fn,"%s%s%s%s%s%s%s", MDFILE(elt), MDSEP(2),
++ MDFLAG(Draft, elt->draft), MDFLAG(Flagged, elt->flagged),
++ MDFLAG(Replied, elt->answered), MDFLAG(Seen, elt->seen),
++ MDFLAG(Trashed, elt->deleted));
++ sprintf (newfile,"%s/%s",LOCAL->curdir,fn);
++ if (ren != 0 && rename (oldfile,newfile) >= 0)
++ try = -1;
++ }
++
++ if (try > 0){
++ sprintf(oldfile,"Unable to write flags to disk: %s",
++ errno == ENOENT ? "message is gone!" : strerror (errno));
++ mm_log(oldfile,ERROR);
++ LOCAL->dirty = 1;
++ return;
++ }
++ maildir_free_file_only ((void **) &elt->maildirp);
++ MDFILE(elt) = cpystr (fn);
++ }
++ }
++
++ void maildir_expunge (MAILSTREAM *stream)
++ {
++ MESSAGECACHE *elt;
++ unsigned long i;
++ unsigned long n = 0;
++ unsigned long nmsgs = stream->nmsgs;
++ unsigned long recent = stream->recent;
++ char tmp[MAILTMPLEN];
++
++ mm_critical (stream); /* go critical */
++ for (i = 1; i <= stream->nmsgs;)
++ if ((elt = mail_elt (stream,i))->deleted){
++ sprintf (tmp,"%s/%s",LOCAL->curdir, MDFILE(elt));
++ if (unlink (tmp)) {/* try to delete the message */
++ sprintf (tmp,"Expunge of message %ld failed, aborted: %s",i,
++ strerror (errno));
++ if (!stream->silent)
++ mm_log (tmp,WARN);
++ break;
++ }
++ /* free the cached filename */
++ if (elt->maildirp)
++ maildir_free_file ((void **) &elt->maildirp);
++
++ if (elt->recent) --recent;/* if recent, note one less recent message */
++ mail_expunged (stream,i); /* notify upper levels */
++ n++; /* count up one more expunged message */
++ }
++ else i++;
++ if (n) { /* output the news if any expunged */
++ sprintf (tmp,"Expunged %ld messages",n);
++ if (!stream->silent)
++ mm_log (tmp,(long) NIL);
++ }
++ else
++ if (!stream->silent)
++ mm_log ("No messages deleted, so no update needed",(long) NIL);
++ mm_nocritical (stream); /* release critical */
++ /* notify upper level of new mailbox size */
++ mail_exists (stream,stream->nmsgs);
++ mail_recent (stream,recent);
++ }
++
++ long maildir_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
++ {
++ STRING st;
++ MESSAGECACHE *elt;
++ unsigned long len;
++ int fd;
++ long i, length;
++ struct stat sbuf;
++ char tmp[MAILTMPLEN], flags[MAILTMPLEN], path[MAILTMPLEN], *s, *b;
++ /* copy the messages */
++ if ((options & CP_UID) ? mail_uid_sequence (stream, sequence) :
++ mail_sequence (stream,sequence))
++ for (i = 1; i <= stream->nmsgs; i++)
++ if ((elt = mail_elt (stream,i))->sequence){
++ sprintf (path,"%s/%s",LOCAL->curdir, MDFILE(elt));
++ if (((fd = open (path,O_RDONLY,NIL)) < 0)
++ ||((!elt->rfc822_size &&
++ ((stat(path, &sbuf) < 0) || !S_ISREG (sbuf.st_mode)))))
++ return NIL;
++ if(!elt->rfc822_size)
++ MDSIZE(elt) = sbuf.st_size;
++ s = (char *) fs_get(MDSIZE(elt) + 1);
++ read (fd,s,MDSIZE(elt));
++ s[MDSIZE(elt)] = '\0';
++ close (fd);
++ len = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen, s, MDSIZE(elt));
++ INIT (&st,mail_string, LOCAL->buf, len);
++ elt->rfc822_size = len;
++ fs_give ((void **)&s);
++
++ flags[0] = flags[1] = '\0';
++ if (elt->seen) strcat (flags," \\Seen");
++ if (elt->draft) strcat (flags," \\Draft");
++ if (elt->deleted) strcat (flags," \\Deleted");
++ if (elt->flagged) strcat (flags," \\Flagged");
++ if (elt->answered) strcat (flags," \\Answered");
++ flags[0] = '('; /* open list */
++ strcat (flags,")"); /* close list */
++ mail_date (tmp,elt); /* generate internal date */
++ if (!mail_append_full (NIL,mailbox,flags,tmp,&st))
++ return NIL;
++ if (options & CP_MOVE) elt->deleted = T;
++ }
++ return T; /* return success */
++ }
++
++ long maildir_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
++ {
++ int fd;
++ STRING *message;
++ char c,*s, *flags, *date;
++ char tmp[MAILTMPLEN],file[MAILTMPLEN],path1[MAILTMPLEN],path2[MAILTMPLEN];
++ MESSAGECACHE elt;
++ long i;
++ long size = 0;
++ long ret = LONGT;
++ unsigned long uf;
++ long f;
++ static unsigned int transact = 0;
++
++ if (!maildir_valid(mailbox)) {
++ sprintf (tmp,"Not a valid Maildir mailbox: %s",mailbox);
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++
++ if (!*mdlocaldomain)
++ md_domain_name(); /* get domain name for maildir files in mdlocaldomain now! */
++
++ if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
++
++ mm_critical (stream); /* go critical */
++ do {
++ if (!SIZE (message)) { /* guard against zero-length */
++ mm_log ("Append of zero-length message",ERROR);
++ ret = NIL;
++ break;
++ }
++ if (date && !mail_parse_date(&elt,date)){
++ sprintf (tmp,"Bad date in append: %.80s",date);
++ mm_log (tmp,ERROR);
++ ret = NIL;
++ break;
++ }
++ f = mail_parse_flags (stream,flags,&uf);
++ /* build file name we will use */
++ sprintf (file,"%u.%d_%09u.%s%s%s%s%s%s",
++ time (0),getpid (),transact++,mdlocaldomain, f ? MDSEP(2) : "",
++ MDFLAG(Draft, f&fDRAFT), MDFLAG(Flagged, f&fFLAGGED),
++ MDFLAG(Replied, f&fANSWERED), MDFLAG(Seen, f&fSEEN));
++ /* build tmp file name */
++ if (maildir_file_path(mailbox, tmp))
++ MSGPATH(path1, tmp, file, Tmp);
++
++ if ((fd = open (path1,O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE)) < 0) {
++ sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++ for (size = 0,i = SIZE (message),s = (char *) fs_get (i + 1); i; --i)
++ if ((c = SNX (message)) != '\015') s[size++] = c;
++ if ((write (fd,s,size) < 0) || fsync (fd)) {
++ unlink (path1); /* delete message */
++ sprintf (tmp,"Message append failed: %s",strerror (errno));
++ mm_log (tmp,ERROR);
++ ret = NIL;
++ }
++ fs_give ((void **) &s); /* flush the buffer */
++ close (fd); /* close the file */
++ /* build final filename to use */
++ if (maildir_file_path(mailbox, tmp))
++ MSGPATH(path2, tmp, file, New);
++ if (link (path1,path2) < 0) {
++ sprintf (tmp,"Message append failed: %s",strerror (errno));
++ mm_log (tmp,ERROR);
++ ret = NIL;
++ }
++ unlink (path1);
++
++ if (ret)
++ if (!(*af) (stream,data,&flags,&date,&message)) ret = NIL;
++
++ } while (ret && message); /* write the data */
++
++ mm_nocritical (stream); /* release critical */
++ return ret;
++ }
++
++ long maildir_delete (MAILSTREAM *stream,char *mailbox)
++ {
++ DIR *dirp;
++ struct direct *d;
++ int i, remove_dir = 0, mddir = 0, rv, error = 0;
++ char tmp[MAILTMPLEN],tmp2[MAILTMPLEN], realname[MAILTMPLEN];
++ struct stat sbuf;
++ char *mdpath = maildir_parameters(GET_INBOXPATH,NIL);
++ int courier = IS_COURIER(mailbox);
++
++ if (mailbox[strlen(mailbox) - 1] == MDSEPARATOR(courier)){
++ remove_dir++;
++ mailbox[strlen(mailbox) -1] = '\0';
++ }
++
++ if (!maildir_valid(mailbox)){
++ maildir_file_path(mailbox, tmp);
++ if (stat(tmp, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode)){
++ sprintf(tmp,"Can not remove %s", mailbox);
++ error++;
++ }
++ }
++
++ if (!error && remove_dir && !maildir_dir_is_empty(mailbox)){
++ sprintf(tmp,"Can not remove directory %s/: directory not empty", mailbox);
++ error++;
++ }
++
++ if(error){
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++
++ maildir_close(stream,0); /* even if stream was NULL */
++
++ maildir_file_path(mailbox, realname);
++
++ if (remove_dir){
++ sprintf(tmp,"%s/%s", realname, MDDIR);
++ if ((rv = stat (tmp,&sbuf)) == 0 && S_ISREG(sbuf.st_mode))
++ rv = unlink(tmp);
++ else if (errno == ENOENT)
++ rv = 0;
++ if (rv != 0){
++ sprintf(tmp,"Can not remove %s/%s: %s", tmp2, MDDIR, strerror(errno));
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++ if (!maildir_valid(realname) && rmdir(realname) != 0){
++ sprintf(tmp,"Can not remove %s/: %s", mailbox, strerror(errno));
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++ return T;
++ }
++ /* else remove just the folder. Remove all hidden files, except MDDIR */
++ for (i = Cur; i != EndDir; i++){
++ MDFLD(tmp, realname, i);
++
++ if (!(dirp = opendir (tmp))){
++ sprintf(tmp,"Can not read %s/: %s", mailbox, strerror(errno));
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++
++ while (d = readdir(dirp)){
++ if (strcmp(d->d_name, ".") && strcmp(d->d_name,"..")){
++ sprintf(tmp2,"%s/%s", tmp, d->d_name);
++ if (unlink(tmp2) != 0){
++ sprintf(tmp2,"Can not remove %s: %s", mailbox, strerror(errno));
++ mm_log (tmp2,ERROR);
++ return NIL;
++ }
++ }
++ }
++ closedir(dirp);
++ if (rmdir(tmp) != 0){
++ sprintf(tmp,"Can not remove %s: %s", mailbox, strerror(errno));
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++ }
++ /*
++ * ok we have removed all subdirectories of the folder mailbox, Remove the
++ * hidden files.
++ */
++
++ if (!(dirp = opendir (realname))){
++ sprintf(tmp,"Can not read %s/: %s", realname, strerror(errno));
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++
++ while (d = readdir(dirp)){
++ if (strcmp(d->d_name, ".") && strcmp(d->d_name,"..")
++ && !strcmp(d->d_name, MDDIR)){
++ sprintf(tmp,"%s/%s", realname, d->d_name);
++ mddir++;
++ if (unlink(tmp) != 0)
++ error++;
++ }
++ }
++ closedir(dirp);
++ if (error ||
++ (maildir_dir_is_empty(mailbox) && mddir == 0 && rmdir(realname) < 0)){
++ sprintf(tmp,"Can not remove folder %s: %s", mailbox, strerror(errno));
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++ return T;
++ }
++
++ long maildir_rename (MAILSTREAM *stream, char *old, char *new)
++ {
++ struct direct **names = NIL;
++ struct stat sbuf;
++ char pathname[MAILTMPLEN], dir[MAILTMPLEN], curdir[MAILTMPLEN];
++ char tmp[MAILTMPLEN],tmpnew[MAILTMPLEN], realold[MAILTMPLEN];
++ char realnew[MAILTMPLEN],realpat[MAILTMPLEN], realname[MAILTMPLEN];
++ char *pat, *endold, c;
++ char *maildirpath = maildir_parameters(GET_INBOXPATH, NIL);
++ int courier = IS_COURIER(old) && IS_COURIER(new);
++ int scand, i, j, rv = T;
++ unsigned long ndir;
++ COURIER_S *cdir;
++
++ if((IS_COURIER(old) || IS_COURIER(new)) && !courier){
++ sprintf (tmp,"Can't rename mailbox %s to %s",old, new);
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++
++ if (!maildir_valid(old)){
++ sprintf (tmp,"Can't rename mailbox %s: folder not in maildir format",old);
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++ maildir_file_path(old, realold);
++ if (!maildir_valid_name(new) && new[0] == '#'){
++ sprintf (tmp,"Can't rename mailbox %s: folder not in maildir format",new);
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++ maildir_file_path(new, realnew);
++ if (access(tmpnew,F_OK) == 0){ /* new mailbox name must not exist */
++ sprintf (tmp,"Can't rename to mailbox %s: destination already exists",new);
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++
++ if(!courier){
++ if (rename (realold,realnew)){ /* try to rename the directory */
++ sprintf (tmp,"Can't rename mailbox %s to %s: %s",old, new,
++ strerror(errno));
++ mm_log (tmp,ERROR);
++ return NIL;
++ }
++ return T; /* return success */
++ }
++
++ cdir = courier_list_dir(old);
++ for (i = 0; cdir && i < cdir->total; i++){
++ if(strstr(cdir->data[i]->name, old)){
++ sprintf(tmp,"%s%s", new, cdir->data[i]->name+strlen(old));
++ maildir_file_path(cdir->data[i]->name, realold);
++ maildir_file_path(tmp, realnew);
++ if (rename (realold,realnew)){
++ sprintf (tmp,"Can't rename mailbox %s to %s: %s",old, new,
++ strerror(errno));
++ mm_log (tmp,ERROR);
++ rv = NIL;
++ }
++ }
++ }
++ courier_free_cdir(&cdir);
++ return rv;
++ }
++
++ long maildir_sub (MAILSTREAM *stream,char *mailbox)
++ {
++ return sm_subscribe (mailbox);
++ }
++
++ long maildir_unsub (MAILSTREAM *stream,char *mailbox)
++ {
++ return sm_unsubscribe (mailbox);
++ }
++
++ void maildir_lsub (MAILSTREAM *stream,char *ref,char *pat)
++ {
++ void *sdb = NIL;
++ char *s, test[MAILTMPLEN];
++ /* get canonical form of name */
++ if (maildir_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) {
++ do if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,NIL);
++ while (s = sm_read (&sdb)); /* until no more subscriptions */
++ }
++ }
++
++ long maildir_canonicalize (char *pattern,char *ref,char *pat)
++ {
++ if (ref && *ref) { /* have a reference */
++ strcpy (pattern,ref); /* copy reference to pattern */
++ /* # overrides mailbox field in reference */
++ if (*pat == '#') strcpy (pattern,pat);
++ /* pattern starts, reference ends, with / */
++ else if ((*pat == '/') && (pattern[strlen (pattern) - 1] == '/'))
++ strcat (pattern,pat + 1); /* append, omitting one of the period */
++
++ else strcat (pattern,pat); /* anything else is just appended */
++ }
++ else strcpy (pattern,pat); /* just have basic name */
++ return (maildir_valid_name(pattern));
++ }
++
++ void maildir_list_work (MAILSTREAM *stream,char *dir,char *pat,long level)
++ {
++ DIR *dp;
++ struct direct *d;
++ struct stat sbuf;
++ char *cp,*np, curdir[MAILTMPLEN],name[MAILTMPLEN], tmp[MAILTMPLEN];
++ int i;
++ char *maildirpath = maildir_parameters(GET_INBOXPATH, NIL);
++
++ sprintf(curdir,"%s/%s/", myhomedir(), dir ? dir :
++ (maildirpath ? maildirpath : "Maildir"));
++ if (dp = opendir (curdir)){
++ if (dir) sprintf (name,"%s%s/",MDPREFIX(CCLIENT),dir);
++ else strcpy (name,MDPREFIX(CCLIENT));
++
++ if (level == 0 && name && pmatch_full (name, pat, '/'))
++ mm_list (stream,'/', name, LATT_NOSELECT);
++
++ while (d = readdir (dp))
++ if(strcmp(d->d_name, ".") && strcmp(d->d_name,"..")
++ && strcmp(d->d_name, MDNAME(Cur))
++ && strcmp(d->d_name, MDNAME(Tmp))
++ && strcmp(d->d_name, MDNAME(New))){
++
++ if (dir) sprintf (tmp,"%s%s", name,d->d_name);
++ else strcpy(tmp, d->d_name);
++
++ if(pmatch_full (tmp, pat,'/')){
++ sprintf(tmp,"%s/%s/%s", myhomedir(), dir ? dir :
++ (maildirpath ? maildirpath : "Maildir"), d->d_name);
++ if(stat (tmp,&sbuf) == 0
++ && ((sbuf.st_mode & S_IFMT) == S_IFDIR)){
++ if (dir) sprintf (tmp,"%s%s", name,d->d_name);
++ else strcpy(tmp, d->d_name);
++ i = maildir_valid(tmp)
++ ? (maildir_contains_folder(dir, d->d_name)
++ ? LATT_HASCHILDREN
++ : (maildir_is_dir(dir, d->d_name)
++ ? LATT_HASNOCHILDREN : LATT_NOINFERIORS))
++ : LATT_NOSELECT;
++ i += maildir_any_new_msgs(tmp)
++ ? LATT_MARKED : LATT_UNMARKED;
++ mm_list (stream,'/',tmp, i);
++ strcat (tmp, "/");
++ if(dmatch (tmp, pat,'/') &&
++ (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL))){
++ sprintf(tmp,"%s/%s",dir,d->d_name);
++ maildir_list_work (stream,tmp,pat,level+1);
++ }
++ }
++ }
++ }
++ }
++ closedir (dp);
++ }
++
++ void courier_list_work (MAILSTREAM *stream, char *dir, char *pat, long level)
++ {
++ unsigned long ndir;
++ struct direct **names = NIL;
++ struct stat sbuf;
++ char c, d, curdir[MAILTMPLEN],name[MAILTMPLEN], tmp[MAILTMPLEN];
++ char realname[MAILTMPLEN], realpat[MAILTMPLEN] = {'\0'}, pathname[MAILTMPLEN];
++ int i, j, scand;
++ long style = (long) maildir_parameters(GET_COURIERSTYLE, NIL);
++ char *maildirpath = maildir_parameters(GET_INBOXPATH, NIL);
++ COURIER_S *cdir;
++
++ j = strlen(pat) - 1;
++ maildir_file_path(pat, realpat);
++ c = pat[j];
++ pat[j] = '\0';
++ realname[0] = '\0';
++ if(dir)
++ maildir_file_path(dir, realname);
++ sprintf(curdir,"%s%s%s/%s", dir ? "" : myhomedir(), dir ? "" : "/",
++ dir ? realname : (maildirpath ? maildirpath : "Maildir"),
++ dir ? "" : ".");
++
++ sprintf(tmp, "%s%s/.", MDPREFIX(COURIER), dir ? dir :
++ (maildirpath ? maildirpath : "Maildir"));
++ if (level == 0 && tmp && pmatch_full (tmp, realpat, '.'))
++ mm_list (stream,'.', tmp, LATT_NOSELECT);
++
++ cdir = courier_list_dir(pat);
++ pat[j] = c;
++ for (i = 0; cdir && i < cdir->total; i++){
++ if(pmatch_full (cdir->data[i]->name, pat, '.')){
++ sprintf(tmp, "%s.", cdir->data[i]->name);
++ if(maildir_valid(cdir->data[i]->name)){
++ if(courier_search_list(cdir->data, tmp, 0, cdir->total - 1))
++ cdir->data[i]->attribute = LATT_HASCHILDREN;
++ else
++ cdir->data[i]->attribute = style == COURIER
++ ? LATT_HASNOCHILDREN : LATT_NOINFERIORS;
++ }
++ else
++ cdir->data[i]->attribute = LATT_NOSELECT;
++ cdir->data[i]->attribute += maildir_any_new_msgs(cdir->data[i]->name)
++ ? LATT_MARKED : LATT_UNMARKED;
++ mm_list (stream,'.',cdir->data[i]->name, cdir->data[i]->attribute);
++ }
++ }
++ courier_free_cdir(&cdir);
++ }
++
++ int
++ same_maildir_file(char *name1, char *name2)
++ {
++ char tmp1[MAILTMPLEN], tmp2[MAILTMPLEN];
++ char *s;
++
++ strcpy(tmp1, name1 ? name1 : "");
++ strcpy(tmp2, name2 ? name2 : "");
++ if (s = strchr(tmp1, FLAGSEP))
++ *s = '\0';
++ if (s = strchr(tmp1, SIZESEP))
++ *s = '\0';
++ if (s = strchr(tmp2, FLAGSEP))
++ *s = '\0';
++ if (s = strchr(tmp2, SIZESEP))
++ *s = '\0';
++
++ return !strcmp(tmp1, tmp2);
++ }
++
++
++ int comp_maildir_file(char *name1, char *name2)
++ {
++ unsigned long t1, t2;
++ int i;
++
++ if (!(name1 && *name1))
++ return name2 && *name2 ? (*name2 == FLAGSEP ? 0 : -1) : 0;
++
++ if (!(name2 && *name2))
++ return name1 && *name1 ? (*name1 == FLAGSEP ? 0 : 1) : 0;
++
++ if(!strcmp(name1,name2))
++ return 0;
++
++ t1 = strtoul(name1, NULL, 10);
++ t2 = strtoul(name2, NULL, 10);
++
++ if (t1 < t2)
++ return -1;
++
++ if (t1 > t2)
++ return 1;
++
++ i = strchr(name1,'.') - name1 + 1;
++ return (strcmp (name1 + i, name2 + i));
++ }
++
++ void
++ maildir_getflag(char *name, int *d, int *f, int *r ,int *s, int *t)
++ {
++ char tmp[MAILTMPLEN], *b;
++ int offset = 0;
++
++ if(d && f && r && s && t)
++ *d = *f = *r = *s = *t = 0;
++ else
++ return; /* can not call this function with null arguments */
++
++ strcpy(tmp,name);
++ while (b = strchr(tmp+offset, FLAGSEP)){
++ char flag,last;
++ int i,k;
++ if (!++b) break;
++ switch (*b){
++ case '1':
++ case '2':
++ case '3': flag = *b; b += 2;
++ for (k = 0; b[k] && b[k] != FLAGSEP && b[k] != ','; k++);
++ last = b[k];
++ b[k] = '\0';
++ if (flag == '2' || flag == '3'){
++ *d = strchr (b, MDFLAGC(Draft)) ? T : NIL;
++ *f = strchr (b, MDFLAGC(Flagged)) ? T : NIL;
++ *r = strchr (b, MDFLAGC(Replied)) ? T : NIL;
++ *s = strchr (b, MDFLAGC(Seen)) ? T : NIL;
++ *t = strchr (b, MDFLAGC(Trashed)) ? T : NIL;
++ }
++ b[k] = last;
++ b += k;
++ for (; tmp[offset] && tmp[offset] != FLAGSEP; offset++);
++ offset++;
++ break;
++ default: break; /* Should we crash?... Nahhh */
++ }
++ }
++ }
++
++ int
++ maildir_message_in_list(char *msgname, struct direct **names,
++ unsigned long bottom, unsigned long top, unsigned long *pos)
++ {
++ unsigned long middle = (bottom + top)/2;
++ int test;
++
++ if (!msgname)
++ return NIL;
++
++ if (pos) *pos = middle;
++
++ if (same_maildir_file(msgname, names[middle]->d_name))
++ return T;
++
++ if (middle == bottom){ /* 0 <= 0 < 1 */
++ int rv = NIL;
++ if (same_maildir_file(msgname, names[middle]->d_name)){
++ rv = T;
++ if (pos) *pos = middle;
++ }
++ else
++ if (same_maildir_file(msgname, names[top]->d_name)){
++ rv = T;
++ if (pos) *pos = top;
++ }
++ return rv;
++ }
++
++ test = comp_maildir_file(msgname, names[middle]->d_name);
++
++ if (top <= bottom)
++ return test ? NIL : T;
++
++ if (test < 0 ) /* bottom < msgname < middle */
++ return maildir_message_in_list(msgname, names, bottom, middle, pos);
++ else if (test > 0) /* middle < msgname < top */
++ return maildir_message_in_list(msgname, names, middle, top, pos);
++ else return T;
++ }
++
++ void
++ maildir_abort(MAILSTREAM *stream)
++ {
++ if (LOCAL){
++ if (LOCAL->dir) fs_give ((void **) &LOCAL->dir);
++ if (LOCAL->curdir) fs_give ((void **) &LOCAL->curdir);
++ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
++ fs_give ((void **) &stream->local);
++ }
++ if (mdfpath) fs_give((void **)&mdfpath);
++ stream->dtb = NIL;
++ }
++
++ int
++ maildir_contains_folder(char *dirname, char *name)
++ {
++ char tmp[MAILTMPLEN], tmp2[MAILTMPLEN];
++ int rv = 0;
++ DIR *dir;
++ struct direct *d;
++ struct stat sbuf;
++ char *maildirpath = maildir_parameters(GET_INBOXPATH, NIL);
++
++ sprintf(tmp2,"%s/%s/%s", myhomedir(), dirname ? dirname
++ : (maildirpath ? maildirpath : "Maildir"), name);
++
++ if (!(dir = opendir (tmp2)))
++ return NIL;
++
++ while (d = readdir(dir)){
++ if (strcmp(d->d_name, ".") && strcmp(d->d_name,"..")
++ && strcmp(d->d_name, MDNAME(Cur))
++ && strcmp(d->d_name, MDNAME(Tmp))
++ && strcmp(d->d_name, MDNAME(New))){
++
++ sprintf(tmp,"%s/%s", tmp2, d->d_name);
++ if(maildir_valid(tmp)){
++ rv++;
++ break;
++ }
++ }
++ }
++ closedir(dir);
++ return rv;
++ }
++
++ int
++ maildir_is_dir(char *dirname, char *name)
++ {
++ char tmp[MAILTMPLEN];
++ struct stat sbuf;
++ char *maildirpath = maildir_parameters(GET_INBOXPATH, NIL);
++
++ sprintf(tmp,"%s/%s/%s/%s", myhomedir(), dirname ? dirname
++ : (maildirpath ? maildirpath : "Maildir"), name, MDDIR);
++
++ return (stat(tmp, &sbuf) == 0 && S_ISREG (sbuf.st_mode)) ? 1 : 0;
++ }
++
++ int
++ maildir_dir_is_empty(char *mailbox)
++ {
++ char tmp[MAILTMPLEN], tmp2[MAILTMPLEN];
++ int rv = 1;
++ DIR *dir;
++ struct direct *d;
++ struct stat sbuf;
++
++ maildir_file_path(mailbox, tmp2);
++
++ if (!(dir = opendir (tmp2)))
++ return rv;
++
++ while (d = readdir(dir)){
++ sprintf(tmp,"%s/%s", tmp2, d->d_name);
++ if (strcmp(d->d_name, ".")
++ && strcmp(d->d_name,"..")
++ && strcmp(d->d_name, MDNAME(Cur))
++ && strcmp(d->d_name, MDNAME(Tmp))
++ && strcmp(d->d_name, MDNAME(New))
++ && strcmp(d->d_name, MDDIR)
++ && strcmp(d->d_name, MDUIDVALIDITY)
++ && !(d->d_name[0] == '.'
++ && stat (tmp,&sbuf) == 0
++ && S_ISREG(sbuf.st_mode))){
++ rv = 0;
++ break;
++ }
++ }
++ closedir(dir);
++ return rv;
++ }
++
++ void
++ maildir_get_file (MAILDIRFILE **mdfile)
++ {
++ MAILDIRFILE *md;
++
++ md = (MAILDIRFILE *) fs_get(sizeof(MAILDIRFILE));
++ memset(md, 0, sizeof(MAILDIRFILE));
++ *mdfile = md;
++ }
++
++ void
++ maildir_free_file (void **mdfile)
++ {
++ MAILDIRFILE *md = (mdfile && *mdfile) ? (MAILDIRFILE *) *mdfile : NULL;
++
++ if (md){
++ if (md->name) fs_give((void **)&md->name);
++ fs_give((void **)&md);
++ }
++ }
++
++ void
++ maildir_free_file_only (void **mdfile)
++ {
++ MAILDIRFILE *md = (mdfile && *mdfile) ? (MAILDIRFILE *) *mdfile : NULL;
++
++ if (md && md->name)
++ fs_give((void **)&md->name);
++ }
++
++ int
++ maildir_any_new_msgs(char *mailbox)
++ {
++ char tmp[MAILTMPLEN];
++ int rv = NIL;
++ DIR *dir;
++ struct direct *d;
++ struct stat sbuf;
++
++ MDFLD(tmp, mailbox, New);
++
++ if (!(dir = opendir (tmp)))
++ return rv;
++
++ while (d = readdir(dir)){
++ if (d->d_name[0] == '.')
++ continue;
++ rv = T;
++ break;
++ }
++ closedir(dir);
++ return rv;
++ }
++
++
++ void
++ maildir_get_date(MAILSTREAM *stream, unsigned long msgno, DirNamesType dirtype)
++ {
++ MESSAGECACHE *elt;
++ struct tm *tm;
++ unsigned long t1;
++
++ elt = mail_elt (stream,msgno);
++ if ((t1 = strtoul(MDFILE(elt), NULL, 10)) > 0){
++ tm = gmtime (&t1);
++ elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
++ elt->year = tm->tm_year + 1900 - BASEYEAR;
++ elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
++ elt->seconds = tm->tm_sec;
++ elt->zhours = 0; elt->zminutes = 0;
++ }
++ }
++
++ /* Support for Courier Style directories
++
++ When this code is complete there will be two types of support, which
++ will be configurable. The problem is the following: In Courier style
++ folder structure, a "folder" may have a subfolder called
++ "folder.subfolder", which is not natural in the file system in the
++ sense that I can not stat for "folder.subfolder" wihtout knowing what
++ "subfolder" is. It needs to be guessed. Because of this I need to look
++ in the list of folders if there is a folder with a name
++ "folder.subfolder", before I can say if the folder is dual or not. One
++ can avoid this annoyance if one ignores the problem by declaring that
++ every folder is dual. I will however code as the default the more
++ complicated idea of scaning the containing directory each time it is
++ modified and search for subfolders, and list the entries it found.
++ */
++
++ int courier_dir_select (struct direct *name)
++ {
++ return name->d_name[0] == '.' && (strlen(name->d_name) > 2
++ || (strlen(name->d_name) == 2 && name->d_name[1] != '.'));
++ }
++
++ int courier_dir_sort (const void *d1, const void *d2)
++ {
++ const struct direct **e1, **e2;
++
++ e1 = (const struct direct **)d1;
++ e2 = (const struct direct **)d2;
++
++ return strcmp((char*)(*e1)->d_name, (char *)(*e2)->d_name);
++ }
++
++ void courier_free_cdir (COURIER_S **cdir)
++ {
++ int i;
++
++ if (!*cdir)
++ return;
++
++ if ((*cdir)->path) fs_give((void **)&((*cdir)->path));
++ for (i = 0; i < (*cdir)->total; i++)
++ if((*cdir)->data[i]->name) fs_give((void **)&((*cdir)->data[i]->name));
++ fs_give((void **)&((*cdir)->data));
++ fs_give((void **)&(*cdir));
++ }
++
++ COURIER_S *courier_get_cdir (int total)
++ {
++ COURIER_S *cdir;
++
++ cdir = (COURIER_S *)fs_get(sizeof(COURIER_S));
++ memset(cdir, 0, sizeof(COURIER_S));
++ cdir->data = (COURIERLOCAL **) fs_get(total*sizeof(COURIERLOCAL *));
++ cdir->total = total;
++ return cdir;
++ }
++
++ int courier_search_list(COURIERLOCAL **data, char *name, int first, int last)
++ {
++ int try = (first + last)/2;
++
++ if(!strstr(data[try]->name, name)){
++ if(first == try) /* first == last || first + 1 == last */
++ return strstr(data[last]->name, name) ? 1 : 0;
++ if(strcmp(data[try]->name, name) < 0) /*data[try] < name < data[end] */
++ return courier_search_list(data, name, try, last);
++ else /* data[begin] < name < data[try] */
++ return courier_search_list(data, name, first, try);
++ }
++ return 1;
++ }
++
++ /* Lists all directories that are subdirectories of a given directory */
++
++ COURIER_S *courier_list_dir(char *curdir)
++ {
++ struct direct **names = NIL;
++ struct stat sbuf;
++ unsigned long ndir;
++ COURIER_S *cdir;
++ char tmp[MAILTMPLEN], tmp2[MAILTMPLEN], pathname[MAILTMPLEN],
++ realname[MAILTMPLEN];
++ char *maildirpath = maildir_parameters(GET_INBOXPATH, NIL);
++ int i, j, scand;
++
++ /* There are two cases, either curdir is
++ #mc/INBOX. #mc/INBOX.foo
++ or
++ #mc/Maildir/. #mc/Maildir/.foo
++ */
++ strcpy(tmp,curdir + 4);
++ if(!strncmp(ucase(tmp), "INBOX", 5))
++ strcpy(tmp, "#mc/INBOX.");
++ else{
++ strcpy(tmp, curdir);
++ for (i = strlen(tmp) - 1; tmp[i] && tmp[i] != '/'; i--);
++ tmp[i+2] = '\0'; /* keep the last "." intact */
++ }
++ maildir_file_path(tmp, realname);
++ maildir_scandir (realname, &names, &ndir, &scand, COURIER);
++
++ if (scand > 0){
++ cdir = courier_get_cdir(ndir);
++ cdir->path = cpystr(realname);
++ for(i = 0, j = 0; i < ndir; i++){
++ sprintf(tmp2,"%s%s", tmp, names[i]->d_name+1);
++ sprintf(pathname,"%s%s", realname, names[i]->d_name);
++ if(stat(pathname, &sbuf) == 0 && S_ISDIR(sbuf.st_mode)){
++ cdir->data[j] = (COURIERLOCAL *) fs_get(sizeof(COURIERLOCAL));
++ cdir->data[j++]->name = cpystr(tmp2);
++ }
++ fs_give((void **)&names[i]);
++ }
++ if(names)
++ fs_give((void **) &names);
++ cdir->total = j;
++ }
++ return cdir;
++ }
+diff -rc pine4.63/imap/src/osdep/unix/maildir.h pine4.63.I.USE/imap/src/osdep/unix/maildir.h
+*** pine4.63/imap/src/osdep/unix/maildir.h Thu May 19 19:59:15 2005
+--- pine4.63.I.USE/imap/src/osdep/unix/maildir.h Thu May 19 19:57:24 2005
+***************
+*** 0 ****
+--- 1,185 ----
++ /*
++ * A few definitions that try to make this module portable to other
++ * platforms (e.g. Cygwin). This module is based on the information from
++ * http://cr.yp.to/proto/maildir.html
++ */
++
++ /* First we deal with the separator character */
++ #ifndef FLAGSEP
++ #define FLAGSEP ':'
++ #endif
++ #define SIZESEP ','
++
++ #define MDUIDVALIDITY ".uidvalidity" /* support for old maildirs */
++ #define MDDIR ".mdir" /* this folder is a directory */
++
++ const char sep1[] = {FLAGSEP, '1', ',', '\0'}; /* experimental semantics*/
++ const char sep2[] = {FLAGSEP, '2', ',', '\0'}; /* Flags Information */
++ const char sep3[] = {FLAGSEP, '3', ',', '\0'}; /* Grrrr.... */
++
++ const char *sep[] = { sep1, sep2, sep3, NULL};
++
++ #define MDSEP(i) sep[((i) - 1)]
++
++ /* Now we deal with flags. Woohoo! */
++ typedef enum {Draft, Flagged, Passed, Replied, Seen, Trashed,
++ EmptyFlag, EndFlags} MdFlagNamesType;
++ const int mdimapflags[] = {Draft, Flagged, Replied, Seen, Trashed, EmptyFlag, EndFlags};
++ const int mdkwdflags[] = {Passed, EmptyFlag, EndFlags};
++
++ /* this array lists the codes for mdflgnms (maildir flag names) above */
++ const char *mdflags[] = { "D", "F", "P", "R", "S", "T", "", NULL};
++ /* and as characters too */
++ const char cmdflags[] = { 'D', 'F', 'P', 'R', 'S', 'T', '0', '\0'};
++
++ /* MDFLAG(Seen, elt->seen) */
++ #define MDFLAG(i,j) mdflags[j ? (i) : EmptyFlag]
++ /* MDFLAGC(Seen) */
++ #define MDFLAGC(i) cmdflags[(i)]
++
++ /* Now we deal with the directory structure */
++ typedef enum {Cur, Tmp, New, EndDir} DirNamesType;
++ char *mdstruct[] = {"cur", "tmp", "new", NULL};
++ #define MDNAME(i) mdstruct[(i)]
++ #define MDFLD(tmp, dir, i) sprintf((tmp),"%s/%s", (dir), mdstruct[(i)])
++ #define MSGPATH(tmp, dir, msg,i) sprintf((tmp),"%s/%s/%s", (dir), mdstruct[(i)],(msg))
++
++ /* Support of Courier Structure */
++ #define CCLIENT 0
++ #define COURIER 1
++ #define IS_CCLIENT(t) \
++ (((t) && (t)[0] == '#' && ((t)[1] == 'm' || (t)[1] == 'M')\
++ && ((t)[2] == 'd' || (t)[2] == 'D')\
++ && (t)[3] == '/' && (t)[4] != '\0') ? 1 : 0)
++
++ #define IS_COURIER(t) \
++ (((t) && (t)[0] == '#' && ((t)[1] == 'm' || (t)[1] == 'M')\
++ && ((t)[2] == 'c' || (t)[2] == 'C')\
++ && (t)[3] == '/' && (t)[4] != '\0') ? 1 : 0)
++ #define MDPREFIX(s) ((s) ? "#mc/" : "#md/")
++ #define MDSEPARATOR(s) ((s) ? '.' : '/')
++
++
++ /* Now we deal with messages filenames */
++ char mdlocaldomain[MAILTMPLEN+1] = {'\0'};
++ static char *mdfpath = NULL;
++ static char *myMdInboxDir = NIL;/* Location of the Maildir INBOX */
++ static long CourierStyle = CCLIENT;
++
++ #define CHUNK 16384 /* from unix.h */
++
++ typedef struct courier_local {
++ char *name; /* name of directory/folder */
++ int attribute; /* attributes (children/marked/etc) */
++ } COURIERLOCAL;
++
++ typedef struct courier {
++ char *path; /* Path to collection */
++ time_t scantime; /* time at which information was generated */
++ int total; /* total number of elements in data */
++ COURIERLOCAL **data;
++ } COURIER_S;
++
++ /* In gdb this is the *(struct maildir_local *)stream->local structure */
++ typedef struct maildir_local {
++ unsigned int dirty : 1; /* diskcopy needs updating */
++ unsigned int courier : 1; /* It is Courier style file system */
++ int fd; /* fd of open message */
++ char *dir; /* mail directory name */
++ char *curdir; /* mail directory name/cur */
++ unsigned char *buf; /* temporary buffer */
++ unsigned long buflen; /* current size of temporary buffer */
++ time_t scantime; /* last time directory scanned */
++ } MAILDIRLOCAL;
++
++ /* Convenient access to local data */
++ #define LOCAL ((MAILDIRLOCAL *) stream->local)
++
++ typedef struct maildir_file_info {
++ char *name; /* name of the file */
++ unsigned long pos; /* place in list where this file is listed */
++ off_t size; /* size in bytes, on disk */
++ time_t atime; /* last access time */
++ time_t mtime; /* last modified time */
++ time_t ctime; /* last changed time */
++ } MAILDIRFILE;
++
++ #define MDFILE(F) (((MAILDIRFILE *)((F)->maildirp))->name)
++ #define MDPOS(F) (((MAILDIRFILE *)((F)->maildirp))->pos)
++ #define MDSIZE(F) (((MAILDIRFILE *)((F)->maildirp))->size)
++ #define MDATIME(F) (((MAILDIRFILE *)((F)->maildirp))->atime)
++ #define MDMTIME(F) (((MAILDIRFILE *)((F)->maildirp))->mtime)
++ #define MDCTIME(F) (((MAILDIRFILE *)((F)->maildirp))->ctime)
++
++ /* Function prototypes */
++
++ DRIVER *maildir_valid (char *name);
++ MAILSTREAM *maildir_open (MAILSTREAM *stream);
++ void maildir_close (MAILSTREAM *stream, long options);
++ long maildir_ping (MAILSTREAM *stream);
++ void maildir_check (MAILSTREAM *stream);
++ long maildir_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
++ char *maildir_header (MAILSTREAM *stream,unsigned long msgno,
++ unsigned long *length, long flags);
++ void maildir_list (MAILSTREAM *stream,char *ref,char *pat);
++ void *maildir_parameters (long function,void *value);
++ int maildir_create_folder (char *mailbox);
++ long maildir_create (MAILSTREAM *stream,char *mailbox);
++ void maildir_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); /*check */
++ void maildir_expunge (MAILSTREAM *stream);
++ long maildir_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
++ long maildir_append (MAILSTREAM *stream,char *mailbox, append_t af, void *data);
++ long maildir_delete (MAILSTREAM *stream,char *mailbox);
++ long maildir_rename (MAILSTREAM *stream,char *old,char *new);
++ long maildir_sub (MAILSTREAM *stream,char *mailbox);
++ long maildir_unsub (MAILSTREAM *stream,char *mailbox);
++ void maildir_lsub (MAILSTREAM *stream,char *ref,char *pat);
++ void courier_list (MAILSTREAM *stream,char *ref, char *pat);
++
++ /* utility functions */
++ void courier_realname (char *name, char *realname);
++ char *maildir_file (char *dst,char *name);
++ int maildir_select (struct direct *name);
++ int maildir_namesort (const void *d1, const void *d2);
++ int courier_dir_select (struct direct *name);
++ int courier_dir_sort (const void *d1, const void *d2);
++ long maildir_canonicalize (char *pattern,char *ref,char *pat);
++ void maildir_list_work (MAILSTREAM *stream,char *subdir,char *pat,long level);
++ void courier_list_work (MAILSTREAM *stream,char *subdir,char *pat,long level);
++ int maildir_file_path(char *name, char *tmp);
++ int maildir_valid_name (char *name);
++ int maildir_valid_dir (char *name);
++ int is_valid_maildir (char **name);
++ int maildir_message_exists(MAILSTREAM *stream,char *name, char *tmp);
++ void maildir_remove_root(char **name);
++ char *maildir_text_work (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned long *length,long flags);
++ unsigned long maildir_parse_message(MAILSTREAM *stream, unsigned long msgno,
++ DirNamesType dirtype);
++ unsigned long maildir_scandir (char *name, struct direct ***flist,
++ unsigned long *nfiles, int *scand, int flag);
++ void maildir_parse_folder (MAILSTREAM *stream, int full);
++ void md_domain_name (void);
++ unsigned long maildir_parse_dir(MAILSTREAM *stream, unsigned long nmsgs,
++ DirNamesType dirtype, int full);
++ int same_maildir_file(char *name1, char *name2);
++ int comp_maildir_file(char *name1, char *name2);
++ int maildir_message_in_list(char *msgname, struct direct **names,
++ unsigned long bottom, unsigned long top, unsigned long *pos);
++ void maildir_getflag(char *name, int *d, int *f, int *r ,int *s, int *t);
++ int maildir_update_elt_maildirp(MAILSTREAM *stream, unsigned long msgno);
++ void maildir_abort (MAILSTREAM *stream);
++ int maildir_contains_folder(char *dirname, char *name);
++ int maildir_is_dir(char *dirname, char *name);
++ int maildir_dir_is_empty(char *mailbox);
++ int maildir_create_work (char *mailbox, int loop);
++ void maildir_get_file (MAILDIRFILE **mdfile);
++ void maildir_free_file (void **mdfile);
++ void maildir_free_file_only (void **mdfile);
++ int maildir_any_new_msgs(char *mailbox);
++ void maildir_get_date(MAILSTREAM *stream, unsigned long msgno, DirNamesType dirtype);
++ void maildir_fast (MAILSTREAM *stream,char *sequence,long flags);
++
++ void courier_free_cdir (COURIER_S **cdir);
++ COURIER_S *courier_get_cdir (int total);
++ int courier_search_list(COURIERLOCAL **data, char *name, int first, int last);
++ COURIER_S *courier_list_dir(char *curdir);
+diff -rc pine4.63/imap/src/osdep/unix/os_cyg.h pine4.63.I.USE/imap/src/osdep/unix/os_cyg.h
+*** pine4.63/imap/src/osdep/unix/os_cyg.h Mon Apr 19 08:22:07 2004
+--- pine4.63.I.USE/imap/src/osdep/unix/os_cyg.h Thu May 19 19:57:24 2005
+***************
+*** 39,44 ****
+--- 39,45 ----
+ #define setpgrp setpgid
+
+ #define SYSTEMUID 18 /* Cygwin returns this for SYSTEM */
++ #define FLAGSEP ';'
+ #define geteuid Geteuid
+ uid_t Geteuid (void);
+
+diff -rc pine4.63/pico/basic.c pine4.63.I.USE/pico/basic.c
+*** pine4.63/pico/basic.c Fri May 7 14:36:44 2004
+--- pine4.63.I.USE/pico/basic.c Thu May 19 19:57:33 2005
+***************
+*** 267,273 ****
+ int f, n; /* default Flag & Numeric argument */
+ {
+ int quoted, qlen;
+! char qstr[NLINE], qstr2[NLINE];
+
+ if (n < 0) /* the other way...*/
+ return(gotoeop(f, -n));
+--- 267,273 ----
+ int f, n; /* default Flag & Numeric argument */
+ {
+ int quoted, qlen;
+! char qstr[NLINE], qstr2[NLINE], ind_str[NLINE];
+
+ if (n < 0) /* the other way...*/
+ return(gotoeop(f, -n));
+***************
+*** 279,284 ****
+--- 279,295 ----
+ curwp->w_dotp = lback(curwp->w_dotp);
+ curwp->w_doto = 0;
+ }
++
++ if (indent_match((glo_quote_str || (Pmaster && Pmaster->quote_str))
++ ? (glo_quote_str ? glo_quote_str : Pmaster->quote_str)
++ : "",
++ curwp->w_dotp,ind_str, NLINE, 0)){
++ if (n){ /* look for another paragraph ? */
++ curwp->w_dotp = lback(curwp->w_dotp);
++ continue;
++ }
++ break;
++ }
+
+ /* scan line by line until we come to a line ending with
+ * a <NL><NL> or <NL><TAB> or <NL><SPACE>
+***************
+*** 288,294 ****
+ */
+ quoted = (glo_quote_str || (Pmaster && Pmaster->quote_str))
+ ? quote_match(glo_quote_str ? glo_quote_str : Pmaster->quote_str,
+! curwp->w_dotp, qstr, NLINE) : 0;
+ qlen = quoted ? strlen(qstr) : 0;
+ while(lback(curwp->w_dotp) != curbp->b_linep
+ && llength(lback(curwp->w_dotp)) > qlen
+--- 299,305 ----
+ */
+ quoted = (glo_quote_str || (Pmaster && Pmaster->quote_str))
+ ? quote_match(glo_quote_str ? glo_quote_str : Pmaster->quote_str,
+! curwp->w_dotp, qstr, NLINE, 0) : 0;
+ qlen = quoted ? strlen(qstr) : 0;
+ while(lback(curwp->w_dotp) != curbp->b_linep
+ && llength(lback(curwp->w_dotp)) > qlen
+***************
+*** 296,308 ****
+ ? (quoted == quote_match(glo_quote_str ? glo_quote_str
+ : Pmaster->quote_str,
+ lback(curwp->w_dotp),
+! qstr2, NLINE)
+ && !strcmp(qstr, qstr2))
+ : 1)
+ && lgetc(curwp->w_dotp, qlen).c != TAB
+ && lgetc(curwp->w_dotp, qlen).c != ' ')
+ curwp->w_dotp = lback(curwp->w_dotp);
+
+ if(n){
+ /* keep looking */
+ if(lback(curwp->w_dotp) == curbp->b_linep)
+--- 307,361 ----
+ ? (quoted == quote_match(glo_quote_str ? glo_quote_str
+ : Pmaster->quote_str,
+ lback(curwp->w_dotp),
+! qstr2, NLINE, 0)
+ && !strcmp(qstr, qstr2))
+ : 1)
++ && !indent_match((glo_quote_str
++ || (Pmaster && Pmaster->quote_str))
++ ? (glo_quote_str ? glo_quote_str : Pmaster->quote_str)
++ : "",
++ lback(curwp->w_dotp),ind_str, NLINE, 0)
+ && lgetc(curwp->w_dotp, qlen).c != TAB
+ && lgetc(curwp->w_dotp, qlen).c != ' ')
+ curwp->w_dotp = lback(curwp->w_dotp);
+
++ /*
++ * Ok, we made it here and we assume that we are at the begining
++ * of the paragraph. Let's double check this now. In order to do
++ * so we shell check if the first line was indented in a special
++ * way.
++ */
++ if(lback(curwp->w_dotp) == curbp->b_linep)
++ break;
++ else{
++ int indented, i, j;
++
++ /*
++ * for the following test we need to have the raw values,
++ * not the processed values
++ */
++ if (glo_quote_str || (Pmaster && Pmaster->quote_str)){
++ quote_match(glo_quote_str ? glo_quote_str : Pmaster->quote_str,
++ curwp->w_dotp, qstr, NLINE, 1);
++ quote_match(glo_quote_str ? glo_quote_str : Pmaster->quote_str,
++ lback(curwp->w_dotp), qstr2, NLINE, 1);
++ }
++ else
++ qstr[0] = qstr2[0] = '\0';
++ indented = indent_match((glo_quote_str || (Pmaster && Pmaster->quote_str))
++ ? (glo_quote_str ? glo_quote_str : Pmaster->quote_str)
++ : "",
++ lback(curwp->w_dotp),
++ ind_str, NLINE, 1);
++ if (strlenis(qstr2) + strlenis(ind_str) < strlenis(qstr))
++ indented = 0; /* Hack, so that it won't return one more line */
++ for (i= 0,j=0; qstr[i] && qstr2[i] && (qstr[i] == qstr2[i]);i++,j++);
++ for (; isspace(qstr2[i]); i++);
++ for (; isspace(qstr[j]); j++);
++ if (!qstr2[i] && !qstr[j] && indented)
++ curwp->w_dotp = lback(curwp->w_dotp);
++ }
++
+ if(n){
+ /* keep looking */
+ if(lback(curwp->w_dotp) == curbp->b_linep)
+***************
+*** 329,346 ****
+ return(TRUE);
+ }
+
+!
+ /*
+! * go forword to the end of the current paragraph
+ * here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
+ * combination to delimit the begining of a paragraph
+ */
+ gotoeop(f, n)
+ int f, n; /* default Flag & Numeric argument */
+-
+ {
+! int quoted, qlen;
+! char qstr[NLINE], qstr2[NLINE];
+
+ if (n < 0) /* the other way...*/
+ return(gotobop(f, -n));
+--- 382,581 ----
+ return(TRUE);
+ }
+
+! GetAccent()
+! {
+! char c,d;
+! c = (char) GetKey();
+! if ((c == '?') || (c == '!')) {
+! d = c;
+! c = '\\';
+! }
+! else
+! if ((c == 's') || (c == 'S')){
+! c = d = 's';
+! }
+! else
+! if ((c == 'l') || (c == 'L')){
+! c = d = 'l';
+! }
+! else
+! d = (char) GetKey();
+! return (int) accent(c,d);
+! }
+!
+! pineaccent(f,n)
+! int f,n;
+! { int e;
+!
+! if (e = GetAccent())
+! execute(e,0,1);
+! return 1;
+! }
+!
+! unsigned char accent(f,n)
+! int f,n;
+! { char c,d;
+!
+! c = (char) f;
+! d = (char) n;
+! switch(c){
+! case '~' :
+! switch(d){
+! case 'a' : return '\343';
+! case 'n' : return '\361';
+! case 'o' : return '\365';
+! case 'A' : return '\303';
+! case 'N' : return '\321';
+! case 'O' : return '\325';
+! }
+! break;
+! case '\047' :
+! switch(d){
+! case 'a' : return '\341';
+! case 'e' : return '\351';
+! case 'i' : return '\355';
+! case 'o' : return '\363';
+! case 'u' : return '\372';
+! case 'y' : return '\375';
+! case 'A' : return '\301';
+! case 'E' : return '\311';
+! case 'I' : return '\315';
+! case 'O' : return '\323';
+! case 'U' : return '\332';
+! case 'Y' : return '\335';
+! }
+! break;
+! case '"' :
+! switch(d){
+! case 'a' : return '\344';
+! case 'e' : return '\353';
+! case 'i' : return '\357';
+! case 'o' : return '\366';
+! case 'u' : return '\374';
+! case 'y' : return '\377';
+! case 'A' : return '\304';
+! case 'E' : return '\313';
+! case 'I' : return '\317';
+! case 'O' : return '\326';
+! case 'U' : return '\334';
+! }
+! break;
+! case '^' :
+! switch(d){
+! case 'a' : return '\342';
+! case 'e' : return '\352';
+! case 'i' : return '\356';
+! case 'o' : return '\364';
+! case 'u' : return '\373';
+! case 'A' : return '\302';
+! case 'E' : return '\312';
+! case 'I' : return '\316';
+! case 'O' : return '\324';
+! case 'U' : return '\333';
+! case '0' : return '\260';
+! case '1' : return '\271';
+! case '2' : return '\262';
+! case '3' : return '\263';
+! }
+! break;
+! case '`' :
+! switch(d){
+! case 'a' : return '\340';
+! case 'e' : return '\350';
+! case 'i' : return '\354';
+! case 'o' : return '\362';
+! case 'u' : return '\371';
+! case 'A' : return '\300';
+! case 'E' : return '\310';
+! case 'I' : return '\314';
+! case 'O' : return '\322';
+! case 'U' : return '\331';
+! }
+! break;
+! case 'o' :
+! switch(d){
+! case 'a' : return '\345';
+! case 'A' : return '\305';
+! case '/' : return '\370';
+! case 'r' : return '\256';
+! case 'R' : return '\256';
+! case 'c' : return '\251';
+! case 'C' : return '\251';
+! }
+! break;
+! case '-' :
+! switch(d){
+! case 'o' : return '\272';
+! case 'O' : return '\272';
+! case '0' : return '\272';
+! case 'a' : return '\252';
+! case 'A' : return '\252';
+! case 'l' : return '\243';
+! case 'L' : return '\243';
+! }
+! break;
+! case 'O' :
+! switch(d){
+! case '/' : return '\330';
+! case 'r' : return '\256';
+! case 'R' : return '\256';
+! case 'c' : return '\251';
+! case 'C' : return '\251';
+! }
+! case '/' :
+! switch(d){
+! case 'o' : return '\370';
+! case 'O' : return '\330';
+! }
+! break;
+! case 'a' :
+! switch(d){
+! case 'e' : return '\346';
+! case 'E' : return '\346';
+! }
+! break;
+! case 'A' :
+! switch(d){
+! case 'E' : return '\306';
+! case 'e' : return '\306';
+! }
+! break;
+! case ',' :
+! switch(d){
+! case 'c' : return '\347';
+! case 'C' : return '\307';
+! }
+! break;
+! case '\\' :
+! switch(d){
+! case '?' : return '\277';
+! case '!' : return '\241';
+! }
+! break;
+! case 's' :
+! switch(d){
+! case 's' : return '\337';
+! }
+! break;
+! case 'l' :
+! switch(d){
+! case 'l' : return '\243';
+! }
+! break;
+! }
+! return '\0';
+! }
+!
+ /*
+! * go forward to the end of the current paragraph
+ * here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
+ * combination to delimit the begining of a paragraph
+ */
+ gotoeop(f, n)
+ int f, n; /* default Flag & Numeric argument */
+ {
+! int quoted, qlen, indented;
+! char qstr[NLINE], qstr2[NLINE], ind_str[NLINE];
+
+ if (n < 0) /* the other way...*/
+ return(gotobop(f, -n));
+***************
+*** 353,358 ****
+--- 588,645 ----
+ break;
+ }
+
++ /*
++ * We need to figure out if this line is the first line of
++ * a paragraph that has been indented in a special way. If this
++ * is the case, we advance one more line before we use the
++ * algorithm below
++ */
++
++ if(curwp->w_dotp != curbp->b_linep){
++ int i,j;
++
++ if (glo_quote_str || (Pmaster && Pmaster->quote_str)){
++ quote_match(glo_quote_str ? glo_quote_str : Pmaster->quote_str,
++ curwp->w_dotp, qstr, NLINE, 1);
++ quote_match(glo_quote_str ? glo_quote_str : Pmaster->quote_str,
++ lforw(curwp->w_dotp), qstr2, NLINE, 1);
++ }
++ else
++ qstr[0] = qstr2[0] = '\0';
++ indented = indent_match((glo_quote_str || (Pmaster && Pmaster->quote_str))
++ ? (glo_quote_str ? glo_quote_str
++ : Pmaster->quote_str) : "", curwp->w_dotp,
++ ind_str, NLINE, 1);
++ if (strlenis(qstr) + strlenis(ind_str) < strlenis(qstr2)){
++ curwp->w_doto = 0;
++ if(n){ /* this line is a paragraph by itself */
++ curwp->w_dotp = lforw(curwp->w_dotp);
++ continue;
++ }
++ break;
++ }
++ for (i=0,j=0; qstr[i] && qstr2[i] && (qstr[i] == qstr2[i]);i++,j++);
++ for (; isspace(qstr[i]); i++);
++ for (; isspace(qstr2[j]); j++);
++ if (!qstr[i] && !qstr2[j] && indented){
++ if (indent_match((glo_quote_str
++ || (Pmaster && Pmaster->quote_str))
++ ? (glo_quote_str ? glo_quote_str
++ : Pmaster->quote_str) : "",
++ lforw(curwp->w_dotp),
++ ind_str, NLINE, 0)){
++ if (n){ /* look for another paragraph ? */
++ curwp->w_dotp = lforw(curwp->w_dotp);
++ continue;
++ }
++ }
++ else{
++ if (!lisblank(lforw(curwp->w_dotp)))
++ curwp->w_dotp = lforw(curwp->w_dotp);
++ }
++ }
++ }
++
+ /* scan line by line until we come to a line ending with
+ * a <NL><NL> or <NL><TAB> or <NL><SPACE>
+ *
+***************
+*** 361,367 ****
+ */
+ quoted = ((glo_quote_str || (Pmaster && Pmaster->quote_str))
+ ? quote_match(glo_quote_str ? glo_quote_str : Pmaster->quote_str,
+! curwp->w_dotp, qstr, NLINE) : 0);
+ qlen = quoted ? strlen(qstr) : 0;
+
+ while(curwp->w_dotp != curbp->b_linep
+--- 648,654 ----
+ */
+ quoted = ((glo_quote_str || (Pmaster && Pmaster->quote_str))
+ ? quote_match(glo_quote_str ? glo_quote_str : Pmaster->quote_str,
+! curwp->w_dotp, qstr, NLINE, 0) : 0);
+ qlen = quoted ? strlen(qstr) : 0;
+
+ while(curwp->w_dotp != curbp->b_linep
+***************
+*** 370,378 ****
+ ? (quoted == quote_match(glo_quote_str ? glo_quote_str
+ : Pmaster->quote_str,
+ lforw(curwp->w_dotp),
+! qstr2, NLINE)
+ && !strcmp(qstr, qstr2))
+ : 1)
+ && lgetc(lforw(curwp->w_dotp), qlen).c != TAB
+ && lgetc(lforw(curwp->w_dotp), qlen).c != ' ')
+ curwp->w_dotp = lforw(curwp->w_dotp);
+--- 657,671 ----
+ ? (quoted == quote_match(glo_quote_str ? glo_quote_str
+ : Pmaster->quote_str,
+ lforw(curwp->w_dotp),
+! qstr2, NLINE, 0)
+ && !strcmp(qstr, qstr2))
+ : 1)
++ && !indent_match((glo_quote_str
++ || (Pmaster && Pmaster->quote_str))
++ ? (glo_quote_str ? glo_quote_str
++ : Pmaster->quote_str) : "",
++ lforw(curwp->w_dotp),
++ ind_str, NLINE, 0)
+ && lgetc(lforw(curwp->w_dotp), qlen).c != TAB
+ && lgetc(lforw(curwp->w_dotp), qlen).c != ' ')
+ curwp->w_dotp = lforw(curwp->w_dotp);
+***************
+*** 653,659 ****
+--- 946,992 ----
+ return (scrollback (n, TRUE));
+ }
+
++ /* deltext deletes from the specified position until the end of the file
++ * or until the signature (when called from Pine), whichever comes first.
++ */
+
++ int
++ deltext (f,n)
++ int f,n;
++ {
++ LINE *currline = curwp->w_dotp;
++
++ if ((lastflag&CFKILL) == 0)
++ kdelete();
++
++ curwp->w_markp = curwp->w_dotp;
++ curwp->w_marko = curwp->w_doto;
++
++ while (curwp->w_dotp != curbp->b_linep){
++ if ((Pmaster)
++ && (llength(curwp->w_dotp) == 3)
++ && (lgetc(curwp->w_dotp, 0).c == '-')
++ && (lgetc(curwp->w_dotp, 1).c == '-')
++ && (lgetc(curwp->w_dotp, 2).c == ' ')){
++ if (curwp->w_dotp == currline){
++ if (curwp->w_doto)
++ curwp->w_dotp = lforw(curwp->w_dotp);
++ else
++ break;
++ }
++ else{
++ curwp->w_dotp = lback(curwp->w_dotp);
++ curwp->w_doto = llength(curwp->w_dotp);
++ break;
++ }
++ }
++ else
++ curwp->w_dotp = lforw(curwp->w_dotp);
++ }
++ killregion(FALSE,1);
++ lastflag |= CFKILL;
++ return TRUE;
++ }
+
+ scrollupline (f, n)
+ int f, n;
+diff -rc pine4.63/pico/composer.c pine4.63.I.USE/pico/composer.c
+*** pine4.63/pico/composer.c Thu Mar 17 11:08:37 2005
+--- pine4.63.I.USE/pico/composer.c Thu May 19 19:57:30 2005
+***************
+*** 1560,1565 ****
+--- 1560,1567 ----
+ }
+
+ UpdateHeader(0);
++ if(sendnow)
++ return(status !=0);
+ PaintHeader(COMPOSER_TOP_LINE, status != 0);
+ PaintBody(1);
+ return(status != 0);
+***************
+*** 1691,1697 ****
+ }
+
+ if(VALID_KEY(ch)){ /* char input */
+! /*
+ * if we are allowing editing, insert the new char
+ * end up leaving tbufp pointing to newly
+ * inserted character in string, and offset to the
+--- 1693,1699 ----
+ }
+
+ if(VALID_KEY(ch)){ /* char input */
+! insert_char:/*
+ * if we are allowing editing, insert the new char
+ * end up leaving tbufp pointing to newly
+ * inserted character in string, and offset to the
+***************
+*** 1775,1780 ****
+--- 1777,1789 ----
+ }
+ else { /* interpret ch as a command */
+ switch (ch = normalize_cmd(ch, ckm, 2)) {
++ case (CTRL|'\\') :
++ if (ch = GetAccent())
++ goto insert_char;
++ else
++ clearcursor();
++ break;
++
+ case (CTRL|'@') : /* word skip */
+ while(strng[ods.p_off]
+ && isalnum((unsigned char)strng[ods.p_off]))
+***************
+*** 2955,2960 ****
+--- 2964,2972 ----
+ {
+ register char *bufp;
+
++ if (sendnow)
++ return;
++
+ if(ComposerTopLine - 1 >= BOTTOM()) /* silently forget it */
+ return;
+
+***************
+*** 3004,3009 ****
+--- 3016,3024 ----
+ register char *bufp;
+ register int i;
+
++ if (sendnow)
++ return(TRUE);
++
+ bufp = headents[entry].prompt; /* fresh prompt paint */
+ if((i = entry_line(entry, FALSE)) == -1)
+ return(-1); /* silently forget it */
+***************
+*** 3884,3889 ****
+--- 3899,3907 ----
+ void
+ ShowPrompt()
+ {
++ if (sendnow)
++ return;
++
+ if(headents[ods.cur_e].key_label){
+ menu_header[TO_KEY].name = "^T";
+ menu_header[TO_KEY].label = headents[ods.cur_e].key_label;
+diff -rc pine4.63/pico/display.c pine4.63.I.USE/pico/display.c
+*** pine4.63/pico/display.c Fri May 7 14:38:24 2004
+--- pine4.63.I.USE/pico/display.c Thu May 19 19:57:32 2005
+***************
+*** 362,367 ****
+--- 362,370 ----
+ register int scroll = 0;
+ CELL c;
+
++ if (sendnow)
++ return;
++
+ #if TYPEAH
+ if (typahead())
+ return;
+***************
+*** 1400,1405 ****
+--- 1403,1409 ----
+
+ maxl = (nbuf-1 < term.t_ncol - plen - 1) ? nbuf-1 : term.t_ncol - plen - 1;
+
++ if (!sendnow)
+ pputs(buf, 1);
+ b = &buf[(flg & QBOBUF) ? 0 : strlen(buf)];
+
+***************
+*** 1460,1465 ****
+--- 1464,1482 ----
+ b++;
+ continue;
+
++ case (CTRL|'N'): /* Insert pattern */
++ if (pat[0] != '\0'){
++ strcat(buf,pat);
++ pputs(pat,1);
++ b += strlen(pat);
++ changed = TRUE;
++ }
++ else
++ (*term.t_beep)();
++ continue;
++
++
++
+ case (CTRL|'G') : /* CTRL-G help */
+ if(term.t_mrow == 0 && km_popped == 0){
+ movecursor(term.t_nrow-2, 0);
+***************
+*** 1515,1520 ****
+--- 1532,1542 ----
+ b--;
+ continue;
+
++ case (CTRL|'\\'):
++ if (c = GetAccent())
++ goto text;
++ continue;
++
+ case KEY_RIGHT:
+ if(*b != '\0')
+ b++;
+***************
+*** 1566,1571 ****
+--- 1588,1594 ----
+ #endif
+
+ default :
++ text:
+ if(strlen(buf) >= maxl){ /* contain the text */
+ (*term.t_beep)();
+ continue;
+***************
+*** 1604,1625 ****
+ b[i+1] = b[i];
+ while(i-- > 0);
+
+! pputc(*b++ = c, 0);
+ }
+ }
+
+! pputs(b, 1); /* show default */
+ i = term.t_ncol-1;
+ while(pscreen[ttrow]->v_text[i].c == ' '
+ && pscreen[ttrow]->v_text[i].a == 0)
+ i--;
+
+! while(ttcol <= i)
+ pputc(' ', 0);
+ }
+
+ ret:
+! if(km_popped){
+ term.t_mrow = 0;
+ movecursor(term.t_nrow, 0);
+ peeol();
+--- 1627,1652 ----
+ b[i+1] = b[i];
+ while(i-- > 0);
+
+! if(sendnow)
+! *b++ = c;
+! else
+! pputc(*b++ = c, 0);
+ }
+ }
+
+! if(!sendnow)
+! pputs(b, 1); /* show default */
+ i = term.t_ncol-1;
+ while(pscreen[ttrow]->v_text[i].c == ' '
+ && pscreen[ttrow]->v_text[i].a == 0)
+ i--;
+
+! while(!sendnow && ttcol <= i)
+ pputc(' ', 0);
+ }
+
+ ret:
+! if(!sendnow && km_popped){
+ term.t_mrow = 0;
+ movecursor(term.t_nrow, 0);
+ peeol();
+***************
+*** 1745,1750 ****
+--- 1772,1779 ----
+ register int c;
+ register char *ap;
+
++ if(sendnow)
++ return 0;
+ /*
+ * the idea is to only highlight if there is something to show
+ */
+***************
+*** 2472,2477 ****
+--- 2501,2509 ----
+ char nbuf[NLINE];
+ #endif
+
++ if(sendnow)
++ return;
++
+ #ifdef _WINDOWS
+ pico_config_menu_items (keymenu);
+ #endif
+diff -rc pine4.63/pico/ebind.h pine4.63.I.USE/pico/ebind.h
+*** pine4.63/pico/ebind.h Fri May 7 14:38:24 2004
+--- pine4.63.I.USE/pico/ebind.h Thu May 19 19:57:30 2005
+***************
+*** 105,111 ****
+ {CTRL|'^', setmark},
+ {CTRL|'_', alt_editor},
+ {0x7F, backdel},
+! {0, NULL}
+ };
+
+
+--- 105,113 ----
+ {CTRL|'^', setmark},
+ {CTRL|'_', alt_editor},
+ {0x7F, backdel},
+! {CTRL|'\\', pineaccent},
+! {0,
+! NULL}
+ };
+
+
+diff -rc pine4.63/pico/edef.h pine4.63.I.USE/pico/edef.h
+*** pine4.63/pico/edef.h Wed Oct 13 18:27:46 2004
+--- pine4.63.I.USE/pico/edef.h Thu May 19 19:57:27 2005
+***************
+*** 43,48 ****
+--- 43,49 ----
+
+ /* initialized global definitions */
+
++ int sendnow = 0; /* should we send now */
+ int fillcol = 72; /* Current fill column */
+ int userfillcol = -1; /* Fillcol set from cmd line */
+ char pat[NPAT]; /* Search pattern */
+***************
+*** 96,101 ****
+--- 97,103 ----
+
+ /* initialized global external declarations */
+
++ extern int sendnow; /* should we send now */
+ extern int fillcol; /* Fill column */
+ extern int userfillcol; /* Fillcol set from cmd line */
+ extern char pat[]; /* Search pattern */
+diff -rc pine4.63/pico/efunc.h pine4.63.I.USE/pico/efunc.h
+*** pine4.63/pico/efunc.h Tue Jun 15 15:22:58 2004
+--- pine4.63.I.USE/pico/efunc.h Thu May 19 19:57:33 2005
+***************
+*** 65,70 ****
+--- 65,71 ----
+ extern int gotoeop PROTO((int, int));
+ extern int forwpage PROTO((int, int));
+ extern int backpage PROTO((int, int));
++ extern int deltext PROTO((int, int));
+ extern int scrollupline PROTO((int, int));
+ extern int scrolldownline PROTO((int, int));
+ extern int scrollto PROTO((int, int));
+***************
+*** 73,78 ****
+--- 74,82 ----
+ extern int setimark PROTO((int, int));
+ extern int swapimark PROTO((int, int));
+ extern int mousepress PROTO((int, int));
++ extern unsigned char accent PROTO((int, int));
++ extern int pineaccent PROTO((int, int));
++ extern int GetAccent PROTO((void));
+
+ /* bind.c */
+ extern int whelp PROTO((int, int));
+***************
+*** 337,342 ****
+ extern int fillpara PROTO((int, int));
+ extern int fillbuf PROTO((int, int));
+ extern int inword PROTO((void));
+! extern int quote_match PROTO((char *, LINE *, char *, int));
+
+ #endif /* EFUNC_H */
+--- 341,350 ----
+ extern int fillpara PROTO((int, int));
+ extern int fillbuf PROTO((int, int));
+ extern int inword PROTO((void));
+! extern int quote_match PROTO((char *, LINE *, char *, int, int));
+! extern void flatten_qstring PROTO((QSTRING_S *, char *));
+! extern void free_qs PROTO((QSTRING_S **));
+! extern QSTRING_S *do_quote_match PROTO((char *, char *, char *, char *, int));
+! extern QSTRING_S *copy_qs PROTO((QSTRING_S *));
+
+ #endif /* EFUNC_H */
+diff -rc pine4.63/pico/line.c pine4.63.I.USE/pico/line.c
+*** pine4.63/pico/line.c Fri May 7 14:41:16 2004
+--- pine4.63.I.USE/pico/line.c Thu May 19 19:57:29 2005
+***************
+*** 635,641 ****
+
+ n = ((glo_quote_str || (Pmaster && Pmaster->quote_str))
+ && quote_match(glo_quote_str ? glo_quote_str : Pmaster->quote_str,
+! line, qstr, NLINE))
+ ? strlen(qstr) : 0;
+
+ for(; n < llength(line); n++)
+--- 635,641 ----
+
+ n = ((glo_quote_str || (Pmaster && Pmaster->quote_str))
+ && quote_match(glo_quote_str ? glo_quote_str : Pmaster->quote_str,
+! line, qstr, NLINE, 1))
+ ? strlen(qstr) : 0;
+
+ for(; n < llength(line); n++)
+diff -rc pine4.63/pico/main.c pine4.63.I.USE/pico/main.c
+*** pine4.63/pico/main.c Fri May 7 14:41:16 2004
+--- pine4.63.I.USE/pico/main.c Thu May 19 19:57:31 2005
+***************
+*** 149,154 ****
+--- 149,155 ----
+ int setlocale_ctype = 0;
+ char bname[NBUFN]; /* buffer name of file to read */
+ char *file_to_edit = NULL;
++ int line_information_on = FALSE;
+
+ timeo = 600;
+ Pmaster = NULL; /* turn OFF composer functionality */
+***************
+*** 306,311 ****
+--- 307,318 ----
+ emlwrite("You may possibly have new mail.", NULL);
+ }
+
++ if (c == (CTRL|'\\')){
++ c = GetAccent();
++ if (!c)
++ c = NODATA;
++ }
++
+ if(km_popped)
+ switch(c){
+ case NODATA:
+***************
+*** 327,340 ****
+ mlerase();
+ }
+
+! f = FALSE;
+ n = 1;
+
+ #ifdef MOUSE
+ clear_mfunc(mouse_in_content);
+ #endif
+ /* Do it. */
+ execute(normalize_cmd(c, fkm, 1), f, n);
+ }
+ }
+
+--- 334,363 ----
+ mlerase();
+ }
+
+! f = (c == (CTRL|'J'));
+ n = 1;
++ if (!line_information_on)
++ line_information_on = (c == (CTRL|'C'));
++ else
++ line_information_on = ((c == KEY_DOWN) || (c == KEY_UP) ||
++ (c == KEY_RIGHT) || (c == KEY_LEFT) ||
++ (c == (CTRL|'V')) || (c == (CTRL|'Y')) ||
++ (c == (CTRL|'K')) || (c == (CTRL|'D')) ||
++ (c == (CTRL|'F')) || (c == (CTRL|'B')) ||
++ (c == (CTRL|'N')) || (c == (CTRL|'P')) ||
++ (c == (CTRL|'A')) || (c == (CTRL|'E')) ||
++ (c == (CTRL|'U')) || (c == (CTRL|'^')))
++ && (c != (CTRL|'C'));
+
+ #ifdef MOUSE
+ clear_mfunc(mouse_in_content);
+ #endif
+ /* Do it. */
+ execute(normalize_cmd(c, fkm, 1), f, n);
++ if (line_information_on){
++ c = (CTRL|'C');
++ execute(normalize_cmd(c, fkm, 1), f, n);
++ }
+ }
+ }
+
+diff -rc pine4.63/pico/osdep/term.cap pine4.63.I.USE/pico/osdep/term.cap
+*** pine4.63/pico/osdep/term.cap Wed Jul 21 15:04:36 2004
+--- pine4.63.I.USE/pico/osdep/term.cap Thu May 19 19:57:27 2005
+***************
+*** 438,443 ****
+--- 438,449 ----
+ {
+ int row, col;
+
++ if (sendnow){
++ term.t_nrow = 23;
++ term.t_ncol = 80;
++ return 0;
++ }
++
+ /*
+ * determine the terminal's communication speed and decide
+ * if we need to do optimization ...
+diff -rc pine4.63/pico/osdep/unix pine4.63.I.USE/pico/osdep/unix
+*** pine4.63/pico/osdep/unix Tue Apr 19 14:28:56 2005
+--- pine4.63.I.USE/pico/osdep/unix Thu May 19 19:57:27 2005
+***************
+*** 363,368 ****
+--- 363,381 ----
+ {
+ int ch, status, cc;
+
++ if(sendnow){
++ ch = Pmaster && Pmaster->auto_cmds && *Pmaster->auto_cmds
++ ? *Pmaster->auto_cmds++ : NODATA;
++
++ if(ch & 0x80 && Pmaster && Pmaster->hibit_entered)
++ *Pmaster->hibit_entered = 1;
++
++ if (ch >= 0x00 && ch <= 0x1F)
++ ch = CTRL | (ch+'@');
++
++ return(ch);
++ }
++
+ if(!ReadyForKey(FUDGE-5))
+ return(NODATA);
+
+diff -rc pine4.63/pico/pico.c pine4.63.I.USE/pico/pico.c
+*** pine4.63/pico/pico.c Thu Mar 31 09:08:57 2005
+--- pine4.63.I.USE/pico/pico.c Thu May 19 19:57:27 2005
+***************
+*** 138,143 ****
+--- 138,152 ----
+ pico_all_done = 0;
+ km_popped = 0;
+
++ if (pm->auto_cmds){
++ int i;
++ #define CTRL_X 24
++ for (i = 0; pm->auto_cmds[i]; i++);
++ if ((i > 1) && (pm->auto_cmds[i - 2] == CTRL_X) &&
++ ((pm->auto_cmds[i - 1] == 'y') || (pm->auto_cmds[i-1] == 'Y')))
++ sendnow++;
++ }
++
+ if(!vtinit()) /* Init Displays. */
+ return(COMP_CANCEL);
+
+***************
+*** 686,691 ****
+--- 695,711 ----
+ return(FALSE);
+ }
+
++ /* When we send a message using the command line we are going to
++ ignore if the user wants to spell check, we assume she already
++ did */
++ if (sendnow){
++ result = (*Pmaster->exittest)(Pmaster->headents,
++ redraw_pico_for_callback, Pmaster->allow_flowed_text);
++ if (!result)
++ pico_all_done = COMP_EXIT;
++ return(result ? FALSE : TRUE);
++ }
++
+ #ifdef SPELLER
+ if(Pmaster->always_spell_check)
+ if(spell(0, 0) == -1)
+diff -rc pine4.63/pico/pico.h pine4.63.I.USE/pico/pico.h
+*** pine4.63/pico/pico.h Wed Mar 30 14:44:42 2005
+--- pine4.63.I.USE/pico/pico.h Thu May 19 19:57:29 2005
+***************
+*** 219,224 ****
+--- 219,225 ----
+ void (*resize)(); /* callback handling screen resize */
+ void (*winch_cleanup)(); /* callback handling screen resize */
+ int arm_winch_cleanup; /* do the winch_cleanup if resized */
++ int *auto_cmds; /* Initial keystroke commands */
+ HELP_T search_help;
+ HELP_T ins_help;
+ HELP_T ins_m_help;
+***************
+*** 342,347 ****
+--- 343,364 ----
+ struct KBSTREE *left;
+ } KBESC_T;
+
++ /*
++ * struct that will help us determine what the quote string of a line
++ * is. The "next" field indicates the presence of a possible continuation.
++ * The idea is that if a continuation fails, we free it and check for the
++ * remaining structure left
++ */
++
++ typedef enum {qsNormal, qsString, qsWord, qsChar} QStrType;
++
++ typedef struct QSTRING {
++ char *value; /* possible quote string */
++ QStrType qstype; /* type of quote string */
++ struct QSTRING *next; /* possible continuation */
++ } QSTRING_S;
++
++
+ /*
+ * Protos for functions used to manage keyboard escape sequences
+ * NOTE: these may ot actually get defined under some OS's (ie, DOS, WIN)
+diff -rc pine4.63/pico/random.c pine4.63.I.USE/pico/random.c
+*** pine4.63/pico/random.c Fri May 7 14:43:48 2004
+--- pine4.63.I.USE/pico/random.c Thu May 19 19:57:29 2005
+***************
+*** 364,370 ****
+ else{
+ backchar(FALSE, 1);
+ dotp = curwp->w_dotp;
+! gotobop(FALSE, 1); /* then go to the top of the para */
+ }
+
+ curwp->w_doto = 0;
+--- 364,371 ----
+ else{
+ backchar(FALSE, 1);
+ dotp = curwp->w_dotp;
+! swapimark(FALSE, 1); /* go back to the spot we marked before justify */
+! /* We assume that no imarks have been set between fillpara and now */
+ }
+
+ curwp->w_doto = 0;
+diff -rc pine4.63/pico/search.c pine4.63.I.USE/pico/search.c
+*** pine4.63/pico/search.c Thu Jul 1 14:36:36 2004
+--- pine4.63.I.USE/pico/search.c Thu May 19 19:57:34 2005
+***************
+*** 78,83 ****
+--- 78,87 ----
+ "\tbrackets. This string is the default search prompt.",
+ "~ Hitting only ~R~e~t~u~r~n or at the prompt will cause the",
+ "\tsearch to be made with the default value.",
++ " ",
++ "~ Hitting ~^~N will reinsert the last string you searched for",
++ "\tso that you can edit it (in case you made a mistake entering the",
++ "\tsearch pattern the first time).",
+ " ",
+ "\tThe text search is not case sensitive, and will examine the",
+ "\tentire message.",
+***************
+*** 235,244 ****
+--- 239,258 ----
+ mlerase();
+ FWS_RETURN(TRUE);
+
++ case (CTRL|'P'):
++ deletepara(0, 1);
++ mlerase();
++ FWS_RETURN(TRUE);
++
+ case (CTRL|'R'): /* toggle replacement option */
+ repl_mode = !repl_mode;
+ break;
+
++ case (CTRL|'X'):
++ deltext(f,n);
++ mlerase();
++ FWS_RETURN(TRUE);
++
+ default:
+ if(status == ABORT)
+ emlwrite("Search Cancelled", NULL);
+***************
+*** 275,281 ****
+ }
+
+ if(status + curwp->w_doto >= llength(curwp->w_dotp) ||
+! !eq(defpat[status],lgetc(curwp->w_dotp, curwp->w_doto + status).c))
+ break; /* do nothing! */
+ status++;
+ }
+--- 289,295 ----
+ }
+
+ if(status + curwp->w_doto >= llength(curwp->w_dotp) ||
+! !eq((unsigned char)defpat[status],lgetc(curwp->w_dotp, curwp->w_doto + status).c))
+ break; /* do nothing! */
+ status++;
+ }
+***************
+*** 499,505 ****
+ register int s;
+ int i = 0;
+ char tpat[NPAT+20];
+! EXTRAKEYS menu_pat[8];
+
+ menu_pat[i = 0].name = "^Y";
+ menu_pat[i].label = "FirstLine";
+--- 513,519 ----
+ register int s;
+ int i = 0;
+ char tpat[NPAT+20];
+! EXTRAKEYS menu_pat[10];
+
+ menu_pat[i = 0].name = "^Y";
+ menu_pat[i].label = "FirstLine";
+***************
+*** 517,522 ****
+--- 531,541 ----
+ KS_OSDATASET(&menu_pat[i], KS_NONE);
+
+ if(!repl_mode){
++ menu_pat[++i].name = "^X";
++ menu_pat[i].label = "EndText";
++ menu_pat[i].key = (CTRL|'X');
++ KS_OSDATASET(&menu_pat[i], KS_NONE);
++
+ menu_pat[++i].name = "^T";
+ menu_pat[i].label = "LineNumber";
+ menu_pat[i].key = (CTRL|'T');
+***************
+*** 532,537 ****
+--- 551,561 ----
+ menu_pat[i].key = (CTRL|'O');
+ KS_OSDATASET(&menu_pat[i], KS_NONE);
+
++ menu_pat[++i].name = "^P";
++ menu_pat[i].label = "Delete Para";
++ menu_pat[i].key = (CTRL|'P');
++ KS_OSDATASET(&menu_pat[i], KS_NONE);
++
+ menu_pat[++i].name = "^U";
+ menu_pat[i].label = "FullJustify";
+ menu_pat[i].key = (CTRL|'U');
+***************
+*** 630,636 ****
+ register int s;
+ int i;
+ char tpat[NPAT+20];
+! EXTRAKEYS menu_pat[7];
+
+ menu_pat[i = 0].name = "^Y";
+ menu_pat[i].label = "FirstLine";
+--- 654,660 ----
+ register int s;
+ int i;
+ char tpat[NPAT+20];
+! EXTRAKEYS menu_pat[9];
+
+ menu_pat[i = 0].name = "^Y";
+ menu_pat[i].label = "FirstLine";
+***************
+*** 643,648 ****
+--- 667,677 ----
+ KS_OSDATASET(&menu_pat[i], KS_NONE);
+
+ if(text_mode){
++ menu_pat[++i].name = "^X";
++ menu_pat[i].label = "EndText";
++ menu_pat[i].key = (CTRL|'X');
++ KS_OSDATASET(&menu_pat[i], KS_NONE);
++
+ menu_pat[++i].name = "^T";
+ menu_pat[i].label = "LineNumber";
+ menu_pat[i].key = (CTRL|'T');
+***************
+*** 658,663 ****
+--- 687,697 ----
+ menu_pat[i].key = (CTRL|'O');
+ KS_OSDATASET(&menu_pat[i], KS_NONE);
+
++ menu_pat[++i].name = "^P";
++ menu_pat[i].label = "Delete Para";
++ menu_pat[i].key = (CTRL|'P');
++ KS_OSDATASET(&menu_pat[i], KS_NONE);
++
+ menu_pat[++i].name = "^U";
+ menu_pat[i].label = "FullJustify";
+ menu_pat[i].key = (CTRL|'U');
+***************
+*** 760,766 ****
+ c = lgetc(curline, curoff++).c; /* get the char */
+
+ /* test it against first char in pattern */
+! if (eq(c, patrn[0]) != FALSE) { /* if we find it..*/
+ /* setup match pointers */
+ matchline = curline;
+ matchoff = curoff;
+--- 794,800 ----
+ c = lgetc(curline, curoff++).c; /* get the char */
+
+ /* test it against first char in pattern */
+! if (eq(c, (unsigned char)patrn[0]) != FALSE) { /* if we find it..*/
+ /* setup match pointers */
+ matchline = curline;
+ matchoff = curoff;
+***************
+*** 781,787 ****
+ return(FALSE);
+
+ /* and test it against the pattern */
+! if (eq(*patptr, c) == FALSE)
+ goto fail;
+ }
+
+--- 815,821 ----
+ return(FALSE);
+
+ /* and test it against the pattern */
+! if (eq((unsigned char) *patptr, c) == FALSE)
+ goto fail;
+ }
+
+***************
+*** 820,829 ****
+ int maxlength; /* maximum chars in destination */
+
+ {
+! char c; /* current char to translate */
+
+ /* scan through the string */
+! while ((c = *srcstr++) != 0) {
+ if (c == '\n') { /* its an EOL */
+ *deststr++ = '<';
+ *deststr++ = 'N';
+--- 854,863 ----
+ int maxlength; /* maximum chars in destination */
+
+ {
+! unsigned char c; /* current char to translate */
+
+ /* scan through the string */
+! while ((c = (unsigned char) *srcstr++) != 0) {
+ if (c == '\n') { /* its an EOL */
+ *deststr++ = '<';
+ *deststr++ = 'N';
+diff -rc pine4.63/pico/word.c pine4.63.I.USE/pico/word.c
+*** pine4.63/pico/word.c Fri May 7 14:45:24 2004
+--- pine4.63.I.USE/pico/word.c Thu May 19 19:57:29 2005
+***************
+*** 360,403 ****
+ && isalnum((unsigned char)lgetc(curwp->w_dotp, curwp->w_doto).c));
+ }
+
+
+ /*
+! * Return number of quotes if whatever starts the line matches the quote string
+ */
+! quote_match(q, l, buf, buflen)
+ char *q;
+ LINE *l;
+ char *buf;
+ int buflen;
+ {
+! register int i, n, j, qb;
+
+! *buf = '\0';
+! if(*q == '\0')
+! return(1);
+!
+! qb = (strlen(q) > 1 && q[strlen(q)-1] == ' ') ? 1 : 0;
+! for(n = 0, j = 0; ;){
+! for(i = 0; j <= llength(l) && qb ? q[i+1] : q[i]; i++, j++)
+! if(q[i] != lgetc(l, j).c)
+! return(n);
+!
+! n++;
+! if((!qb && q[i] == '\0') || (qb && q[i+1] == '\0')){
+! if(strlen(buf) + strlen(q) + 1 < buflen){
+! strcat(buf,q);
+! if(qb && (j > llength(l) || lgetc(l, j).c != ' '))
+! buf[strlen(buf)-1] = '\0';
+! }
+ }
+! if(j > llength(l))
+! return(n);
+! else if(qb && lgetc(l, j).c == ' ')
+! j++;
+ }
+! return(n); /* never reached */
+ }
+
+
+ /* Justify the entire buffer instead of just a paragraph */
+ fillbuf(f, n)
+--- 360,1419 ----
+ && isalnum((unsigned char)lgetc(curwp->w_dotp, curwp->w_doto).c));
+ }
+
++ /* Support of indentation of paragraphs */
++ #define NBSP ((unsigned char) '\240')
++ #define ISspace(c) ((c) == ' ' || (c) == TAB || ((unsigned char)(c)) == NBSP)
++ #define is_indent_char(c) (((c) == '.' || (c) == '}' || (c) == RPAREN || \
++ (c) == '*' || (c) == '+' || is_a_digit(c) || \
++ ISspace(c) || (c) == '-' || \
++ (c) == ']') ? 1 : 0)
++ #define allowed_after_digit(c,word,k) ((((c) == '.' && \
++ allowed_after_period(next((word),(k)))) ||\
++ (c) == RPAREN || (c) == '}' || (c) == ']' ||\
++ ISspace(c) || is_a_digit(c) || \
++ ((c) == '-' ) && \
++ allowed_after_dash(next((word),(k)))) \
++ ? 1 : 0)
++ #define allowed_after_period(c) (((c) == RPAREN || (c) == '}' || (c) == ']' ||\
++ ISspace(c) || (c) == '-' || \
++ is_a_digit(c)) ? 1 : 0)
++ #define allowed_after_parenth(c) (ISspace(c) ? 1 : 0)
++ #define allowed_after_space(c) (ISspace(c) ? 1 : 0)
++ #define allowed_after_braces(c) (ISspace(c) ? 1 : 0)
++ #define allowed_after_star(c) ((ISspace(c) || (c) == RPAREN ||\
++ (c) == ']' || (c) == '}') ? 1 : 0)
++ #define allowed_after_dash(c) ((ISspace(c) || is_a_digit(c)) ? 1 : 0)
++ #define EOLchar(c) (((c) == '.' || (c) == ':' || (c) == '?' ||\
++ (c) == '!') ? 1 : 0)
++
++ int is_indent PROTO((char *, int));
++ int indent_match PROTO(( char *, LINE *, char *, int, int));
++
++ /* Extended justification support */
++
++ #define is_cquote(c) ((c) == '>' || (c) == '|' || (c) == ']' || (c) == ':')
++ #define is_cword(c) ((((c) >= 'a') && ((c) <= 'z')) || \
++ (((c) >= 'A') && ((c) <= 'Z')) || \
++ (((c) >= '0') && ((c) <= '9')) || \
++ ((c) == ' ') || ((c) == '?') || \
++ ((c) == '@') || ((c) == '.') || \
++ ((c) == '!') || ((c) == '\'') || \
++ ((c) == ',') || ((c) == '\"') ? 1 : 0)
++ #define isaquote(c) ((c) == '\"' || (c) == '\'')
++ #define is8bit(c) ((((int) (c)) & 0x80) ? 1 : 0)
++ #define forbidden(c) (((c) == '\"') || ((c) == '\'') || ((c) == '$') ||\
++ ((c) == ',') || ((c) == '.') || ((c) == '-') ||\
++ ((c) == LPAREN) || ((c) == '/')|| ((c) == '`') ||\
++ ((c) == '{') || ((c) == '\\') || \
++ (((c) >= '0') && ((c) <= '9')))
++ #define is_cletter(c) ((((c) >= 'a') && ((c) <= 'z'))) ||\
++ ((((c) >= 'A') && ((c) <= 'Z'))||\
++ is8bit(c))
++ #define is_cnumber(c) ((c) >= '0' && (c) <= '9')
++ #define allwd_after_word(c) (((c) == ' ') || ((c) == '>') || is_cletter(c))
++ #define allwd_after_qsword(c) (((c) != '\\') && ((c) != RPAREN))
++ #define before(word,i) (((i) > 0) ? (word)[(i) - 1] : 0)
++ #define next(w,i) ((((w)[(i)]) != 0) ? ((w)[(i) + 1]) : 0)
++ #define now(w,i) ((w)[(i)])
++ #define is_qsword(c) (((c) == ':') || ((c) == RPAREN) ? 1 : 0)
++ #define is_colon(c) (((c) == ':') ? 1 : 0)
++ #define is_rarrow(c) (((c) == '>') ? 1 : 0)
++ #define is_tilde(c) (((c) == '~') ? 1 : 0)
++ #define is_dash(c) (((c) == '-') ? 1 : 0)
++ #define is_pound(c) (((c) == '#') ? 1 : 0)
++ #define is_space(c) (((c) == ' ') ? 1 : 0)
++ #define is_a_digit(c) ((((c) >= '0') && ((c) <= '9')) ? 1 : 0)
++ #define is_allowed(c) (is_cquote(c) || is_cword(c) || is_dash(c) || \
++ is_pound(c))
++
++ /* Internal justification functions */
++
++ QSTRING_S *is_quote PROTO((char *, char *, int));
++ QSTRING_S *copy_qs PROTO((QSTRING_S *));
++ QSTRING_S *qs_normal_part PROTO((QSTRING_S *));
++ QSTRING_S *qs_remove_trailing_spaces PROTO((QSTRING_S *));
++ QSTRING_S *trim_qs_from_cl PROTO((QSTRING_S *, QSTRING_S *, QSTRING_S *));
++ QSTRING_S *fix_qstring PROTO((QSTRING_S *, QSTRING_S *, QSTRING_S *));
++ QSTRING_S *qs_add PROTO((char *, char *, QStrType, int, int, int, int));
++ QSTRING_S *remove_qsword PROTO((QSTRING_S *));
++ int qstring_is_normal PROTO((QSTRING_S *));
++ int exists_good_part PROTO((QSTRING_S *));
++ int value_is_space PROTO((char *));
++ int strcmp_qs PROTO((char *, char *));
++ int count_levels_qstring PROTO((QSTRING_S *));
++ int same_qstring PROTO((QSTRING_S *, QSTRING_S *));
++ int advance_quote_string PROTO((char *, char *, int));
++ int strlenis PROTO((char *));
++ void flatten_qstring PROTO((QSTRING_S *, char *));
++ void linencpy PROTO((char *, LINE *, int));
++
++ /*
++ * This function creates a qstring pointer with the information that
++ * is_quote handles to it.
++ * Parameters:
++ * qs - User supplied quote string
++ * word - The line of text that the user is trying to read/justify
++ * beginw - Where we need to start copying from
++ * endw - Where we end copying
++ * offset - Any offset in endw that we need to account for
++ * typeqs - type of the string to be created
++ * neednext - boolean, indicating if we need to compute the next field
++ * of leave it NULL
++ *
++ * It is a mistake to call this function if beginw >= endw + offset.
++ * Please note the equality sign in the above inequality (this is because
++ * we always assume that qstring->value != "").
++ */
++
++ QSTRING_S *
++ qs_add(qs, word, typeqs, beginw, endw, offset, neednext)
++ char *qs;
++ char word[NSTRING];
++ QStrType typeqs;
++ int beginw;
++ int endw;
++ int offset;
++ int neednext;
++ {
++ QSTRING_S *qstring, *nextqs = (QSTRING_S *) NULL;
++ int i;
++
++ qstring = (QSTRING_S *) malloc (sizeof(QSTRING_S));
++ memset (qstring, 0, sizeof(QSTRING_S));
++ qstring->qstype = qsNormal;
++
++ if (beginw == 0){
++ beginw = endw + offset;
++ qstring->qstype = typeqs;
++ }
++
++ if (neednext)
++ nextqs = is_quote(qs, word+beginw, 1);
++
++ qstring->value = (char *) malloc((beginw+1)*sizeof(char));
++ strncpy(qstring->value, word, beginw);
++ qstring->value[beginw] = '\0';
++
++ qstring->next = nextqs;
++
++ return qstring;
++ }
++
++
++ int
++ qstring_is_normal(cl)
++ QSTRING_S *cl;
++ {
++ for (;cl && (cl->qstype == qsNormal); cl = cl->next);
++
++ return cl ? 0 : 1;
++ }
++
++ void
++ free_qs(cl)
++ QSTRING_S **cl;
++ {
++ if (!(*cl))
++ return;
++
++ if ((*cl)->next)
++ free_qs(&((*cl)->next));
++
++ (*cl)->next = (QSTRING_S *) NULL;
++
++ if ((*cl)->value)
++ free((void *)(*cl)->value);
++
++ (*cl)->value = (char *) NULL;
++
++ free((void *)(*cl));
++ *cl = (QSTRING_S *) NULL;
++ }
++
++ QSTRING_S *
++ copy_qs(cl)
++ QSTRING_S *cl;
++ {
++ QSTRING_S *qs;
++
++ if (!cl)
++ return (QSTRING_S *)NULL;
++
++ qs = (QSTRING_S *) malloc (sizeof(QSTRING_S));
++ memset (qs, 0, sizeof(QSTRING_S));
++
++ qs->value = (char *) malloc ((strlen(cl->value)+1)*sizeof(char));
++ strcpy(qs->value, cl->value);
++ qs->qstype = cl->qstype;
++ qs->next = copy_qs(cl->next);
++ return qs;
++ }
++
++ /*
++ * Given a quote string, this function returns the part that is the leading
++ * normal part of it. (the normal part is the part that is tagged qsNormal,
++ * that is to say, the one that is not controversial at all (like qsString
++ * for example).
++ */
++ QSTRING_S *
++ qs_normal_part(cl)
++ QSTRING_S *cl;
++ {
++
++ if (!cl) /* nothing in, nothing out */
++ return cl;
++
++ if (cl->qstype != qsNormal)
++ free_qs(&cl);
++
++ if (cl)
++ cl->next = qs_normal_part(cl->next);
++
++ return cl;
++ }
++
++ int
++ value_is_space(value)
++ char *value;
++ {
++ for (; value && *value && ISspace((unsigned char) *value); value++);
++
++ return value && *value ? 0 : 1;
++ }
++
++ /*
++ * this function removes trailing spaces from a quote string, but leaves the
++ * last one if there are trailing spaces
++ */
++ QSTRING_S *
++ qs_remove_trailing_spaces(cl)
++ QSTRING_S *cl;
++ {
++ QSTRING_S *rl = cl;
++
++ if (!cl) /* nothing in, nothing out */
++ return cl;
++
++ if (cl->next)
++ cl->next = qs_remove_trailing_spaces(cl->next);
++ else{
++ if (value_is_space(cl->value))
++ free_qs(&cl);
++ else{
++ int i, l;
++ i = l = strlen(cl->value) - 1;
++ while (cl->value && cl->value[i]
++ && ISspace((unsigned char) cl->value[i]))
++ i--;
++ i += (i < l) ? 2 : 1;
++ cl->value[i] = '\0';
++ }
++ }
++
++ return cl;
++ }
++
++ /*
++ * This function returns if two strings are the same quote string.
++ * The call is not symmetric. cl must preceed the line nl. This function
++ * should be called for comparing the last part of cl and nl.
++ */
++ int
++ strcmp_qs(valuecl, valuenl)
++ char *valuecl;
++ char *valuenl;
++ {
++ int j;
++
++ for (j = 0; valuecl[j] && (valuecl[j] == valuenl[j]); j++);
++ return !strcmp(valuecl, valuenl)
++ || (valuenl[j] && value_is_space(valuenl+j)
++ && value_is_space(valuecl+j)
++ && strlenis(valuecl+j) >= strlenis(valuenl+j))
++ || (!valuenl[j] && value_is_space(valuecl+j));
++ }
++
++ int
++ count_levels_qstring(cl)
++ QSTRING_S *cl;
++ {
++ int count;
++ for (count = 0; cl ; count++, cl = cl->next);
++
++ return count;
++ }
++
++ /*
++ * This function returns the number of agreements between
++ * cl and nl. The call is not symmetric. cl must be the line
++ * preceding nl.
++ */
++ int
++ same_qstring(cl,nl)
++ QSTRING_S *cl;
++ QSTRING_S *nl;
++ {
++ int same = 0, done = 0;
++
++ for (;cl && nl && !done; cl = cl->next, nl = nl->next)
++ if ((cl->qstype == nl->qstype) && (!strcmp(cl->value, nl->value)
++ || ((!cl->next) && strcmp_qs(cl->value, nl->value))))
++ same++;
++ else
++ done++;
++
++ return same;
++ }
++
++ QSTRING_S *
++ trim_qs_from_cl(cl, nl, pl)
++ QSTRING_S *cl;
++ QSTRING_S *nl;
++ QSTRING_S *pl;
++ {
++ QSTRING_S *cqstring = pl ? pl : nl;
++ QSTRING_S *tl = pl ? pl : nl;
++ int p, c;
++
++ if (qstring_is_normal(tl))
++ return tl;
++
++ p = same_qstring(pl ? pl : cl, pl ? cl : nl);
++
++ for (c = 1; c < p; c++, cl = cl->next, tl = tl->next);
++
++ /*
++ * cl->next and tl->next differ, it may be because cl->next does not
++ * exist or tl->next does not exist or simply both exist but are
++ * different. In this last case, it may be that cl->next->value is made
++ * of spaces. If this is the case, tl advances once more.
++ */
++
++ if (tl->next){
++ if (cl && cl->next && value_is_space(cl->next->value))
++ tl = tl->next;
++ if (tl->next)
++ free_qs(&(tl->next));
++ }
++
++ if (!p)
++ free_qs(&cqstring);
++
++ return cqstring;
++ }
++
++ /* This function trims cl so that it returns a real quote string based
++ * on information gathered from the previous and next lines. pl and cl are
++ * also trimmed, but that is done in another function, not here.
++ */
++ QSTRING_S *
++ fix_qstring(cl, nl, pl)
++ QSTRING_S *cl;
++ QSTRING_S *nl;
++ QSTRING_S *pl;
++ {
++ QSTRING_S *cqstring = cl, *nqstring = nl, *pqstring = pl;
++ int c, n;
++
++ if (qstring_is_normal(cl))
++ return cl;
++
++ c = count_levels_qstring(cl);
++ n = same_qstring(cl,nl);
++
++ if (!n){ /* no next line or no agreement with next line */
++ int p = same_qstring(pl, cl); /* number of agreements between pl and cl */
++ QSTRING_S *tl; /* test line */
++
++ /*
++ * Here p <= c, so either p < c or p == c. If p == c, we are done,
++ * and return cl. If not, there are two cases, either p == 0 or
++ * 0 < p < c. In the first case, we do not have enough evidence
++ * to return anything other than the normal part of cl, in the second
++ * case we can only return p levels of cl.
++ */
++
++ if (p == c)
++ tl = cqstring;
++ else{
++ if (p){
++ for (c = 1; c < p; c++)
++ cl = cl->next;
++ free_qs(&(cl->next));
++ tl = cqstring;
++ }
++ else{
++ int done = 0;
++ QSTRING_S *al = cl; /* another line */
++ /*
++ * Ok, we reaelly don't have enough evidence to return anything,
++ * different from the normal part of cl, but it could be possible
++ * that we may want to accept the not-normal part, so we better
++ * make an extra test to determine what needs to be freed
++ */
++ while (pl && cl && !strucmp(cl->value, pl->value)){
++ cl = cl->next;
++ pl = pl->next;
++ }
++ if (pl && cl && strcmp_qs(pl->value, cl->value))
++ cl = cl->next; /* next level differs only in spaces */
++ while (!done){
++ while (cl && cl->qstype == qsNormal)
++ cl = cl->next;
++ if (cl){
++ if ((cl->qstype == qsString)
++ && (cl->value[strlen(cl->value) - 1] == '>'))
++ cl = cl->next;
++ else done++;
++ }
++ else done++;
++ }
++ if (al == cl){
++ free_qs(&(cl));
++ tl = cl;
++ }
++ else {
++ while (al && (al->next != cl))
++ al = al->next;
++ cl = al;
++ if (cl && cl->next)
++ free_qs(&(cl->next));
++ tl = cqstring;
++ }
++ }
++ }
++ return tl;
++ }
++ if (n + 1 < c){ /* if there are not enough agreements */
++ int p = same_qstring(pl, cl); /* number of agreement between pl and cl */
++ QSTRING_S *tl; /* test line */
++
++ /*
++ * There's no way we can use cl in this case, but we can use
++ * part of cl, this is if pl does not have more agreements
++ * with cl.
++ */
++
++ if (p == c)
++ tl = cqstring;
++ else{
++ int m = p < n ? n : p;
++ for (c = 1; c < m; c++){
++ pl = pl ? pl->next : (QSTRING_S *) NULL;
++ nl = nl ? nl->next : (QSTRING_S *) NULL;
++ cl = cl->next;
++ }
++ if ((p == n) && pl && pl->next && nl && nl->next
++ && ((cl->next->qstype == pl->next->qstype)
++ || (cl->next->qstype == nl->next->qstype))
++ && (strcmp_qs(cl->next->value, pl->next->value)
++ || strcmp_qs(pl->next->value, cl->next->value)
++ || strcmp_qs(cl->next->value, nl->next->value)
++ || strcmp_qs(nl->next->value, cl->next->value)))
++ cl = cl->next; /* next level differs only in spaces */
++ if (cl->next)
++ free_qs(&(cl->next));
++ tl = cqstring;
++ }
++ return tl;
++ }
++ if (n + 1 == c){
++ int p = same_qstring(pl, cl);
++ QSTRING_S *tl; /* test line */
++
++ /*
++ * p <= c, so p <= n+1, which means p < n + 1 or p == n + 1.
++ * If p < n + 1, then p <= n.
++ * so we have three possibilities:
++ * p == n + 1 or p == n or p < n.
++ * In the first case we copy p == n + 1 == c levels, in the second
++ * and third case we copy n levels, and check if we can copy the
++ * n + 1 == c level.
++ */
++
++ if (p == n + 1) /* p == c, in the above sense of c */
++ tl = cl; /* use cl, this is enough evidence */
++ else{
++ for (c = 1; c < n; c++)
++ cl = cl->next;
++ /*
++ * Here c == n, we only have one more level of cl, and at least one
++ * more level of nl
++ */
++ if (cl->next->qstype == qsNormal)
++ cl = cl->next;
++ if (cl->next)
++ free_qs(&(cl->next));
++ tl = cqstring;
++ }
++ return tl;
++ }
++ if (n == c) /* Yeah!!! */
++ return cqstring;
++ }
++
++ /*
++ * This function flattens the quote string returned to us by is_quote. A
++ * crash in this function implies a bug elsewhere.
++ */
++ void
++ flatten_qstring(qs, buff)
++ QSTRING_S *qs;
++ char *buff;
++ {
++ int i = 0, j;
++
++ for (; qs; qs = qs->next)
++ for (j = 0; (qs->value[j]) && (buff[i++] = qs->value[j]); j++);
++ buff[i] = '\0';
++ }
++
++ /*
++ * Given a string, we return the position where the function thinks that
++ * the quote string is over, if you are ever thinking of fixing something,
++ * you got to the right place. Memory freed by caller. Experience shows
++ * that it only makes sense to initialize memory when we need it, not at
++ * the start of this function.
++ */
++ QSTRING_S *
++ is_quote (qs,word, been_here)
++ char *qs;
++ char word[NSTRING];
++ int been_here;
++ {
++ int i = 0, j, c, nxt, prev, finished = 0, offset;
++ QSTRING_S *qstring = (QSTRING_S *) NULL;
++
++ if (!word || !word[0])
++ return (QSTRING_S *) NULL;
++
++ while (!finished){
++ /*
++ * Before we apply our rules, let's advance past the quote string
++ * given by the user, this will avoid not recognition of the
++ * user's indent string and application of the arbitrary rules
++ * below. Notice that this step may bring bugs into this
++ * procedure, but these bugs will only appear if the indent string
++ * is really really strange and the text to be justified
++ * cooperates a lot too, so in general this will not be a problem.
++ * If you are concerned about this bug, simply remove the
++ * following lines after this comment and before the "switch"
++ * command below and use a more normal quote string!.
++ */
++ i += advance_quote_string(qs, word, i);
++ if (!word[i]) /* went too far? */
++ return qs_add(qs, word, qsNormal, 0, i, 0, 0);
++
++ switch (c = now(word,i)){
++ case NBSP:
++ case TAB :
++ case ' ' : { QSTRING_S *nextqs, *testqs = NULL;
++ int j;
++
++ for (; ISspace((unsigned char) word[i]); i++);
++ nextqs = is_quote(qs,word+i, 1);
++ /*
++ * Merge qstring and nextqs, since this is an artificial
++ * separation, unless nextqs is of different type.
++ * What this means in practice is that if
++ * qs->qstype == qsNormal and qs->next != NULL, then
++ * qs->next->qstype != qsNormal.
++ *
++ * Can't use qs_add to merge because it could lead
++ * to an infinite loop (e.g a line "^ ^").
++ */
++ if (nextqs){
++ if(nextqs->qstype == qsNormal){
++ i += strlen(nextqs->value);
++ testqs = copy_qs(nextqs->next);
++ }
++ else
++ testqs = copy_qs(nextqs);
++ free_qs(&nextqs);
++ }
++
++ qstring = (QSTRING_S *) malloc (sizeof(QSTRING_S));
++ memset (qstring, 0, sizeof(QSTRING_S));
++
++ qstring->value = (char *) malloc((i+1)*sizeof(char));
++ strncpy(qstring->value, word, i);
++ qstring->value[i] = '\0';
++ qstring->qstype = qsNormal;
++
++ qstring->next = testqs;
++
++ return qstring;
++ }
++ break;
++
++ case RPAREN: /* parenthesis ')' */
++ if ((i != 0) || ((i == 0) && been_here))
++ i++;
++ else
++ if (i == 0)
++ return qs_add(qs, word, qsChar, i, i, 1, 1);
++ else
++ finished++;
++ break;
++
++ case ';':
++ case ':': /* colon */
++ case '~': nxt = next(word,i);
++ if (is_tilde(c) && (nxt == '/'))
++ finished++;
++ else if (is_cquote(c)
++ || is_cquote(nxt)
++ || ((c != '~') && (nxt == RPAREN))
++ || ((i != 0) && is_space(nxt))
++ || is_cquote(prev = before(word,i))
++ || (is_space(prev) && !is_tilde(c))
++ || (is_tilde(c) && nxt != '/'))
++ i++;
++ else if (i == 0 && been_here)
++ return qs_add(qs, word, qsChar, i, i, 1, 1);
++ else
++ finished++;
++ break;
++
++ case '<' :
++ case '=' :
++ case '-' : offset = is_cquote(nxt = next(word,i)) ? 2
++ : ((nxt == c)
++ && is_cquote(next(word,i+1))) ? 3 : -1;
++
++ if (offset > 0)
++ return qs_add(qs, word, qsString, i, i, offset, 1);
++ else
++ finished++;
++ break;
++
++ case '[' :
++ case '+' : /* accept +>, *> */
++ case '*' : if (is_rarrow(nxt = next(word, i)) || /* stars */
++ (is_space(nxt) && is_rarrow(next(word,i+1))))
++ i++;
++ else
++ finished++;
++ break;
++
++ case '^' :
++ case '!' :
++ case '%' :
++ case '#' : if (next(word,i) != c)
++ return qs_add(qs, word, qsChar, i, i+1, 0, 1);
++ else
++ finished++;
++ break;
++
++ default:
++ if (is_cquote(c))
++ i++;
++ else if (is_cletter(c)){
++ for (j = i; (is_cletter(nxt = next(word,j)) || is_cnumber(nxt))
++ && !(is_space(nxt));j++);
++ /*
++ * The whole reason why we are splitting the quote
++ * string is so that we will be able to accept quote
++ * strings that are strange in some way. Here we got to
++ * a point in which a quote string might exist, but it
++ * could be strange, so we need to create a "next" field
++ * for the quote string to warn us that something
++ * strange is coming. We need to confirm if this is a
++ * good choice later. For now we will let it pass.
++ */
++ if (isaword(word,i,j) || isamailbox(word,i,j)){
++ int offset;
++ QStrType qstype;
++
++ offset = (is_cquote(c = next(word,j))
++ || (c == RPAREN)) ? 2
++ : ((is_space(c)
++ && is_cquote(next(word,j+1))) ? 3 : -1);
++
++ qstype = (is_cquote(c) || (c == RPAREN))
++ ? (is_qsword(c) ? qsWord : qsString)
++ : ((is_space(c) && is_cquote(next(word,j+1)))
++ ? (is_qsword(next(word,j+1))
++ ? qsWord : qsString)
++ : qsString);
++
++ /*
++ * qsWords are valid quote strings only when
++ * they are followed by text.
++ */
++ if ((offset > 0) && (qstype == qsWord) &&
++ !(allwd_after_qsword(now(word,j + offset))))
++ offset = -1;
++
++ if (offset > 0)
++ return qs_add(qs, word, qstype, i, j, offset, 1);
++ }
++ finished++;
++ }
++ else{
++ if(!forbidden(c))
++ return qs_add(qs, word, qsChar, 0, 1, 0, 1);
++ else /* chao pescao */
++ finished++;
++ }
++ break;
++ } /* End Switch */
++ } /* End while */
++
++ if (i > 0)
++ qstring = qs_add(qs, word, qsNormal, 0, i, 0, 0);
++
++ return qstring;
++ }
++
++ void
++ linencpy(word, l, buflen)
++ char word[NSTRING];
++ LINE *l;
++ int buflen;
++ {
++ int i = 0;
++ for (;(i < buflen) && (i < llength(l)) && (word[i] = (char)lgetc(l,i).c); i++);
++ word[buflen - 1] = '\0';
++ }
++
++
++
++ int
++ isaword(word,i,j)
++ char word[NSTRING];
++ int i;
++ int j;
++ {
++ return i <= j && is_cletter(word[i]) ?
++ (i < j ? isaword(word,i+1,j) : 1) : 0;
++ }
++
++ int
++ isamailbox(word,i,j)
++ char word[NSTRING];
++ int i;
++ int j;
++ {
++ return i <= j && (is_cletter(word[i]) || is_a_digit(word[i])
++ || word[i] == '.')
++ ? (i < j ? isamailbox(word,i+1,j) : 1) : 0;
++ }
++
++
++ /*
++ * This function returns the quote string as a structure. In this way we
++ have two ways to get the quote string: as a char * or as a QSTRING_S *
++ directly.
++ */
++ QSTRING_S *
++ qs_quote_match(q, l, buf, buflen, raw)
++ char *q;
++ LINE *l;
++ char *buf;
++ int buflen;
++ int raw;
++ {
++ char GLine[NSTRING] = {'\0'}, NLine[NSTRING] = {'\0'},
++ PLine[NSTRING] = {'\0'};
++ LINE *nl = l != curbp->b_linep ? lforw(l) : NULL;
++ LINE *pl = lback(l) != curbp->b_linep ? lback(l) : NULL;
++
++ if (nl)
++ linencpy(NLine, nl, NSTRING);
++
++ if (pl)
++ linencpy(PLine, pl, NSTRING);
++
++ linencpy(GLine, l, NSTRING);
++
++ return do_quote_match(q,GLine, NLine, PLine, raw);
++ }
+
+ /*
+! * Return number of quotes if whatever starts the line matches the quote
+! * string
+ */
+! quote_match(q, l, buf, buflen, raw)
+ char *q;
+ LINE *l;
+ char *buf;
+ int buflen;
++ int raw;
+ {
+! QSTRING_S *qs;
+
+! qs = qs_quote_match(q, l, buf, buflen, raw);
+! flatten_qstring(qs, buf);
+! if (qs)
+! free_qs(&qs);
+!
+! return buf && buf[0] ? strlen(buf) : 0;
+! }
+!
+! /*
+! This routine removes the last part that is qsword or qschar that is not
+! followed by a normal part. This means that if a qsword or qschar is
+! followed by a qsnormal (or qsstring), we accept the qsword (or qschar)
+! as part of a quote string.
+! */
+!
+! QSTRING_S *
+! remove_qsword(cl)
+! QSTRING_S *cl;
+! {
+! QSTRING_S *np = cl;
+! QSTRING_S *cp = np; /* this variable trails cl */
+!
+! while(1){
+! while (cl && cl->qstype == qsNormal)
+! cl = cl->next;
+!
+! if (cl){
+! if (((cl->qstype == qsWord) || (cl->qstype == qsChar))
+! && !exists_good_part(cl)){
+! if (np == cl) /* qsword or qschar at the beginning */
+! free_qs(&cp);
+! else{
+! while (np->next != cl)
+! np = np->next;
+! free_qs(&(np->next));
+! }
+! break;
+! }
+! else
+! cl = cl->next;
+! }
+! else
+! break;
+! }
+! return cp;
+! }
+!
+! int
+! exists_good_part (cl)
+! QSTRING_S *cl;
+! {
+! return (cl ? (((cl->qstype != qsWord) && (cl->qstype != qsChar)
+! && !value_is_space(cl->value))
+! ? 1
+! : exists_good_part(cl->next))
+! : 0);
+! }
+!
+!
+! QSTRING_S *
+! do_quote_match(q,GLine, NLine, PLine, raw)
+! char *q;
+! char GLine[NSTRING];
+! char NLine[NSTRING];
+! char PLine[NSTRING];
+! int raw;
+! {
+! QSTRING_S *cl, *nl = NULL, *pl = NULL;
+! int c, n, p,i, j, NewC, NewN, clength, same = 0;
+! char nbuf[NSTRING], pbuf[NSTRING], buf[NSTRING];
+! int emptynl = 0, emptypl = 0;
+!
+! cl = is_quote(q,GLine, 0); /* Current or Given line */
+!
+! if (!cl) /* if nothing in, nothing out */
+! return cl;
+!
+! if (NLine && NLine[0])
+! nl = is_quote(q,NLine, 0); /* Next Line */
+! if (PLine && PLine[0])
+! pl = is_quote(q,PLine, 0); /* Previous Line */
+!
+! /*
+! * If there's nothing in the preceeding or following line
+! * there is not enough information to accept it or discard it. In this
+! * case it's likely to be an isolated line, so we better accept it
+! * if it does not look like a word. */
+!
+! flatten_qstring(pl, pbuf);
+! emptypl = (!PLine || !PLine[0] ||
+! (pl && value_is_space(pbuf)) && !PLine[strlen(pbuf)]) ? 1 : 0;
+! if (emptypl){
+! flatten_qstring(nl, nbuf);
+! emptynl = (!NLine || !NLine[0] ||
+! (nl && value_is_space(nbuf) && !NLine[strlen(nbuf)])) ? 1 : 0;
+! if (emptynl){
+! cl = remove_qsword(cl);
+! cl = qs_remove_trailing_spaces(cl);
+! free_qs(&nl);
+! free_qs(&pl);
+!
+! return cl;
+! }
+! }
+!
+! /*
+! * If either cl, nl or pl contain suspicious characters that may make
+! * them (or not) be quote strings, we need to fix them, so that the
+! * next pass will be done correctly.
+! */
+!
+! cl = fix_qstring(cl, nl, pl);
+! nl = trim_qs_from_cl(cl, nl, NULL);
+! pl = trim_qs_from_cl(cl, NULL, pl);
+! flatten_qstring(cl, buf);
+! flatten_qstring(nl, nbuf);
+! flatten_qstring(pl, pbuf);
+!
+! if (raw){ /* if we are asked for the raw string */
+! free_qs(&nl);
+! free_qs(&pl);
+!
+! return cl; /* return now! */
+! }
+! /*
+! * Once upon a time, is_quote used to return the length of the quote
+! * string that it had found. One day, not long ago, black hand came
+! * and changed all that, and made is_quote return a quote string
+! * divided in several fields, making the algorithm much more
+! * complicated. Fortunately black hand left a few comments in the
+! * source code to make it more understandable. Because of this change
+! * we need to compute the lengths of the quote strings separately
+! */
+! c = buf && buf[0] ? strlen(buf) : 0;
+! n = nbuf && nbuf[0] ? strlen(nbuf) : 0;
+! p = pbuf && pbuf[0] ? strlen(pbuf) : 0;
+!
+! /*
+! * When quote strings contain only blank spaces (ascii code 32) the
+! * above count is equal to the length of the quote string, but if
+! * there are TABS, the length of the quote string as seen by the user
+! * is different than the number that was just computed. Because of
+! * this we demand a recount (hmm.. unless you are in Florida, where
+! * recounts are forbidden)
+! */
+!
+! NewC = strlenis(buf);
+! NewN = strlenis(nbuf);
+!
+! /*
+! * For paragraphs with spaces in the first line, but no space in the
+! * quote string of the second line, we make sure we choose the quote
+! * string without a space at the end of it.
+! */
+! if ((NLine && !NLine[0])
+! && ((PLine && !PLine[0])
+! || (((same = same_qstring(pl, cl)) != 0)
+! && (same != count_levels_qstring(cl)))))
+! cl = qs_remove_trailing_spaces(cl);
+! else
+! if (NewC > NewN){
+! for (j = 0; (j < n) && (GLine[j] == NLine[j]); j++);
+! clength = j;
+! if (j < n){ /* see if buf and nbuf are padded with spaces and tabs */
+! for (i = clength; i < n && ISspace((unsigned char)NLine[i]); i++);
+! if (i == n){
+! for (i = clength; i < c && ISspace((unsigned char)GLine[i]); i++);
+! if (i == c)
+! j = n;
+! }
+ }
+! if (j == n){
+! for (j = clength; j < c && ISspace((unsigned char)GLine[j]); j++);
+! if (j == c){
+!
+! /*
+! * If we get here, it means that the current line has the same
+! * quote string (visually) than the next line, but both of them
+! * are padded with different amount of TABS or spaces at the end.
+! * The current line (GLine) has more spaces/TABs than the next
+! * line. This is the typical situation that is found at the
+! * begining of a paragraph. We need to check this, however, by
+! * checking the previous line. This avoids that we confuse
+! * ourselves with being in the last line of a paragraph.
+! */
+!
+! for (j = 0; (j < p) && (GLine[j] == PLine[j]); j++);
+! if (((p == c) && ((j != p) && NLine[n]))
+! || ((p != c) && NLine[n])){
+! free_qs(&cl);
+! cl = copy_qs(nl);
+! }
+! }
+! }
+! }
+!
+! free_qs(&nl);
+! free_qs(&pl);
+!
+! return cl;
+! }
+!
+! /*
+! * Given a line, an initial position, and a quote string, we advance the
+! * current line past the quote string, including arbitraty spaces
+! * contained in the line, except that it removes trailing spaces. We do
+! * not handle TABs, if any, contained in the quote string. At least not
+! * yet.
+! *
+! * Arguments: q - quote string
+! * l - a line to process
+! * i - position in the line to start processing. i = 0 is the
+! * begining of that line.
+! */
+! int
+! advance_quote_string(q, l, i)
+! char *q;
+! char l[NSTRING];
+! int i;
+! {
+! int n = 0, j = 0, is = 0, es = 0;
+! int k, m, p, adv;
+! char qs[NSTRING] = {'\0'};
+!
+! if(!q || !*q)
+! return(0);
+!
+! for (p = strlen(q); (p > 0) && (q[p - 1] == ' '); p--, es++);
+! if (!p){ /* string contains only spaces */
+! for (k = 0; l[i + k] == ' '; k++);
+! k -= k % es;
+! return k;
+! }
+! for (is = 0; q[is] == ' '; is++); /* count initial spaces */
+! for (m = 0 ; is + m < p ; m++)
+! qs[m] = q[is + m]; /* qs = quote string without any space at the end */
+! /* advance as many spaces as there are at the begining */
+! for (k = 0; l[i + j] == ' '; k++, j++);
+! /* now find the visible string in the line */
+! for (m = 0; qs[m] && l[i + j] == qs[m]; m++, j++);
+! if (!qs[m]){ /* no match */
+! /*
+! * So far we have advanced at least "is" spaces, plus the visible
+! * string "qs". Now we need to advance the trailing number of
+! * spaces "es". If we can do that, we have found the quote string.
+! */
+! for (p = 0; l[i + j + p] == ' '; p++);
+! adv = advance_quote_string(q, l, i + j + ((p < es) ? p : es));
+! n = ((p < es) ? 0 : es) + k + m + adv;
+ }
+! return n;
+ }
+
++ /*
++ * This function returns the effective length in screen of the quote
++ * string. If the string contains a TAB character, it is added here, if
++ * not, the length returned is the length of the string
++ */
++
++ int
++ strlenis(qstr)
++ char *qstr;
++ {
++ int i, rv = 0;
++
++ if (qstr && *qstr){
++ for (i = 0; qstr[i]; i++)
++ rv += ((qstr[i] == TAB) ? (~rv & 0x07) + 1 : 1);
++ }
++ return rv;
++ }
+
+ /* Justify the entire buffer instead of just a paragraph */
+ fillbuf(f, n)
+***************
+*** 475,485 ****
+ int f, n; /* deFault flag and Numeric argument */
+
+ {
+! int i, j, c, qlen, word[NSTRING], same_word,
+! spaces, word_len, line_len, line_last, qn;
+! char *qstr, qstr2[NSTRING];
+ LINE *eopline;
+ REGION region;
+
+ if(curbp->b_mode&MDVIEW){ /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+--- 1491,1503 ----
+ int f, n; /* deFault flag and Numeric argument */
+
+ {
+! int i = 0, j, c, qlen, word[NSTRING], same_word, qlenis,
+! spaces, word_len, line_len, line_last, qn, indlen, qi, pqi;
+! char *qstr, qstr2[NSTRING], tbuf[NSTRING], ind_str[NSTRING],
+! *qstrfl, qstrfl2[NSTRING], quoid[NSTRING];
+ LINE *eopline;
+ REGION region;
++ QSTRING_S *tl;
+
+ if(curbp->b_mode&MDVIEW){ /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+***************
+*** 499,512 ****
+
+ /* and back to the beginning of the paragraph */
+ gotobop(FALSE, 1);
+
+! /* determine if we're justifying quoted text or not */
+ qstr = ((glo_quote_str || (Pmaster && Pmaster->quote_str))
+! && quote_match(glo_quote_str ? glo_quote_str
+! : Pmaster->quote_str,
+! curwp->w_dotp, qstr2, NSTRING)
+! && *qstr2) ? qstr2 : NULL;
+! qlen = qstr ? strlen(qstr) : 0;
+
+ /* let yank() know that it may be restoring a paragraph */
+ thisflag |= CFFILL;
+--- 1517,1602 ----
+
+ /* and back to the beginning of the paragraph */
+ gotobop(FALSE, 1);
++ setimark(FALSE, 1); /* Remember this spot in case we unjustify */
+
+! /*
+! * When a paragraph has special indentation, we will get two quote
+! * strings. One from the first line of the paragraph, and one from
+! * the last line of the paragraph. We will need to use both when
+! * we justify.
+! *
+! * Here's a model of what we will code:
+! *
+! * +-------+-------+-+-----+
+! * | qstrfl|ind_str|X| text|
+! * +-----+-+-------+-+-----+
+! * | qstr| *(space)|X| text|
+! * +-----+---------+-+-----+
+! *
+! * Here X represents 1 space if it exists after ind_str and
+! * "*(space)" represent a variable amount of space that is put there
+! * to pad text so that it will align correctly when justified.
+! */
+! indlen = indent_match((glo_quote_str || (Pmaster && Pmaster->quote_str))
+! ? (glo_quote_str ? glo_quote_str : Pmaster->quote_str)
+! : "", curwp->w_dotp, ind_str, NSTRING, 0);
+! qstrfl = (quote_match((glo_quote_str || (Pmaster && Pmaster->quote_str))
+! ? (glo_quote_str ? glo_quote_str : Pmaster->quote_str)
+! : ">", curwp->w_dotp, qstrfl2, NSTRING,0)
+! && *qstrfl2) ? qstrfl2 : NULL;
+! if (qstrfl){
+! if (glo_quote_str || (Pmaster && Pmaster->quote_str))
+! for (; (i < NSTRING) && (quoid[i] = qstrfl[i]); i++);
+! else{
+! for (; (i < NSTRING) && qstrfl[i] && (quoid[i] = ' '); i++);
+! qstrfl[0] = '\0';
+! }
+! }
+! if (indlen)
+! for (j = 0; ((i + j) < NSTRING) && (quoid[i] = ind_str[j]); i++,j++);
+! quoid[i] = '\0';
+! qi = quoid && quoid[0] ? strlen(quoid) : 0;
+! if (indlen) /* strip trailing spaces */
+! for (;ISspace((unsigned char) quoid[qi - 1]); qi--);
+! quoid[qi] = '\0'; /* we have closed quoid at "X" in the first line */
+!
+! if (strlenis(quoid) > fillcol)
+! return FALSE; /* Too wide, we can't justify this! */
+!
+! /* determine if we're justifying quoted text or not */
+ qstr = ((glo_quote_str || (Pmaster && Pmaster->quote_str))
+! && quote_match(glo_quote_str ? glo_quote_str :
+! Pmaster->quote_str,
+! curwp->w_dotp, qstr2, NSTRING, 0)
+! && *qstr2) ? qstr2 : NULL;
+! /* In some situations, like in the following paragraph, qstr can be non
+! * empty as returned above, when indeed it is empty. Fix it!.
+!
+! * Item #1
+! * Item #2
+! continuation of item #2
+! */
+! if (qstr && indlen){
+! for (i = strlen(qstr) - 1; ISspace((unsigned char) qstr[i]); i--);
+! qstr[i + 1] = '\0';
+! }
+!
+! qlen = qstr ? strlen(qstr) : 0;
+! qlenis = qstr ? strlenis(qstr) : 0;
+!
+! /*
+! * Compare effective lengths of quoid and qstr to decide how much space
+! * we need to use to pad with.
+! */
+! if (indlen && ((j = strlenis(quoid) - strlenis(qstr)) > 0)){
+! pqi = qstr ? strlen(qstr) : 0;
+! for (i = 0; (i < j) && (qstr2[pqi + i] = ' '); i++);
+! if (ISspace((unsigned char) ind_str[indlen - 1]))
+! qstr2[pqi + i++] = ' ';
+! qstr2[pqi + i] = '\0';
+! if (!qstr)
+! qstr = qstr2;
+! }
+
+ /* let yank() know that it may be restoring a paragraph */
+ thisflag |= CFFILL;
+***************
+*** 524,541 ****
+ return(FALSE);
+
+ /* Now insert it back wrapped */
+! spaces = word_len = line_len = same_word = 0;
+
+ /* Beginning with leading quoting... */
+! if(qstr){
+! while(qstr[line_len])
+! linsert(1, qstr[line_len++]);
+
+ line_last = ' '; /* no word-flush space! */
+ }
+
+ /* ...and leading white space */
+! for(i = qlen; (c = fremove(i)) == ' ' || c == TAB; i++){
+ linsert(1, line_last = c);
+ line_len += ((c == TAB) ? (~line_len & 0x07) + 1 : 1);
+ }
+--- 1614,1651 ----
+ return(FALSE);
+
+ /* Now insert it back wrapped */
+! spaces = word_len = line_len = same_word = i = 0;
+
+ /* Beginning with leading quoting... */
+! if(qstrfl){
+! while((tbuf[line_len] = qstrfl[line_len]) == fremove(line_len))
+! linsert(1, qstrfl[line_len++]);
+! /*
+! * The only way that at the end of the above loop we don't have
+! * line_len == qlen is that there are trailing spaces or TABS
+! * which could not be accounted in the qstr in is_quote or other
+! * functions before we got here. Now we enter the common part of
+! * the quote string in the first line and the rest is only spaces
+! * (or TABS) that need to be entered, which are left to the loop
+! * following this "if" statement
+! */
+! i = line_len; /* start next loop from here */
+! tbuf[line_len] = '\0'; /* closing tbuf... */
+! line_len = strlenis(tbuf); /* we demand a recount! */
+! line_last = ' '; /* no word-flush space! */
+! }
+
++ /* ...followed by the indent string, if any */
++ if (indlen){
++ for (i, j = 0; (c = fremove(i)) && ind_str[j]; i++, j++){
++ linsert(1, line_last = c);
++ line_len += ((c == TAB) ? (~line_len & 0x07) + 1 : 1);
++ }
+ line_last = ' '; /* no word-flush space! */
+ }
+
+ /* ...and leading white space */
+! for(i; (c = fremove(i)) == ' ' || c == TAB; i++){
+ linsert(1, line_last = c);
+ line_len += ((c == TAB) ? (~line_len & 0x07) + 1 : 1);
+ }
+***************
+*** 558,572 ****
+
+ default :
+ if(spaces){ /* flush word? */
+! if((line_len - qlen > 0)
+ && line_len + word_len + 1 > fillcol
+! && ((isspace((unsigned char)line_last))
+ || (linsert(1, ' ')))
+ && (line_len = fpnewline(qstr)))
+ line_last = ' '; /* no word-flush space! */
+
+ if(word_len){ /* word to write? */
+! if(line_len && !isspace((unsigned char) line_last)){
+ linsert(1, ' '); /* need padding? */
+ line_len++;
+ }
+--- 1668,1682 ----
+
+ default :
+ if(spaces){ /* flush word? */
+! if((line_len - qlenis > 0)
+ && line_len + word_len + 1 > fillcol
+! && ((ISspace((unsigned char)line_last))
+ || (linsert(1, ' ')))
+ && (line_len = fpnewline(qstr)))
+ line_last = ' '; /* no word-flush space! */
+
+ if(word_len){ /* word to write? */
+! if(line_len && !ISspace((unsigned char) line_last)){
+ linsert(1, ' '); /* need padding? */
+ line_len++;
+ }
+***************
+*** 588,595 ****
+
+ if(word_len + 1 >= NSTRING){
+ /* Magic! Fake that we output a wrapped word */
+! if((line_len - qlen > 0) && !same_word++){
+! if(!isspace((unsigned char) line_last))
+ linsert(1, ' ');
+ line_len = fpnewline(qstr);
+ }
+--- 1698,1705 ----
+
+ if(word_len + 1 >= NSTRING){
+ /* Magic! Fake that we output a wrapped word */
+! if((line_len - qlenis > 0) && !same_word++){
+! if(!ISspace((unsigned char) line_last))
+ linsert(1, ' ');
+ line_len = fpnewline(qstr);
+ }
+***************
+*** 608,619 ****
+ }
+
+ if(word_len){
+! if((line_len - qlen > 0) && (line_len + word_len + 1 > fillcol)){
+! if(!isspace((unsigned char) line_last))
+ linsert(1, ' ');
+! (void) fpnewline(qstr);
+ }
+! else if(line_len && !isspace((unsigned char) line_last))
+ linsert(1, ' ');
+
+ for(j = 0; j < word_len; j++)
+--- 1718,1730 ----
+ }
+
+ if(word_len){
+! if((line_len - qlenis > 0) && (line_len + word_len + 1 > fillcol)){
+! if(!ISspace((unsigned char) line_last))
+ linsert(1, ' ');
+! if (line_len && (line_len != qlenis))
+! (void) fpnewline(qstr);
+ }
+! else if(line_len && !ISspace((unsigned char) line_last))
+ linsert(1, ' ');
+
+ for(j = 0; j < word_len; j++)
+***************
+*** 640,644 ****
+--- 1751,1885 ----
+ for(len = 0; quote && *quote; quote++, len++)
+ linsert(1, *quote);
+
++ quote -= len; /* go back */
++ len = strlenis(quote); /* and recount */
+ return(len);
+ }
++
++ int
++ is_indent (word, plb)
++ char word[NSTRING];
++ int plb;
++ {
++ int i = 0, finished = 0, c, nxt, j, k, digit = 0, bdigits = -1;
++
++ if (!word || !word[0])
++ return i;
++
++ for (i = 0, j = 0; ISspace((unsigned char) word[i]); i++, j++);
++ while ((i < NSTRING - 2) && !finished){
++ switch (c = now(word,i)){
++ case NBSP:
++ case TAB :
++ case ' ' : for (; ISspace((unsigned char )word[i]); i++);
++ if (!is_indent_char(now(word,i)))
++ finished++;
++ break;
++
++ case '+' :
++ case '.' :
++ case ']' :
++ case '*' :
++ case '}' :
++ case '-' :
++ case RPAREN:
++ nxt = next(word,i);
++ if (((c == '.') && allowed_after_period(nxt))
++ || ((c == '*') && allowed_after_star(nxt))
++ || ((c == '}') && allowed_after_braces(nxt))
++ || ((c == '-') && allowed_after_dash(nxt))
++ || ((c == '+') && allowed_after_dash(nxt))
++ || ((c == RPAREN) && allowed_after_parenth(nxt))
++ || ((c == ']') && allowed_after_parenth(nxt)))
++ i++;
++ else
++ finished++;
++ break;
++
++ default : if (is_a_digit(c) && plb){
++ if (bdigits < 0)
++ bdigits = i; /* first digit */
++ for (k = i; is_a_digit(now(word,k)); k++);
++ if (k - bdigits > 2){ /* more than 2 digits? */
++ i = bdigits; /* too many! */
++ finished++;
++ }
++ else{
++ if(allowed_after_digit(now(word,k),word,k))
++ i = k;
++ else{
++ i = bdigits;
++ finished++;
++ }
++ }
++ }
++ else
++ finished++;
++ break;
++ }
++ }
++ if (i == j)
++ i = 0; /* there must be something more than spaces in an indent string */
++ return i;
++ }
++
++
++ /*
++ * If there is an indent string this function returns
++ * its length
++ */
++ int
++ indent_match(q, l, buf, buflen, raw)
++ char *q;
++ LINE *l;
++ char *buf;
++ int buflen;
++ int raw;
++ {
++ char GLine[NSTRING] = {0};
++ int i, j, k, plb;
++
++ k = quote_match(q,l, buf, buflen, raw);
++
++ linencpy(GLine, l, NSTRING);
++
++ plb = (lback(l) != curbp->b_linep) ? lisblank(lback(l)) : 1;
++ if (!plb){
++ i = llength(lback(l)) - 1;
++ for (; i >= 0 && ISspace((unsigned char)lgetc(lback(l), i).c); i--);
++ if (EOLchar(lgetc(lback(l), i).c))
++ plb++;
++ }
++
++ i = is_indent(GLine+k, plb);
++
++ for (j = 0; (j < i) && (buf[j] = GLine[j + k]); j++);
++ buf[j] = '\0';
++
++ return i;
++ }
++
++ deletepara(f, n) /* Delete the current paragraph */
++
++ int f, n; /* deFault flag and Numeric argument */
++
++ {
++ if(curbp->b_mode&MDVIEW){ /* don't allow this command if */
++ return(rdonly()); /* we are in read only mode */
++ }
++
++ if(!lisblank(curwp->w_dotp))
++ gotobop(FALSE, 1);
++
++ curwp->w_markp = curwp->w_dotp;
++ curwp->w_marko = curwp->w_doto;
++
++ gotoeop(FALSE, 1);
++ if (curwp->w_dotp != curbp->b_linep){ /* if we are not at the end of buffer */
++ curwp->w_dotp = lforw(curwp->w_dotp); /* get one more line */
++ curwp->w_doto = 0; /* but only the beginning */
++ }
++ killregion(f,n);
++
++ return(TRUE);
++ }
+diff -rc pine4.63/pine/addrbook.c pine4.63.I.USE/pine/addrbook.c
+*** pine4.63/pine/addrbook.c Tue Apr 26 15:15:46 2005
+--- pine4.63.I.USE/pine/addrbook.c Thu May 19 19:57:32 2005
+***************
+*** 6658,6667 ****
+ *warped;
+ {
+ int find_result, rc, flags;
+ static char search_string[MAX_SEARCH + 1] = { '\0' };
+ char prompt[MAX_SEARCH + 50], nsearch_string[MAX_SEARCH+1];
+ HelpType help;
+! ESCKEY_S ekey[4];
+ PerAddrBook *pab;
+ long nl;
+
+--- 6658,6668 ----
+ *warped;
+ {
+ int find_result, rc, flags;
++ static char last_search_string[MAX_SEARCH + 1] = { '\0' };
+ static char search_string[MAX_SEARCH + 1] = { '\0' };
+ char prompt[MAX_SEARCH + 50], nsearch_string[MAX_SEARCH+1];
+ HelpType help;
+! ESCKEY_S ekey[5];
+ PerAddrBook *pab;
+ long nl;
+
+***************
+*** 6676,6692 ****
+ ekey[0].name = "";
+ ekey[0].label = "";
+
+! ekey[1].ch = ctrl('Y');
+! ekey[1].rval = 10;
+! ekey[1].name = "^Y";
+! ekey[1].label = "First Adr";
+!
+! ekey[2].ch = ctrl('V');
+! ekey[2].rval = 11;
+! ekey[2].name = "^V";
+! ekey[2].label = "Last Adr";
+
+! ekey[3].ch = -1;
+
+ flags = OE_APPEND_CURRENT | OE_KEEP_TRAILING_SPACE;
+ while(1){
+--- 6677,6698 ----
+ ekey[0].name = "";
+ ekey[0].label = "";
+
+! ekey[1].ch = ctrl('N');
+! ekey[1].rval = 9;
+! ekey[1].name = "^N";
+! ekey[1].label = "Ins Pat";
+!
+! ekey[2].ch = ctrl('Y');
+! ekey[2].rval = 10;
+! ekey[2].name = "^Y";
+! ekey[2].label = "First Adr";
+!
+! ekey[3].ch = ctrl('V');
+! ekey[3].rval = 11;
+! ekey[3].name = "^V";
+! ekey[3].label = "Last Adr";
+
+! ekey[4].ch = -1;
+
+ flags = OE_APPEND_CURRENT | OE_KEEP_TRAILING_SPACE;
+ while(1){
+***************
+*** 6697,6702 ****
+--- 6703,6711 ----
+ help = help == NO_HELP ? h_oe_searchab : NO_HELP;
+ continue;
+ }
++ else if(rc == 9)
++ insert_pattern_in_string(nsearch_string, last_search_string
++ , MAX_SEARCH);
+ else if(rc == 10){
+ *warped = 1;
+ warp_to_beginning(); /* go to top of addrbooks */
+***************
+*** 6724,6730 ****
+ }
+ }
+
+! if(rc != 4)
+ break;
+ }
+
+--- 6733,6739 ----
+ }
+ }
+
+! if(rc != 4 && rc != 9)
+ break;
+ }
+
+***************
+*** 6737,6742 ****
+--- 6746,6754 ----
+ search_string[sizeof(search_string)-1] = '\0';
+ }
+
++ strncpy(last_search_string, nsearch_string, sizeof(last_search_string));
++ last_search_string[sizeof(last_search_string)-1] = '\0';
++
+ find_result = find_in_book(cur_line, search_string, new_line, wrapped);
+
+ if(*wrapped == 1)
+diff -rc pine4.63/pine/adrbkcmd.c pine4.63.I.USE/pine/adrbkcmd.c
+*** pine4.63/pine/adrbkcmd.c Thu Mar 31 09:29:09 2005
+--- pine4.63.I.USE/pine/adrbkcmd.c Thu May 19 19:57:26 2005
+***************
+*** 3866,3871 ****
+--- 3866,3873 ----
+ * 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{
+***************
+*** 3873,3878 ****
+--- 3875,3881 ----
+ 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 pine4.63/pine/args.c pine4.63.I.USE/pine/args.c
+*** pine4.63/pine/args.c Wed Mar 9 17:10:34 2005
+--- pine4.63.I.USE/pine/args.c Thu May 19 19:57:27 2005
+***************
+*** 74,79 ****
+--- 74,80 ----
+ char args_err_non_abs_passfile[] = "argument to \"-passfile\" should be fully-qualified";
+ char args_err_missing_lu[] = "missing argument for option \"-create_lu\"\nUsage: pine -create_lu <addrbook_file> <addrbook_sort_type>";
+ char args_err_missing_sort[] = "missing argument for option \"-sort\"";
++ char args_err_missing_thread_sort[] = "missing argument for option \"-threadsort\"";
+ char args_err_missing_flag_arg[] = "missing argument for flag \"%c\"";
+ char args_err_missing_flag_num[] = "Non numeric argument for flag \"%c\"";
+ char args_err_missing_debug_num[] = "Non numeric argument for \"%s\"";
+***************
+*** 117,122 ****
+--- 118,124 ----
+ " -z \t\tSuspend - allow use of ^Z suspension",
+ " -r \t\tRestricted - can only send mail to oneself",
+ " -sort <sort>\tSort - Specify sort order of folder:",
++ " -threadsort <sort>\tSort - Specify sort order of thread index screen:",
+ "\t\t subject, arrival, date, from, size, /reverse",
+ " -i\t\tIndex - Go directly to index, bypassing main menu",
+ " -I <keystroke_list> Initial keystrokes to be executed",
+***************
+*** 202,207 ****
+--- 204,210 ----
+ char *cmd_list = NULL;
+ char *debug_str = NULL;
+ char *sort = NULL;
++ char *threadsort = NULL;
+ char *pinerc_file = NULL;
+ char *addrbook_file = NULL;
+ char *ab_sort_descrip = NULL;
+***************
+*** 389,394 ****
+--- 392,409 ----
+
+ goto Loop;
+ }
++ else if(strcmp(*av, "threadsort") == 0){
++ if(--ac){
++ threadsort = *++av;
++ COM_THREAD_SORT_KEY = cpystr(threadsort);
++ }
++ else{
++ display_args_err(args_err_missing_thread_sort, NULL, 1);
++ ++usage;
++ }
++
++ goto Loop;
++ }
+ else if(strcmp(*av, "url") == 0){
+ if(args->action == aaFolder && !args->data.folder){
+ args->action = aaURL;
+***************
+*** 496,501 ****
+--- 511,522 ----
+ do_version = 1;
+ goto Loop;
+ }
++ else if(strcmp(*av, "subject") == 0){
++ if(--ac){
++ pine_state->subject = cpystr(*++av);
++ }
++ goto Loop;
++ }
+ #ifdef _WINDOWS
+ else if(strcmp(*av, "install") == 0){
+ ps_global->install_flag = 1;
+diff -rc pine4.63/pine/bldaddr.c pine4.63.I.USE/pine/bldaddr.c
+*** pine4.63/pine/bldaddr.c Fri Mar 25 15:33:27 2005
+--- pine4.63.I.USE/pine/bldaddr.c Thu May 19 19:57:26 2005
+***************
+*** 2306,2313 ****
+ 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;
+--- 2306,2319 ----
+ 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 pine4.63/pine/filter.c pine4.63.I.USE/pine/filter.c
+*** pine4.63/pine/filter.c Thu Apr 7 11:00:56 2005
+--- pine4.63.I.USE/pine/filter.c Thu May 19 19:57:30 2005
+***************
+*** 204,209 ****
+--- 204,213 ----
+ error_description(errno)));
+ if(source == TmpFileStar)
+ (void)unlink(so->name);
++ if (ps_global->send_immediately){
++ printf("%s : %s\n", so->name, error_description(errno));
++ exit(1);
++ }
+
+ fs_give((void **)&so->name);
+ fs_give((void **)&so); /* so freed & set to NULL */
+***************
+*** 6764,6769 ****
+--- 6768,6778 ----
+ margin_r,
+ indent;
+ char special[256];
++ long curlinenum; /* current line number */
++ int curqstrpos; /* current position in quote string */
++ long linenum; /* line number */
++ long qstrlen; /* multiples of 100 */
++ char **qstrln; /* qstrln[i] = quote string line i - 1 */
+ } WRAP_S;
+
+ #define WRAP_MARG_L(F) (((WRAP_S *)(F)->opt)->margin_l)
+***************
+*** 6798,6803 ****
+--- 6807,6818 ----
+ #define WRAP_COLOR(F) (((WRAP_S *)(F)->opt)->color)
+ #define WRAP_COLOR_SET(F) ((WRAP_COLOR(F)) && (WRAP_COLOR(F)->fg[0]))
+ #define WRAP_SPACES(F) (((WRAP_S *)(F)->opt)->spaces)
++ #define WRAP_CURLINE(F) (((WRAP_S *)(F)->opt)->curlinenum)
++ #define WRAP_CURPOS(F) (((WRAP_S *)(F)->opt)->curqstrpos)
++ #define WRAP_LINENUM(F) (((WRAP_S *)(F)->opt)->linenum)
++ #define WRAP_QSTRLEN(F) (((WRAP_S *)(F)->opt)->qstrlen)
++ #define WRAP_QSTRN(F) (((WRAP_S *)(F)->opt)->qstrln)
++ #define WRAP_QSTR(F, N) (((WRAP_S *)(F)->opt)->qstrln[(N)])
+ #define WRAP_PUTC(F,C,V) { \
+ if((F)->linep == WRAP_LASTC(F)){ \
+ size_t offset = (F)->linep - (F)->line; \
+***************
+*** 6872,6877 ****
+--- 6887,6894 ----
+ case CCR : /* CRLF or CR in text ? */
+ state = BOL; /* either way, handle start */
+
++ WRAP_CURLINE(f)++;
++ WRAP_CURPOS(f) = 0;
+ if(WRAP_FLOW(f)){
+ if(f->f2 == 0 && WRAP_SPC_LEN(f)){ /* wrapped line */
+ /*
+***************
+*** 6963,6969 ****
+
+ case BOL :
+ if(WRAP_FLOW(f)){
+! if(c == '>'){
+ WRAP_FL_QC(f) = 1; /* init it */
+ state = FL_QLEV; /* go collect it */
+ }
+--- 6980,6989 ----
+
+ case BOL :
+ if(WRAP_FLOW(f)){
+! if(WRAP_QSTR(f, WRAP_CURLINE(f))
+! && WRAP_QSTR(f, WRAP_CURLINE(f))[WRAP_CURPOS(f)]
+! && WRAP_QSTR(f, WRAP_CURLINE(f))[WRAP_CURPOS(f)] == c){
+! WRAP_CURPOS(f)++;
+ WRAP_FL_QC(f) = 1; /* init it */
+ state = FL_QLEV; /* go collect it */
+ }
+***************
+*** 6977,6983 ****
+ }
+
+ /* quote level change implies new paragraph */
+! if(WRAP_FL_QD(f)){
+ WRAP_FL_QD(f) = 0;
+ if(WRAP_HARD(f) == 0){
+ WRAP_HARD(f) = 1;
+--- 6997,7012 ----
+ }
+
+ /* quote level change implies new paragraph */
+! if (WRAP_CURLINE(f) > 0
+! && WRAP_CURLINE(f) < WRAP_QSTRLEN(f)
+! && (WRAP_QSTR(f, WRAP_CURLINE(f)) != NULL
+! || WRAP_QSTR(f, WRAP_CURLINE(f) - 1) != NULL)
+! && ((WRAP_QSTR(f, WRAP_CURLINE(f)) != NULL &&
+! WRAP_QSTR(f, WRAP_CURLINE(f) - 1) == NULL)
+! || (WRAP_QSTR(f, WRAP_CURLINE(f)) == NULL &&
+! WRAP_QSTR(f, WRAP_CURLINE(f) - 1) != NULL)
+! || strcmp(WRAP_QSTR(f, WRAP_CURLINE(f)),
+! WRAP_QSTR(f, WRAP_CURLINE(f) - 1)))){
+ WRAP_FL_QD(f) = 0;
+ if(WRAP_HARD(f) == 0){
+ WRAP_HARD(f) = 1;
+***************
+*** 7029,7036 ****
+ break;
+
+ case FL_QLEV :
+! if(c == '>'){ /* another level */
+! WRAP_FL_QC(f)++;
+ }
+ else {
+ /* if EMBEDed, process it and return here */
+--- 7058,7068 ----
+ break;
+
+ case FL_QLEV :
+! if(WRAP_QSTR(f, WRAP_CURLINE(f))
+! && WRAP_QSTR(f, WRAP_CURLINE(f))[WRAP_CURPOS(f)]
+! && WRAP_QSTR(f, WRAP_CURLINE(f))[WRAP_CURPOS(f)] == c){
+! WRAP_CURPOS(f)++;
+! WRAP_FL_QC(f)++; /* another level */
+ }
+ else {
+ /* if EMBEDed, process it and return here */
+***************
+*** 7042,7048 ****
+ }
+
+ /* quote level change signals new paragraph */
+! if(WRAP_FL_QC(f) != WRAP_FL_QD(f)){
+ WRAP_FL_QD(f) = WRAP_FL_QC(f);
+ if(WRAP_HARD(f) == 0){ /* add hard newline */
+ WRAP_HARD(f) = 1; /* hard newline */
+--- 7074,7089 ----
+ }
+
+ /* quote level change signals new paragraph */
+! if (WRAP_CURLINE(f) > 0
+! && WRAP_CURLINE(f) < WRAP_QSTRLEN(f)
+! && (WRAP_QSTR(f, WRAP_CURLINE(f))
+! || WRAP_QSTR(f, WRAP_CURLINE(f) - 1))
+! && ((WRAP_QSTR(f, WRAP_CURLINE(f)) &&
+! !WRAP_QSTR(f, WRAP_CURLINE(f) - 1))
+! || (!WRAP_QSTR(f, WRAP_CURLINE(f)) &&
+! WRAP_QSTR(f, WRAP_CURLINE(f) - 1))
+! || strcmp(WRAP_QSTR(f, WRAP_CURLINE(f)),
+! WRAP_QSTR(f, WRAP_CURLINE(f) - 1)))){
+ WRAP_FL_QD(f) = WRAP_FL_QC(f);
+ if(WRAP_HARD(f) == 0){ /* add hard newline */
+ WRAP_HARD(f) = 1; /* hard newline */
+***************
+*** 7099,7104 ****
+--- 7140,7151 ----
+ state = FL_SIG;
+ break;
+
++ case ' ' : /* what? */
++ if (WRAP_QSTR(f, WRAP_CURLINE(f))){
++ WRAP_SPC_LEN(f)++;
++ so_writec(' ', WRAP_SPACES(f));
++ }
++
+ default : /* something else */
+ state = DFL;
+ goto case_dfl; /* handle c like DFL */
+***************
+*** 7115,7121 ****
+ &eob); /* note any embedded*/
+ wrap_eol(f, 1, &ip, &eib,
+ &op, &eob); /* plunk down newline */
+! wrap_bol(f, 1, 1, &ip, &eib,
+ &op, &eob); /* write any prefix */
+ }
+
+--- 7162,7168 ----
+ &eob); /* note any embedded*/
+ wrap_eol(f, 1, &ip, &eib,
+ &op, &eob); /* plunk down newline */
+! wrap_bol(f, 1, WRAP_FLOW(f), &ip, &eib,
+ &op, &eob); /* write any prefix */
+ }
+
+***************
+*** 7420,7426 ****
+ wrap_flush_embed(f, &ip, &eib, &op, &eob);
+ wrap_eol(f, 1, &ip, &eib, &op,
+ &eob); /* plunk down newline */
+! wrap_bol(f,1,1, &ip, &eib, &op,
+ &eob); /* write any prefix */
+ }
+
+--- 7467,7473 ----
+ wrap_flush_embed(f, &ip, &eib, &op, &eob);
+ wrap_eol(f, 1, &ip, &eib, &op,
+ &eob); /* plunk down newline */
+! wrap_bol(f,1,WRAP_FLOW(f), &ip, &eib, &op,
+ &eob); /* write any prefix */
+ }
+
+***************
+*** 7478,7483 ****
+--- 7525,7537 ----
+ if(WRAP_COLOR(f))
+ free_color_pair(&WRAP_COLOR(f));
+
++ { long i;
++ for (i = 0L; i < WRAP_QSTRLEN(f); i++)
++ if (WRAP_QSTR(f,i))
++ fs_give((void **) &(WRAP_QSTR(f,i)));
++ fs_give((void **)&WRAP_QSTRN(f));
++ }
++
+ fs_give((void **) &f->line); /* free temp line buffer */
+ so_give(&WRAP_SPACES(f));
+ fs_give((void **) &f->opt); /* free wrap widths struct */
+***************
+*** 7799,7805 ****
+ {
+ int j, i;
+ COLOR_PAIR *col = NULL;
+! char *prefix = NULL, *last_prefix = NULL;
+
+ if(ps_global->VAR_QUOTE_REPLACE_STRING){
+ get_pair(ps_global->VAR_QUOTE_REPLACE_STRING, &prefix, &last_prefix, 0, 0);
+--- 7853,7860 ----
+ {
+ int j, i;
+ COLOR_PAIR *col = NULL;
+! char *prefix = NULL, *last_prefix = NULL, *wrap_qstr = NULL;
+! int level = 0, oldj, len;
+
+ if(ps_global->VAR_QUOTE_REPLACE_STRING){
+ get_pair(ps_global->VAR_QUOTE_REPLACE_STRING, &prefix, &last_prefix, 0, 0);
+***************
+*** 7808,7817 ****
+ last_prefix = NULL;
+ }
+ }
+!
+! for(j = 0; j < WRAP_FL_QD(f); j++){
+ if(WRAP_USE_CLR(f)){
+! if((j % 3) == 0
+ && ps_global->VAR_QUOTE1_FORE_COLOR
+ && ps_global->VAR_QUOTE1_BACK_COLOR
+ && (col = new_color_pair(ps_global->VAR_QUOTE1_FORE_COLOR,
+--- 7863,7884 ----
+ last_prefix = NULL;
+ }
+ }
+!
+! if(WRAP_QSTR(f, WRAP_CURLINE(f)))
+! wrap_qstr = cpystr(WRAP_QSTR(f, WRAP_CURLINE(f)));
+! len = wrap_qstr ? strlen(wrap_qstr) : 0;
+!
+! for (j = wrap_qstr && *wrap_qstr == ' ' ? 1 : 0;
+! j < len && isspace((unsigned char)wrap_qstr[j]); j++){
+! GF_PUTC_GLO(f->next, wrap_qstr[j]);
+! f->n += ((wrap_qstr[j] == TAB) ? (~f->n & 0x07) + 1 : 1);
+! }
+!
+! for(; j < len && level < len; level++){
+! oldj = j;
+! j = next_level_quote(wrap_qstr, (char **)NULL, j, WRAP_FLOW(f));
+ if(WRAP_USE_CLR(f)){
+! if((level % 3) == 0
+ && ps_global->VAR_QUOTE1_FORE_COLOR
+ && ps_global->VAR_QUOTE1_BACK_COLOR
+ && (col = new_color_pair(ps_global->VAR_QUOTE1_FORE_COLOR,
+***************
+*** 7819,7825 ****
+ && pico_is_good_colorpair(col)){
+ GF_COLOR_PUTC(f, col);
+ }
+! else if((j % 3) == 1
+ && ps_global->VAR_QUOTE2_FORE_COLOR
+ && ps_global->VAR_QUOTE2_BACK_COLOR
+ && (col = new_color_pair(ps_global->VAR_QUOTE2_FORE_COLOR,
+--- 7886,7892 ----
+ && pico_is_good_colorpair(col)){
+ GF_COLOR_PUTC(f, col);
+ }
+! else if((level % 3) == 1
+ && ps_global->VAR_QUOTE2_FORE_COLOR
+ && ps_global->VAR_QUOTE2_BACK_COLOR
+ && (col = new_color_pair(ps_global->VAR_QUOTE2_FORE_COLOR,
+***************
+*** 7827,7833 ****
+ && pico_is_good_colorpair(col)){
+ GF_COLOR_PUTC(f, col);
+ }
+! else if((j % 3) == 2
+ && ps_global->VAR_QUOTE3_FORE_COLOR
+ && ps_global->VAR_QUOTE3_BACK_COLOR
+ && (col = new_color_pair(ps_global->VAR_QUOTE3_FORE_COLOR,
+--- 7894,7900 ----
+ && pico_is_good_colorpair(col)){
+ GF_COLOR_PUTC(f, col);
+ }
+! else if((level % 3) == 2
+ && ps_global->VAR_QUOTE3_FORE_COLOR
+ && ps_global->VAR_QUOTE3_BACK_COLOR
+ && (col = new_color_pair(ps_global->VAR_QUOTE3_FORE_COLOR,
+***************
+*** 7840,7884 ****
+ col = NULL;
+ }
+ }
+
+! if(!WRAP_LV_FLD(f)){
+! if(ps_global->VAR_QUOTE_REPLACE_STRING && prefix){
+! for(i = 0; prefix[i]; i++)
+! GF_PUTC_GLO(f->next, prefix[i]);
+! f->n += strlen(prefix);
+! }
+! else if(ps_global->VAR_REPLY_STRING
+! && (!strcmp(ps_global->VAR_REPLY_STRING, ">")
+! || !strcmp(ps_global->VAR_REPLY_STRING, "\">\""))){
+! GF_PUTC_GLO(f->next, '>');
+! f->n += 1;
+! }
+! else{
+! GF_PUTC_GLO(f->next, '>');
+! GF_PUTC_GLO(f->next, ' ');
+! f->n += 2;
+! }
+ }
+ else{
+! GF_PUTC_GLO(f->next, '>');
+! f->n += 1;
+ }
+ }
+ if(j && WRAP_LV_FLD(f)){
+ GF_PUTC_GLO(f->next, ' ');
+ f->n++;
+ }
+! else if(j && last_prefix){
+ for(i = 0; last_prefix[i]; i++)
+ GF_PUTC_GLO(f->next, last_prefix[i]);
+! f->n += strlen(last_prefix);
+ }
+
+ if(prefix)
+ fs_give((void **)&prefix);
+ if(last_prefix)
+ fs_give((void **)&last_prefix);
+!
+ return 0;
+ }
+
+--- 7907,7960 ----
+ col = NULL;
+ }
+ }
++ if (j > 1 && wrap_qstr[j-1] == ' ')
++ j -= 1;
+
+! if(!WRAP_LV_FLD(f) && ps_global->VAR_QUOTE_REPLACE_STRING && prefix){
+! for(i = 0; prefix[i]; i++)
+! GF_PUTC_GLO(f->next, prefix[i]);
+! f->n += strlenis(prefix);
+ }
+ else{
+! for (i = oldj; i < j; i++)
+! GF_PUTC_GLO(f->next, wrap_qstr[i]);
+! f->n += j - oldj;
+! }
+! for (i = j; isspace((unsigned char)wrap_qstr[i]); i++);
+! if(!wrap_qstr[i]){
+! f->n += i - j;
+! for (; j < i; j++)
+! GF_PUTC_GLO(f->next, ' ');
+ }
++ else{
++ if((WRAP_LV_FLD(f)
++ || !ps_global->VAR_QUOTE_REPLACE_STRING || !prefix)
++ || !ps_global->VAR_REPLY_STRING
++ || (strcmp(ps_global->VAR_REPLY_STRING, ">")
++ && strcmp(ps_global->VAR_REPLY_STRING, "\">\""))){
++ GF_PUTC_GLO(f->next, ' ');
++ f->n += 1;
++ }
++ }
++ for (; isspace((unsigned char)wrap_qstr[j]); j++);
+ }
+ if(j && WRAP_LV_FLD(f)){
+ GF_PUTC_GLO(f->next, ' ');
+ f->n++;
+ }
+! else if(j && !value_is_space(wrap_qstr) && last_prefix){
+ for(i = 0; last_prefix[i]; i++)
+ GF_PUTC_GLO(f->next, last_prefix[i]);
+! f->n += strlenis(last_prefix);
+ }
+
+ if(prefix)
+ fs_give((void **)&prefix);
+ if(last_prefix)
+ fs_give((void **)&last_prefix);
+! if (wrap_qstr)
+! fs_give((void **)&wrap_qstr);
+!
+ return 0;
+ }
+
+***************
+*** 7909,7914 ****
+--- 7985,7996 ----
+ wrap->leave_flowed = (GFW_FLOW_RESULT & flags) == GFW_FLOW_RESULT;
+ wrap->delsp = (GFW_DELSP & flags) == GFW_DELSP;
+ wrap->use_color = (GFW_USECOLOR & flags) == GFW_USECOLOR;
++ wrap->curlinenum = 0L;
++ wrap->curqstrpos = 0;
++ wrap->linenum = 0L;
++ wrap->qstrlen = 100L;
++ wrap->qstrln = (char **) fs_get(100*sizeof(char *));
++ memset(wrap->qstrln, 0, 100*sizeof(char *));
+
+ return((void *) wrap);
+ }
+***************
+*** 8330,8336 ****
+--- 8412,8595 ----
+ } \
+ }
+
++ #define ADD_QUOTE_STRING(F) { \
++ int len = tmp_20k_buf[0] ? strlen(tmp_20k_buf) + 1 : 0; \
++ FILTER_S *fltr; \
++ \
++ for(fltr = (F); fltr && fltr->f != gf_wrap; fltr = fltr->next);\
++ if (fltr){ \
++ if (WRAP_LINENUM(fltr) >= WRAP_QSTRLEN(fltr)){ \
++ fs_resize((void **)&WRAP_QSTRN(fltr), \
++ (WRAP_QSTRLEN(fltr) + 100) * sizeof(char *)); \
++ memset(WRAP_QSTRN(fltr)+WRAP_QSTRLEN(fltr), 0, \
++ 100*sizeof(char*)); \
++ WRAP_QSTRLEN(fltr) += 100L; \
++ } \
++ if (len){ \
++ WRAP_QSTR(fltr, WRAP_LINENUM(fltr)) = \
++ (char *) fs_get(len*sizeof(char)); \
++ WRAP_QSTR(fltr, WRAP_LINENUM(fltr)) = cpystr(tmp_20k_buf);\
++ } \
++ WRAP_LINENUM(fltr)++; \
++ } \
++ }
++
++ #define GF_ADD_QUOTED_LINE(F, line) \
++ { \
++ LT_INS_S *ins = NULL, *insp; \
++ int done;\
++ unsigned char ch;\
++ register char *cp;\
++ register int l;\
++ \
++ if (line){\
++ done = (*((LINETEST_S *) (F)->opt)->f)((F)->n++,\
++ line, &ins,\
++ ((LINETEST_S *) (F)->opt)->local);\
++ if (done < 2){ \
++ ADD_QUOTE_STRING((F));\
++ for(insp = ins, cp = line; *cp ; ){\
++ while(insp && cp == insp->where){\
++ for(l = 0; l < insp->len; l++){\
++ ch = (unsigned char) insp->text[l];\
++ GF_PUTC((F)->next, ch);\
++ }\
++ insp = insp->next;\
++ }\
++ GF_PUTC((F)->next, *cp);\
++ cp++;\
++ }\
++ while(insp){\
++ for(l = 0; l < insp->len; l++){\
++ ch = (unsigned char) insp->text[l];\
++ GF_PUTC((F)->next, ch);\
++ }\
++ insp = insp->next;\
++ }\
++ gf_line_test_free_ins(&ins);\
++ GF_PUTC((F)->next, '\015');\
++ GF_PUTC((F)->next, '\012');\
++ }\
++ }\
++ }
++ /* test second line of old line first */
++ #define SECOND_LINE_QUOTE_TEST(line, F) \
++ {\
++ *p = '\0';\
++ for (i = 0; ((F)->oldline)[i] && ((F)->oldline)[i] != '\015'; i++);\
++ if (((F)->oldline)[i]){\
++ i += (((F)->oldline)[i+1] == '\012') ? 2 : 1;\
++ line = (F)->oldline + i;\
++ }\
++ for (i = 0; ((F)->line) \
++ && (i < LINE_TEST_BLOCK) \
++ && (i < SIZEOF_20KBUF)\
++ && ((F)->line)[i] \
++ && (((F)->line)[i] != '\015')\
++ && (((F)->line)[i] != '\012')\
++ && (tmp_20k_buf[i] = ((F)->line)[i]); i++);\
++ tmp_20k_buf[i] = '\0';\
++ GF_ADD_QUOTED_LINE((F), line);\
++ }
++
++ #define FIRST_LINE_QUOTE_TEST(line, F)\
++ {\
++ *p = '\0';\
++ line = (F)->line;\
++ (F)->oldline = cpystr(line);\
++ for (i = 0; line[i] && line[i] != '\015' && line[i] != '\012'; i++); \
++ if (line[i]){\
++ (line[i]) = '\0'; \
++ i+= (line[i+1] == '\012') ? 2 : 1;\
++ }\
++ for (j = 0; ((F)->line) \
++ && ((i + j) < LINE_TEST_BLOCK) \
++ && (j < SIZEOF_20KBUF) \
++ && ((F)->line)[i + j] \
++ && (((F)->line)[i + j] != '\015')\
++ && (((F)->line)[i + j] != '\012')\
++ && (tmp_20k_buf[j] = ((F)->line)[i + j]); j++);\
++ tmp_20k_buf[j] = '\0';\
++ GF_ADD_QUOTED_LINE((F), line);\
++ }
++
++
++ void
++ gf_quote_test(f, flg)
++ FILTER_S *f;
++ int flg;
++ {
++ register char *p = f->linep;
++ register char *eobuf = GF_LINE_TEST_EOB(f);
++ char *line = NULL;
++ int i, j;
++ GF_INIT(f, f->next);
++
++ if(flg == GF_DATA){
++ register unsigned char c;
++ register int state = f->f1;
++
++ while(GF_GETC(f, c)){
++
++ if(state == 2){ /* two full lines read */
++ state = 0;
++
++ /* first process the second line of an old line */
++ if (f->oldline && f->oldline[0])
++ SECOND_LINE_QUOTE_TEST(line, f);
++
++ /* now we process the first line */
++ FIRST_LINE_QUOTE_TEST(line, f);
+
++ p = f->line;
++ continue;
++ }
++ if(c == '\015'){
++ state++;
++ if (state == 1)
++ GF_LINE_TEST_ADD(f, c);
++ }
++ else
++ GF_LINE_TEST_ADD(f, c);
++ }
++
++ f->f1 = state;
++ GF_END(f, f->next);
++ }
++ else if(flg == GF_EOD){
++ /* first process the second line of an old line */
++ if (f->oldline && f->oldline[0])
++ SECOND_LINE_QUOTE_TEST(line, f);
++
++ /* now we process the first line */
++ FIRST_LINE_QUOTE_TEST(line, f);
++
++ /* We are out of data. In this case we have processed the second
++ * line of an oldline, then the first line of a line, but we need
++ * to process the second line of the given line. We do this by
++ * processing it now!.
++ */
++ if (line[i]){
++ tmp_20k_buf[0] = '\0'; /* No next line */
++ GF_ADD_QUOTED_LINE(f, line+i);
++ }
++
++ fs_give((void **) &f->oldline); /* free old line buffer */
++ fs_give((void **) &f->line); /* free line buffer */
++ fs_give((void **) &f->opt); /* free test struct */
++ GF_FLUSH(f->next);
++ (*f->next->f)(f->next, GF_EOD);
++ }
++ else if(flg == GF_RESET){
++ dprint(9, (debugfile, "-- gf_reset line_test\n"));
++ f->f1 = 0; /* state */
++ f->n = 0L; /* line number */
++ f->f2 = LINE_TEST_BLOCK; /* size of alloc'd line */
++ f->line = p = (char *) fs_get(f->f2 * sizeof(char));
++ }
++
++ f->linep = p;
++ }
+
+ /*
+ * this simple filter accumulates characters until a newline, offers it
+***************
+*** 8355,8361 ****
+ if(state){
+ state = 0;
+ if(c == '\012'){
+! int done;
+
+ GF_LINE_TEST_TEST(f, done);
+
+--- 8614,8625 ----
+ if(state){
+ state = 0;
+ if(c == '\012'){
+! int done, i, j = 0;
+!
+! for (i = 0; op && op[i] && (i < LINE_TEST_BLOCK) &&
+! (i < SIZEOF_20KBUF) && (op[i] != '\015') &&
+! (tmp_20k_buf[i] = op[i]); i++);
+! tmp_20k_buf[i] = '\0';
+
+ GF_LINE_TEST_TEST(f, done);
+
+***************
+*** 8417,8422 ****
+--- 8681,8687 ----
+ else if(flg == GF_EOD){
+ int i;
+
++ tmp_20k_buf[0] = '\0';
+ GF_LINE_TEST_TEST(f, i); /* examine remaining data */
+ fs_give((void **) &f->line); /* free line buffer */
+ fs_give((void **) &f->opt); /* free test struct */
+diff -rc pine4.63/pine/folder.c pine4.63.I.USE/pine/folder.c
+*** pine4.63/pine/folder.c Mon Apr 4 11:42:52 2005
+--- pine4.63.I.USE/pine/folder.c Thu May 19 19:57:31 2005
+***************
+*** 94,100 ****
+ #define FLW_SLCT 0x02
+ #define FLW_LIST 0x04
+
+!
+
+
+ /*----------------------------------------------------------------------
+--- 94,100 ----
+ #define FLW_SLCT 0x02
+ #define FLW_LIST 0x04
+
+! static int max_slot_size = 0;
+
+
+ /*----------------------------------------------------------------------
+***************
+*** 224,229 ****
+--- 224,230 ----
+ gf_io_t, HANDLE_S **, int));
+ int folder_list_write_folder PROTO((gf_io_t, CONTEXT_S *,
+ int, char *, int));
++ int folder_list_write_count PROTO((FOLDER_S *, CONTEXT_S *, gf_io_t, int));
+ int folder_list_write_prefix PROTO((FOLDER_S *, int, gf_io_t));
+ int folder_list_ith PROTO((int, CONTEXT_S *));
+ char *folder_list_center_space PROTO((char *, int));
+***************
+*** 469,475 ****
+
+ HELP_MENU,
+ OTHER_MENU,
+! NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+--- 470,476 ----
+
+ HELP_MENU,
+ OTHER_MENU,
+! {"^H","ChkIncFld",{MC_FORCECHECK,1,ctrl('H')}, KS_NONE},
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+***************
+*** 1708,1713 ****
+--- 1709,1715 ----
+ gf_io_t pc;
+
+ dprint(1, (debugfile, "\n\n ---- FOLDER LISTER ----\n"));
++ ps->in_fld_list = 1;
+
+ memset(&folder_proc_data, 0, sizeof(FPROC_S));
+ folder_proc_data.fs = fs;
+***************
+*** 1842,1847 ****
+--- 1844,1850 ----
+ *fs->cache_streamp = NULL;
+ }
+
++ ps->in_fld_list = 0;
+ return(folder_proc_data.rv);
+ }
+
+***************
+*** 1955,1960 ****
+--- 1958,1975 ----
+ gf_puts("\n", pc);
+ }
+
++ if (c_list->use & CNTXT_INCMNG &&
++ F_ON(F_ENABLE_INCOMING_CHECK,ps_global) &&
++ F_ON(F_ENABLE_INCOMING,ps_global) &&
++ F_OFF(F_ENABLE_FAST_RECENT, ps_global)){
++ sprintf(tmp_20k_buf,
++ "Format: Folder-name [Total New Messages/Total Messages]");
++ gf_puts(folder_list_center_space(tmp_20k_buf, cols), pc);
++ gf_puts(tmp_20k_buf, pc);
++ gf_puts("\n", pc);
++ }
++
++
+ gf_puts(repeat_char(cols, '-'), pc);
+ gf_puts("\n\n", pc);
+ }
+***************
+*** 1992,1999 ****
+--- 2007,2027 ----
+ else if(c_list == fp->fs->list_cntxt)
+ len += 4; /* "[X] " */
+
++ if (c_list->use & CNTXT_INCMNG &&
++ F_ON(F_ENABLE_INCOMING_CHECK,ps_global) &&
++ F_ON(F_ENABLE_INCOMING,ps_global) &&
++ F_OFF(F_ENABLE_FAST_RECENT, ps_global))
++ if (need_folder_report(FLDR_NAME(f))){
++ len += 5; /* "[/]" + " " */
++ len += strlen(comatose(f->countrecent));
++ len += strlen(comatose(f->messages));
++ }
++ else
++ len += 1;
++
+ if(slot_size < len)
+ slot_size = len;
++ max_slot_size = slot_size;
+ }
+
+ if(F_ON(F_SINGLE_FOLDER_LIST, ps_global)){
+***************
+*** 2098,2104 ****
+ int flags;
+ {
+ char buf[256];
+! int l = 0;
+ FOLDER_S *fp;
+ HANDLE_S *h;
+
+--- 2126,2132 ----
+ int flags;
+ {
+ char buf[256];
+! int l = 0, s = 0;
+ FOLDER_S *fp;
+ HANDLE_S *h;
+
+***************
+*** 2121,2126 ****
+--- 2149,2155 ----
+ && (*pc)(strlen(buf)) && gf_puts(buf, pc)) : 1)
+ && (fp ? ((l = folder_list_write_prefix(fp, flags, pc)) >= 0
+ && gf_puts(FLDR_NAME(fp), pc)
++ && (s = folder_list_write_count(fp, ctxt, pc, l)) >= 0
+ && ((fp->isdir && fp->isfolder) ? (*pc)('[') : 1)
+ && ((fp->isdir) ? (*pc)(ctxt->dir->delim) : 1)
+ && ((fp->isdir && fp->isfolder) ? (*pc)(']') : 1))
+***************
+*** 2128,2134 ****
+ && (h ? ((*pc)(TAG_EMBED) && (*pc)(TAG_BOLDOFF)
+ && (*pc)(TAG_EMBED) && (*pc)(TAG_INVOFF)) : 1)){
+ if(fp){
+! l += strlen(FLDR_NAME(fp));
+ if(fp->isdir)
+ l += (fp->isfolder) ? 3 : 1;
+ }
+--- 2157,2163 ----
+ && (h ? ((*pc)(TAG_EMBED) && (*pc)(TAG_BOLDOFF)
+ && (*pc)(TAG_EMBED) && (*pc)(TAG_INVOFF)) : 1)){
+ if(fp){
+! l += strlen(FLDR_NAME(fp)) + s;
+ if(fp->isdir)
+ l += (fp->isfolder) ? 3 : 1;
+ }
+***************
+*** 2139,2144 ****
+--- 2168,2203 ----
+ return(l);
+ }
+
++ int
++ folder_list_write_count(f, ctxt, pc, l)
++ FOLDER_S *f;
++ CONTEXT_S *ctxt;
++ gf_io_t pc;
++ int l;
++ {
++ int rv = 0, i;
++ int offset = 1;
++
++ if (ctxt->use & CNTXT_INCMNG &&
++ F_ON(F_ENABLE_INCOMING_CHECK,ps_global) &&
++ F_ON(F_ENABLE_INCOMING,ps_global) &&
++ F_OFF(F_ENABLE_FAST_RECENT, ps_global) &&
++ need_folder_report(FLDR_NAME(f))){
++ rv = max_slot_size - strlen(FLDR_NAME(f)) - l;
++ rv -= strlen(comatose(f->countrecent));
++ rv -= strlen(comatose(f->messages));
++ rv -= 5 + offset;
++ for (i = 0; i <= rv; i++) gf_puts(" ", pc);
++ gf_puts("[", pc);
++ gf_puts(comatose(f->countrecent), pc);
++ gf_puts("/", pc);
++ gf_puts(comatose(f->messages), pc);
++ gf_puts("]", pc);
++ rv = max_slot_size - strlen(FLDR_NAME(f)) - l - offset -1;
++ }
++ return rv;
++ }
++
+
+ int
+ folder_list_write_prefix(f, flags, pc)
+***************
+*** 2224,2229 ****
+--- 2283,2301 ----
+ p = strchr(p, fs->context->dir->delim))
+ name = ++p;
+
++ if(fs->context->use & CNTXT_INCMNG){
++ FOLDER_S *f;
++ int total = folder_total(FOLDERS(fs->context)), index;
++ for(index = folder_index(ps_global->inbox_name, fs->context, FI_FOLDER);
++ index >= 0 && index < total
++ && (f = folder_entry(index, FOLDERS(fs->context)))
++ && !f->isdir; index++)
++ if(!strcmp(fs->first_folder, f->name)){
++ name = FLDR_NAME(f);
++ break;
++ }
++ }
++
+ for(h = handles; h; h = h->next)
+ if(h->h.f.context == fs->context){
+ if(!h_found) /* match at least given context */
+***************
+*** 2462,2468 ****
+ "Empty folder collection. No folder to rename!");
+
+ break;
+!
+
+ /*-------------- Delete --------------------*/
+ case MC_DELETE :
+--- 2534,2549 ----
+ "Empty folder collection. No folder to rename!");
+
+ break;
+!
+!
+! /*------- Check incoming forlders -------*/
+! case MC_FORCECHECK:
+! ps_global->force_check_now = 1;
+! rv = (new_mail_incfolder(ps_global,MC_FORCECHECK) &&
+! ps_global->refresh_list > 0) ? 1 : 0;
+! ps_global->refresh_list = 0;
+! break;
+!
+
+ /*-------------- Delete --------------------*/
+ case MC_DELETE :
+***************
+*** 2783,2792 ****
+ if(we_cancel)
+ cancel_busy_alarm(-1);
+
+! if(gotit)
+ sprintf(tmp_output,
+ "%lu total message%.2s, %lu of them recent",
+ tot, plural(tot), rec);
+ }
+ }else
+ strncpy(tmp_output, "No folder to check! Can't get recent info",
+--- 2864,2880 ----
+ if(we_cancel)
+ cancel_busy_alarm(-1);
+
+! if(gotit){
+ sprintf(tmp_output,
+ "%lu total message%.2s, %lu of them recent",
+ tot, plural(tot), rec);
++ folder->countrecent = rec;
++ folder->messages = tot;
++ if (rec > 0L)
++ folder->notified = 1;
++ folder->selected = rec > 0L ? 1 : folder->user_selected;
++ ps_global->refresh_list++;
++ }
+ }
+ }else
+ strncpy(tmp_output, "No folder to check! Can't get recent info",
+***************
+*** 3323,3330 ****
+ case 'f' : /* flip selection */
+ n = folder_total(FOLDERS(context));
+ for(total = i = 0; i < n; i++)
+! if(f = folder_entry(i, FOLDERS(context)))
+ f->selected = !f->selected;
+
+ return(1); /* repaint */
+
+--- 3411,3420 ----
+ case 'f' : /* flip selection */
+ n = folder_total(FOLDERS(context));
+ for(total = i = 0; i < n; i++)
+! if(f = folder_entry(i, FOLDERS(context))){
+ f->selected = !f->selected;
++ f->user_selected = f->selected;
++ }
+
+ return(1); /* repaint */
+
+***************
+*** 3467,3481 ****
+ CONTEXT_S *context;
+ {
+ int i, n, total;
+
+ n = folder_total(FOLDERS(context));
+! for(total = i = 0; i < n; i++)
+! if(folder_entry(i, FOLDERS(context))->selected)
+ total++;
+
+ return(total);
+ }
+
+
+ SELECTED_S *
+ new_selected()
+--- 3557,3620 ----
+ CONTEXT_S *context;
+ {
+ int i, n, total;
++ FOLDER_S *f;
+
+ n = folder_total(FOLDERS(context));
+! for(total = i = 0; i < n; i++){
+! f = folder_entry(i, FOLDERS(context));
+! if(f->selected)
+ total++;
++ }
+
+ return(total);
+ }
+
++ void
++ update_incoming_folder_data(stream, context)
++ MAILSTREAM *stream;
++ CONTEXT_S *context;
++ {
++ FOLDER_S *f = incoming_folder_data(stream, context);
++
++ if(f){
++ f->origrecent = f->recent = stream->recent;
++ f->messages = stream->nmsgs;
++ }
++ }
++
++
++ FOLDER_S *
++ incoming_folder_data(stream, cntxt)
++ MAILSTREAM *stream;
++ CONTEXT_S *cntxt;
++ {
++ long index, total, done = 0;
++ FOLDER_S *f = NULL;
++
++ if (cntxt && cntxt->use & CNTXT_INCMNG){
++ total = folder_total(FOLDERS(cntxt));
++ for (index = 0L; index < total ; index++){
++ f = folder_entry(index, FOLDERS(cntxt));
++ if (!strcmp(STREAMNAME(stream), FLDR_NAME(f))){
++ done++;
++ break;
++ }
++ }
++ }
++ if (!done)
++ f = NULL;
++ return f;
++ }
++
++ int
++ need_folder_report(folder)
++ char *folder;
++ {
++ return (ps_global->VAR_INCOMING_FOLDERS_CHECK &&
++ ((ps_global->VAR_INCOMING_FOLDERS_CHECK[0] == '*') ||
++ strstr(ps_global->VAR_INCOMING_FOLDERS_CHECK, folder)));
++ }
++
+
+ SELECTED_S *
+ new_selected()
+***************
+*** 4204,4209 ****
+--- 4343,4349 ----
+
+ if(f = folder_entry(index, FOLDERS(context))){
+ f->selected = !f->selected;
++ f->user_selected = f->selected;
+ return((*func)(context, index));
+ }
+ return 1;
+***************
+*** 7223,7228 ****
+--- 7363,7371 ----
+ FOLDERS(context) = init_folder_entries();
+ init_incoming_folder_list(ps_global, context);
+ init_inbox_mapping(ps_global->VAR_INBOX_PATH, context);
++ ps_global->force_check_now = 1; /* sorry about this */
++ new_mail_incfolder(ps_global,MC_FORCECHECK);
++ ps_global->refresh_list += 1;
+ }
+
+
+***************
+*** 8406,8416 ****
+ long *find_recent;
+ int *did_cancel;
+ {
+! int index, recent = 0, failed_status = 0, try_fast;
+ char prompt[128];
+ FOLDER_S *f = NULL;
+ char tmp[MAILTMPLEN];
+!
+
+ /* note: find_folders may assign "stream" */
+ build_folder_list(streamp, cntxt, NULL, NULL,
+--- 8549,8565 ----
+ long *find_recent;
+ int *did_cancel;
+ {
+! int index, recent = 0, failed_status = 0, try_fast, done = 0;
+ char prompt[128];
+ FOLDER_S *f = NULL;
+ char tmp[MAILTMPLEN];
+! char *test_current = cpystr(current);
+! int cur_indx = folder_index(ps_global->cur_folder, cntxt, FI_FOLDER);
+! int loop = !strcmp(next, ps_global->cur_folder) ? 0 :
+! (folder_index(test_current, cntxt, FI_FOLDER) <= cur_indx
+! ? 1 : 0);
+! int last = !strcmp(ps_global->cur_folder, ps_global->inbox_name)
+! ? 1 : cur_indx;
+
+ /* note: find_folders may assign "stream" */
+ build_folder_list(streamp, cntxt, NULL, NULL,
+***************
+*** 8421,8427 ****
+ if(find_recent)
+ *find_recent = 0L;
+
+! for(index = folder_index(current, cntxt, FI_FOLDER) + 1;
+ index > 0
+ && index < folder_total(FOLDERS(cntxt))
+ && (f = folder_entry(index, FOLDERS(cntxt)))
+--- 8570,8578 ----
+ if(find_recent)
+ *find_recent = 0L;
+
+!
+! find_new_message:
+! for(index = folder_index(test_current, cntxt, FI_FOLDER) + 1;
+ index > 0
+ && index < folder_total(FOLDERS(cntxt))
+ && (f = folder_entry(index, FOLDERS(cntxt)))
+***************
+*** 8432,8437 ****
+--- 8583,8593 ----
+ int rv, we_cancel = 0, mlen, match;
+ char msg_buf[MAX_BM+1], mbuf[MAX_BM+1];
+
++ if (loop && (index == last)){
++ done++;
++ break;
++ }
++
+ /* must be a folder and it can't be the current one */
+ if(ps_global->context_current == ps_global->context_list
+ && !strcmp(ps_global->cur_folder, FLDR_NAME(f)))
+***************
+*** 8583,8601 ****
+ }
+ }
+
+! if(f && (!find_recent || recent))
+ strcpy(next, FLDR_NAME(f));
+ else
+ *next = '\0';
+
+ /* BUG: how can this be made smarter so we cache the list? */
+ free_folder_list(cntxt);
+ return((*next) ? next : NULL);
+ }
+
+
+
+ /*
+ * folder_is_nick - check to see if the given name is a nickname
+ * for some folder in the given context...
+ *
+--- 8739,8906 ----
+ }
+ }
+
+! if(f && (!find_recent || recent)){
+ strcpy(next, FLDR_NAME(f));
++ done++;
++ }
+ else
+ *next = '\0';
+
++ if (!done && F_ON(F_AUTO_CIRCULAR_TAB,ps_global)
++ && strcmp(test_current,ps_global->inbox_name)){
++ done++; loop++;
++ if (test_current)
++ fs_give((void **)&test_current);
++ test_current = cpystr(ps_global->inbox_name);
++ goto find_new_message;
++ }
++
+ /* BUG: how can this be made smarter so we cache the list? */
+ free_folder_list(cntxt);
++ if (test_current)
++ fs_give((void **)&test_current);
+ return((*next) ? next : NULL);
+ }
+
+
+
+ /*
++ * next_folder - given a current folder in a context, return the next in
++ * the list, or NULL if no more or there's a problem.
++ */
++ int
++ next_folder_check(streamp, cntxt, find_recent, find_messages, f, opstrm)
++ MAILSTREAM **streamp;
++ CONTEXT_S *cntxt;
++ long *find_recent, *find_messages;
++ FOLDER_S *f;
++ int *opstrm;
++ {
++ char *next;
++ int index, failed_status = 0;
++
++ /* note: find_folders may assign "stream" */
++ build_folder_list(streamp, cntxt, NULL, NULL, BFL_NONE);
++
++ if(find_recent && find_messages && opstrm){
++ MAILSTREAM *stream = NULL;
++ int rv, we_cancel = 0;
++ char msg_buf[MAX_SCREEN_COLS+1] = {'\0'};
++ char tmp[MAILTMPLEN];
++
++ *opstrm = 0; /* default value */
++ *find_recent = f->recent; /* default value. Return this if */
++ *find_messages = f->messages; /* not requested */
++
++ if((stream = sp_stream_get(context_apply(tmp, cntxt, f->name,sizeof(tmp)),
++ SP_MATCH)) != NULL){
++ *opstrm = 1;
++ (void) pine_mail_ping(stream);
++ next = new_mail_in_open_stream(stream, find_recent, find_messages);
++ free_folder_list(cntxt);
++ return next ? 1 : 0;
++ }
++ else if ((F_ON(F_ENABLE_FAST_RECENT, ps_global) &&
++ F_OFF(F_ENABLE_INCOMING_RECHECK,ps_global) &&
++ (f->notified || f->selected))
++ || (f->selected && f->user_selected)){
++
++ next = f->notified ? FLDR_NAME(f) : NULL;
++ free_folder_list(cntxt);
++ return next ? 1 : 0;
++ }
++ else if (need_folder_report(FLDR_NAME(f))
++ && (strcmp(ps_global->cur_folder, FLDR_NAME(f)) || !stream)){
++
++ we_cancel = busy_alarm(1, msg_buf, NULL, 1);
++
++ /* First, get a stream for the test */
++ if(streamp && *streamp){
++ if(context_same_stream(cntxt, f->name, *streamp))
++ stream = *streamp;
++ else{
++ mail_close(*streamp);
++ *streamp = NULL;
++ }
++ }
++
++ if(!stream)
++ stream = sp_stream_get(context_apply(tmp, cntxt, f->name,
++ sizeof(tmp)), SP_SAME);
++
++ if(!stream){
++ if(!(stream = sp_stream_status_get(
++ context_apply(tmp, cntxt, f->name,
++ sizeof(tmp))))){
++ stream = (*f->name == '{')
++ ? mail_open (NIL,f->name,OP_HALFOPEN) : NIL;
++ sp_add_status(stream);
++ }
++ }
++
++ if(F_OFF(F_ENABLE_FAST_RECENT, ps_global)
++ || !((rv = folder_exists(cntxt,f->name))
++ & (FEX_ISMARKED | FEX_UNMARKED))){
++ extern MAILSTATUS mm_status_result;
++
++ if((F_ON(F_ENABLE_FAST_RECENT, ps_global) &&
++ (rv == 0 || rv & FEX_ERROR))){
++ failed_status = 1;
++ mm_status_result.flags = 0L;
++ }
++ else{
++ if(stream){
++ if(!context_status_full(cntxt, stream,
++ f->name, SA_RECENT | SA_MESSAGES,
++ &f->uidvalidity,
++ &f->uidnext)){
++ failed_status = 1;
++ mm_status_result.flags = 0L;
++ }
++ }
++ else{
++ if(!context_status_streamp_full(cntxt, streamp, f->name,
++ SA_RECENT | SA_MESSAGES,
++ &f->uidvalidity,
++ &f->uidnext)){
++ failed_status = 1;
++ mm_status_result.flags = 0L;
++ }
++ }
++ }
++
++ if (!failed_status){
++ *find_messages = mm_status_result.messages;
++ *find_recent = mm_status_result.recent;
++ }
++ else{
++ *find_recent = *find_messages = 0;
++ }
++ rv = (((mm_status_result.flags & SA_RECENT) ||
++ (F_OFF(F_ENABLE_FAST_RECENT,ps_global)
++ && (mm_status_result.recent != f->recent)))
++ && (*find_recent = mm_status_result.recent))
++ ? FEX_ISMARKED : 0;
++ }
++
++ if(we_cancel)
++ cancel_busy_alarm(0);
++
++ failed_status = 0;
++
++ if(rv & FEX_ISMARKED){
++ next = f ? FLDR_NAME(f) : NULL;
++ free_folder_list(cntxt);
++ return next ? 1 : 0;
++ }
++ }
++ return 0;
++ }
++ }
++
++
++
++ /*
+ * folder_is_nick - check to see if the given name is a nickname
+ * for some folder in the given context...
+ *
+diff -rc pine4.63/pine/imap.c pine4.63.I.USE/pine/imap.c
+*** pine4.63/pine/imap.c Fri Jan 21 17:31:32 2005
+--- pine4.63.I.USE/pine/imap.c Thu May 19 19:57:33 2005
+***************
+*** 704,710 ****
+ q_line = -(ps_global->ttyo ? ps_global->ttyo->footer_rows : 3);
+
+ /* make sure errors are seen */
+! if(ps_global->ttyo)
+ flush_status_messages(0);
+
+ /*
+--- 704,710 ----
+ q_line = -(ps_global->ttyo ? ps_global->ttyo->footer_rows : 3);
+
+ /* make sure errors are seen */
+! if(ps_global->ttyo && !ps_global->checking_incfld)
+ flush_status_messages(0);
+
+ /*
+***************
+*** 1949,1959 ****
+--- 1949,1963 ----
+ #endif
+
+ if(elapsed >= (long)ps_global->tcp_query_timeout){
++ if(!ps_global->checking_incfld){
+ sprintf(pmt,
+ "Waited %s seconds for server reply. Break connection to server",
+ long2string(elapsed));
+ if(want_to(pmt, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y')
+ return(0L);
++ }
++ else
++ rv = 0L;
+ }
+
+ return(rv);
+***************
+*** 1995,2000 ****
+--- 1999,2005 ----
+ if(elapsed >= (long)ps_global->tcp_query_timeout){
+ int clear_inverse;
+
++ if(!ps_global->checking_incfld){
+ ClearLine(ps_global->ttyo->screen_rows - FOOTER_ROWS(ps_global));
+ if(clear_inverse = !InverseState())
+ StartInverse();
+***************
+*** 2015,2020 ****
+--- 2020,2028 ----
+ EndInverse();
+
+ ClearLine(ps_global->ttyo->screen_rows - FOOTER_ROWS(ps_global));
++ }
++ else
++ rv = 0L;
+ }
+
+ if(rv == 1L){ /* just warn 'em something's up */
+***************
+*** 2031,2036 ****
+--- 2039,2074 ----
+ return(rv);
+ }
+
++ QUOTALIST *pine_quotalist_copy (pquota)
++ QUOTALIST *pquota;
++ {
++ QUOTALIST *cquota = NULL;
++
++ if(pquota){
++ cquota = mail_newquotalist();
++ if (pquota->name && *pquota->name){
++ cquota->name = (char *) fs_get((strlen(pquota->name) + 1)*sizeof(char));
++ cquota->name = cpystr(pquota->name);
++ }
++ cquota->usage = pquota->usage;
++ cquota->limit = pquota->limit;
++ if (pquota->next)
++ cquota->next = pine_quotalist_copy(pquota->next);
++ }
++ return cquota;
++ }
++
++
++ /* C-client callback to handle quota */
++
++ void
++ pine_parse_quota (stream, msg, pquota)
++ MAILSTREAM *stream;
++ unsigned char *msg;
++ QUOTALIST *pquota;
++ {
++ ps_global->quota = pine_quotalist_copy (pquota);
++ }
+
+ /*
+ * C-client callback to handle SSL/TLS certificate validation failures
+diff -rc pine4.63/pine/init.c pine4.63.I.USE/pine/init.c
+*** pine4.63/pine/init.c Thu Apr 7 11:01:42 2005
+--- pine4.63.I.USE/pine/init.c Thu May 19 19:57:32 2005
+***************
+*** 71,76 ****
+--- 71,77 ----
+ typedef enum {Sapling, Seedling, Seasoned} FeatureLevel;
+
+ #define TO_BAIL_THRESHOLD 60
++ #define INCFLD_THRESHOLD 5
+
+ #define METASTR "\nremote-abook-metafile="
+ static char meta_prefix[] = ".ab";
+***************
+*** 158,163 ****
+--- 159,166 ----
+
+ CONF_TXT_T cf_text_incoming_folders[] = "List of incoming msg folders besides INBOX, e.g. ={host2}inbox, {host3}inbox\n# Syntax: optnl-label {optnl-imap-host-name}folder-path";
+
++ CONF_TXT_T cf_incoming_folders_check[] = "List of incoming folders to be checked for new mail";
++
+ CONF_TXT_T cf_text_folder_collections[] = "List of directories where saved-message folders may be. First one is\n# the default for Saves. Example: Main {host1}mail/[], Desktop mail\\[]\n# Syntax: optnl-label {optnl-imap-hostname}optnl-directory-path[]";
+
+ CONF_TXT_T cf_text_news_collections[] = "List, only needed if nntp-server not set, or news is on a different host\n# than used for NNTP posting. Examples: News *[] or News *{host3/nntp}[]\n# Syntax: optnl-label *{news-host/protocol}[]";
+***************
+*** 214,223 ****
+--- 217,256 ----
+
+ CONF_TXT_T cf_text_sort_key[] = "Sets presentation order of messages in Index. Choices:\n# Subject, From, Arrival, Date, Size, To, Cc, OrderedSubj, Score, and Thread.\n# Order may be reversed by appending /Reverse. Default: \"Arrival\".";
+
++ CONF_TXT_T cf_text_thread_sort_key[] = "#Sets presentation order of threads in thread index. Choices:\n#arrival, and thread.";
++
+ CONF_TXT_T cf_text_addrbook_sort_rule[] = "Sets presentation order of address book entries. Choices: dont-sort,\n# fullname-with-lists-last, fullname, nickname-with-lists-last, nickname\n# Default: \"fullname-with-lists-last\".";
+
+ CONF_TXT_T cf_text_folder_sort_rule[] = "Sets presentation order of folder list entries. Choices: alphabetical,\n# alpha-with-dirs-last, alpha-with-dirs-first.\n# Default: \"alpha-with-directories-last\".";
+
++ 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 supercede global index format variable in designated folders.";
++
++ 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_character_set[] = "Reflects capabilities of the display you have. Default: US-ASCII.\n# Typical alternatives include ISO-8859-x, (x is a number between 1 and 9).";
+
+ CONF_TXT_T cf_text_editor[] = "Specifies the program invoked by ^_ in the Composer,\n# or the \"enable-alternate-editor-implicitly\" feature.";
+***************
+*** 228,233 ****
+--- 261,268 ----
+
+ CONF_TXT_T cf_text_fillcol[] = "Specifies the column of the screen where the composer should wrap.";
+
++ CONF_TXT_T cf_special_text_color[] = "Specifies a comma separated list of text and regular expresions that Pine\n# will highlight";
++
+ CONF_TXT_T cf_text_replystr[] = "Specifies the string to insert when replying to a message.";
+
+ CONF_TXT_T cf_text_quotereplstr[] = "Specifies the string to replace quotes with when viewing a message.";
+***************
+*** 242,247 ****
+--- 277,284 ----
+
+ CONF_TXT_T cf_text_inc_startup[] = "Sets message which cursor begins on. Choices: first-unseen, first-recent,\n# first-important, first-important-or-unseen, first-important-or-recent,\n# first, last. Default: \"first-unseen\".";
+
++ CONF_TXT_T cf_text_inc_check[] = "Sets how and when checks for new mail should happen. Choices: automatic,\n# automatic-after-first-manual-check, manual-only, Default: automatic";
++
+ CONF_TXT_T cf_pruning_rule[] = "Allows a default answer for the prune folder questions. Choices: yes-ask,\n# yes-no, no-ask, no-no, ask-ask, ask-no. Default: \"ask-ask\".";
+
+ CONF_TXT_T cf_reopen_rule[] = "Controls behavior when reopening an already open folder.";
+***************
+*** 378,383 ****
+--- 415,422 ----
+
+ CONF_TXT_T cf_text_tcp_query_timeo[] = "If this much time has elapsed at the time of a tcp read or write\n# timeout, pine will ask if you want to break the connection.\n# Default is 60 seconds, minimum is 5, maximum is 1000.";
+
++ CONF_TXT_T cf_text_inc_fld_timeout[] = "If this much time has elapsed at the time of a tcp read or write\n# timeout while checking for new mail in an incoming folder, pine will break the connection.\n# Default is 5 seconds, minimum is 2, maximum is 60.";
++
+ CONF_TXT_T cf_text_rsh_open_timeo[] = "Sets the time in seconds that Pine will attempt to open a UNIX remote\n# shell connection. The default is 15, min is 5, and max is unlimited.\n# Zero disables rsh altogether.";
+
+ CONF_TXT_T cf_text_rsh_path[] = "Sets the name of the command used to open a UNIX remote shell connection.\n# The default is typically /usr/ucb/rsh.";
+***************
+*** 418,423 ****
+--- 457,465 ----
+
+ CONF_TXT_T cf_text_newsrc_path[] = "Full path and name of NEWSRC file";
+
++ CONF_TXT_T cf_text_maildir_location[] = "Location relative to your HOME directory of the directory where your INBOX\n# for the maildir format is located. Default value is \"Maildir\". If your\n# inbox is located at \"~/Maildir\" you do not need to change this value.\n# A common value is also \".maildir\"";
++
++
+ /* these are used to report folder directory creation problems */
+ CONF_TXT_T init_md_exists[] = "The \"%s\" subdirectory already exists, but it is not writable by Pine so Pine cannot run. Please correct the permissions and restart Pine.";
+
+***************
+*** 471,476 ****
+--- 513,520 ----
+ cf_text_nntp_server},
+ {"inbox-path", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
+ cf_text_inbox_path},
++ {"incoming-folders-to-check", 0, 1, 0, 1, 1, 0, 0, 0, 0, 0,
++ cf_incoming_folders_check},
+ {"incoming-archive-folders", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0,
+ cf_text_archived_folders},
+ {"pruned-folders", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
+***************
+*** 511,516 ****
+--- 555,562 ----
+ cf_text_fcc_name_rule},
+ {"sort-key", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
+ cf_text_sort_key},
++ {"thread-sort-key", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
++ cf_text_thread_sort_key},
+ {"addrbook-sort-rule", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
+ cf_text_addrbook_sort_rule},
+ {"folder-sort-rule", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
+***************
+*** 519,524 ****
+--- 565,572 ----
+ cf_text_goto_default},
+ {"incoming-startup-rule", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
+ cf_text_inc_startup},
++ {"incoming-check-rule", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
++ cf_text_inc_check},
+ {"pruning-rule", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
+ cf_pruning_rule},
+ {"folder-reopen-rule", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
+***************
+*** 533,538 ****
+--- 581,612 ----
+ cf_text_thread_exp_char},
+ {"threading-lastreply-character", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
+ cf_text_thread_lastreply_char},
++ {"threading-display-style-rule", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
++ cf_text_thread_displaystyle_rule},
++ {"threading-index-style-rule", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
++ cf_text_thread_indexstyle_rule},
++ {"compose-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
++ cf_text_compose_rules},
++ {"forward-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
++ cf_text_forward_rules},
++ {"index-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
++ cf_text_index_rules},
++ {"replace-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
++ cf_text_replace_rules},
++ {"reply-indent-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
++ cf_text_reply_indent_rules},
++ {"reply-leadin-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
++ cf_text_reply_leadin_rules},
++ {"reply-subject-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
++ cf_text_reply_subject_rules},
++ {"save-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
++ cf_text_save_rules},
++ {"smtp-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
++ cf_text_smtp_rules},
++ {"sort-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
++ cf_text_sort_rules},
++ {"startup-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
++ cf_text_startup_rules},
+ {"character-set", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
+ cf_text_character_set},
+ {"editor", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
+***************
+*** 541,546 ****
+--- 615,622 ----
+ cf_text_speller},
+ {"composer-wrap-column", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
+ cf_text_fillcol},
++ {"special-text-color", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
++ cf_special_text_color},
+ {"reply-indent-string", 0, 1, 0, 1, 1, 0, 0, 0, 0, 0,
+ cf_text_replystr},
+ {"reply-leadin", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
+***************
+*** 605,610 ****
+--- 681,688 ----
+ cf_text_news_active},
+ {"news-spool-directory", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
+ cf_text_news_spooldir},
++ {"maildir-location", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
++ cf_text_maildir_location},
+ {"upload-command", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
+ cf_text_upload_cmd},
+ {"upload-command-prefix", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
+***************
+*** 673,678 ****
+--- 751,758 ----
+ cf_text_tcp_write_timeo},
+ {"tcp-query-timeout", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
+ cf_text_tcp_query_timeo},
++ {"inc-fld-timeout", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
++ cf_text_inc_fld_timeout},
+ {"rsh-command", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
+ cf_text_rsh_command},
+ {"rsh-path", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
+***************
+*** 772,777 ****
+--- 852,859 ----
+ {"quote3-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, NULL},
+ {"signature-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, NULL},
+ {"signature-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, NULL},
++ {"special-text-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, NULL},
++ {"special-text-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, NULL},
+ {"prompt-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, NULL},
+ {"prompt-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, NULL},
+ {"index-to-me-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, NULL},
+***************
+*** 1475,1481 ****
+ register struct variable *vars = ps->vars;
+ int obs_header_in_reply, /* the obs_ variables are to */
+ obs_old_style_reply, /* support backwards compatibility */
+! obs_save_by_sender, i, def_sort_rev;
+ long rvl;
+ PINERC_S *fixedprc = NULL;
+ FeatureLevel obs_feature_level;
+--- 1557,1563 ----
+ register struct variable *vars = ps->vars;
+ int obs_header_in_reply, /* the obs_ variables are to */
+ obs_old_style_reply, /* support backwards compatibility */
+! obs_save_by_sender, i, def_sort_rev, thread_def_sort_rev;
+ long rvl;
+ PINERC_S *fixedprc = NULL;
+ FeatureLevel obs_feature_level;
+***************
+*** 1497,1502 ****
+--- 1579,1585 ----
+ GLO_FEATURE_LEVEL = cpystr(DF_FEATURE_LEVEL);
+ GLO_OLD_STYLE_REPLY = cpystr(DF_OLD_STYLE_REPLY);
+ GLO_SORT_KEY = cpystr(DF_SORT_KEY);
++ GLO_THREAD_SORT_KEY = cpystr(DF_THREAD_SORT_KEY);
+ GLO_SAVED_MSG_NAME_RULE = cpystr(DF_SAVED_MSG_NAME_RULE);
+ GLO_FCC_RULE = cpystr(DF_FCC_RULE);
+ GLO_AB_SORT_RULE = cpystr(DF_AB_SORT_RULE);
+***************
+*** 1507,1512 ****
+--- 1590,1596 ----
+ GLO_REMOTE_ABOOK_VALIDITY = cpystr(DF_REMOTE_ABOOK_VALIDITY);
+ GLO_GOTO_DEFAULT_RULE = cpystr(DF_GOTO_DEFAULT_RULE);
+ GLO_INCOMING_STARTUP = cpystr(DF_INCOMING_STARTUP);
++ GLO_INCOMING_RULE = cpystr(DF_INCOMING_RULE);
+ GLO_PRUNING_RULE = cpystr(DF_PRUNING_RULE);
+ GLO_REOPEN_RULE = cpystr(DF_REOPEN_RULE);
+ GLO_THREAD_DISP_STYLE = cpystr(DF_THREAD_DISP_STYLE);
+***************
+*** 1856,1863 ****
+--- 1940,1959 ----
+ set_current_val(&vars[V_POSTPONED_FOLDER], TRUE, TRUE);
+ set_current_val(&vars[V_READ_MESSAGE_FOLDER], TRUE, TRUE);
+ set_current_val(&vars[V_FORM_FOLDER], 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_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);
+ set_current_val(&vars[V_EDITOR], TRUE, TRUE);
+ set_current_val(&vars[V_SPELLER], TRUE, TRUE);
++ set_current_val(&vars[V_SPECIAL_TEXT], TRUE, TRUE);
+ set_current_val(&vars[V_IMAGE_VIEWER], TRUE, TRUE);
+ set_current_val(&vars[V_BROWSER], TRUE, TRUE);
+ set_current_val(&vars[V_SMTP_SERVER], TRUE, TRUE);
+***************
+*** 2076,2081 ****
+--- 2172,2184 ----
+ else
+ ps->tcp_query_timeout = i;
+
++ set_current_val(&vars[V_INCFLDTIMEO], TRUE, TRUE);
++ ps->incfld_timeout = i = INCFLD_THRESHOLD;
++ if(VAR_INCFLDTIMEO && SVAR_INCFLDQUERY(ps, i, tmp_20k_buf))
++ init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
++ else
++ ps->incfld_timeout = i;
++
+ set_current_val(&vars[V_NEWSRC_PATH], TRUE, TRUE);
+ if(VAR_NEWSRC_PATH && VAR_NEWSRC_PATH[0])
+ mail_parameters(NULL, SET_NEWSRC, (void *)VAR_NEWSRC_PATH);
+***************
+*** 2090,2095 ****
+--- 2193,2202 ----
+ mail_parameters(NULL, SET_NEWSSPOOL,
+ (void *)VAR_NEWS_SPOOL_DIR);
+
++ set_current_val(&vars[V_MAILDIR_LOCATION], TRUE, TRUE);
++ if(VAR_MAILDIR_LOCATION && VAR_MAILDIR_LOCATION[0])
++ maildir_parameters(SET_INBOXPATH, (void *)VAR_MAILDIR_LOCATION);
++
+ /* guarantee a save default */
+ set_current_val(&vars[V_DEFAULT_SAVE_FOLDER], TRUE, TRUE);
+ if(!VAR_DEFAULT_SAVE_FOLDER || !VAR_DEFAULT_SAVE_FOLDER[0])
+***************
+*** 2323,2330 ****
+ set_current_val(&vars[V_PRUNED_FOLDERS], TRUE, TRUE);
+ set_current_val(&vars[V_ARCHIVED_FOLDERS], TRUE, TRUE);
+ set_current_val(&vars[V_INCOMING_FOLDERS], TRUE, TRUE);
+ set_current_val(&vars[V_SORT_KEY], TRUE, TRUE);
+! if(decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev) == -1){
+ sprintf(tmp_20k_buf, "Sort type \"%.200s\" is invalid", VAR_SORT_KEY);
+ init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
+ ps->def_sort = SortArrival;
+--- 2430,2438 ----
+ set_current_val(&vars[V_PRUNED_FOLDERS], TRUE, TRUE);
+ set_current_val(&vars[V_ARCHIVED_FOLDERS], TRUE, TRUE);
+ set_current_val(&vars[V_INCOMING_FOLDERS], TRUE, TRUE);
++ set_current_val(&vars[V_INCOMING_FOLDERS_CHECK], TRUE, TRUE);
+ set_current_val(&vars[V_SORT_KEY], TRUE, TRUE);
+! if(decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev,0) == -1){
+ sprintf(tmp_20k_buf, "Sort type \"%.200s\" is invalid", VAR_SORT_KEY);
+ init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
+ ps->def_sort = SortArrival;
+***************
+*** 2333,2338 ****
+--- 2441,2457 ----
+ else
+ ps->def_sort_rev = def_sort_rev;
+
++ set_current_val(&vars[V_THREAD_SORT_KEY], TRUE, TRUE);
++ if(decode_sort(VAR_THREAD_SORT_KEY, &ps->thread_def_sort,
++ &thread_def_sort_rev, 1) == -1){
++ sprintf(tmp_20k_buf, "Sort type \"%s\" is invalid", VAR_THREAD_SORT_KEY);
++ init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
++ ps->thread_def_sort = SortThread;
++ ps->thread_def_sort_rev = 0;
++ }
++ else
++ ps->thread_def_sort_rev = thread_def_sort_rev;
++
+ cur_rule_value(&vars[V_SAVED_MSG_NAME_RULE], TRUE, TRUE);
+ {NAMEVAL_S *v; int i;
+ for(i = 0; v = save_msg_rules(i); i++)
+***************
+*** 2360,2370 ****
+--- 2479,2492 ----
+ cur_rule_value(&vars[V_TITLEBAR_COLOR_STYLE], TRUE, TRUE);
+ cur_rule_value(&vars[V_FLD_SORT_RULE], TRUE, TRUE);
+ cur_rule_value(&vars[V_INCOMING_STARTUP], TRUE, TRUE);
++ cur_rule_value(&vars[V_INCOMING_RULE], TRUE, TRUE);
+ cur_rule_value(&vars[V_PRUNING_RULE], TRUE, TRUE);
+ cur_rule_value(&vars[V_REOPEN_RULE], TRUE, TRUE);
+ cur_rule_value(&vars[V_GOTO_DEFAULT_RULE], TRUE, TRUE);
+ cur_rule_value(&vars[V_THREAD_DISP_STYLE], TRUE, TRUE);
+ cur_rule_value(&vars[V_THREAD_INDEX_STYLE], TRUE, TRUE);
++ cur_rule_value(&vars[V_THREAD_DISP_STYLE_RULES], TRUE, TRUE);
++ cur_rule_value(&vars[V_THREAD_INDEX_STYLE_RULES], TRUE, TRUE);
+
+ set_current_val(&vars[V_THREAD_MORE_CHAR], TRUE, TRUE);
+ if(VAR_THREAD_MORE_CHAR[0] && VAR_THREAD_MORE_CHAR[1]){
+***************
+*** 2418,2423 ****
+--- 2540,2546 ----
+ if(VAR_INIT_CMD_LIST && VAR_INIT_CMD_LIST[0] && VAR_INIT_CMD_LIST[0][0])
+ process_init_cmds(ps, VAR_INIT_CMD_LIST);
+
++ create_rule_list();
+ #ifdef _WINDOWS
+ mswin_set_quit_confirm (F_OFF(F_QUIT_WO_CONFIRM, ps_global));
+ if(ps_global->update_registry != UREG_NEVER_SET){
+***************
+*** 2607,2612 ****
+--- 2730,2737 ----
+ F_STRIP_WS_BEFORE_SEND, h_config_strip_ws_before_send, PREF_COMP},
+
+ /* Reply Prefs */
++ {"alternate-reply-menu",
++ F_ALT_REPLY_MENU, h_config_alt_reply_menu, PREF_RPLY},
+ {"enable-reply-indent-string-editing",
+ F_ENABLE_EDIT_REPLY_INDENT, h_config_prefix_editing, PREF_RPLY},
+ {"include-attachments-in-reply",
+***************
+*** 2641,2646 ****
+--- 2766,2773 ----
+ F_AUTO_FCC_ONLY, h_config_auto_fcc_only, PREF_SEND},
+ {"fcc-without-attachments",
+ F_NO_FCC_ATTACH, h_config_no_fcc_attach, PREF_SEND},
++ {"return-path-uses-domain-name",
++ F_USE_DOMAIN_NAME, h_config_use_domain, PREF_SEND},
+ {"mark-fcc-seen",
+ F_MARK_FCC_SEEN, h_config_mark_fcc_seen, PREF_SEND},
+ {"send-without-confirm",
+***************
+*** 2661,2666 ****
+--- 2788,2797 ----
+ F_ENABLE_DOT_FOLDERS, h_config_enable_dot_folders, PREF_FLDR},
+ {"enable-incoming-folders",
+ F_ENABLE_INCOMING, h_config_enable_incoming, PREF_FLDR},
++ {"enable-check-incoming-folders",
++ F_ENABLE_INCOMING_CHECK, h_config_enable_check_incoming, PREF_FLDR},
++ {"recheck-all-incoming-folders",
++ F_ENABLE_INCOMING_RECHECK, h_config_enable_recheck_incoming,PREF_FLDR},
+ {"enable-lame-list-mode",
+ F_FIX_BROKEN_LIST, h_config_lame_list_mode, PREF_FLDR},
+ {"expanded-view-of-folders",
+***************
+*** 2677,2682 ****
+--- 2808,2815 ----
+ F_SORT_DEFAULT_SAVE_ALPHA, h_config_sort_save_alpha, PREF_FLDR},
+ {"vertical-folder-list",
+ F_VERTICAL_FOLDER_LIST, h_config_vertical_list, PREF_FLDR},
++ {"use-courier-folder-list",
++ F_COURIER_FOLDER_LIST, h_config_courier_list, PREF_FLDR},
+
+ /* Addr book */
+ {"combined-addrbook-display",
+***************
+*** 2693,2698 ****
+--- 2826,2833 ----
+ /* Index prefs */
+ {"auto-open-next-unread",
+ F_AUTO_OPEN_NEXT_UNREAD, h_config_auto_open_unread, PREF_INDX},
++ {"enable-circular-tab",
++ F_AUTO_CIRCULAR_TAB, h_config_circular_tab, PREF_INDX},
+ {"continue-tab-without-confirm",
+ F_TAB_NO_CONFIRM, h_config_tab_no_prompt, PREF_INDX},
+ {"delete-skips-deleted",
+***************
+*** 2715,2720 ****
+--- 2850,2857 ----
+ F_TAB_TO_NEW, h_config_tab_new_only, PREF_INDX},
+ {"thread-index-shows-important-color",
+ F_COLOR_LINE_IMPORTANT, h_config_color_thrd_import, PREF_INDX},
++ {"enhanced-fancy-thread-support",
++ F_ENHANCED_THREAD, h_config_enhanced_thread, PREF_INDX},
+
+ /* Viewer prefs */
+ {"enable-msg-view-addresses",
+***************
+*** 2820,2825 ****
+--- 2957,2964 ----
+ F_FORCE_LOW_SPEED, h_config_force_low_speed, PREF_OS_LWSD},
+ {"auto-move-read-msgs",
+ F_AUTO_READ_MSGS, h_config_auto_read_msgs, PREF_MISC},
++ {"auto-move-read-msgs-using-rules",
++ F_AUTO_READ_MSGS_RULES, h_config_auto_read_msgs_rules, PREF_MISC},
+ {"auto-unzoom-after-apply",
+ F_AUTO_UNZOOM, h_config_auto_unzoom, PREF_MISC},
+ {"auto-zoom-after-select",
+***************
+*** 3767,3772 ****
+--- 3906,3928 ----
+ ? &is_rules[index] : NULL);
+ }
+
++ /*
++ * Standard way to get incoming check rules...
++ */
++ NAMEVAL_S *
++ incoming_check_rules(index)
++ int index;
++ {
++ static NAMEVAL_S is_rules[] = {
++ {"automatic", NULL, IC_AUTO},
++ {"automatic-after-first-manual-check", NULL, IC_MAN_AUTO},
++ {"manual-only", NULL, IC_MAN}
++ };
++
++ return((index >= 0 && index < (sizeof(is_rules)/sizeof(is_rules[0])))
++ ? &is_rules[index] : NULL);
++ }
++
+
+ NAMEVAL_S *
+ startup_rules(index)
+***************
+*** 4201,4210 ****
+ if(i > 0){
+ ps->initial_cmds = (int *)fs_get((i+1) * sizeof(int));
+ ps->free_initial_cmds = ps->initial_cmds;
+ for(j = 0; j < i; j++)
+! ps->initial_cmds[j] = i_cmds[j];
+!
+! ps->initial_cmds[i] = 0;
+ ps->in_init_seq = ps->save_in_init_seq = 1;
+ }
+ }
+--- 4357,4371 ----
+ if(i > 0){
+ ps->initial_cmds = (int *)fs_get((i+1) * sizeof(int));
+ ps->free_initial_cmds = ps->initial_cmds;
++ ps->initial_cmds_backup = (int *)fs_get((i+1) * sizeof(int));
++ ps->free_initial_cmds_backup = ps->initial_cmds_backup;
+ for(j = 0; j < i; j++)
+! ps->initial_cmds[j] = ps->initial_cmds_backup[j] = i_cmds[j];
+! #define ctrl_x 24
+! if (i > 1)
+! ps->send_immediately = i_cmds[i - 2] == ctrl_x
+! && ((i_cmds[i - 1] == 'y') || (i_cmds[i-1] == 'Y'));
+! ps->initial_cmds[i] = ps->initial_cmds_backup[i] = 0;
+ ps->in_init_seq = ps->save_in_init_seq = 1;
+ }
+ }
+***************
+*** 6442,6464 ****
+ * argument also means arrival/reverse.
+ */
+ int
+! decode_sort(sort_spec, def_sort, def_sort_rev)
+ char *sort_spec;
+ SortOrder *def_sort;
+ int *def_sort_rev;
+ {
+ char *sep;
+ char *fix_this = NULL;
+! int x, reverse;
+
+ if(!sort_spec || !*sort_spec){
+! *def_sort = SortArrival;
+ *def_sort_rev = 0;
+ return(0);
+ }
+
+ if(struncmp(sort_spec, "reverse", strlen(sort_spec)) == 0){
+! *def_sort = SortArrival;
+ *def_sort_rev = 1;
+ return(0);
+ }
+--- 6603,6626 ----
+ * argument also means arrival/reverse.
+ */
+ int
+! decode_sort(sort_spec, def_sort, def_sort_rev, thread)
+ char *sort_spec;
+ SortOrder *def_sort;
+ int *def_sort_rev;
++ int thread;
+ {
+ char *sep;
+ char *fix_this = NULL;
+! int x = 0, reverse;
+
+ if(!sort_spec || !*sort_spec){
+! *def_sort = thread ? SortThread : SortArrival;
+ *def_sort_rev = 0;
+ return(0);
+ }
+
+ if(struncmp(sort_spec, "reverse", strlen(sort_spec)) == 0){
+! *def_sort = thread ? SortThread : SortArrival;
+ *def_sort_rev = 1;
+ return(0);
+ }
+***************
+*** 6481,6493 ****
+ sort_spec, strlen(sort_spec)) == 0)
+ break;
+
+ if(fix_this)
+ *fix_this = '/';
+
+ if(ps_global->sort_types[x] == EndofList)
+ return(-1);
+
+! *def_sort = ps_global->sort_types[x];
+ *def_sort_rev = reverse;
+ return(0);
+ }
+--- 6643,6661 ----
+ sort_spec, strlen(sort_spec)) == 0)
+ break;
+
++ if (thread && ps_global->sort_types[x] != SortArrival
++ && ps_global->sort_types[x] != SortDate
++ && ps_global->sort_types[x] != SortThread)
++ for(x = 0; ps_global->sort_types[x] != EndofList; x++);
++
+ if(fix_this)
+ *fix_this = '/';
+
+ if(ps_global->sort_types[x] == EndofList)
+ return(-1);
+
+! *def_sort = (thread && ps_global->sort_types[x] == SortDate)
+! ? SortThread : ps_global->sort_types[x];
+ *def_sort_rev = reverse;
+ return(0);
+ }
+***************
+*** 11038,11043 ****
+--- 11206,11219 ----
+ break;
+ }
+ }
++ else if(var == &ps_global->vars[V_INCOMING_RULE]){
++ if(ps_global->VAR_INCOMING_RULE)
++ for(i = 0; v = incoming_check_rules(i); i++)
++ if(!strucmp(ps_global->VAR_INCOMING_RULE, S_OR_L(v))){
++ ps_global->inc_check_rule = v->value;
++ break;
++ }
++ }
+ else if(var == &ps_global->vars[V_PRUNING_RULE]){
+ if(ps_global->VAR_PRUNING_RULE)
+ for(i = 0; v = pruning_rules(i); i++)
+diff -rc pine4.63/pine/mailcmd.c pine4.63.I.USE/pine/mailcmd.c
+*** pine4.63/pine/mailcmd.c Wed Apr 27 11:54:59 2005
+--- pine4.63.I.USE/pine/mailcmd.c Thu May 19 19:57:34 2005
+***************
+*** 58,63 ****
+--- 58,64 ----
+ /*
+ * Internal Prototypes
+ */
++ void cmd_quota PROTO((struct pine *));
+ void cmd_delete PROTO((struct pine *, MSGNO_S *, int, CmdWhere));
+ void cmd_undelete PROTO((struct pine *, MSGNO_S *, int));
+ void cmd_reply PROTO((struct pine *, MSGNO_S *, int));
+***************
+*** 89,99 ****
+ int save_ex_explain_body PROTO((BODY *, unsigned long *, gf_io_t));
+ int save_ex_explain_parts PROTO((BODY *, int, unsigned long *, gf_io_t));
+ int save_ex_output_line PROTO((char *, unsigned long *, gf_io_t));
+ int create_for_save PROTO((MAILSTREAM *, CONTEXT_S *, char *));
+ void set_keywords_in_msgid_msg PROTO((MAILSTREAM *, MESSAGECACHE *,
+ MAILSTREAM *, char *, long));
+ long get_msgno_by_msg_id PROTO((MAILSTREAM *, char *, MSGNO_S *));
+! int select_sort PROTO((struct pine *, int, SortOrder *, int *));
+ void aggregate_select PROTO((struct pine *, MSGNO_S *, int, CmdWhere,int));
+ int select_number PROTO((MAILSTREAM *, MSGNO_S *, SEARCHSET **));
+ int select_thrd_number PROTO((MAILSTREAM *, MSGNO_S *, SEARCHSET **));
+--- 90,103 ----
+ int save_ex_explain_body PROTO((BODY *, unsigned long *, gf_io_t));
+ int save_ex_explain_parts PROTO((BODY *, int, unsigned long *, gf_io_t));
+ int save_ex_output_line PROTO((char *, unsigned long *, gf_io_t));
++ void total_messages_status PROTO ((MAILSTREAM *, int, unsigned long *,
++ unsigned long *));
++ char *any_report_message PROTO ((MAILSTREAM *));
+ int create_for_save PROTO((MAILSTREAM *, CONTEXT_S *, char *));
+ void set_keywords_in_msgid_msg PROTO((MAILSTREAM *, MESSAGECACHE *,
+ MAILSTREAM *, char *, long));
+ long get_msgno_by_msg_id PROTO((MAILSTREAM *, char *, MSGNO_S *));
+! int select_sort PROTO((struct pine *, int, SortOrder *, int *, int));
+ void aggregate_select PROTO((struct pine *, MSGNO_S *, int, CmdWhere,int));
+ int select_number PROTO((MAILSTREAM *, MSGNO_S *, SEARCHSET **));
+ int select_thrd_number PROTO((MAILSTREAM *, MSGNO_S *, SEARCHSET **));
+***************
+*** 109,114 ****
+--- 113,139 ----
+ char *currentf_sequence PROTO((MAILSTREAM *, MSGNO_S *, long, long *,
+ int, char **, char **));
+ char *invalid_elt_sequence PROTO((MAILSTREAM *, MSGNO_S *));
++ long top_thread PROTO((MAILSTREAM *, long));
++ void move_top_thread PROTO((MAILSTREAM *, MSGNO_S *, long));
++ long top_this_thread PROTO((MAILSTREAM *, long));
++ void move_top_this_thread PROTO((MAILSTREAM *, MSGNO_S *, long));
++ void cmd_delete_this_thread PROTO((struct pine *, MAILSTREAM *, MSGNO_S *));
++ void cmd_delete_thread PROTO((struct pine *, MAILSTREAM *, MSGNO_S *));
++ void cmd_undelete_this_thread PROTO((struct pine *, MAILSTREAM *, MSGNO_S *));
++ void cmd_undelete_thread PROTO((struct pine *, MAILSTREAM *, MSGNO_S *));
++ void cmd_select_thread PROTO((struct pine *, MAILSTREAM *, MSGNO_S *));
++ void kolapse_thread PROTO((struct pine *, MAILSTREAM *, MSGNO_S *, char, int));
++ int count_thread PROTO((struct pine *, MAILSTREAM *, MSGNO_S *, long));
++ int count_this_thread PROTO((MAILSTREAM *, unsigned long));
++ int this_thread_is_kolapsed PROTO((struct pine *, MAILSTREAM *, MSGNO_S *, long));
++ int thread_is_kolapsed PROTO((struct pine *, MAILSTREAM *, MSGNO_S *, long));
++ int collapse_this_thread PROTO((struct pine *, MAILSTREAM *, MSGNO_S *, int, int));
++ void collapse_thread PROTO((struct pine *, MAILSTREAM *, MSGNO_S *, int));
++ int expand_this_thread PROTO((struct pine *, MAILSTREAM *, MSGNO_S *, int, int));
++ void expand_thread PROTO((struct pine *, MAILSTREAM *, MSGNO_S *, int));
++ int move_next_this_thread PROTO((struct pine *, MAILSTREAM *, MSGNO_S *, int));
++ int move_next_thread PROTO((struct pine *, MAILSTREAM *, MSGNO_S *, int));
++ int move_prev_thread PROTO((struct pine *, MAILSTREAM *, MSGNO_S *, int));
+ char *selected_sequence PROTO((MAILSTREAM *, MSGNO_S *, long *, int));
+ int any_messages PROTO((MSGNO_S *, char *, char *));
+ int can_set_flag PROTO((struct pine *, char *, int));
+***************
+*** 119,124 ****
+--- 144,155 ----
+ int read_msg_prompt PROTO((long, char *));
+ char *move_read_incoming PROTO((MAILSTREAM *, CONTEXT_S *, char *,
+ char **, char *));
++ char *move_read_msgs_using_rules PROTO((MAILSTREAM *, char *, char *));
++ unsigned get_perfolder_startup_rule PROTO((MAILSTREAM *, int, char *));
++ void setup_threading_index_style PROTO(());
++ int find_startup_position PROTO((int, MAILSTREAM *, long));
++ char *get_rule_result PROTO((int, char *, int));
++ char *get_folder_to_save PROTO((MAILSTREAM *, long, char *));
+ void cross_delete_crossposts PROTO((MAILSTREAM *));
+ void menu_clear_cmd_binding PROTO((struct key_menu *, int));
+ int update_folder_spec PROTO((char *, char *));
+***************
+*** 141,146 ****
+--- 172,180 ----
+ #define SV_FOR_FILT 0x2
+ #define SV_FIX_DELS 0x4
+
++ static MAILSTREAM *saved_stream;
++ static unsigned long rule_curpos = 0L;
++
+ typedef struct append_package {
+ MAILSTREAM *stream;
+ char *flags;
+***************
+*** 267,272 ****
+--- 301,307 ----
+ {'r', 'r', "R", "Recipient"},
+ {'p', 'p', "P", "Participant"},
+ {'b', 'b', "B", "Body"},
++ {'h', 'h', "H", "Header"},
+ {-1, 0, NULL, NULL}
+ };
+
+***************
+*** 936,942 ****
+ state->context_current, &recent_cnt,
+ F_ON(F_TAB_NO_CONFIRM,state)
+ ? NULL : &did_cancel))){
+! if(!in_inbox){
+ static ESCKEY_S inbox_opt[] = {
+ {'y', 'y', "Y", "Yes"},
+ {'n', 'n', "N", "No"},
+--- 971,977 ----
+ state->context_current, &recent_cnt,
+ F_ON(F_TAB_NO_CONFIRM,state)
+ ? NULL : &did_cancel))){
+! if(!in_inbox && F_OFF(F_AUTO_CIRCULAR_TAB,state)){
+ static ESCKEY_S inbox_opt[] = {
+ {'y', 'y', "Y", "Yes"},
+ {'n', 'n', "N", "No"},
+***************
+*** 1186,1191 ****
+--- 1221,1230 ----
+ if(SORT_IS_THREADED(msgmap))
+ refresh_sort(stream, msgmap, SRT_NON);
+
++ if (msgmap->nmsgs
++ && F_ON(F_ENHANCED_THREAD, state) && COLL_THRDS())
++ kolapse_thread(state, stream, msgmap, '[', 0);
++
+ state->mangled_body = 1;
+ state->mangled_header = 1;
+ q_status_message2(SM_ORDER, 0, 4,
+***************
+*** 1256,1261 ****
+--- 1295,1301 ----
+ ps_global->expunge_in_progress = 0;
+ if(we_cancel)
+ cancel_busy_alarm((sp_expunge_count(stream) > 0) ? 0 : -1);
++ update_incoming_folder_data(stream, state->context_current);
+
+ dprint(2,(debugfile,"expunge complete cur:%ld max:%ld\n",
+ mn_get_cur(msgmap), mn_get_total(msgmap)));
+***************
+*** 1298,1303 ****
+--- 1338,1346 ----
+ */
+ if(SORT_IS_THREADED(msgmap))
+ refresh_sort(stream, msgmap, SRT_NON);
++ if (msgmap->nmsgs
++ && F_ON(F_ENHANCED_THREAD, state) && COLL_THRDS())
++ kolapse_thread(state, stream, msgmap, '[', 0);
+ }
+ else{
+ if(del_count)
+***************
+*** 1434,1440 ****
+ if(any_messages(msgmap, NULL, NULL)){
+ if(any_lflagged(msgmap, MN_SLCT) > 0L){
+ if(apply_command(state, stream, msgmap, 0,
+! AC_NONE, question_line)
+ && F_ON(F_AUTO_UNZOOM, state))
+ unzoom_index(state, stream, msgmap);
+ }
+--- 1477,1483 ----
+ if(any_messages(msgmap, NULL, NULL)){
+ if(any_lflagged(msgmap, MN_SLCT) > 0L){
+ if(apply_command(state, stream, msgmap, 0,
+! AC_NONE, question_line, 1)
+ && F_ON(F_AUTO_UNZOOM, state))
+ unzoom_index(state, stream, msgmap);
+ }
+***************
+*** 1447,1464 ****
+
+ /*-------- Sort command -------*/
+ case MC_SORT :
+ {
+ int were_threading = THREADING();
+ SortOrder sort = mn_get_sort(msgmap);
+ int rev = mn_get_revsort(msgmap);
+
+ dprint(1, (debugfile,"MAIL_CMD: sort\n"));
+! if(select_sort(state, question_line, &sort, &rev)){
+ /* $ command reinitializes threading collapsed/expanded info */
+ if(SORT_IS_THREADED(msgmap) && !SEP_THRDINDX())
+ erase_threading_info(stream, msgmap);
+
+! sort_folder(stream, msgmap, sort, rev, SRT_VRB|SRT_MAN);
+ }
+
+ state->mangled_footer = 1;
+--- 1490,1514 ----
+
+ /*-------- Sort command -------*/
+ case MC_SORT :
++ case MC_SORTHREAD :
+ {
+ int were_threading = THREADING();
+ SortOrder sort = mn_get_sort(msgmap);
+ int rev = mn_get_revsort(msgmap);
++ int thread = (command == MC_SORT) ? 0 : 1;
+
++ if (sort == SortThread)
++ sort = ps_global->thread_cur_sort;
+ dprint(1, (debugfile,"MAIL_CMD: sort\n"));
+! if(select_sort(state, question_line, &sort, &rev, thread)){
+ /* $ command reinitializes threading collapsed/expanded info */
+ if(SORT_IS_THREADED(msgmap) && !SEP_THRDINDX())
+ erase_threading_info(stream, msgmap);
+
+! if (command == MC_SORTHREAD)
+! ps_global->thread_cur_sort = sort;
+! sort = (command == MC_SORT) ? sort : SortThread;
+! sort_folder(stream, msgmap, sort, rev, SRT_VRB|SRT_MAN, 1);
+ }
+
+ state->mangled_footer = 1;
+***************
+*** 1533,1538 ****
+--- 1583,1594 ----
+ break;
+
+
++ /*--------Incoming Folders Auto Check --------*/
++ case MC_FORCECHECK:
++ state->force_check_now = 1;
++ new_mail_incfolder(state,command);
++ break;
++
+ /*--------- Default, unknown command ----------*/
+ default:
+ panic("Unexpected command case");
+***************
+*** 1940,1945 ****
+--- 1996,2163 ----
+ }
+
+
++ static struct key quota_keys[] =
++ {HELP_MENU,
++ NULL_MENU,
++ {"E","Exit",{MC_EXIT,3,{'e','i',ctrl('C')}},KS_EXITMODE},
++ NULL_MENU,
++ NULL_MENU,
++ NULL_MENU,
++ NULL_MENU,
++ NULL_MENU,
++ NULL_MENU,
++ NULL_MENU,
++ NULL_MENU,
++ NULL_MENU};
++ INST_KEY_MENU(pine_quota_keymenu, quota_keys);
++
++ int process_quota_cmd(cmd, msgmap, sparms)
++ int cmd;
++ MSGNO_S *msgmap;
++ SCROLL_S *sparms;
++ {
++ return cmd;
++ }
++
++
++ void cmd_quota (state)
++ struct pine *state;
++ {
++ QUOTALIST *imapquota;
++ NETMBX mb;
++ unsigned long len, storageuse, storagelim, messageuse, messagelim;
++ STORE_S *store;
++ SCROLL_S sargs;
++ char *linedata;
++ char *storageq = NULL, *messageq = NULL;
++ int storage=0, message=0, other=0, storagelen = 0, messagelen = 0;
++
++ if(!state->mail_stream || !is_imap_stream(state->mail_stream)){
++ q_status_message(SM_ORDER, 1, 5, "Quota only available for IMAP folders");
++ return;
++ }
++
++ if (state->mail_stream
++ && !sp_dead_stream(state->mail_stream)
++ && state->mail_stream->mailbox
++ && *state->mail_stream->mailbox
++ && mail_valid_net_parse(state->mail_stream->mailbox, &mb))
++ imap_getquotaroot(state->mail_stream, mb.mailbox);
++
++ if(!state->quota) /* failed ? */
++ return; /* go back... */
++
++ if(!(store = so_get(CharStar, NULL, EDIT_ACCESS))){
++ q_status_message(SM_ORDER | SM_DING, 3, 3, "Error allocating space.");
++ return;
++ }
++
++ if (state->mail_stream && state->mail_stream->original_mailbox){
++ len = strlen(state->mail_stream->original_mailbox) + 18;
++ linedata = (char *) fs_get(len*sizeof(char));
++ sprintf(linedata,"Quota Report for %s\n",
++ state->mail_stream->original_mailbox);
++ so_puts(store,linedata);
++ if (linedata)
++ fs_give((void **)&linedata);
++ }
++ else
++ so_puts(store,"Quota Report:\n");
++ so_puts(store,"\n");
++
++ for (imapquota = state->quota; imapquota; imapquota = imapquota->next){
++ if(!strucmp(imapquota->name,"STORAGE")){
++ storage++;
++ storagelen = strlen(long2string(imapquota->limit)) + 1;
++ storageuse = imapquota->usage;
++ storagelim = imapquota->limit;
++ }
++ if(!strucmp(imapquota->name,"MESSAGE")){
++ message++;
++ messagelen = strlen(long2string(imapquota->limit)) + 1;
++ messageuse = imapquota->usage;
++ messagelim = imapquota->limit;
++ }
++ other += strucmp(imapquota->name,"STORAGE") &&
++ strucmp(imapquota->name,"MESSAGE") ? 0 : 1;
++ }
++
++ storageq = (char *) fs_get(storagelen*sizeof(char));
++ if (storage)
++ sprintf(storageq, "%lu KB", storageuse);
++ messageq = (char *) fs_get(messagelen*sizeof(char));
++ if (message)
++ sprintf(messageq, "%lu message%s", messageuse, plural(messageuse));
++ len = strlen("Usage: ") + storagelen + messagelen + 20;
++ linedata = (char *) fs_get(len*sizeof(char));
++ sprintf(linedata,"Usage: %s%s%s%s\n", storage ? storageq : "",
++ message ? (storage ? " (" : "") : "",
++ message ? messageq : "",
++ message ? (storage ? ")" : "") : "");
++ so_puts(store, linedata);
++ if (storageq)
++ fs_give((void **)&storageq);
++ if (messageq)
++ fs_give((void **)&messageq);
++ if (linedata)
++ fs_give((void **)&linedata);
++
++ storageq = (char *) fs_get(storagelen*sizeof(char));
++ if (storage)
++ sprintf(storageq, "%lu KB", storagelim);
++ messageq = (char *) fs_get(messagelen*sizeof(char));
++ if (message)
++ sprintf(messageq, "%lu message%s", messagelim, plural(messagelim));
++ len = strlen("Limit: ") + storagelen + messagelen + 20;
++ linedata = (char *) fs_get(len*sizeof(char));
++ sprintf(linedata,"Limit: %s%s%s%s", storage ? storageq : "",
++ message ? (storage ? " (" : "") : "",
++ message ? messageq : "",
++ message ? (storage ? ")" : "") : "");
++ so_puts(store, linedata);
++ if (storageq)
++ fs_give((void **)&storageq);
++ if (messageq)
++ fs_give((void **)&messageq);
++ if (linedata)
++ fs_give((void **)&linedata);
++
++ for (imapquota = state->quota; other && imapquota;
++ imapquota = imapquota->next){
++ if (strucmp(imapquota->name,"STORAGE") &&
++ strucmp(imapquota->name,"MESSAGE")){
++ len = (imapquota->name ? strlen(imapquota->name) : strlen("No Name"))
++ + 2*strlen(long2string(imapquota->limit)) + 46;
++ linedata = (char *) fs_get(len*sizeof(char));
++ sprintf(linedata,
++ "Resource : %s\nUsage : %lu (%lu%%)\nLimit : %lu\n\n",
++ imapquota->name ? imapquota->name : "No Name",
++ imapquota->usage, 100*imapquota->usage/imapquota->limit,
++ imapquota->limit);
++ so_puts(store,linedata);
++ if (linedata)
++ fs_give((void **)&linedata);
++ }
++ }
++
++ memset(&sargs, 0, sizeof(SCROLL_S));
++ sargs.text.text = so_text(store);
++ sargs.text.src = CharStar;
++ sargs.text.desc = "Quota Resources Summary";
++ sargs.bar.title = cpystr("QUOTA SUMMARY");
++ sargs.proc.tool = process_quota_cmd;
++ sargs.help.text = NO_HELP;
++ sargs.help.title = NULL;
++ sargs.keys.menu = &pine_quota_keymenu;
++ setbitmap(sargs.keys.bitmap);
++
++ scrolltool(&sargs);
++ so_give(&store);
++
++ if (state->quota)
++ mail_free_quotalist(&(state->quota));
++ }
++
+ /*----------------------------------------------------------------------
+ Execute DELETE message command
+
+***************
+*** 2928,2933 ****
+--- 3146,3152 ----
+
+ dprint(4, (debugfile, "\n - saving message -\n"));
+
++ saved_stream = stream; /* ugly hack! */
+ state->ugly_consider_advancing_bit = 0;
+ if(F_OFF(F_SAVE_PARTIAL_WO_CONFIRM, state)
+ && msgno_any_deletedparts(stream, msgmap)
+***************
+*** 3175,3181 ****
+ {
+ static char folder[MAILTMPLEN+1] = {'\0'};
+ static CONTEXT_S *last_context = NULL;
+! int rc, n, flags, last_rc = 0, saveable_count = 0, done = 0;
+ int context_was_set, delindex;
+ char prompt[MAX_SCREEN_COLS+1], *p, expanded[MAILTMPLEN];
+ char *buf = tmp_20k_buf;
+--- 3394,3400 ----
+ {
+ static char folder[MAILTMPLEN+1] = {'\0'};
+ static CONTEXT_S *last_context = NULL;
+! int rc, n=0, flags, last_rc = 0, saveable_count = 0, done = 0;
+ int context_was_set, delindex;
+ char prompt[MAX_SCREEN_COLS+1], *p, expanded[MAILTMPLEN];
+ char *buf = tmp_20k_buf;
+***************
+*** 3184,3189 ****
+--- 3403,3411 ----
+ char *deltext = NULL;
+ CONTEXT_S *tc;
+ ESCKEY_S ekey[9];
++ RULE_RESULT *rule;
++
++ saved_stream = state->mail_stream;
+
+ if(!cntxt)
+ panic("no context ptr in save_prompt");
+***************
+*** 3214,3219 ****
+--- 3436,3448 ----
+ return(0);
+ }
+
++ if (rule = get_result_rule(V_SAVE_RULES, FOR_RULE | FOR_SAVE, env)){
++ strncpy(folder,rule->result,sizeof(folder)-1);
++ folder[sizeof(folder)-1] = '\0';
++ 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)
+***************
+*** 4134,4140 ****
+ *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(sp_expunge_count(stream))
+--- 4363,4369 ----
+ *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(sp_expunge_count(stream))
+***************
+*** 7265,7270 ****
+--- 7494,7558 ----
+ return(newfolder);
+ }
+
++ char *
++ any_report_message (stream)
++ MAILSTREAM *stream;
++ {
++ char message[40] = {'\0'}, *report;
++ unsigned long new, unseen;
++ int i, imapstatus = 0;
++
++ for (i = 0; ps_global->index_disp_format[i].ctype != iNothing
++ && ps_global->index_disp_format[i].ctype != iIStatus; i++);
++ imapstatus = ps_global->index_disp_format[i].ctype == iIStatus;
++
++ report = (char *) fs_get(41*sizeof(char));
++ total_messages_status(stream, imapstatus, &new, &unseen);
++
++ if (new > 0L || (unseen > 0L && imapstatus)){
++ sprintf(message," - %s%s%s%s%s", new > 0L ? comatose(new) : "",
++ new > 0L ? " new" : "",
++ new > 0L && unseen > 0L && imapstatus ? ", " : "",
++ unseen > 0L && imapstatus ? comatose(unseen) : "",
++ unseen > 0L && imapstatus ? " unseen" : "");
++ }
++ report = *message ? cpystr(message) : cpystr("");
++
++ return report;
++ }
++
++ void
++ total_messages_status (stream, imapstatus, new, unseen)
++ MAILSTREAM *stream;
++ int imapstatus;
++ unsigned long *new, *unseen;
++ {
++ MESSAGECACHE *mc;
++ unsigned long i;
++ int *searched;
++
++ if (new) *new = imapstatus ? count_flagged(stream, F_RECENT | F_UNDEL)
++ : count_flagged(stream, F_UNSEEN | F_UNDEL);
++ if (unseen) *unseen = 0L;
++
++ if (!imapstatus || !unseen)
++ return;
++
++ searched = (int *) fs_get(stream->nmsgs*sizeof(int));
++ memset(searched, 0, stream->nmsgs*sizeof(searched));
++ for (i = 1L; stream && i <= stream->nmsgs && (mc = mail_elt(stream, i)); i++)
++ if (mc->searched
++ || (mc->valid && !get_lflag(stream, NULL, i, MN_EXLD)
++ && mc->recent && !mc->deleted))
++ searched[i-1] = 1;
++ count_flagged(stream, F_UNSEEN | F_UNDEL);
++ for (i = 1L; stream && i <= stream->nmsgs && (mc = mail_elt(stream, i)); i++)
++ if (!searched[i-1] && (mc->searched
++ || (mc->valid && !get_lflag(stream, NULL, i, MN_EXLD)
++ && !mc->seen && !mc->recent && !mc->deleted)))
++ (*unseen)++;
++ fs_give((void **)&searched);
++ }
+
+ /*----------------------------------------------------------------------
+ Check to see if user input is in form of old c-client mailbox speck
+***************
+*** 7322,7327 ****
+--- 7610,7821 ----
+ return(FALSE);
+ }
+
++ void
++ setup_threading_index_style()
++ {
++ RULE_RESULT *rule;
++ NAMEVAL_S *v;
++ int i;
++
++ rule = get_result_rule(V_THREAD_INDEX_STYLE_RULES,
++ FOR_RULE | FOR_THREAD, (ENVELOPE *) 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);
++ }
++ }
++ }
++
++
++ char *get_rule_result(rule_context, newfolder, code)
++ 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 = (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;
++ }
++
++ find_startup_position(rule, m, pc)
++ int rule;
++ MAILSTREAM *m;
++ long pc;
++ {
++ long n;
++ switch(rule){
++ /*
++ * For news in incoming collection we're doing the same thing
++ * for first-unseen and first-recent. In both those cases you
++ * get first-unseen if FAKE_NEW is off and first-recent if
++ * FAKE_NEW is on. If FAKE_NEW is on, first unseen is the
++ * same as first recent because all recent msgs are unseen
++ * and all unrecent msgs are seen (see pine_mail_open).
++ */
++ case IS_FIRST_UNSEEN:
++ first_unseen:
++ mn_set_cur(ps_global->msgmap,
++ (sp_first_unseen(m)
++ && mn_get_sort(ps_global->msgmap) == SortArrival
++ && !mn_get_revsort(ps_global->msgmap)
++ && !get_lflag(ps_global->mail_stream, NULL,
++ sp_first_unseen(m), MN_EXLD)
++ && (n = mn_raw2m(ps_global->msgmap,
++ sp_first_unseen(m))))
++ ? n
++ : first_sorted_flagged(F_UNSEEN | F_UNDEL, m, pc,
++ THREADING() ? 0 : FSF_SKIP_CHID));
++ break;
++
++ case IS_FIRST_RECENT:
++ first_recent:
++ /*
++ * We could really use recent for news but this is the way
++ * it has always worked, so we'll leave it. That is, if
++ * the FAKE_NEW feature is on, recent and unseen are
++ * equivalent, so it doesn't matter. If the feature isn't
++ * on, all the undeleted messages are unseen and we start
++ * at the first one. User controls with the FAKE_NEW feature.
++ */
++ if(IS_NEWS(ps_global->mail_stream)){
++ mn_set_cur(ps_global->msgmap,
++ first_sorted_flagged(F_UNSEEN|F_UNDEL, m, pc,
++ THREADING() ? 0 : FSF_SKIP_CHID));
++ }
++ else{
++ mn_set_cur(ps_global->msgmap,
++ first_sorted_flagged(F_RECENT | F_UNSEEN
++ | F_UNDEL,
++ m, pc,
++ THREADING() ? 0 : FSF_SKIP_CHID));
++ }
++ break;
++
++ case IS_FIRST_IMPORTANT:
++ mn_set_cur(ps_global->msgmap,
++ first_sorted_flagged(F_FLAG|F_UNDEL, m, pc,
++ THREADING() ? 0 : FSF_SKIP_CHID));
++ break;
++
++ case IS_FIRST_IMPORTANT_OR_UNSEEN:
++
++ if(IS_NEWS(ps_global->mail_stream))
++ goto first_unseen;
++
++ {
++ MsgNo flagged, first_unseen;
++
++ flagged = first_sorted_flagged(F_FLAG|F_UNDEL, m, pc,
++ THREADING() ? 0 : FSF_SKIP_CHID);
++ first_unseen = (sp_first_unseen(m)
++ && mn_get_sort(ps_global->msgmap) == SortArrival
++ && !mn_get_revsort(ps_global->msgmap)
++ && !get_lflag(ps_global->mail_stream, NULL,
++ sp_first_unseen(m), MN_EXLD)
++ && (n = mn_raw2m(ps_global->msgmap,
++ sp_first_unseen(m))))
++ ? n
++ : first_sorted_flagged(F_UNSEEN|F_UNDEL, m, pc,
++ THREADING() ? 0 : FSF_SKIP_CHID);
++ mn_set_cur(ps_global->msgmap,
++ (MsgNo) min((int) flagged, (int) first_unseen));
++
++ }
++
++ break;
++
++ case IS_FIRST_IMPORTANT_OR_RECENT:
++
++ if(IS_NEWS(ps_global->mail_stream))
++ goto first_recent;
++
++ {
++ MsgNo flagged, first_recent;
++
++ flagged = first_sorted_flagged(F_FLAG|F_UNDEL, m, pc,
++ THREADING() ? 0 : FSF_SKIP_CHID);
++ first_recent = first_sorted_flagged(F_RECENT | F_UNSEEN
++ | F_UNDEL,
++ m, pc,
++ THREADING() ? 0 : FSF_SKIP_CHID);
++ mn_set_cur(ps_global->msgmap,
++ (MsgNo) min((int) flagged, (int) first_recent));
++ }
++
++ break;
++
++ case IS_FIRST:
++ mn_set_cur(ps_global->msgmap,
++ first_sorted_flagged(F_UNDEL, m, pc,
++ THREADING() ? 0 : FSF_SKIP_CHID));
++ break;
++
++ case IS_LAST:
++ mn_set_cur(ps_global->msgmap,
++ first_sorted_flagged(F_UNDEL, m, pc,
++ FSF_LAST | (THREADING() ? 0 : FSF_SKIP_CHID)));
++ break;
++
++ default:
++ panic("Unexpected incoming startup case");
++ break;
++
++ }
++ }
++
++ unsigned
++ get_perfolder_startup_rule(stream, rule_type, folder)
++ 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_RULE | 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;
++ }
++
+
+ /*----------------------------------------------------------------------
+ Actually attempt to open given folder
+***************
+*** 7356,7362 ****
+ int open_inbox, rv, old_tros, we_cancel = 0,
+ do_reopen = 0, n, was_dead = 0, cur_already_set = 0;
+ char expanded_file[max(MAXPATH,MAILTMPLEN)+1],
+! *old_folder, *old_path, *p;
+ long openmode, rflags = 0L, pc = 0L, cur, raw;
+ ENVELOPE *env = NULL;
+ char status_msg[81];
+--- 7850,7856 ----
+ int open_inbox, rv, old_tros, we_cancel = 0,
+ do_reopen = 0, n, was_dead = 0, cur_already_set = 0;
+ char expanded_file[max(MAXPATH,MAILTMPLEN)+1],
+! *old_folder, *old_path, *p, *report;
+ long openmode, rflags = 0L, pc = 0L, cur, raw;
+ ENVELOPE *env = NULL;
+ char status_msg[81];
+***************
+*** 7690,7704 ****
+ 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;
+ reset_index_format();
+ clear_index_cache();
+ /* MUST sort before restoring msgno! */
+ refresh_sort(ps_global->mail_stream, ps_global->msgmap, SRT_NON);
+! q_status_message3(SM_ORDER, 0, 3,
+! "Opened folder \"%.200s\" with %.200s message%.200s",
+! ps_global->inbox_name,
+! long2string(mn_get_total(ps_global->msgmap)),
+! plural(mn_get_total(ps_global->msgmap)));
+ #ifdef _WINDOWS
+ mswin_settitle(ps_global->inbox_name);
+ #endif
+--- 8184,8203 ----
+ 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();
+ /* MUST sort before restoring msgno! */
+ refresh_sort(ps_global->mail_stream, ps_global->msgmap, SRT_NON);
+! report = any_report_message(ps_global->mail_stream);
+! q_status_message4(SM_ORDER, 0, 3,
+! "Opened folder \"%.200s\" with %.200s message%.200s%.200s",
+! ps_global->inbox_name,
+! long2string(mn_get_total(ps_global->msgmap)),
+! plural(mn_get_total(ps_global->msgmap)),
+! report);
+! if (report)
+! fs_give((void **)&report);
+ #ifdef _WINDOWS
+ mswin_settitle(ps_global->inbox_name);
+ #endif
+***************
+*** 7999,8004 ****
+--- 8498,8504 ----
+
+ clear_index_cache();
+ reset_index_format();
++ setup_threading_index_style();
+
+ /*
+ * Start news reading with messages the user's marked deleted
+***************
+*** 8018,8025 ****
+ if(!sp_flagged(ps_global->mail_stream, SP_FILTERED))
+ process_filter_patterns(ps_global->mail_stream, ps_global->msgmap, 0L);
+
+! q_status_message6(SM_ORDER, 0, 4,
+! "%.20s \"%.200s\" opened with %.20s message%.20s%.20s%.20s",
+ IS_NEWS(ps_global->mail_stream)
+ ? "News group" : "Folder",
+ pretty_fn(newfolder),
+--- 8518,8533 ----
+ if(!sp_flagged(ps_global->mail_stream, SP_FILTERED))
+ process_filter_patterns(ps_global->mail_stream, ps_global->msgmap, 0L);
+
+! if(!(rflags & SP_MATCH) || !(rflags & SP_LOCKED))
+! reset_sort_order(SRT_VRB);
+! else if(sp_new_mail_count(ps_global->mail_stream) > 0L
+! || sp_unsorted_newmail(ps_global->mail_stream)
+! || sp_need_to_rethread(ps_global->mail_stream))
+! refresh_sort(ps_global->mail_stream, ps_global->msgmap, SRT_NON);
+!
+! report = any_report_message(ps_global->mail_stream);
+! q_status_message7(SM_ORDER, 0, 4,
+! "%.20s \"%.200s\" opened with %.20s message%.20s%.20s%.20s%.20s",
+ IS_NEWS(ps_global->mail_stream)
+ ? "News group" : "Folder",
+ pretty_fn(newfolder),
+***************
+*** 8029,8048 ****
+ && sp_flagged(ps_global->mail_stream, SP_PERMLOCKED))
+ ? " (StayOpen)" : "",
+ READONLY_FOLDER(ps_global->mail_stream)
+! ? " READONLY" : "");
+
+ #ifdef _WINDOWS
+ mswin_settitle(pretty_fn(newfolder));
+ #endif
+
+- if(!(rflags & SP_MATCH) || !(rflags & SP_LOCKED))
+- reset_sort_order(SRT_VRB);
+- else if(sp_new_mail_count(ps_global->mail_stream) > 0L
+- || sp_unsorted_newmail(ps_global->mail_stream)
+- || sp_need_to_rethread(ps_global->mail_stream))
+- refresh_sort(ps_global->mail_stream, ps_global->msgmap, SRT_NON);
+-
+-
+ /*
+ * Set current message number when re-opening Stay-Open or
+ * cached folders.
+--- 8537,8551 ----
+ && sp_flagged(ps_global->mail_stream, SP_PERMLOCKED))
+ ? " (StayOpen)" : "",
+ READONLY_FOLDER(ps_global->mail_stream)
+! ? " READONLY" : "",
+! report);
+! if (report)
+! fs_give((void **)&report);
+
+ #ifdef _WINDOWS
+ mswin_settitle(pretty_fn(newfolder));
+ #endif
+
+ /*
+ * Set current message number when re-opening Stay-Open or
+ * cached folders.
+***************
+*** 8106,8112 ****
+
+ 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)
+--- 8609,8618 ----
+
+ 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)
+***************
+*** 8128,8267 ****
+ else
+ use_this_startup_rule = ps_global->inc_startup_rule;
+
+! switch(use_this_startup_rule){
+! /*
+! * For news in incoming collection we're doing the same thing
+! * for first-unseen and first-recent. In both those cases you
+! * get first-unseen if FAKE_NEW is off and first-recent if
+! * FAKE_NEW is on. If FAKE_NEW is on, first unseen is the
+! * same as first recent because all recent msgs are unseen
+! * and all unrecent msgs are seen (see pine_mail_open).
+! */
+! case IS_FIRST_UNSEEN:
+! first_unseen:
+! mn_set_cur(ps_global->msgmap,
+! (sp_first_unseen(m)
+! && mn_get_sort(ps_global->msgmap) == SortArrival
+! && !mn_get_revsort(ps_global->msgmap)
+! && !get_lflag(ps_global->mail_stream, NULL,
+! sp_first_unseen(m), MN_EXLD)
+! && (n = mn_raw2m(ps_global->msgmap,
+! sp_first_unseen(m))))
+! ? n
+! : first_sorted_flagged(F_UNSEEN | F_UNDEL, m, pc,
+! THREADING() ? 0 : FSF_SKIP_CHID));
+! break;
+
+! case IS_FIRST_RECENT:
+! first_recent:
+! /*
+! * We could really use recent for news but this is the way
+! * it has always worked, so we'll leave it. That is, if
+! * the FAKE_NEW feature is on, recent and unseen are
+! * equivalent, so it doesn't matter. If the feature isn't
+! * on, all the undeleted messages are unseen and we start
+! * at the first one. User controls with the FAKE_NEW feature.
+! */
+! if(IS_NEWS(ps_global->mail_stream)){
+! mn_set_cur(ps_global->msgmap,
+! first_sorted_flagged(F_UNSEEN|F_UNDEL, m, pc,
+! THREADING() ? 0 : FSF_SKIP_CHID));
+! }
+! else{
+! mn_set_cur(ps_global->msgmap,
+! first_sorted_flagged(F_RECENT | F_UNSEEN
+! | F_UNDEL,
+! m, pc,
+ THREADING() ? 0 : FSF_SKIP_CHID));
+! }
+! break;
+!
+! case IS_FIRST_IMPORTANT:
+! mn_set_cur(ps_global->msgmap,
+! first_sorted_flagged(F_FLAG|F_UNDEL, m, pc,
+! THREADING() ? 0 : FSF_SKIP_CHID));
+! break;
+!
+! case IS_FIRST_IMPORTANT_OR_UNSEEN:
+!
+! if(IS_NEWS(ps_global->mail_stream))
+! goto first_unseen;
+!
+! {
+! MsgNo flagged, first_unseen;
+!
+! flagged = first_sorted_flagged(F_FLAG|F_UNDEL, m, pc,
+! THREADING() ? 0 : FSF_SKIP_CHID);
+! first_unseen = (sp_first_unseen(m)
+! && mn_get_sort(ps_global->msgmap) == SortArrival
+! && !mn_get_revsort(ps_global->msgmap)
+! && !get_lflag(ps_global->mail_stream, NULL,
+! sp_first_unseen(m), MN_EXLD)
+! && (n = mn_raw2m(ps_global->msgmap,
+! sp_first_unseen(m))))
+! ? n
+! : first_sorted_flagged(F_UNSEEN|F_UNDEL, m, pc,
+! THREADING() ? 0 : FSF_SKIP_CHID);
+! mn_set_cur(ps_global->msgmap,
+! (MsgNo) min((int) flagged, (int) first_unseen));
+!
+! }
+!
+! break;
+!
+! case IS_FIRST_IMPORTANT_OR_RECENT:
+!
+! if(IS_NEWS(ps_global->mail_stream))
+! goto first_recent;
+!
+! {
+! MsgNo flagged, first_recent;
+!
+! flagged = first_sorted_flagged(F_FLAG|F_UNDEL, m, pc,
+! THREADING() ? 0 : FSF_SKIP_CHID);
+! first_recent = first_sorted_flagged(F_RECENT | F_UNSEEN
+! | F_UNDEL,
+! m, pc,
+! THREADING() ? 0 : FSF_SKIP_CHID);
+! mn_set_cur(ps_global->msgmap,
+! (MsgNo) min((int) flagged, (int) first_recent));
+! }
+!
+! break;
+!
+! case IS_FIRST:
+! mn_set_cur(ps_global->msgmap,
+! first_sorted_flagged(F_UNDEL, m, pc,
+! THREADING() ? 0 : FSF_SKIP_CHID));
+! break;
+!
+! case IS_LAST:
+! mn_set_cur(ps_global->msgmap,
+! first_sorted_flagged(F_UNDEL, m, pc,
+! FSF_LAST | (THREADING() ? 0 : FSF_SKIP_CHID)));
+! break;
+!
+! default:
+! panic("Unexpected incoming startup case");
+! break;
+!
+! }
+! }
+! else if(IS_NEWS(ps_global->mail_stream)){
+! /*
+! * This will go to two different places depending on the FAKE_NEW
+! * feature (see pine_mail_open).
+! */
+! 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,
+! mn_get_revsort(ps_global->msgmap)
+! ? 1L
+! : mn_get_total(ps_global->msgmap));
+! }
+
+ adjust_cur_to_visible(ps_global->mail_stream, ps_global->msgmap);
+ }
+--- 8634,8657 ----
+ 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)){
+! /*
+! * This will go to two different places depending on the FAKE_NEW
+! * feature (see pine_mail_open).
+! */
+! 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,
+! mn_get_revsort(ps_global->msgmap)
+! ? 1L
+! : mn_get_total(ps_global->msgmap));
+! }
+
+ adjust_cur_to_visible(ps_global->mail_stream, ps_global->msgmap);
+ }
+***************
+*** 8284,8290 ****
+ PAT_S *pat;
+ int we_set_it = 0;
+
+! if(ps_global->mail_stream && nonempty_patterns(rflags, &pstate)){
+ for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)){
+ if(match_pattern(pat->patgrp, ps_global->mail_stream, NULL,
+ NULL, NULL, SO_NOSERVER|SE_NOPREFETCH))
+--- 8674,8683 ----
+ PAT_S *pat;
+ int we_set_it = 0;
+
+! if(find_index_rule())
+! return;
+!
+! if(ps_global->mail_stream && nonempty_patterns(rflags, &pstate)){
+ for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)){
+ if(match_pattern(pat->patgrp, ps_global->mail_stream, NULL,
+ NULL, NULL, SO_NOSERVER|SE_NOPREFETCH))
+***************
+*** 8314,8323 ****
+ PAT_S *pat;
+ SortOrder the_sort_order;
+ int sort_is_rev;
+!
+ /* set default order */
+ the_sort_order = ps_global->def_sort;
+! sort_is_rev = ps_global->def_sort_rev;
+
+ if(ps_global->mail_stream && nonempty_patterns(rflags, &pstate)){
+ for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)){
+--- 8707,8733 ----
+ 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_RULE | FOR_SORT, ps_global->cur_folder,
+! V_SORT_RULES);
+! if (rule_result && *rule_result){
+! new_sort = (SortOrder) translate(rule_result, 1);
+! is_rev = (SortOrder) translate(rule_result, 0) == EndofList ? 0 : 1;
+! fs_give((void **)&rule_result);
+! }
+! if (new_sort != EndofList){
+! the_sort_order = new_sort;
+! sort_is_rev = is_rev;
+! }
+! else{
+ /* set default order */
+ the_sort_order = ps_global->def_sort;
+! sort_is_rev = the_sort_order == SortThread
+! ? (ps_global->thread_def_sort_rev + ps_global->def_sort_rev) % 2
+! : ps_global->def_sort_rev;
+
+ if(ps_global->mail_stream && nonempty_patterns(rflags, &pstate)){
+ for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)){
+***************
+*** 8329,8340 ****
+ if(pat && pat->action && !pat->action->bogus
+ && pat->action->sort_is_set){
+ the_sort_order = pat->action->sortorder;
+! sort_is_rev = pat->action->revsort;
+ }
+ }
+
+ sort_folder(ps_global->mail_stream, ps_global->msgmap,
+! the_sort_order, sort_is_rev, flags);
+ }
+
+
+--- 8739,8756 ----
+ if(pat && pat->action && !pat->action->bogus
+ && pat->action->sort_is_set){
+ the_sort_order = pat->action->sortorder;
+! sort_is_rev = the_sort_order == SortThread
+! ? (ps_global->thread_def_sort_rev + pat->action->revsort) % 2
+! : pat->action->revsort;
+ }
+ }
++ }
++ if (ps_global->thread_cur_sort != SortArrival
++ && ps_global->thread_cur_sort != SortThread)
++ 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);
+ }
+
+
+***************
+*** 8420,8425 ****
+--- 8836,8842 ----
+ temp[MAILTMPLEN+1], buff1[MAX_SCREEN_COLS+1], *moved_msg = NULL,
+ buff2[MAX_SCREEN_COLS+1], *folder;
+ CONTEXT_S *context;
++ FOLDER_S *f;
+ struct variable *vars = ps_global->vars;
+ int ret, expunge = FALSE, no_close = 0;
+ char ing[4];
+***************
+*** 8436,8442 ****
+ }
+
+ if(stream != NULL){
+! context = sp_context(stream);
+ folder = STREAMNAME(stream);
+
+ dprint(2, (debugfile, "expunge_and_close: \"%s\"%s\n",
+--- 8853,8859 ----
+ }
+
+ if(stream != NULL){
+! context = ps_global->context_current;
+ folder = STREAMNAME(stream);
+
+ dprint(2, (debugfile, "expunge_and_close: \"%s\"%s\n",
+***************
+*** 8449,8454 ****
+--- 8866,8879 ----
+ buff1[0] = '\0';
+ buff2[0] = '\0';
+
++ if(F_OFF(F_ENABLE_FAST_RECENT,ps_global) &&
++ (f = incoming_folder_data(stream, context))){
++ new_mail_in_open_stream(stream, &(f->recent), &(f->messages));
++ f->notified = 0;
++ f->countrecent = 0L;
++ f->selected = f->user_selected;
++ }
++
+ if(!stream->rdonly){
+
+ if(!no_close){
+***************
+*** 8476,8484 ****
+ /* 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)
+ || read_msg_prompt(seen_not_del, VAR_READ_MESSAGE_FOLDER))
+ /* move inbox's read messages */
+ moved_msg = move_read_msgs(stream, VAR_READ_MESSAGE_FOLDER,
+--- 8901,8911 ----
+ /* 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)
+ || read_msg_prompt(seen_not_del, VAR_READ_MESSAGE_FOLDER))
+ /* move inbox's read messages */
+ moved_msg = move_read_msgs(stream, VAR_READ_MESSAGE_FOLDER,
+***************
+*** 10133,10138 ****
+--- 10560,10568 ----
+ 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;
+***************
+*** 10174,10181 ****
+ sprintf(buf, "Moving %s read message%s to \"%.45s\"",
+ comatose(searched), plural(searched), dstfldr);
+ we_cancel = busy_alarm(1, buf, NULL, 1);
+! if(save(ps_global, stream, save_context, dstfldr, msgmap,
+! SV_DELETE | SV_FIX_DELS) == searched)
+ strncpy(bufp = buf + 1, "Moved", 5); /* change Moving to Moved */
+
+ mn_give(&msgmap);
+--- 10604,10612 ----
+ sprintf(buf, "Moving %s read message%s to \"%.45s\"",
+ comatose(searched), plural(searched), dstfldr);
+ we_cancel = busy_alarm(1, buf, NULL, 1);
+! ps_global->exiting = 1;
+! if((save(ps_global, stream, save_context, dstfldr, msgmap,
+! SV_DELETE | SV_FIX_DELS) == searched))
+ strncpy(bufp = buf + 1, "Moved", 5); /* change Moving to Moved */
+
+ mn_give(&msgmap);
+***************
+*** 10186,10191 ****
+--- 10617,10759 ----
+ return(bufp);
+ }
+
++ char *
++ move_read_msgs_using_rules(stream, dstfldr,buf)
++ MAILSTREAM *stream;
++ char *dstfldr;
++ char *buf;
++ {
++ CONTEXT_S *save_context = NULL;
++ char **folder_to_save = NULL;
++ int num, we_cancel;
++ long i, j, success, nmsgs = 0L;
++ MSGNO_S *msgmap = NULL;
++
++ saved_stream = stream; /* horrible hack! */
++ if(!is_absolute_path(dstfldr)
++ && !(save_context = default_save_context(ps_global->context_list)))
++ save_context = ps_global->context_list;
++
++ folder_to_save = (char **)fs_get((stream->nmsgs + 1)*sizeof(char *));
++ folder_to_save[0] = NULL;
++ mn_init(&msgmap, stream->nmsgs);
++ 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(msgmap);
++ sprintf(buf, "Moving %s read message%s to \"%.45s\"",
++ comatose(num), plural(num), folder_to_save[i]);
++ we_cancel = busy_alarm(1, 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_alarm(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;
++ }
++
++ unsigned long
++ rules_cursor_pos(stream)
++ MAILSTREAM *stream;
++ {
++ MSGNO_S *msgmap = sp_msgmap(stream);
++ return rule_curpos != 0L ? rule_curpos : mn_m2raw(msgmap,mn_get_cur(msgmap));
++ }
++
++
++ MAILSTREAM *
++ find_open_stream()
++ {
++ return saved_stream;
++ }
++
++ char *
++ get_folder_to_save(stream, i, dstfldr)
++ 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_RULE | FOR_SAVE,
++ (ENVELOPE *) 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;
++ }
+
+
+ /*----------------------------------------------------------------------
+***************
+*** 10232,10238 ****
+ && ((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;
+--- 10800,10808 ----
+ && ((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;
+***************
+*** 11514,11526 ****
+
+ ----*/
+ int
+! apply_command(state, stream, msgmap, preloadkeystroke, flags, q_line)
+ struct pine *state;
+ MAILSTREAM *stream;
+ MSGNO_S *msgmap;
+ int preloadkeystroke;
+ int flags;
+ int q_line;
+ {
+ int i = 8, /* number of static entries in sel_opts3 */
+ rv = 1,
+--- 12084,12097 ----
+
+ ----*/
+ int
+! apply_command(state, stream, msgmap, preloadkeystroke, flags, q_line, display)
+ struct pine *state;
+ MAILSTREAM *stream;
+ MSGNO_S *msgmap;
+ int preloadkeystroke;
+ int flags;
+ int q_line;
++ int display;
+ {
+ int i = 8, /* number of static entries in sel_opts3 */
+ rv = 1,
+***************
+*** 11647,11655 ****
+ collapse_or_expand(state, stream, msgmap,
+ F_ON(F_SLASH_COLL_ENTIRE, ps_global)
+ ? 0L
+! : mn_get_cur(msgmap));
+ break;
+
+ case ':' :
+ select_thread_stmp(state, stream, msgmap);
+ break;
+--- 12218,12236 ----
+ collapse_or_expand(state, stream, msgmap,
+ F_ON(F_SLASH_COLL_ENTIRE, ps_global)
+ ? 0L
+! : mn_get_cur(msgmap),
+! display);
+ break;
+
++ case '[' :
++ collapse_this_thread(state, stream, msgmap, display, 0);
++ break;
++
++ case ']' :
++ expand_this_thread(state, stream, msgmap, display, 0);
++ break;
++
++
+ case ':' :
+ select_thread_stmp(state, stream, msgmap);
+ break;
+***************
+*** 12167,12172 ****
+--- 12748,12754 ----
+ SEARCHSET **msgset;
+ {
+ PINETHRD_S *nthrd, *bthrd;
++ unsigned long next, branch;
+
+ if(!(stream && thrd))
+ return;
+***************
+*** 12175,12188 ****
+ && (!(msgset && *msgset) || in_searchset(*msgset, thrd->rawno)))
+ mm_searched(stream, thrd->rawno);
+
+! if(thrd->next){
+! nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ set_search_bit_for_thread(stream, nthrd, msgset);
+ }
+
+! if(thrd->branch){
+! bthrd = fetch_thread(stream, thrd->branch);
+ if(bthrd)
+ set_search_bit_for_thread(stream, bthrd, msgset);
+ }
+--- 12757,12770 ----
+ && (!(msgset && *msgset) || in_searchset(*msgset, thrd->rawno)))
+ mm_searched(stream, thrd->rawno);
+
+! if(next= get_next(stream, thrd)){
+! nthrd = fetch_thread(stream, next);
+ if(nthrd)
+ set_search_bit_for_thread(stream, nthrd, msgset);
+ }
+
+! if(branch = get_branch(stream, thrd)){
+! bthrd = fetch_thread(stream, branch);
+ if(bthrd)
+ set_search_bit_for_thread(stream, bthrd, msgset);
+ }
+***************
+*** 12390,12396 ****
+ {
+ int r, type, we_cancel = 0, not = 0, flags, old_imap;
+ char sstring[80], savedsstring[80], origcharset[16], tmp[128];
+! char *sval = NULL, *cset = NULL, *charset = NULL;
+ char buftmp[MAILTMPLEN];
+ ESCKEY_S ekey[4];
+ ENVELOPE *env = NULL;
+--- 12972,12978 ----
+ {
+ int r, type, we_cancel = 0, not = 0, flags, old_imap;
+ char sstring[80], savedsstring[80], origcharset[16], tmp[128];
+! char namehdr[80], *sval = NULL, *cset = NULL, *charset = NULL;
+ char buftmp[MAILTMPLEN];
+ ESCKEY_S ekey[4];
+ ENVELOPE *env = NULL;
+***************
+*** 12464,12469 ****
+--- 13046,13085 ----
+ sval = "BODYTEXT";
+ break;
+
++ case 'h' :
++ sprintf(tmp, "Name of HEADER to match : ");
++ flags = OE_APPEND_CURRENT;
++ namehdr[0] = '\0';
++ r = 'x';
++ while (r == 'x'){
++ int done = 0;
++
++ r = optionally_enter(namehdr, -FOOTER_ROWS(ps_global), 0,
++ sizeof(namehdr), tmp, ekey, NO_HELP, &flags);
++ if (r == 1){
++ cmd_cancelled("Selection by text");
++ return(1);
++ }
++ removing_leading_white_space(namehdr);
++ while(!done){
++ while ((namehdr[0] != '\0') && /* remove trailing ":" */
++ (namehdr[strlen(namehdr) - 1] == ':'))
++ namehdr[strlen(namehdr) - 1] = '\0';
++ if ((namehdr[0] != '\0')
++ && isspace((unsigned char) namehdr[strlen(namehdr) - 1]))
++ removing_trailing_white_space(namehdr);
++ else
++ done++;
++ }
++ if (strchr(namehdr,' ') || strchr(namehdr,'\t') ||
++ strchr(namehdr,':'))
++ namehdr[0] = '\0';
++ if (namehdr[0] == '\0')
++ r = 'x';
++ }
++ sval = namehdr;
++ break;
++
+ case 'x':
+ break;
+
+***************
+*** 12587,12592 ****
+--- 13203,13211 ----
+ }
+
+ switch(type){
++ case 'h' : /* Any header */
++ pgm->header = mail_newsearchheader (namehdr,sstring);
++ break;
+ case 'r' : /* TO or CC */
+ if(old_imap){
+ /* No OR on old servers */
+***************
+*** 13764,13777 ****
+ Returns 0 if it was cancelled, 1 otherwise.
+ ----*/
+ int
+! select_sort(state, ql, sort, rev)
+ struct pine *state;
+ int ql;
+ SortOrder *sort;
+ int *rev;
+ {
+ char prompt[200], tmp[3], *p;
+! int s, i;
+ int deefault = 'a', retval = 1;
+ HelpType help;
+ ESCKEY_S sorts[14];
+--- 14383,14397 ----
+ Returns 0 if it was cancelled, 1 otherwise.
+ ----*/
+ int
+! select_sort(state, ql, sort, rev, thread)
+ struct pine *state;
+ int ql;
+ SortOrder *sort;
+ int *rev;
++ int thread;
+ {
+ char prompt[200], tmp[3], *p;
+! int s, i, j;
+ int deefault = 'a', retval = 1;
+ HelpType help;
+ ESCKEY_S sorts[14];
+***************
+*** 13805,13821 ****
+ strncpy(prompt, "Choose type of sort, or 'R' to reverse current sort : ",
+ sizeof(prompt));
+
+! for(i = 0; state->sort_types[i] != EndofList; i++) {
+! sorts[i].rval = i;
+! p = sorts[i].label = sort_name(state->sort_types[i]);
+! while(*(p+1) && islower((unsigned char)*p))
+! p++;
+!
+! sorts[i].ch = tolower((unsigned char)(tmp[0] = *p));
+! sorts[i].name = cpystr(tmp);
+!
+! if(mn_get_sort(state->msgmap) == state->sort_types[i])
+! deefault = sorts[i].rval;
+ }
+
+ sorts[i].ch = 'r';
+--- 14425,14451 ----
+ strncpy(prompt, "Choose type of sort, or 'R' to reverse current sort : ",
+ sizeof(prompt));
+
+! for(i = 0, j = 0; state->sort_types[i] != EndofList; i++) {
+! sorts[i].rval = i;
+! sorts[i].name = cpystr("");
+! sorts[i].label = "";
+! sorts[i].ch = -2;
+! if (!thread || state->sort_types[i] == SortArrival
+! || state->sort_types[i] == SortThread){
+! p = sorts[j].label = sort_name(state->sort_types[i]);
+! while(*(p+1) && islower((unsigned char)*p))
+! p++;
+! sorts[j].ch = tolower((unsigned char)(tmp[0] = *p));
+! sorts[j++].name = cpystr(tmp);
+! }
+!
+! if (thread){
+! if (state->thread_def_sort == state->sort_types[i])
+! deefault = sorts[j-1].rval;
+! }
+! else
+! if(mn_get_sort(state->msgmap) == state->sort_types[i])
+! deefault = sorts[i].rval;
+ }
+
+ sorts[i].ch = 'r';
+***************
+*** 13840,13846 ****
+ if(s == 'r')
+ *rev = !mn_get_revsort(state->msgmap);
+ else
+! *sort = state->sort_types[s];
+
+ if(F_ON(F_SHOW_SORT, ps_global))
+ ps_global->mangled_header = 1;
+--- 14470,14476 ----
+ if(s == 'r')
+ *rev = !mn_get_revsort(state->msgmap);
+ else
+! *sort = state->sort_types[thread ? (s == 0 ? 1 : 9) : s];
+
+ if(F_ON(F_SHOW_SORT, ps_global))
+ ps_global->mangled_header = 1;
+***************
+*** 13854,13859 ****
+--- 14484,14492 ----
+ fs_give((void **)&sorts[i].name);
+
+ blank_keymenu(ps_global->ttyo->screen_rows - 2, 0);
++ if(*sort == SortScore)
++ scores_are_used(SCOREUSE_INVALID);
++
+ return(retval);
+ }
+
+***************
+*** 14524,14526 ****
+--- 15157,15855 ----
+ return(flag_submenu);
+ }
+ #endif /* _WINDOWS */
++
++ /* Extra Fancy Thread support */
++
++ long
++ top_thread(stream, rawmsgno)
++ MAILSTREAM *stream;
++ long rawmsgno;
++ {
++ PINETHRD_S *thrd = NULL;
++ unsigned long rawno;
++
++ if(!stream)
++ return -1L;
++
++ if(rawmsgno)
++ thrd = fetch_thread(stream, rawmsgno);
++
++ if(!thrd)
++ return -1L;
++
++ return F_ON(F_ENHANCED_THREAD, ps_global)
++ ? (thrd->toploose ? thrd->toploose : thrd->top)
++ : thrd->top;
++ }
++
++ void
++ move_top_thread(stream, msgmap, rawmsgno)
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ long rawmsgno;
++ {
++ mn_set_cur(msgmap,mn_raw2m(msgmap, top_thread(stream, rawmsgno)));
++ }
++
++ long
++ top_this_thread(stream, rawmsgno)
++ MAILSTREAM *stream;
++ long rawmsgno;
++ {
++ PINETHRD_S *thrd = NULL;
++ unsigned long rawno;
++
++ if(!stream)
++ return -1L;
++
++ if(rawmsgno)
++ thrd = fetch_thread(stream, rawmsgno);
++
++ if(!thrd)
++ return -1L;
++
++ return thrd->top;
++ }
++
++ void
++ move_top_this_thread(stream, msgmap, rawmsgno)
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ long rawmsgno;
++ {
++ mn_set_cur(msgmap,mn_raw2m(msgmap, top_this_thread(stream, rawmsgno)));
++ }
++
++
++ void
++ cmd_delete_this_thread(state, stream, msgmap)
++ struct pine *state;
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ {
++ unsigned long rawno, top, save_kolapsed;
++ PINETHRD_S *thrd = NULL, *nxthrd;
++
++ if(!stream)
++ return;
++
++ rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ move_top_this_thread(stream, msgmap, rawno);
++ top = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ if(top)
++ thrd = fetch_thread(stream, top);
++
++ if(!thrd)
++ return;
++
++ save_kolapsed = this_thread_is_kolapsed(state, stream, msgmap, top);
++ collapse_this_thread(state, stream, msgmap, 0, 0);
++ thread_command(state, stream, msgmap, 'd', -FOOTER_ROWS(state), 1);
++ if (!save_kolapsed)
++ expand_this_thread(state, stream, msgmap, 0, 0);
++ }
++
++ void
++ cmd_delete_thread(state, stream, msgmap)
++ struct pine *state;
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ {
++ unsigned long rawno, top, orig_top, topnxt, save_kolapsed;
++ PINETHRD_S *thrd = NULL, *nxthrd;
++ int done = 0, count;
++
++ if(!stream)
++ return;
++
++ rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ move_top_thread(stream, msgmap, rawno);
++ top = orig_top = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ if(top)
++ thrd = fetch_thread(stream, top);
++
++ if(!thrd)
++ return;
++
++ while (!done){
++ cmd_delete_this_thread(state, stream, msgmap);
++ if (F_OFF(F_ENHANCED_THREAD, state)
++ || (move_next_this_thread(state, stream, msgmap, 0) <= 0)
++ || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap)))
++ || (orig_top != top_thread(stream, top)))
++ done++;
++ }
++ mn_set_cur(msgmap,mn_raw2m(msgmap, rawno));
++ cmd_delete(state, msgmap, 0, MsgIndx);
++ count = count_thread(state, stream, msgmap, rawno);
++ q_status_message2(SM_ORDER, 0, 1, "%s message%s marked deleted",
++ int2string(count), plural(count));
++ }
++
++
++
++ int
++ thread_is_kolapsed(state, stream, msgmap, rawmsgno)
++ struct pine *state;
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ long rawmsgno;
++ {
++ int collapsed;
++ PINETHRD_S *thrd = NULL;
++ unsigned long rawno, orig, orig_rawno;
++
++ if(!stream)
++ return -1;
++
++ orig = mn_get_cur(msgmap);
++ move_top_thread(stream, msgmap, rawmsgno);
++ rawno = orig_rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ if(rawno)
++ thrd = fetch_thread(stream, rawno);
++
++ if(!thrd)
++ return -1;
++
++ while(collapsed = this_thread_is_kolapsed(state, stream, msgmap, rawno))
++ if (F_OFF(F_ENHANCED_THREAD, state)
++ || (move_next_this_thread(state, stream, msgmap, 0) <= 0)
++ || !(rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)))
++ || (orig_rawno != top_thread(stream, rawno)))
++ break;
++
++ mn_set_cur(msgmap,orig); /* return home */
++
++ return collapsed;
++ }
++
++ /* this function tells us if the thread (or branch in the case of loose threads)
++ * is collapsed
++ */
++
++ int
++ this_thread_is_kolapsed(state, stream, msgmap, rawmsgno)
++ struct pine *state;
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ long rawmsgno;
++ {
++ int collapsed;
++ PINETHRD_S *thrd = NULL;
++ unsigned long rawno, orig;
++
++ if(!stream)
++ return -1;
++
++ rawno = rawmsgno;
++ if(rawno)
++ thrd = fetch_thread(stream, rawno);
++
++ if(!thrd)
++ return -1;
++
++ collapsed = get_lflag(stream, NULL, rawno, MN_COLL | MN_CHID);
++
++ if (!thrd->next){
++ if (thrd->rawno != top_thread(stream, thrd->rawno))
++ collapsed = get_lflag(stream, NULL, rawno, MN_CHID);
++ else
++ collapsed = get_lflag(stream, NULL, rawno, MN_COLL);
++ }
++
++ return collapsed;
++ }
++
++ int
++ collapse_this_thread(state, stream, msgmap, display, special)
++ struct pine *state;
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ int display;
++ int special;
++ {
++ int collapsed, rv = 1, done = 0;
++ PINETHRD_S *thrd = NULL, *nthrd;
++ unsigned long rawno, orig, msgno;
++
++ if(!stream)
++ return 0;
++
++ rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
++
++ if(rawno)
++ thrd = fetch_thread(stream, rawno);
++
++ if(!thrd)
++ return rv;
++
++ collapsed = this_thread_is_kolapsed(state, stream, msgmap, rawno);
++
++ if (special && collapsed){
++ expand_this_thread(state, stream, msgmap, 0, 0);
++ collapsed = 0;
++ }
++
++ clear_index_cache_ent(mn_raw2m(msgmap,rawno));
++
++ if (!collapsed && thrd->next){
++ if (thrd->rawno == top_thread(stream, thrd->rawno))
++ collapse_or_expand(state, stream, msgmap, mn_get_cur(msgmap), display);
++ else{
++ set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno), MN_COLL, 1);
++ set_thread_subtree(stream, thrd, msgmap, 1, MN_CHID);
++ }
++ }
++ else{
++ if (!collapsed && special
++ && ((F_OFF(F_ENHANCED_THREAD, state) && !thrd->next)
++ || F_ON(F_ENHANCED_THREAD, state))){
++ if (thrd->toploose){
++ if (thrd->rawno != thrd->toploose)
++ set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno),MN_CHID,
++ 1);
++ else
++ set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno),MN_COLL,
++ 1);
++ }
++ }
++ else{
++ rv = 0;
++ if (display)
++ q_status_message(SM_ORDER, 0, 1, "Thread already collapsed");
++ }
++ }
++ return rv;
++ }
++
++ void
++ collapse_thread(state, stream, msgmap, display)
++ struct pine *state;
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ int display;
++ {
++ int collapsed, rv = 1, done = 0;
++ PINETHRD_S *thrd = NULL;
++ unsigned long orig, orig_top, top;
++
++ if(!stream)
++ return;
++
++ expand_this_thread(state, stream, msgmap, display, 1);
++ orig = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ move_top_thread(stream, msgmap,orig);
++ top = orig_top = mn_m2raw(msgmap, mn_get_cur(msgmap));
++
++ if(top)
++ thrd = fetch_thread(stream, top);
++
++ if(!thrd)
++ return;
++
++ while (!done){
++ collapse_this_thread(state, stream, msgmap, display, 1);
++ if (F_OFF(F_ENHANCED_THREAD, state)
++ || (move_next_this_thread(state, stream, msgmap, 0) <= 0)
++ || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap)))
++ || (orig_top != top_thread(stream, top)))
++ done++;
++ }
++ mn_set_cur(msgmap,mn_raw2m(msgmap, orig_top));
++ }
++
++ int
++ expand_this_thread(state, stream, msgmap, display, special)
++ struct pine *state;
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ int display;
++ int special;
++ {
++ int collapsed, rv = 1, done = 0;
++ PINETHRD_S *thrd = NULL, *nthrd;
++ unsigned long rawno, orig, msgno;
++
++ if(!stream)
++ return 0;
++
++ orig = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ move_top_this_thread(stream, msgmap,orig);
++ rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
++
++ if(rawno)
++ thrd = fetch_thread(stream, rawno);
++
++ if(!thrd)
++ return rv;
++
++ collapsed = this_thread_is_kolapsed(state, stream, msgmap, rawno);
++
++ if (special && !collapsed){
++ collapse_this_thread(state, stream, msgmap, 0, 0);
++ collapsed = 1;
++ }
++
++ clear_index_cache_ent(mn_raw2m(msgmap,rawno));
++
++ if (collapsed && thrd->next){
++ if (thrd->rawno == top_thread(stream, thrd->rawno))
++ collapse_or_expand(state, stream, msgmap, mn_get_cur(msgmap), display);
++ else{
++ set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno), MN_COLL, 0);
++ set_thread_subtree(stream, thrd, msgmap, 0, MN_CHID);
++ }
++ }
++ else{
++ if (collapsed && special
++ && ((F_OFF(F_ENHANCED_THREAD, state) && !thrd->next)
++ || F_ON(F_ENHANCED_THREAD, state))){
++ if (thrd->toploose)
++ if (thrd->rawno != thrd->toploose)
++ set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno),MN_CHID, 0);
++ else
++ set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno),MN_COLL, 0);
++ }
++ else{
++ rv = 0;
++ if (display)
++ q_status_message(SM_ORDER, 0, 1, "Thread already expanded");
++ }
++ }
++ return rv;
++ }
++
++ void
++ expand_thread(state, stream, msgmap, display)
++ struct pine *state;
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ int display;
++ {
++ int collapsed, rv = 1, done = 0;
++ PINETHRD_S *thrd = NULL;
++ unsigned long orig, orig_top, top;
++
++ if(!stream)
++ return;
++
++ orig = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ top = orig_top = mn_m2raw(msgmap, mn_get_cur(msgmap));
++
++ if(top)
++ thrd = fetch_thread(stream, top);
++
++ if(!thrd)
++ return;
++
++ while (!done){
++ expand_this_thread(state, stream, msgmap, display, 1);
++ if (F_OFF(F_ENHANCED_THREAD, state)
++ || (move_next_this_thread(state, stream, msgmap, 0) <= 0)
++ || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap)))
++ || (orig_top != top_thread(stream, top)))
++ done++;
++ }
++ mn_set_cur(msgmap,mn_raw2m(msgmap, orig_top));
++ }
++
++
++ void
++ cmd_undelete_this_thread(state, stream, msgmap)
++ struct pine *state;
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ {
++ unsigned long rawno;
++ int save_kolapsed;
++
++ rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ save_kolapsed = this_thread_is_kolapsed(state, stream, msgmap, rawno);
++ collapse_this_thread(state, stream, msgmap, 0, 0);
++ thread_command(state, stream, msgmap, 'u', -FOOTER_ROWS(state), 1);
++ if (!save_kolapsed)
++ expand_this_thread(state, stream, msgmap, 0, 0);
++ }
++
++ void
++ cmd_undelete_thread(state, stream, msgmap)
++ struct pine *state;
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ {
++ PINETHRD_S *thrd = NULL;
++ unsigned long rawno, top, orig_top;
++ int done = 0, count;
++
++ rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ move_top_thread(stream, msgmap, rawno);
++ top = orig_top = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ if(top)
++ thrd = fetch_thread(stream, top);
++
++ if(!thrd)
++ return;
++
++ while (!done){
++ cmd_undelete_this_thread(state, stream, msgmap);
++ if (F_OFF(F_ENHANCED_THREAD, state)
++ || (move_next_this_thread(state, stream, msgmap, 0) <= 0)
++ || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap)))
++ || (orig_top != top_thread(stream, top)))
++ done++;
++ }
++ mn_set_cur(msgmap,mn_raw2m(msgmap, rawno));
++ count = count_thread(state, stream, msgmap, rawno);
++ q_status_message2(SM_ORDER, 0, 1, "Deletion mark removed from %s message%s",
++ int2string(count), plural(count));
++ }
++
++ void
++ kolapse_thread(state, stream, msgmap, ch, display)
++ struct pine *state;
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ char ch;
++ int display;
++ {
++ PINETHRD_S *thrd = NULL;
++ unsigned long rawno;
++ int rv = 1, done = 0;
++
++ if(!stream)
++ return;
++
++ rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ if(rawno)
++ thrd = fetch_thread(stream, rawno);
++
++ if(!thrd)
++ return;
++
++ clear_index_cache();
++ mn_set_cur(msgmap,1); /* go to the first message */
++ while (!done){
++ if (ch == '[')
++ collapse_thread(state, stream, msgmap, display);
++ else
++ expand_thread(state, stream, msgmap, display);
++ if ((rv = move_next_thread(state, stream, msgmap, 0)) <= 0)
++ done++;
++ }
++
++ if (rv < 0){
++ if (display)
++ q_status_message(SM_ORDER, 0, 1, (ch == '[')
++ ? "Error while collapsing thread"
++ : "Error while expanding thread");
++ }
++ else
++ if(display)
++ q_status_message(SM_ORDER, 0, 1, (ch == '[')
++ ? "All threads collapsed. Use \"}\" to expand them"
++ : "All threads expanded. Use \"{\" to collapse them");
++
++ mn_set_cur(msgmap,mn_raw2m(msgmap, top_thread(stream,rawno)));
++ }
++
++ int
++ move_next_this_thread(state, stream, msgmap, display)
++ struct pine *state;
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ int display;
++ {
++ PINETHRD_S *thrd = NULL, *thrdnxt;
++ unsigned long rawno, top;
++ int rv = 1;
++
++ if(!stream)
++ return -1;
++
++ rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ if(rawno)
++ thrd = fetch_thread(stream, rawno);
++
++ if(!thrd)
++ return -1;
++
++ top = top_thread(stream, rawno);
++
++ thrdnxt = (top == rawno) ? fetch_thread(stream, top) : thrd;
++ if (thrdnxt->nextthd)
++ mn_set_cur(msgmap,mn_raw2m(msgmap, thrdnxt->nextthd));
++ else{
++ rv = 0;
++ if (display)
++ q_status_message(SM_ORDER, 0, 1, "No more Threads to advance");
++ }
++ return rv;
++ }
++
++ int
++ move_next_thread(state, stream, msgmap, display)
++ struct pine *state;
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ int display;
++ {
++ int collapsed, rv = 1, done = 0;
++ PINETHRD_S *thrd = NULL;
++ unsigned long orig, orig_top, top;
++
++ if(!stream)
++ return 0;
++
++ orig = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ move_top_thread(stream, msgmap,orig);
++ top = orig_top = mn_m2raw(msgmap, mn_get_cur(msgmap));
++
++ if(top)
++ thrd = fetch_thread(stream, top);
++
++ if(!thrd)
++ return 0;
++
++ while (rv > 0 && !done){
++ rv = move_next_this_thread(state, stream, msgmap, display);
++ if (F_OFF(F_ENHANCED_THREAD, state)
++ || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap)))
++ || (orig_top != top_thread(stream, top)))
++ done++;
++ }
++ if (display){
++ if (rv > 0 && SEP_THRDINDX())
++ q_status_message(SM_ORDER, 0, 2, "Viewing next thread");
++ if (!rv)
++ q_status_message(SM_ORDER, 0, 2, "No more threads to advance");
++ }
++ if(rv <= 0){
++ rv = 0;
++ mn_set_cur(msgmap, mn_raw2m(msgmap, orig));
++ }
++
++ return rv;
++ }
++
++ int
++ move_prev_thread(state, stream, msgmap, display)
++ struct pine *state;
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ int display;
++ {
++ PINETHRD_S *thrd = NULL;
++ unsigned long rawno, top;
++ int rv = 1;
++
++ if(!stream)
++ return -1;
++
++ rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ if(rawno)
++ thrd = fetch_thread(stream, rawno);
++
++ if(!thrd)
++ return -1;
++
++ top = top_thread(stream, rawno);
++
++ if (top != rawno)
++ mn_set_cur(msgmap,mn_raw2m(msgmap, top));
++ else if (thrd->prevthd)
++ mn_set_cur(msgmap,mn_raw2m(msgmap, top_thread(stream,thrd->prevthd)));
++ else
++ rv = 0;
++ if (display){
++ if (rv && SEP_THRDINDX())
++ q_status_message(SM_ORDER, 0, 2, "Viewing previous thread");
++ if (!rv)
++ q_status_message(SM_ORDER, 0, 2, "No more threads to go back");
++ }
++
++ return rv;
++ }
++
++ void
++ cmd_select_thread(state, stream, msgmap)
++ struct pine *state;
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ {
++ unsigned long rawno;
++ int save_kolapsed;
++
++ rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ save_kolapsed = thread_is_kolapsed(state, stream, msgmap, rawno);
++ collapse_thread(state, stream, msgmap, 0);
++ thread_command(state, stream, msgmap, ':', -FOOTER_ROWS(state), 1);
++ if (!save_kolapsed)
++ expand_thread(state, stream, msgmap, 0);
++ }
++
++ /*
++ * This function assumes that it is called at a top of a thread in its
++ * first call
++ */
++
++ int
++ count_this_thread(stream, rawno)
++ MAILSTREAM *stream;
++ unsigned long rawno;
++ {
++ unsigned long top, orig_top, topnxt;
++ PINETHRD_S *thrd = NULL;
++ int count = 1;
++
++ if(!stream)
++ return 0;
++
++ if(rawno)
++ thrd = fetch_thread(stream, rawno);
++
++ if(!thrd)
++ return 0;
++
++ if (thrd->next)
++ count += count_this_thread(stream, thrd->next);
++
++ if (thrd->branch)
++ count += count_this_thread(stream, thrd->branch);
++
++ return count;
++ }
++
++ int
++ count_thread(state, stream, msgmap, rawno)
++ struct pine *state;
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ long rawno;
++ {
++ unsigned long top, orig, orig_top;
++ PINETHRD_S *thrd = NULL;
++ int done = 0, count = 0;
++
++ if(!stream)
++ return 0;
++
++ orig = mn_m2raw(msgmap, mn_get_cur(msgmap));
++ move_top_thread(stream, msgmap,rawno);
++ top = orig_top = top_thread(stream, rawno);
++ if(top)
++ thrd = fetch_thread(stream, top);
++
++ if(!thrd)
++ return 0;
++
++ while (!done){
++ count += count_this_thread(stream, top);
++ if (F_OFF(F_ENHANCED_THREAD, state)
++ || (move_next_this_thread(state, stream, msgmap, 0) <= 0)
++ || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap)))
++ || (orig_top != top_thread(stream, top)))
++ done++;
++ }
++ mn_set_cur(msgmap,mn_raw2m(msgmap, orig));
++ return count;
++ }
+diff -rc pine4.63/pine/mailindx.c pine4.63.I.USE/pine/mailindx.c
+*** pine4.63/pine/mailindx.c Wed Apr 27 11:55:00 2005
+--- pine4.63.I.USE/pine/mailindx.c Thu May 19 19:57:34 2005
+***************
+*** 112,120 ****
+ RCOMPOSE_MENU,
+ HOMEKEY_MENU,
+ ENDKEY_MENU,
+! NULL_MENU,
+ {"/","Collapse/Expand",{MC_COLLAPSE,1,{'/'}},KS_NONE},
+! NULL_MENU,
+ NULL_MENU};
+ INST_KEY_MENU(index_keymenu, index_keys);
+ #define BACK_KEY 2
+--- 112,133 ----
+ RCOMPOSE_MENU,
+ HOMEKEY_MENU,
+ ENDKEY_MENU,
+! {"K","Sort Thread",{MC_SORTHREAD,1,{'k'}},KS_NONE},
+ {"/","Collapse/Expand",{MC_COLLAPSE,1,{'/'}},KS_NONE},
+! {"{","Collapse All",{MC_KOLAPSE,1,{'{'}},KS_NONE},
+! {"}","Expand All", {MC_EXPTHREAD,1,{'}'}},KS_NONE},
+!
+! HELP_MENU,
+! OTHER_MENU,
+! {")","Next Threa",{MC_NEXTHREAD,1,{')'}},KS_NONE},
+! {"(","Prev Threa",{MC_PRETHREAD,1,{'('}},KS_NONE},
+! {"^D","Delete Thr",{MC_DELTHREAD,1,{ctrl('D')}},KS_NONE},
+! {"^U","Undel Thre",{MC_UNDTHREAD,1,{ctrl('U')}},KS_NONE},
+! {"^T","Select Thr",{MC_SELTHREAD,1,{ctrl('T')}},KS_NONE},
+! {"^H","ChkIncFl",{MC_FORCECHECK,1,{ctrl('H')}},KS_NONE},
+! {"[","Close Thre",{MC_CTHREAD,1,{'['}},KS_NONE},
+! {"]","Open Threa",{MC_OTHREAD,1,{']'}},KS_NONE},
+! QUOTA_MENU,
+ NULL_MENU};
+ INST_KEY_MENU(index_keymenu, index_keys);
+ #define BACK_KEY 2
+***************
+*** 197,205 ****
+ RCOMPOSE_MENU,
+ HOMEKEY_MENU,
+ ENDKEY_MENU,
+! NULL_MENU,
+ {"/","Collapse/Expand",{MC_COLLAPSE,1,{'/'}},KS_NONE},
+ NULL_MENU,
+ NULL_MENU};
+ INST_KEY_MENU(thread_keymenu, thread_keys);
+
+--- 210,231 ----
+ RCOMPOSE_MENU,
+ HOMEKEY_MENU,
+ ENDKEY_MENU,
+! {"]","Open Threa",{MC_OTHREAD,1,{']'}},KS_NONE},
+ {"/","Collapse/Expand",{MC_COLLAPSE,1,{'/'}},KS_NONE},
++ {")","Next Threa",{MC_NEXTHREAD,1,{')'}},KS_NONE},
++ {"(","Prev Threa",{MC_PRETHREAD,1,{'('}},KS_NONE},
++
++ HELP_MENU,
++ OTHER_MENU,
+ NULL_MENU,
++ NULL_MENU,
++ {"^D","Delete Thr",{MC_DELTHREAD,1,{ctrl('D')}},KS_NONE},
++ {"^U","Undel Thre",{MC_UNDTHREAD,1,{ctrl('U')}},KS_NONE},
++ {"^T","Select Thr",{MC_SELTHREAD,1,{ctrl('T')}},KS_NONE},
++ NULL_MENU,
++ {"^H","ChkIncFl",{MC_FORCECHECK,1,{ctrl('H')}},KS_NONE},
++ QUOTA_MENU,
++ {"K","Sort Thread",{MC_SORTHREAD,1,{'k'}},KS_NONE},
+ NULL_MENU};
+ INST_KEY_MENU(thread_keymenu, thread_keys);
+
+***************
+*** 315,326 ****
+
+ HLINE_S *(*format_index_line) PROTO((INDEXDATA_S *));
+ void (*setup_header_widths) PROTO((void));
+!
+
+
+ /*
+ * Internal prototypes
+ */
+ void index_index_screen PROTO((struct pine *));
+ void thread_index_screen PROTO((struct pine *));
+ void setup_for_index_index_screen PROTO((void));
+--- 341,357 ----
+
+ HLINE_S *(*format_index_line) PROTO((INDEXDATA_S *));
+ void (*setup_header_widths) PROTO((void));
+! static int erase_thread_info = 1;
+
+
+ /*
+ * Internal prototypes
+ */
++ SortOrder translate PROTO ((char *, int));
++ ENVELOPE *make_envelope PROTO ((INDEXDATA_S *, int));
++ char *find_value PROTO ((char *,char *, int, char *, int, char *, int, INDEXDATA_S *, int));
++ int find_index_rule PROTO((void));
++ void setup_threading_display_style PROTO((void));
+ void index_index_screen PROTO((struct pine *));
+ void thread_index_screen PROTO((struct pine *));
+ void setup_for_index_index_screen PROTO((void));
+***************
+*** 346,351 ****
+--- 377,390 ----
+ void index_data_env PROTO((INDEXDATA_S *, ENVELOPE *));
+ int set_index_addr PROTO((INDEXDATA_S *, char *, ADDRESS *,
+ char *, int, char *));
++ unsigned long get_next PROTO((MAILSTREAM *,PINETHRD_S *));
++ unsigned long get_branch PROTO((MAILSTREAM *,PINETHRD_S *));
++ long get_length_branch PROTO((MAILSTREAM *, long));
++ THREADNODE *copy_tree PROTO((THREADNODE *));
++ void find_msgmap PROTO((MAILSTREAM *, MSGNO_S *, int, SortOrder,
++ unsigned));
++ void move_thread PROTO((struct pine *, MAILSTREAM *, MSGNO_S *, int));
++ void relink_threads PROTO((MAILSTREAM *, MSGNO_S *, long *));
+ int i_cache_size PROTO((long));
+ int i_cache_width PROTO(());
+ int ctype_is_fixed_length PROTO((IndexColType));
+***************
+*** 390,406 ****
+ struct pass_along
+ *sort_thread_flatten PROTO((THREADNODE *, MAILSTREAM *,
+ struct pass_along *,
+! PINETHRD_S *, unsigned));
+ void make_thrdflags_consistent PROTO((MAILSTREAM *, MSGNO_S *,
+ PINETHRD_S *, int));
+ THREADNODE *collapse_threadnode_tree PROTO((THREADNODE *));
+ PINETHRD_S *msgno_thread_info PROTO((MAILSTREAM *, unsigned long,
+ PINETHRD_S *, unsigned));
+ long calculate_visible_threads PROTO((MAILSTREAM *));
+ void set_thread_subtree PROTO((MAILSTREAM *, PINETHRD_S *,
+ MSGNO_S *, int, int));
+ void thread_command PROTO((struct pine *, MAILSTREAM *, MSGNO_S *,
+! int, int));
+ void set_flags_for_thread PROTO((MAILSTREAM *, MSGNO_S *, int,
+ PINETHRD_S *, int));
+ unsigned long count_flags_in_thread PROTO((MAILSTREAM *, PINETHRD_S *, long));
+--- 429,447 ----
+ struct pass_along
+ *sort_thread_flatten PROTO((THREADNODE *, MAILSTREAM *,
+ struct pass_along *,
+! PINETHRD_S *, unsigned, int,
+! long,long));
+ void make_thrdflags_consistent PROTO((MAILSTREAM *, MSGNO_S *,
+ PINETHRD_S *, int));
+ THREADNODE *collapse_threadnode_tree PROTO((THREADNODE *));
++ THREADNODE *copy_tree PROTO((THREADNODE *));
+ PINETHRD_S *msgno_thread_info PROTO((MAILSTREAM *, unsigned long,
+ PINETHRD_S *, unsigned));
+ long calculate_visible_threads PROTO((MAILSTREAM *));
+ void set_thread_subtree PROTO((MAILSTREAM *, PINETHRD_S *,
+ MSGNO_S *, int, int));
+ void thread_command PROTO((struct pine *, MAILSTREAM *, MSGNO_S *,
+! int, int, int));
+ void set_flags_for_thread PROTO((MAILSTREAM *, MSGNO_S *, int,
+ PINETHRD_S *, int));
+ unsigned long count_flags_in_thread PROTO((MAILSTREAM *, PINETHRD_S *, long));
+***************
+*** 592,600 ****
+--- 633,644 ----
+ return;
+ }
+
++ state->redrawer = redraw_index_body;
+ 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)
+ unview_thread(state, state->mail_stream, state->msgmap);
+***************
+*** 702,720 ****
+ MAILSTREAM *stream;
+ MSGNO_S *msgmap;
+ {
+! int ch, cmd, which_keys, force,
+ cur_row, cur_col, km_popped, paint_status;
+ int old_day = -1;
+! long i, j, k, old_max_msgno;
+ IndexType style, old_style = MsgIndex;
+ struct index_state id;
+ struct key_menu *km = NULL;
+ #if defined(DOS) || defined(OS2)
+ extern void (*while_waiting)();
+ #endif
+
+ dprint(1, (debugfile, "\n\n ---- INDEX MANAGER ----\n"));
+!
+ ch = 'x'; /* For displaying msg 1st time thru */
+ force = 0;
+ km_popped = 0;
+--- 746,770 ----
+ MAILSTREAM *stream;
+ MSGNO_S *msgmap;
+ {
+! int ch, cmd, which_keys, force, skip = 0,
+ cur_row, cur_col, km_popped, paint_status;
+ int old_day = -1;
+! long i, j, k, old_max_msgno, nm;
+ IndexType style, old_style = MsgIndex;
+ struct index_state id;
+ struct key_menu *km = NULL;
++ FOLDER_S *f;
+ #if defined(DOS) || defined(OS2)
+ extern void (*while_waiting)();
+ #endif
+
+ dprint(1, (debugfile, "\n\n ---- INDEX MANAGER ----\n"));
+! if (f = incoming_folder_data(stream, cntxt)){
+! f->selected = f->user_selected; /* unselect this folder now */
+! f->origrecent = stream->recent; /* more accurate than f->recent */
+! f->notified = 1; /* no updates in this screen */
+! f->countrecent = 0;
+! }
+ ch = 'x'; /* For displaying msg 1st time thru */
+ force = 0;
+ km_popped = 0;
+***************
+*** 749,757 ****
+ }
+
+ /*------- Check for new mail -------*/
+! new_mail(force, NM_TIMING(ch), NM_STATUS_MSG);
+! force = 0; /* may not need to next time around */
+!
+ /*
+ * If the width of the message number field in the display changes
+ * we need to flush the cache and redraw. When the cache is cleared
+--- 799,822 ----
+ }
+
+ /*------- Check for new mail -------*/
+! nm = new_mail(force, NM_TIMING(ch), NM_STATUS_MSG);
+! if (!skip || nm > 0L){
+! if(nm > 0L)
+! state->force_check_now = 1;
+! if(f)
+! f->notified = 1;
+! new_mail_incfolder(state, MC_IFAUTOCHECK);
+! }
+! if (f){
+! long rec, tot;
+! new_mail_in_open_stream(stream, &rec, &tot);
+! f->countrecent = rec > f->recent ? rec - f->countrecent : 0;
+! f->selected = f->user_selected;
+! f->recent = rec;
+! f->messages = tot;
+! }
+! ps_global->refresh_list = 0; /* reset refresh_list */
+! force = skip = 0; /* may not need to next time around */
+ /*
+ * If the width of the message number field in the display changes
+ * we need to flush the cache and redraw. When the cache is cleared
+***************
+*** 943,948 ****
+--- 1008,1016 ----
+ break;
+ }
+
++ if ((cmd != MC_NONE) && (cmd != MC_FORCECHECK))
++ state->force_check_now = 0;
++
+ /*----------- Execute the command ------------------*/
+ switch(cmd){
+
+***************
+*** 958,963 ****
+--- 1026,1032 ----
+
+ /*---------- Scroll line up ----------*/
+ case MC_CHARUP :
++ previtem:
+ (void) process_cmd(state, stream, msgmap, MC_PREVITEM,
+ (style == MsgIndex
+ || style == MultiMsgIndex
+***************
+*** 975,980 ****
+--- 1044,1050 ----
+
+ /*---------- Scroll line down ----------*/
+ case MC_CHARDOWN :
++ nextitem:
+ /*
+ * Special Page framing handling here. If we
+ * did something that should scroll-by-a-line, frame
+***************
+*** 1192,1197 ****
+--- 1262,1268 ----
+
+
+ case MC_THRDINDX :
++ mc_thrdindx:
+ msgmap->top = msgmap->top_after_thrd;
+ if(unview_thread(state, stream, msgmap)){
+ ps_global->redrawer = NULL;
+***************
+*** 1239,1245 ****
+ && mp.col == id.plus_col
+ && style != ThreadIndex){
+ collapse_or_expand(state, stream, msgmap,
+! mn_get_cur(msgmap));
+ }
+ else if (mp.doubleclick){
+ if(mp.button == M_BUTTON_LEFT){
+--- 1310,1316 ----
+ && mp.col == id.plus_col
+ && style != ThreadIndex){
+ collapse_or_expand(state, stream, msgmap,
+! mn_get_cur(msgmap), 1);
+ }
+ else if (mp.doubleclick){
+ if(mp.button == M_BUTTON_LEFT){
+***************
+*** 1309,1314 ****
+--- 1380,1387 ----
+ reset_index_border();
+ break;
+
++ case MC_QUOTA:
++ cmd_quota(state);
+
+ /*---------- Redraw ----------*/
+ case MC_REPAINT :
+***************
+*** 1333,1341 ****
+
+
+ case MC_COLLAPSE :
+! thread_command(state, stream, msgmap, ch, -FOOTER_ROWS(state));
+ break;
+
+ case MC_DELETE :
+ case MC_UNDELETE :
+ case MC_REPLY :
+--- 1406,1511 ----
+
+
+ case MC_COLLAPSE :
+! thread_command(state, stream, msgmap, ch, -FOOTER_ROWS(state), 1);
+ break;
+
++ case MC_CTHREAD :
++ if (SEP_THRDINDX())
++ goto mc_thrdindx;
++ else
++ if (THREADING()){
++ if (any_messages(ps_global->msgmap, NULL,
++ "to collapse a thread"))
++ collapse_thread(state, stream,msgmap, 1);
++ }
++ else
++ q_status_message(SM_ORDER, 0, 1,
++ "Command available in threaded mode only");
++ break;
++
++ case MC_OTHREAD :
++ if (SEP_THRDINDX())
++ goto view_a_thread;
++ else
++ if (THREADING()){
++ if (any_messages(ps_global->msgmap, NULL, "to expand a thread"))
++ expand_thread(state, stream,msgmap, 1);
++ }
++ else
++ q_status_message(SM_ORDER, 0, 1,
++ "Command available in threaded mode only");
++ break;
++
++ case MC_NEXTHREAD:
++ case MC_PRETHREAD:
++ if (THRD_INDX()){
++ if (cmd == MC_NEXTHREAD)
++ goto nextitem;
++ else
++ goto previtem;
++ }
++ else
++ if (THREADING()){
++ if (any_messages(ps_global->msgmap, NULL,
++ "to move to other thread"))
++ move_thread(state, stream, msgmap,
++ cmd == MC_NEXTHREAD ? 1 : -1);
++ }
++ else
++ q_status_message(SM_ORDER, 0, 1,
++ "Command available in threaded mode only");
++ break;
++
++ case MC_KOLAPSE:
++ case MC_EXPTHREAD:
++ if (SEP_THRDINDX()){
++ q_status_message(SM_ORDER, 0, 1,
++ "Command not available in this screen");
++ }
++ else{
++ if (THREADING()){
++ if (any_messages(ps_global->msgmap, NULL,
++ cmd == MC_KOLAPSE ? "to collapse" : "to expand"))
++ kolapse_thread(state, stream, msgmap,
++ (cmd == MC_KOLAPSE) ? '[' : ']', 1);
++ }
++ else
++ q_status_message(SM_ORDER, 0, 1,
++ "Command available in threaded mode only");
++ }
++ break;
++
++ case MC_DELTHREAD:
++ if (THREADING()){
++ if (any_messages(ps_global->msgmap, NULL, "to delete"))
++ cmd_delete_thread(state, stream, msgmap);
++ }
++ else
++ q_status_message(SM_ORDER, 0, 1,
++ "Command available in threaded mode only");
++ break;
++
++ case MC_UNDTHREAD:
++ if (THREADING()){
++ if (any_messages(ps_global->msgmap, NULL, "to undelete"))
++ cmd_undelete_thread(state, stream, msgmap);
++ }
++ else
++ q_status_message(SM_ORDER, 0, 1,
++ "Command available in threaded mode only");
++ break;
++
++
++ case MC_SELTHREAD:
++ if (THREADING()){
++ if (any_messages(ps_global->msgmap, NULL, "to undelete"))
++ cmd_select_thread(state, stream, msgmap);
++ }
++ else
++ q_status_message(SM_ORDER, 0, 1,
++ "Command available in threaded mode only");
++ break;
++
+ case MC_DELETE :
+ case MC_UNDELETE :
+ case MC_REPLY :
+***************
+*** 1356,1368 ****
+ if(rawno)
+ thrd = fetch_thread(stream, rawno);
+
+! collapsed = thrd && thrd->next
+! && get_lflag(stream, NULL, rawno, MN_COLL);
+ }
+
+ if(collapsed){
+ thread_command(state, stream, msgmap,
+! ch, -FOOTER_ROWS(state));
+ /* increment current */
+ if(cmd == MC_DELETE){
+ advance_cur_after_delete(state, stream, msgmap,
+--- 1526,1537 ----
+ if(rawno)
+ thrd = fetch_thread(stream, rawno);
+
+! collapsed = thread_is_kolapsed(ps_global, stream, msgmap, rawno);
+ }
+
+ if(collapsed){
+ thread_command(state, stream, msgmap,
+! ch, -FOOTER_ROWS(state),1);
+ /* increment current */
+ if(cmd == MC_DELETE){
+ advance_cur_after_delete(state, stream, msgmap,
+***************
+*** 1401,1407 ****
+ }
+ /* else fall thru to normal default */
+
+!
+ /*---------- Default -- all other command ----------*/
+ default:
+ do_the_default:
+--- 1570,1579 ----
+ }
+ /* else fall thru to normal default */
+
+! case MC_TAB:
+! skip++;
+! /* do not check for new mail in inc fldrs and fall through */
+!
+ /*---------- Default -- all other command ----------*/
+ default:
+ do_the_default:
+***************
+*** 2772,2777 ****
+--- 2944,2950 ----
+ n = mn_raw2m(msgs, thrd->rawno);
+
+ while(thrd){
++ unsigned long branch;
+ if(!msgline_hidden(stream, msgs, n, 0)
+ && (++m % lines_per_page) == 1L)
+ t = n;
+***************
+*** 2840,2850 ****
+
+ /* n is the end of this thread */
+ while(thrd){
+ n = mn_raw2m(msgs, thrd->rawno);
+! if(thrd->branch)
+! thrd = fetch_thread(stream, thrd->branch);
+! else if(thrd->next)
+! thrd = fetch_thread(stream, thrd->next);
+ else
+ thrd = NULL;
+ }
+--- 3013,3024 ----
+
+ /* n is the end of this thread */
+ while(thrd){
++ unsigned long next = 0L, branch = 0L;
+ n = mn_raw2m(msgs, thrd->rawno);
+! if(branch = get_branch(stream,thrd))
+! thrd = fetch_thread(stream, branch);
+! else if(next = get_next(stream,thrd))
+! thrd = fetch_thread(stream, next);
+ else
+ thrd = NULL;
+ }
+***************
+*** 2998,3003 ****
+--- 3172,3178 ----
+ case iSTime:
+ case iKSize:
+ case iSize:
++ case iSizeThread:
+ (*answer)[column].req_width = 7;
+ break;
+ case iS1Date:
+***************
+*** 3034,3047 ****
+ static INDEX_PARSE_T itokens[] = {
+ {"STATUS", iStatus, FOR_INDEX},
+ {"MSGNO", iMessNo, FOR_INDEX},
+! {"DATE", iDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+ {"FROMORTO", iFromTo, FOR_INDEX},
+ {"FROMORTONOTNEWS", iFromToNotNews, FOR_INDEX},
+ {"SIZE", iSize, FOR_INDEX},
+ {"SIZECOMMA", iSizeComma, FOR_INDEX},
+ {"SIZENARROW", iSizeNarrow, FOR_INDEX},
+ {"KSIZE", iKSize, FOR_INDEX},
+! {"SUBJECT", iSubject, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+ {"FULLSTATUS", iFStatus, FOR_INDEX},
+ {"IMAPSTATUS", iIStatus, FOR_INDEX},
+ {"SUBJKEY", iSubjKey, FOR_INDEX},
+--- 3209,3223 ----
+ static INDEX_PARSE_T itokens[] = {
+ {"STATUS", iStatus, FOR_INDEX},
+ {"MSGNO", iMessNo, FOR_INDEX},
+! {"DATE", iDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"FROMORTO", iFromTo, FOR_INDEX},
+ {"FROMORTONOTNEWS", iFromToNotNews, FOR_INDEX},
+ {"SIZE", iSize, FOR_INDEX},
+ {"SIZECOMMA", iSizeComma, FOR_INDEX},
++ {"SIZETHREAD", iSizeThread, FOR_INDEX},
+ {"SIZENARROW", iSizeNarrow, FOR_INDEX},
+ {"KSIZE", iKSize, FOR_INDEX},
+! {"SUBJECT", iSubject, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_TRIM},
+ {"FULLSTATUS", iFStatus, FOR_INDEX},
+ {"IMAPSTATUS", iIStatus, FOR_INDEX},
+ {"SUBJKEY", iSubjKey, FOR_INDEX},
+***************
+*** 3051,3076 ****
+ {"DESCRIPSIZE", iDescripSize, FOR_INDEX},
+ {"ATT", iAtt, FOR_INDEX},
+ {"SCORE", iScore, 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},
+! {"SMARTDATETIME", iSDateTime, 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},
+--- 3227,3255 ----
+ {"DESCRIPSIZE", iDescripSize, FOR_INDEX},
+ {"ATT", iAtt, FOR_INDEX},
+ {"SCORE", iScore, 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},
+! {"SMARTDATETIME", iSDateTime, 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_SAVE|FOR_RULE|FOR_COMPOSE},
+! {"TO", iTo, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_SAVE|FOR_RULE|FOR_COMPOSE},
+! {"SENDER", iSender, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_SAVE|FOR_RULE},
+! {"CC", iCc, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_SAVE|FOR_RULE},
+! {"ADDRESSTO", iAddressTo, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_SAVE|FOR_RULE},
+! {"ADDRESSCC", iAddressCc, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_SAVE|FOR_RULE},
+! {"ADDRESSRECIPS", iAddressRecip, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_SAVE|FOR_RULE},
+ {"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},
+***************
+*** 3079,3124 ****
+ {"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},
+! {"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},
+! {"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},
+ {"ARROW", iArrow, FOR_INDEX},
+ {"CURSORPOS", iCursorPos, FOR_TEMPLATE},
+ {NULL, iNothing, FOR_NOTHING}
+ };
+
+--- 3258,3312 ----
+ {"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},
+! {"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_RULE|FOR_SAVE|FOR_FILT},
+! {"CURDATEISO", iCurDateIso, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"CURDATEISOS", iCurDateIsoS, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"CURTIME24", iCurTime24, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"CURTIME12", iCurTime12, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"CURDAY", iCurDay, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"CURDAY2DIGIT", iCurDay2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"CURDAYOFWEEK", iCurDayOfWeek, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+ {"CURDAYOFWEEKABBREV", iCurDayOfWeekAbb,
+! FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"CURMONTH", iCurMon, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"CURMONTH2DIGIT", iCurMon2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"CURMONTHLONG", iCurMonLong, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"CURMONTHABBREV", iCurMonAbb, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"CURYEAR", iCurYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"CURYEAR2DIGIT", iCurYear2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"LASTMONTH", iLstMon, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"LASTMONTH2DIGIT", iLstMon2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"LASTMONTHLONG", iLstMonLong, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"LASTMONTHABBREV", iLstMonAbb, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"LASTMONTHYEAR", iLstMonYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+ {"LASTMONTHYEAR2DIGIT", iLstMonYear2Digit,
+! FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"LASTYEAR", iLstYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+! {"LASTYEAR2DIGIT", iLstYear2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_FILT},
+ {"ARROW", iArrow, FOR_INDEX},
+ {"CURSORPOS", iCursorPos, FOR_TEMPLATE},
++ {"NICK", iNick, FOR_RULE|FOR_SAVE},
++ {"FOLDER", iFolder, FOR_RULE|FOR_SAVE|FOR_FOLDER},
++ {"ROLE", iRole, FOR_RULE|FOR_RESUB|FOR_TRIM|FOR_TEMPLATE},
++ {"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}
+ };
+
+***************
+*** 3286,3292 ****
+ */
+ static IndexColType fixed_ctypes[] = {
+ iArrow, iMessNo, iStatus, iFStatus, iIStatus, iDate, iSDate, iSDateTime,
+! iSTime, iLDate,
+ iS1Date, iS2Date, iS3Date, iS4Date, iDateIso, iDateIsoS,
+ iSize, iSizeComma, iSizeNarrow, iKSize, iDescripSize,
+ iAtt, iTime24, iTime12, iTimezone, iMonAbb, iYear, iYear2Digit,
+--- 3474,3480 ----
+ */
+ static IndexColType fixed_ctypes[] = {
+ iArrow, iMessNo, iStatus, iFStatus, iIStatus, iDate, iSDate, iSDateTime,
+! iSTime, iLDate, iSizeThread,
+ iS1Date, iS2Date, iS3Date, iS4Date, iDateIso, iDateIsoS,
+ iSize, iSizeComma, iSizeNarrow, iKSize, iDescripSize,
+ iAtt, iTime24, iTime12, iTimezone, iMonAbb, iYear, iYear2Digit,
+***************
+*** 3457,3462 ****
+--- 3645,3651 ----
+ case iTime12:
+ case iSize:
+ case iKSize:
++ case iSizeThread:
+ cdesc->actual_length = 7;
+ cdesc->adjustment = Right;
+ break;
+***************
+*** 3521,3527 ****
+ cdesc->ctype != iNothing;
+ cdesc++)
+ if(cdesc->ctype == iSize || cdesc->ctype == iKSize ||
+! cdesc->ctype == iSizeNarrow ||
+ cdesc->ctype == iSizeComma || cdesc->ctype == iDescripSize){
+ if(cdesc->actual_length == 0){
+ if((fix=cdesc->width) > 0){ /* had this reserved */
+--- 3710,3716 ----
+ cdesc->ctype != iNothing;
+ cdesc++)
+ if(cdesc->ctype == iSize || cdesc->ctype == iKSize ||
+! cdesc->ctype == iSizeNarrow || cdesc->ctype == iSizeThread ||
+ cdesc->ctype == iSizeComma || cdesc->ctype == iDescripSize){
+ if(cdesc->actual_length == 0){
+ if((fix=cdesc->width) > 0){ /* had this reserved */
+***************
+*** 3813,3818 ****
+--- 4002,4081 ----
+ }
+ }
+
++ ENVELOPE *make_envelope(idata, index)
++ INDEXDATA_S *idata;
++ int index;
++ {
++ ENVELOPE *result;
++
++ result = mail_newenvelope();
++
++ result->from = rfc822_cpy_adr(idata->from);
++ result->to = rfc822_cpy_adr(idata->to);
++ result->cc = rfc822_cpy_adr(idata->cc);
++ result->sender = rfc822_cpy_adr(idata->sender);
++ result->subject = cpystr(idata->subject);
++ result->newsgroups = index ? cpystr(idata->newsgroups) :
++ IS_NEWS(idata->stream) ? cpystr(ps_global->cur_folder)
++ : NULL;
++ return result;
++ }
++
++ /*---------------------------------
++
++ -----------*/
++
++ char *find_value(token,function1, context1, function2, context2, function3, context3, idata, code)
++ char *token;
++ char *function1;
++ int context1;
++ char *function2;
++ int context2;
++ char *function3;
++ int context3;
++ INDEXDATA_S *idata;
++ int code;
++ { int n = 0, done = 0, next_step = 0;
++ char *rule_result;
++ int rule_context;
++ RULELIST *rule = get_rulelist_from_code(code, ps_global->rule_list);
++ RULE_S *prule;
++
++ if (rule){
++ rule_context = FOR_RULE;
++ while (!done && (prule = get_rule(rule,n++))){
++ if (context1 && prule->action->token &&
++ !strcmp(prule->action->token, token)
++ && !strcmp(prule->action->function, function1)){
++ rule_context |= context1;
++ next_step++;
++ }
++ if (context2 && prule->action->token &&
++ !strcmp(prule->action->token, token)
++ && !strcmp(prule->action->function, function2)){
++ rule_context |= context2;
++ next_step++;
++ }
++ if (context3 && prule->action->token &&
++ !strcmp(prule->action->token, token)
++ && !strcmp(prule->action->function, function3)){
++ rule_context |= context3;
++ next_step++;
++ }
++ if (next_step){
++ ENVELOPE *local_env = make_envelope(idata,1);
++ next_step = FALSE;
++ rule_result = process_rule(prule, rule_context, local_env);
++ if (local_env)
++ mail_free_envelope(&local_env);
++ if (rule_result)
++ done++;
++ }
++ }
++ }
++ return done ? rule_result : NULL;
++ }
++
+
+ /*----------------------------------------------------------------------
+ Create a string summarizing the message header for index on screen
+***************
+*** 3945,3954 ****
+
+ /* find next thread which is visible */
+ do{
+ if(mn_get_revsort(msgmap) && thrd->prevthd)
+ thrd = fetch_thread(stream, thrd->prevthd);
+! else if(!mn_get_revsort(msgmap) && thrd->nextthd)
+! thrd = fetch_thread(stream, thrd->nextthd);
+ else
+ thrd = NULL;
+ } while(thrd
+--- 4208,4218 ----
+
+ /* find next thread which is visible */
+ do{
++ unsigned long branch;
+ if(mn_get_revsort(msgmap) && thrd->prevthd)
+ thrd = fetch_thread(stream, thrd->prevthd);
+! else if(!mn_get_revsort(msgmap) && thrd->branch)
+! thrd = fetch_thread(stream, thrd->branch);
+ else
+ thrd = NULL;
+ } while(thrd
+***************
+*** 4404,4414 ****
+ }
+
+ /* is this a collapsed thread index line? */
+ if(!idata->bogus && THREADING()){
+! thrd = fetch_thread(idata->stream, idata->rawno);
+! collapsed = thrd && thrd->next
+! && get_lflag(idata->stream, NULL,
+! idata->rawno, MN_COLL);
+ }
+
+ /* calculate contents of the required fields */
+--- 4668,4676 ----
+ }
+
+ /* is this a collapsed thread index line? */
++ thrd = fetch_thread(idata->stream, idata->rawno);
+ if(!idata->bogus && THREADING()){
+! collapsed = thrd && thread_is_kolapsed(ps_global, idata->stream, ps_global->msgmap, idata->rawno);
+ }
+
+ /* calculate contents of the required fields */
+***************
+*** 4940,4946 ****
+--- 5202,5232 ----
+
+ break;
+
++ case iSizeThread:
++ if (!THREADING()){
++ goto getsize;
++ } else if (collapsed){
++ l = count_flags_in_thread(idata->stream, thrd, F_NONE);
++ sprintf(str, "(%lu)", l);
++ }
++ else{
++ thrd = fetch_thread(idata->stream, idata->rawno);
++ if(!thrd)
++ sprintf(str,"Error");
++ else{
++ long lengthb;
++ lengthb = get_length_branch(idata->stream, idata->rawno);
++
++ if (lengthb > 0L)
++ sprintf(str,"(%lu)", lengthb);
++ else
++ sprintf(str," ");
++ }
++ }
++ break;
++
+ case iSize:
++ getsize:
+ /* 0 ... 9999 */
+ if((l = fetch_size(idata)) < 10*1000L)
+ sprintf(str, "(%lu)", l);
+***************
+*** 7031,7041 ****
+ unsigned long rawno;
+ unsigned char buf[MAILTMPLEN];
+ OFFCOLOR_S myoffs[OFFS];
+! int mynoff = 0;
+
+ memset(str, 0, (width+1) * sizeof(*str));
+ origstr = str;
+! origsubj = fetch_subject(idata);
+ if(!origsubj)
+ origsubj = "";
+
+--- 7317,7335 ----
+ unsigned long rawno;
+ unsigned char buf[MAILTMPLEN];
+ OFFCOLOR_S myoffs[OFFS];
+! int mynoff = 0, we_clear = 0;
+! char *rule_result;
+
+ memset(str, 0, (width+1) * sizeof(*str));
+ origstr = str;
+! rule_result = find_value("_SUBJECT_", "_REPLACE_", FOR_REPLACE, "_TRIM_", FOR_TRIM, "_REXTRIM_", FOR_TRIM, idata, V_REPLACE_RULES);
+! if (rule_result){
+! we_clear++;
+! origsubj = cpystr(rule_result);
+! fs_give((void **)&rule_result);
+! }
+! else
+! origsubj = fetch_subject(idata);
+ if(!origsubj)
+ origsubj = "";
+
+***************
+*** 7060,7067 ****
+ thdorig = thd = fetch_thread(idata->stream, idata->rawno);
+ border = str + width;
+ if(current_index_state->plus_col >= 0 && !THRD_INDX()){
+! collapsed = thd && thd->next &&
+! get_lflag(idata->stream, NULL, idata->rawno, MN_COLL);
+ hline = get_index_cache(idata->msgno);
+ hline->plus = collapsed ? ps_global->VAR_THREAD_MORE_CHAR[0]
+ : (thd && thd->next)
+--- 7354,7361 ----
+ thdorig = thd = fetch_thread(idata->stream, idata->rawno);
+ border = str + width;
+ if(current_index_state->plus_col >= 0 && !THRD_INDX()){
+! collapsed = this_thread_is_kolapsed(ps_global, idata->stream, ps_global->msgmap, idata->rawno);
+! collapsed = collapsed && (count_thread(ps_global,idata->stream, ps_global->msgmap, idata->rawno) != 1);
+ hline = get_index_cache(idata->msgno);
+ hline->plus = collapsed ? ps_global->VAR_THREAD_MORE_CHAR[0]
+ : (thd && thd->next)
+***************
+*** 7316,7321 ****
+--- 7610,7617 ----
+
+ if(free_subj)
+ fs_give((void **) &free_subj);
++ if (we_clear && origsubj)
++ fs_give((void **)&origsubj);
+
+ /* adjust offsets for indents and subject truncation */
+ if(offs && noff && *noff < OFFS && mynoff && pico_usingcolor()){
+***************
+*** 7543,7550 ****
+ thdorig = thd = fetch_thread(idata->stream, idata->rawno);
+ border = str + width;
+ if(current_index_state->plus_col >= 0 && !THRD_INDX()){
+! collapsed = thd && thd->next &&
+! get_lflag(idata->stream, NULL, idata->rawno, MN_COLL);
+ hline = get_index_cache(idata->msgno);
+ hline->plus = collapsed ? ps_global->VAR_THREAD_MORE_CHAR[0]
+ : (thd && thd->next)
+--- 7839,7846 ----
+ thdorig = thd = fetch_thread(idata->stream, idata->rawno);
+ border = str + width;
+ if(current_index_state->plus_col >= 0 && !THRD_INDX()){
+! collapsed = this_thread_is_kolapsed(ps_global, idata->stream, ps_global->msgmap, idata->rawno);
+! collapsed = collapsed && (count_thread (ps_global,idata->stream, ps_global->msgmap, idata->rawno) != 1);
+ hline = get_index_cache(idata->msgno);
+ hline->plus = collapsed ? ps_global->VAR_THREAD_MORE_CHAR[0]
+ : (thd && thd->next)
+***************
+*** 7635,7650 ****
+ ? "To"
+ : (addr = fetch_cc(idata))
+ ? "Cc"
+! : NULL))
+! && set_index_addr(idata, field, addr, "To: ",
+! width, fptr))
+! break;
+!
+ if(ctype == iFromTo &&
+ (newsgroups = fetch_newsgroups(idata)) &&
+ *newsgroups){
+! sprintf(fptr, "To: %-*.*s", width-4, width-4,
+! newsgroups);
+ break;
+ }
+
+--- 7931,7960 ----
+ ? "To"
+ : (addr = fetch_cc(idata))
+ ? "Cc"
+! : NULL))){
+! char *rule_result;
+! rule_result = find_value("_FROM_","_REPLACE_",FOR_REPLACE, NULL,0,NULL,0, idata,V_REPLACE_RULES);
+! if (!rule_result)
+! set_index_addr(idata, field, addr, "To: ",
+! width, str);
+! else{
+! sprintf(str, "%-*.*s", width, width, rule_result);
+! fs_give((void **)&rule_result);
+! }
+! break;
+! }
+ if(ctype == iFromTo &&
+ (newsgroups = fetch_newsgroups(idata)) &&
+ *newsgroups){
+! char *rule_result;
+! rule_result = find_value("_FROM_","_REPLACE_",FOR_REPLACE, NULL,0,NULL, 0, idata, V_REPLACE_RULES);
+! if (!rule_result)
+! sprintf(str, "To: %-*.*s", width-4, width-4,
+! newsgroups);
+! else{
+! sprintf(str, "%-*.*s", width, width, rule_result);
+! fs_give((void **)&rule_result);
+! }
+ break;
+ }
+
+***************
+*** 7657,7664 ****
+ break;
+
+ case iFrom:
+! set_index_addr(idata, "From", fetch_from(idata),
+! NULL, width, fptr);
+ break;
+
+ case iAddress:
+--- 7967,7983 ----
+ break;
+
+ case iFrom:
+! { char *rule_result;
+! rule_result = find_value("_FROM_","_REPLACE_", FOR_REPLACE, "_TRIM_", FOR_TRIM, "_REXTRIM_", FOR_TRIM, idata, V_REPLACE_RULES);
+! if (!rule_result)
+! set_index_addr(idata, "From", fetch_from(idata),
+! NULL, width, str);
+! else{
+! sprintf(str, "%-*.*s", width, width, rule_result);
+! fs_give((void **)&rule_result);
+! }
+! }
+!
+ break;
+
+ case iAddress:
+***************
+*** 7741,7746 ****
+--- 8060,8083 ----
+ return(1);
+ }
+
++ void
++ insert_pattern_in_string(buf, last, maxbuf)
++ char *buf;
++ char *last;
++ int maxbuf;
++ {
++ if (last[0] != '\0'){
++ int lenlast, lenbuf;
++ lenlast = strlen(last);
++ lenbuf = buf[0] == '\0' ? 0 : strlen(buf);
++ if (lenlast + lenbuf <= maxbuf){
++ if (buf[0] == '\0')
++ strcpy(buf, last);
++ else
++ strcat(buf, last);
++ }
++ }
++ }
+
+
+ /*----------------------------------------------------------------------
+***************
+*** 7765,7773 ****
+--- 8102,8112 ----
+ long i, sorted_msg, selected = 0L;
+ char prompt[MAX_SEARCH+50], new_string[MAX_SEARCH+1];
+ HelpType help;
++ static char last_search_pat[MAX_SEARCH+1] = {'\0'};
+ static char search_string[MAX_SEARCH+1] = { '\0' };
+ HLINE_S *hl;
+ static ESCKEY_S header_search_key[] = { {0, 0, NULL, NULL },
++ {ctrl('N'), 9, "^N","Ins Pat"},
+ {ctrl('Y'), 10, "^Y", "First Msg"},
+ {ctrl('V'), 11, "^V", "Last Msg"},
+ {-1, 0, NULL, NULL} };
+***************
+*** 7814,7819 ****
+--- 8153,8160 ----
+ : h_os_index_whereis;
+ continue;
+ }
++ else if(rc == 9)
++ insert_pattern_in_string(new_string, last_search_pat, MAX_SEARCH);
+ else if(rc == 10){
+ q_status_message(SM_ORDER, 0, 3, "Searched to First Message.");
+ if(any_lflagged(msgmap, MN_HIDE | MN_CHID)){
+***************
+*** 7851,7857 ****
+ break;
+ }
+
+! if(rc != 4) /* redraw */
+ break; /* redraw */
+ }
+
+--- 8192,8198 ----
+ break;
+ }
+
+! if(rc != 4 && rc != 9) /* redraw */
+ break; /* redraw */
+ }
+
+***************
+*** 7868,7873 ****
+--- 8209,8217 ----
+ strncpy(search_string, new_string, sizeof(search_string));
+ search_string[sizeof(search_string)-1] = '\0';
+
++ strncpy(last_search_pat, new_string, sizeof(last_search_pat));
++ last_search_pat[sizeof(last_search_pat)-1] = '\0';
++
+ #ifndef DOS
+ intr_handling_on();
+ #endif
+***************
+*** 8054,8059 ****
+--- 8398,8440 ----
+ : ((mdiff = *mess_a - *mess_b) ? ((mdiff > 0) ? 1 : -1) : 0));
+ }
+
++ SortOrder translate(order, is_rev)
++ 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;
++ }
+
+ /*----------------------------------------------------------------------
+ Sort the current folder into the order set in the msgmap
+***************
+*** 8069,8080 ****
+ causes the sort to happen if it is still needed.
+ ----*/
+ void
+! sort_folder(stream, msgmap, new_sort, new_rev, flags)
+ MAILSTREAM *stream;
+ MSGNO_S *msgmap;
+ SortOrder new_sort;
+ int new_rev;
+ unsigned flags;
+ {
+ long raw_current, i, j;
+ unsigned long *sort = NULL;
+--- 8450,8462 ----
+ causes the sort to happen if it is still needed.
+ ----*/
+ void
+! sort_folder(stream, msgmap, new_sort, new_rev, flags, first)
+ MAILSTREAM *stream;
+ MSGNO_S *msgmap;
+ SortOrder new_sort;
+ int new_rev;
+ unsigned flags;
++ int first;
+ {
+ long raw_current, i, j;
+ unsigned long *sort = NULL;
+***************
+*** 8084,8089 ****
+--- 8466,8480 ----
+ int current_rev;
+ MESSAGECACHE *mc;
+
++ if (first){
++ if (new_sort == SortThread)
++ find_msgmap(stream, msgmap, flags,
++ ps_global->thread_cur_sort, new_rev);
++ else
++ sort_folder(stream, msgmap, new_sort, new_rev, flags, 0);
++ return;
++ }
++
+ dprint(2, (debugfile, "Sorting by %s%s\n",
+ sort_name(new_sort), new_rev ? "/reverse" : ""));
+
+***************
+*** 8446,8451 ****
+--- 8837,8843 ----
+
+ thrd = fetch_head_thread(stream);
+ for(j = msgmap->max_thrdno; thrd && j >= 1L; j--){
++ unsigned long branch;
+ thrd->thrdno = j;
+
+ if(thrd->nextthd)
+***************
+*** 8512,8518 ****
+ MESSAGECACHE *mc;
+ PINELT_S *peltp;
+
+! if(!(stream && stream->spare))
+ return;
+
+ ps_global->view_skipped_index = 0;
+--- 8904,8910 ----
+ MESSAGECACHE *mc;
+ PINELT_S *peltp;
+
+! if(!(stream && stream->spare) || !erase_thread_info)
+ return;
+
+ ps_global->view_skipped_index = 0;
+***************
+*** 8574,8580 ****
+ unsigned long msgno, rawno, set_in_thread, in_thread;
+ int bail, this_is_vis;
+ int un_view_thread = 0;
+! long raw_current;
+
+
+ dprint(2, (debugfile, "sort_thread_callback\n"));
+--- 8966,8972 ----
+ unsigned long msgno, rawno, set_in_thread, in_thread;
+ int bail, this_is_vis;
+ int un_view_thread = 0;
+! long raw_current, branch;
+
+
+ dprint(2, (debugfile, "sort_thread_callback\n"));
+***************
+*** 8593,8601 ****
+ * way. If the dummy node is at the top-level, then its children are
+ * promoted to the top-level as separate threads.
+ */
+! collapsed_tree = collapse_threadnode_tree(tree);
+! (void) sort_thread_flatten(collapsed_tree, stream, thrd_flatten_array,
+! NULL, THD_TOP);
+ mail_free_threadnode(&collapsed_tree);
+
+ if(any_lflagged(g_sort.msgmap, MN_HIDE))
+--- 8985,8995 ----
+ * way. If the dummy node is at the top-level, then its children are
+ * promoted to the top-level as separate threads.
+ */
+! collapsed_tree = F_ON(F_ENHANCED_THREAD, ps_global) ?
+! copy_tree(tree) : collapse_threadnode_tree(tree);
+! (void) sort_thread_flatten(collapsed_tree,
+! stream, thrd_flatten_array,
+! NULL, THD_TOP, 0, 1L, 0L);
+ mail_free_threadnode(&collapsed_tree);
+
+ if(any_lflagged(g_sort.msgmap, MN_HIDE))
+***************
+*** 8760,8771 ****
+ else{
+ thrd = fetch_head_thread(stream);
+ while(thrd){
+ /*
+ * The top-level threads aren't hidden by collapse.
+ */
+ msgno = mn_raw2m(g_sort.msgmap, thrd->rawno);
+! if(msgno)
+! set_lflag(stream, g_sort.msgmap, msgno, MN_CHID, 0);
+
+ if(thrd->next){
+ PINETHRD_S *nthrd;
+--- 9154,9167 ----
+ else{
+ thrd = fetch_head_thread(stream);
+ while(thrd){
++ unsigned long raw = thrd->rawno;
++ unsigned long top = top_thread(stream, raw);
+ /*
+ * The top-level threads aren't hidden by collapse.
+ */
+ msgno = mn_raw2m(g_sort.msgmap, thrd->rawno);
+! if(msgno && !get_lflag(stream, NULL,thrd->rawno, MN_COLL))
+! set_lflag(stream, g_sort.msgmap, msgno, MN_CHID, 0);
+
+ if(thrd->next){
+ PINETHRD_S *nthrd;
+***************
+*** 8779,8787 ****
+ MN_COLL));
+ }
+
+! if(thrd->nextthd)
+ thrd = fetch_thread(stream, thrd->nextthd);
+! else
+ thrd = NULL;
+ }
+ }
+--- 9175,9184 ----
+ MN_COLL));
+ }
+
+! while (thrd && top_thread(stream, thrd->rawno) == top
+! && thrd->nextthd)
+ thrd = fetch_thread(stream, thrd->nextthd);
+! if (!(thrd && thrd->nextthd))
+ thrd = NULL;
+ }
+ }
+***************
+*** 8802,8811 ****
+ PINETHRD_S *not_this_thread;
+ {
+ PINETHRD_S *thrd = NULL, *nthrd;
+! unsigned long msgno;
+
+ dprint(9, (debugfile, "collapse_threads\n"));
+
+ thrd = fetch_head_thread(stream);
+ while(thrd){
+ if(thrd != not_this_thread){
+--- 9199,9215 ----
+ PINETHRD_S *not_this_thread;
+ {
+ PINETHRD_S *thrd = NULL, *nthrd;
+! unsigned long msgno, branch;
+
+ dprint(9, (debugfile, "collapse_threads\n"));
+
++ /* if(F_ON(F_ENHANCED_THREAD, ps_global)){*/
++ kolapse_thread(ps_global, stream, msgmap, '[', 0);
++ if (not_this_thread)
++ expand_thread(ps_global, stream, msgmap, 0);
++ return;
++ /* }*/
++
+ thrd = fetch_head_thread(stream);
+ while(thrd){
+ if(thrd != not_this_thread){
+***************
+*** 8840,8846 ****
+ int a_parent_is_collapsed;
+ {
+ PINETHRD_S *nthrd, *bthrd;
+! unsigned long msgno;
+
+ if(!thrd)
+ return;
+--- 9244,9250 ----
+ int a_parent_is_collapsed;
+ {
+ PINETHRD_S *nthrd, *bthrd;
+! unsigned long msgno, next, branch;
+
+ if(!thrd)
+ return;
+***************
+*** 8858,8865 ****
+ set_lflag(stream, msgmap, msgno, MN_CHID, 0);
+ }
+
+! if(thrd->next){
+! nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ make_thrdflags_consistent(stream, msgmap, nthrd,
+ a_parent_is_collapsed
+--- 9262,9269 ----
+ set_lflag(stream, msgmap, msgno, MN_CHID, 0);
+ }
+
+! if(next = get_next(stream, thrd)){
+! nthrd = fetch_thread(stream, next);
+ if(nthrd)
+ make_thrdflags_consistent(stream, msgmap, nthrd,
+ a_parent_is_collapsed
+***************
+*** 8868,8875 ****
+ MN_COLL));
+ }
+
+! if(thrd->branch){
+! bthrd = fetch_thread(stream, thrd->branch);
+ if(bthrd)
+ make_thrdflags_consistent(stream, msgmap, bthrd,
+ a_parent_is_collapsed);
+--- 9272,9279 ----
+ MN_COLL));
+ }
+
+! if(branch = get_branch(stream, thrd)){
+! bthrd = fetch_thread(stream, branch);
+ if(bthrd)
+ make_thrdflags_consistent(stream, msgmap, bthrd,
+ a_parent_is_collapsed);
+***************
+*** 8882,8888 ****
+ MAILSTREAM *stream;
+ {
+ PINETHRD_S *thrd = NULL;
+! long vis = 0L;
+
+ thrd = fetch_head_thread(stream);
+ while(thrd){
+--- 9286,9292 ----
+ MAILSTREAM *stream;
+ {
+ PINETHRD_S *thrd = NULL;
+! long vis = 0L, branch;
+
+ thrd = fetch_head_thread(stream);
+ while(thrd){
+***************
+*** 8899,8945 ****
+
+
+ struct pass_along *
+! sort_thread_flatten(node, stream, entry, thrd, flags)
+ THREADNODE *node;
+ MAILSTREAM *stream;
+ struct pass_along *entry;
+ PINETHRD_S *thrd;
+ unsigned flags;
+ {
+ long n = 0L;
+! PINETHRD_S *newthrd = NULL;
+
+ if(node){
+! if(node->num){ /* holes happen */
+ n = (long) (entry - thrd_flatten_array);
+
+ for(; n > 0; n--)
+ if(thrd_flatten_array[n].rawno == node->num)
+ break; /* duplicate */
+
+! if(!n)
+! entry->rawno = node->num;
+! }
+!
+! /*
+! * Build a richer threading structure that will help us paint
+! * and operate on threads and subthreads.
+! */
+! if(!n && node->num){
+! newthrd = msgno_thread_info(stream, node->num, thrd, flags);
+! if(newthrd){
+! entry->thrd = newthrd;
+! entry++;
+!
+! if(node->next)
+ entry = sort_thread_flatten(node->next, stream, entry,
+! newthrd, THD_NEXT);
+!
+ if(node->branch)
+ entry = sort_thread_flatten(node->branch, stream, entry,
+! newthrd,
+! (flags == THD_TOP) ? THD_TOP
+! : THD_BRANCH);
+ }
+ }
+ }
+--- 9303,9388 ----
+
+
+ struct pass_along *
+! sort_thread_flatten(node, stream, entry, thrd, flags, adopted, top, threadno)
+ THREADNODE *node;
+ MAILSTREAM *stream;
+ struct pass_along *entry;
+ PINETHRD_S *thrd;
+ unsigned flags;
++ int adopted;
++ long top;
++ long threadno;
+ {
+ long n = 0L;
+! PINETHRD_S *newthrd = NULL, *save_thread = NULL;
+
+ if(node){
+! if(node->num){
+ n = (long) (entry - thrd_flatten_array);
+
++ if (adopted == 2)
++ top = node->num;
++
+ for(; n > 0; n--)
+ if(thrd_flatten_array[n].rawno == node->num)
+ break; /* duplicate */
+
+! if(!n){
+! entry->rawno = node->num;
+! newthrd = msgno_thread_info(stream, node->num, thrd, flags);
+! if(newthrd){
+! if (adopted == 2)
+! threadno = newthrd->thrdno;
+! if (adopted){
+! newthrd->toploose = top;
+! newthrd->thrdno = threadno;
+! }
+! entry->thrd = newthrd;
+! entry++;
+! }
+! adopted = adopted ? 1 : 0;
+! if (node->next)
+ entry = sort_thread_flatten(node->next, stream, entry,
+! newthrd, THD_NEXT, adopted, top,
+! threadno);
+ if(node->branch)
+ entry = sort_thread_flatten(node->branch, stream, entry,
+! newthrd,
+! (flags == THD_TOP) ? THD_TOP: THD_BRANCH,
+! adopted, top, threadno);
+! }
+! }
+! else{
+! adopted = 2;
+! if(node->next)
+! entry = sort_thread_flatten(node->next, stream, entry,
+! thrd, THD_TOP, adopted, top, threadno);
+! adopted = 0;
+! if(node->branch){
+! if(entry){
+! struct pass_along *last_entry = entry;
+! int i = 0;
+!
+! /*
+! * Next moved up to replace "tree" in the tree.
+! * If next has no branches, then we want to branch off
+! * of next. If next has branches, we want to branch off
+! * of the last of those branches instead.
+! */
+! last_entry--;
+! while(last_entry->thrd->parent)
+! last_entry--;
+! save_thread = last_entry->thrd;
+! last_entry += i+1;
+!
+! last_entry = sort_thread_flatten(node->branch, stream, entry,
+! save_thread,
+! (flags == THD_TOP) ? THD_TOP: THD_BRANCH,
+! adopted, top, threadno);
+! }
+! else
+! entry = sort_thread_flatten(node->branch, stream, entry,
+! NULL, THD_TOP, adopted, top, threadno);
+ }
+ }
+ }
+***************
+*** 8947,8952 ****
+--- 9390,9415 ----
+ return(entry);
+ }
+
++ /*
++ * Make a copy of c-client's THREAD tree
++ */
++ THREADNODE *
++ copy_tree(tree)
++ THREADNODE *tree;
++ {
++ THREADNODE *newtree = NULL;
++
++ if(tree){
++ newtree = mail_newthreadnode(NULL);
++ newtree->num = tree->num;
++ if(tree->next)
++ newtree->next = copy_tree(tree->next);
++
++ if(tree->branch)
++ newtree->branch = copy_tree(tree->branch);
++ }
++ return(newtree);
++ }
+
+ /*
+ * Make a copy of c-client's THREAD tree while eliminating dummy nodes.
+***************
+*** 10694,10705 ****
+
+
+ void
+! thread_command(state, stream, msgmap, preloadkeystroke, q_line)
+ struct pine *state;
+ MAILSTREAM *stream;
+ MSGNO_S *msgmap;
+ int preloadkeystroke;
+ int q_line;
+ {
+ PINETHRD_S *thrd = NULL;
+ unsigned long rawno, save_branch;
+--- 11157,11169 ----
+
+
+ void
+! thread_command(state, stream, msgmap, preloadkeystroke, q_line, display)
+ struct pine *state;
+ MAILSTREAM *stream;
+ MSGNO_S *msgmap;
+ int preloadkeystroke;
+ int q_line;
++ int display;
+ {
+ PINETHRD_S *thrd = NULL;
+ unsigned long rawno, save_branch;
+***************
+*** 10748,10754 ****
+ cancel_busy_alarm(0);
+
+ (void ) apply_command(state, stream, msgmap, preloadkeystroke, flags,
+! q_line);
+
+ /* restore the original flags */
+ copy_lflags(stream, msgmap, MN_STMP, MN_SLCT);
+--- 11212,11218 ----
+ cancel_busy_alarm(0);
+
+ (void ) apply_command(state, stream, msgmap, preloadkeystroke, flags,
+! q_line, display);
+
+ /* restore the original flags */
+ copy_lflags(stream, msgmap, MN_STMP, MN_SLCT);
+***************
+*** 10786,10805 ****
+ int v;
+ {
+ PINETHRD_S *nthrd, *bthrd;
+
+ if(!(stream && thrd && msgmap))
+ return;
+
+ set_lflag(stream, msgmap, mn_raw2m(msgmap, thrd->rawno), f, v);
+
+! if(thrd->next){
+! nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ set_flags_for_thread(stream, msgmap, f, nthrd, v);
+ }
+
+! if(thrd->branch){
+! bthrd = fetch_thread(stream, thrd->branch);
+ if(bthrd)
+ set_flags_for_thread(stream, msgmap, f, bthrd, v);
+ }
+--- 11250,11270 ----
+ int v;
+ {
+ PINETHRD_S *nthrd, *bthrd;
++ unsigned long next = 0L, branch = 0L;
+
+ if(!(stream && thrd && msgmap))
+ return;
+
+ set_lflag(stream, msgmap, mn_raw2m(msgmap, thrd->rawno), f, v);
+
+! if(next = get_next(stream,thrd)){
+! nthrd = fetch_thread(stream, next);
+ if(nthrd)
+ set_flags_for_thread(stream, msgmap, f, nthrd, v);
+ }
+
+! if(branch = get_branch(stream, thrd)){
+! bthrd = fetch_thread(stream, branch);
+ if(bthrd)
+ set_flags_for_thread(stream, msgmap, f, bthrd, v);
+ }
+***************
+*** 10854,10864 ****
+ * index.
+ */
+ void
+! collapse_or_expand(state, stream, msgmap, msgno)
+ struct pine *state;
+ MAILSTREAM *stream;
+ MSGNO_S *msgmap;
+ unsigned long msgno;
+ {
+ int collapsed, adjust_current = 0;
+ PINETHRD_S *thrd = NULL, *nthrd;
+--- 11319,11330 ----
+ * index.
+ */
+ void
+! collapse_or_expand(state, stream, msgmap, msgno, display)
+ struct pine *state;
+ MAILSTREAM *stream;
+ MSGNO_S *msgmap;
+ unsigned long msgno;
++ int display;
+ {
+ int collapsed, adjust_current = 0;
+ PINETHRD_S *thrd = NULL, *nthrd;
+***************
+*** 10912,10918 ****
+ if(!thrd)
+ return;
+
+! collapsed = get_lflag(stream, NULL, thrd->rawno, MN_COLL) && thrd->next;
+
+ if(collapsed){
+ msgno = mn_raw2m(msgmap, thrd->rawno);
+--- 11378,11384 ----
+ if(!thrd)
+ return;
+
+! collapsed = this_thread_is_kolapsed(ps_global, stream, msgmap, thrd->rawno);
+
+ if(collapsed){
+ msgno = mn_raw2m(msgmap, thrd->rawno);
+***************
+*** 10930,10942 ****
+ msgno = mn_raw2m(msgmap, thrd->rawno);
+ if(msgno > 0L && msgno <= mn_get_total(msgmap)){
+ set_lflag(stream, msgmap, msgno, MN_COLL, 1);
+! if(nthrd = fetch_thread(stream, thrd->next))
+ set_thread_subtree(stream, nthrd, msgmap, 1, MN_CHID);
+
+ clear_index_cache_ent(msgno);
+ }
+ }
+! else
+ q_status_message(SM_ORDER, 0, 1,
+ "No thread to collapse or expand on this line");
+
+--- 11396,11408 ----
+ msgno = mn_raw2m(msgmap, thrd->rawno);
+ if(msgno > 0L && msgno <= mn_get_total(msgmap)){
+ set_lflag(stream, msgmap, msgno, MN_COLL, 1);
+! if((thrd->next) && (nthrd = fetch_thread(stream, thrd->next)))
+ set_thread_subtree(stream, nthrd, msgmap, 1, MN_CHID);
+
+ clear_index_cache_ent(msgno);
+ }
+ }
+! else if (display)
+ q_status_message(SM_ORDER, 0, 1,
+ "No thread to collapse or expand on this line");
+
+***************
+*** 11018,11035 ****
+ unsigned long rawno, count = 0;
+ PINETHRD_S *nthrd, *bthrd;
+ MESSAGECACHE *mc;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+ return count;
+
+! if(thrd->next){
+! nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ count += count_flags_in_thread(stream, nthrd, flags);
+ }
+
+! if(thrd->branch){
+! bthrd = fetch_thread(stream, thrd->branch);
+ if(bthrd)
+ count += count_flags_in_thread(stream, bthrd, flags);
+ }
+--- 11484,11502 ----
+ unsigned long rawno, count = 0;
+ PINETHRD_S *nthrd, *bthrd;
+ MESSAGECACHE *mc;
++ unsigned long next = 0L, branch = 0L;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+ return count;
+
+! if(next = get_next(stream, thrd)){
+! nthrd = fetch_thread(stream, next);
+ if(nthrd)
+ count += count_flags_in_thread(stream, nthrd, flags);
+ }
+
+! if(branch = get_branch(stream, thrd)){
+! bthrd = fetch_thread(stream, branch);
+ if(bthrd)
+ count += count_flags_in_thread(stream, bthrd, flags);
+ }
+***************
+*** 11060,11079 ****
+ MSGNO_S *msgmap;
+ int flags; /* flag to count */
+ {
+! unsigned long rawno, count = 0;
+ PINETHRD_S *nthrd, *bthrd;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+ return count;
+
+! if(thrd->next){
+! nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ count += count_lflags_in_thread(stream, nthrd, msgmap, flags);
+ }
+
+! if(thrd->branch){
+! bthrd = fetch_thread(stream, thrd->branch);
+ if(bthrd)
+ count += count_lflags_in_thread(stream, bthrd, msgmap,flags);
+ }
+--- 11527,11546 ----
+ MSGNO_S *msgmap;
+ int flags; /* flag to count */
+ {
+! unsigned long rawno, count = 0, next, branch;
+ PINETHRD_S *nthrd, *bthrd;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+ return count;
+
+! if(next = get_next(stream, thrd)){
+! nthrd = fetch_thread(stream, next);
+ if(nthrd)
+ count += count_lflags_in_thread(stream, nthrd, msgmap, flags);
+ }
+
+! if(branch = get_branch(stream, thrd)){
+! bthrd = fetch_thread(stream, branch);
+ if(bthrd)
+ count += count_lflags_in_thread(stream, bthrd, msgmap,flags);
+ }
+***************
+*** 11095,11101 ****
+ MAILSTREAM *stream;
+ PINETHRD_S *thrd;
+ {
+! unsigned long rawno, count = 0;
+ PINETHRD_S *nthrd, *bthrd;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+--- 11562,11568 ----
+ MAILSTREAM *stream;
+ PINETHRD_S *thrd;
+ {
+! unsigned long rawno, count = 0, next, branch;
+ PINETHRD_S *nthrd, *bthrd;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+***************
+*** 11104,11117 ****
+ if(get_lflag(stream, NULL, thrd->rawno, MN_HIDE) == 0)
+ return 1;
+
+! if(thrd->next){
+! nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd && thread_has_some_visible(stream, nthrd))
+ return 1;
+ }
+
+! if(thrd->branch){
+! bthrd = fetch_thread(stream, thrd->branch);
+ if(bthrd && thread_has_some_visible(stream, bthrd))
+ return 1;
+ }
+--- 11571,11584 ----
+ if(get_lflag(stream, NULL, thrd->rawno, MN_HIDE) == 0)
+ return 1;
+
+! if(next = get_next(stream, thrd)){
+! nthrd = fetch_thread(stream, next);
+ if(nthrd && thread_has_some_visible(stream, nthrd))
+ return 1;
+ }
+
+! if(branch = get_branch(stream, thrd)){
+! bthrd = fetch_thread(stream, branch);
+ if(bthrd && thread_has_some_visible(stream, bthrd))
+ return 1;
+ }
+***************
+*** 11186,11205 ****
+ MSGNO_S *msgmap;
+ {
+ int count = 0;
+ PINETHRD_S *nthrd, *bthrd;
+ MESSAGECACHE *mc;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+ return count;
+
+! if(thrd->next){
+! nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ count += mark_msgs_in_thread(stream, nthrd, msgmap);
+ }
+
+! if(thrd->branch){
+! bthrd = fetch_thread(stream, thrd->branch);
+ if(bthrd)
+ count += mark_msgs_in_thread(stream, bthrd, msgmap);
+ }
+--- 11653,11673 ----
+ MSGNO_S *msgmap;
+ {
+ int count = 0;
++ long next, branch;
+ PINETHRD_S *nthrd, *bthrd;
+ MESSAGECACHE *mc;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+ return count;
+
+! if(next = get_next(stream, thrd)){
+! nthrd = fetch_thread(stream, next);
+ if(nthrd)
+ count += mark_msgs_in_thread(stream, nthrd, msgmap);
+ }
+
+! if(branch = get_branch(stream, thrd)){
+! bthrd = fetch_thread(stream, branch);
+ if(bthrd)
+ count += mark_msgs_in_thread(stream, bthrd, msgmap);
+ }
+***************
+*** 11233,11239 ****
+ int flags; /* flags to set or clear */
+ int v; /* set or clear? */
+ {
+! unsigned long rawno, msgno;
+ PINETHRD_S *nthrd, *bthrd;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+--- 11701,11707 ----
+ int flags; /* flags to set or clear */
+ int v; /* set or clear? */
+ {
+! unsigned long rawno, msgno, next, branch;
+ PINETHRD_S *nthrd, *bthrd;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+***************
+*** 11259,11272 ****
+ && v == 1 && get_index_cache(msgno)->line[0])
+ clear_index_cache_ent(msgno);
+
+! if(thrd->next){
+! nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ set_thread_lflags(stream, nthrd, msgmap, flags, v);
+ }
+
+! if(thrd->branch){
+! bthrd = fetch_thread(stream, thrd->branch);
+ if(bthrd)
+ set_thread_lflags(stream, bthrd, msgmap, flags, v);
+ }
+--- 11727,11740 ----
+ && v == 1 && get_index_cache(msgno)->line[0])
+ clear_index_cache_ent(msgno);
+
+! if(next = get_next(stream, thrd)){
+! nthrd = fetch_thread(stream, next);
+ if(nthrd)
+ set_thread_lflags(stream, nthrd, msgmap, flags, v);
+ }
+
+! if(branch = get_branch(stream,thrd)){
+! bthrd = fetch_thread(stream, branch);
+ if(bthrd)
+ set_thread_lflags(stream, bthrd, msgmap, flags, v);
+ }
+***************
+*** 11353,11371 ****
+ {
+ char to_us = ' ';
+ PINETHRD_S *nthrd, *bthrd;
+ MESSAGECACHE *mc;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+ return to_us;
+
+! if(thrd->next){
+! nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ to_us = to_us_symbol_for_thread(stream, nthrd, consider_flagged);
+ }
+
+! if(to_us == ' ' && thrd->branch){
+! bthrd = fetch_thread(stream, thrd->branch);
+ if(bthrd)
+ to_us = to_us_symbol_for_thread(stream, bthrd, consider_flagged);
+ }
+--- 11821,11840 ----
+ {
+ char to_us = ' ';
+ PINETHRD_S *nthrd, *bthrd;
++ unsigned long next = 0L, branch = 0L;
+ MESSAGECACHE *mc;
+
+ if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
+ return to_us;
+
+! if(next = get_next(stream,thrd)){
+! nthrd = fetch_thread(stream, next);
+ if(nthrd)
+ to_us = to_us_symbol_for_thread(stream, nthrd, consider_flagged);
+ }
+
+! if(to_us == ' ' && (branch = get_branch(stream, thrd))){
+! bthrd = fetch_thread(stream, branch);
+ if(bthrd)
+ to_us = to_us_symbol_for_thread(stream, bthrd, consider_flagged);
+ }
+***************
+*** 11400,11406 ****
+ break;
+ }
+
+! if(to_us != '+' && resent_to_us(&idata))
+ to_us = '+';
+
+ if(to_us == ' ' && F_ON(F_MARK_FOR_CC,ps_global))
+--- 11869,11875 ----
+ break;
+ }
+
+! if(to_us != '+' && !idata.bogus && resent_to_us(&idata))
+ to_us = '+';
+
+ if(to_us == ' ' && F_ON(F_MARK_FOR_CC,ps_global))
+***************
+*** 11436,11442 ****
+ int flags; /* flags to set or clear */
+ {
+ int hiding;
+! unsigned long rawno, msgno;
+ PINETHRD_S *nthrd, *bthrd;
+
+ hiding = (flags == MN_CHID) && v;
+--- 11905,11911 ----
+ int flags; /* flags to set or clear */
+ {
+ int hiding;
+! unsigned long rawno, msgno, next, branch;
+ PINETHRD_S *nthrd, *bthrd;
+
+ hiding = (flags == MN_CHID) && v;
+***************
+*** 11448,11454 ****
+
+ set_lflag(stream, msgmap, msgno, flags, v);
+
+! if(thrd->next && (hiding || !get_lflag(stream,NULL,thrd->rawno,MN_COLL))){
+ nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ set_thread_subtree(stream, nthrd, msgmap, v, flags);
+--- 11917,11924 ----
+
+ set_lflag(stream, msgmap, msgno, flags, v);
+
+! if(thrd->next
+! && (hiding || !get_lflag(stream,NULL,thrd->rawno,MN_COLL))){
+ nthrd = fetch_thread(stream, thrd->next);
+ if(nthrd)
+ set_thread_subtree(stream, nthrd, msgmap, v, flags);
+***************
+*** 11492,11499 ****
+ if(rawno)
+ thrd = fetch_thread(stream, rawno);
+
+! if(thrd && thrd->top && thrd->top != thrd->rawno)
+! thrd = fetch_thread(stream, thrd->top);
+
+ if(!thrd)
+ return 0;
+--- 11962,11969 ----
+ if(rawno)
+ thrd = fetch_thread(stream, rawno);
+
+! if(thrd && thrd->top && top_thread(stream,thrd->top) != thrd->rawno)
+! thrd = fetch_thread(stream, top_thread(stream,thrd->top));
+
+ if(!thrd)
+ return 0;
+***************
+*** 11509,11516 ****
+ set_thread_lflags(stream, thrd, msgmap, MN_CHID2, 1);
+ }
+
+! if(current_index_state)
+! msgmap->top_after_thrd = current_index_state->msg_at_top;
+
+ /*
+ * If this is one of those wacky users who like to sort backwards
+--- 11979,11987 ----
+ set_thread_lflags(stream, thrd, msgmap, MN_CHID2, 1);
+ }
+
+! /* if(current_index_state)
+! msgmap->top_after_thrd = current_index_state->msg_at_top;*/
+! msgmap->top_after_thrd = mn_raw2m(msgmap, thrd->top);
+
+ /*
+ * If this is one of those wacky users who like to sort backwards
+***************
+*** 11563,11569 ****
+ thrd = fetch_thread(stream, rawno);
+
+ if(thrd && thrd->top)
+! topthrd = fetch_thread(stream, thrd->top);
+
+ if(!topthrd)
+ return 0;
+--- 12034,12040 ----
+ thrd = fetch_thread(stream, rawno);
+
+ if(thrd && thrd->top)
+! topthrd = fetch_thread(stream, top_thread(stream,thrd->top));
+
+ if(!topthrd)
+ return 0;
+***************
+*** 11700,11702 ****
+--- 12171,12508 ----
+ }
+ }
+ }
++
++ unsigned long
++ get_branch(stream,thrd)
++ MAILSTREAM *stream;
++ PINETHRD_S *thrd;
++ {
++ PINETHRD_S *nthrd = NULL;
++ unsigned long top;
++
++ if (thrd->toploose && thrd->nextthd)
++ nthrd = fetch_thread(stream, thrd->nextthd);
++ if (!nthrd)
++ return thrd->branch;
++ top = top_thread(stream, thrd->rawno);
++ return thrd->branch
++ ? thrd->branch
++ : (F_ON(F_ENHANCED_THREAD, ps_global)
++ ? (top == top_thread(stream, nthrd->rawno) ? thrd->nextthd : 0L)
++ : 0L);
++ }
++
++ unsigned long
++ get_next(stream,thrd)
++ MAILSTREAM *stream;
++ PINETHRD_S *thrd;
++ {
++ return thrd->next;
++ }
++
++ long
++ get_length_branch(stream, rawno)
++ MAILSTREAM *stream;
++ long rawno;
++ {
++ int branchp = 0, done = 0;
++ long top, count = 1L, raw;
++ PINETHRD_S *thrd, *pthrd = NULL, *nthrd;
++
++ thrd = fetch_thread(stream, rawno);
++
++ if (!thrd)
++ return -1L;
++
++ top = thrd->top;
++
++ if (thrd->parent)
++ pthrd = fetch_thread(stream, thrd->parent);
++
++ if (thrd->rawno == top)
++ branchp++;
++
++ if (!branchp && !pthrd){ /* what!!?? */
++ raw = top;
++ while (!done){
++ pthrd = fetch_thread(stream, raw);
++ if ((pthrd->next == rawno) || (pthrd->branch == rawno))
++ done++;
++ else{
++ if (pthrd->next)
++ raw = pthrd->next;
++ else if (pthrd->branch)
++ raw = pthrd->branch;
++ }
++ }
++ }
++
++ if (pthrd && pthrd->next == thrd->rawno && thrd->branch)
++ branchp++;
++
++ if (pthrd && pthrd->next && pthrd->next != thrd->rawno){
++ nthrd = fetch_thread(stream, pthrd->next);
++ while (nthrd && nthrd->branch && nthrd->branch != thrd->rawno)
++ nthrd = fetch_thread(stream, nthrd->branch);
++ if(nthrd && nthrd->branch && nthrd->branch == thrd->rawno)
++ branchp++;
++ }
++
++ if(branchp){
++ int entry = 0;
++ while(thrd && thrd->next){
++ entry = 1;
++ count++;
++ thrd = fetch_thread(stream, thrd->next);
++ if (thrd->branch)
++ break;
++ }
++ if (entry && thrd->branch)
++ count--;
++ }
++ return branchp ? (count ? count : 1L) : 0L;
++ }
++
++ void
++ find_msgmap(stream, msgmap, flags, ordersort, is_rev)
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ int flags;
++ SortOrder ordersort;
++ unsigned is_rev;
++ {
++ int we_cancel;
++ long *old_arrival,*new_arrival;
++ long init_thread, end_thread, current;
++ long k = 1L, j, last_thread = 0L;
++ long i, tmsg, ntmsg, nthreads;
++ int nflags = (SRT_VRB | SRT_MAN);
++ char sort_msg[MAX_SCREEN_COLS+1] = {'\0'};
++ PINETHRD_S *thrd, *tthrd, *nthrd;
++
++ erase_thread_info = 0;
++ current = mn_m2raw(msgmap, mn_get_cur(msgmap));
++
++ /* now sort by arrival */
++ sort_folder(stream, msgmap, ordersort, 0, nflags, 0);
++
++ tmsg = mn_get_total(msgmap) + 1;
++
++ if (tmsg <= 1)
++ return;
++
++ old_arrival = (long *) fs_get(tmsg * sizeof(long));
++ memset(old_arrival, 0, tmsg*sizeof(long));
++ for (i= 1L;(i <= mn_get_total(msgmap)) && (old_arrival[i] = msgmap->sort[i]); i++);
++
++ /* now sort by thread */
++ sort_folder(stream, msgmap, SortThread, 0, nflags, 0);
++ ntmsg = mn_get_total(msgmap) + 1;
++
++ if (tmsg != ntmsg){ /* oh oh, something happened,we better try again */
++ fs_give((void **)&old_arrival);
++ find_msgmap(stream, msgmap, flags, ordersort, is_rev);
++ return;
++ }
++
++ /* reconstruct the msgmap */
++
++ new_arrival = (long *) fs_get(tmsg * sizeof(long));
++ memset(new_arrival, 0, tmsg*sizeof(long));
++ i = mn_get_total(msgmap);
++ while (new_arrival[1] == 0){ /* think of this as (tmsg > 0) */
++ int done = 0;
++ long n = mn_get_total(msgmap);
++
++ init_thread = top_thread(stream, old_arrival[i]);
++ thrd = fetch_thread(stream, init_thread);
++ while ((new_arrival[n] != 0) && !done){ /* compare raw numbers */
++ done = (new_arrival[n] == init_thread);
++ n--;
++ }
++ if (!done){
++ k = 1L;
++ mn_set_cur(msgmap, mn_raw2m(msgmap, init_thread));
++ if (move_next_thread(ps_global, stream, msgmap, 0) <= 0)
++ j = mn_get_total(msgmap) - mn_raw2m(msgmap, init_thread) + 1;
++ else
++ j = mn_get_cur(msgmap) - mn_raw2m(msgmap, init_thread);
++ end_thread = mn_raw2m(msgmap, init_thread) + j;
++ while (k <= j){
++ new_arrival[tmsg - k] = msgmap->sort[end_thread - k];
++ k++;
++ }
++ tmsg -= j;
++ }
++ i--;
++ }
++ relink_threads(stream, msgmap, new_arrival);
++ for (i = 1; (i <= mn_get_total(msgmap))
++ && (msgmap->sort[i] = new_arrival[i]); i++);
++ msgno_reset_isort(msgmap);
++
++ fs_give((void **)&new_arrival);
++ fs_give((void **)&old_arrival);
++
++
++ if(is_rev && (mn_get_total(msgmap) > 1L)){
++ long *rev_sort;
++ long i = 1L, l = mn_get_total(msgmap);
++
++ rev_sort = (long *) fs_get((mn_get_total(msgmap)+1L) * sizeof(long));
++ memset(rev_sort, 0, (mn_get_total(msgmap)+1L)*sizeof(long));
++ while (l > 0L){
++ if (top_thread(stream, msgmap->sort[l]) == msgmap->sort[l]){
++ long init_thread = msgmap->sort[l];
++ long j, k;
++
++ mn_set_cur(msgmap, mn_raw2m(msgmap, init_thread));
++ if (move_next_thread(ps_global, stream, msgmap, 0) <= 0)
++ j = mn_get_total(msgmap) - mn_raw2m(msgmap, init_thread) + 1;
++ else
++ j = mn_get_cur(msgmap) - mn_raw2m(msgmap, init_thread);
++ for (k = 0L; (k < j) && (rev_sort[i+k] = msgmap->sort[l+k]); k++);
++ i += j;
++ }
++ l--;
++ }
++ relink_threads(stream, msgmap, rev_sort);
++ for (i = 1L; i <= mn_get_total(msgmap); i++)
++ msgmap->sort[i] = rev_sort[i];
++ msgno_reset_isort(msgmap);
++ fs_give((void **)&rev_sort);
++ }
++ mn_reset_cur(msgmap, first_sorted_flagged(is_rev ? F_NONE : F_SRCHBACK,
++ stream, mn_raw2m(msgmap, current), FSF_SKIP_CHID));
++ msgmap->top = -1L;
++
++ sp_set_unsorted_newmail(ps_global->mail_stream, 0);
++
++ for(i = 1L; i <= ps_global->mail_stream->nmsgs; i++)
++ mail_elt(ps_global->mail_stream, i)->spare7 = 0;
++
++ mn_set_sort(msgmap, SortThread);
++ mn_set_revsort(msgmap, is_rev);
++ erase_thread_info = 1;
++ clear_index_cache();
++ }
++
++ void
++ move_thread(state, stream, msgmap, direction)
++ struct pine *state;
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ int direction;
++ {
++ long new_cursor, old_cursor = mn_get_cur(msgmap);
++ int rv;
++ PINETHRD_S *thrd;
++
++ rv = direction > 0 ? move_next_thread(state, stream, msgmap, 1):
++ move_prev_thread(state, stream, msgmap, 1);
++ if (rv > 0 && THRD_INDX_ENABLED()){
++ new_cursor = mn_get_cur(msgmap);
++ mn_set_cur(msgmap, old_cursor);
++ unview_thread(state, stream, msgmap);
++ thrd = fetch_thread(stream,mn_m2raw(msgmap, new_cursor));
++ mn_set_cur(msgmap, new_cursor);
++ view_thread(state, stream, msgmap, 1);
++ state->next_screen = SCREEN_FUN_NULL;
++ }
++ }
++
++ void
++ relink_threads(stream, msgmap, new_arrival)
++ MAILSTREAM *stream;
++ MSGNO_S *msgmap;
++ long *new_arrival;
++ {
++ long last_thread = 0L;
++ long i = 0L, j = 1L, k;
++ PINETHRD_S *thrd, *nthrd;
++
++ while (j <= mn_get_total(msgmap)){
++ i++;
++ thrd = fetch_thread(stream, new_arrival[j]);
++ if (!thrd) /* sort failed!, better leave from here now!!! */
++ break;
++ thrd->prevthd = last_thread;
++ thrd->thrdno = i;
++ thrd->head = new_arrival[1];
++ last_thread = thrd->rawno;
++ mn_set_cur(msgmap, mn_raw2m(msgmap,thrd->top));
++ k = mn_get_cur(msgmap);
++ if (move_next_thread(ps_global, stream, msgmap, 0) <= 0)
++ j += mn_get_total(msgmap) + 1 - k;
++ else
++ j += mn_get_cur(msgmap) - k;
++ if (!thrd->toploose)
++ thrd->nextthd = (j <= mn_get_total(msgmap)) ? new_arrival[j] : 0L;
++ else{
++ int done = 0;
++ while(thrd->nextthd && !done){
++ thrd->thrdno = i;
++ thrd->head = new_arrival[1];
++ if (thrd->nextthd)
++ nthrd = fetch_thread(stream, thrd->nextthd);
++ else
++ done++;
++ if(top_thread(stream, thrd->rawno) == top_thread(stream, nthrd->rawno))
++ thrd = nthrd;
++ else
++ done++;
++ }
++ thrd->nextthd = (j <= mn_get_total(msgmap)) ? new_arrival[j] : 0L;
++ last_thread = thrd->rawno;
++ }
++ }
++ }
++
++
++ int
++ find_index_rule()
++ {
++ int found = 0;
++ RULE_RESULT *rule;
++ INDEXDATA_S idata;
++ ENVELOPE *local_env;
++
++ memset(&idata, 0, sizeof(INDEXDATA_S));
++ idata.stream = ps_global->mail_stream;
++ local_env = (ENVELOPE *)make_envelope(&idata, 0);
++ rule = get_result_rule(V_INDEX_RULES, FOR_RULE | FOR_INDEX, local_env);
++ if (local_env)
++ mail_free_envelope(&local_env);
++ if (rule){
++ init_index_format(rule->result, &ps_global->index_disp_format);
++ found = 1;
++ if (rule->result)
++ fs_give((void **)&rule->result);
++ fs_give((void **)&rule);
++ }
++ return found;
++ }
++
++ void
++ setup_threading_display_style()
++ {
++ RULE_RESULT *rule;
++ NAMEVAL_S *v;
++ int i;
++
++ rule = get_result_rule(V_THREAD_DISP_STYLE_RULES,
++ FOR_RULE | FOR_THREAD, (ENVELOPE *) 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);
++ }
++ }
++ }
+diff -rc pine4.63/pine/mailpart.c pine4.63.I.USE/pine/mailpart.c
+*** pine4.63/pine/mailpart.c Wed Apr 27 11:55:01 2005
+--- pine4.63.I.USE/pine/mailpart.c Thu May 19 19:57:32 2005
+***************
+*** 815,822 ****
+--- 815,828 ----
+ /*--- get string ---*/
+ {int rc, found = 0;
+ char *result = NULL, buf[64];
++ static char last_pat[64] = {'\0'};
+ static char last[64], tmp[64];
+ HelpType help;
++ static ESCKEY_S ekey[] = {
++ {0, 0, "", ""},
++ {ctrl('N'), 9, "^N", "Ins Pat"},
++ {-1, 0, NULL, NULL}};
++
+
+ ps->mangled_footer = 1;
+ buf[0] = '\0';
+***************
+*** 829,846 ****
+ int flags = OE_APPEND_CURRENT | OE_SEQ_SENSITIVE;
+
+ rc = optionally_enter(buf,-FOOTER_ROWS(ps),0,sizeof(buf),
+! tmp,NULL,help,&flags);
+ if(rc == 3)
+ help = help == NO_HELP ? h_attach_index_whereis : NO_HELP;
+! else if(rc == 0 || rc == 1 || !buf[0]){
+ if(rc == 0 && !buf[0] && last[0])
+ strcpy(buf, last);
+!
+! break;
+ }
+ }
+
+ if(rc == 0 && buf[0]){
+ ctmp = current;
+ while(ctmp = next_attline(ctmp))
+ if(srchstr(ctmp->dstring, buf)){
+--- 835,857 ----
+ int flags = OE_APPEND_CURRENT | OE_SEQ_SENSITIVE;
+
+ rc = optionally_enter(buf,-FOOTER_ROWS(ps),0,sizeof(buf),
+! tmp,ekey,help,&flags);
+ if(rc == 3)
+ help = help == NO_HELP ? h_attach_index_whereis : NO_HELP;
+! else if(rc == 0 || rc == 1 || rc == 9 || !buf[0]){
+ if(rc == 0 && !buf[0] && last[0])
+ strcpy(buf, last);
+! if (rc == 9)
+! insert_pattern_in_string(buf, last_pat, 63);
+! else
+! break;
+ }
+ }
+
+ if(rc == 0 && buf[0]){
++ strncpy(last_pat, buf, sizeof(last_pat));
++ last_pat[sizeof(last_pat)-1] = '\0';
++
+ ctmp = current;
+ while(ctmp = next_attline(ctmp))
+ if(srchstr(ctmp->dstring, buf)){
+***************
+*** 3463,3469 ****
+ /*
+ * For consistency, the first question is always "include text?"
+ */
+! if((include_text = reply_text_query(ps_global, 1, &prefix)) >= 0
+ && reply_news_test(a->body->nested.msg->env, outgoing) > 0
+ && reply_harvest(ps_global, msgno, a->number,
+ a->body->nested.msg->env, &saved_from,
+--- 3474,3480 ----
+ /*
+ * For consistency, the first question is always "include text?"
+ */
+! if((include_text = reply_text_query(ps_global, 1, NULL, &prefix)) >= 0
+ && reply_news_test(a->body->nested.msg->env, outgoing) > 0
+ && reply_harvest(ps_global, msgno, a->number,
+ a->body->nested.msg->env, &saved_from,
+diff -rc pine4.63/pine/mailview.c pine4.63.I.USE/pine/mailview.c
+*** pine4.63/pine/mailview.c Wed Apr 27 11:55:02 2005
+--- pine4.63.I.USE/pine/mailview.c Thu May 19 19:57:34 2005
+***************
+*** 75,80 ****
+--- 75,89 ----
+ int len;
+ } SCRLFILE_S;
+
++ #include <regex.h>
++
++ #define REGERROR 128
++
++ typedef struct IVAL {
++ int start;
++ int end;
++ struct IVAL *next;
++ } IVAL_S;
+
+ /*
+ * Struct to help write lines do display as they're decoded
+***************
+*** 152,157 ****
+--- 161,167 ----
+ #define SS_CUR 2
+ #define SS_FREE 3
+
++ static ACTION_S *role_chosen = NULL;
+
+ /*
+ * Def's to help page reframing based on handles
+***************
+*** 235,246 ****
+ HOMEKEY_MENU,
+ ENDKEY_MENU,
+ RCOMPOSE_MENU,
+! NULL_MENU,
+! NULL_MENU,
+! NULL_MENU,
+! NULL_MENU,
+! NULL_MENU,
+! NULL_MENU,
+ NULL_MENU};
+ INST_KEY_MENU(view_keymenu, view_keys);
+ #define VIEW_ATT_KEY 3
+--- 245,256 ----
+ HOMEKEY_MENU,
+ ENDKEY_MENU,
+ RCOMPOSE_MENU,
+! {"(","Prev Threa",{MC_PRETHREAD,1,{'('}},KS_NONE},
+! {")","Next Threa",{MC_NEXTHREAD,1,{')'}},KS_NONE},
+! {"^D","Delete Thr",{MC_DELTHREAD,1,{ctrl('D')}},KS_NONE},
+! {"^U","Undel Thre",{MC_UNDTHREAD,1,{ctrl('U')}},KS_NONE},
+! {"^T","selcT Thre",{MC_SELTHREAD,1,{ctrl('T')}},KS_NONE},
+! {"^H","ChkIncFl",{MC_FORCECHECK,1,{ctrl('H')}},KS_NONE},
+ NULL_MENU};
+ INST_KEY_MENU(view_keymenu, view_keys);
+ #define VIEW_ATT_KEY 3
+***************
+*** 268,274 ****
+ {"S", "Save", {MC_SAVETEXT,1,{'s'}}, KS_SAVE}};
+ INST_KEY_MENU(simple_text_keymenu, simple_text_keys);
+
+!
+
+
+ /*
+--- 278,289 ----
+ {"S", "Save", {MC_SAVETEXT,1,{'s'}}, KS_SAVE}};
+ INST_KEY_MENU(simple_text_keymenu, simple_text_keys);
+
+! static char *prefix;
+! #define NO_FLOWED 0x0000
+! #define IS_FLOWED 0x0001
+! #define DELETEQUO 0x0010
+! #define COLORAQUO 0x0100
+! #define RAWSTRING 0x1000
+
+
+ /*
+***************
+*** 362,367 ****
+--- 377,392 ----
+ void embed_color PROTO((COLOR_PAIR *, gf_io_t));
+ int color_a_quote PROTO((long, char *, LT_INS_S **, void *));
+ int color_signature PROTO((long, char *, LT_INS_S **, void *));
++ IVAL_S *copy_ival PROTO((IVAL_S *));
++ IVAL_S * compute_interval PROTO((char *, char *, int));
++ void remove_spaces_ival PROTO((IVAL_S **, char *));
++ void interval_free PROTO((IVAL_S **));
++ char * regex_pattern PROTO((char **));
++ LT_INS_S ** insert_color_special_text PROTO((LT_INS_S **, char **, IVAL_S *,
++ int, COLOR_PAIR *));
++ int any_color_in_string PROTO((char *));
++ int length_color PROTO((char *, int));
++ int color_this_text PROTO((long, char *, LT_INS_S **, void *));
+ int color_headers PROTO((long, char *, LT_INS_S **, void *));
+ int url_hilite_hdr PROTO((long, char *, LT_INS_S **, void *));
+ int url_launch PROTO((HANDLE_S *));
+***************
+*** 386,391 ****
+--- 411,418 ----
+ int pcpine_resize_scroll PROTO((void));
+ int pcpine_view_cursor PROTO((int, long));
+ #endif
++ int is_word PROTO((char [], int, int));
++ int is_mailbox PROTO((char [], int, int));
+
+
+
+***************
+*** 420,425 ****
+--- 447,453 ----
+ HANDLE_S *handles = NULL;
+ SCROLL_S scrollargs;
+ SourceType src = CharStar;
++ FOLDER_S *f = NULL;
+
+ dprint(1, (debugfile, "\n\n ----- MAIL VIEW -----\n"));
+
+***************
+*** 473,478 ****
+--- 501,517 ----
+ else
+ ps->unseen_in_view = !mc->seen;
+
++ prefix = reply_quote_str(env);
++ /* Make sure the prefix is not only made of spaces, so that we do not
++ * paint the screen incorrectly
++ */
++ if (prefix && *prefix){
++ int i;
++ for (i = 0; isspace((unsigned char) prefix[i]); i++);
++ if (i == strlen(prefix))
++ fs_give((void **)&prefix);
++ }
++
+ #if defined(DOS) && !defined(WIN32)
+ /*
+ * Handle big text for DOS here.
+***************
+*** 634,639 ****
+--- 673,680 ----
+ }
+ while(ps->next_screen == SCREEN_FUN_NULL);
+
++ if (prefix && *prefix)
++ fs_give((void **)&prefix);
+ if(we_cancel)
+ cancel_busy_alarm(-1);
+
+***************
+*** 1590,1595 ****
+--- 1631,1644 ----
+ if((flgs & FM_DISPLAY)
+ && !(flgs & FM_NOCOLOR)
+ && pico_usingcolor()
++ && ps_global->VAR_SPECIAL_TEXT_FORE_COLOR
++ && ps_global->VAR_SPECIAL_TEXT_BACK_COLOR){
++ gf_link_filter(gf_line_test, gf_line_test_opt(color_this_text, NULL));
++ }
++
++ if((flgs & FM_DISPLAY)
++ && !(flgs & FM_NOCOLOR)
++ && pico_usingcolor()
+ && ps_global->VAR_SIGNATURE_FORE_COLOR
+ && ps_global->VAR_SIGNATURE_BACK_COLOR){
+ gf_link_filter(gf_line_test, gf_line_test_opt(color_signature, &is_in_sig));
+***************
+*** 1600,1607 ****
+ && pico_usingcolor()
+ && ps_global->VAR_QUOTE1_FORE_COLOR
+ && ps_global->VAR_QUOTE1_BACK_COLOR){
+! gf_link_filter(gf_line_test, gf_line_test_opt(color_a_quote, NULL));
+ }
+
+ wrapflags = (flgs & FM_DISPLAY) ? GFW_HANDLES : 0;
+ if(flgs & FM_DISPLAY
+--- 1649,1658 ----
+ && pico_usingcolor()
+ && ps_global->VAR_QUOTE1_FORE_COLOR
+ && ps_global->VAR_QUOTE1_BACK_COLOR){
+! gf_link_filter(gf_quote_test,gf_line_test_opt(color_a_quote, NULL));
+ }
++ else
++ gf_link_filter(gf_quote_test,gf_line_test_opt(select_quote, NULL));
+
+ wrapflags = (flgs & FM_DISPLAY) ? GFW_HANDLES : 0;
+ if(flgs & FM_DISPLAY
+***************
+*** 2691,2696 ****
+--- 2742,2749 ----
+ {0, 'a', "A", "editApp"},
+ {-1, 0, NULL, NULL}};
+
++ if (role_chosen)
++ free_action(&role_chosen);
+ if(handle->type == URL){
+ launch_opts[4].ch = 'u';
+
+***************
+*** 2801,2811 ****
+ * sense if you just say View selected URL ...
+ */
+ if(handle->type == URL &&
+! !struncmp(handle->h.url.path, "mailto:", 7))
+! sprintf(prompt, "Compose mail to \"%.*s%s\" ? ",
+! min(max(0,sc - 25), sizeof(prompt)-50), handle->h.url.path+7,
+! (strlen(handle->h.url.path+7) > max(0,sc-25)) ? "..." : "");
+! else
+ sprintf(prompt, "View selected %s %s%.*s%s ? ",
+ (handle->type == URL) ? "URL" : "Attachment",
+ (handle->type == URL) ? "\"" : "",
+--- 2854,2894 ----
+ * sense if you just say View selected URL ...
+ */
+ if(handle->type == URL &&
+! !struncmp(handle->h.url.path, "mailto:", 7)){
+! int rolenick = role_chosen ? strlen(role_chosen->nick) : 0;
+! int offset = 25 + (role_chosen ? 20 : 0);
+! int offset2 = max(0, sc - offset) - strlen(handle->h.url.path+7);
+! int offset3 = sc - strlen(handle->h.url.path+7) - rolenick - offset;
+! int laddress = min(max(0,sc - offset), sizeof(prompt)-50);
+! int lrole = rolenick;
+!
+! if (offset3 < 0){
+! lrole = rolenick;
+! laddress = sc - offset - lrole;
+! offset3 = laddress - 20; /* redefine offset3 */
+! if (offset3 < 0){
+! laddress = 20;
+! lrole = sc - offset - laddress;
+! }
+! }
+! launch_opts[2].ch = 'r';
+! launch_opts[2].rval = 'r';
+! launch_opts[2].name = "R";
+! launch_opts[2].label = "Set Role";
+! sprintf(prompt, "Compose mail to \"%.*s%s\" %s%.*s%s%s? ",
+! laddress, handle->h.url.path+7,
+! offset2 < 0 ? "..." : "",
+! role_chosen ? "using role \"" : "",
+! role_chosen ? lrole : 0,
+! role_chosen ? role_chosen->nick : "",
+! role_chosen ? (rolenick > lrole ? "..." : "") : "",
+! role_chosen ? "\" " : "");
+! }
+! else{
+! launch_opts[2].ch = -2;
+! launch_opts[2].rval = 0;
+! launch_opts[2].name = NULL;
+! launch_opts[2].label = NULL;
+ sprintf(prompt, "View selected %s %s%.*s%s ? ",
+ (handle->type == URL) ? "URL" : "Attachment",
+ (handle->type == URL) ? "\"" : "",
+***************
+*** 2814,2825 ****
+--- 2897,2931 ----
+ (handle->type == URL)
+ ? ((strlen(handle->h.url.path) > max(0,sc-27))
+ ? "...\"" : "\"") : "");
++ }
+
+ switch(radio_buttons(prompt, -FOOTER_ROWS(ps_global),
+ launch_opts, 'y', 'n', NO_HELP, RB_SEQ_SENSITIVE)){
+ case 'y' :
+ return(1);
+
++ case 'r':
++ {
++ void (*prev_screen)() = ps_global->prev_screen,
++ (*redraw)() = ps_global->redrawer;
++ ps_global->redrawer = NULL;
++ ps_global->next_screen = SCREEN_FUN_NULL;
++ if(role_select_screen(ps_global, &role_chosen, 1) < 0){
++ cmd_cancelled("Compose");
++ ps_global->next_screen = prev_screen;
++ ps_global->redrawer = redraw;
++ if(ps_global->redrawer)
++ (*ps_global->redrawer)();
++ return 0;
++ }
++ ps_global->next_screen = prev_screen;
++ ps_global->redrawer = redraw;
++ if(role_chosen)
++ role_chosen = combine_inherited_role(role_chosen);
++ if(ps_global->redrawer)
++ (*ps_global->redrawer)();
++ }
++
+ case 'u' :
+ strncpy(tmp, handle->h.url.path, sizeof(tmp)-1);
+ tmp[sizeof(tmp)-1] = '\0';
+***************
+*** 3481,3486 ****
+--- 3587,3621 ----
+ return(buf);
+ }
+
++ #define is_digit(c) ((((c) >= '0') && ((c) <= '9')) ? 1 : 0)
++
++ #define is_letter(c) (((c) >= 'a' && (c) <= 'z') || \
++ ((c) >= 'A' && (c) <= 'Z'))
++
++ #define next(w,i) ((((w)[(i)]) != 0) ? ((w)[(i) + 1]) : 0)
++
++ #define single_level(c) (((c) == '>') || ((c) == '|') || ((c) == '~') || \
++ ((c) == ']'))
++
++ int
++ is_word (buf, i, j)
++ char buf[NSTRING];
++ int i;
++ int j;
++ {
++ return i <= j && is_letter(buf[i]) ?
++ (i < j ? is_word(buf,i+1,j) : 1) : 0;
++ }
++
++ int
++ is_mailbox(buf,i,j)
++ char buf[NSTRING];
++ int i;
++ int j;
++ {
++ return i <= j && (is_letter(buf[i]) || is_digit(buf[i]) || buf[i] == '.')
++ ? (i < j ? is_mailbox(buf,i+1,j) : 1) : 0;
++ }
+
+ int
+ colorcmp(color1, color2)
+***************
+*** 3503,3508 ****
+--- 3638,3710 ----
+ struct quote_colors *next;
+ };
+
++
++ int
++ next_level_quote(buf, line, i, is_flowed)
++ char *buf;
++ char **line;
++ int i;
++ int is_flowed;
++ {
++ int j;
++
++ if (!single_level(buf[i])){
++ if(is_mailbox(buf,i,i)){
++ for (j = i; buf[j] && !isspace(buf[j]); j++);
++ if (is_word(buf,i,j-1) || is_mailbox(buf,i,j-1))
++ j += isspace(buf[j]) ? 2 : 1;
++ }
++ else{
++ switch(buf[i]){
++ case ':' :
++ if (next(buf,i) != RPAREN)
++ j = i + 1;
++ else
++ j = i + 2;
++ break;
++
++ case '-' :
++ if (next(buf,i) != '-')
++ j = i + 2;
++ else
++ j = i + 3;
++ break;
++
++ case '+' :
++ case '*' :
++ if (next(buf,i) != ' ')
++ j = i + 2;
++ else
++ j = i + 3;
++ break;
++
++ default :
++ for (j = i; buf[j] && !isspace(buf[j])
++ && (!single_level(buf[i]) && !is_letter(buf[j])); j++);
++ j += isspace(buf[j]) ? 1 : 0;
++ break;
++ }
++ }
++ if (line && *line)
++ (*line) += j - i;
++ }
++ else{
++ j = i+1;
++ if (line && *line)
++ (*line)++;
++ }
++ if(!is_flowed){
++ if(line && *line)
++ for(; isspace((unsigned char)*(*line)); (*line)++);
++ for (i = j; isspace((unsigned char) buf[i]); i++);
++ }
++ else i = j;
++ if (is_flowed && i != j)
++ buf[i] = '\0';
++ return i;
++ }
++
++
+ int
+ color_a_quote(linenum, line, ins, is_flowed_msg)
+ long linenum;
+***************
+*** 3510,3528 ****
+ LT_INS_S **ins;
+ void *is_flowed_msg;
+ {
+! int countem = 0;
+ struct variable *vars = ps_global->vars;
+ char *p;
+ struct quote_colors *colors = NULL, *cp, *next;
+ COLOR_PAIR *col = NULL;
+ int is_flowed = is_flowed_msg ? *((int *)is_flowed_msg) : 0;
+
+ p = line;
+! if(!is_flowed)
+! while(isspace((unsigned char)*p))
+! p++;
+
+! if(p[0] == '>'){
+ struct quote_colors *c;
+
+ /*
+--- 3712,3736 ----
+ LT_INS_S **ins;
+ void *is_flowed_msg;
+ {
+! int countem = 0, i, j = 0;
+ struct variable *vars = ps_global->vars;
+ char *p;
++ char buf[NSTRING] = {'\0'};
+ struct quote_colors *colors = NULL, *cp, *next;
+ COLOR_PAIR *col = NULL;
++ int code;
+ int is_flowed = is_flowed_msg ? *((int *)is_flowed_msg) : 0;
+
++ code = (is_flowed ? IS_FLOWED : NO_FLOWED) | COLORAQUO;
++ select_quote(linenum, line, ins, (void *)code);
++ for (i = 0; tmp_20k_buf[i] && (buf[i] = tmp_20k_buf[i]); i++);
++ buf[i] = '\0';
++
+ p = line;
+! for(i = 0; isspace((unsigned char)buf[i]); i++)
+! p++; /*(i = is_flowed ? (buf[j] ? j : 0): j);*/
+
+! if(buf[i]){
+ struct quote_colors *c;
+
+ /*
+***************
+*** 3571,3577 ****
+ free_color_pair(&col);
+
+ cp = NULL;
+! while(*p == '>'){
+ cp = (cp && cp->next) ? cp->next : colors;
+
+ if(countem > 0)
+--- 3779,3785 ----
+ free_color_pair(&col);
+
+ cp = NULL;
+! while(buf[i]){
+ cp = (cp && cp->next) ? cp->next : colors;
+
+ if(countem > 0)
+***************
+*** 3581,3590 ****
+
+ countem = (countem == 1) ? 0 : countem;
+
+! p++;
+! if(!is_flowed)
+! for(; isspace((unsigned char)*p); p++)
+! ;
+ }
+
+ if(colors){
+--- 3789,3797 ----
+
+ countem = (countem == 1) ? 0 : countem;
+
+! i = next_level_quote(buf, &p, i, is_flowed);
+! for (; isspace((unsigned char)*p); p++);
+! for (; isspace((unsigned char)buf[i]); i++);
+ }
+
+ if(colors){
+***************
+*** 3648,3653 ****
+--- 3855,3919 ----
+ return(0);
+ }
+
++ /* This filter gives a quote string of a line. It sends its reply back to the
++ calling filter in the tmp_20k_buf variable. This filter replies with
++ the full quote string including tailing spaces if any. It is the
++ responsibility of the calling filter to figure out if thos spaces are
++ useful for that filter or if they should be removed before doing any
++ useful work. For example, color_a_quote does not require the trailing
++ spaces, but gf_wrap does.
++ */
++ int
++ select_quote(linenum, line, ins, code)
++ long linenum;
++ char *line;
++ LT_INS_S **ins;
++ void *code;
++ {
++ int i;
++ char buf[NSTRING] = {'\0'};
++ char GLine[NSTRING] = {'\0'};
++ char PLine[NSTRING] = {'\0'};
++ char NLine[NSTRING] = {'\0'};
++ static char GLine1[NSTRING] = {'\0'};
++ static char PLine1[NSTRING] = {'\0'};
++ static char GLine2[NSTRING] = {'\0'};
++ static char PLine2[NSTRING] = {'\0'};
++ QSTRING_S *qs;
++ int buflen = NSTRING < SIZEOF_20KBUF ? NSTRING - 1: SIZEOF_20KBUF - 1;
++ int who = ((int) code) & COLORAQUO; /* may I ask who is calling? */
++ int raw = ((int) code) & RAWSTRING; /* return raw string */
++
++ strncpy(GLine, who ? GLine1 : GLine2, buflen);
++ strncpy(PLine, who ? PLine1 : PLine2, buflen);
++
++ if (linenum != 0)
++ strncpy(PLine, GLine, buflen);
++
++ strncpy(NLine, tmp_20k_buf, buflen);
++
++ if (line)
++ strncpy(GLine, line, buflen);
++ else
++ GLine[0] = '\0';
++
++ qs = do_quote_match(prefix && *prefix ? prefix : ">",
++ GLine, NLine, PLine, raw);
++ flatten_qstring(qs, buf);
++ free_qs(&qs);
++ /* do not paint an extra level for a line with a >From string at the
++ * begining of it
++ */
++ if (buf[0]){
++ i = strlen(buf);
++ if (strlen(line) >= i + 6 && !strncmp(line+i-1,">From ", 6))
++ buf[i - 1] = '\0';
++ }
++ strncpy(tmp_20k_buf, buf, buflen);
++ strncpy((who ? GLine1 : GLine2), GLine, buflen);
++ strncpy((who ? PLine1 : PLine2), PLine, buflen);
++ return -1;
++ }
+
+ /*
+ * Paint the signature.
+***************
+*** 3660,3686 ****
+ void *is_in_sig;
+ {
+ struct variable *vars = ps_global->vars;
+! int *in_sig_block;
+ COLOR_PAIR *col = NULL;
+
+ if(is_in_sig == NULL)
+ return 0;
+
+ in_sig_block = (int *) is_in_sig;
+!
+! if(!strcmp(line, SIGDASHES))
+! *in_sig_block = START_SIG_BLOCK;
+! else if(*line == '\0')
+ /*
+ * Suggested by Eduardo: allow for a blank line right after
+ * the sigdashes.
+ */
+ *in_sig_block = (*in_sig_block == START_SIG_BLOCK)
+ ? IN_SIG_BLOCK : OUT_SIG_BLOCK;
+ else
+! *in_sig_block = (*in_sig_block != OUT_SIG_BLOCK)
+ ? IN_SIG_BLOCK : OUT_SIG_BLOCK;
+
+ if(*in_sig_block != OUT_SIG_BLOCK
+ && VAR_SIGNATURE_FORE_COLOR && VAR_SIGNATURE_BACK_COLOR
+ && (col = new_color_pair(VAR_SIGNATURE_FORE_COLOR,
+--- 3926,4005 ----
+ void *is_in_sig;
+ {
+ struct variable *vars = ps_global->vars;
+! int *in_sig_block, i, j,same_qstr = 0;
+ COLOR_PAIR *col = NULL;
++ static char GLine[NSTRING] = {'\0'};
++ static char PLine[NSTRING] = {'\0'};
++ char NLine[NSTRING] = {'\0'};
++ static char *buf, buf2[NSTRING] = {'\0'};
++ QSTRING_S *qs;
++ static qstrlen = 0;
+
+ if(is_in_sig == NULL)
+ return 0;
+
++ if (linenum != 0){
++ for (i = 0; GLine[i] && (PLine[i] = GLine[i]); i++);
++ PLine[i] = '\0';
++ }
++
++ for (i = 0; tmp_20k_buf[i] && (tmp_20k_buf[i] != '\015') && (i < NSTRING)
++ && (i < SIZEOF_20KBUF)
++ && (NLine[i] = tmp_20k_buf[i]); i++);
++ NLine[i] = '\0';
++
++ for (i = 0; (i < NSTRING) && ((GLine[i] = line[i]) != 0); i++);
++ GLine[NSTRING - 1] = '\0';
++ qs = do_quote_match(prefix && *prefix ? prefix : ">",
++ GLine, NLine, PLine, 1);
++ flatten_qstring(qs, buf2);
++ i = buf2 && buf2[0] ? strlen(buf2) : 0;
++ free_qs(&qs);
++
++ /* determine if buf and buf2 are the same quote string */
++ if (!struncmp(buf, buf2, qstrlen)){
++ for (j = qstrlen; buf2[j] && isspace((unsigned char)buf2[j]); j++);
++ if (!buf2[j] || buf2[j] == '|' || (buf2[j] == '*' && buf2[j+1] != '>'))
++ same_qstr++;
++ }
++
+ in_sig_block = (int *) is_in_sig;
+!
+! if (*in_sig_block != OUT_SIG_BLOCK){
+! if (line && *line && (strlen(line) >= qstrlen) && same_qstr)
+! line += qstrlen;
+! else if (strlen(line) < qstrlen)
+! line += i;
+! else if (!same_qstr)
+! *in_sig_block = OUT_SIG_BLOCK;
+! }
+! else
+! line += i;
+!
+! if(!strcmp(line, SIGDASHES) || !strcmp(line, "--")){
+! *in_sig_block = START_SIG_BLOCK;
+! buf = (char *) fs_get((i + 1)*sizeof(char));
+! buf = cpystr(buf2);
+! qstrlen = i;
+! }
+! else if(*line == '\0'){
+ /*
+ * Suggested by Eduardo: allow for a blank line right after
+ * the sigdashes.
+ */
+ *in_sig_block = (*in_sig_block == START_SIG_BLOCK)
+ ? IN_SIG_BLOCK : OUT_SIG_BLOCK;
++ }
+ else
+! *in_sig_block = (*in_sig_block != OUT_SIG_BLOCK)
+ ? IN_SIG_BLOCK : OUT_SIG_BLOCK;
+
++ if (*in_sig_block == OUT_SIG_BLOCK){
++ qstrlen = 0; /* reset back in case there's another paragraph */
++ if (buf)
++ fs_give((void **)&buf);
++ }
++
+ if(*in_sig_block != OUT_SIG_BLOCK
+ && VAR_SIGNATURE_FORE_COLOR && VAR_SIGNATURE_BACK_COLOR
+ && (col = new_color_pair(VAR_SIGNATURE_FORE_COLOR,
+***************
+*** 3751,3756 ****
+--- 4070,4316 ----
+ return 0;
+ }
+
++ IVAL_S *
++ copy_ival(ival)
++ IVAL_S *ival;
++ {
++ IVAL_S *cp;
++
++ if (!ival)
++ return (IVAL_S *)NULL;
++
++ cp = (IVAL_S *) malloc (sizeof(IVAL_S));
++ memset (cp, 0, sizeof(IVAL_S));
++
++ cp->start = ival->start;
++ cp->end = ival->end;
++ cp->next = copy_ival(ival->next);
++ return cp;
++ }
++
++ void
++ interval_free(ival)
++ IVAL_S **ival;
++ {
++ if (!(*ival))
++ return;
++
++ if ((*ival)->next)
++ interval_free(&((*ival)->next));
++
++ (*ival)->next = (IVAL_S *) NULL;
++
++ free((void *)(*ival));
++ *ival = (IVAL_S *) NULL;
++ }
++
++ IVAL_S *
++ compute_interval (string, pattern, endm)
++ char *string;
++ char *pattern;
++ int endm;
++ {
++ IVAL_S *ival = NULL, *nextival= NULL;
++ int error, sizerror;
++ regex_t preg;
++ regmatch_t pmatch;
++
++ if (error = regcomp(&preg, pattern, REG_EXTENDED)){
++ /* char message[REGERROR];
++ sizerror = regerror(error, &preg, message, REGERROR);
++ printf("%s\n", message);*/
++ regfree(&preg);
++ return (IVAL_S *) NULL;
++ }
++ else{
++ if (((error = regexec(&preg, string, 1, &pmatch, 0)) != REG_NOMATCH)
++ && !error){
++ ival = (IVAL_S *) malloc(sizeof(IVAL_S));
++ memset (ival, 0, sizeof(IVAL_S));
++ ival->start = endm + pmatch.rm_so;
++ ival->end = endm + pmatch.rm_eo;
++ nextival = compute_interval(string+pmatch.rm_so+1, pattern, ival->start+1);
++ if (nextival){
++ if (nextival->start <= ival->end){
++ ival->end = nextival->end;
++ ival->next = copy_ival(nextival->next);
++ interval_free(&nextival);
++ }
++ else
++ ival->next = nextival;
++ }
++ }
++ }
++ regfree(&preg);
++ return ival;
++ }
++
++ char *
++ regex_pattern(plist)
++ char **plist;
++ {
++ int i = 0, j = 0, k = 0, n = 0, len = 0;
++ char *pattern = NULL;
++
++ if(plist && plist[0] && plist[0][0]){
++ for (i = 0; plist[i] && plist[i][0]; i++)
++ len += strlen(plist[i]) + 1;
++ pattern = (char *) fs_get(len * sizeof(char));
++ for (j = 0; j < i; j++){
++ for(k = 0; plist[j][k]; k++)
++ pattern[n++] = plist[j][k];
++ pattern[n++] = (j == i - 1) ? '\0' : '|';
++ }
++ }
++ return pattern;
++ }
++
++ LT_INS_S **
++ insert_color_special_text(ins, p, ival, last_end, col)
++ LT_INS_S **ins;
++ char **p;
++ IVAL_S *ival;
++ int last_end;
++ COLOR_PAIR *col;
++ {
++ struct variable *vars = ps_global->vars;
++
++ if (ival){
++ *p += ival->start - last_end;
++ ins = gf_line_test_new_ins(ins, *p, color_embed(col->fg, col->bg),
++ (2 * RGBLEN) + 4);
++ *p += ival->end - ival->start;
++ ins = gf_line_test_new_ins(ins, *p, color_embed(VAR_NORM_FORE_COLOR,
++ VAR_NORM_BACK_COLOR), (2 * RGBLEN) + 4);
++ ins = insert_color_special_text(ins, p, ival->next, ival->end, col);
++ }
++ return ins;
++ }
++
++ int
++ length_color(p, begin_color)
++ char *p;
++ int begin_color;
++ {
++ int len = 0, done = begin_color ? 0 : -1;
++ char *orig = p;
++
++ while (*p && done <= 0){
++ switch(*p++){
++ case TAG_HANDLE :
++ p += *p + 1;
++ done++;
++ break;
++
++ case TAG_FGCOLOR :
++ case TAG_BGCOLOR :
++ p += RGBLEN;
++ if (!begin_color)
++ done++;
++ break;
++
++ default :
++ break;
++ }
++ }
++ len = p - orig;
++ return len;
++ }
++
++ int
++ any_color_in_string(p)
++ char *p;
++ {
++ int rv = 0;
++ char *orig = p;
++ while (*p && !rv)
++ if (*p++ == TAG_EMBED)
++ rv = p - orig;
++ return rv;
++ }
++
++ void
++ remove_spaces_ival(ivalp, p)
++ IVAL_S **ivalp;
++ char *p;
++ {
++ IVAL_S *ival;
++ int i;
++ if (!ivalp || !*ivalp)
++ return;
++ ival = *ivalp;
++ for (i = 0; isspace((unsigned char) p[ival->start + i]); i++);
++ if (ival->start + i < ival->end) /* do not do this if match only spaces */
++ ival->start += i;
++ else
++ return;
++ for (i = 0; isspace((unsigned char) p[ival->end - i - 1]); i++);
++ ival->end -= i;
++ if (ival->next)
++ remove_spaces_ival(&(ival->next), p);
++ }
++
++ int
++ color_this_text(linenum, line, ins, local)
++ long linenum;
++ char *line;
++ LT_INS_S **ins;
++ void *local;
++ {
++ struct variable *vars = ps_global->vars;
++ COLOR_PAIR *col = NULL;
++ char *p;
++ int i;
++ static char *pattern = NULL;
++
++ select_quote(linenum, line, ins, NULL);
++ p = line + strlen(tmp_20k_buf);
++
++ if(VAR_SPECIAL_TEXT_FORE_COLOR && VAR_SPECIAL_TEXT_BACK_COLOR
++ && (col = new_color_pair(VAR_SPECIAL_TEXT_FORE_COLOR,
++ VAR_SPECIAL_TEXT_BACK_COLOR))
++ && !pico_is_good_colorpair(col))
++ free_color_pair(&col);
++
++ if (linenum == 0){
++ if (pattern)
++ fs_give((void **)&pattern);
++ pattern = regex_pattern(ps_global->VAR_SPECIAL_TEXT);
++ }
++
++ if(pattern && col){
++ IVAL_S *ival;
++ int done = 0, begin_color = 0;
++
++ while (!done){
++ if (i = any_color_in_string(p)){
++ begin_color = (begin_color + 1) % 2;
++ if (begin_color){
++ p[i - 1] = '\0';
++ ival = compute_interval(p, pattern, 0);
++ remove_spaces_ival(&ival, p);
++ p[i - 1] = TAG_EMBED;
++ ins = insert_color_special_text(ins, &p, ival, 0, col);
++ }
++ for (;*p++ != TAG_EMBED; );
++ p += length_color(p, begin_color);
++ }
++ else{
++ ival = compute_interval(p, pattern, 0);
++ remove_spaces_ival(&ival, p);
++ ins = insert_color_special_text(ins, &p, ival, 0, col);
++ done++;
++ }
++ interval_free(&ival);
++ if (!*p)
++ done++;
++ }
++ free_color_pair(&col);
++ }
++
++ return 0;
++ }
++
+
+ /*
+ * Replace quotes of nonflowed messages. This needs to happen
+***************
+*** 3843,3849 ****
+ {
+ DELQ_S *dq;
+ char *lp;
+! int i, lines, not_a_quote = 0;
+ size_t len;
+
+ dq = (DELQ_S *) local;
+--- 4403,4409 ----
+ {
+ DELQ_S *dq;
+ char *lp;
+! int i, lines, not_a_quote = 0, code, feedback;
+ size_t len;
+
+ dq = (DELQ_S *) local;
+***************
+*** 3853,3858 ****
+--- 4413,4419 ----
+ if(dq->lines > 0 || dq->lines == Q_DEL_ALL){
+
+ lines = (dq->lines == Q_DEL_ALL) ? 0 : dq->lines;
++ feedback = (dq->lines == Q_DEL_ALL) ? 0 : 1;
+
+ /*
+ * First determine if this line is part of a quote.
+***************
+*** 3863,3868 ****
+--- 4424,4432 ----
+ for(i = dq->indent_length; i > 0 && !not_a_quote && *lp; i--)
+ if(*lp++ != SPACE)
+ not_a_quote++;
++
++ while(isspace((unsigned char) *lp))
++ lp++;
+
+ /* skip over leading tags */
+ while(!not_a_quote
+***************
+*** 3902,3918 ****
+ }
+ }
+
+! /* skip over whitespace */
+! if(!dq->is_flowed)
+! while(isspace((unsigned char) *lp))
+! lp++;
+!
+! /* check first character to see if it is a quote */
+! if(!not_a_quote && *lp != '>')
+! not_a_quote++;
+
+ if(not_a_quote){
+! if(dq->in_quote > lines+1){
+ char tmp[500];
+
+ /*
+--- 4466,4481 ----
+ }
+ }
+
+! code = (dq->is_flowed ? IS_FLOWED : NO_FLOWED) | DELETEQUO;
+! len = lp - line;
+! if(strlen(tmp_20k_buf) > len)
+! strcpy(tmp_20k_buf, tmp_20k_buf+len);
+! select_quote(linenum, lp, ins, (void *) code);
+! if (!not_a_quote && !tmp_20k_buf[0])
+! not_a_quote++;
+
+ if(not_a_quote){
+! if(dq->in_quote > lines+1 && feedback){
+ char tmp[500];
+
+ /*
+***************
+*** 5017,5023 ****
+ fs_give((void **) &urlp);
+
+ rflags = ROLE_COMPOSE;
+! if(nonempty_patterns(rflags, &dummy)){
+ role = set_role_from_msg(ps_global, rflags, -1L, NULL);
+ if(confirm_role(rflags, &role))
+ role = combine_inherited_role(role);
+--- 5580,5586 ----
+ fs_give((void **) &urlp);
+
+ rflags = ROLE_COMPOSE;
+! if(!(role = copy_action(role_chosen)) && nonempty_patterns(rflags, &dummy)){
+ role = set_role_from_msg(ps_global, rflags, -1L, NULL);
+ if(confirm_role(rflags, &role))
+ role = combine_inherited_role(role);
+***************
+*** 5093,5098 ****
+--- 5656,5662 ----
+
+ free_redraft_pos(&redraft_pos);
+ free_action(&role);
++ free_action(&role_chosen);
+
+ return(rv);
+ }
+***************
+*** 5665,5671 ****
+ char *err, *charset;
+ int filtcnt = 0, error_found = 0, column, wrapit;
+ int is_in_sig = OUT_SIG_BLOCK;
+! int is_flowed_msg = 0;
+ int is_delsp_yes = 0;
+ int filt_only_c0 = 0;
+ char *parmval;
+--- 6229,6235 ----
+ char *err, *charset;
+ int filtcnt = 0, error_found = 0, column, wrapit;
+ int is_in_sig = OUT_SIG_BLOCK;
+! int is_flowed_msg = 0, add_me = 1;
+ int is_delsp_yes = 0;
+ int filt_only_c0 = 0;
+ char *parmval;
+***************
+*** 5767,5772 ****
+--- 6331,6345 ----
+ filters[filtcnt++].data = gf_line_test_opt(url_hilite, handlesp);
+ }
+
++ if((flags & FM_DISPLAY)
++ && !(flags & FM_NOCOLOR)
++ && pico_usingcolor()
++ && VAR_SPECIAL_TEXT_FORE_COLOR
++ && VAR_SPECIAL_TEXT_BACK_COLOR){
++ filters[filtcnt].filter = gf_line_test;
++ filters[filtcnt++].data = gf_line_test_opt(color_this_text, NULL);
++ }
++
+ /*
+ * First, paint the signature.
+ * Disclaimers noted below for coloring quotes apply here as well.
+***************
+*** 5794,5802 ****
+ && pico_usingcolor()
+ && VAR_QUOTE1_FORE_COLOR
+ && VAR_QUOTE1_BACK_COLOR){
+! filters[filtcnt].filter = gf_line_test;
+! filters[filtcnt++].data = gf_line_test_opt(color_a_quote,
+! &is_flowed_msg);
+ }
+ }
+ else if(!strucmp(att->body->subtype, "richtext")){
+--- 6367,6375 ----
+ && pico_usingcolor()
+ && VAR_QUOTE1_FORE_COLOR
+ && VAR_QUOTE1_BACK_COLOR){
+! add_me = 0;
+! filters[filtcnt].filter = gf_quote_test;
+! filters[filtcnt++].data = gf_line_test_opt(color_a_quote, &is_flowed_msg);
+ }
+ }
+ else if(!strucmp(att->body->subtype, "richtext")){
+***************
+*** 5866,5871 ****
+--- 6439,6450 ----
+ }
+ }
+
++ if (add_me){
++ filters[filtcnt].filter = gf_quote_test;
++ filters[filtcnt++].data = gf_line_test_opt(select_quote,
++ (void *) RAWSTRING);
++ }
++
+ if(wrapit && !(flags & FM_NOWRAP)){
+ int margin = 0, wrapflags = (flags & FM_DISPLAY) ? GFW_HANDLES : 0;
+
+***************
+*** 5913,5919 ****
+ dq.saved_line = &free_this;
+ dq.handlesp = handlesp;
+
+! filters[filtcnt].filter = gf_line_test;
+ filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq);
+ }
+
+--- 6492,6498 ----
+ dq.saved_line = &free_this;
+ dq.handlesp = handlesp;
+
+! filters[filtcnt].filter = gf_quote_test;
+ filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq);
+ }
+
+***************
+*** 6453,6460 ****
+ format_addr_string(s, n, sect, "Return-Path: ", e->return_path,
+ flags, pc);
+
+! if((which & FE_NEWSGROUPS) && e->newsgroups)
+ format_newsgroup_string("Newsgroups: ", e->newsgroups, flags, pc);
+
+ if((which & FE_FOLLOWUPTO) && e->followup_to)
+ format_newsgroup_string("Followup-To: ", e->followup_to, flags, pc);
+--- 7032,7051 ----
+ format_addr_string(s, n, sect, "Return-Path: ", e->return_path,
+ flags, pc);
+
+! if((which & FE_NEWSGROUPS) && e->newsgroups){
+! int bogus = NIL;
+ format_newsgroup_string("Newsgroups: ", e->newsgroups, flags, pc);
++ if (!e->ngpathexists && e->message_id &&
++ strncmp (e->message_id,"<Pine.",6) &&
++ strncmp (e->message_id,"<MS-C.",6) &&
++ strncmp (e->message_id,"<MailManager.",13) &&
++ strncmp (e->message_id,"<EasyMail.",11) &&
++ strncmp (e->message_id,"<ML-",4)) bogus = T;
++
++ if(bogus)
++ q_status_message(SM_ORDER, 0, 3,
++ "Unverified Newsgroup header -- Message MAY or MAY NOT have been posted");
++ }
+
+ if((which & FE_FOLLOWUPTO) && e->followup_to)
+ format_newsgroup_string("Followup-To: ", e->followup_to, flags, pc);
+***************
+*** 7189,7196 ****
+ {
+ register long cur_top_line, num_display_lines;
+ int result, done, ch, cmd, found_on, found_on_col,
+! first_view, force, scroll_lines, km_size,
+! cursor_row, cursor_col, km_popped;
+ long jn;
+ struct key_menu *km;
+ HANDLE_S *next_handle;
+--- 7780,7787 ----
+ {
+ register long cur_top_line, num_display_lines;
+ int result, done, ch, cmd, found_on, found_on_col,
+! first_view, force, scroll_lines, km_size, skip = 0,
+! cursor_row, cursor_col, km_popped, nm;
+ long jn;
+ struct key_menu *km;
+ HANDLE_S *next_handle;
+***************
+*** 7397,7403 ****
+
+ /*============ Check for New Mail and CheckPoint ============*/
+ if(!sparms->quell_newmail &&
+! new_mail(force, NM_TIMING(ch), NM_STATUS_MSG) >= 0){
+ update_scroll_titlebar(cur_top_line, 1);
+ if(ps_global->mangled_footer)
+ draw_keymenu(km, bitmap, ps_global->ttyo->screen_cols,
+--- 7988,7996 ----
+
+ /*============ Check for New Mail and CheckPoint ============*/
+ if(!sparms->quell_newmail &&
+! (nm = new_mail(force, NM_TIMING(ch), NM_STATUS_MSG)) >= 0){
+! skip = 0;
+! ps_global->force_check_now = nm > 0 ? 1 : 0;
+ update_scroll_titlebar(cur_top_line, 1);
+ if(ps_global->mangled_footer)
+ draw_keymenu(km, bitmap, ps_global->ttyo->screen_cols,
+***************
+*** 7405,7410 ****
+--- 7998,8015 ----
+
+ ps_global->mangled_footer = 0;
+ }
++ ps_global->in_pico = 0;
++
++ if (!skip)
++ new_mail_incfolder(ps_global, MC_IFAUTOCHECK);
++ skip = 0;
++ if (ps_global->refresh_list > 0){
++ ps_global->refresh_list = 0;
++ if (ps_global->in_fld_list){
++ cmd = MC_RESIZE;
++ goto end;
++ }
++ }
+
+ /*
+ * If an expunge of the current message happened during the
+***************
+*** 7539,7544 ****
+--- 8144,8150 ----
+ break;
+ }
+
++ ps_global->force_check_now = (((cmd == MC_NONE) || (cmd == MC_FORCECHECK)) ? 1 : 0);
+
+ /*============= Execute command =======================*/
+ switch(cmd){
+***************
+*** 8251,8256 ****
+--- 8857,8908 ----
+ print_to_printer(sparms);
+ break;
+
++ case MC_NEXTHREAD:
++ case MC_PRETHREAD:
++ if (THREADING()){
++ if (any_messages(ps_global->msgmap, NULL,
++ "to move to other thread"))
++ move_thread(ps_global, ps_global->mail_stream, ps_global->msgmap,
++ cmd == MC_NEXTHREAD ? 1 : -1);
++ done = 1;
++ }
++ else
++ q_status_message(SM_ORDER, 0, 1,
++ "Command available in threaded mode only");
++ break;
++
++ case MC_DELTHREAD:
++ if (THREADING()){
++ if (any_messages(ps_global->msgmap, NULL, "to delete"))
++ cmd_delete_thread(ps_global, ps_global->mail_stream, ps_global->msgmap);
++ done = 1;
++ }
++ else
++ q_status_message(SM_ORDER, 0, 1,
++ "Command available in threaded mode only");
++ break;
++
++ case MC_UNDTHREAD:
++ if (THREADING()){
++ if (any_messages(ps_global->msgmap, NULL, "to undelete"))
++ cmd_undelete_thread(ps_global, ps_global->mail_stream, ps_global->msgmap);
++ done = 1;
++ }
++ else
++ q_status_message(SM_ORDER, 0, 1,
++ "Command available in threaded mode only");
++ break;
++
++ case MC_SELTHREAD:
++ if (THREADING()){
++ if (any_messages(ps_global->msgmap, NULL, "to undelete"))
++ cmd_select_thread(ps_global, ps_global->mail_stream, ps_global->msgmap);
++ done = 1;
++ }
++ else
++ q_status_message(SM_ORDER, 0, 1,
++ "Command available in threaded mode only");
++ break;
+
+ /* ------- First handle on Line ------ */
+ case MC_GOTOBOL :
+***************
+*** 8283,8289 ****
+--- 8935,8957 ----
+
+ break;
+
++ /*------- Check incoming folders -------*/
++ case MC_FORCECHECK:
++ ps_global->force_check_now = 1;
++ if (new_mail_incfolder(ps_global,MC_FORCECHECK) &&
++ ps_global->refresh_list > 0){
++ ps_global->refresh_list = 0;
++ if (ps_global->in_fld_list){
++ cmd = MC_RESIZE;
++ goto end;
++ }
++ }
++ break;
+
++ case MC_TAB:
++ skip++;
++ /* do not check for new mail in inc fldrs and fall through */
++
+ /*------- Standard commands ------*/
+ default:
+ whereis_pos.row = 0;
+***************
+*** 8355,8360 ****
+--- 9023,9029 ----
+
+ } /* End of while() -- loop executing commands */
+
++ end:
+ ps_global->redrawer = NULL; /* next statement makes this invalid! */
+ zero_scroll_text(); /* very important to zero out on return!!! */
+ scroll_state(SS_FREE);
+***************
+*** 8463,8470 ****
+--- 9132,9141 ----
+ char prompt[MAX_SEARCH+50], nsearch_string[MAX_SEARCH+1];
+ HelpType help;
+ int rc, flags;
++ static char last_search_string[MAX_SEARCH+1] = { '\0' };
+ static char search_string[MAX_SEARCH+1] = { '\0' };
+ static ESCKEY_S word_search_key[] = { { 0, 0, "", "" },
++ {ctrl('N'), 9, "^N", "Ins Pat"},
+ {ctrl('Y'), 10, "^Y", "First Line"},
+ {ctrl('V'), 11, "^V", "Last Line"},
+ {-1, 0, NULL, NULL}
+***************
+*** 8486,8491 ****
+--- 9157,9165 ----
+ help = help == NO_HELP ? h_oe_searchview : NO_HELP;
+ continue;
+ }
++ else if(rc == 9)
++ insert_pattern_in_string(nsearch_string, last_search_string,
++ MAX_SEARCH);
+ else if(rc == 10){
+ strcpy(report, "Searched to First Line.");
+ return(-4);
+***************
+*** 8495,8501 ****
+ return(-5);
+ }
+
+! if(rc != 4)
+ break;
+ }
+
+--- 9169,9175 ----
+ return(-5);
+ }
+
+! if(rc != 4 && rc != 9)
+ break;
+ }
+
+***************
+*** 8507,8512 ****
+--- 9181,9189 ----
+ search_string[sizeof(search_string)-1] = '\0';
+ }
+
++ strncpy(last_search_string, nsearch_string, sizeof(last_search_string));
++ last_search_string[sizeof(last_search_string)-1] = '\0';
++
+ rc = search_scroll_text(start_line, start_col, search_string, cursor_pos,
+ offset_in_line);
+ return(rc);
+diff -rc pine4.63/pine/newmail.c pine4.63.I.USE/pine/newmail.c
+*** pine4.63/pine/newmail.c Thu Jan 13 16:44:30 2005
+--- pine4.63.I.USE/pine/newmail.c Thu May 19 19:57:28 2005
+***************
+*** 48,53 ****
+--- 48,55 ----
+
+ #include "headers.h"
+
++ static long incoming_folders_new_mail = 0L;
++
+
+ /*
+ * Internal prototypes
+***************
+*** 701,706 ****
+--- 703,709 ----
+ "subject:"
+ };
+
++ ps_global->refresh_list += 1; /* Force update in folder screen */
+ if(stream)
+ e = pine_mail_fetchstructure(stream, max_num, NULL);
+
+***************
+*** 1095,1100 ****
+--- 1098,1108 ----
+ if(m && sp_flagged(m, SP_LOCKED))
+ sp_set_mail_since_cmd(m, 0L);
+ }
++
++ if (incoming_folders_new_mail > 0L){
++ icon_text(NULL, IT_NEWMAIL);
++ incoming_folders_new_mail = 0L;
++ }
+ }
+
+
+***************
+*** 1299,1301 ****
+--- 1307,1545 ----
+ }
+ }
+ #endif
++
++ #define ADD_FLD_MSG(m, F, j) \
++ {\
++ strcat((m),"\"");\
++ strcat((m),FLDR_NAME((F)));\
++ strcat((m),"\"");\
++ (F)->notified = 1;\
++ if (j)\
++ strcat((m),", ");\
++ }
++ #define MSG(n) (((n) + 30 > SIZEOF_20KBUF) ? message : tmp_20k_buf)
++ #define CODE() ((command == MC_FORCECHECK) ? 1 : ((newflds > 0) ? -1 : 1))
++ #define NMVAR() ((command == MC_FORCECHECK) ? nflds : \
++ newflds > 0 ? newflds : nflds)
++
++ /* Check for new mail in incoming folders */
++ int
++ new_mail_incfolder(state,command)
++ struct pine *state;
++ int command;
++ {
++ char *message = NULL;
++ int index = 0, i, nflds = 0, tflds, tlflds = 0, newflds = 0, save_state;
++ static time_t now, old = 0;
++ static int check_started = 0;
++ int tcp_query_timeout = state->tcp_query_timeout;
++ int tcp_open_timeout = 30;
++ int offset = !F_OFF(F_ENABLE_FAST_RECENT, state);
++ FOLDER_S *f;
++
++ if (F_OFF(F_ENABLE_INCOMING,ps_global)
++ || F_OFF(F_ENABLE_INCOMING_CHECK,ps_global)
++ || (state->inc_check_rule == IC_MAN
++ && command != MC_FORCECHECK)
++ || (state->inc_check_rule == IC_MAN_AUTO
++ && check_started == 0 && command != MC_FORCECHECK))
++ return -1;
++
++ if ((!state->force_check_now) || (state->checking_incfld)){
++ state->force_check_now = 1; /* I'll be back, but wait a moment */
++ return -1;
++ }
++
++ now = time(0);
++ if ((old != 0) && (command != MC_FORCECHECK) &&
++ (state->refresh_list == 0) &&
++ (now - old < timeo*state->delay))
++ return -1;
++
++ state->checking_incfld = 1; /* point of no return */
++ check_started = 1; /* checks have already started */
++ ps_global->mm_log_error = 0; /* turn off display of errors */
++ ps_global->noshow_error = 1;
++
++ if(state->VAR_TCPOPENTIMEO)
++ (void)SVAR_TCP_OPEN(state, tcp_open_timeout, tmp_20k_buf);
++ mail_parameters(NULL, SET_OPENTIMEOUT, (void *)(long)state->incfld_timeout);
++
++ save_state = ps_global->in_init_seq;
++ state->in_init_seq = 0; /* force output of cue during check */
++ check_cue_display("+"); /* Show something to indicate delay */
++ MoveCursor(state->ttyo->screen_rows -FOOTER_ROWS(state),0);
++ fflush(stdout);
++ state->tcp_query_timeout = state->incfld_timeout;
++
++ if(state->context_current){
++ MAILSTREAM *nxtstrm = NULL;
++ long rec, tot, fslctd;
++ int opstrm, updated;
++ CONTEXT_S *ctxt = sp_context(sp_inbox_stream());
++
++ /* Look for the Incoming folder collections, Normally the incoming folders
++ * collection is the first collection, but just to be sure, we back up to
++ * the beginning and go forward from there to try to find it.
++ */
++
++ if (!ctxt){
++ ctxt = state->context_current;
++ while (1){
++ if (ctxt->prev)
++ ctxt = ctxt->prev;
++ else
++ break;
++ }
++ while (1){
++ if (ctxt->use & CNTXT_INCMNG)
++ break;
++ else
++ ctxt = ctxt->next;
++ }
++ }
++
++ tflds = folder_total(FOLDERS(ctxt));
++ for(index = folder_index(state->inbox_name, ctxt, FI_FOLDER) + offset;
++ index >= offset && index < tflds
++ && (f = folder_entry(index, FOLDERS(ctxt)))
++ && !f->isdir; index++){
++
++ rec = tot = fslctd = 0L;
++
++ fslctd = next_folder_check(&nxtstrm, ctxt, &rec, &tot, f, &opstrm);
++
++ if(fslctd && !strcmp(FLDR_NAME(f), state->cur_folder)
++ && !state->in_fld_list)
++ fslctd = 0L;
++
++ updated = (rec != f->recent || tot != f->messages);
++ if ((f->recent + f->messages == 0L && updated)
++ || (((!opstrm && updated) || (!f->notified && opstrm && updated))
++ && fslctd))
++ state->refresh_list++;
++
++ f->countrecent = rec > f->origrecent ? rec - f->origrecent : 0;
++ f->messages = tot;
++ f->recent = rec;
++
++ if (!offset && f->countrecent == 0L && fslctd)
++ fslctd = 0L;
++
++ if (fslctd){ /* this folder contains new mail */
++ state->refresh_list += f->selected ? 0 : 1;
++ f->selected = 1;
++ if (strcmp(FLDR_NAME(f), state->inbox_name)){
++ tlflds += strlen(FLDR_NAME(f)) + 4;
++ f->new_mail = 1;
++ if(!f->notified){
++ newflds++;
++ f->new_mail = (command == MC_FORCECHECK) ? 1 : -1;
++ }
++ nflds++;
++ }
++ }
++ else{
++ if (f->selected)
++ state->refresh_list += f->user_selected ? 0 : 1;
++ if (f->notified)
++ f->selected = f->user_selected ? 1 : 0;
++ f->notified = f->new_mail = 0; /* reset */
++ }
++ }
++
++ if(nxtstrm)
++ pine_mail_close(nxtstrm);
++
++ state->mm_log_error = 1; /* turn display of errors back on */
++ state->noshow_error = 0;
++
++ if(nflds == 0){
++ if (command == MC_FORCECHECK && state->VAR_INCOMING_FOLDERS_CHECK)
++ q_status_message(SM_ORDER, 0, 2,
++ "There are NO new messages in your Incoming Folders");
++ }
++ else{ /* nflds > 0 */
++ if (tlflds + 30 > SIZEOF_20KBUF)
++ message = (char *) fs_get((tlflds + 30)*sizeof(char));
++ if(newflds > 0)
++ state->refresh_list += 1;
++ strcpy(MSG(tlflds),"New message in folder");
++ strcat(MSG(tlflds),(NMVAR() > 1) ? "s " : " ");
++ for(i = 0, index = folder_index(state->inbox_name, ctxt, FI_FOLDER)
++ + offset;
++ index >= offset && index < tflds
++ && (f = folder_entry(index, FOLDERS(ctxt))); index++)
++ if(f->new_mail == CODE()){
++ if(NMVAR() > 1){
++ ADD_FLD_MSG(MSG(tlflds), f, (i < (NMVAR() - 2)) ? 1 : 0);
++ if(i == NMVAR() - 2)
++ strcat(MSG(tlflds)," and ");
++ }
++ else
++ ADD_FLD_MSG(MSG(tlflds), f, 0);
++ f->new_mail = 1;
++ if(++i == NMVAR())
++ break;
++ }
++ if (newflds > 0 || command == MC_FORCECHECK){
++ if(strlen(MSG(tlflds)) < state->ttyo->screen_cols - 2){
++ if (command != MC_FORCECHECK){
++ q_status_message(SM_ASYNC | SM_DING, 0, 60, MSG(tlflds));
++ icon_text(MSG(tlflds), IT_NEWMAIL);
++ }
++ else
++ q_status_message(SM_ORDER, 0, 2, MSG(tlflds));
++ }
++ else{
++ strcpy(tmp_20k_buf,
++ "You have NEW messages in your Incoming Folders");
++ if (command != MC_FORCECHECK){
++ q_status_message(SM_ASYNC | SM_DING, 0, 60, tmp_20k_buf);
++ icon_text(tmp_20k_buf, IT_NEWMAIL);
++ }
++ else
++ q_status_message(SM_ORDER, 0, 2, tmp_20k_buf);
++ }
++ }
++ if (message)
++ fs_give((void **)&message);
++ } /* end of nflds > 0 */
++ }
++ state->checking_incfld = 0;
++ check_cue_display(" "); /* Erase the "+" added before */
++ state->in_init_seq = save_state; /* restore original value */
++ MoveCursor(state->ttyo->screen_rows -FOOTER_ROWS(state),0);
++ incoming_folders_new_mail = nflds;
++
++ old = time(0);
++ state->delay = time(0) - now + 1;
++ state->tcp_query_timeout = tcp_query_timeout;
++ mail_parameters(NULL, SET_OPENTIMEOUT, (void *)(long)tcp_open_timeout);
++
++ return nflds;
++ }
++
++
++ char *
++ new_mail_in_open_stream(stream, rec, tot)
++ MAILSTREAM *stream;
++ long *rec;
++ long *tot;
++ {
++ long excluded;
++
++ if((excluded = any_lflagged(sp_msgmap(stream), MN_EXLD))){
++ *tot = stream->nmsgs - excluded;
++ if(tot)
++ *rec = count_flagged(stream, F_RECENT);
++ else
++ *rec = 0L;
++ }
++ else{
++ *tot = stream->nmsgs;
++ *rec = sp_recent_since_visited(stream);
++ }
++
++ return *rec ? STREAMNAME(stream) : NULL;
++ }
+diff -rc pine4.63/pine/osdep/termin.gen pine4.63.I.USE/pine/osdep/termin.gen
+*** pine4.63/pine/osdep/termin.gen Wed Dec 1 10:56:39 2004
+--- pine4.63.I.USE/pine/osdep/termin.gen Thu May 19 19:57:28 2005
+***************
+*** 6,11 ****
+--- 6,28 ----
+ int pcpine_oe_cursor PROTO((int, long));
+ #endif
+
++ void
++ fake_config_screen(tt)
++ struct ttyo **tt;
++ {
++ struct ttyo *ttyo;
++
++ ttyo = (struct ttyo *)fs_get(sizeof (struct ttyo));
++
++ ttyo->header_rows = 2;
++ ttyo->footer_rows = 3;
++ ttyo->screen_rows = 24;
++ ttyo->screen_cols = 80;
++
++ *tt = ttyo;
++
++ }
++
+
+ /*
+ * Generic tty input routines
+***************
+*** 227,233 ****
+ (escape_list && escape_list[0].ch != -1)
+ ? escape_list[0].label: ""));
+
+! if(!ps_global->ttyo)
+ return(pre_screen_config_opt_enter(string, field_len, prompt,
+ escape_list, help, flags));
+
+--- 244,250 ----
+ (escape_list && escape_list[0].ch != -1)
+ ? escape_list[0].label: ""));
+
+! if((!ps_global->ttyo) || (ps_global->send_immediately))
+ return(pre_screen_config_opt_enter(string, field_len, prompt,
+ escape_list, help, flags));
+
+***************
+*** 1030,1035 ****
+--- 1047,1053 ----
+ return(0);
+
+ *ch = *ps_global->initial_cmds++;
++ ps_global->initial_cmds_offset++;
+ if(!*ps_global->initial_cmds && ps_global->free_initial_cmds){
+ fs_give((void **)&(ps_global->free_initial_cmds));
+ ps_global->initial_cmds = 0;
+***************
+*** 1039,1045 ****
+ }
+
+ if(firsttime) {
+! firsttime = 0;
+ if(ps_global->in_init_seq) {
+ ps_global->in_init_seq = 0;
+ ps_global->save_in_init_seq = 0;
+--- 1057,1063 ----
+ }
+
+ if(firsttime) {
+! firsttime = ps_global->checking_incfld ? (char) 1 : 0;
+ if(ps_global->in_init_seq) {
+ ps_global->in_init_seq = 0;
+ ps_global->save_in_init_seq = 0;
+diff -rc pine4.63/pine/osdep/termin.unx pine4.63.I.USE/pine/osdep/termin.unx
+*** pine4.63/pine/osdep/termin.unx Tue Aug 3 14:46:44 2004
+--- pine4.63.I.USE/pine/osdep/termin.unx Thu May 19 19:57:27 2005
+***************
+*** 46,51 ****
+--- 46,53 ----
+ init_tty_driver(ps)
+ struct pine *ps;
+ {
++ if(ps->send_immediately)
++ return 0;
+ #ifdef MOUSE
+ if(F_ON(F_ENABLE_MOUSE, ps_global))
+ init_mouse();
+***************
+*** 573,578 ****
+--- 575,583 ----
+ init_keyboard(use_fkeys)
+ int use_fkeys;
+ {
++ if (ps_global->send_immediately)
++ return;
++
+ if(use_fkeys && (!strucmp(term_name,"vt102")
+ || !strucmp(term_name,"vt100")))
+ printf("\033\133\071\071\150");
+***************
+*** 591,596 ****
+--- 596,604 ----
+ end_keyboard(use_fkeys)
+ int use_fkeys;
+ {
++ if(ps_global->send_immediately)
++ return;
++
+ if(use_fkeys && (!strcmp(term_name, "vt102")
+ || !strcmp(term_name, "vt100"))){
+ printf("\033\133\071\071\154");
+diff -rc pine4.63/pine/osdep/termout.unx pine4.63.I.USE/pine/osdep/termout.unx
+*** pine4.63/pine/osdep/termout.unx Tue Nov 30 09:53:57 2004
+--- pine4.63.I.USE/pine/osdep/termout.unx Thu May 19 19:57:27 2005
+***************
+*** 160,165 ****
+--- 160,168 ----
+ void
+ init_screen()
+ {
++ if(ps_global->send_immediately)
++ return;
++
+ if(_termcap_init) /* init using termcap's rule */
+ tputs(_termcap_init, 1, outchar);
+
+***************
+*** 267,272 ****
+--- 270,278 ----
+ {
+ int footer_rows_was_one = 0;
+
++ if(ps_global->send_immediately)
++ return;
++
+ if(!panicking){
+
+ dprint(9, (debugfile, "end_screen called\n"));
+***************
+*** 321,327 ****
+ _line = 0; /* clear leaves us at top... */
+ _col = 0;
+
+! if(ps_global->in_init_seq)
+ return;
+
+ mark_status_unknown();
+--- 327,333 ----
+ _line = 0; /* clear leaves us at top... */
+ _col = 0;
+
+! if(ps_global->in_init_seq || ps_global->send_immediately)
+ return;
+
+ mark_status_unknown();
+diff -rc pine4.63/pine/other.c pine4.63.I.USE/pine/other.c
+*** pine4.63/pine/other.c Fri Apr 15 15:07:11 2005
+--- pine4.63.I.USE/pine/other.c Thu May 19 19:57:32 2005
+***************
+*** 362,369 ****
+ char *checkbox_pretty_value PROTO((struct pine *, CONF_S *));
+ char *color_pretty_value PROTO((struct pine *, CONF_S *));
+ char *radio_pretty_value PROTO((struct pine *, CONF_S *));
+! char *sort_pretty_value PROTO((struct pine *, CONF_S *));
+! char *generalized_sort_pretty_value PROTO((struct pine *, CONF_S *, int));
+ char *yesno_pretty_value PROTO((struct pine *, CONF_S *));
+ char *sigfile_pretty_value PROTO((struct pine *, CONF_S *));
+ void set_radio_pretty_vals PROTO((struct pine *, CONF_S **));
+--- 362,369 ----
+ char *checkbox_pretty_value PROTO((struct pine *, CONF_S *));
+ char *color_pretty_value PROTO((struct pine *, CONF_S *));
+ char *radio_pretty_value PROTO((struct pine *, CONF_S *));
+! char *sort_pretty_value PROTO((struct pine *, CONF_S *, int));
+! char *generalized_sort_pretty_value PROTO((struct pine *, CONF_S *, int, int));
+ char *yesno_pretty_value PROTO((struct pine *, CONF_S *));
+ char *sigfile_pretty_value PROTO((struct pine *, CONF_S *));
+ void set_radio_pretty_vals PROTO((struct pine *, CONF_S **));
+***************
+*** 1608,1614 ****
+ if(lv < (j = strlen(sort_name(ps->sort_types[i]))))
+ lv = j;
+
+! decode_sort(pval, &def_sort, &def_sort_rev);
+
+ for(j = 0; j < 2; j++){
+ for(i = 0; ps->sort_types[i] != EndofList; i++){
+--- 1608,1614 ----
+ if(lv < (j = strlen(sort_name(ps->sort_types[i]))))
+ lv = j;
+
+! decode_sort(pval, &def_sort, &def_sort_rev, 0);
+
+ for(j = 0; j < 2; j++){
+ for(i = 0; ps->sort_types[i] != EndofList; i++){
+***************
+*** 1623,1628 ****
+--- 1623,1678 ----
+ }
+ }
+ }
++ else if(vtmp == &ps->vars[V_THREAD_SORT_KEY]){ /* radio case */
++ SortOrder thread_def_sort;
++ int thread_def_sort_rev;
++
++ ctmpa->flags |= CF_NOSELECT;
++ ctmpa->keymenu = &config_radiobutton_keymenu;
++ ctmpa->tool = NULL;
++
++ /* put a nice delimiter before list */
++ new_confline(&ctmpa)->var = NULL;
++ ctmpa->varnamep = ctmpb;
++ ctmpa->keymenu = &config_radiobutton_keymenu;
++ ctmpa->help = NO_HELP;
++ ctmpa->tool = radiobutton_tool;
++ ctmpa->valoffset = 12;
++ ctmpa->flags |= CF_NOSELECT;
++ ctmpa->value = cpystr("Set Thread Sort Options");
++
++ new_confline(&ctmpa)->var = NULL;
++ ctmpa->varnamep = ctmpb;
++ ctmpa->keymenu = &config_radiobutton_keymenu;
++ ctmpa->help = NO_HELP;
++ ctmpa->tool = radiobutton_tool;
++ ctmpa->valoffset = 12;
++ ctmpa->flags |= CF_NOSELECT;
++ ctmpa->value = cpystr("--- ----------------------");
++
++ /* find longest value's name */
++ for(lv = 0, i = 0; ps->sort_types[i] != EndofList; i++)
++ if(lv < (j = strlen(sort_name(ps->sort_types[i]))))
++ lv = j;
++
++ decode_sort(pval, &thread_def_sort, &thread_def_sort_rev, 1);
++
++ for(j = 0; j < 2; j++){
++ for(i = 0; ps->sort_types[i] != EndofList; i++){
++ if (ps->sort_types[i] == SortArrival
++ || ps->sort_types[i] == SortThread){
++ new_confline(&ctmpa)->var = vtmp;
++ ctmpa->varnamep = ctmpb;
++ ctmpa->keymenu = &config_radiobutton_keymenu;
++ ctmpa->help = config_help(vtmp - ps->vars, 0);
++ ctmpa->tool = radiobutton_tool;
++ ctmpa->valoffset = 12;
++ ctmpa->varmem = i + (j * EndofList);
++ ctmpa->value = pretty_value(ps, ctmpa);
++ }
++ }
++ }
++ }
+ else if(vtmp == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){ /* yesno case */
+ ctmpa->keymenu = &config_yesno_keymenu;
+ ctmpa->tool = yesno_tool;
+***************
+*** 1674,1679 ****
+--- 1724,1730 ----
+ || vtmp == &ps->vars[V_TCPREADWARNTIMEO]
+ || vtmp == &ps->vars[V_TCPWRITEWARNTIMEO]
+ || vtmp == &ps->vars[V_TCPQUERYTIMEO]
++ || vtmp == &ps->vars[V_INCFLDTIMEO]
+ || vtmp == &ps->vars[V_RSHOPENTIMEO]
+ || vtmp == &ps->vars[V_SSHOPENTIMEO]
+ || vtmp == &ps->vars[V_USERINPUTTIMEO]
+***************
+*** 1779,1784 ****
+--- 1830,1844 ----
+ }
+ }
+
++ pval = PVAL(&ps->vars[V_THREAD_SORT_KEY], ew);
++ if(vsave[V_THREAD_SORT_KEY].saved_user_val.p && pval
++ && strcmp(vsave[V_THREAD_SORT_KEY].saved_user_val.p, pval)){
++ if(!mn_get_mansort(ps_global->msgmap)){
++ clear_index_cache();
++ reset_sort_order(SRT_VRB);
++ }
++ }
++
+ treat_color_vars_as_text = 0;
+ free_saved_config(ps, &vsave, expose_hidden_config);
+ #ifdef _WINDOWS
+***************
+*** 1799,1804 ****
+--- 1859,1865 ----
+ v == &ps->vars[V_FCC_RULE] ||
+ v == &ps->vars[V_GOTO_DEFAULT_RULE] ||
+ v == &ps->vars[V_INCOMING_STARTUP] ||
++ v == &ps->vars[V_INCOMING_RULE] ||
+ v == &ps->vars[V_PRUNING_RULE] ||
+ v == &ps->vars[V_REOPEN_RULE] ||
+ v == &ps->vars[V_THREAD_DISP_STYLE] ||
+***************
+*** 1828,1833 ****
+--- 1889,1896 ----
+ rulefunc = goto_rules;
+ else if(v == &ps->vars[V_INCOMING_STARTUP])
+ rulefunc = incoming_startup_rules;
++ else if(v == &ps->vars[V_INCOMING_RULE])
++ rulefunc = incoming_check_rules;
+ else if(v == startup_ptr)
+ rulefunc = startup_rules;
+ else if(v == &ps->vars[V_PRUNING_RULE])
+***************
+*** 1933,1939 ****
+ CONF_S *ctmp;
+
+ if(!(cl && *cl &&
+! ((*cl)->var == &ps->vars[V_SORT_KEY] ||
+ standard_radio_var(ps, (*cl)->var) ||
+ (*cl)->var == startup_ptr)))
+ return;
+--- 1996,2003 ----
+ CONF_S *ctmp;
+
+ if(!(cl && *cl &&
+! (((*cl)->var == &ps->vars[V_SORT_KEY]) ||
+! ((*cl)->var == &ps->vars[V_THREAD_SORT_KEY]) ||
+ standard_radio_var(ps, (*cl)->var) ||
+ (*cl)->var == startup_ptr)))
+ return;
+***************
+*** 1999,2004 ****
+--- 2063,2069 ----
+ case V_TCPREADWARNTIMEO :
+ case V_TCPWRITEWARNTIMEO :
+ case V_TCPQUERYTIMEO :
++ case V_INCFLDTIMEO :
+ case V_RSHCMD :
+ case V_RSHPATH :
+ case V_RSHOPENTIMEO :
+***************
+*** 6460,6466 ****
+ int multicol;
+ {
+ char tmp[MAXPATH+1];
+! int cmd, i, j, ch = 'x', done = 0, changes = 0;
+ int retval = 0;
+ int km_popped = 0, stay_in_col = 0;
+ struct key_menu *km = NULL;
+--- 6525,6531 ----
+ int multicol;
+ {
+ char tmp[MAXPATH+1];
+! int cmd, i, j, k = 1, ch = 'x', done = 0, changes = 0;
+ int retval = 0;
+ int km_popped = 0, stay_in_col = 0;
+ struct key_menu *km = NULL;
+***************
+*** 6507,6512 ****
+--- 6572,6578 ----
+ }
+
+ /*----------- Check for new mail -----------*/
++ if (!ps->send_immediately){
+ if(new_mail(0, NM_TIMING(ch), NM_STATUS_MSG | NM_DEFER_SORT) >= 0)
+ ps->mangled_header = 1;
+
+***************
+*** 6536,6541 ****
+--- 6602,6608 ----
+ mark_status_unknown();
+ }
+
++ } /* send_immediately */
+ if(ps->mangled_footer || km != screen->current->keymenu){
+ bitmap_t bitmap;
+
+***************
+*** 6607,6612 ****
+--- 6674,6680 ----
+ }
+ }
+
++ if(!ps_global->send_immediately){
+ MoveCursor(cursor_pos.row, cursor_pos.col);
+ #ifdef MOUSE
+ mouse_in_content(KEY_MOUSE, -1, -1, 0, 0); /* prime the handler */
+***************
+*** 6625,6630 ****
+--- 6693,6706 ----
+ #ifdef _WINDOWS
+ mswin_setscrollcallback(NULL);
+ #endif
++ } /* send_immediately */
++
++ if (ps->send_immediately){
++ ps_global->dont_use_init_cmds = 0;
++ process_config_input(&ch);
++ if (ch == '\030') /* ^X, bye */
++ goto end;
++ }
+
+ cmd = menu_command(ch, km);
+
+***************
+*** 7046,7055 ****
+--- 7122,7133 ----
+ #define FOUND_NOSELECT 0x08
+ #define FOUND_ABOVE 0x10
+ char *result = NULL, buf[64];
++ static char last_pat[64] = {'\0'};
+ static char last[64];
+ HelpType help;
+ static ESCKEY_S ekey[] = {
+ {0, 0, "", ""},
++ {ctrl('N'), 9, "^N", "Ins Pat"},
+ {ctrl('Y'), 10, "^Y", "Top"},
+ {ctrl('V'), 11, "^V", "Bottom"},
+ {-1, 0, NULL, NULL}};
+***************
+*** 7068,7080 ****
+ tmp,ekey,help,&flags);
+ if(rc == 3)
+ help = help == NO_HELP ? h_config_whereis : NO_HELP;
+! else if(rc == 0 || rc == 1 || rc == 10 || rc == 11 || !buf[0]){
+ if(rc == 0 && !buf[0] && last[0])
+ strncpy(buf, last, 64);
+
+! break;
+ }
+ }
+
+ screen->current->flags &= ~CF_VAR2;
+ if(rc == 0 && buf[0]){
+--- 7146,7167 ----
+ tmp,ekey,help,&flags);
+ if(rc == 3)
+ help = help == NO_HELP ? h_config_whereis : NO_HELP;
+! else if(rc == 0 || rc == 1 || rc == 9 || rc == 10
+! || rc == 11 || !buf[0]){
+ if(rc == 0 && !buf[0] && last[0])
+ strncpy(buf, last, 64);
+
+! if(rc == 9)
+! insert_pattern_in_string(buf, last_pat, 63);
+! else
+! break;
+ }
+ }
++
++ if (buf[0] != '\0'){
++ strncpy(last_pat, buf, sizeof(last_pat));
++ last_pat[sizeof(buf) - 1] = '\0';
++ }
+
+ screen->current->flags &= ~CF_VAR2;
+ if(rc == 0 && buf[0]){
+***************
+*** 7286,7292 ****
+ break;
+ }
+ }
+!
+ screen->current = first_confline(screen->current);
+ free_conflines(&screen->current);
+ return(retval);
+--- 7373,7379 ----
+ break;
+ }
+ }
+! end:
+ screen->current = first_confline(screen->current);
+ free_conflines(&screen->current);
+ return(retval);
+***************
+*** 7429,7434 ****
+--- 7516,7523 ----
+ return(h_config_nntp_server);
+ case V_INBOX_PATH :
+ return(h_config_inbox_path);
++ case V_INCOMING_FOLDERS_CHECK :
++ return(h_config_check_inc_fld);
+ case V_PRUNED_FOLDERS :
+ return(h_config_pruned_folders);
+ case V_DEFAULT_FCC :
+***************
+*** 7467,7476 ****
+--- 7556,7593 ----
+ return(h_config_fcc_rule);
+ case V_SORT_KEY :
+ return(h_config_sort_key);
++ case V_THREAD_SORT_KEY :
++ return(h_config_thread_sort_key);
+ case V_AB_SORT_RULE :
+ return(h_config_ab_sort_rule);
+ case V_FLD_SORT_RULE :
+ return(h_config_fld_sort_rule);
++ case V_THREAD_DISP_STYLE_RULES:
++ return(h_config_thread_display_style_rule);
++ case V_THREAD_INDEX_STYLE_RULES:
++ return(h_config_thread_index_style_rule);
++ case V_COMPOSE_RULES:
++ return(h_config_compose_rules);
++ case V_FORWARD_RULES:
++ return(h_config_forward_rules);
++ case V_INDEX_RULES:
++ return(h_config_index_rules);
++ case V_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_CHAR_SET :
+ return(h_config_char_set);
+ case V_EDITOR :
+***************
+*** 7503,7508 ****
+--- 7620,7627 ----
+ return(h_config_scroll_margin);
+ case V_DEADLETS :
+ return(h_config_deadlets);
++ case V_SPECIAL_TEXT :
++ return(h_config_special_text_to_color);
+ case V_FILLCOL :
+ return(h_config_composer_wrap_column);
+ case V_TCPOPENTIMEO :
+***************
+*** 7513,7518 ****
+--- 7632,7639 ----
+ return(h_config_tcp_writewarn_timeo);
+ case V_TCPQUERYTIMEO :
+ return(h_config_tcp_query_timeo);
++ case V_INCFLDTIMEO :
++ return(h_config_inc_fld_timeo);
+ case V_RSHOPENTIMEO :
+ return(h_config_rsh_open_timeo);
+ case V_SSHOPENTIMEO :
+***************
+*** 7595,7600 ****
+--- 7716,7723 ----
+ return(h_config_goto_default);
+ case V_INCOMING_STARTUP:
+ return(h_config_inc_startup);
++ case V_INCOMING_RULE:
++ return(h_config_inc_rule);
+ case V_PRUNING_RULE:
+ return(h_config_pruning_rule);
+ case V_REOPEN_RULE:
+***************
+*** 7621,7626 ****
+--- 7744,7751 ----
+ return(h_config_newmailwidth);
+ case V_NEWSRC_PATH :
+ return(h_config_newsrc_path);
++ case V_MAILDIR_LOCATION :
++ return(h_config_maildir_location);
+ case V_BROWSER :
+ return(h_config_browser);
+ #if defined(DOS) || defined(OS2)
+***************
+*** 7652,7657 ****
+--- 7777,7785 ----
+ case V_SIGNATURE_FORE_COLOR :
+ case V_SIGNATURE_BACK_COLOR :
+ return(h_config_signature_color);
++ case V_SPECIAL_TEXT_FORE_COLOR :
++ case V_SPECIAL_TEXT_BACK_COLOR :
++ return(h_config_special_text_color);
+ case V_PROMPT_FORE_COLOR :
+ case V_PROMPT_BACK_COLOR :
+ return(h_config_prompt_color);
+***************
+*** 8045,8050 ****
+--- 8173,8182 ----
+ lowrange = 5;
+ hirange = 1000;
+ }
++ else if((*cl)->var == &ps->vars[V_INCFLDTIMEO]){
++ lowrange = 2;
++ hirange = 60;
++ }
+ else if((*cl)->var == &ps->vars[V_TCPWRITEWARNTIMEO] ||
+ (*cl)->var == &ps->vars[V_RSHOPENTIMEO] ||
+ (*cl)->var == &ps->vars[V_SSHOPENTIMEO] ||
+***************
+*** 9371,9377 ****
+ }
+
+ set_current_val((*cl)->var, TRUE, TRUE);
+! if(decode_sort(ps->VAR_SORT_KEY, &def_sort, &def_sort_rev) != -1){
+ ps->def_sort = def_sort;
+ ps->def_sort_rev = def_sort_rev;
+ }
+--- 9503,9509 ----
+ }
+
+ set_current_val((*cl)->var, TRUE, TRUE);
+! if(decode_sort(ps->VAR_SORT_KEY, &def_sort, &def_sort_rev,0) != -1){
+ ps->def_sort = def_sort;
+ ps->def_sort_rev = def_sort_rev;
+ }
+***************
+*** 9380,9385 ****
+--- 9512,9548 ----
+ ps->mangled_body = 1; /* BUG: redraw it all for now? */
+ rv = 1;
+ }
++ else if((*cl)->var == &ps->vars[V_THREAD_SORT_KEY]){
++ SortOrder thread_def_sort;
++ int thread_def_sort_rev;
++
++ thread_def_sort_rev = (*cl)->varmem >= (short) EndofList;
++ thread_def_sort = (SortOrder) ((*cl)->varmem - (thread_def_sort_rev
++ * EndofList));
++ sprintf(tmp_20k_buf, "%s%s", sort_name(thread_def_sort),
++ (thread_def_sort_rev) ? "/Reverse" : "");
++
++ if((*cl)->var->cmdline_val.p)
++ fs_give((void **)&(*cl)->var->cmdline_val.p);
++
++ if(apval){
++ if(*apval)
++ fs_give((void **)apval);
++
++ *apval = cpystr(tmp_20k_buf);
++ }
++
++ set_current_val((*cl)->var, TRUE, TRUE);
++ if(decode_sort(ps->VAR_THREAD_SORT_KEY, &thread_def_sort,
++ &thread_def_sort_rev, 1) != -1){
++ ps->thread_def_sort = thread_def_sort;
++ ps->thread_def_sort_rev = thread_def_sort_rev;
++ }
++
++ set_radio_pretty_vals(ps, cl);
++ ps->mangled_body = 1; /* BUG: redraw it all for now? */
++ rv = 1;
++ }
+ else
+ q_status_message(SM_ORDER | SM_DING, 3, 6,
+ "Programmer botch! Unknown radiobutton type.");
+***************
+*** 10903,10909 ****
+ else if(standard_radio_var(ps, v) || v == startup_ptr)
+ return(radio_pretty_value(ps, cl));
+ else if(v == &ps->vars[V_SORT_KEY])
+! return(sort_pretty_value(ps, cl));
+ else if(v == &ps->vars[V_SIGNATURE_FILE])
+ return(sigfile_pretty_value(ps, cl));
+ else if(v == &ps->vars[V_USE_ONLY_DOMAIN_NAME])
+--- 11066,11074 ----
+ else if(standard_radio_var(ps, v) || v == startup_ptr)
+ return(radio_pretty_value(ps, cl));
+ else if(v == &ps->vars[V_SORT_KEY])
+! return(sort_pretty_value(ps, cl, 0));
+! else if(v == &ps->vars[V_THREAD_SORT_KEY])
+! return(sort_pretty_value(ps, cl, 1));
+ else if(v == &ps->vars[V_SIGNATURE_FILE])
+ return(sigfile_pretty_value(ps, cl));
+ else if(v == &ps->vars[V_USE_ONLY_DOMAIN_NAME])
+***************
+*** 11572,11590 ****
+
+
+ char *
+! sort_pretty_value(ps, cl)
+ struct pine *ps;
+ CONF_S *cl;
+ {
+! return(generalized_sort_pretty_value(ps, cl, 1));
+ }
+
+
+ char *
+! generalized_sort_pretty_value(ps, cl, default_ok)
+ struct pine *ps;
+ CONF_S *cl;
+ int default_ok;
+ {
+ char tmp[MAXPATH];
+ char *pvalnorm, *pvalexc, *pval;
+--- 11737,11757 ----
+
+
+ char *
+! sort_pretty_value(ps, cl, thread)
+ struct pine *ps;
+ CONF_S *cl;
++ int thread;
+ {
+! return(generalized_sort_pretty_value(ps, cl, 1, thread));
+ }
+
+
+ char *
+! generalized_sort_pretty_value(ps, cl, default_ok, thread)
+ struct pine *ps;
+ CONF_S *cl;
+ int default_ok;
++ int thread;
+ {
+ char tmp[MAXPATH];
+ char *pvalnorm, *pvalexc, *pval;
+***************
+*** 11634,11640 ****
+ }
+ else if(fixed){
+ pval = v->fixed_val.p;
+! decode_sort(pval, &var_sort, &var_sort_rev);
+ is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
+
+ sprintf(tmp, "(%c) %s%-*s%*s%s",
+--- 11801,11807 ----
+ }
+ else if(fixed){
+ pval = v->fixed_val.p;
+! decode_sort(pval, &var_sort, &var_sort_rev, thread);
+ is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
+
+ sprintf(tmp, "(%c) %s%-*s%*s%s",
+***************
+*** 11645,11653 ****
+ is_the_one ? " (value is fixed)" : "");
+ }
+ else if(is_set_for_this_level){
+! decode_sort(pval, &var_sort, &var_sort_rev);
+ is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
+! decode_sort(pvalexc, &exc_sort, &exc_sort_rev);
+ the_exc_one = (editing_normal_which_isnt_except && pvalexc &&
+ exc_sort_rev == line_sort_rev && exc_sort == line_sort);
+ sprintf(tmp, "(%c) %s%-*s%*s%s",
+--- 11812,11820 ----
+ is_the_one ? " (value is fixed)" : "");
+ }
+ else if(is_set_for_this_level){
+! decode_sort(pval, &var_sort, &var_sort_rev, thread);
+ is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
+! decode_sort(pvalexc, &exc_sort, &exc_sort_rev, thread);
+ the_exc_one = (editing_normal_which_isnt_except && pvalexc &&
+ exc_sort_rev == line_sort_rev && exc_sort == line_sort);
+ sprintf(tmp, "(%c) %s%-*s%*s%s",
+***************
+*** 11665,11671 ****
+ }
+ else{
+ if(pvalexc){
+! decode_sort(pvalexc, &exc_sort, &exc_sort_rev);
+ is_the_one = (exc_sort_rev == line_sort_rev &&
+ exc_sort == line_sort);
+ sprintf(tmp, "( ) %s%-*s%*s%s",
+--- 11832,11838 ----
+ }
+ else{
+ if(pvalexc){
+! decode_sort(pvalexc, &exc_sort, &exc_sort_rev, thread);
+ is_the_one = (exc_sort_rev == line_sort_rev &&
+ exc_sort == line_sort);
+ sprintf(tmp, "( ) %s%-*s%*s%s",
+***************
+*** 11676,11682 ****
+ }
+ else{
+ pval = v->current_val.p;
+! decode_sort(pval, &var_sort, &var_sort_rev);
+ is_the_one = ((pval || default_ok) &&
+ var_sort_rev == line_sort_rev &&
+ var_sort == line_sort);
+--- 11843,11849 ----
+ }
+ else{
+ pval = v->current_val.p;
+! decode_sort(pval, &var_sort, &var_sort_rev, thread);
+ is_the_one = ((pval || default_ok) &&
+ var_sort_rev == line_sort_rev &&
+ var_sort == line_sort);
+***************
+*** 11874,11879 ****
+--- 12041,12059 ----
+
+ cl->value = pretty_value(ps, cl);
+ }
++ if (f->id == F_ENHANCED_THREAD && ps->mail_stream
++ && SORT_IS_THREADED(ps->msgmap)){
++ refresh_sort(ps->mail_stream, ps->msgmap, SRT_NON);
++ if (COLL_THRDS()) /* sortring by thread destroys collapsed info */
++ kolapse_thread(ps, ps->mail_stream, ps->msgmap,'[', 0);
++ if(SEP_THRDINDX() && SORT_IS_THREADED(ps->msgmap)
++ && sp_viewing_a_thread(ps->mail_stream)){
++ unview_thread(ps, ps->mail_stream, ps->msgmap);
++ view_thread(ps, ps->mail_stream, ps->msgmap, 0);
++ ps_global->next_screen = SCREEN_FUN_NULL;
++ }
++ }
++
+
+ /*
+ * Handle any features that need special attention here...
+***************
+*** 11884,11889 ****
+--- 12064,12073 ----
+ mail_parameters(NULL,SET_FROMWIDGET,(void *)(F_ON(f->id ,ps) ? 1 : 0));
+ break;
+
++ case F_COURIER_FOLDER_LIST:
++ mail_parameters(NULL,SET_COURIERSTYLE,(void *)(F_ON(f->id ,ps)? 1 : 0));
++ break; /* COURIER == 1, CCLIENT == 0, see maildir.h */
++
+ case F_CMBND_ABOOK_DISP :
+ addrbook_reset();
+ break;
+***************
+*** 12683,12688 ****
+--- 12867,12893 ----
+ var == &ps->vars[V_ABOOK_FORMATS]){
+ addrbook_reset();
+ }
++ else if(var == &ps->vars[V_COMPOSE_RULES] ||
++ var == &ps->vars[V_FORWARD_RULES] ||
++ var == &ps->vars[V_INDEX_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();
++ if(var == &ps->vars[V_INDEX_RULES]){
++ reset_index_format();
++ clear_iindex_cache();
++ }
++ }
+ else if(var == &ps->vars[V_INDEX_FORMAT]){
+ reset_index_format();
+ clear_iindex_cache();
+***************
+*** 12849,12854 ****
+--- 13054,13065 ----
+ if(ps->VAR_TCPQUERYTIMEO && SVAR_TCP_QUERY(ps, val, tmp_20k_buf))
+ q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
+ }
++ else if(var == &ps->vars[V_INCFLDTIMEO]){
++ val = 5;
++ if(!revert)
++ if(ps->VAR_INCFLDTIMEO && SVAR_TCP_QUERY(ps, val, tmp_20k_buf))
++ q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
++ }
+ else if(var == &ps->vars[V_RSHOPENTIMEO]){
+ val = 15;
+ if(!revert)
+***************
+*** 12890,12895 ****
+--- 13101,13111 ----
+ fs_give((void **)&ps->vars[V_OPER_DIR].main_user_val.p);
+ }
+ }
++ else if(var == &ps->vars[V_INCOMING_FOLDERS_CHECK] &&
++ F_OFF(F_ENABLE_FAST_RECENT, ps)){
++ ps->force_check_now = 1;
++ new_mail_incfolder(ps, MC_FORCECHECK); /* yes, update it now */
++ }
+ else if(var == &ps->vars[V_MAILCHECK]){
+ timeo = 15;
+ if(SVAR_MAILCHK(ps, timeo, tmp_20k_buf)){
+***************
+*** 12955,12960 ****
+--- 13171,13180 ----
+ (void *)var->current_val.p);
+ }
+ #endif
++ else if(var == &ps->vars[V_MAILDIR_LOCATION]){
++ if(var->current_val.p && var->current_val.p[0])
++ maildir_parameters(SET_INBOXPATH, (void *)var->current_val.p);
++ }
+ else if(revert && standard_radio_var(ps, var)){
+
+ cur_rule_value(var, TRUE, FALSE);
+***************
+*** 13001,13009 ****
+ else if(revert && var == &ps->vars[V_SORT_KEY]){
+ int def_sort_rev;
+
+! decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev);
+ ps->def_sort_rev = def_sort_rev;
+ }
+ else if(var == &ps->vars[V_THREAD_MORE_CHAR] ||
+ var == &ps->vars[V_THREAD_EXP_CHAR] ||
+ var == &ps->vars[V_THREAD_LASTREPLY_CHAR]){
+--- 13221,13235 ----
+ else if(revert && var == &ps->vars[V_SORT_KEY]){
+ int def_sort_rev;
+
+! decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev, 0);
+ ps->def_sort_rev = def_sort_rev;
+ }
++ else if(revert && var == &ps->vars[V_THREAD_SORT_KEY]){
++ int thread_def_sort_rev;
++
++ decode_sort(VAR_THREAD_SORT_KEY, &ps->thread_def_sort, &thread_def_sort_rev, 1);
++ ps->thread_def_sort_rev = thread_def_sort_rev;
++ }
+ else if(var == &ps->vars[V_THREAD_MORE_CHAR] ||
+ var == &ps->vars[V_THREAD_EXP_CHAR] ||
+ var == &ps->vars[V_THREAD_LASTREPLY_CHAR]){
+***************
+*** 13760,13771 ****
+
+ if(!(nonempty_patterns(rflags, &pstate) &&
+ first_pattern(&pstate))){
+! q_status_message(SM_ORDER, 0, 3,
+ "No roles available. Use Setup/Rules to add roles.");
+ return(ret);
+ }
+
+-
+ if(alt_compose){
+ menu_init_binding(&role_select_km,
+ alt_compose == MC_FORWARD ? 'F' : alt_compose == MC_REPLY ? 'R' : 'C',
+--- 13986,14001 ----
+
+ if(!(nonempty_patterns(rflags, &pstate) &&
+ first_pattern(&pstate))){
+! if (!ps->send_immediately)
+! q_status_message(SM_ORDER, 0, 3,
+ "No roles available. Use Setup/Rules to add roles.");
++ else{
++ printf("No roles available. Use Setup/Rules to add roles.");
++ exit(-1);
++ }
+ return(ret);
+ }
+
+ if(alt_compose){
+ menu_init_binding(&role_select_km,
+ alt_compose == MC_FORWARD ? 'F' : alt_compose == MC_REPLY ? 'R' : 'C',
+***************
+*** 17979,17985 ****
+
+ pval = PVAL(&sort_act_var, ew);
+ if(pval)
+! decode_sort(pval, &def_sort, &def_sort_rev);
+
+ /* allow user to set their default sort order */
+ new_confline(&ctmp)->var = &sort_act_var;
+--- 18209,18215 ----
+
+ pval = PVAL(&sort_act_var, ew);
+ if(pval)
+! decode_sort(pval, &def_sort, &def_sort_rev, 0);
+
+ /* allow user to set their default sort order */
+ new_confline(&ctmp)->var = &sort_act_var;
+***************
+*** 17989,17995 ****
+ ctmp->tool = role_sort_tool;
+ ctmp->valoffset = 12;
+ ctmp->varmem = -1;
+! ctmp->value = generalized_sort_pretty_value(ps, ctmp, 0);
+
+ for(j = 0; j < 2; j++){
+ for(i = 0; ps->sort_types[i] != EndofList; i++){
+--- 18219,18225 ----
+ ctmp->tool = role_sort_tool;
+ ctmp->valoffset = 12;
+ ctmp->varmem = -1;
+! ctmp->value = generalized_sort_pretty_value(ps, ctmp, 0, 0);
+
+ for(j = 0; j < 2; j++){
+ for(i = 0; ps->sort_types[i] != EndofList; i++){
+***************
+*** 18001,18007 ****
+ ctmp->valoffset = 12;
+ ctmp->varmem = i + (j * EndofList);
+ ctmp->value = generalized_sort_pretty_value(ps, ctmp,
+! 0);
+ }
+ }
+
+--- 18231,18237 ----
+ ctmp->valoffset = 12;
+ ctmp->varmem = i + (j * EndofList);
+ ctmp->value = generalized_sort_pretty_value(ps, ctmp,
+! 0, 0);
+ }
+ }
+
+***************
+*** 18906,18912 ****
+ (*result)->patgrp->stat_boy = PAT_STAT_EITHER;
+
+ if(sort_act){
+! decode_sort(sort_act, &def_sort, &def_sort_rev);
+ (*result)->action->sort_is_set = 1;
+ (*result)->action->sortorder = def_sort;
+ (*result)->action->revsort = (def_sort_rev ? 1 : 0);
+--- 19136,19142 ----
+ (*result)->patgrp->stat_boy = PAT_STAT_EITHER;
+
+ if(sort_act){
+! decode_sort(sort_act, &def_sort, &def_sort_rev, 0);
+ (*result)->action->sort_is_set = 1;
+ (*result)->action->sortorder = def_sort;
+ (*result)->action->revsort = (def_sort_rev ? 1 : 0);
+***************
+*** 21330,21335 ****
+--- 21560,21570 ----
+ 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));
+
+***************
+*** 24130,24135 ****
+--- 24365,24371 ----
+ set_color_val(&vars[V_IND_UNS_FORE_COLOR], 0);
+ set_color_val(&vars[V_IND_ARR_FORE_COLOR], 0);
+ set_color_val(&vars[V_SIGNATURE_FORE_COLOR], 0);
++ set_color_val(&vars[V_SPECIAL_TEXT_FORE_COLOR], 0);
+
+ set_current_val(&ps->vars[V_VIEW_HDR_COLORS], TRUE, TRUE);
+ set_current_val(&ps->vars[V_KW_COLORS], TRUE, TRUE);
+***************
+*** 24680,24682 ****
+--- 24916,24920 ----
+ return(TRUE);
+ }
+ #endif /* _WINDOWS */
++
++ #include "rules.c"
+diff -rc pine4.63/pine/pine.c pine4.63.I.USE/pine/pine.c
+*** pine4.63/pine/pine.c Wed Apr 27 11:55:02 2005
+--- pine4.63.I.USE/pine/pine.c Thu May 19 19:57:34 2005
+***************
+*** 87,92 ****
+--- 87,93 ----
+ /*
+ * Internal prototypes
+ */
++ int sp_add_status PROTO((MAILSTREAM *));
+ int sp_add PROTO((MAILSTREAM *, int));
+ int sp_nusepool_notperm PROTO((void));
+ void sp_delete PROTO((MAILSTREAM *));
+***************
+*** 252,257 ****
+--- 253,259 ----
+ pine_state = (struct pine *)fs_get(sizeof (struct pine));
+ memset((void *)pine_state, 0, sizeof(struct pine));
+ ps_global = pine_state;
++ ps_global->thread_def_sort = SortDate;
+ ps_global->def_sort = SortArrival;
+ ps_global->sort_types[0] = SortSubject;
+ ps_global->sort_types[1] = SortArrival;
+***************
+*** 264,269 ****
+--- 266,273 ----
+ ps_global->sort_types[8] = SortScore;
+ ps_global->sort_types[9] = SortThread;
+ ps_global->sort_types[10] = EndofList;
++ ps_global->force_check_now = 1;
++ ps_global->delay = 1;
+ ps_global->atmts = (ATTACH_S *) fs_get(sizeof(ATTACH_S));
+ ps_global->atmts_allocated = 1;
+ ps_global->atmts->description = NULL;
+***************
+*** 342,348 ****
+ pine_args(pine_state, argc, argv, &args);
+
+ #ifndef _WINDOWS
+! if(!isatty(0)){
+ /*
+ * monkey with descriptors so our normal tty i/o routines don't
+ * choke...
+--- 346,352 ----
+ pine_args(pine_state, argc, argv, &args);
+
+ #ifndef _WINDOWS
+! if((!pine_state->send_immediately) && !isatty(0)){
+ /*
+ * monkey with descriptors so our normal tty i/o routines don't
+ * choke...
+***************
+*** 366,377 ****
+--- 370,384 ----
+ exit(-1);
+ }
+
++ mail_parameters(NULL, SET_QUOTA, (void *) pine_parse_quota);
++
+ /* set some default timeouts in case pinerc is remote */
+ mail_parameters(NULL, SET_OPENTIMEOUT, (void *)(long)30);
+ mail_parameters(NULL, SET_READTIMEOUT, (void *)(long)15);
+ mail_parameters(NULL, SET_TIMEOUT, (void *) pine_tcptimeout);
+ /* could be TO_BAIL_THRESHOLD, 15 seems more appropriate for now */
+ pine_state->tcp_query_timeout = 15;
++ pine_state->incfld_timeout = 5;
+
+ mail_parameters(NULL, SET_SENDCOMMAND, (void *) pine_imap_cmd_happened);
+ mail_parameters(NULL, SET_FREESTREAMSPAREP, (void *) sp_free_callback);
+***************
+*** 506,517 ****
+--- 513,532 ----
+ ps_global->s_pool.max_remstream));
+
+ init_vars(pine_state);
++ if (args.action == aaFolder && !args.data.folder &&
++ ps_global->send_immediately){
++ printf("No value for To: field specified\n");
++ exit(-1);
++ }
+
+ if(args.action == aaFolder){
+ pine_state->beginning_of_month = first_run_of_month();
+ pine_state->beginning_of_year = first_run_of_year();
+ }
+
++ mail_parameters(NULL,SET_COURIERSTYLE,
++ (void *)(F_ON(F_COURIER_FOLDER_LIST, ps_global) ? 1 : 0));
++
+ set_collation(F_OFF(F_DISABLE_SETLOCALE_COLLATE, ps_global),
+ F_ON(F_ENABLE_SETLOCALE_CTYPE, ps_global));
+
+***************
+*** 559,565 ****
+ rv = 0;
+ if(pine_state->VAR_TCPWRITEWARNTIMEO){
+ if(!SVAR_TCP_WRITEWARN(pine_state, rv, tmp_20k_buf))
+! if(rv == 0 || rv > 4) /* making sure */
+ mail_parameters(NULL, SET_WRITETIMEOUT, (void *)(long)rv);
+ }
+
+--- 574,580 ----
+ rv = 0;
+ if(pine_state->VAR_TCPWRITEWARNTIMEO){
+ if(!SVAR_TCP_WRITEWARN(pine_state, rv, tmp_20k_buf))
+! if(rv == 0 || rv > 4) /* making sure */
+ mail_parameters(NULL, SET_WRITETIMEOUT, (void *)(long)rv);
+ }
+
+***************
+*** 717,722 ****
+--- 732,738 ----
+
+
+ /*--- output side ---*/
++ if (!ps_global->send_immediately){
+ rv = config_screen(&(pine_state->ttyo));
+ #if !defined(DOS) && !defined(OS2) /* always succeeds under DOS! */
+ if(rv){
+***************
+*** 741,746 ****
+--- 757,765 ----
+ exit(-1);
+ }
+ #endif
++ }
++ else
++ fake_config_screen(&(pine_state->ttyo));
+
+ if(F_ON(F_BLANK_KEYMENU,ps_global))
+ FOOTER_ROWS(ps_global) = 1;
+***************
+*** 787,793 ****
+ goodnight_gracey(pine_state, exit_val);
+ }
+
+! if(args.action == aaFolder
+ && (pine_state->first_time_user || pine_state->show_new_version)){
+ pine_state->mangled_header = 1;
+ show_main_screen(pine_state, 0, FirstMenu, &main_keymenu, 0,
+--- 806,812 ----
+ goodnight_gracey(pine_state, exit_val);
+ }
+
+! if(!pine_state->send_immediately && args.action == aaFolder
+ && (pine_state->first_time_user || pine_state->show_new_version)){
+ pine_state->mangled_header = 1;
+ show_main_screen(pine_state, 0, FirstMenu, &main_keymenu, 0,
+***************
+*** 941,946 ****
+--- 960,971 ----
+ int len, good_addr = 1;
+ int exit_val = 0;
+ BUILDER_ARG fcc;
++ ACTION_S *role = NULL;
++
++ if (pine_state->in_init_seq && pine_state->send_immediately
++ && (char) *pine_state->initial_cmds++ == '#'
++ && ++pine_state->initial_cmds_offset)
++ role_select_screen(pine_state, &role, 1);
+
+ if(pine_state->in_init_seq){
+ pine_state->in_init_seq = pine_state->save_in_init_seq = 0;
+***************
+*** 976,982 ****
+ memset(&fcc, 0, sizeof(fcc));
+
+ if(good_addr){
+! compose_mail(addr, fcc.tptr, NULL,
+ args.data.mail.attachlist, stdin_getc);
+ }
+ else{
+--- 1001,1007 ----
+ memset(&fcc, 0, sizeof(fcc));
+
+ if(good_addr){
+! compose_mail(addr, fcc.tptr, role,
+ args.data.mail.attachlist, stdin_getc);
+ }
+ else{
+***************
+*** 1009,1014 ****
+--- 1034,1040 ----
+
+ pine_state->mail_stream = NULL;
+ pine_state->mangled_screen = 1;
++ pine_state->subject = NULL;
+
+ if(args.action == aaURL){
+ url_tool_t f;
+***************
+*** 1098,1103 ****
+--- 1124,1130 ----
+ "mail folder");
+ }
+
++ if (!pine_state->send_immediately)
+ fflush(stdout);
+
+ #if !defined(DOS) && !defined(OS2) && !defined(LEAVEOUTFIFO)
+***************
+*** 3164,3170 ****
+ {
+ int quit = 0;
+
+! dprint(1, (debugfile, "\n\n ---- QUIT SCREEN ----\n"));
+
+ if(F_ON(F_CHECK_MAIL_ONQUIT,ps_global)
+ && new_mail(1, VeryBadTime, NM_STATUS_MSG | NM_DEFER_SORT) > 0
+--- 3191,3198 ----
+ {
+ int quit = 0;
+
+! dprint(1, (debugfile, "\n\n ---- QUIT SCREEN ----\n"));
+! ps_global->in_pico = 1; /* we are leaving anyway */
+
+ if(F_ON(F_CHECK_MAIL_ONQUIT,ps_global)
+ && new_mail(1, VeryBadTime, NM_STATUS_MSG | NM_DEFER_SORT) > 0
+***************
+*** 3209,3214 ****
+--- 3237,3243 ----
+ extern KBESC_T *kbesc;
+
+ dprint(2, (debugfile, "goodnight_gracey:\n"));
++ sprintf(pine_state->cur_folder, pine_state->inbox_name);
+
+ /* We want to do this here before we close up the streams */
+ trim_remote_adrbks();
+***************
+*** 3311,3316 ****
+--- 3340,3346 ----
+ dprint(7, (debugfile, "goodnight_gracey: sp_end\n"));
+ ps_global->noshow_error = 1;
+ sp_end();
++ sp_status_end();
+
+ /* after sp_end, which might call a filter */
+ completely_done_with_adrbks();
+***************
+*** 3348,3353 ****
+--- 3378,3385 ----
+ free_saved_query_parameters();
+ #endif
+
++ if(pine_state->subject != NULL)
++ fs_give((void **)&pine_state->subject);
+ if(pine_state->hostname != NULL)
+ fs_give((void **)&pine_state->hostname);
+ if(pine_state->localdomain != NULL)
+***************
+*** 3409,3414 ****
+--- 3441,3449 ----
+
+ fs_give((void **)&ps_global->atmts);
+ }
++
++ if(ps_global->rule_list)
++ free_parsed_rule_list(&ps_global->rule_list);
+
+ dprint(7, (debugfile, "goodnight_gracey: free_vars\n"));
+ free_vars(pine_state);
+***************
+*** 3956,3969 ****
+
+ was_invisible = (mc->spare || mc->spare4) ? 1 : 0;
+
+ if(chk_thrd_cnt = ((msgs->visible_threads >= 0L)
+ && THRD_INDX_ENABLED() && (f & MN_HIDE) && (mc->spare != v))){
+- thrd = fetch_thread(stream, rawno);
+ if(thrd && thrd->top){
+! if(thrd->top == thrd->rawno)
+ topthrd = thrd;
+ else
+! topthrd = fetch_thread(stream, thrd->top);
+ }
+
+ if(topthrd){
+--- 3991,4005 ----
+
+ was_invisible = (mc->spare || mc->spare4) ? 1 : 0;
+
++ thrd = fetch_thread(stream, rawno);
++
+ if(chk_thrd_cnt = ((msgs->visible_threads >= 0L)
+ && THRD_INDX_ENABLED() && (f & MN_HIDE) && (mc->spare != v))){
+ if(thrd && thrd->top){
+! if(top_thread(stream,thrd->top) == thrd->rawno)
+ topthrd = thrd;
+ else
+! topthrd = fetch_thread(stream, top_thread(stream,thrd->top));
+ }
+
+ if(topthrd){
+***************
+*** 6320,6325 ****
+--- 6356,6446 ----
+ return(NULL);
+ }
+
++ MAILSTREAM *
++ sp_stream_status_get(mailbox)
++ char *mailbox;
++ {
++ int i;
++ MAILSTREAM *m = NULL;
++
++ for(i = 0; i < ps_global->s_pool_status.nstream; i++){
++ m = ps_global->s_pool_status.streams[i];
++ if(m && same_stream(mailbox, m) && pine_mail_ping(m))
++ return m;
++ }
++ return NULL;
++ }
++
++ void
++ sp_status_end()
++ {
++ int i;
++ MAILSTREAM *m;
++
++ for(i = 0; i < ps_global->s_pool_status.nstream; i++){
++ m = ps_global->s_pool_status.streams[i];
++ if(m)
++ pine_mail_actually_close(m);
++ }
++
++ if(ps_global->s_pool_status.streams)
++ fs_give((void **) &ps_global->s_pool_status.streams);
++
++ ps_global->s_pool_status.nstream = 0;
++ }
++
++ int
++ sp_add_status(stream)
++ MAILSTREAM *stream;
++ {
++ int i, slot = -1;
++ MAILSTREAM *m;
++
++ if(!stream)
++ return -1;
++
++ for(i = 0; i < ps_global->s_pool_status.nstream; i++){
++ m = ps_global->s_pool_status.streams[i];
++ if(m == stream){
++ slot = i;
++ return 0;
++ }
++ }
++
++ for(i = 0; i < ps_global->s_pool_status.nstream; i++){
++ m = ps_global->s_pool_status.streams[i];
++ if(!m){
++ slot = i;
++ break;
++ }
++ }
++
++ if(slot < 0){
++ slot = ps_global->s_pool_status.nstream++;
++ if(ps_global->s_pool_status.streams){
++ fs_resize((void **) &ps_global->s_pool_status.streams,
++ ps_global->s_pool_status.nstream *
++ sizeof(*ps_global->s_pool_status.streams));
++ ps_global->s_pool_status.streams[slot] = NULL;
++ }
++ else{
++ ps_global->s_pool_status.streams =
++ (MAILSTREAM **) fs_get(ps_global->s_pool_status.nstream *
++ sizeof(*ps_global->s_pool_status.streams));
++ memset(ps_global->s_pool_status.streams, 0,
++ ps_global->s_pool_status.nstream *
++ sizeof(*ps_global->s_pool_status.streams));
++ }
++ }
++
++ if(slot >= 0 && slot < ps_global->s_pool_status.nstream){
++ ps_global->s_pool_status.streams[slot] = stream;
++ return 0;
++ }
++ else
++ return -1;
++ }
++
+
+ void
+ sp_end()
+diff -rc pine4.63/pine/pine.h pine4.63.I.USE/pine/pine.h
+*** pine4.63/pine/pine.h Fri Apr 15 15:07:15 2005
+--- pine4.63.I.USE/pine/pine.h Thu May 19 19:57:34 2005
+***************
+*** 231,236 ****
+--- 231,239 ----
+ #ifndef DF_INCOMING_STARTUP
+ #define DF_INCOMING_STARTUP "first-unseen"
+ #endif
++ #ifndef DF_INCOMING_RULE
++ #define DF_INCOMING_RULE "automatic"
++ #endif
+ #ifndef DF_PRUNING_RULE
+ #define DF_PRUNING_RULE "ask-ask"
+ #endif
+***************
+*** 622,627 ****
+--- 625,631 ----
+ , V_SMTP_SERVER
+ , V_NNTP_SERVER
+ , V_INBOX_PATH
++ , V_INCOMING_FOLDERS_CHECK
+ , V_ARCHIVED_FOLDERS
+ , V_PRUNED_FOLDERS
+ , V_DEFAULT_FCC
+***************
+*** 642,651 ****
+--- 646,657 ----
+ , V_SAVED_MSG_NAME_RULE
+ , V_FCC_RULE
+ , V_SORT_KEY
++ , V_THREAD_SORT_KEY
+ , V_AB_SORT_RULE
+ , V_FLD_SORT_RULE
+ , V_GOTO_DEFAULT_RULE
+ , V_INCOMING_STARTUP
++ , V_INCOMING_RULE
+ , V_PRUNING_RULE
+ , V_REOPEN_RULE
+ , V_THREAD_DISP_STYLE
+***************
+*** 653,662 ****
+--- 659,682 ----
+ , 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_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
+ , V_CHAR_SET
+ , V_EDITOR
+ , V_SPELLER
+ , V_FILLCOL
++ , V_SPECIAL_TEXT
+ , V_REPLY_STRING
+ , V_REPLY_INTRO
+ , V_QUOTE_REPLACE_STRING
+***************
+*** 689,694 ****
+--- 709,715 ----
+ , V_NEWSRC_PATH
+ , V_NEWS_ACTIVE_PATH
+ , V_NEWS_SPOOL_DIR
++ , V_MAILDIR_LOCATION
+ , V_UPLOAD_CMD
+ , V_UPLOAD_CMD_PREFIX
+ , V_DOWNLOAD_CMD
+***************
+*** 726,731 ****
+--- 747,753 ----
+ , V_TCPREADWARNTIMEO
+ , V_TCPWRITEWARNTIMEO
+ , V_TCPQUERYTIMEO
++ , V_INCFLDTIMEO
+ , V_RSHCMD
+ , V_RSHPATH
+ , V_RSHOPENTIMEO
+***************
+*** 787,792 ****
+--- 809,816 ----
+ , V_QUOTE3_BACK_COLOR
+ , V_SIGNATURE_FORE_COLOR
+ , V_SIGNATURE_BACK_COLOR
++ , V_SPECIAL_TEXT_FORE_COLOR
++ , V_SPECIAL_TEXT_BACK_COLOR
+ , V_PROMPT_FORE_COLOR
+ , V_PROMPT_BACK_COLOR
+ , V_IND_PLUS_FORE_COLOR
+***************
+*** 843,848 ****
+--- 867,874 ----
+ #define VAR_INBOX_PATH vars[V_INBOX_PATH].current_val.p
+ #define GLO_INBOX_PATH vars[V_INBOX_PATH].global_val.p
+ #define VAR_INCOMING_FOLDERS vars[V_INCOMING_FOLDERS].current_val.l
++ #define VAR_INCOMING_FOLDERS_CHECK vars[V_INCOMING_FOLDERS_CHECK].current_val.p
++ #define GLO_INCOMING_FOLDERS_CHECK vars[V_INCOMING_FOLDERS_CHECK].global_val.p
+ #define VAR_FOLDER_SPEC vars[V_FOLDER_SPEC].current_val.l
+ #define GLO_FOLDER_SPEC vars[V_FOLDER_SPEC].global_val.l
+ #define VAR_NEWS_SPEC vars[V_NEWS_SPEC].current_val.l
+***************
+*** 897,912 ****
+--- 923,980 ----
+ #define VAR_SORT_KEY vars[V_SORT_KEY].current_val.p
+ #define GLO_SORT_KEY vars[V_SORT_KEY].global_val.p
+ #define COM_SORT_KEY vars[V_SORT_KEY].cmdline_val.p
++ #define VAR_THREAD_SORT_KEY vars[V_THREAD_SORT_KEY].current_val.p
++ #define GLO_THREAD_SORT_KEY vars[V_THREAD_SORT_KEY].global_val.p
++ #define COM_THREAD_SORT_KEY vars[V_THREAD_SORT_KEY].cmdline_val.p
+ #define VAR_AB_SORT_RULE vars[V_AB_SORT_RULE].current_val.p
+ #define GLO_AB_SORT_RULE vars[V_AB_SORT_RULE].global_val.p
+ #define VAR_FLD_SORT_RULE vars[V_FLD_SORT_RULE].current_val.p
+ #define GLO_FLD_SORT_RULE vars[V_FLD_SORT_RULE].global_val.p
++ #define VAR_COMPOSE_RULES vars[V_COMPOSE_RULES].current_val.l
++ #define GLO_COMPOSE_RULES vars[V_COMPOSE_RULES].global_val.l
++ #define USR_COMPOSE_RULES vars[V_COMPOSE_RULES].user_val.l
++ #define VAR_FORWARD_RULES vars[V_FORWARD_RULES].current_val.l
++ #define GLO_FORWARD_RULES vars[V_FORWARD_RULES].global_val.l
++ #define USR_FORWARD_RULES vars[V_FORWARD_RULES].user_val.l
++ #define VAR_INDEX_RULES vars[V_INDEX_RULES].current_val.l
++ #define GLO_INDEX_RULES vars[V_INDEX_RULES].global_val.l
++ #define USR_INDEX_RULES vars[V_INDEX_RULES].user_val.l
++ #define VAR_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
+ #define VAR_CHAR_SET vars[V_CHAR_SET].current_val.p
+ #define GLO_CHAR_SET vars[V_CHAR_SET].global_val.p
+ #define VAR_EDITOR vars[V_EDITOR].current_val.l
+ #define GLO_EDITOR vars[V_EDITOR].global_val.l
+ #define VAR_SPELLER vars[V_SPELLER].current_val.p
+ #define GLO_SPELLER vars[V_SPELLER].global_val.p
++ #define VAR_SPECIAL_TEXT vars[V_SPECIAL_TEXT].current_val.l
++ #define GLO_SPECIAL_TEXT vars[V_SPECIAL_TEXT].global_val.l
+ #define VAR_FILLCOL vars[V_FILLCOL].current_val.p
+ #define GLO_FILLCOL vars[V_FILLCOL].global_val.p
+ #define VAR_DEADLETS vars[V_DEADLETS].current_val.p
+***************
+*** 991,996 ****
+--- 1059,1066 ----
+ #define GLO_NEWS_ACTIVE_PATH vars[V_NEWS_ACTIVE_PATH].global_val.p
+ #define VAR_NEWS_SPOOL_DIR vars[V_NEWS_SPOOL_DIR].current_val.p
+ #define GLO_NEWS_SPOOL_DIR vars[V_NEWS_SPOOL_DIR].global_val.p
++ #define VAR_MAILDIR_LOCATION vars[V_MAILDIR_LOCATION].current_val.p
++ #define GLO_MAILDIR_LOCATION vars[V_MAILDIR_LOCATION].global_val.p
+ #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
+***************
+*** 1035,1040 ****
+--- 1105,1111 ----
+ #define VAR_TCPREADWARNTIMEO vars[V_TCPREADWARNTIMEO].current_val.p
+ #define VAR_TCPWRITEWARNTIMEO vars[V_TCPWRITEWARNTIMEO].current_val.p
+ #define VAR_TCPQUERYTIMEO vars[V_TCPQUERYTIMEO].current_val.p
++ #define VAR_INCFLDTIMEO vars[V_INCFLDTIMEO].current_val.p
+ #define VAR_RSHOPENTIMEO vars[V_RSHOPENTIMEO].current_val.p
+ #define VAR_RSHPATH vars[V_RSHPATH].current_val.p
+ #define VAR_RSHCMD vars[V_RSHCMD].current_val.p
+***************
+*** 1045,1050 ****
+--- 1116,1123 ----
+ #define VAR_BROWSER vars[V_BROWSER].current_val.l
+ #define VAR_INCOMING_STARTUP vars[V_INCOMING_STARTUP].current_val.p
+ #define GLO_INCOMING_STARTUP vars[V_INCOMING_STARTUP].global_val.p
++ #define VAR_INCOMING_RULE vars[V_INCOMING_RULE].current_val.p
++ #define GLO_INCOMING_RULE vars[V_INCOMING_RULE].global_val.p
+ #define VAR_PRUNING_RULE vars[V_PRUNING_RULE].current_val.p
+ #define GLO_PRUNING_RULE vars[V_PRUNING_RULE].global_val.p
+ #define VAR_REOPEN_RULE vars[V_REOPEN_RULE].current_val.p
+***************
+*** 1122,1127 ****
+--- 1195,1202 ----
+ #define VAR_QUOTE3_BACK_COLOR vars[V_QUOTE3_BACK_COLOR].current_val.p
+ #define VAR_SIGNATURE_FORE_COLOR vars[V_SIGNATURE_FORE_COLOR].current_val.p
+ #define VAR_SIGNATURE_BACK_COLOR vars[V_SIGNATURE_BACK_COLOR].current_val.p
++ #define VAR_SPECIAL_TEXT_FORE_COLOR vars[V_SPECIAL_TEXT_FORE_COLOR].current_val.p
++ #define VAR_SPECIAL_TEXT_BACK_COLOR vars[V_SPECIAL_TEXT_BACK_COLOR].current_val.p
+ #define VAR_PROMPT_FORE_COLOR vars[V_PROMPT_FORE_COLOR].current_val.p
+ #define VAR_PROMPT_BACK_COLOR vars[V_PROMPT_BACK_COLOR].current_val.p
+ #define VAR_VIEW_HDR_COLORS vars[V_VIEW_HDR_COLORS].current_val.l
+***************
+*** 1151,1156 ****
+--- 1226,1232 ----
+ 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,
+***************
+*** 1168,1173 ****
+--- 1244,1250 ----
+ F_SHOW_DELAY_CUE,
+ F_CANCEL_CONFIRM,
+ F_AUTO_OPEN_NEXT_UNREAD,
++ F_AUTO_CIRCULAR_TAB,
+ F_SELECTED_SHOWN_BOLD,
+ F_QUOTE_ALL_FROMS,
+ F_AUTO_INCLUDE_IN_REPLY,
+***************
+*** 1184,1189 ****
+--- 1261,1268 ----
+ F_DISABLE_PIPES_IN_TEMPLATES,
+ F_ATTACHMENTS_IN_REPLY,
+ F_ENABLE_INCOMING,
++ F_ENABLE_INCOMING_CHECK,
++ F_ENABLE_INCOMING_RECHECK,
+ F_NO_NEWS_VALIDATION,
+ F_QUELL_EXTRA_POST_PROMPT,
+ F_DISABLE_TAKE_LASTFIRST,
+***************
+*** 1206,1215 ****
+--- 1285,1296 ----
+ F_PASS_C1_CONTROL_CHARS,
+ F_SINGLE_FOLDER_LIST,
+ F_VERTICAL_FOLDER_LIST,
++ F_COURIER_FOLDER_LIST,
+ F_TAB_CHK_RECENT,
+ F_AUTO_REPLY_TO,
+ F_VERBOSE_POST,
+ F_FCC_ON_BOUNCE,
++ F_USE_DOMAIN_NAME,
+ F_SEND_WO_CONFIRM,
+ F_USE_SENDER_NOT_X,
+ F_BLANK_KEYMENU,
+***************
+*** 1314,1323 ****
+--- 1395,1406 ----
+ F_MAILDROPS_PRESERVE_STATE,
+ F_EXPOSE_HIDDEN_CONFIG,
+ F_ALT_COMPOSE_MENU,
++ F_ALT_REPLY_MENU,
+ F_ALT_ROLE_MENU,
+ F_ALWAYS_SPELL_CHECK,
+ F_QUELL_TIMEZONE,
+ F_COLOR_LINE_IMPORTANT,
++ F_ENHANCED_THREAD,
+ F_SLASH_COLL_ENTIRE,
+ F_ENABLE_FULL_HDR_AND_TEXT,
+ F_QUELL_FULL_HDR_RESET,
+***************
+*** 1547,1552 ****
+--- 1630,1642 ----
+ #define IS_NOTSET 7 /* for reset version */
+
+ /*
++ * Incoming check rules
++ */
++ #define IC_AUTO 0
++ #define IC_MAN_AUTO 1
++ #define IC_MAN 2
++
++ /*
+ * Pruning rules. If these grow, widen pruning_rule.
+ */
+ #define PRUNE_ASK_AND_ASK 0
+***************
+*** 1830,1835 ****
+--- 1920,1929 ----
+ #define SVAR_TCP_QUERY(ps, n, e) strtoval((ps)->VAR_TCPQUERYTIMEO, \
+ &(n), 5, 30000, 0, (e), \
+ "Tcp-Query-Timeout")
++ #define SVAR_INCFLDQUERY(ps, n, e) strtoval((ps)->VAR_INCFLDTIMEO, \
++ &(n), 2, 60, 0, (e), \
++ "Inc-fld-timeout")
++
+ #define SVAR_RSH_OPEN(ps, n, e) strtoval((ps)->VAR_RSHOPENTIMEO, \
+ &(n), 5, 30000, 0, (e), \
+ "Rsh-Open-Timeout")
+***************
+*** 1930,1936 ****
+ SortSubject2, SortScore, SortThread, EndofList} SortOrder;
+
+ #define refresh_sort(S,M,F) sort_folder((S), (M), mn_get_sort(M), \
+! mn_get_revsort(M), (F))
+
+ /*
+ * The two structs below hold all knowledge regarding
+--- 2024,2030 ----
+ SortSubject2, SortScore, SortThread, EndofList} SortOrder;
+
+ #define refresh_sort(S,M,F) sort_folder((S), (M), mn_get_sort(M), \
+! mn_get_revsort(M), (F), 1)
+
+ /*
+ * The two structs below hold all knowledge regarding
+***************
+*** 1974,1986 ****
+ typedef struct pine_thrd {
+ unsigned long rawno; /* raw msgno of this message */
+ unsigned long thrdno; /* thread number */
+- unsigned long flags;
+ unsigned long next; /* msgno of first reply to us */
+ unsigned long branch; /* like THREADNODE branch, next replier */
+ unsigned long parent; /* message that this is a reply to */
+ unsigned long nextthd; /* next thread, only tops have this */
+ unsigned long prevthd; /* previous thread, only tops have this */
+ unsigned long top; /* top of this thread */
+ unsigned long head; /* head of the whole thread list */
+ } PINETHRD_S;
+
+--- 2068,2080 ----
+ typedef struct pine_thrd {
+ unsigned long rawno; /* raw msgno of this message */
+ unsigned long thrdno; /* thread number */
+ unsigned long next; /* msgno of first reply to us */
+ unsigned long branch; /* like THREADNODE branch, next replier */
+ unsigned long parent; /* message that this is a reply to */
+ unsigned long nextthd; /* next thread, only tops have this */
+ unsigned long prevthd; /* previous thread, only tops have this */
+ unsigned long top; /* top of this thread */
++ unsigned long toploose; /* top of this thread, if is loose */
+ unsigned long head; /* head of the whole thread list */
+ } PINETHRD_S;
+
+***************
+*** 2571,2580 ****
+--- 2665,2681 ----
+ unsigned hasnochildren:1; /* known not to have children */
+ unsigned scanned:1; /* scanned by c-client */
+ unsigned selected:1; /* selected by user */
++ unsigned user_selected:1; /* selected by user (not Pine)*/
+ unsigned subscribed:1; /* selected by user */
+ unsigned long varhash; /* hash of var for incoming */
+ unsigned long uidvalidity; /* only for #move folder */
+ unsigned long uidnext; /* only for #move folder */
++ int notified; /* notified the change? */
++ int new_mail; /* folder has new mail */
++ long origrecent; /* # recent messages in stream*/
++ long countrecent; /* # recent messages displayed*/
++ long recent; /* # recent messages adjusted */
++ long messages; /* # messages */
+ char *nickname; /* folder's short name */
+ char name[1]; /* folder's name */
+ } FOLDER_S;
+***************
+*** 2600,2611 ****
+ iLstYear, iLstYear2Digit,
+ iMessNo, iAtt, iMsgID, iSubject,
+ iSubjKey, iSubjKeyInit, iKey, iKeyInit,
+! iSize, iSizeComma, iSizeNarrow, iDescripSize,
+ iNewsAndTo, iToAndNews, iNewsAndRecips, iRecipsAndNews,
+ iFromTo, iFromToNotNews, iFrom, iTo, iSender, iCc, iNews, iRecips,
+ iCurNews, iArrow,
+ iMailbox, iAddress, iInit, iCursorPos,
+ iDay2Digit, iMon2Digit, iYear2Digit,
+ iSTime, iKSize,
+ iRoleNick,
+ iScore, iDayOfWeekAbb, iDayOfWeek,
+--- 2701,2715 ----
+ iLstYear, iLstYear2Digit,
+ iMessNo, iAtt, iMsgID, iSubject,
+ iSubjKey, iSubjKeyInit, iKey, iKeyInit,
+! iSize, iSizeComma, iSizeNarrow, iDescripSize, iSizeThread,
+ iNewsAndTo, iToAndNews, iNewsAndRecips, iRecipsAndNews,
+ iFromTo, iFromToNotNews, iFrom, iTo, iSender, iCc, iNews, iRecips,
+ iCurNews, iArrow,
+ iMailbox, iAddress, iInit, iCursorPos,
+ iDay2Digit, iMon2Digit, iYear2Digit,
++ iFolder, iFlag, iCollection, iRole,
++ iNick, iAddressTo, iAddressCc, iAddressRecip, iBcc, iLcc,
++ iFfrom, iFadd,
+ iSTime, iKSize,
+ iRoleNick,
+ iScore, iDayOfWeekAbb, iDayOfWeek,
+***************
+*** 2622,2634 ****
+ } INDEX_PARSE_T;
+
+ /* 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 DEFAULT_REPLY_INTRO "default"
+
+--- 2726,2749 ----
+ } INDEX_PARSE_T;
+
+ /* 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 FOR_SAVE 0x00040 /* for rules */
+! #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 DEFAULT_REPLY_INTRO "default"
+
+***************
+*** 2992,3002 ****
+ #define MC_NOT 799
+ #define MC_COLLAPSE 800
+ #define MC_CHK_RECENT 801
+!
+
+ /*
+ * Some standard Key/Command Bindings
+ */
+ #define NULL_MENU {NULL, NULL, {MC_NONE}, KS_NONE}
+ #define HELP_MENU {"?", "Help", \
+ {MC_HELP, 2, {'?',ctrl('G')}}, \
+--- 3107,3132 ----
+ #define MC_NOT 799
+ #define MC_COLLAPSE 800
+ #define MC_CHK_RECENT 801
+! #define MC_PRETHREAD 802
+! #define MC_CTHREAD 803
+! #define MC_OTHREAD 804
+! #define MC_DELTHREAD 805
+! #define MC_UNDTHREAD 806
+! #define MC_SELTHREAD 807
+! #define MC_SSUTHREAD 808
+! #define MC_DSUTHREAD 809
+! #define MC_USUTHREAD 810
+! #define MC_SORTHREAD 811
+! #define MC_NEXTHREAD 812
+! #define MC_KOLAPSE 813
+! #define MC_EXPTHREAD 814
+! #define MC_QUOTA 815
+
+ /*
+ * Some standard Key/Command Bindings
+ */
++ #define MC_IFAUTOCHECK 820
++ #define MC_FORCECHECK 821
+ #define NULL_MENU {NULL, NULL, {MC_NONE}, KS_NONE}
+ #define HELP_MENU {"?", "Help", \
+ {MC_HELP, 2, {'?',ctrl('G')}}, \
+***************
+*** 3094,3100 ****
+ #define TAB_MENU {"Tab", "NextNew", \
+ {MC_TAB,1,{TAB}}, \
+ KS_NONE}
+!
+
+ #define USER_INPUT_TIMEOUT(ps) ((ps->hours_to_timeout > 0) && \
+ ((time(0) - time_of_last_input) > 60*60*(ps->hours_to_timeout)))
+--- 3224,3232 ----
+ #define TAB_MENU {"Tab", "NextNew", \
+ {MC_TAB,1,{TAB}}, \
+ KS_NONE}
+! #define QUOTA_MENU {"@", "Quota", \
+! {MC_QUOTA,1,{'@'}}, \
+! KS_NONE}
+
+ #define USER_INPUT_TIMEOUT(ps) ((ps->hours_to_timeout > 0) && \
+ ((time(0) - time_of_last_input) > 60*60*(ps->hours_to_timeout)))
+***************
+*** 3681,3688 ****
+--- 3813,3872 ----
+ #define HEX_CHAR1(C) HEX_ARRAY[((C) & 0xf0) >> 4]
+ #define HEX_CHAR2(C) HEX_ARRAY[(C) & 0xf]
+
++ typedef struct rule {
++ char *result; /* The result of the rule */
++ int number; /* The number of the rule that succeded, -1 if not */
++ } RULE_RESULT;
++
++ #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
++
++ TOKEN_VALUE {
++ char *testxt;
++ TOKEN_VALUE *next;
++ };
++
++ typedef enum {Equal, Subset, Includes,
++ NotEqual, NotSubset, NotIncludes,
++ EndTypes} TestType;
++
++ CONDITION_S {
++ char *tname; /* tname ttype {value} */
++ TestType ttype; /* tname ttype {value} */
++ TOKEN_VALUE *value; /* value to check against */
++ CONDITION_S *next; /* next condition to test */
++ };
++
++ RULEACTION_S {
++ char *token; /* token := function{value} or token = null */
++ char *function; /* token := function{value} or simply function{value}*/
++ TOKEN_VALUE *value; /* token := function{value} or simply function{value}*/
++ int context; /* context in which this rule can be used */
++ char* (*exec)();
++ unsigned int is_trim:1;
++ unsigned int is_rextrim:1;
++ unsigned int is_replace:1;
++ };
+
++ RULE_S {
++ CONDITION_S *condition;
++ RULEACTION_S *action;
++ };
+
++ RULELIST {
++ RULE_S *prule;
++ RULELIST *next;
++ };
++
++ PRULELIST_S {
++ int varnum; /* number associated to the variable */
++ RULELIST *rlist;
++ PRULELIST_S *next;
++ };
+
+ /*------------------------------
+ Structure to pass optionally_enter to tell it what keystrokes
+***************
+*** 3830,3835 ****
+--- 4014,4020 ----
+ PrivateAffector *affector;
+ } PrivateTop;
+
++ #define DF_THREAD_SORT_KEY "thread"
+
+ typedef enum {OpenFolder, SaveMessage, FolderMaint, GetFcc,
+ Subscribe, PostNews} FolderFun;
+***************
+*** 3954,3959 ****
+--- 4139,4146 ----
+ unsigned char t; /* temporary char */
+ char *line; /* place for temporary storage */
+ char *linep; /* pointer into storage space */
++ char *oldline; /* the previous line to "line" */
++ char *oldlinep; /* the previous line to "line" */
+ void *opt; /* optional per instance data */
+ void *data; /* misc internal data pointer */
+ unsigned char queue[1 + GF_MAXBUF];
+***************
+*** 4221,4226 ****
+--- 4408,4414 ----
+ CONTEXT_S *context_last; /* most recently open context */
+
+ SP_S s_pool; /* stream pool */
++ SP_S s_pool_status; /* stream pool */
+
+ char inbox_name[MAXFOLDER+1];
+ char pine_pre_vers[10]; /* highest version previously run */
+***************
+*** 4228,4237 ****
+--- 4416,4436 ----
+ MAILSTREAM *mail_stream; /* ptr to current folder stream */
+ MSGNO_S *msgmap; /* ptr to current message map */
+
++ char *role; /* role used when composing */
++ int exiting;
++
+ unsigned read_predicted:1;
+
+ char cur_folder[MAXPATH+1];
++ QUOTALIST *quota;
+ char last_unambig_folder[MAXPATH+1];
++ int refresh_list;
++ int in_pico;
++ int in_fld_list;
++ int force_check_now;
++ int checking_incfld;
++ int incfld_timeout;
++ int delay;
+ ATTACH_S *atmts;
+ int atmts_allocated;
+ int remote_abook_validity; /* minutes, -1=never, 0=only on opens */
+***************
+*** 4255,4260 ****
+--- 4454,4461 ----
+ unsigned unseen_in_view:1;
+ unsigned start_in_context:1; /* start fldr_scrn in current cntxt */
+ unsigned def_sort_rev:1; /* true if reverse sort is default */
++ unsigned thread_def_sort_rev:1; /* true if reverse sort is default in thread screen */
++ unsigned msgmap_thread_def_sort_rev:1; /* true if reverse sort is being used in thread screen */
+ unsigned restricted:1;
+
+ unsigned save_msg_rule:5;
+***************
+*** 4265,4270 ****
+--- 4466,4472 ----
+ unsigned titlebar_color_style:3;
+ unsigned fld_sort_rule:3;
+ unsigned inc_startup_rule:3;
++ unsigned inc_check_rule:2;
+ unsigned pruning_rule:3;
+ unsigned reopen_rule:4;
+ unsigned goto_default_rule:3;
+***************
+*** 4356,4361 ****
+--- 4558,4566 ----
+
+ int *initial_cmds; /* cmds to execute on startup */
+ int *free_initial_cmds; /* used to free when done */
++ int *initial_cmds_backup; /* keep a copy in case they are freed */
++ int *free_initial_cmds_backup; /* free the copy */
++ int initial_cmds_offset; /* how many commands we have executed */
+
+ char c_client_error[300]; /* when nowhow_error is set and PARSE */
+
+***************
+*** 4392,4397 ****
+--- 4597,4605 ----
+ EditWhich ew_for_other_take;
+
+ SortOrder def_sort, /* Default sort type */
++ thread_def_sort, /* Default Sort Type in Thread Screen */
++ thread_cur_sort, /* current sort style for threads */
++ msgmap_thread_sort,
+ sort_types[22];
+
+ int last_expire_year, last_expire_month;
+***************
+*** 4404,4409 ****
+--- 4612,4620 ----
+
+ int nmw_width;
+
++ char *subject;
++ int send_immediately;
++
+ int hours_to_timeout;
+
+ int tcp_query_timeout;
+***************
+*** 4425,4430 ****
+--- 4636,4642 ----
+ INIT_ERR_S *init_errs;
+
+ PRINT_S *print;
++ PRULELIST_S *rule_list;
+
+ struct variable *vars;
+ };
+***************
+*** 4552,4557 ****
+--- 4764,4770 ----
+ void gf_busy PROTO((FILTER_S *, int));
+ void gf_nvtnl_local PROTO((FILTER_S *, int));
+ void gf_local_nvtnl PROTO((FILTER_S *, int));
++ void gf_quote_test PROTO((FILTER_S *, int));
+ void gf_line_test PROTO((FILTER_S *, int));
+ void *gf_line_test_opt PROTO((linetest_t, void *));
+ LT_INS_S **gf_line_test_new_ins PROTO((LT_INS_S **, char *, char *, int));
+***************
+*** 4588,4599 ****
+--- 4801,4817 ----
+ char *folder_is_nick PROTO((char *, void *, int));
+ char *next_folder PROTO((MAILSTREAM **, char *, char *,CONTEXT_S *,
+ long *, int *));
++ int next_folder_check PROTO((MAILSTREAM **, CONTEXT_S *, long *, long *,
++ FOLDER_S *, int *));
+ void init_inbox_mapping PROTO((char *, CONTEXT_S *));
+ int news_build PROTO((char *, char **, char **, BUILDER_ARG *, int *));
+ char *news_group_selector PROTO((char **));
+ void free_newsgrp_cache PROTO(());
+ char *context_edit_screen PROTO((struct pine *, char *, char *,
+ char *, char *, char *));
++ void update_incoming_folder_data PROTO((MAILSTREAM *, CONTEXT_S *));
++ FOLDER_S *incoming_folder_data PROTO((MAILSTREAM *, CONTEXT_S *));
++ int need_folder_report PROTO ((char *));
+ SELECTED_S *new_selected PROTO((void));
+ void free_selected PROTO((SELECTED_S **));
+ int add_new_folder PROTO((CONTEXT_S *, EditWhich, int, char *, size_t,
+***************
+*** 4615,4620 ****
+--- 4833,4839 ----
+ #endif
+
+ /*-- imap.c --*/
++ void pine_parse_quota PROTO((MAILSTREAM *, unsigned char *msg,QUOTALIST *));
+ char *cached_user_name PROTO((char *));
+ void imap_flush_passwd_cache PROTO(());
+ long pine_tcptimeout PROTO((long, long));
+***************
+*** 4647,4653 ****
+ int write_pinerc PROTO((struct pine *, EditWhich, int));
+ int var_in_pinerc PROTO((char *));
+ void free_pinerc_lines PROTO((PINERC_LINE **));
+! int decode_sort PROTO((char *, SortOrder *, int *));
+ void dump_global_conf PROTO((void));
+ void dump_new_pinerc PROTO((char *));
+ int set_variable PROTO((int, char *, int, int, EditWhich));
+--- 4866,4872 ----
+ int write_pinerc PROTO((struct pine *, EditWhich, int));
+ int var_in_pinerc PROTO((char *));
+ void free_pinerc_lines PROTO((PINERC_LINE **));
+! int decode_sort PROTO((char *, SortOrder *, int *, int));
+ void dump_global_conf PROTO((void));
+ void dump_new_pinerc PROTO((char *));
+ int set_variable PROTO((int, char *, int, int, EditWhich));
+***************
+*** 4678,4683 ****
+--- 4897,4903 ----
+ NAMEVAL_S *titlebar_col_style PROTO((int));
+ NAMEVAL_S *fld_sort_rules PROTO((int));
+ NAMEVAL_S *incoming_startup_rules PROTO((int));
++ NAMEVAL_S *incoming_check_rules PROTO((int));
+ NAMEVAL_S *startup_rules PROTO((int));
+ NAMEVAL_S *pruning_rules PROTO((int));
+ NAMEVAL_S *reopen_rules PROTO((int));
+***************
+*** 4720,4729 ****
+ int set_mime_extension_by_type PROTO((char *, char *));
+
+ /*---- mailcmd.c ----*/
+ int process_cmd PROTO((struct pine *, MAILSTREAM *, MSGNO_S *,
+ int, CmdWhere, int *));
+ int apply_command PROTO((struct pine *, MAILSTREAM *, MSGNO_S *, int,
+! int, int));
+ int menu_command PROTO((int, struct key_menu *));
+ void menu_init_binding PROTO((struct key_menu *, int, int,
+ char *, char *, int));
+--- 4940,4950 ----
+ int set_mime_extension_by_type PROTO((char *, char *));
+
+ /*---- mailcmd.c ----*/
++ MAILSTREAM *find_open_stream PROTO((void));
+ int process_cmd PROTO((struct pine *, MAILSTREAM *, MSGNO_S *,
+ int, CmdWhere, int *));
+ int apply_command PROTO((struct pine *, MAILSTREAM *, MSGNO_S *, int,
+! int, int, int));
+ int menu_command PROTO((int, struct key_menu *));
+ void menu_init_binding PROTO((struct key_menu *, int, int,
+ char *, char *, int));
+***************
+*** 4766,4771 ****
+--- 4987,4993 ----
+ char *get_uname PROTO((char *, char *, int));
+ char *build_updown_cmd PROTO((char *, char *, char *, char*));
+ int file_lister PROTO((char *, char *, int, char *, int, int, int));
++ unsigned long rules_cursor_pos PROTO((MAILSTREAM *));
+ int display_folder_list PROTO((CONTEXT_S **, char *, int,
+ int (*) PROTO((struct pine *,
+ CONTEXT_S **,
+***************
+*** 4790,4795 ****
+--- 5012,5018 ----
+ #endif
+
+ /*--- mailindx.c ---*/
++ void insert_pattern_in_string PROTO((char *, char *, int));
+ void mail_index_screen PROTO((struct pine *));
+ int index_lister PROTO((struct pine *, CONTEXT_S *, char *,
+ MAILSTREAM *, MSGNO_S *));
+***************
+*** 4820,4826 ****
+ MSGNO_S *, IndexType, int *, int));
+ char *sort_name PROTO((SortOrder));
+ void sort_folder PROTO((MAILSTREAM *, MSGNO_S *,
+! SortOrder, int, unsigned));
+ int percent_sorted PROTO((void));
+ void msgno_init PROTO((MSGNO_S **, long));
+ void msgno_give PROTO((MSGNO_S **));
+--- 5043,5049 ----
+ MSGNO_S *, IndexType, int *, int));
+ char *sort_name PROTO((SortOrder));
+ void sort_folder PROTO((MAILSTREAM *, MSGNO_S *,
+! SortOrder, int, unsigned, int));
+ int percent_sorted PROTO((void));
+ void msgno_init PROTO((MSGNO_S **, long));
+ void msgno_give PROTO((MSGNO_S **));
+***************
+*** 4843,4849 ****
+ void free_pine_elt PROTO((void **));
+ SEARCHSET *build_searchset PROTO((MAILSTREAM *));
+ void collapse_or_expand PROTO((struct pine *, MAILSTREAM *, MSGNO_S *,
+! unsigned long));
+ PINETHRD_S *fetch_thread PROTO((MAILSTREAM *, unsigned long));
+ PINETHRD_S *fetch_head_thread PROTO((MAILSTREAM *));
+ int view_thread PROTO((struct pine *, MAILSTREAM *, MSGNO_S *, int));
+--- 5066,5072 ----
+ void free_pine_elt PROTO((void **));
+ SEARCHSET *build_searchset PROTO((MAILSTREAM *));
+ void collapse_or_expand PROTO((struct pine *, MAILSTREAM *, MSGNO_S *,
+! unsigned long, int));
+ PINETHRD_S *fetch_thread PROTO((MAILSTREAM *, unsigned long));
+ PINETHRD_S *fetch_head_thread PROTO((MAILSTREAM *));
+ int view_thread PROTO((struct pine *, MAILSTREAM *, MSGNO_S *, int));
+***************
+*** 4891,4896 ****
+--- 5114,5121 ----
+ int, char *));
+
+ /*--- mailview.c ---*/
++ int select_quote PROTO((long, char *, LT_INS_S **, void *));
++ int next_level_quote PROTO((char *, char **, int, int));
+ void mail_view_screen PROTO((struct pine *));
+ int scrolltool PROTO((SCROLL_S *));
+ char *body_type_names PROTO((int));
+***************
+*** 4937,4942 ****
+--- 5162,5169 ----
+ void check_point_change PROTO((MAILSTREAM *));
+ void reset_check_point PROTO((MAILSTREAM *));
+ void zero_new_mail_count PROTO((void));
++ int new_mail_incfolder PROTO((struct pine *, int));
++ char *new_mail_in_open_stream PROTO((MAILSTREAM *, long *, long *));
+ int changes_to_checkpoint PROTO((MAILSTREAM *));
+ void close_newmailfifo PROTO((void));
+ void init_newmailfifo PROTO((char *));
+***************
+*** 5122,5133 ****
+--- 5349,5362 ----
+ int sp_flagged PROTO((MAILSTREAM *, unsigned long));
+ void sp_mark_stream_dead PROTO((MAILSTREAM *));
+ MAILSTREAM *sp_stream_get PROTO((char *, unsigned long));
++ MAILSTREAM *sp_stream_status_get PROTO((char *));
+ int sp_a_locked_stream_is_dead PROTO((void));
+ int sp_a_locked_stream_changed PROTO((void));
+ MAILSTREAM *sp_inbox_stream PROTO((void));
+ void sp_cleanup_dead_streams PROTO((void));
+ int sp_nremote_permlocked PROTO((void));
+ void sp_end PROTO((void));
++ void sp_status_end PROTO((void));
+
+ /*-- reply.c --*/
+ void reply PROTO((struct pine *, ACTION_S *));
+***************
+*** 5138,5144 ****
+ ENVELOPE *, ADDRESS **, ADDRESS **,
+ ADDRESS **, ADDRESS **,int *));
+ int reply_news_test PROTO((ENVELOPE *, ENVELOPE *));
+! int reply_text_query PROTO((struct pine *, long, char **));
+ BODY *reply_body PROTO((MAILSTREAM *, ENVELOPE *, BODY *, long,
+ char *, void *, char *, int, ACTION_S *, int,
+ REDRAFT_POS_S **));
+--- 5367,5373 ----
+ ENVELOPE *, ADDRESS **, ADDRESS **,
+ ADDRESS **, ADDRESS **,int *));
+ int reply_news_test PROTO((ENVELOPE *, ENVELOPE *));
+! int reply_text_query PROTO((struct pine *, long, ENVELOPE *, char **));
+ BODY *reply_body PROTO((MAILSTREAM *, ENVELOPE *, BODY *, long,
+ char *, void *, char *, int, ACTION_S *, int,
+ REDRAFT_POS_S **));
+***************
+*** 5185,5190 ****
+--- 5414,5459 ----
+ void standard_picobuf_setup PROTO((PICO *));
+ void standard_picobuf_teardown PROTO((PICO *));
+
++ /* -- rules.c -- */
++ RULE_RESULT *get_result_rule PROTO ((int, int, ENVELOPE *));
++ char *test_rule PROTO ((RULELIST *, int, ENVELOPE *, int *));
++ char *process_rule PROTO ((RULE_S *, int, ENVELOPE *));
++ int test_condition PROTO ((CONDITION_S *, int, ENVELOPE *));
++ int test_in PROTO ((CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int));
++ int test_ni PROTO ((CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int));
++ int test_not_in PROTO ((CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int));
++ int test_not_ni PROTO ((CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int));
++ int test_eq PROTO ((CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int));
++ int test_not_eq PROTO ((CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int));
++ int isolate_condition PROTO ((char *, char **, int *));
++ int condition_contains_token PROTO((CONDITION_S *, char *));
++ char *trim PROTO ((RULEACTION_S *, int, ENVELOPE *));
++ char *rextrim PROTO ((RULEACTION_S *, int, ENVELOPE *));
++ char *raw_value PROTO ((RULEACTION_S *, int, ENVELOPE *));
++ char *extended_value PROTO ((RULEACTION_S *, int, ENVELOPE *));
++ char *expand PROTO ((char *, char *));
++ char *get_name_token PROTO ((char *));
++ char *advance_to_char PROTO ((char *, char, int, int *));
++ void free_token_value PROTO ((TOKEN_VALUE **));
++ void free_condition PROTO ((CONDITION_S **));
++ void free_ruleaction PROTO ((RULEACTION_S **));
++ void free_rule PROTO ((RULE_S **));
++ void free_rule_list PROTO ((RULELIST **));
++ void free_parsed_rule_list PROTO((PRULELIST_S **));
++ void *alloc_mem PROTO ((size_t));
++ void add_rule PROTO ((int, int));
++ void create_rule_list PROTO ((void));
++ RULE_S *parse_rule PROTO ((char *, int));
++ RULE_S *get_rule PROTO ((RULELIST *, int));
++ RULELIST *get_rule_list PROTO ((char **, int, int));
++ RULELIST *get_rulelist_from_code PROTO((int, PRULELIST_S *));
++ TOKEN_VALUE *parse_group_data PROTO ((char *,int *));
++ TOKEN_VALUE *copy_parsed_value PROTO((TOKEN_VALUE *, int, ENVELOPE *));
++ CONDITION_S *fill_condition PROTO ((char *));
++ CONDITION_S *parse_condition PROTO ((char *, int *));
++ PRULELIST_S *add_prule PROTO ((PRULELIST_S *, PRULELIST_S *));
++ RULEACTION_S *parse_action PROTO ((char *, int));
++
+ /*-- screen.c --*/
+ void draw_keymenu PROTO((struct key_menu *, bitmap_t, int, int,
+ int, OtherMenu));
+***************
+*** 5309,5314 ****
+--- 5578,5584 ----
+ void removing_leading_white_space PROTO((char *));
+ void removing_leading_and_trailing_white_space PROTO((char *));
+ int removing_double_quotes PROTO((char *));
++ void removing_extra_stuff PROTO((char *));
+ char *skip_white_space PROTO((char *));
+ char *skip_to_white_space PROTO((char *));
+ char *removing_quotes PROTO((char *));
+***************
+*** 5490,5495 ****
+--- 5760,5766 ----
+ void MoveCursor PROTO((int, int));
+ void NewLine PROTO((void));
+ int config_screen PROTO((struct ttyo **));
++ void fake_config_screen PROTO((struct ttyo **));
+ void init_screen PROTO((void));
+ void end_screen PROTO((char *, int));
+ void outchar PROTO((int));
+diff -rc pine4.63/pine/pine.hlp pine4.63.I.USE/pine/pine.hlp
+*** pine4.63/pine/pine.hlp Thu Apr 28 10:22:02 2005
+--- pine4.63.I.USE/pine/pine.hlp Thu May 19 19:59:15 2005
+***************
+*** 457,462 ****
+--- 457,463 ----
+ <P>
+ Some topics of current interest include:
+ <UL>
++ <P><LI> Information on <A HREF="h_patches">patches for this release</A>
+ <P><LI> <A HREF="h_maildrop">Mail Drops</A>
+ <P><LI> Information on <A HREF="h_info_on_locking">Folder Locking</A>
+ <P><LI> Information on <A HREF="h_info_on_mbox">Missing mail and the mbox driver</A>
+***************
+*** 1081,1086 ****
+--- 1082,1143 ----
+ &lt;End of Configuration Notes&gt;
+ </BODY>
+ </HTML>
++ ====== h_patches ======
++ <html>
++ <head>
++ <TITLE>Information on patches added to this release</TITLE>
++ </head>
++ <body>
++ <H1>Information on patches added to this release</H1>
++ <P>
++ This version of Pine has been modified by including patches from
++ <A HREF="http://www.math.washington.edu/~chappa/pine/">
++ http://www.math.washington.edu/~chappa/pine/</A>. These patches include
++ new features and bug fixes. More complete information on each patch
++ included in this version can be found in the web.
++
++ <P>If you have any problems with this release of Pine, please contact
++ Eduardo Chappa &lt;chappa@math.washington.edu&gt;. Include the word
++ &quot;Pine&quot; in the subject of the message to bypass spam filters.
++
++ <P>The list of patches included in this release are:
++
++ <P>New Features:
++
++ <UL>
++ <LI> Maildir Patch. <A HREF="h_config_maildir">(more...)</A>
++ <LI> Enhanced fancy thread interface.
++ <A HREF="h_config_enhanced_thread">(more...)</A>
++ <LI> Pine justifies paragraphs with more than one level of indentation.
++ <A HREF="h_compose_justify">(more...)</A>
++ <LI> Rules patch, to make Pine flexible.
++ <A HREF="h_config_new_rules">(more...)</A>
++ <LI> Send mail from the command line.
++ <LI> Automatic check of new mail in incoming folders.
++ <A HREF="h_config_enable_check_incoming">(more...)</A>
++ <LI> Write accents like &aacute;&eacute; or other foreing characters: &ntilde; etc.
++ <LI> Tab check folders on cycles.
++ <A HREF="h_config_circular_tab">(more...)</A>
++ <LI> Get the number of new messages when opening a folder.
++ <LI> Reinsert the pattern you searched for last.
++ <LI> New Reply command menu.
++ <A HREF="h_config_alt_reply_menu">(more...)</A>
++ <LI> Change your From header without any effort!
++ <LI> Choose a role when composing a message from a mailto: link.
++ <LI> Paint special text in the body of the message in any custom color.
++ <A HREF="h_config_special_text_to_color">(more...)</A>
++ <LI> Select messages by the content of an arbitrary header.
++ <LI> Delete until the the end of a file, or message (press ^W^X).
++ <LI> Get the QUOTA information from an IMAP server (if such server supports
++ the QUOTA command).
++ </UL>
++ <P> Bug Fixes:
++ <UL>
++ <LI> Fix a bug which could make the sort by score be computed incorrectly.
++ </UL>
++
++ </body>
++ </html>
+ ====== h_news_legal ======
+ <html>
+ <head>
+***************
+*** 3091,3097 ****
+--- 3148,3156 ----
+ <li><a href="h_config_alt_role_menu">FEATURE: Alternate-Role-Menu</a>
+ <li><a href="h_config_force_low_speed">FEATURE: Assume-Slow-Link</a>
+ <li><a href="h_config_auto_read_msgs">FEATURE: Auto-Move-Read-Msgs</a>
++ <li><a href="h_config_auto_read_msgs_rules">FEATURE: auto-move-read-msgs-using-rules</a>
+ <li><a href="h_config_auto_open_unread">FEATURE: Auto-Open-Next-Unread</a>
++ <li><a href="h_config_circular_tab">FEATURE: enable-circular-tab</a>
+ <li><a href="h_config_auto_unzoom">FEATURE: Auto-Unzoom-After-Apply</a>
+ <li><a href="h_config_auto_zoom">FEATURE: Auto-Zoom-After-Select</a>
+ <li><a href="h_config_check_mail_onquit">FEATURE: Check-Newmail-When-Quitting</a>
+***************
+*** 3349,3354 ****
+--- 3408,3414 ----
+ <li><a href="h_config_abook_formats">OPTION: Addressbook-Formats</a>
+ <li><a href="h_config_alt_addresses">OPTION: Alt-Addresses</a>
+ <li><a href="h_config_char_set">OPTION: Character-Set</a>
++ <li><a href="h_config_special_text_to_color">OPTION: Special Text to Color</a>
+ <li><a href="h_config_color_style">OPTION: Color-Style</a>
+ <li><a href="h_config_composer_wrap_column">OPTION: Composer-Wrap-Column</a>
+ <li><a href="h_config_index_color_style">OPTION: Current-Indexline-Style</a>
+***************
+*** 3449,3457 ****
+--- 3509,3519 ----
+ <li><a href="h_config_sending_filter">OPTION: Sending-Filters</a>
+ <li><a href="h_config_sendmail_path">OPTION: Sendmail-Path</a>
+ <li><a href="h_config_signature_color">OPTION: Signature Color</a>
++ <li><a href="h_config_special_text_color">OPTION: Special Text Color</a>
+ <li><a href="h_config_signature_file">OPTION: Signature-File</a>
+ <li><a href="h_config_smtp_server">OPTION: SMTP-Server</a>
+ <li><a href="h_config_sort_key">OPTION: Sort-Key</a>
++ <li><a href="h_config_thread_sort_key">OPTION: Thread-Sort-Key</a>
+ <li><a href="h_config_speller">OPTION: Speller</a>
+ <li><a href="h_config_sshcmd">OPTION: Ssh-Command</a>
+ <li><a href="h_config_ssh_open_timeo">OPTION: Ssh-Open-Timeout</a>
+***************
+*** 5297,5302 ****
+--- 5359,5517 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ======= h_thread_index_sort_arrival =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: Arrival</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: Arrival</H1>
++
++ The <EM>Arrival</EM> sort option arranges threads according to the last
++ time that a message was added to it. In this order the last thread
++ contains the most recent message in the folder.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ======= h_thread_index_sort_date =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: Date</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: Date</H1>
++
++ The <EM>Date</EM> sort option in the THREAD&nbsp;INDEX screen is the same
++ as sorting by thread, the most likely thing is that you won't see Pine
++ sorting the folder, because it's already sorted.
++
++ <P>
++ On a folder like INBOX, sorting by &quot;Date&quot; should be almost
++ identical to sorting by &quot;Arrival&quot;.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ======= h_thread_index_sort_subj =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: Subject</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: Subject</H1>
++
++ The <EM>Subject</EM> sort option has not been defined yet.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ======= h_thread_index_sort_ordsubj =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: OrderedSubject</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: OrderedSubject</H1>
++
++ The <EM>OrderedSubject</EM> sort option in the THREAD&nbsp;INDEX screen is
++ the same as sorting by <A HREF="h_thread_index_sort_subj">Subject</A>.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ======= h_thread_index_sort_thread =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: Thread</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: Thread</H1>
++
++ The <EM>Thread</EM> sort option in the THREAD&nbsp;INDEX screen sorts all
++ messages by the proposed algorithm by Crispin and Murchison. In this
++ method of sorting once threads have been isolated they are sorted by the
++ date of their parents, or if that is missing, the first message in that
++ thread.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ======= h_thread_index_sort_from =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: From</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: From</H1>
++
++ The <EM>From</EM> sort option has not been defined yet.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ======= h_thread_index_sort_size =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: Size</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: Size</H1>
++
++ The <EM>Size</EM> sort option has not been defined yet.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ======= h_thread_index_sort_score =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: Score</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: Score</H1>
++
++ The <EM>Score</EM> sort option has not been defined yet.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ======= h_thread_index_sort_to =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: To</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: To</H1>
++
++ The <EM>To</EM> sort option has not been defined yet.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ======= h_thread_index_sort_cc =======
++ <HTML>
++ <HEAD>
++ <TITLE>SORT OPTION: Cc</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>SORT OPTION: Cc</H1>
++
++ The <EM>Cc</EM> sort option has not been defined yet.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ======= h_index_cmd_whereis =======
+ <HTML>
+ <HEAD>
+***************
+*** 6515,6520 ****
+--- 6730,6775 ----
+ not preserved.
+
+ <P>
++ This version of Pine contains an enhanced algorithm for justification,
++ which allows you to justify text that contains more complicated quote
++ strings. This algorithm is based on pragmatics, rather than on a theory,
++ and seems to work well with most messages. Below you will find technical
++ information on how this algorithm works.
++
++ <P>
++ When justifying, Pine goes through each line of the text and tries to
++ determine for each line what the quote string of that line is. The quote
++ string you provided is always recognized. Among other characters
++ recognized is &quot;&gt;&quot;.
++
++ <P>
++ Some other constructions of quote strings are recognized only if they
++ appear enough in the text. For example &quot;Peter :&quot; is only
++ recognized if it appears in two consecutive lines.
++
++ <P>
++ Additionaly, Pine recognizes indent-strings and justifies text in a
++ paragraph to the right of indent-string, padding with spaces if necessary.
++ An indent string is one which you use to delimit elements of a list. For
++ example, if you were to write a list of groceries, one may write:
++
++ <UL>
++ <LI> Fruit
++ <LI> Bread
++ <LI> Eggs
++ </UL>
++
++ <P>
++ In this case the character &quot;*&quot; is the indent-string. Pine
++ recognizes numbers (0, 1, 2.5, etc) also as indent-strings, and certain
++ combinations of spaces, periods, and parenthesis. In any case, numbers are
++ recognized <B>ONLY</B> if the line preceeding the given line is empty or
++ ends in one of the characters &quot;.&quot; or &quot;:&quot;.
++ In addition to the explanation of what constitutes a paragraph above, a
++ new paragraph is recognized when an indent-string is found in it (and
++ validated according to the above stated rules).
++
++ <P>
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
+***************
+*** 17318,17323 ****
+--- 17573,17579 ----
+ <A HREF="h_config_index_format">&quot;Index-Format&quot;</A> option,
+ in the <A HREF="h_config_reply_intro">&quot;Reply-Leadin&quot;</A> option,
+ in signature files,
++ in the <A HREF="h_config_reply_leadin_rules">&quot;new-rules&quot; option</A>,
+ in template files used in
+ <A HREF="h_rules_roles">&quot;roles&quot;</A>, and in the folder name
+ that is the target of a Filter Rule.
+***************
+*** 17330,17336 ****
+ <P>
+ <P>
+
+! <H1><EM>Tokens Available for all Cases (except Filter Rules)</EM></H1>
+
+ <DL>
+ <DT>SUBJECT</DT>
+--- 17586,17592 ----
+ <P>
+ <P>
+
+! <H1><EM>Tokens Available for all Cases (except Filter Rules or in some cases for new-rules)</EM></H1>
+
+ <DL>
+ <DT>SUBJECT</DT>
+***************
+*** 17352,17357 ****
+--- 17608,17622 ----
+ For example, &quot;mailbox@domain&quot;.
+ </DD>
+
++ <DT>ADDRESSTO</DT>
++ <DD>
++ This is similar to the &quot;TO&quot; token, only it is always the
++ email address of all people listed in the TO: field of the messages. Addresses
++ are separated by a blank space. Example, &quot;mailbox@domain&quot; when
++ the e-mail message contains only one person in the To: field, or
++ &quot;peter@flintstones.com president@world.com&quot;.
++ </DD>
++
+ <DT>MAILBOX</DT>
+ <DD>
+ This is the same as the &quot;ADDRESS&quot; except that the
+***************
+*** 17399,17404 ****
+--- 17664,17678 ----
+ message's &quot;Cc:&quot; header field.
+ </DD>
+
++ <DT>ADDRESSCC</DT>
++ <DD>
++ This is similar to the &quot;CC&quot; token, only it is always the
++ email address of all people listed in the Cc: field of the messages. Addresses
++ are separated by a blank space. Example: &quot;mailbox@domain&quot; when
++ the e-mail message contains only one person in the Cc: field, or
++ &quot;peter@flintstones.com president@world.com&quot;.
++ </DD>
++
+ <DT>RECIPS</DT>
+ <DD>
+ This token represents the personal names (or email addresses if the names
+***************
+*** 17407,17412 ****
+--- 17681,17694 ----
+ the message's &quot;Cc:&quot; header field.
+ </DD>
+
++ <DT>ADDRESSRECIPS</DT>
++ <DD>
++ This token represent the e-mail addresses of the people in the To: and
++ Cc: fields, exactly in that order separated by a space. It is almost obtained
++ by concatenating the ADDRESSTO and ADDRESSCC tokens.
++ </DD>
++
++
+ <DT>NEWSANDRECIPS</DT>
+ <DD>
+ This token represents the newsgroups from the
+***************
+*** 17779,17784 ****
+--- 18061,18074 ----
+ <P>
+ </DD>
+
++ <DT>SIZETHREAD</DT>
++ <DD>
++ This token represents the total size of the thread for a collapsed thread
++ or the size of the branch for an expanded thread. The field is omitted for
++ messages that are not top of threads nor branches and it defaults to
++ the SIZE token when your folders is not sorted by thread.
++ </DD>
++
+ <DT>SIZENARROW</DT>
+ <DD>
+ This token represents the total size, in bytes, of the message.
+***************
+*** 18134,18139 ****
+--- 18424,18501 ----
+ </DL>
+
+ <P>
++ <H1><EM>Tokens Available Only for New-Rules</EM></H1>
++
++ <DL>
++ <DT>FOLDER</DT>
++ <DD>
++ Name of the folder where the rule will be applied
++ </DD>
++ </DL>
++
++ <DL>
++ <DT>COLLECTION</DT>
++ <DD>
++ Name of the collection list where the rule will be applied.
++ </DD>
++ </DL>
++
++ <DL>
++ <DT>ROLE</DT>
++ <DD>
++ Name of the Role used to reply a message.
++ </DD>
++ </DL>
++
++ <DL>
++ <DT>BCC</DT>
++ <DD>
++ Not implemented yet, but it will be implemented in future versions. It will
++ be used for <A HREF="h_config_compose_rules">compose</A>
++ <A HREF="h_config_reply_rules">reply</A>
++ <A HREF="h_config_forward_rules">forward</A>
++ rules.
++ </DD>
++ </DL>
++
++ <DL>
++ <DT>LCC</DT>
++ <DD>
++ This is the value of the Lcc: field at the moment that you start the composition.
++ </DD>
++ </DL>
++
++ <DL>
++ <DT>FORWARDFROM</DT>
++ <DD>
++ This corresponds to the personal name (or address if there's no personal
++ name) of the person who sent the message that you are forwarding.
++ </DD>
++ </DL>
++
++ <DL>
++ <DT>FORWARDADDRESS</DT>
++ <DD>
++ This is the address of the person that sent the message that you
++ are forwarding.
++ </DD>
++ </DL>
++
++
++
++
++ <DL>
++ <DT>FLAG</DT>
++ <DD>
++ A string containing the value of all the flags associated to a specific
++ message. The possible values of allowed flags are "*" for Important, "N"
++ for recent or new, "U" for unseen or unread, "R" for seen or read, "A" for
++ answered and "D" for deleted. See an example of its use in the
++ <A HREF="h_config_new_rules">new rules</A> explanation and example help.
++ </DD>
++ </DL>
++
++ <P>
+ <H1><EM>Token Available Only for Templates and Signatures</EM></H1>
+
+ <DL>
+***************
+*** 18866,18871 ****
+--- 19228,19250 ----
+ be combined with the other fields if you'd like.
+
+ <End of help on this topic>
++ ====== h_config_check_inc_fld ======
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: incoming-folders-to-check</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: incoming-folders-to-check</H1>
++ <P>
++ if you set this option and <A HREF="h_config_enable_check_incoming">
++ enable-check-incoming-folders</A> then you can use this option to write a space
++ separate list of incoming folders where you want new mail to be
++ checked. If you want all your incoming folders to be checked just write a
++ "*" as the value for this option.
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ======= h_address_format =======
+ <HTML>
+ <HEAD>
+***************
+*** 19988,20048 ****
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
+! ====== h_config_literal_sig =====
+ <HTML>
+ <HEAD>
+! <TITLE>OPTION: Literal-Signature</TITLE>
+ </HEAD>
+ <BODY>
+! <H1>OPTION: Literal-Signature</H1>
+
+- With this option your actual signature, as opposed to
+- the name of a file containing your signature,
+- is stored in the Pine configuration file.
+- If this is defined it takes precedence over the Signature-File option.
+ <P>
+
+- This is simply a different way to store the signature.
+- The signature is stored inside your Pine configuration file instead of in
+- a separate file.
+- Tokens work the same way they do with the
+- <A HREF="h_config_signature_file">Signature-File</A> so look there for
+- help.
+ <P>
+
+- The Setup/Signature command on Pine's Main Menu will edit
+- the &quot;Literal-Signature&quot; by default. However, if no
+- &quot;Literal-Signature&quot; is defined and the file named in the
+- &quot;Signature-File&quot; option exists, then the latter will be used
+- instead.
+ <P>
+!
+! The two character sequence &#92;n (backslash followed by
+! the character n) will be used to signify a line-break in your signature.
+! You don't have to enter the &#92;n, but it will be visible in the
+! SETUP CONFIGURATION window after you are done editing the signature.
+
+ <P>
+! <UL>
+ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+! </UL><P>
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
+! ====== h_config_signature_file =====
+ <HTML>
+ <HEAD>
+! <TITLE>OPTION: Signature-File</TITLE>
+ </HEAD>
+ <BODY>
+! <H1>OPTION: Signature-File</H1>
+
+! If a <A HREF="h_config_literal_sig">Literal-Signature</A> option is defined,
+! then this &quot;Signature-File&quot; option will be ignored.
+! You can tell that that is the case because the value of the
+! &quot;Signature-File&quot; will show up as
+ <P>
+! <CENTER><SAMP>&lt;Ignored: using Literal-Signature instead&gt;</SAMP></CENTER>
+ <P>
+ You may either use all Literal Signatures (signatures stored in your
+ configuration file) throughout Pine, or all signature files.
+--- 20367,20523 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
+! ====== h_config_maildir_location ======
+ <HTML>
+ <HEAD>
+! <TITLE>OPTION: maildir-location</TITLE>
+ </HEAD>
+ <BODY>
+! <H1>OPTION: maildir-location</H1>
+
+ <P>
++ This option should be used only if you have a Maildir folder which you
++ want to use as your INBOX. If this is not your case (or don't know what
++ this is), you can safely ignore this option.
+
+ <P>
++ This option overrides the default directory Pine uses to find the location of
++ your INBOX, in case this is in Maildir format. The default value of this
++ option is "Maildir", but in some systems, this directory could have been
++ renamed (e.g. to ".maildir"). If this is your case use this option to change
++ the default.
+
+ <P>
+! The value of this option is prefixed with the "~/" string to determine the
+! full path to your INBOX.
+
+ <P>
+! You should probably <A HREF="h_config_maildir">read</A> a few tips that
+! teach you how to configure your maildir for optimal performance. This
+! version also has <A HREF="h_config_courier_list">support</A> for the
+! Courier style file system when a maildir collection is accessed locally.
+!
+! <P><UL>
+ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+! </UL>
+! <P>
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
+! ====== h_config_maildir =====
+ <HTML>
+ <HEAD>
+! <TITLE>Maildir Support</TITLE>
+ </HEAD>
+ <BODY>
+! <H1>Maildir Support</H1>
+
+! This version of Pine has been enhanced with Maildir support. This text is
+! intended to be a reference on its support.
+ <P>
+!
+! A Maildir folder is a directory that contains three directories called
+! cur, tmp and new. A program that delivers mail (e.g. postfix) will put new
+! mail in the new directory. A program that reads mail will look for for old
+! messages in the cur directory, while it will look for new mail in the new
+! directory.
+! <P>
+!
+! In order to use maildir support it is better to set your inbox-path to the
+! value &quot;#md/inbox&quot; (without quotes). This assumes that your mail
+! delivery agent is delivering new mail to ~/Maildir/new. If the directory
+! where new mail is being delivered is not called "Maildir", you can set the
+! name of the subdirectory of home where it is being delivered in the <A
+! HREF="h_config_maildir_location">maildir-location</A> configuration
+! variable. Most of the time you will not have to worry about the
+! maildir-location variable, because it will probably be set by your
+! administrator in the pine.conf configuration file.
+! <P>
+!
+! One of the advantages of the Maildir support of this version of Pine is
+! that you do not have to stop using folders in another styles (mbox, mbx,
+! etc.). This is desirable since the usage of a specific mail storage system
+! is a personal decision. Folders in the maildir format that are part of the
+! Mail collection will be recognized without any extra configuration of your
+! part. If your mail/ collection is located under the mail/ directory, then
+! creating a new maildir folder in this collection is done by pressing "A"
+! and entering the string "#driver.md/mail/newfolder". Observe that adding a
+! new folder as "newfolder" may not create such folder in maildir format.
+!
+! <P>
+! If you would like to have all folders created in the maildir format by
+! default, you do so by adding a Maildir Collection. In order to convert
+! your current mail/ collection into a maildir collection, edit the
+! collection and change the path variable from &quot;mail/&quot; to
+! &quot;#md/mail&quot;. In a maildir collection folders of any other format
+! are ignored.
+!
+! <P> Finally, This version also has
+! <A HREF="h_config_courier_list">support</A> for the Courier style file system
+! when a maildir collection is accessed locally.
+!
+! <P>
+! <UL>
+! <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+! </UL><P>
+! &lt;End of help on this topic&gt;
+! </BODY>
+! </HTML>
+! ====== h_config_literal_sig =====
+! <HTML>
+! <HEAD>
+! <TITLE>OPTION: Literal-Signature</TITLE>
+! </HEAD>
+! <BODY>
+! <H1>OPTION: Literal-Signature</H1>
+!
+! With this option your actual signature, as opposed to
+! the name of a file containing your signature,
+! is stored in the Pine configuration file.
+! If this is defined it takes precedence over the Signature-File option.
+! <P>
+!
+! This is simply a different way to store the signature.
+! The signature is stored inside your Pine configuration file instead of in
+! a separate file.
+! Tokens work the same way they do with the
+! <A HREF="h_config_signature_file">Signature-File</A> so look there for
+! help.
+! <P>
+!
+! The Setup/Signature command on Pine's Main Menu will edit
+! the &quot;Literal-Signature&quot; by default. However, if no
+! &quot;Literal-Signature&quot; is defined and the file named in the
+! &quot;Signature-File&quot; option exists, then the latter will be used
+! instead.
+! <P>
+!
+! The two character sequence &#92;n (backslash followed by
+! the character n) will be used to signify a line-break in your signature.
+! You don't have to enter the &#92;n, but it will be visible in the
+! SETUP CONFIGURATION window after you are done editing the signature.
+!
+! <P>
+! <UL>
+! <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+! </UL><P>
+! &lt;End of help on this topic&gt;
+! </BODY>
+! </HTML>
+! ====== h_config_signature_file =====
+! <HTML>
+! <HEAD>
+! <TITLE>OPTION: Signature-File</TITLE>
+! </HEAD>
+! <BODY>
+! <H1>OPTION: Signature-File</H1>
+!
+! If a <A HREF="h_config_literal_sig">Literal-Signature</A> option is defined,
+! then this &quot;Signature-File&quot; option will be ignored.
+! You can tell that that is the case because the value of the
+! &quot;Signature-File&quot; will show up as
+! <P>
+! <CENTER><SAMP>&lt;Ignored: using Literal-Signature instead&gt;</SAMP></CENTER>
+ <P>
+ You may either use all Literal Signatures (signatures stored in your
+ configuration file) throughout Pine, or all signature files.
+***************
+*** 20750,20755 ****
+--- 21225,21265 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_thread_sort_key =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: Thread-Sort-Key</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: Thread-Sort-Key</H1>
++
++ This option determines the order in which threads will be displayed. You
++ can choose from the following options.
++
++ <P>
++ <UL>
++ <LI> <A HREF="h_thread_index_sort_arrival">Arrival</A>
++ <!-- <LI> <A HREF="h_thread_index_sort_date">Date</A>
++ <LI> <A HREF="h_thread_index_sort_subj">Subject</A>
++ <LI> <A HREF="h_thread_index_sort_ordsubj">OrderedSubj</A>-->
++ <LI> <A HREF="h_thread_index_sort_thread">Thread</A>
++ <!-- <LI> <A HREF="h_thread_index_sort_from">From</A>
++ <LI> <A HREF="h_thread_index_sort_size">Size</A>
++ <LI> <A HREF="h_thread_index_sort_score">Score</A>
++ <LI> <A HREF="h_thread_index_sort_to">To</A>
++ <LI> <A HREF="h_thread_index_sort_cc">Cc</A>-->
++ </UL>
++
++ <P> Each type of sort may also be reversed. Normal default is by
++ &quot;Thread&quot;.
++
++ <P>
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_other_startup =====
+ <HTML>
+ <HEAD>
+***************
+*** 20866,20898 ****
+ This option controls the order in which address book entries will be
+ presented. Choose one of the following:
+
+! <DL>
+! <DT>fullname</DT>
+! <DD>use fullname field, lists mixed in
+! </DD>
+
+! <DT>fullname-with-lists-last</DT>
+! <DD>use fullname field, but put lists at end
+! </DD>
+
+! <DT>nickname</DT>
+! <DD>use nickname field, lists mixed in
+! </DD>
+
+! <DT>nickname-with-lists-last</DT>
+! <DD>use nickname field, but put lists at end
+! </DD>
+
+! <DT>dont-sort</DT>
+! <DD>don't change order of file
+! </DD>
+! </DL>
+
+ <P>
+! The normal default is &quot;fullname-with-lists-last&quot;.
+
+ <P>
+! <UL>
+ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+ </UL><P>
+ &lt;End of help on this topic&gt;
+--- 21376,22052 ----
+ This option controls the order in which address book entries will be
+ presented. Choose one of the following:
+
+! <DL>
+! <DT>fullname</DT>
+! <DD>use fullname field, lists mixed in
+! </DD>
+!
+! <DT>fullname-with-lists-last</DT>
+! <DD>use fullname field, but put lists at end
+! </DD>
+!
+! <DT>nickname</DT>
+! <DD>use nickname field, lists mixed in
+! </DD>
+!
+! <DT>nickname-with-lists-last</DT>
+! <DD>use nickname field, but put lists at end
+! </DD>
+!
+! <DT>dont-sort</DT>
+! <DD>don't change order of file
+! </DD>
+! </DL>
+!
+! <P>
+! The normal default is &quot;fullname-with-lists-last&quot;.
+!
+! <P>
+! <UL>
+! <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+! </UL><P>
+! &lt;End of help on this topic&gt;
+! </BODY>
+! </HTML>
+! ====== h_config_compose_rules =====
+! <HTML>
+! <HEAD>
+! <TITLE>OPTION: Compose-Rule</TITLE>
+! </HEAD>
+! <BODY>
+! <H1>OPTION: Compose-Rule</H1>
+!
+! <P> At this time, this option is used to generate values for signature
+! files that is not possible to do with the use of
+! <A HREF="h_rules_roles">roles</A>.
+!
+! <P> For example, you can have a rule like:<BR>
+! _TO_ >> {Peter Flinstones} => _SIGNATURE_{~/.petersignature}
+!
+! <P> This configuration option is just one of many that allow you to
+! override the value of some global configurations within Pine. There is a
+! help text explaining how to define all of them, which you can read by
+! following this <A HREF="h_config_new_rules">link</A>.
+!
+! <P>&lt;End of help on this topic&gt;
+! </BODY>
+! </HTML>
+! ====== h_config_forward_rules =====
+! <HTML>
+! <HEAD>
+! <TITLE>OPTION: Forward-Rule</TITLE>
+! </HEAD>
+! <BODY>
+! <H1>OPTION: Forward-Rule</H1>
+!
+! <P> At this time this option can be used to trim values of some fields,
+! for example it can be used in the following way:
+!
+! <P>
+! _ROLE_ == {work} => _LCC_ := _TRIM_{_FORWARDFROM_ <_FORWARDADDRESS_>}
+!
+! <P> This configuration option is just one of many that allow you to
+! override the value of some global configurations within Pine. There is a
+! help text explaining how to define all of them, which you can read by
+! following this <A HREF="h_config_new_rules">link</A>.
+!
+! <P>&lt;End of help on this topic&gt;
+! </BODY>
+! </HTML>
+! ====== h_config_index_rules =====
+! <HTML>
+! <HEAD>
+! <TITLE>OPTION: Index-Rule</TITLE>
+! </HEAD>
+! <BODY>
+! <H1>OPTION: Index-Rule</H1>
+!
+! <P> This option is used to supercede the value of the option <A
+! HREF="h_config_index_format">index-format</A> for specific folders. In
+! this form you can have different index-formats for different folders. For
+! example an entry here may be:
+!
+! <P>
+! _FOLDER_ == {INBOX} => _INDEX_{IMAPSTATUS DATE FROM(33%) SIZE SUBJECT(67%)}
+!
+! <P> This configuration option is just one of many that allow you to
+! override the value of some global configurations within Pine. There is a
+! help text explaining how to define all of them, which you can read by
+! following this <A HREF="h_config_new_rules">link</A>.
+!
+! <P>&lt;End of help on this topic&gt;
+! </BODY>
+! </HTML>
+! ====== h_config_replace_rules =====
+! <HTML>
+! <HEAD>
+! <TITLE>OPTION: Replace-Rule</TITLE>
+! </HEAD>
+! <BODY>
+! <H1>OPTION: Replace-Rule</H1>
+!
+! <P> This option is used to have Pine print different values for specific
+! tokens in the <A HREF="h_config_index_format">index-format</A>. For example you
+! can replace strings like "To: newsgroup" by your name.
+!
+! <P> Here are examples of possible rules:<BR>
+! _FOLDER_ != {sent-mail} && _NICK_ != {} => _FROM_ := _REPLACE_{_FROM_ (_NICK_)}
+!
+! <P> or if you receive messages with tags that contain arbitrary numbers, and
+! you want them removed from the index (but not from the subject), use a rule
+! like the following<BR>
+! _FOLDER_ == {INBOX} => _SUBJECT_ := _REXTRIM_{&#92;[some-tag-here #[0-9].*&#92;]}
+!
+! <P> You can also use this configuration option to remove specific strings of
+! the index display screen, so that you can trim unnecessary information in
+! your index.
+!
+! <P> This configuration option is just one of many that allow you to
+! override the value of some global configurations within Pine. There is a
+! help text explaining how to define all of them, which you can read by
+! following this <A HREF="h_config_new_rules">link</A>.
+!
+! <P>&lt;End of help on this topic&gt;
+! </BODY>
+! </HTML>
+! ====== h_config_reply_leadin_rules =====
+! <HTML>
+! <HEAD>
+! <TITLE>OPTION: Reply-Leadin-Rule</TITLE>
+! </HEAD>
+! <BODY>
+! <H1>OPTION: Reply-Leadin-Rule</H1>
+!
+! <P> This option is used to have Pine generate a different
+! <A HREF="h_config_reply_intro">reply-leadin</A> string dependent either on
+! the person you are replying to, or the folder where the message is being
+! replied is in, or both.
+!
+! <P> Here there are examples of how this can be used. One can use the definition
+! below to post to newsgroups and the pine-info mailing list, say:
+! <P>
+! _FOLDER_ << {pine-info;_NEWS_} => _REPLY_{*** _FROM_ _ADDRESS_("_FROM_" "" "(_ADDRESS_) ")wrote in_NEWS_("" " the" "") _FOLDER_ _NEWS_("" "list " "")_SMARTDATE_("Today" "today" "on _LONGDATE_"):}
+!
+! <P> Here there is an example that one can use to change the reply indent string
+! to reply people that speak spanish.
+! <P>
+! _FROM_{Condorito;Quico} => _REPLY_{*** _FROM_ (_ADDRESS_) escribi&oacute; _SMARTDATE_("Today" "hoy" "en _LONGDATE_"):}
+!
+! <P> This configuration option is just one of many that allow you to
+! override the value of some global configurations within Pine. There is a
+! help text explaining how to define all of them, which you can read by
+! following this <A HREF="h_config_new_rules">link</A>.
+!
+! <P>&lt;End of help on this topic&gt;
+! </BODY>
+! </HTML>
+! ====== h_config_resub_rules =====
+! <HTML>
+! <HEAD>
+! <TITLE>OPTION: Replace-Subject-Rule</TITLE>
+! </HEAD>
+! <BODY>
+! <H1>OPTION: Replace-Subject-Rule</H1>
+!
+! <P> This option is used to have Pine generate a different subject when
+! replying rather than the one Pine would generate automatically.
+!
+! <P> Here there are a couple of examples about how to use this
+! configuration option:
+!
+! <P> In order to have messages with empty subject to be replied with the message
+! "your message" use the rule<BR>
+! <center>_SUBJECT_ == {} => _RESUB_{Re: your message}</center>
+!
+! <P> If you want to trim some parts of the subject when you reply use the
+! rule<BR>
+! <center>_SUBJECT_ >> {[one];two} => _SUBJECT_ := _TRIM_{[;];two}</center>
+!
+! <P>this rule removes the brackets "[" and "]" whenever the string "[one]"
+! appears in it, it also removes the word "two" from it.
+!
+! <P>Another example where you may want to use this rule is when you
+! correspond with people that change the reply string from &quot;Re:&quot;
+! to &quot;AW:&quot; or &quot;Sv:&quot;. In this case a rule like<BR>
+! <center>_SUBJECT_ >> {Sv: ;AW: } => _SUBJECT_ := _TRIM_{Sv: ;AW: }</center>
+! <P>
+! would eliminate undesired strings in replies.
+!
+! <P> You can also use this configuration option to customize reply subjects
+! according to the sender of the message.
+!
+! <P> This configuration option is just one of many that allow you to
+! override the value of some global configurations within Pine. There is a
+! help text explaining how to define all of them, which you can read by
+! following this <A HREF="h_config_new_rules">link</A>.
+!
+! <P>&lt;End of help on this topic&gt;
+! </BODY>
+! </HTML>
+! ====== h_config_sort_rules =====
+! <HTML>
+! <HEAD>
+! <TITLE>OPTION: Sort-Rule</TITLE>
+! </HEAD>
+! <BODY>
+! <H1>OPTION: Sort-Rule</H1>
+!
+! <P> This option is used to have Pine sort different folders in different orders
+! and thus override the value already set in the
+! <A HREF="h_config_sort_key">sort-key</A> configuration option.
+!
+! <P> Here's an example of the way it can be used. In this case all incoming
+! folders are mailing lists, except for INBOX, so we sort INBOX by arrival
+! (which is the default type of sort), but we want all the rest of mailing
+! lists and newsgroups to be sorted by thread.
+!
+! <P>
+! _COLLECTION_ >> {Incoming-Folders;News} && _FOLDER_ != {INBOX} => _SORT_{tHread}
+!
+! <P> Another example could be<BR>
+! _FOLDER_ == {Mailing List} => _SORT_{Reverse tHread}
+!
+! <P> This configuration option is just one of many that allow you to
+! override the value of some global configurations within Pine. There is a
+! help text explaining how to define all of them, which you can read by
+! following this <A HREF="h_config_new_rules">link</A>.
+!
+! <P>&lt;End of help on this topic&gt;
+!
+! </BODY>
+! </HTML>
+! ====== h_config_save_rules =====
+! <HTML>
+! <HEAD>
+! <TITLE>OPTION: Save-Rules</TITLE>
+! </HEAD>
+! <BODY>
+! <H1>OPTION: Save-Rules</H1>
+!
+! <P> This option is used to specify which folder should be used to save a
+! message depending either on the folder the message is in, who the message
+! is from, or text that the message contains in specific headers (Cc:,
+! Subject:, etc).
+!
+! <P> If this option is set and the
+! <A HREF="h_config_auto_read_msgs">auto-move-read-msgs</A> configuration
+! option is also set then these definitions will be used to move messages
+! from your INBOX when exiting Pine.
+!
+! <P>Here there are some examples<BR>
+! _FLAG_ >> {D} -> Trash<BR>
+! _FROM_ == {U2} -> Bono<BR>
+! _FOLDER_ == {comp.mail.pine} -> pine-stuff<BR>
+! _NICK_ != {} -> _NICK_/_NICK_<BR>
+! _DATEISO_ >> {02-10;02-11} -> archive-oct-nov-2002
+!
+! <P> This configuration option is just one of many that allow you to
+! override the value of some global configurations within Pine. There is a
+! help text explaining how to define all of them, which you can read by
+! following this <A HREF="h_config_new_rules">link</A>.
+!
+! <P>&lt;End of help on this topic&gt;
+!
+! </BODY>
+! </HTML>
+! ====== h_config_reply_indent_rules =====
+! <HTML>
+! <HEAD>
+! <TITLE>OPTION: Reply-indent-Rule</TITLE>
+! </HEAD>
+! <BODY>
+! <H1>OPTION: Reply-indent-Rule</H1>
+!
+! <P> This option is used to specify which reply-indent-string is to be used
+! when replying to an e-mail. If none of the rules are successful, the result in
+! the variable <a href="h_config_reply_indent_string">reply-indent-string</a>
+! is used.
+!
+! <P> The associated function to this configuration option is called "RESTR" (for
+! REply STRing). Some examples of its use are:<BR>
+! _FROM_ == {Your Boss} => _RESTR_{"> "}<BR>
+! _FROM_ == {My Wife} => _RESTR_{":* "}<BR>
+! _FROM_ == {Perter Flinstone;Wilma Flinstone} => _RESTR_{"_INIT_ > "}<BR>
+!
+! <P> This configuration option is just one of many that allow you to
+! override the value of some global configurations within Pine. There is a
+! help text explaining how to define all of them, which you can read by
+! following this <A HREF="h_config_new_rules">link</A>.
+!
+! <P>&lt;End of help on this topic&gt;
+!
+! </BODY>
+! </HTML>
+! ====== h_config_smtp_rules =====
+! <HTML>
+! <HEAD>
+! <TITLE>OPTION: SMTP-Rule</TITLE>
+! </HEAD>
+! <BODY>
+! <H1>OPTION: SMTP-Rule</H1>
+!
+! <P> This option is used to specify which SMTP server should be used when
+! sending a message, if this rule is not defined, or the execution of the rule
+! results in no server selected, then Pine 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 Pine will get
+! the name of the server from the
+! <A HREF="h_config_smtp_server">&quot;smtp-server&quot;</A> configuration
+! option according to the rules used in that variable.
+!
+! <P> The function associated to this configuration option is _SMTP_, an example
+! of the use of this function is<BR>
+! _ADDRESSTO_ == {peter@bedrock.com} => _SMTP_{smtp.bedrock.com}
+!
+! <P> This configuration option is just one of many that allow you to
+! override the value of some global configurations within Pine. There is a
+! help text explaining how to define all of them, which you can read by
+! following this <A HREF="h_config_new_rules">link</A>.
+!
+! <P>&lt;End of help on this topic&gt;
+!
+! </BODY>
+! </HTML>
+! ====== h_config_startup_rules =====
+! <HTML>
+! <HEAD>
+! <TITLE>OPTION: Startup-Rule</TITLE>
+! </HEAD>
+! <BODY>
+! <H1>OPTION: Startup-Rule</H1>
+!
+! <P> This option is used when a folder is being opened. You can use it to
+! specify its <A HREF="h_config_inc_startup">incoming-startup-rule</A> and override
+! Pine's global value set for all folders.
+!
+! <P> An example of the usage of this option is:<BR>
+! _FOLDER_ == {Lynx;pine-info;_NEWS_} => _STARTUP_{first-unseen}
+!
+! <P> This configuration option is just one of many that allow you to
+! override the value of some global configurations within Pine. There is a
+! help text explaining how to define all of them, which you can read by
+! following this <A HREF="h_config_new_rules">link</A>.
+!
+! <P>&lt;End of help on this topic&gt;
+!
+! </BODY>
+! </HTML>
+! ====== h_config_new_rules =====
+! <HTML>
+! <HEAD>
+! <TITLE>OPTION: New Rules Explained</TITLE>
+! </HEAD>
+! <BODY>
+! <H1>OPTION: New Rules Explained</H1>
+!
+! This is a quite powerful option. Here you can define rules that override
+! the values of any other global rule you have globally set in pine.
+!
+! <P>
+! For example, you can set your folders to be sorted in a certain way when
+! you open them (say by Arrival). You may not want to be this the behavior
+! of, say, a Newsgroup, maybe you would like there to have your folder to be
+! automatically ordered by Ordered Subject. The purpose of this feature is
+! to accomplish exactly that. You can use this option for defining such
+! exception and make Pine automatically sort your favorite Newsgroup by
+! Ordered Subject.
+!
+! <P>
+! On the other hand you may be suscribed to a mailing list, and maybe you
+! don't care to see in the index the size of the messages, however in other
+! lists you may want to see the size of the messages. You can use this
+! configuration for changing the way the index is displayed in a folder.
+!
+! <P>
+! Also there may be a mailing list that identifies itself by adding a
+! certain string to its subject which makes difficult to read the total
+! subject, so you may want to delete that string from the subject whenever
+! it appears. You can do that also with this configuration.
+!
+! <P>
+! You may also want to make your reply-leadin-string person or folder
+! dependent. You can do this with this feature (part of this feature can be
+! accomplised with the roles definitions, but roles are not the right tool
+! to do this as you will see).
+!
+! <P>
+! Every rule has three parts, a condition, a separator and an action. The
+! action is what will happen if the condition of the rule is satisified.
+!
+! <P>
+! Here is an example:
+!
+! <P>
+! _FROM_ == {Fred Flinstone} =&gt; _SAVE_{Fred}
+!
+! <P>
+! Here the separator is "=&gt;". Whatever is to the left of the separator
+! is the condition (that is to say _FROM_ == {Fred Flinstone}) and to the
+! right is the action (_SAVE_{Fred}). The condition means that the rule will
+! be applied only if the message that you are reading is from "Fred
+! Flinstone", 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.
+!
+! <P>
+! The separator is always "=&gt;", with one exception to be seen later.
+! But for the most part this will be the only one you'll ever need.
+!
+! <P>
+! Now let us see how to do it. There are 12 functions already defined for
+! you. These are: _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.
+!
+! <P>
+! At the end of the document you will find more examples.Here is a short
+! description of what each function does:
+!
+! <P>
+! <UL>
+! <LI> _INDEX_ : This function takes as an argument an index-format, and
+! makes that the index-format for the specified folder.
+! <LI> _REPLACE_ : This function replaces the subject/from of the given e-mail by
+! another subject/from only when displaying the index.
+! <LI> _REPLY_ : This function takes as an argument a definition of a
+! reply-leadin-string and makes this the reply-leading-string of the
+! specified folder or person.
+! <LI> _RESTR_ : This function takes as an argument the value of the
+! reply-indent-string to be used to answer the message being replied to.
+! <LI> _RESUB_ : This function replaces the subject of the given e-mail by
+! another subject only when replying to a message.
+! <LI> _SAVE_ : The save function takes as an argument the name of a
+! possibly non existing folder, whenever you want to save a message, that
+! folder will be offered for you to save.
+! <LI> _SIGNATURE_ : This function takes as an argument a signature file and
+! uses that file as the signature for the message you are about to
+! compose/reply/forward.
+! <LI> _SMTP_ : This function takes as an argument the definition of a
+! SMTP server.
+! <LI> _SORT_ : This function takes as an argument a Sort Style, and sorts a
+! specified folder in that sort order.
+! <LI> _TRIM_ : This function takes as an argument a list of strings that
+! you want removed from another string. At this time this only works for
+! _FROM_ and _SUBJECT_.
+! <LI> _REXTRIM_ : Same as _TRIM_ but its argument is one and
+! only one extended regular expression.
+! <LI> _STARTUP_ : This function takes as an argument an
+! incoming-startup-rule, and open an specified folder using that rule.
+! <LI> _THREADSTYLE_ : This function takes as an argument a
+! threading-display-style and uses it to display threads in a folder.
+! <LI> _THREADINDEX_ : This function takes as an argument a
+! threading-index-style and uses it to display threads in a folder.
+! </UL>
+!
+! <P>
+! You must me wondering how to define the person/folder over who to apply
+! the action. This is done in the condition. When you specify a rule, the
+! rule is only executed if the condition is satisfied. In another words for
+! the rule:
+!
+! <P>
+! _FROM_ == {Fred Flinstone} =&gt; _SAVE_{Fred}
+!
+! <P>
+! it will only be applied if the from is "Fred Flinstone", if the From is
+! "Wilma Flinstone" the rule will be skipped.
+!
+! <P> In order to test a condition you can use the following tokens (in
+! alphabetical order): _ADDRESS_,_CC_, _FOLDER_, _FROM_,_NICK_, _ROLE,
+! _SENDER_, _SUBJECT_ and _TO_. The token will always be tested against what
+! it is between "{" and "}" in the condition, this part of the condition is
+! called the "condition set". The definition of each token can be found
+! <A HREF="h_index_tokens">here</A>.
+!
+! <P>
+! You can also test in different ways, you can
+! use the following "test operands": &lt;&lt;, !&lt;, &gt;&gt;, !&gt;, ==
+! and !=. All of them are two strings long. Here is the meaning of them:
+!
+! <P>
+! <UL>
+! <LI> &lt;&lt; : It tests if the value of the token is contained in
+! the condition set. Here for example if the condition set were equal to
+! "Freddy", then the condition: _NICK_ &lt;&lt; {Freddy}, would be true if
+! the value of _NICK_ were "Fred", "red" or "Freddy". You are just looking
+! for substrings here.
+! <LI> &gt;&gt; : It tests if the value of the token contains the value of
+! the condition set. Here for example if the condittion set were equal to
+! "Fred", then the condition: _FROM_ &gt;&gt; {Fred}, would be true if
+! the value of _FROM_ were "Fred Flinstone" or "Fred P. Flinstone" or "Freddy".
+! <LI> == : It tests if the value of the token is exactly equal to the value
+! of the set condition. For example _NICK_ == {Fred} will be false if the value
+! of _NICK_ is "Freddy" or "red".
+! <LI> !&lt; : This is true only when &lt;&lt; is false and viceversa.
+! <LI> !&gt; : This is true only when &gt;&gt; is false and viceversa.
+! <LI> != : This is true only when == is false and viceversa.
+! </UL>
+!
+! <P>
+! Now let us say that you want the same action to be applied to more than
+! one person or folder, say you want "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.
+!
+! <P>
+! _FOLDER_ &lt;&lt; {folder1; folder2} =&gt; _SORT_{OrderedSubj}
+!
+! <P>
+! Here is the first subtelty about these definitions. Notice that the
+! following rule:
+!
+! <P>
+! _FOLDER_ == {folder1; folder2} =&gt; _SORT_{Reverse OrderedSubj}
+!
+! <P> works only for "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 <BR>
+! "folder2" == " folder2". The extra space makes the difference.
+! The reason why the first rule does not fail is because
+! "folder2" &lt;&lt; " folder2" is actually
+! true. If something ever fails this may be something to look into.
+!
+! <P>
+! Here are a few examples of what we have talked about before.
+!
+! <P>
+! _NICK_ == {lisa;kika} =&gt; _SAVE_{_NICK_/_NICK_} <BR>
+! This means that if the nick is lisa, it will
+! save the message in the folder "lisa/lisa", and if the nick
+! is "kika", it will save the message in the folder "kika/kika"
+!
+! <P>
+! _FOLDER_ == {Lynx} -&gt; lynx <BR>
+! This, is an abreviation of the following rule:<BR>
+! _FOLDER_ == {Lynx} =&gt; _SAVE_{lynx} <BR>
+! (note the change in separator from "=&gt;" to "-&gt;"). In the future
+! I will use that abreviation.
+!
+! <P> _FOLDER_ &lt;&lt; {comp.mail.pine; pine-info; pine-alpha} -&gt; pine <BR>
+! Any message in the folders "comp.mail.pine", "pine-info" or "pine-alpha"
+! will be saved to the folder "pine".
+!
+! <P> _FROM_ &lt;&lt; {Pine Master} -&gt; pine <BR>
+! Any message whose From field contains
+! "Pine Master" will be saved in the folder pine.
+!
+! <P> _FOLDER_ &lt;&lt; {Lynx; pine-info; comp.mail.pine} =&gt;
+! _INDEX_{IMAPSTATUS MSGNO DATE FROMORTO(33%) SUBJECT(66%)} <BR> Use a
+! different index-format for the folders "Lynx", "pine-info" and
+! "comp.mail.pine", where the size is not present.
+!
+! <P> _FOLDER_ == {Lynx;pine-info} =&gt; _REPLY_{*** _FROM_ (_ADDRESS_)
+! wrote in the _FOLDER_ list _SMARTDATE_("Today" "today" "on
+! _LONGDATE_"):}<BR> 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:
+!
+! <P>
+! *** Steve Hubert (hubert@cac.washington.edu) wrote in the pine-info list today:
+!
+! <P>
+! However replying for a message in the Lynx list would look:
+!
+! <P>
+! *** mattack@area.com (mattack@area.com) wrote in the Lynx list today:
+!
+! <P>
+! If you write in more than one language you can use this feature to create
+! Reply-leadin-strings in different languages.
+!
+! <P> Note that at least for people you can create particular
+! reply-leadin-string using the role features, but it does not work as this
+! one does. This seems to be the right way to do it.
+!
+! <P> _FOLDER_ &lt;&lt; {Lynx; comp.mail.pine; pine_info; pine-alpha} =&gt;
+! _SORT_{OrderedSubj}<BR> This means upon opening, sort the folders "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).
+!
+! <P> The last examples use the function _TRIM_ which has a special form.
+! This function can only be used in the index list.
+!
+! <P> _FOLDER_ &lt;&lt; {Lynx} =&gt; _SUBJECT_ := _TRIM_{lynx-dev }<BR> In
+! the folder "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.
+!
+! <P> _FROM_ &gt;&gt; {Name (Comment)} =&gt; _FROM_ :=
+! _TRIM_{ (Comment)}<BR> Remove the part " (Comment)"
+! from the _FROM_, so when displaying in the index the real From "Name"
+! will appear.
+!
+! <P> _SUBJECT_ == {} =&gt; _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.
+!
+! <P> You can add more complexity to your rules by checking more than one
+! conditions before a rule is executed. For example: Assume that you want to
+! answer every email that contains the string "bug report", with the subject
+! "Re: About your bug report", you could make
+!
+! <P>
+! _SUBJECT_ == {bug report} =&gt; _RESUB_{Re: About your _SUBJECT_}
+!
+! <P> The problem with this construction is that if the person emails you
+! back, then the next time you answer the message the subject will be: "Re:
+! About your Re: About your bug report", so it grew. You may want to avoid
+! this growth by using the following rule:
+!
+! <P>
+! _SUBJECT_ &gt;&gt; {bug report} && _SUBJECT_ !&gt; {Re: } =&gt; _RESUB_{Re: About your _SUBJECT_}<BR>
+
+! <P>
+! which will only add the string "Re: About your" only the first time the
+! message is replied.
+
+! <P>
+! Say your personal name is "Fred Flinstones", and assume that you don't
+! like to see "To: comp.mail.pine" in every post you make to this newsgroup,
+! but instead would like to see it as everyone else sees it. <BR>
+! _FOLDER_ == {comp.mail.pine} && _FROM_ == {Fred Flinstones} => _FROM_ := _REPLACE_{_FROM_}
+
+! <P>
+! You can also list your index by nick, in the following way:<BR>
+! _NICK_ != {} => _FROM_ := _REPLACE_{_NICK_}
+
+! <P>
+! If you want to open the folder "pine-info" in the first non-read message
+! use the rule:<BR>
+! _FOLDER_ == {pine-info} => _STARTUP_{first-unseen}
+
+ <P>
+! If you want to move your deleted messages to a folder, called "Trash", use
+! the following rule:<BR>
+! _FLAG_ >> {D} -> Trash
+
+ <P>
+! 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.
+!
+! <P> If you want to use a specific signature when you are in a specific collection
+! use the following rule:<BR>
+! _COLLECTION_ == {Mail} => _SIGNATURE_{/full/path/to/.signature}
+!
+! <P> Finally about the question of which rule will be executed. Only the
+! first rule that matches will be executed. It is important to notice though
+! that "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.
+!
+! <P> Here are some things to do still:
+! <UL>
+! <LI> To make _TRIM_ compatible with more tokens (_TO_, _SENDER_, etc)
+! <LI> To make this list dissapear!
+! </UL>
+!
+! <P>
+! <UL>
+ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+ </UL><P>
+ &lt;End of help on this topic&gt;
+***************
+*** 21032,21037 ****
+--- 22186,22227 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_special_text_to_color =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: Special Text to Color</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: Specil Text to Color</H1>
++
++ Use this option to enter patterns (text or regular expressions) that Pine
++ will highlight in the body of the text that is not part of a handle (and
++ internal or external link that Pine paints in a different color).
++
++ <P>
++ Enter each pattern in a different line. Pine will internally merge these
++ patterns (by adding a "|" character), or you can add them all in one line
++ by separating them by a "|" character.
++
++ <P>
++ Pine will use the colors defined in the
++ <A HREF="h_config_special_text_color"> Special Text Color</A> variable.
++ to paint any match.
++
++ <P>
++ If the Special Text Color is not set, setting this variable will not
++ cause that special text to be indicated in any special way. It will look
++ like any normal text. You must set those colors in order to make Pine
++ paint the screen differently when it finds the patterns specified in this
++ variable.
++
++ <P>
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_display_filters =====
+ <HTML>
+ <HEAD>
+***************
+*** 21850,21855 ****
+--- 23040,23077 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_inc_fld_timeo =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: inc-fld-timeout</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: inc-fld-timeout</H1>
++
++ When Pine is checking for new mail in an external incoming folder, and the
++ amount of time specified in this variable has elapsed without Pine being
++ able to connect to the server holding that mailbox, Pine will drop the
++ connection to that server and continue checking for new mail in other
++ incoming folders, if any.
++
++ <P>
++ Observe that Pine will not print an error message in this case, but it
++ will silently drop the connection. If your connections are fast setting
++ this to a large value will not cause you any problem, but if your
++ connections are slow setting this to a small value will make Pine speed
++ checking for new mail, although it is possible that not all of your
++ incoming folders will be checked for new mail.
++
++ <P>
++ The default is 5 seconds, which is also the minimum and the maximum is 60.
++
++ <P>
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_incoming_folders =====
+ <HTML>
+ <HEAD>
+***************
+*** 24123,24128 ****
+--- 25345,25420 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_thread_display_style_rule =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: Threading-Display-Style-Rule</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: Threading-Display-Style-Rule</H1>
++
++ This option is very similar to <A HREF="h_config_thread_disp_style">
++ threading-display-style</A>, but it is a rule which specifies the
++ display styles for a thread that you want displayed in a specific
++ folder or collection.
++ <P>
++ The token to be used in this function is _THREADSTYLE_. Here there is
++ an example of its use
++ <P>
++ _FOLDER_ == {pine-info} => _THREADSTYLE_{mutt-like}
++ <P>
++ The values that can be given for the _THREADSTYLE_ function are the
++ values of the threading-display-style function, which can be found
++ listed in the <A HREF="h_config_thread_disp_style">threading-display-style</A>
++ configuration option.
++
++ <P> This configuration option is just one of many that allow you to
++ override the value of some global configurations within Pine. There is a
++ help text explaining how to define all of them, which you can read by
++ following this <A HREF="h_config_new_rules">link</A>.
++
++ <P>
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
++ ====== h_config_thread_index_style_rule =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: Threading-Index-Style-Rule</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: Threading-Index-Style-Rule</H1>
++
++ This option is very similar to <A HREF="h_config_thread_index_style">
++ threading-index-style</A>, but it is a rule which specifies the
++ index styles for a thread that you want displayed in a specific
++ folder or collection.
++ <P>
++ The token to be used in this function is _THREADINDEX_. Here there is
++ an example of its use
++ <P>
++ _FOLDER_ == {pine-info} => _THREADINDEX_{regular-index-with-expanded-threads}
++ <P>
++ The values that can be given for the _THREADINDEX_ function are the
++ values of the threading-index-display function, which can be found
++ listed in the <A HREF="h_config_thread_index_style">threading-index-display</A>
++ configuration option.
++
++ <P> This configuration option is just one of many that allow you to
++ override the value of some global configurations within Pine. There is a
++ help text explaining how to define all of them, which you can read by
++ following this <A HREF="h_config_new_rules">link</A>.
++
++ <P>
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_pruning_rule =====
+ <HTML>
+ <HEAD>
+***************
+*** 24416,24421 ****
+--- 25708,25758 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_inc_rule =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: Incoming-Check-Rule</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: Incoming-Check-Rule</H1>
++
++ This value affects Pine's behavior when starting Pine. It determines
++ how and when Pine will check for new mail in your incoming folders. The
++ default value is &quot;automatic&quot;.
++
++ <P>
++ The three possible values for this option are:
++
++ <DL>
++ <DT>automatic</DT>
++ <DD>This is the default. When this is selected the first check for new
++ mail will be done when Pine is starting up and you either go to the
++ INDEX or FOLDER LIST screens.
++ </DD>
++
++ <DT>automatic-after-first-manual-check</DT>
++ <DD>Similar to the default, but no check is done until you force the first
++ one by pressing CTRL-H. All checks are automatic after the first one. Observe
++ that this feature does not work once an automatic check has been done.
++ </DD>
++
++ <DT>manual-only</DT>
++ <DD>This forces Pine to do only manual checks. This will probably speed
++ Pine, since checks will only happen when they are forced by pressing CTRL-H.
++ </DD>
++ </DL>
++
++ <P>
++ If you just want to stop Pine from checking in one folder, then simply
++ select that folder. Checks on that folder will be skipped.
++
++ <P>
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_browser =====
+ <HTML>
+ <HEAD>
+***************
+*** 25490,25495 ****
+--- 26827,26909 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_enable_check_incoming ======
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: enable-check-incoming-folders</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: enable-check-incoming-folders</H1>
++ If you have enabled <A HREF="h_config_enable_incoming">incoming
++ folders</A> then setting this feature allows you to check for new mail in
++ these. A message stating that new mail was received and in which folders
++ will be written in the screen. You can decide which incoming folders you
++ want to check for new mail, and the list of them has to be entered in the
++ setting <A HREF="h_config_check_inc_fld">incoming-folders-to-check</A>.
++
++ <P> If you have the option
++ <A HREF="h_config_fast_recent">enable-fast-recent-test</A>
++ <B>disabled</B>, but have this feature enabled, then a full report on the
++ total number of messages, and the number of new messages in the folder is
++ printed in the <A HREF="h_folder_maint">FOLDER LIST</A> screen
++ for each folder listed in the variable
++ <A HREF="h_config_check_inc_fld">incoming-folders-to-check</A>. The report for each
++ folder is made in the format
++
++ <P>
++ folder-name [Number of new messages/Number of messages in the folder]
++
++ <P>
++ If an incoming folder is not listed in the variable
++ <A HREF="h_config_check_inc_fld">incoming-folders-to-check</A>, then only
++ the name of the folder and no other report is made about that folder.
++
++ <P>
++ Other important features related to this feature are:
++ <OL>
++ <LI><A HREF="h_config_enable_recheck_incoming">recheck-all-incoming-folders</A>,
++ which allows you to decide if you want to check all folders every check,
++ <LI><A HREF="h_config_inc_rule">incoming-check-rule</A>, which determines
++ how and when Pine will check for new mail in your incoming folders.
++ </OL>
++
++ <P>
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL>
++ </BODY>
++ </HTML>
++ ====== h_config_enable_recheck_incoming ======
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: recheck-all-incoming-folders</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: recheck-all-incoming-folders</H1>
++ If you have enabled <A HREF="h_config_enable_incoming">incoming folders</A>
++ and <A HREF="h_config_enable_check_incoming">enable-check-incoming-folder</A>
++ then setting this feature will force Pine to recheck all incoming folders
++ for new mail. The normal behavior (that is to say, when this feature
++ is not enabled) is that Pine will skip checking for new mail in folders
++ where it already found. This is done to speed checking for new mail.
++
++ <P>
++ The default behavior, however, can cause problems if you use two clients
++ to access the same incoming folders, because Pine will not realize that
++ new mail does not exist in one folder where it already reported new mail,
++ but was opened with the other client. Setting this feature will cause Pine
++ to recheck all folders all the time. In this way Pine will know for sure
++ which folders DO contain new mail.
++
++ <P> If you only use Pine to access your incoming folders, then DO NOT
++ enable this feature.
++
++ <P>
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL>
++ </BODY>
++ </HTML>
+ ====== h_config_attach_in_reply ======
+ <HTML>
+ <HEAD>
+***************
+*** 25788,25793 ****
+--- 27202,27223 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_use_domain =====
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: return-path-uses-domain-name </TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: return-path-uses-domain-name</H1>
++
++ If you enable this configuration option Pine will use your domain name and your
++ username in that domain name to construct your Return-Path header, if not Pine
++ will use the address that you have set in the From: field to construct it.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_use_sender_not_x =====
+ <HTML>
+ <HEAD>
+***************
+*** 25954,25959 ****
+--- 27384,27416 ----
+ successes. You will usually receive the full message back when there is
+ a failure.
+
++ <P> When this feature is <B>disabled</B>, and the feature
++ <A HREF="h_config_enable_check_incoming">enable-check-incoming-folders</A>
++ is enabled, then a full report of the number of messages and number of
++ new messages in each incoming folder listed in the option
++ <A HREF="h_config_check_inc_fld">incoming-folders-to-check</A> is made. This
++ report is printed in the <A HREF="h_folder_maint">FOLDER LIST</A> screen. The
++ report is given in the form
++
++ <P>
++ folder-name [Number of New Messages/Number of messages in the folder]
++
++ <P> If an incoming-folder is not listed in the variable
++ <A HREF="h_config_check_inc_fld">incoming-folders-to-check</A>, no check for
++ that folder is made, so only the folder name, and no other information is
++ printed about that folder.
++
++ <P> If this feature is enabled and the feature
++ <A HREF="h_config_enable_recheck_incoming">recheck-all-incoming-folders</A>
++ is disabled, then selecting a folder will cancel further checks on that
++ folder. This is useful if checks to a particular incoming folder are slow
++ and want to be avoided (until the folder is unselected and a new cycle of
++ checks is done) without changing the list of folders to be checked.
++ Selecting a folder in order to avoid checks for new mail does not work in
++ other cases, since it is either explicitly requested this way or because
++ it is necessary to update the count of new and total number of messages of
++ every requested folder.
++
+ <P>
+ If you turn on the DSNOpts the default is to return as much information as
+ possible to you. That is, by default, the Success and Delay options are
+***************
+*** 26332,26337 ****
+--- 27789,27846 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_alt_reply_menu =====
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: alternate-reply-menu</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: alternate-reply-menu</H1>
++
++ This feature controls the menu that is displayed when Reply is selected.
++ If set, a list of options will be presented, with each option representing
++ the type of composition that could be used. This feature is most useful
++ for users who want to avoid being prompted with each option separately, or
++ would like to override some defaults set in your configuration for the
++ message that you are replying (e.g. you may have set the option to strip
++ signatures, but for the message you are answering you would like not to do
++ that)
++
++ <P>
++ The way this feature works is as follows. Initially you get the question
++ if you want to include the message, and in the menu you will see several
++ options, each option is accompanied by some text explaining what will
++ happen if you press the associated command. For example, if you read the
++ text &quot;S Strip Sig&quot;, it means that if you press the letter
++ &quot;S&quot; the signature will be stripped off the message you are
++ replying. Observer that the menu will change to
++ &quot;S No Strip&quot;, which means that if you press &quot;S&quot;, the
++ signature will not be stripped off from the message. Your choices are
++ activated when you press RETURN.
++
++ <P>
++ Another way to remember what Pine will do, is that what will be done is
++ exactly the opposite of what you read in the menu.
++
++ <P>
++ The possible options are:
++
++ <OL>
++ <LI> F: To decide if you want to send flowed text or not. This option appears
++ unless you have quelled sending flowed text.
++
++ <LI> S: To strip the signature from a message, only available is the feature
++ <a href="h_config_sigdashes">enable-sigdashes</a> or the
++ <a href="h_config_strip_sigdashes">strip-from-sigdashes-on-reply</a> option are
++ enabled.
++
++ <LI> R: To set a role, if you do not want Pine to set one automatically for you
++ or would like to set one when you can not select any.
++ </OL>
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_del_from_dot =====
+ <HTML>
+ <HEAD>
+***************
+*** 27077,27082 ****
+--- 28586,28634 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_courier_list =====
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: Courier-Folder-List</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: Courier-Folder-List</H1>
++
++ In a maildir collection, a folder could be used as a directory to store
++ folders. In the Courier server if you create a folder, then a directory
++ with the same name is created. If you use this patch to access a
++ collection created by the Courier server, then the display of such
++ collection will look confusing. The best way to access a maildir
++ collection created by the Courier server is by using the &quot;#mc/&quot;
++ prefix instead of the &quot;#md/&quot; prefix. If you use this alternate
++ prefix, then this feature applies to you, otherwise you can safely ignore
++ the text that follows.
++ <P>
++ Depending on if you have enabled the option
++ <a href="h_config_separate_yold_dir_view">separate-folder-and-firectory-entries</a>
++ a folder may be listed as &quot;folder[.]&quot;, or as two entries in the
++ list by &quot;folder&quot; and &quot;folder.&quot;.
++ <P>
++ If this option is disabled, Pine will list local folders that are in Courier
++ style format, as &quot;folder&quot;, and those that are also directories as
++ &quot;folder[.]&quot;. This makes the default display cleaner.
++ <P>
++ If this feature is enabled then creating folders in a maildir collection
++ will create a directory with the same name. If this feature is disabled, then
++ a folder is considered a directory only if it contains subfolders, so you can
++ not create a directory with the same name as an exisiting folder unless
++ you create a subfolder of that folder first (e.g. if you have a folder
++ called &quot;foo&quot; simply add &quot;foo.bar&quot; directly. This will
++ create the directory &quot;foo&quot; and the subfolder &quot;bar&quot; of it).
++ <P>
++ Observe that this feature works only for maildir collections that are accessed
++ locally. If a collection is accessed remotely then this feature has no value,
++ as the report is created in a server, and Pine only reports what received
++ from the server in this case.
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_verbose_post =====
+ <HTML>
+ <HEAD>
+***************
+*** 27228,27233 ****
+--- 28780,28808 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_auto_read_msgs_rules =====
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: auto-move-read-msgs-using-rules</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: auto-move-read-msgs-using-rules</H1>
++ This feature controls an aspect of Pine's behavior upon quitting. If set,
++ and the
++ <A HREF="h_config_read_message_folder">&quot;read-message-folder&quot;</A>
++ option is also set, then Pine will automatically transfer all read
++ messages to the designated folder using the rules that you have defined in
++ your
++ <A HREF="h_config_save_rules">&quot;save-rules&quot;</A> and mark
++ them as deleted in the INBOX. Messages in the INBOX marked with an
++ &quot;N&quot; (meaning New, or unseen) are not affected.
++ <P>
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_auto_fcc_only =====
+ <HTML>
+ <HEAD>
+***************
+*** 27616,27621 ****
+--- 29191,29213 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_enhanced_thread =====
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: enhanced-fancy-thread-support</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: enhanced-fancy-thread-support</H1>
++
++ If this option is set certain commands in Pine will operate in loose
++ threads too. For example, the command ^D marks a thread deleted, but if
++ this feature is set, it will remove all threads that share the same missing
++ parent with this thread.
++
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_news_cross_deletes =====
+ <HTML>
+ <HEAD>
+***************
+*** 28224,28229 ****
+--- 29816,29842 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_circular_tab =====
++ <HTML>
++ <HEAD>
++ <TITLE>FEATURE: enable-circular-tab</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>FEATURE: enable-circular-tab</H1>
++
++ <P>
++ This Feature is like
++ <A HREF="h_config_auto_open_unread">&quot;auto-open-next-unread&quot;</A>,
++ in the sense that you can use TAB to browse through all of your Incoming
++ Folders checking for new mail. Once it gets to the last folder of the
++ collection it goes back to check again until it returns to the original
++ folder where it started.
++ <UL>
++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A>
++ </UL><P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_auto_include_reply =====
+ <HTML>
+ <HEAD>
+***************
+*** 28715,28720 ****
+--- 30328,30357 ----
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
++ ====== h_config_special_text_color =====
++ <HTML>
++ <HEAD>
++ <TITLE>OPTION: Special Text Color</TITLE>
++ </HEAD>
++ <BODY>
++ <H1>OPTION: Special Text Color</H1>
++
++ Sets the color Pine uses for coloring any text in the body of the message
++ that is not part of a handle (and internal or external link that Pine
++ paints in a different color). By default, this variable is not defined,
++ which means that text that matches the pattern is not painted in any
++ particular way. This variable must be set in a special form if you
++ want text to be painted.
++
++ <P>
++ <A HREF="h_color_setup">Descriptions of the available commands</A>
++ <P>
++ Look <A HREF="h_edit_nav_cmds">here</A>
++ to see the available Editing and Navigation commands.
++ <P>
++ &lt;End of help on this topic&gt;
++ </BODY>
++ </HTML>
+ ====== h_config_prompt_color =====
+ <HTML>
+ <HEAD>
+diff -rc pine4.63/pine/reply.c pine4.63.I.USE/pine/reply.c
+*** pine4.63/pine/reply.c Thu Apr 28 10:22:03 2005
+--- pine4.63.I.USE/pine/reply.c Thu May 19 19:57:34 2005
+***************
+*** 62,67 ****
+--- 62,69 ----
+
+ #include "headers.h"
+
++ static ACTION_S *role_chosen;
++ static int strip, send_flowed = 1;
+
+
+ /*
+***************
+*** 276,282 ****
+ if(!times){ /* only first time */
+ char *p = cpystr(prefix);
+
+! if((include_text=reply_text_query(pine_state,totalm,&prefix)) < 0)
+ goto done_early;
+
+ /* edited prefix? */
+--- 278,284 ----
+ if(!times){ /* only first time */
+ char *p = cpystr(prefix);
+
+! if((include_text=reply_text_query(pine_state,totalm,env,&prefix)) < 0)
+ goto done_early;
+
+ /* edited prefix? */
+***************
+*** 307,312 ****
+--- 309,355 ----
+ else if(i == 0)
+ goto done_early;
+
++ if (ps_global->role)
++ fs_give((void **)&ps_global->role);
++
++ /* Setup possible role */
++ if (role_chosen)
++ role = role_chosen;
++ else if(role_arg)
++ role = copy_action(role_arg);
++
++ if(!role){
++ rflags = ROLE_REPLY;
++ if(!role_chosen && 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 */
++
+ /*------------ Format the subject line ---------------*/
+ if(outgoing->subject){
+ /*
+***************
+*** 319,326 ****
+ outgoing->subject = cpystr("Re: several messages");
+ }
+ }
+! else
+! outgoing->subject = reply_subject(env->subject, NULL, 0);
+ }
+
+
+--- 362,380 ----
+ outgoing->subject = cpystr("Re: several messages");
+ }
+ }
+! else{
+! RULE_RESULT *rule;
+! rule = get_result_rule(V_RESUB_RULES,
+! FOR_RULE|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);
+! }
+ }
+
+
+***************
+*** 331,369 ****
+ if(sp_expunge_count(pine_state->mail_stream)) /* cur msg expunged */
+ goto done_early;
+
+- /* Setup possible role */
+- if(role_arg)
+- role = copy_action(role_arg);
+-
+- if(!role){
+- rflags = ROLE_REPLY;
+- if(nonempty_patterns(rflags, &dummy)){
+- /* setup default role */
+- 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;
+- }
+- }
+- }
+-
+ /*
+ * Reply_seed may call c-client in get_fcc_based_on_to, so env may
+ * no longer be valid. Get it again.
+--- 385,390 ----
+***************
+*** 995,1001 ****
+ prompt_fodder);
+ }
+
+! cmd = radio_buttons(prompt, -FOOTER_ROWS(ps_global), ekey,
+ 'y', 'x', help, RB_NORM);
+
+ switch(cmd){
+--- 1016,1023 ----
+ prompt_fodder);
+ }
+
+! cmd = ps_global->send_immediately ? 'n' :
+! radio_buttons(prompt, -FOOTER_ROWS(ps_global), ekey,
+ 'y', 'x', help, RB_NORM);
+
+ switch(cmd){
+***************
+*** 1623,1630 ****
+ 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 */
+--- 1645,1671 ----
+ 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_RULE|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 */
+***************
+*** 1680,1689 ****
+ int
+ reply_quote_str_contains_tokens()
+ {
+! 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)));
+ }
+
+ /*
+--- 1721,1750 ----
+ int
+ reply_quote_str_contains_tokens()
+ {
+! char *reply_string;
+!
+! reply_string = (char *) malloc( 80*sizeof(char));
+! { RULE_RESULT *rule;
+! rule = get_result_rule(V_REPLY_INDENT_RULES,
+! FOR_RULE | FOR_COMPOSE, (ENVELOPE *)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)));
+ }
+
+ /*
+***************
+*** 1693,1738 ****
+ * 0 if we're NOT to include the text
+ * -1 on cancel or error
+ */
+ int
+! reply_text_query(ps, many, prefix)
+ struct pine *ps;
+ long many;
+ char **prefix;
+ {
+ int ret, edited = 0;
+! static ESCKEY_S rtq_opts[] = {
+! {'y', 'y', "Y", "Yes"},
+! {'n', 'n', "N", "No"},
+! {-1, 0, NULL, NULL}, /* may be overridden below */
+! {-1, 0, NULL, NULL}
+! };
+
+ if(F_ON(F_AUTO_INCLUDE_IN_REPLY, ps)
+! && F_OFF(F_ENABLE_EDIT_REPLY_INDENT, ps))
+ return(1);
+
+ while(1){
+! sprintf(tmp_20k_buf, "Include %s%soriginal message%s in Reply%s%s%s? ",
+ (many > 1L) ? comatose(many) : "",
+ (many > 1L) ? " " : "",
+ (many > 1L) ? "s" : "",
+ F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? " (using \"" : "",
+ F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? *prefix : "",
+ F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? "\")" : "");
+
+! if(F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps)){
+! rtq_opts[2].ch = ctrl('R');
+! rtq_opts[2].rval = 'r';
+! rtq_opts[2].name = "^R";
+! rtq_opts[2].label = "Edit Indent String";
+! }
+! else
+! rtq_opts[2].ch = -1;
+
+ switch(ret = radio_buttons(tmp_20k_buf,
+ ps->ttyo->screen_rows > 4
+ ? -FOOTER_ROWS(ps_global) : -1,
+! rtq_opts,
+ (edited || F_ON(F_AUTO_INCLUDE_IN_REPLY, ps))
+ ? 'y' : 'n',
+ 'x', NO_HELP, RB_SEQ_SENSITIVE)){
+--- 1754,1854 ----
+ * 0 if we're NOT to include the text
+ * -1 on cancel or error
+ */
++
++ #define MAX_REPLY_OPTIONS 8
++
+ int
+! reply_text_query(ps, many, env, prefix)
+ struct pine *ps;
+ long many;
++ ENVELOPE *env;
+ char **prefix;
+ {
+ int ret, edited = 0;
+! static ESCKEY_S compose_style[MAX_REPLY_OPTIONS];
+! int ekey_num;
+! int orig_sf;
+!
+! orig_sf = send_flowed = *prefix && **prefix ? (F_OFF(F_QUELL_FLOWED_TEXT, ps)
+! && F_OFF(F_STRIP_WS_BEFORE_SEND, ps)
+! && (strcmp(*prefix, "> ") == 0
+! || strcmp(*prefix, ">") == 0)) : 0;
+!
+! role_chosen = NULL;
+! strip = F_ON(F_ENABLE_STRIP_SIGDASHES, ps) || F_ON(F_ENABLE_SIGDASHES, ps);
+
+ if(F_ON(F_AUTO_INCLUDE_IN_REPLY, ps)
+! && F_OFF(F_ENABLE_EDIT_REPLY_INDENT, ps) && F_OFF(F_ALT_REPLY_MENU,ps))
+ return(1);
+
+ while(1){
+! sprintf(tmp_20k_buf,"Include %s%soriginal message%s in Reply%s%s%s%s%s? ",
+ (many > 1L) ? comatose(many) : "",
+ (many > 1L) ? " " : "",
+ (many > 1L) ? "s" : "",
+ F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? " (using \"" : "",
+ F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? *prefix : "",
++ role_chosen ? "\" and role \"" : "",
++ role_chosen ? role_chosen->nick : "",
+ F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? "\")" : "");
+
+! ekey_num = 0;
+! compose_style[ekey_num].ch = 'y';
+! compose_style[ekey_num].rval = 'y';
+! compose_style[ekey_num].name = "Y";
+! compose_style[ekey_num++].label = "Yes";
+!
+! compose_style[ekey_num].ch = 'n';
+! compose_style[ekey_num].rval = 'n';
+! compose_style[ekey_num].name = "N";
+! compose_style[ekey_num++].label = "No";
+!
+! if (F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps)){
+! compose_style[ekey_num].ch = ctrl('R');
+! compose_style[ekey_num].rval = 'r';
+! compose_style[ekey_num].name = "^R";
+! compose_style[ekey_num++].label = "Indent Str" ;
+! }
+!
+! /***** Alternate Reply Menu ********/
+!
+! if (F_ON(F_ALT_REPLY_MENU, ps)){
+! unsigned which_help;
+!
+! if (F_ON(F_ENABLE_STRIP_SIGDASHES, ps) ||
+! F_ON(F_ENABLE_SIGDASHES, ps)){
+! compose_style[ekey_num].ch = 's';
+! compose_style[ekey_num].rval = 's';
+! compose_style[ekey_num].name = "S";
+! compose_style[ekey_num++].label = strip ? "No Strip"
+! : "Strip Sig";
+! }
+!
+! compose_style[ekey_num].ch = 'r';
+! compose_style[ekey_num].rval = 'R';
+! compose_style[ekey_num].name = "R";
+! compose_style[ekey_num++].label = "Set Role";
+!
+! if(orig_sf){
+! compose_style[ekey_num].ch = 'f';
+! compose_style[ekey_num].rval = 'F';
+! compose_style[ekey_num].name = "F";
+! compose_style[ekey_num++].label = send_flowed ? "Quell Flowed"
+! : "Send Flowed";
+! }
+!
+! }
+! compose_style[ekey_num].ch = -1;
+! compose_style[ekey_num].name = NULL;
+! compose_style[ekey_num].label = NULL;
+!
+!
+! /***** End Alt Reply Menu *********/
+
+ switch(ret = radio_buttons(tmp_20k_buf,
+ ps->ttyo->screen_rows > 4
+ ? -FOOTER_ROWS(ps_global) : -1,
+! compose_style,
+ (edited || F_ON(F_AUTO_INCLUDE_IN_REPLY, ps))
+ ? 'y' : 'n',
+ 'x', NO_HELP, RB_SEQ_SENSITIVE)){
+***************
+*** 1740,1745 ****
+--- 1856,1892 ----
+ cmd_cancelled("Reply");
+ return(-1);
+
++ case 'F':
++ send_flowed = (send_flowed + 1) % 2;
++ break;
++
++ case 's':
++ strip = (strip + 1) % 2;
++ break;
++
++ case 'R':
++ {
++ void (*prev_screen)() = ps->prev_screen,
++ (*redraw)() = ps->redrawer;
++ ps->redrawer = NULL;
++ ps->next_screen = SCREEN_FUN_NULL;
++ if(role_select_screen(ps, &role_chosen, 1) < 0){
++ cmd_cancelled("Reply");
++ ps->next_screen = prev_screen;
++ ps->redrawer = redraw;
++ if (ps->redrawer)
++ (*ps->redrawer)();
++ continue;
++ }
++ ps->next_screen = prev_screen;
++ ps->redrawer = redraw;
++ if(role_chosen)
++ role_chosen = combine_inherited_role(role_chosen);
++ }
++ if (ps->redrawer)
++ (*ps->redrawer)();
++ break;
++
+ case 'r':
+ if(prefix && *prefix){
+ int done = 0;
+***************
+*** 1763,1768 ****
+--- 1910,1921 ----
+ if(flags & OE_USER_MODIFIED){
+ fs_give((void **)prefix);
+ *prefix = removing_quotes(cpystr(buf));
++ orig_sf = *prefix && **prefix ?
++ (F_OFF(F_QUELL_FLOWED_TEXT, ps)
++ && F_OFF(F_STRIP_WS_BEFORE_SEND, ps)
++ && (strcmp(*prefix, "> ") == 0
++ || strcmp(*prefix, ">") == 0)) : 0;
++ send_flowed = orig_sf;
+ edited = 1;
+ }
+
+***************
+*** 2251,2256 ****
+--- 2404,2413 ----
+ buf[0] = '\0';
+
+ switch(type){
++ case iFfrom:
++ addr = env && env->sparep ? env->sparep : NULL;
++ break;
++
+ case iFrom:
+ addr = env ? env->from : NULL;
+ break;
+***************
+*** 2682,2702 ****
+
+ 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 iAddress:
+ case iMailbox:
+--- 2839,2959 ----
+
+ break;
+
++ case iRole:
++ if (ps_global->role)
++ sprintf(buf, ps_global->role);
++ break;
++
++ case iRoleNick:
++ if(role && role->nick){
++ strncpy(buf, role->nick, 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:
+! sprintf(buf,ps_global->cur_folder);
+! break;
+!
+! case iCollection:
+! sprintf(buf,ps_global->context_current->nickname);
+! break;
+!
+! case iFlag:
+! {MAILSTREAM *stream = find_open_stream();
+! MSGNO_S *msgmap = NULL;
+! long msgno;
+! MESSAGECACHE *mc;
+! strcpy(buf, "_FLAG_"); /* default value */
+! if (stream){
+! mn_init(&msgmap, stream->nmsgs);
+! msgno = mn_m2raw(msgmap, rules_cursor_pos(stream));
+! if (msgno > 0L) mc = stream ? mail_elt(stream, msgno) : NULL;
+! if (mc)
+! sprintf(buf,"%s%s%s%s",mc->flagged ? "*" : "",
+! mc->recent ? (mc->seen ? "R" : "N") : (mc->seen) ? "R" : "U",
+! mc->answered ? "A" : "",
+! mc->deleted ? "D" : "" );
+! mn_give(&msgmap);
+! }
+! }
+! break;
+!
+! case iNick:
+! {
+! ADDRESS *tmp_adr = NULL;
+! if (env){
+! tmp_adr = env->from ? copyaddr(env->from)
+! : env->sender ? copyaddr(env->sender) : NULL;
+! get_nickname_from_addr(tmp_adr,buf,maxlen);
+! mail_free_address(&tmp_adr);
+! }
+! }
+! break;
+!
+! case iAddressCc:
+! case iAddressRecip:
+! case iAddressTo:
+! case iFadd:
+! {
+! int plen = 0; /* partial length */
+! ADDRESS *sparep2 = (type == iAddressTo || type == iAddressRecip)
+! ? ((env && env->to)
+! ? copyaddrlist(env->to)
+! : NULL)
+! : (type == iAddressCc)
+! ? ((env && env->cc)
+! ? copyaddrlist(env->cc)
+! : NULL)
+! : ((env && env->sparep)
+! ? copyaddr((ADDRESS *)env->sparep)
+! : NULL);
+! ADDRESS *sparep;
+!
+! if (type == iAddressRecip){
+! ADDRESS *last_to = NULL;
+!
+! for(last_to = sparep2;last_to && last_to->next; last_to= last_to->next);
+!
+! /* Make the end of To list point to cc list */
+! if(last_to)
+! last_to->next = (env && env->cc ? copyaddrlist(env->cc) : NULL);
+!
+! }
+! sparep = sparep2;
+! for(; sparep ; sparep = sparep->next)
+! if(sparep && sparep->mailbox && sparep->mailbox[0] &&
+! (plen ? plen + 1 : plen) + strlen(sparep->mailbox) <= maxlen){
+! if (plen == 0)
+! strcpy(buf, sparep->mailbox);
+! else{
+! strcat(buf, " ");
+! strcat(buf, sparep->mailbox);
+! }
+! if(sparep->host &&
+! sparep->host[0] &&
+! sparep->host[0] != '.' &&
+! strlen(buf) + strlen(sparep->host) + 1 <= maxlen){
+! strcat(buf, "@");
+! strcat(buf, sparep->host);
+! }
+! plen = strlen(buf);
+! }
+! mail_free_address(&sparep2);
+! }
+!
+! break;
+
+ case iAddress:
+ case iMailbox:
+***************
+*** 2715,2720 ****
+--- 2972,2982 ----
+
+ break;
+
++ case iLcc: /* fake it, there are not enough spare pointers */
++ if (env && env->date)
++ sprintf(buf,env->date);
++ break;
++
+ case iNews:
+ case iCurNews:
+ get_news_data(env, type, buf, maxlen);
+***************
+*** 2826,2832 ****
+ 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)){
+--- 3088,3106 ----
+ if(!env)
+ return;
+
+! { RULE_RESULT *rule;
+! rule = get_result_rule(V_REPLY_LEADIN_RULES,
+! FOR_RULE | 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)){
+***************
+*** 2988,2996 ****
+ }
+ else if(!outgoing->newsgroups)
+ outgoing->newsgroups = cpystr(env->newsgroups);
+- if(!IS_NEWS(ps_global->mail_stream))
+- q_status_message(SM_ORDER, 2, 3,
+- "Replying to message that MAY or MAY NOT have been posted to newsgroup");
+ }
+
+ return(ret);
+--- 3262,3267 ----
+***************
+*** 3051,3056 ****
+--- 3322,3329 ----
+
+ 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;
+***************
+*** 3064,3077 ****
+ * 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;
+--- 3337,3361 ----
+ * 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_RULE|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;
+***************
+*** 3269,3275 ****
+ }
+ }
+ }
+! else if(pt->what_for & FOR_REPLY_INTRO)
+ repl = get_reply_data(env, role, pt->ctype,
+ subbuf, sizeof(subbuf)-1);
+
+--- 3553,3559 ----
+ }
+ }
+ }
+! else if(pt->what_for & (FOR_REPLY_INTRO|FOR_RULE))
+ repl = get_reply_data(env, role, pt->ctype,
+ subbuf, sizeof(subbuf)-1);
+
+***************
+*** 3747,3755 ****
+ }
+ }
+
+! if(role)
+ q_status_message1(SM_ORDER, 3, 4,
+ "Forwarding using role \"%.200s\"", role->nick);
+
+ if(role && role->template){
+ char *filtered;
+--- 4031,4044 ----
+ }
+ }
+
+! if (ps_global->role)
+! fs_give((void **)&ps_global->role);
+!
+! if(role){
+ q_status_message1(SM_ORDER, 3, 4,
+ "Forwarding using role \"%.200s\"", role->nick);
++ ps_global->role = cpystr(role->nick);
++ }
+
+ if(role && role->template){
+ char *filtered;
+***************
+*** 3953,3958 ****
+--- 4242,4248 ----
+ #if defined(DOS) && !defined(_WINDOWS)
+ free((void *)reserve);
+ #endif
++ outgoing->sparep = env && env->from ? (ADDRESS *)copyaddr(env->from) : NULL;
+ pine_send(outgoing, &body, "FORWARD MESSAGE",
+ role, NULL, reply.flags ? &reply : NULL, redraft_pos,
+ NULL, NULL, FALSE);
+***************
+*** 4873,4881 ****
+ * tied our hands, alter the prefix to continue flowed
+ * formatting...
+ */
+! if(flow_res)
+ wrapflags |= GFW_FLOW_RESULT;
+
+ filters[i].filter = gf_wrap;
+ /*
+ * The 80 will cause longer lines than what is likely
+--- 5163,5174 ----
+ * tied our hands, alter the prefix to continue flowed
+ * formatting...
+ */
+! if(flow_res && send_flowed)
+ wrapflags |= GFW_FLOW_RESULT;
+
++ filters[i].filter = gf_quote_test;
++ filters[i++].data = gf_line_test_opt(select_quote, NULL);
++
+ filters[i].filter = gf_wrap;
+ /*
+ * The 80 will cause longer lines than what is likely
+***************
+*** 4909,4916 ****
+ * We also want to fold "> " quotes so we get the
+ * attributions correct.
+ */
+! if(flow_res && prefix && !strucmp(prefix, "> "))
+ *(prefix_p = prefix + 1) = '\0';
+ if(!(wrapflags & GFW_FLOWED)
+ && flow_res){
+ filters[i].filter = gf_line_test;
+--- 5202,5210 ----
+ * We also want to fold "> " quotes so we get the
+ * attributions correct.
+ */
+! if(flow_res && send_flowed && prefix && !strucmp(prefix, "> "))
+ *(prefix_p = prefix + 1) = '\0';
++ send_flowed = 1; /* reset for next call */
+ if(!(wrapflags & GFW_FLOWED)
+ && flow_res){
+ filters[i].filter = gf_line_test;
+***************
+*** 4938,4945 ****
+ }
+
+ if(prefix){
+! if(F_ON(F_ENABLE_SIGDASHES, ps_global) ||
+! F_ON(F_ENABLE_STRIP_SIGDASHES, ps_global)){
+ dashdata = 0;
+ filters[i].filter = gf_line_test;
+ filters[i++].data = gf_line_test_opt(sigdash_strip, &dashdata);
+--- 5232,5239 ----
+ }
+
+ if(prefix){
+! if(strip && (F_ON(F_ENABLE_SIGDASHES, ps_global) ||
+! F_ON(F_ENABLE_STRIP_SIGDASHES, ps_global))){
+ dashdata = 0;
+ filters[i].filter = gf_line_test;
+ filters[i++].data = gf_line_test_opt(sigdash_strip, &dashdata);
+diff -rc pine4.63/pine/rules.c pine4.63.I.USE/pine/rules.c
+*** pine4.63/pine/rules.c Thu May 19 19:59:15 2005
+--- pine4.63.I.USE/pine/rules.c Thu May 19 19:57:27 2005
+***************
+*** 0 ****
+--- 1,905 ----
++ /* This module was written by
++ *
++ * Eduardo Chappa (chappa@math.washington.edu)
++ * http://www.math.washington.edu/~chappa/pine/
++ *
++ * Original Version: November 1999
++ * Last Modified : December 14, 2004
++ *
++ * Send bug reports about this module to the address above.
++ */
++
++ #include "rules.h"
++
++ void free_token_value(token)
++ TOKEN_VALUE **token;
++ {
++ if(token && *token){
++ if ((*token)->testxt)
++ fs_give((void **)&((*token)->testxt));
++ if((*token)->next)
++ free_token_value(&((*token)->next));
++ fs_give((void **)token);
++ }
++ }
++
++ void free_condition(condition)
++ CONDITION_S **condition;
++ {
++ if(condition && *condition){
++ if ((*condition)->tname)
++ fs_give((void **)&((*condition)->tname));
++ if ((*condition)->value)
++ free_token_value(&((*condition)->value));
++ if((*condition)->next)
++ free_condition(&((*condition)->next));
++ fs_give((void **)condition);
++ }
++ }
++
++ void free_ruleaction(raction)
++ 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)
++ fs_give((void **)&((*raction)->value));
++ fs_give((void **)raction);
++ }
++ }
++
++ void free_rule(rule)
++ RULE_S **rule;
++ {
++ if(rule && *rule){
++ free_condition(&((*rule)->condition));
++ free_ruleaction(&((*rule)->action));
++ fs_give((void **)rule);
++ }
++ }
++
++ void free_rule_list(rule)
++ 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(rule)
++ 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 (amount)
++ size_t amount;
++ {
++ void *genmem;
++ memset(genmem = fs_get(amount), 0, amount);
++ return genmem;
++ }
++
++ int
++ isolate_condition (data, cvalue, len)
++ char *data, **cvalue;
++ int *len;
++ {
++ char *p = data;
++ int done = 0, error = 0, next_condition = 0, l;
++
++ *cvalue = NULL;
++ while (*p && !done){
++ switch (*p){
++ case '_': *cvalue = advance_to_char(p,'}', STRICT, NULL);
++ if(*cvalue){
++ strcat(*cvalue,"}");
++ p += strlen(*cvalue);
++ }
++ else
++ error++;
++ done++;
++ case ' ': p++;
++ break;
++ case '&': if (*(p+1) == '&'){ /* looking for && */
++ p += 2;
++ next_condition++;
++ }
++ else{
++ error++;
++ done++;
++ }
++ break;
++ case '=': /* looking for => or -> */
++ case '-': if ((*(p+1) == '>') && (!next_condition)){
++ is_save = (*p == '-');
++ p += 2;
++ }
++ else
++ error++;
++ done++;
++ break;
++ default : done++;
++ error++;
++ break;
++ }
++ }
++ *len = p - data;
++ return error ? -1 : (*cvalue ? 1 : 0);
++ }
++
++ TOKEN_VALUE *
++ parse_group_data (data, error)
++ char *data;
++ int *error;
++ {
++ TOKEN_VALUE *rvalue;
++ char *p;
++ int offset, err = 0;
++
++ if(error)
++ *error = 0;
++
++ if (!data)
++ return (TOKEN_VALUE *) NULL;
++
++ rvalue = (TOKEN_VALUE *) alloc_mem(sizeof(TOKEN_VALUE));
++ if (p = advance_to_char(data,';', STRICT, &offset)){
++ rvalue->testxt = cpystr(p);
++ data += strlen(p) + 1 + offset;
++ rvalue->next = parse_group_data(data, error);
++ }
++ else if (p = advance_to_char(data,'}', STRICT, NULL))
++ rvalue->testxt = cpystr(p);
++ else{
++ err++;
++ free_token_value(&rvalue);
++ }
++ if (error)
++ *error += err;
++ return(rvalue);
++ }
++
++ CONDITION_S *
++ fill_condition(data)
++ char *data;
++ {
++ CONDITION_S *condition;
++ int i, done, error = 0;
++ char *group;
++
++ for (i = 0, done = 0; !done && (i < NTOKENS); i++)
++ done = strncmp(data,token_rules[i], strlen(token_rules[i])) ? 0 : 1;
++ if (done){
++ condition = (CONDITION_S *) alloc_mem(sizeof(CONDITION_S));
++ condition->tname = cpystr(token_rules[--i]);
++ }
++ else
++ return (CONDITION_S *)NULL;
++
++ data += strlen(token_rules[i]);
++ for (; *data && *data == ' '; data++);
++ if (*data){
++ for (i = 0, done = 0; !done && (i < NREL); i++)
++ done = strncmp(data, rel_rules_test[i].value, 2) ? 0 : 1;
++ if (done)
++ condition->ttype = rel_rules_test[--i].ttype;
++ else{
++ free_condition(&condition);
++ return (CONDITION_S *) NULL;
++ }
++ }
++ data += 2;
++ for (; *data && *data == ' '; data++);
++ if (*data++ != '{'){
++ free_condition(&condition);
++ return (CONDITION_S *) NULL;
++ }
++ group = advance_to_char(data,'}', STRICT, &error);
++ if (group || (!group && error < 0)){
++ condition->value = parse_group_data(data, &error);
++ if(group && error)
++ free_condition(&condition);
++ if(group)
++ fs_give((void **) &group);
++ }
++ else
++ free_condition(&condition);
++ return condition;
++ }
++
++ CONDITION_S *
++ parse_condition (data, eoc)
++ char *data;
++ int *eoc; /* end of condition, equal to -1 on error */
++ {
++ CONDITION_S *condition = NULL;
++ char *p = data, *cvalue;
++ int len, error = 0, rv;
++
++ if((rv = isolate_condition(data, &cvalue, &len)) > 0){
++ if(condition = fill_condition(cvalue))
++ condition->next = parse_condition(data+len, eoc);
++ else
++ error++;
++ }
++ *eoc += len;
++ if (error)
++ *eoc = -1;
++ return condition;
++ }
++
++ RULEACTION_S *
++ parse_action (data, context)
++ char *data;
++ int context;
++ {
++ int i, done;
++ RULEACTION_S *raction = NULL;
++ char *function, *p = data;
++
++ if (!p)
++ return (RULEACTION_S *) NULL;
++
++ for (; *p && *p == ' '; p++);
++ if (!*p)
++ return (RULEACTION_S *) NULL;
++
++ if (is_save){
++ raction = (RULEACTION_S *) alloc_mem(sizeof(RULEACTION_S));
++ raction->function = cpystr("_SAVE_");
++ raction->value = (TOKEN_VALUE *) alloc_mem(sizeof(TOKEN_VALUE));
++ raction->context |= FOR_SAVE;
++ raction->exec = extended_value;
++ raction->value->testxt = cpystr(p);
++ return raction;
++ }
++ for (i = 0, done = 0; !done && (i < NFCN); i++)
++ done = (strstr(p,rule_fcns[i].name) == p);
++ p += done ? strlen(rule_fcns[--i].name) + 1 : 0;
++ if(!*p || (rule_fcns[i].what_for && !(rule_fcns[i].what_for & context)))
++ return (RULEACTION_S *) NULL;
++ if (done){
++ raction = (RULEACTION_S *) alloc_mem(sizeof(RULEACTION_S));
++ 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,'}', STRICT, NULL);
++ if(!raction->value->testxt)
++ free_ruleaction(&raction);
++ return raction;
++ }
++
++ done = (((function = strstr(p, "_TRIM_")) != NULL)
++ ? 1 : ((function = strstr(p, "_REXTRIM_")) != NULL)
++ ? 2 : ((function = strstr(p, "_REPLACE_")) != NULL)
++ ? 3 : 0);
++
++ if(!function)
++ return (RULEACTION_S *) NULL;
++
++ *function = '\0';
++ raction = (RULEACTION_S *) alloc_mem(sizeof(RULEACTION_S));
++ raction->token = get_name_token(p);
++ *function = '_';
++ p += strlen(raction->token) + 1;
++ for (; *p && *p == ' '; p++);
++ if (!strncmp(p,":=",2))
++ p += 2;
++ else{
++ free_ruleaction(&raction);
++ return (RULEACTION_S *) NULL;
++ }
++ for (; *p && *p == ' '; p++);
++ if (p != function){
++ free_ruleaction(&raction);
++ return (RULEACTION_S *) NULL;
++ }
++ p += done == 1 ? 6: 9;
++ if (*p != '{'){
++ free_ruleaction(&raction);
++ return (RULEACTION_S *) NULL;
++ }
++ *p = '\0';
++ for(i = 0; i < NFCN && strcmp(function, rule_fcns[i].name);i++);
++ raction->function = cpystr(function);
++ raction->is_trim = strcmp(function,"_TRIM_") ? 0 : 1;
++ raction->is_rextrim = strcmp(function,"_REXTRIM_") ? 0 : 1;
++ raction->is_replace = strcmp(function,"_REPLACE_") ? 0 : 1;
++ raction->context = rule_fcns[i].what_for;
++ raction->exec = rule_fcns[i].execute;
++ *p++ = '{';
++ raction->value = parse_group_data(p, NULL);
++ if(!raction->value->testxt)
++ free_ruleaction(&raction);
++ return raction;
++ }
++
++ RULE_S *
++ parse_rule (data, context)
++ 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(list, context, i)
++ char **list;
++ int context, 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(rule_list, rule)
++ 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(code, context)
++ int code, 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);
++ }
++ }
++
++ void
++ create_rule_list(void)
++ {
++ add_rule(V_THREAD_DISP_STYLE_RULES,FOR_RULE|FOR_THREAD);
++ add_rule(V_THREAD_INDEX_STYLE_RULES,FOR_RULE|FOR_THREAD);
++ add_rule(V_COMPOSE_RULES,FOR_RULE|FOR_COMPOSE);
++ add_rule(V_FORWARD_RULES,FOR_RULE|FOR_COMPOSE);
++ add_rule(V_INDEX_RULES,FOR_RULE|FOR_INDEX);
++ add_rule(V_REPLACE_RULES,FOR_RULE|FOR_REPLACE);
++ add_rule(V_REPLY_INDENT_RULES,FOR_RULE|FOR_COMPOSE);
++ add_rule(V_REPLY_LEADIN_RULES,FOR_RULE|FOR_REPLY_INTRO);
++ add_rule(V_RESUB_RULES,FOR_RULE|FOR_RESUB|FOR_TRIM);
++ add_rule(V_SAVE_RULES,FOR_RULE|FOR_SAVE);
++ add_rule(V_SMTP_RULES,FOR_RULE|FOR_COMPOSE);
++ add_rule(V_SORT_RULES,FOR_RULE|FOR_SORT);
++ add_rule(V_STARTUP_RULES,FOR_RULE|FOR_STARTUP);
++ }
++
++ int
++ condition_contains_token(condition, token)
++ CONDITION_S *condition;
++ char *token;
++ {
++ if (!condition)
++ return 0;
++
++ if (!strcmp(condition->tname, token))
++ return 1;
++ else
++ return condition_contains_token(condition->next, token);
++ }
++
++ RULELIST *
++ get_rulelist_from_code(code, list)
++ int code;
++ PRULELIST_S *list;
++ {
++ if (!list)
++ return (RULELIST *) NULL;
++
++ if(list->varnum == code)
++ return list->rlist;
++ else
++ return get_rulelist_from_code(code, list->next);
++ }
++
++ char *
++ test_rule(rlist, ctxt, env, n)
++ RULELIST *rlist;
++ int ctxt, *n;
++ ENVELOPE *env;
++ {
++ 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 (rule, n)
++ RULELIST *rule;
++ int n;
++ {
++ if (!rule)
++ return (RULE_S *) NULL;
++
++ return n ? get_rule(rule->next, n-1) : rule->prule;
++ }
++
++ /* 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(code, rule_context, env)
++ int code, rule_context;
++ ENVELOPE *env;
++ {
++ char *rule_result;
++ RULE_RESULT *rule = NULL;
++ RULELIST *rlist;
++ int n = 0;
++
++ 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;
++ }
++
++ /* process_rule:
++ Parameters: rule_data, is a rule. It's obtained as
++ rule_data = ps_global->VAR_SOME_RULE[n], for
++ some integer n
++ rule_context: context of the rule, and
++ env: An envelope if needed.
++
++ Returns : The value of the processed rule_data if the processing was
++ successful and matches context and possibly the envelope, or
++ NULL if there's no match
++ */
++
++ char *
++ process_rule (prule, rule_context, env)
++ RULE_S *prule;
++ int rule_context;
++ ENVELOPE *env;
++ {
++ int rv;
++ char *result = NULL;
++ CONDITION_S *condition;
++
++ if(!prule)
++ return NULL;
++
++ for(condition = prule->condition;
++ condition &&
++ (rv = test_condition(condition, rule_context, env));
++ condition = condition->next);
++
++ if(rv && !condition)
++ result = (prule->action->exec)(prule->action, rule_context, env);
++
++ return result;
++ }
++
++ TOKEN_VALUE *
++ copy_parsed_value(value, ctxt, env)
++ TOKEN_VALUE *value;
++ int ctxt;
++ ENVELOPE *env;
++ {
++ TOKEN_VALUE *tval = NULL;
++
++ if(!value)
++ return NULL;
++
++ if(value->testxt){
++ tval = (TOKEN_VALUE *) alloc_mem(sizeof(TOKEN_VALUE));
++ tval->testxt = detoken_src(value->testxt, ctxt, env, NULL, NULL, NULL);
++ }
++ if(value->next)
++ tval->next = copy_parsed_value(value->next, ctxt, env);
++
++ return tval;
++ }
++
++ int
++ test_condition(condition, rule_context, env)
++ CONDITION_S *condition;
++ int rule_context;
++ ENVELOPE *env;
++ {
++ int next_step;
++ TOKEN_VALUE *group;
++
++ group = copy_parsed_value(condition->value, rule_context, env);
++ next_step = (*rel_rules_test[condition->ttype].execute)(condition, group, env, rule_context);
++ free_token_value(&group);
++ return next_step;
++ }
++
++ /* returns the name of the token it found or NULL if there is no token, the
++ * real value of the token is obtained by calling the detoken_src function.
++ */
++
++ char *
++ get_name_token (condition)
++ 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, group, env, context)
++ TOKEN_VALUE *group;
++ CONDITION_S *condition;
++ ENVELOPE *env;
++ int context;
++ {
++ int rv = 0;
++ char *test;
++ TOKEN_VALUE *test_group = group;
++
++ test = detoken_src(condition->tname, context, env, NULL, NULL, NULL);
++ if (test){
++ while (rv == 0 && test_group){
++ if(!*test || strstr(test_group->testxt, test))
++ rv++;
++ else
++ test_group = test_group->next;
++ }
++ }
++ return rv;
++ }
++
++ int test_ni (condition, group, env, context)
++ TOKEN_VALUE *group;
++ CONDITION_S *condition;
++ ENVELOPE *env;
++ int context;
++ {
++ int rv = 0;
++ char *test;
++ TOKEN_VALUE *test_group = group;
++
++ test = detoken_src(condition->tname, context, env, NULL, NULL, NULL);
++ if (test){
++ if(!test_group)
++ rv++;
++ while (rv == 0 && test_group){
++ if(!*test_group->testxt || strstr(test, test_group->testxt))
++ rv++;
++ else
++ test_group = test_group->next;
++ }
++ }
++ return rv;
++ }
++
++ int test_not_in (condition, group, env, context)
++ TOKEN_VALUE *group;
++ CONDITION_S *condition;
++ ENVELOPE *env;
++ int context;
++ {
++ return !test_in(condition, group, env, context);
++ }
++
++ int test_not_ni (condition, group, env, context)
++ TOKEN_VALUE *group;
++ CONDITION_S *condition;
++ ENVELOPE *env;
++ int context;
++ {
++ return !test_ni(condition, group, env, context);
++ }
++
++ int test_eq (condition, group, env, context)
++ CONDITION_S *condition;
++ TOKEN_VALUE *group;
++ ENVELOPE *env;
++ int context;
++ {
++ int rv = 0;
++ char *test;
++ TOKEN_VALUE *test_group = group;
++
++ test = detoken_src(condition->tname, context, env, NULL, NULL, NULL);
++ if (test){
++ while (rv == 0 && test_group){
++ if((!*test && !*test_group->testxt) || !strcmp(test_group->testxt, test))
++ rv++;
++ else
++ test_group = test_group->next;
++ }
++ }
++ return rv;
++ }
++
++ int test_not_eq (condition, group, env, context)
++ CONDITION_S *condition;
++ TOKEN_VALUE *group;
++ ENVELOPE *env;
++ int context;
++ {
++ return !test_eq(condition, group, env, context);
++ }
++
++ char *
++ do_trim (test, tval)
++ char *test;
++ TOKEN_VALUE *tval;
++ {
++ char *begin_text;
++ int offset = 0;
++
++ if (!tval)
++ return test;
++
++ while(begin_text = strstr(test+offset,tval->testxt)){
++ strcpy(begin_text, begin_text+strlen(tval->testxt));
++ offset = begin_text - test;
++ }
++
++ return do_trim(test, tval->next);
++ }
++
++ char *
++ trim (action, context, env)
++ RULEACTION_S *action;
++ int context;
++ ENVELOPE *env;
++ {
++ char *begin_text, *test;
++ RULEACTION_S *taction = action;
++ int offset;
++
++ if (taction->context & context){
++ test = detoken_src(taction->token, context, env, NULL, NULL, NULL);
++ if (test)
++ test = do_trim(test, taction->value);
++ return test;
++ }
++ return NULL;
++ }
++
++
++ char *
++ do_rextrim (test, tval)
++ char *test;
++ TOKEN_VALUE *tval;
++ {
++ char *begin_text, *trim_text;
++ int offset = 0;
++
++ if (!tval)
++ return test;
++
++ trim_text = expand(test, tval->testxt);
++ 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 (action, context, env)
++ RULEACTION_S *action;
++ int context;
++ ENVELOPE *env;
++ {
++ char *begin_text, *trim_text, *test;
++ RULEACTION_S *taction = action;
++ TOKEN_VALUE **token = NULL;
++ int offset;
++
++ if (taction->context & context){
++ test = detoken_src(taction->token, context, env, NULL, NULL, NULL);
++ if (test){
++ test = do_rextrim(test, taction->value);
++ }
++ return test;
++ }
++ else
++ return NULL;
++ }
++
++ char *
++ raw_value (action, context,env)
++ RULEACTION_S *action;
++ int context;
++ ENVELOPE *env;
++ {
++ return (action->context & context) ? cpystr(action->value->testxt) : NULL;
++ }
++
++ char *
++ extended_value (action, ctxt,env)
++ RULEACTION_S *action;
++ int ctxt;
++ ENVELOPE *env;
++ {
++ return (action->context & ctxt)
++ ? detoken_src(action->value->testxt, ctxt, env, NULL, NULL, NULL)
++ : NULL;
++ }
++
++ /* advances given_string until it finds given_char */
++ char *
++ advance_to_char(given_string,given_char, flag, error)
++ 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 & STRICT ? 0 : 1;
++ err++;
++ break;
++ }
++ b[i++] = '\\';
++ }
++ if(c == given_char){
++ err += flag & STRICT ? 0 : 1;
++ break;
++ }
++ b[i++] = c;
++ }
++ b[i] = '\0';
++ if (b && (strlen(b) == strlen(given_string)) && (flag & STRICT))
++ 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 (string, pattern)
++ char *string;
++ char *pattern;
++ {
++ char tmp[1000];
++ int error, i = 0;
++ char *new_start, c;
++ char *ret_string = NULL;
++ regex_t preg;
++ regmatch_t pmatch;
++
++ if (error = regcomp(&preg, pattern, REG_EXTENDED)){
++ regerror(error, &preg, tmp, 1000);
++ return NULL;
++ }
++
++ if(((error = regexec(&preg, string, 1, &pmatch, 0)) != REG_NOMATCH)&& !error){
++ 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;
++ }
+diff -rc pine4.63/pine/rules.h pine4.63.I.USE/pine/rules.h
+*** pine4.63/pine/rules.h Thu May 19 19:59:15 2005
+--- pine4.63.I.USE/pine/rules.h Thu May 19 19:57:27 2005
+***************
+*** 0 ****
+--- 1,204 ----
++ #include "headers.h"
++ #ifndef _REGEX_H_
++ #include <regex.h>
++ #endif
++
++ int is_save; /* this rule has the form condition -> folder */
++ typedef struct {
++ char *value;
++ int type;
++ } RULE_ACTION;
++
++
++ RULE_RESULT *get_result_rule PROTO ((int, int, ENVELOPE *));
++ char *test_rule PROTO ((RULELIST *, int, ENVELOPE *, int *));
++ char *process_rule PROTO ((RULE_S *, int, ENVELOPE *));
++ int test_condition PROTO ((CONDITION_S *, int, ENVELOPE *));
++ int test_in PROTO ((CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int));
++ int test_ni PROTO ((CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int));
++ int test_not_in PROTO ((CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int));
++ int test_not_ni PROTO ((CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int));
++ int test_eq PROTO ((CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int));
++ int test_not_eq PROTO ((CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int));
++ char *trim PROTO ((RULEACTION_S *, int, ENVELOPE *));
++ char *rextrim PROTO ((RULEACTION_S *, int, ENVELOPE *));
++ char *raw_value PROTO ((RULEACTION_S *, int, ENVELOPE *));
++ char *extended_value PROTO ((RULEACTION_S *, int, ENVELOPE *));
++ char *expand PROTO((char *, char *));
++ char *get_name_token PROTO((char *));
++ char *advance_to_char PROTO ((char *, char, int, int *));
++
++ /* Separators:
++ *
++ * A separator is a string that separates the rule condition with the rule
++ * action. Below is the list of separators
++ *
++ */
++
++ #define SAVE_TO_SEP "->"
++ #define APPLY_SEP "=>"
++
++ /*------- Definitions of tokens -------*/
++ /*------ Keep the list alphabetically sorted, thanks -------*/
++
++ #define ADDR_TOKEN "_ADDRESS_"
++ #define ADDCC_TOKEN "_ADDRESSCC_"
++ #define ADDRECIP_TOKEN "_ADDRESSRECIPS_"
++ #define ADDTO_TOKEN "_ADDRESSTO_"
++ #define BCC_TOKEN "_BCC_"
++ #define CC_TOKEN "_CC_"
++ #define COLLECT_TOKEN "_COLLECTION_"
++ #define FLAG_TOKEN "_FLAG_"
++ #define FOLDER_TOKEN "_FOLDER_"
++ #define FADDRESS_TOKEN "_FORWARDADDRESS_"
++ #define FFROM_TOKEN "_FORWARDFROM_"
++ #define FROM_TOKEN "_FROM_"
++ #define LCC_TOKEN "_LCC_"
++ #define NICK_TOKEN "_NICK_"
++ #define ROLE_TOKEN "_ROLE_"
++ #define SEND_TOKEN "_SENDER_"
++ #define SUBJ_TOKEN "_SUBJECT_"
++ #define THDDSPSTY_TOKEN "_THREADSTYLE_"
++ #define THDNDXSTY_TOKEN "_THREADINDEX_"
++ #define TO_TOKEN "_TO_"
++
++ /* Mail related tokens
++ *
++ * The following is an array with the list of tokens.
++ */
++
++ char* token_rules[] = {
++ FROM_TOKEN,
++ NICK_TOKEN,
++ ROLE_TOKEN,
++ FOLDER_TOKEN,
++ SUBJ_TOKEN,
++ THDDSPSTY_TOKEN,
++ THDNDXSTY_TOKEN,
++ FLAG_TOKEN,
++ COLLECT_TOKEN,
++ THDDSPSTY_TOKEN,
++ ADDR_TOKEN,
++ TO_TOKEN,
++ ADDTO_TOKEN,
++ ADDCC_TOKEN,
++ ADDRECIP_TOKEN,
++ SEND_TOKEN,
++ CC_TOKEN,
++ LCC_TOKEN,
++ BCC_TOKEN,
++ FFROM_TOKEN,
++ FADDRESS_TOKEN,
++ NULL
++ };
++
++ #define NTOKENS (sizeof(token_rules)/sizeof(token_rules[0]) - 1)
++
++ /*------ 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*/
++
++ 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)
++
++ /*--- 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},
++ {ROLE_TOKEN, FOR_COMPOSE},
++ {FOLDER_TOKEN, FOR_SAVE|FOR_FOLDER|FOR_THREAD},
++ {SUBJ_TOKEN, FOR_SAVE|FOR_FOLDER},
++ {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},
++ {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 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_"
++
++
++ RULE_FCN rule_fcns[] = {
++ {SAVE_FCN, extended_value, FOR_SAVE},
++ {REPLY_FCN, extended_value, FOR_REPLY_INTRO},
++ {TRIM_FCN, trim, FOR_TRIM | FOR_RESUB},
++ {REPLACE_FCN, extended_value, FOR_REPLACE},
++ {SORT_FCN, raw_value, FOR_SORT},
++ {INDEX_FCN, raw_value, FOR_INDEX},
++ {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},
++ {THRDSTYLE_FCN, raw_value, FOR_THREAD},
++ {THRDINDEX_FCN, raw_value, FOR_THREAD},
++ {SMTP_FCN, raw_value, FOR_COMPOSE}
++ };
++
++ #define NFCN (sizeof(rule_fcns)/sizeof(rule_fcns[0]))
++
++ #define STRICT 0x1
++ #define RELAXED 0x2
++
+diff -rc pine4.63/pine/send.c pine4.63.I.USE/pine/send.c
+*** pine4.63/pine/send.c Mon Mar 21 12:14:41 2005
+--- pine4.63.I.USE/pine/send.c Thu May 19 19:57:31 2005
+***************
+*** 377,382 ****
+--- 377,387 ----
+ 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);
+***************
+*** 581,588 ****
+ }
+ ps_global->next_screen = prev_screen;
+ ps_global->redrawer = redraw;
+! if(role)
+ role = combine_inherited_role(role);
+ }
+ break;
+ case 'f':
+--- 586,597 ----
+ }
+ 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;
+ case 'f':
+***************
+*** 675,680 ****
+--- 684,694 ----
+
+ if(exists & FEX_ISFILE){
+ context_apply(tmp, p_cntxt, mbox, sizeof(tmp));
++ if (!strncmp(tmp, "#md/",4) || !struncmp(tmp, "#mc/", 4)){
++ char tmp2[MAILTMPLEN];
++ maildir_file_path(tmp, tmp2);
++ strcpy(tmp, tmp2);
++ }
+ if(!(IS_REMOTE(tmp) || is_absolute_path(tmp))){
+ /*
+ * The mbox is relative to the home directory.
+***************
+*** 775,780 ****
+--- 789,799 ----
+
+ if(exists & FEX_ISFILE){
+ context_apply(tmp, p_cntxt, mbox, sizeof(tmp));
++ if (!strncmp(tmp, "#md/",4) || !struncmp(tmp, "#mc/", 4)){
++ char tmp2[MAILTMPLEN];
++ maildir_file_path(tmp, tmp2);
++ strcpy(tmp, tmp2);
++ }
+ if(!(IS_REMOTE(tmp) || is_absolute_path(tmp))){
+ /*
+ * The mbox is relative to the home directory.
+***************
+*** 864,869 ****
+--- 883,889 ----
+ if(given_to)
+ rfc822_parse_adrlist(&outgoing->to, given_to, ps_global->maildomain);
+
++ outgoing->subject = cpystr(ps_global->subject);
+ outgoing->message_id = generate_message_id();
+
+ /*
+***************
+*** 894,902 ****
+ }
+ }
+
+! if(role)
+ q_status_message1(SM_ORDER, 3, 4, "Composing using role \"%.200s\"",
+ role->nick);
+
+ /*
+ * The type of storage object allocated below is vitally
+--- 914,928 ----
+ }
+ }
+
+! if (ps_global->role)
+! fs_give((void **)&ps_global->role);
+!
+!
+! if(role){
+ q_status_message1(SM_ORDER, 3, 4, "Composing using role \"%.200s\"",
+ role->nick);
++ ps_global->role = cpystr(role->nick);
++ }
+
+ /*
+ * The type of storage object allocated below is vitally
+***************
+*** 2195,2201 ****
+ static struct headerentry he_template[]={
+ {"From : ", "From", h_composer_from, 10, 0, NULL,
+ build_address, NULL, NULL, addr_book_compose, "To AddrBk", NULL,
+! 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, KS_TOADDRBOOK},
+ {"Reply-To: ", "Reply To", h_composer_reply_to, 10, 0, NULL,
+ build_address, NULL, NULL, addr_book_compose, "To AddrBk", NULL,
+ 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, KS_TOADDRBOOK},
+--- 2221,2227 ----
+ static struct headerentry he_template[]={
+ {"From : ", "From", h_composer_from, 10, 0, NULL,
+ build_address, NULL, NULL, addr_book_compose, "To AddrBk", NULL,
+! 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, KS_TOADDRBOOK},
+ {"Reply-To: ", "Reply To", h_composer_reply_to, 10, 0, NULL,
+ build_address, NULL, NULL, addr_book_compose, "To AddrBk", NULL,
+ 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, KS_TOADDRBOOK},
+***************
+*** 2302,2308 ****
+ #define N_OURREPLYTO 21
+ #define N_OURHDRS 22
+ #define N_SENDER 23
+!
+ #define TONAME "To"
+ #define CCNAME "cc"
+ #define SUBJNAME "Subject"
+--- 2328,2335 ----
+ #define N_OURREPLYTO 21
+ #define N_OURHDRS 22
+ #define N_SENDER 23
+! #define CAN_EDIT(x) (!((x)->never_allow_changing_from) && \
+! F_ON(F_ALLOW_CHANGING_FROM, (x)))
+ #define TONAME "To"
+ #define CCNAME "cc"
+ #define SUBJNAME "Subject"
+***************
+*** 2310,2316 ****
+ /* this is used in pine_send and pine_simple_send */
+ /* name::type::canedit::writehdr::localcopy::rcptto */
+ static PINEFIELD pf_template[] = {
+! {"From", Address, 0, 1, 1, 0},
+ {"Reply-To", Address, 0, 1, 1, 0},
+ {TONAME, Address, 1, 1, 1, 1},
+ {CCNAME, Address, 1, 1, 1, 1},
+--- 2337,2343 ----
+ /* this is used in pine_send and pine_simple_send */
+ /* name::type::canedit::writehdr::localcopy::rcptto */
+ static PINEFIELD pf_template[] = {
+! {"From", Address, 1, 1, 1, 0},
+ {"Reply-To", Address, 0, 1, 1, 0},
+ {TONAME, Address, 1, 1, 1, 1},
+ {CCNAME, Address, 1, 1, 1, 1},
+***************
+*** 2459,2465 ****
+ *p = *(p+4);
+
+ pf->type = pf_template[i].type;
+! pf->canedit = pf_template[i].canedit;
+ pf->rcptto = pf_template[i].rcptto;
+ pf->writehdr = pf_template[i].writehdr;
+ pf->localcopy = pf_template[i].localcopy;
+--- 2486,2492 ----
+ *p = *(p+4);
+
+ pf->type = pf_template[i].type;
+! pf->canedit = (i == N_FROM) ? CAN_EDIT(ps_global) : pf_template[i].canedit;
+ pf->rcptto = pf_template[i].rcptto;
+ pf->writehdr = pf_template[i].writehdr;
+ pf->localcopy = pf_template[i].localcopy;
+***************
+*** 3175,3180 ****
+--- 3202,3210 ----
+ pbf = &pbuf1;
+ standard_picobuf_setup(pbf);
+
++ pbf->auto_cmds = ps_global->initial_cmds_backup +
++ ps_global->initial_cmds_offset;
++
+ /*
+ * Cancel any pending initial commands since pico uses a different
+ * input routine. If we didn't cancel them, they would happen after
+***************
+*** 3662,3667 ****
+--- 3692,3702 ----
+ he->rich_header = 0;
+ }
+ }
++ if (F_ON(F_ALLOW_CHANGING_FROM, ps_global) &&
++ !ps_global->never_allow_changing_from){
++ he->display_it = 1; /* show it */
++ he->rich_header = 0;
++ }
+
+ he_from = he;
+ break;
+***************
+*** 3769,3774 ****
+--- 3804,3827 ----
+ 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 = cpystr(addr);
++ rule = get_result_rule(V_FORWARD_RULES,
++ FOR_RULE|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);
++ }
++ if (outgoing->date)
++ fs_give((void **)&outgoing->date);
++ }
++
+ rfc822_parse_adrlist(pf->addr, addr,
+ ps_global->maildomain);
+ fs_give((void **)&addr);
+***************
+*** 4274,4282 ****
+--- 4327,4338 ----
+ /* turn off user input timeout when in composer */
+ saved_user_timeout = ps_global->hours_to_timeout;
+ ps_global->hours_to_timeout = 0;
++ ps_global->in_pico = 1; /* in */
+ dprint(1, (debugfile, "\n ---- COMPOSER ----\n"));
+ editor_result = pico(pbf);
++ ps_global->force_check_now = 0; /* do not check incoming folders now */
+ dprint(4, (debugfile, "... composer returns (0x%x)\n", editor_result));
++ ps_global->in_pico = 0; /* out */
+ ps_global->hours_to_timeout = saved_user_timeout;
+
+ #if defined(DOS) && !defined(_WINDOWS)
+***************
+*** 4285,4291 ****
+ #ifdef _WINDOWS
+ mswin_setwindowmenu (MENU_DEFAULT);
+ #endif
+! fix_windsize(ps_global);
+ /*
+ * Only reinitialize signals if we didn't receive an interesting
+ * one while in pico, since pico's return is part of processing that
+--- 4341,4352 ----
+ #ifdef _WINDOWS
+ mswin_setwindowmenu (MENU_DEFAULT);
+ #endif
+! if (ps_global->send_immediately){
+! if(ps_global->free_initial_cmds_backup)
+! fs_give((void **)&ps_global->free_initial_cmds_backup);
+! }
+! else
+! fix_windsize(ps_global);
+ /*
+ * Only reinitialize signals if we didn't receive an interesting
+ * one while in pico, since pico's return is part of processing that
+***************
+*** 4345,4351 ****
+ if(outgoing->return_path)
+ mail_free_address(&outgoing->return_path);
+
+! outgoing->return_path = rfc822_cpy_adr(outgoing->from);
+
+ /*
+ * Don't ever believe the sender that is there.
+--- 4406,4414 ----
+ if(outgoing->return_path)
+ mail_free_address(&outgoing->return_path);
+
+! outgoing->return_path = F_ON(F_USE_DOMAIN_NAME,ps_global)
+! ? rfc822_cpy_adr(generate_from())
+! : rfc822_cpy_adr(outgoing->from);
+
+ /*
+ * Don't ever believe the sender that is there.
+***************
+*** 4947,4956 ****
+ if(sending_filter_requested
+ && !filter_message_text(sending_filter_requested, outgoing,
+ *body, &orig_so, &header)){
+! q_status_message1(SM_ORDER, 3, 3,
+ "Problem filtering! Nothing sent%.200s.",
+ fcc ? " or saved to fcc" : "");
+! continue;
+ }
+
+ /*------ Actually post -------*/
+--- 5010,5025 ----
+ if(sending_filter_requested
+ && !filter_message_text(sending_filter_requested, outgoing,
+ *body, &orig_so, &header)){
+! if (!ps_global->send_immediately){
+! q_status_message1(SM_ORDER, 3, 3,
+ "Problem filtering! Nothing sent%.200s.",
+ fcc ? " or saved to fcc" : "");
+! continue;
+! }
+! else{
+! fprintf(stderr, "Problem filtering! Nothing sent or saved to Fcc\n");
+! exit(-1);
+! }
+ }
+
+ /*------ Actually post -------*/
+***************
+*** 5171,5176 ****
+--- 5240,5247 ----
+ /*----- Mail Post FAILED, back to composer -----*/
+ if(result & (P_MAIL_LOSE | P_FCC_LOSE)){
+ dprint(1, (debugfile, "Send failed, continuing\n"));
++ if (ps_global->send_immediately)
++ exit(1);
+
+ if(result & P_FCC_LOSE){
+ /*
+***************
+*** 5205,5210 ****
+--- 5276,5282 ----
+ update_answered_flags(reply);
+
+ /*----- Signed, sealed, delivered! ------*/
++ if (!ps_global->send_immediately)
+ q_status_message(SM_ORDER, 0, 3,
+ pine_send_status(result, fcc, tmp_20k_buf, NULL));
+
+***************
+*** 5789,5795 ****
+ if(background_posting(FALSE))
+ return("Can't send while background posting. Use postpone.");
+
+! if(F_ON(F_SEND_WO_CONFIRM, ps_global))
+ return(NULL);
+
+ ps_global->redrawer = redraw_pico;
+--- 5861,5867 ----
+ if(background_posting(FALSE))
+ return("Can't send while background posting. Use postpone.");
+
+! if(!ps_global->send_immediately && F_ON(F_SEND_WO_CONFIRM, ps_global))
+ return(NULL);
+
+ ps_global->redrawer = redraw_pico;
+***************
+*** 5940,5946 ****
+
+ opts[i].ch = -1;
+
+! fix_windsize(ps_global);
+
+ while(1){
+ if(filters && filters->filter && (p = strindex(filters->filter, ' ')))
+--- 6012,6019 ----
+
+ opts[i].ch = -1;
+
+! if (!ps_global->send_immediately)
+! fix_windsize(ps_global);
+
+ while(1){
+ if(filters && filters->filter && (p = strindex(filters->filter, ' ')))
+***************
+*** 6075,6081 ****
+
+ if(double_rad +
+ (dsn_requested ? 4 : F_ON(F_DSN, ps_global) ? 1 : 0) > 11)
+! rv = double_radio_buttons(tmp_20k_buf, -FOOTER_ROWS(ps_global), opts,
+ 'y', 'z',
+ (F_ON(F_DSN, ps_global) && allow_flowed)
+ ? h_send_prompt_dsn_flowed :
+--- 6148,6155 ----
+
+ if(double_rad +
+ (dsn_requested ? 4 : F_ON(F_DSN, ps_global) ? 1 : 0) > 11)
+! rv = ps_global->send_immediately ? 'y' :
+! double_radio_buttons(tmp_20k_buf, -FOOTER_ROWS(ps_global), opts,
+ 'y', 'z',
+ (F_ON(F_DSN, ps_global) && allow_flowed)
+ ? h_send_prompt_dsn_flowed :
+***************
+*** 6084,6090 ****
+ h_send_prompt,
+ RB_NORM);
+ else
+! rv = radio_buttons(tmp_20k_buf, -FOOTER_ROWS(ps_global), opts,
+ 'y', 'z',
+ (double_rad +
+ (dsn_requested ? 4 : F_ON(F_DSN, ps_global)
+--- 6158,6165 ----
+ h_send_prompt,
+ RB_NORM);
+ else
+! rv = ps_global->send_immediately ? 'y' :
+! radio_buttons(tmp_20k_buf, -FOOTER_ROWS(ps_global), opts,
+ 'y', 'z',
+ (double_rad +
+ (dsn_requested ? 4 : F_ON(F_DSN, ps_global)
+***************
+*** 6671,6679 ****
+ if(tmp_so = so_get(PicoText, NULL, EDIT_ACCESS)){
+ gf_set_so_writec(&pc, tmp_so);
+ ps_global->mangled_screen = 1;
+! suspend_busy_alarm();
+! ClearScreen();
+! fflush(stdout);
+ if(tmpf){
+ PIPE_S *fpipe;
+
+--- 6746,6756 ----
+ if(tmp_so = so_get(PicoText, NULL, EDIT_ACCESS)){
+ gf_set_so_writec(&pc, tmp_so);
+ ps_global->mangled_screen = 1;
+! if (!ps_global->send_immediately){
+! suspend_busy_alarm();
+! ClearScreen();
+! fflush(stdout);
+! }
+ if(tmpf){
+ PIPE_S *fpipe;
+
+***************
+*** 6779,6787 ****
+ b->encoding = ENCOTHER;
+ set_mime_type_by_grope(b, NULL);
+ }
+!
+! ClearScreen();
+! resume_busy_alarm(0);
+ }
+ else
+ errstr = "Can't create space for filtered text.";
+--- 6856,6865 ----
+ b->encoding = ENCOTHER;
+ set_mime_type_by_grope(b, NULL);
+ }
+! if (!ps_global->send_immediately){
+! ClearScreen();
+! resume_busy_alarm(0);
+! }
+ }
+ else
+ errstr = "Can't create space for filtered text.";
+***************
+*** 6812,6821 ****
+ if(tmp_so)
+ so_give(&tmp_so);
+
+! q_status_message1(SM_ORDER | SM_DING, 3, 6, "Problem filtering: %.200s",
+ errstr);
+! dprint(1, (debugfile, "Filter FAILED: %s\n",
+ errstr ? errstr : "?"));
+ }
+
+ return(errstr == NULL);
+--- 6890,6905 ----
+ if(tmp_so)
+ so_give(&tmp_so);
+
+! if (!ps_global->send_immediately){
+! q_status_message1(SM_ORDER | SM_DING, 3, 6, "Problem filtering: %.200s",
+ errstr);
+! dprint(1, (debugfile, "Filter FAILED: %s\n",
+ errstr ? errstr : "?"));
++ }
++ else{
++ fprintf(stderr, "Filter FAILED: %s\n", errstr ? errstr : "?");
++ exit(-1);
++ }
+ }
+
+ return(errstr == NULL);
+***************
+*** 6971,6979 ****
+ 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;
+
+--- 7055,7063 ----
+ 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;
+
+***************
+*** 7101,7119 ****
+ * 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, (debugfile, "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, (debugfile, "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)){
+ char *cmdlist[2];
+--- 7185,7234 ----
+ * 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 = 0, j = 0;
+!
+! added_rules = 0;
+! smtp_list = (char **) fs_get ((num_rules + 1)*sizeof(char*));
+! for (i = 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_RULE|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, (debugfile, "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)){
+ char *cmdlist[2];
+***************
+*** 7313,7318 ****
+--- 7428,7435 ----
+
+ q_status_message(SM_ORDER | SM_DING, 4, 7, error_mess);
+ dprint(1, (debugfile, "call_mailer ERROR: %s\n", error_mess));
++ if (ps_global->send_immediately)
++ printf("%s\n",error_mess);
+ return(-1);
+ }
+ else{
+diff -rc pine4.63/pine/signals.c pine4.63.I.USE/pine/signals.c
+*** pine4.63/pine/signals.c Thu Nov 4 14:33:05 2004
+--- pine4.63.I.USE/pine/signals.c Thu May 19 19:57:34 2005
+***************
+*** 673,679 ****
+
+ add_review_message(buf, -1);
+ }
+! else{
+ q_status_message(SM_ORDER, 0, 1, progress);
+
+ /*
+--- 673,680 ----
+
+ add_review_message(buf, -1);
+ }
+! else if (!ps_global->send_immediately
+! && !ps_global->checking_incfld){
+ q_status_message(SM_ORDER, 0, 1, progress);
+
+ /*
+***************
+*** 683,700 ****
+ * its min display time yet. In that case, we don't want
+ * to force out the initial message.
+ */
+! display_message('x');
+ }
+ }
+
+ #ifdef _WINDOWS
+ mswin_setcursor (MSWIN_CURSOR_BUSY);
+ #endif
+ fflush(stdout);
+ }
+
+ /* set alarm */
+! if(F_OFF(F_DISABLE_ALARM, ps_global))
+ alarm(seconds);
+
+ return(retval);
+--- 684,703 ----
+ * its min display time yet. In that case, we don't want
+ * to force out the initial message.
+ */
+! display_message('x');
+ }
+ }
+
+ #ifdef _WINDOWS
+ mswin_setcursor (MSWIN_CURSOR_BUSY);
+ #endif
++ if (!ps_global->send_immediately)
+ fflush(stdout);
+ }
+
+ /* set alarm */
+! if(F_OFF(F_DISABLE_ALARM, ps_global) && !ps_global->send_immediately
+! && !ps_global->checking_incfld)
+ alarm(seconds);
+
+ return(retval);
+***************
+*** 731,748 ****
+
+ right = (slots_used - 4)/2;
+ left = slots_used - 4 - right;
+ sprintf(progress, "%s |%*s100%%%*s|",
+ busy_message, left, "", right, "");
+ q_status_message(SM_ORDER,
+ message_pri>=2 ? max(message_pri,3) : 0,
+! message_pri+2, progress);
+ }
+ else{
+ sprintf(progress, "%s%*sDONE", busy_message,
+ DISPLAY_CHARS_COLS - 4 + 1, "");
+ q_status_message(SM_ORDER,
+ message_pri>=2 ? max(message_pri,3) : 0,
+! message_pri+2, progress);
+ }
+ }
+ else
+--- 734,755 ----
+
+ right = (slots_used - 4)/2;
+ left = slots_used - 4 - right;
++ if (!ps_global->send_immediately){
+ sprintf(progress, "%s |%*s100%%%*s|",
+ busy_message, left, "", right, "");
++ if (!ps_global->checking_incfld)
+ q_status_message(SM_ORDER,
+ message_pri>=2 ? max(message_pri,3) : 0,
+! message_pri+2, progress);}
+ }
+ else{
++ if (!ps_global->send_immediately){
+ sprintf(progress, "%s%*sDONE", busy_message,
+ DISPLAY_CHARS_COLS - 4 + 1, "");
++ if (!ps_global->checking_incfld)
+ q_status_message(SM_ORDER,
+ message_pri>=2 ? max(message_pri,3) : 0,
+! message_pri+2, progress);}
+ }
+ }
+ else
+diff -rc pine4.63/pine/status.c pine4.63.I.USE/pine/status.c
+*** pine4.63/pine/status.c Tue Apr 26 15:15:45 2005
+--- pine4.63.I.USE/pine/status.c Thu May 19 19:57:28 2005
+***************
+*** 142,147 ****
+--- 142,150 ----
+ char *clean_msg;
+ size_t mlen;
+
++ if (ps_global->send_immediately)
++ return;
++
+ /*
+ * By convention, we have min_time equal to zero in messages which we
+ * think are not as important, so-called comfort messages. We have
+***************
+*** 1184,1190 ****
+ char *q2;
+ int rv;
+
+! if(!ps_global->ttyo)
+ return(pre_screen_config_want_to(question, dflt, on_ctrl_C));
+ #ifdef _WINDOWS
+ if (mswin_usedialog ()) {
+--- 1187,1193 ----
+ char *q2;
+ int rv;
+
+! if((!ps_global->ttyo) || (ps_global->send_immediately))
+ return(pre_screen_config_want_to(question, dflt, on_ctrl_C));
+ #ifdef _WINDOWS
+ if (mswin_usedialog ()) {
+diff -rc pine4.63/pine/strings.c pine4.63.I.USE/pine/strings.c
+*** pine4.63/pine/strings.c Fri Apr 15 15:07:17 2005
+--- pine4.63.I.USE/pine/strings.c Thu May 19 19:57:27 2005
+***************
+*** 6069,6075 ****
+ SortOrder def_sort;
+ int def_sort_rev;
+
+! if(decode_sort(p, &def_sort, &def_sort_rev) != -1){
+ action->sort_is_set = 1;
+ action->sortorder = def_sort;
+ action->revsort = (def_sort_rev ? 1 : 0);
+--- 6069,6075 ----
+ SortOrder def_sort;
+ int def_sort_rev;
+
+! if(decode_sort(p, &def_sort, &def_sort_rev, 0) != -1){
+ action->sort_is_set = 1;
+ action->sortorder = def_sort;
+ action->revsort = (def_sort_rev ? 1 : 0);
+***************
+*** 9624,9629 ****
+--- 9624,9635 ----
+ break;
+
+ case '#':
++ if(!struncmp(patfolder, "#md/", 4)
++ || !struncmp(patfolder, "#mc/", 4)){
++ maildir_file_path(patfolder, tmp1);
++ strncpy(patfolder, tmp1, sizeof(patfolder));
++ patfolder[sizeof(patfolder)-1] = '\0';
++ }
+ if(!strcmp(patfolder, stream->mailbox))
+ match++;
+
+***************
+*** 11417,11419 ****
+--- 11423,11457 ----
+
+ return(idata);
+ }
++
++
++ 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 pine4.63/pine/takeaddr.c pine4.63.I.USE/pine/takeaddr.c
+*** pine4.63/pine/takeaddr.c Mon Mar 7 15:16:41 2005
+--- pine4.63.I.USE/pine/takeaddr.c Thu May 19 19:57:32 2005
+***************
+*** 1782,1791 ****
+--- 1782,1793 ----
+ TA_S *p;
+ int rc, found = 0, wrapped = 0, flags;
+ char *result = NULL, buf[MAX_SEARCH+1], tmp[MAX_SEARCH+20];
++ static char last_pat[MAX_SEARCH+1] = {'\0'};
+ static char last[MAX_SEARCH+1];
+ HelpType help;
+ static ESCKEY_S ekey[] = {
+ {0, 0, "", ""},
++ {ctrl('N'), 9, "^N", "Ins Pat"},
+ {ctrl('Y'), 10, "^Y", "Top"},
+ {ctrl('V'), 11, "^V", "Bottom"},
+ {-1, 0, NULL, NULL}};
+***************
+*** 1806,1822 ****
+ tmp,ekey,help,&flags);
+ if(rc == 3)
+ help = help == NO_HELP ? h_config_whereis : NO_HELP;
+! else if(rc == 0 || rc == 1 || rc == 10 || rc == 11 || !buf[0]){
+ if(rc == 0 && !buf[0] && last[0]){
+ strncpy(buf, last, sizeof(buf)-1);
+ buf[sizeof(buf)-1] = '\0';
+ }
+!
+! break;
+ }
+ }
+
+ if(rc == 0 && buf[0]){
+ p = current;
+ while(p = next_taline(p))
+ if(srchstr((char *)rfc1522_decode((unsigned char *)tmp_20k_buf,
+--- 1808,1828 ----
+ tmp,ekey,help,&flags);
+ if(rc == 3)
+ help = help == NO_HELP ? h_config_whereis : NO_HELP;
+! else if(rc == 0 || rc == 1 || rc == 10 || rc == 11 || rc == 9 || !buf[0]){
+ if(rc == 0 && !buf[0] && last[0]){
+ strncpy(buf, last, sizeof(buf)-1);
+ buf[sizeof(buf)-1] = '\0';
+ }
+! if (rc == 9)
+! insert_pattern_in_string(buf, last_pat, MAX_SEARCH);
+! else
+! break;
+ }
+ }
+
+ if(rc == 0 && buf[0]){
++ strncpy(last_pat, buf, sizeof(last_pat));
++ last_pat[sizeof(last_pat)-1] = '\0';
+ p = current;
+ while(p = next_taline(p))
+ if(srchstr((char *)rfc1522_decode((unsigned char *)tmp_20k_buf,
diff --git a/packages/pine/pine-4.63/pine-ldap3.patch b/packages/pine/pine-4.63/pine-ldap3.patch
new file mode 100644
index 0000000000..a824438fbd
--- /dev/null
+++ b/packages/pine/pine-4.63/pine-ldap3.patch
@@ -0,0 +1,11 @@
+--- pine4.63/pine/bldaddr.c.orig 2005-07-12 15:40:04.000000000 +0200
++++ pine4.63/pine/bldaddr.c 2005-07-12 15:40:14.000000000 +0200
+@@ -6504,7 +6504,7 @@
+ ldap_v3_is_supported(ld)
+ LDAP *ld;
+ {
+- int v3_is_supported_by_server = 0;
++ int v3_is_supported_by_server = 1;
+ #ifdef NO_VERSION3_PROTO_YET
+ /*
+ * When we use version 3 protocol we will be getting back utf8 results.
diff --git a/packages/pine/pine-4.63/transparency.patch b/packages/pine/pine-4.63/transparency.patch
new file mode 100644
index 0000000000..890cf13f6c
--- /dev/null
+++ b/packages/pine/pine-4.63/transparency.patch
@@ -0,0 +1,14 @@
+diff -ru pine4.55-orig/pico/osdep/unix pine4.55/pico/osdep/unix
+--- pine4.55-orig/pico/osdep/unix 2003-04-15 17:20:22.000000000 -0500
++++ pine4.55/pico/osdep/unix 2003-06-23 13:05:19.000000000 -0500
+@@ -998,7 +998,9 @@
+ if(ANSI_COLOR()){
+ char buf[10];
+
+- if(color < 8)
++ if(color == 0)
++ memcpy(buf, "\033[49m", 6);
++ else if(color < 8)
+ sprintf(buf, "\033[4%cm", color + '0');
+ else
+ sprintf(buf, "\033[10%cm", (color-8) + '0');
diff --git a/packages/pine/pine_4.63.bb b/packages/pine/pine_4.63.bb
new file mode 100644
index 0000000000..87cf602c96
--- /dev/null
+++ b/packages/pine/pine_4.63.bb
@@ -0,0 +1,82 @@
+DESCRIPTION = "Pine(R) - a Program for Internet News & Email"
+PR = "r1"
+SECTION = "console/network"
+LICENSE = "Pine"
+DEPENDS = "ncurses libldap"
+RDEPENDS_pine = "pico"
+HOMEPAGE = "http://www.washington.edu/pine/"
+MAINTAINER = "Michael 'Mickey' Lauer <mickey_at_Vanille.de>"
+
+SRC_URI = "ftp://ftp.cac.washington.edu/pine/pine.tar.bz2 \
+ file://pine-4.63/pine-4.63-r2-chappa-all.patch;patch=1 \
+ file://pine-4.63/pine-4.62-spooldir-permissions.patch;patch=1 \
+ file://pine-4.63/pine-4.30-ldap.patch;patch=1 \
+ file://pine-4.63/pine-ldap3.patch;patch=1 \
+ file://pine-4.63/pine-4.56-passfile.patch;patch=1 \
+ file://pine-4.63/pine-4.61-largeterminal.patch;patch=1 \
+ file://pine-4.63/pine-4.31-segfix.patch;patch=1 \
+ file://pine-4.63/pine-4.40-lockfile-perm.patch;patch=1 \
+ file://pine-4.63/imap-2000-time.patch;patch=1 \
+ file://pine-4.63/transparency.patch;patch=1 \
+ file://pine-4.63/pine-4.61-subjectlength.patch;patch=1"
+
+S = "${WORKDIR}/pine${PV}"
+
+inherit autotools
+
+#
+# ~lart Pine's build structure...
+#
+PARALLEL_MAKE = ""
+EXTRA_OEMAKE = "-e"
+export MAKE = 'MAKE="make -e" make -e'
+
+CFLAGS += "-I${S}/imap/c-client"
+LDFLAGS += "${S}/imap/c-client/c-client.a -lssl -lcrypt"
+
+export SSLDEFINES = "-DSSL_CERT_DIRECTORY=\\"/etc/ssl/certs\\" -DSSL_KEY_DIRECTORY=\\"/etc/ssl/private\\""
+export SSLCFLAGS = "${CFLAGS} -I${STAGING_INCDIR}/openssl ${SSLDEFINES}"
+export SSLLDFLAGS = "-lssl -lcrypt ${LDFLAGS} -L${STAGING_LIBDIR}/openssl"
+export LDAPCFLAGS = "-DENABLE_LDAP"
+export LDAPLIBS = "-lldap -llber"
+export EXTRALDFLAGS = "${LDFLAGS}"
+
+do_configure() {
+ ln -sf ${S}/imap/c-client ${S}/c-client
+ cd ${S}/pico/osdep && \
+ ${BUILD_CC} -o includer includer.c
+ cd ${S}/pine/osdep && \
+ ${BUILD_CC} -o includer includer.c
+ mkdir ${S}/ldap
+ cd ${S}/ldap &&
+ ln -sf ${STAGING_INCDIR} include &&
+ ln -sf ${STAGING_LIBDIR} libraries
+ cd ${S}
+ sed -e "s:/usr/local/lib/pine.conf:/etc/pine.conf:" \
+ -i "${S}/pine/osdep/os-lnx.h" || exit 1
+ ls -l ${S}/contrib/ldap-setup
+}
+
+do_compile() {
+ unset CFLAGS && unset LDFLAGS
+ cd ${S}/imap && oe_runmake slx
+
+ for i in pico pine
+ do
+ cd ${S}/$i && oe_runmake -f makefile.lnx
+ done
+}
+
+BINARIES = "imap/mailutil/mailutil imap/mlock/mlock pico/pico pico/pilot pine/pine"
+
+do_install() {
+ install -d 0644 ${D}${bindir}
+ for binary in ${BINARIES}
+ do
+ install -m 0755 $binary ${D}${bindir}
+ done
+}
+
+PACKAGES = "pico pine"
+FILES_pico = "${bindir}/pico ${bindir}/pilot"
+