diff options
author | Oyvind Repvik <nail@nslu2-linux.org> | 2005-08-02 15:46:39 +0000 |
---|---|---|
committer | OpenEmbedded Project <openembedded-devel@lists.openembedded.org> | 2005-08-02 15:46:39 +0000 |
commit | e1d810e915c961d01100a697e9c077328048ffd4 (patch) | |
tree | b95a86025f4117220cd1669c0cdea86c82841ba6 | |
parent | 4ae0c9e63f7ea08e9ad2b74bfc8b2781b5ceee08 (diff) | |
parent | 2c2c957d5b8a09b6bbe1046d802eabf1fc621f59 (diff) |
merge of 0aba4d5c115b944af22e79b2d43f8d1848724fc2
and 1aebe30c46f7b39a3a73dcd30e1227c1a403f1bd
-rw-r--r-- | packages/pine/pine-4.63/.mtn2git_empty | 0 | ||||
-rw-r--r-- | packages/pine/pine-4.63/imap-2000-time.patch | 56 | ||||
-rw-r--r-- | packages/pine/pine-4.63/pine-4.30-ldap.patch | 11 | ||||
-rw-r--r-- | packages/pine/pine-4.63/pine-4.31-segfix.patch | 17 | ||||
-rw-r--r-- | packages/pine/pine-4.63/pine-4.40-lockfile-perm.patch | 22 | ||||
-rw-r--r-- | packages/pine/pine-4.63/pine-4.56-passfile.patch | 12 | ||||
-rw-r--r-- | packages/pine/pine-4.63/pine-4.61-largeterminal.patch | 14 | ||||
-rw-r--r-- | packages/pine/pine-4.63/pine-4.61-subjectlength.patch | 59 | ||||
-rw-r--r-- | packages/pine/pine-4.63/pine-4.62-spooldir-permissions.patch | 12 | ||||
-rw-r--r-- | packages/pine/pine-4.63/pine-4.63-r2-chappa-all.patch | 21900 | ||||
-rw-r--r-- | packages/pine/pine-4.63/pine-ldap3.patch | 11 | ||||
-rw-r--r-- | packages/pine/pine-4.63/transparency.patch | 14 | ||||
-rw-r--r-- | packages/pine/pine_4.63.bb | 131 |
13 files changed, 22205 insertions, 54 deletions
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 ---- + <End of Configuration Notes> + </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 <chappa@math.washington.edu>. Include the word ++ "Pine" 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 áé or other foreing characters: ñ 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 ---- + <End of help on this topic> + </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> ++ <End of help on this topic> ++ </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 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 "Date" should be almost ++ identical to sorting by "Arrival". ++ ++ <P> ++ <End of help on this topic> ++ </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> ++ <End of help on this topic> ++ </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 INDEX screen is ++ the same as sorting by <A HREF="h_thread_index_sort_subj">Subject</A>. ++ ++ <P> ++ <End of help on this topic> ++ </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 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> ++ <End of help on this topic> ++ </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> ++ <End of help on this topic> ++ </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> ++ <End of help on this topic> ++ </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> ++ <End of help on this topic> ++ </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> ++ <End of help on this topic> ++ </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> ++ <End of help on this topic> ++ </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 ">". ++ ++ <P> ++ Some other constructions of quote strings are recognized only if they ++ appear enough in the text. For example "Peter :" 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 "*" 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 "." or ":". ++ 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> + <End of help on this topic> + </BODY> + </HTML> +*************** +*** 17318,17323 **** +--- 17573,17579 ---- + <A HREF="h_config_index_format">"Index-Format"</A> option, + in the <A HREF="h_config_reply_intro">"Reply-Leadin"</A> option, + in signature files, ++ in the <A HREF="h_config_reply_leadin_rules">"new-rules" option</A>, + in template files used in + <A HREF="h_rules_roles">"roles"</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, "mailbox@domain". + </DD> + ++ <DT>ADDRESSTO</DT> ++ <DD> ++ This is similar to the "TO" token, only it is always the ++ email address of all people listed in the TO: field of the messages. Addresses ++ are separated by a blank space. Example, "mailbox@domain" when ++ the e-mail message contains only one person in the To: field, or ++ "peter@flintstones.com president@world.com". ++ </DD> ++ + <DT>MAILBOX</DT> + <DD> + This is the same as the "ADDRESS" except that the +*************** +*** 17399,17404 **** +--- 17664,17678 ---- + message's "Cc:" header field. + </DD> + ++ <DT>ADDRESSCC</DT> ++ <DD> ++ This is similar to the "CC" token, only it is always the ++ email address of all people listed in the Cc: field of the messages. Addresses ++ are separated by a blank space. Example: "mailbox@domain" when ++ the e-mail message contains only one person in the Cc: field, or ++ "peter@flintstones.com president@world.com". ++ </DD> ++ + <DT>RECIPS</DT> + <DD> + This token represents the personal names (or email addresses if the names +*************** +*** 17407,17412 **** +--- 17681,17694 ---- + the message's "Cc:" 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> ++ <End of help on this topic> ++ </BODY> ++ </HTML> + ======= h_address_format ======= + <HTML> + <HEAD> +*************** +*** 19988,20048 **** + <End of help on this topic> + </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 "Literal-Signature" by default. However, if no +- "Literal-Signature" is defined and the file named in the +- "Signature-File" option exists, then the latter will be used +- instead. + <P> +! +! The two character sequence \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 \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> + <End of help on this topic> + </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 "Signature-File" option will be ignored. +! You can tell that that is the case because the value of the +! "Signature-File" will show up as + <P> +! <CENTER><SAMP><Ignored: using Literal-Signature instead></SAMP></CENTER> + <P> + You may either use all Literal Signatures (signatures stored in your + configuration file) throughout Pine, or all signature files. +--- 20367,20523 ---- + <End of help on this topic> + </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> + <End of help on this topic> + </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 "#md/inbox" (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 "mail/" to +! "#md/mail". 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> +! <End of help on this topic> +! </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 "Literal-Signature" by default. However, if no +! "Literal-Signature" is defined and the file named in the +! "Signature-File" option exists, then the latter will be used +! instead. +! <P> +! +! The two character sequence \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 \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> +! <End of help on this topic> +! </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 "Signature-File" option will be ignored. +! You can tell that that is the case because the value of the +! "Signature-File" will show up as +! <P> +! <CENTER><SAMP><Ignored: using Literal-Signature instead></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 ---- + <End of help on this topic> + </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 ++ "Thread". ++ ++ <P> ++ <UL> ++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A> ++ </UL><P> ++ <End of help on this topic> ++ </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 "fullname-with-lists-last". + + <P> +! <UL> + <LI><A HREF="h_finding_help">Finding more information and requesting help</A> + </UL><P> + <End of help on this topic> +--- 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 "fullname-with-lists-last". +! +! <P> +! <UL> +! <LI><A HREF="h_finding_help">Finding more information and requesting help</A> +! </UL><P> +! <End of help on this topic> +! </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><End of help on this topic> +! </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><End of help on this topic> +! </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><End of help on this topic> +! </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_{\[some-tag-here #[0-9].*\]} +! +! <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><End of help on this topic> +! </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ó _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><End of help on this topic> +! </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 "Re:" +! to "AW:" or "Sv:". 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><End of help on this topic> +! </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><End of help on this topic> +! +! </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><End of help on this topic> +! +! </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><End of help on this topic> +! +! </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">"smtp-server"</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><End of help on this topic> +! +! </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><End of help on this topic> +! +! </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} => _SAVE_{Fred} +! +! <P> +! Here the separator is "=>". 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 "=>", 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} => _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": <<, !<, >>, !>, == +! and !=. All of them are two strings long. Here is the meaning of them: +! +! <P> +! <UL> +! <LI> << : It tests if the value of the token is contained in +! the condition set. Here for example if the condition set were equal to +! "Freddy", then the condition: _NICK_ << {Freddy}, would be true if +! the value of _NICK_ were "Fred", "red" or "Freddy". You are just looking +! for substrings here. +! <LI> >> : It tests if the value of the token contains the value of +! the condition set. Here for example if the condittion set were equal to +! "Fred", then the condition: _FROM_ >> {Fred}, would be true if +! the value of _FROM_ were "Fred 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> !< : This is true only when << is false and viceversa. +! <LI> !> : This is true only when >> 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_ << {folder1; folder2} => _SORT_{OrderedSubj} +! +! <P> +! Here is the first subtelty about these definitions. Notice that the +! following rule: +! +! <P> +! _FOLDER_ == {folder1; folder2} => _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" << " 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} => _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} -> lynx <BR> +! This, is an abreviation of the following rule:<BR> +! _FOLDER_ == {Lynx} => _SAVE_{lynx} <BR> +! (note the change in separator from "=>" to "->"). In the future +! I will use that abreviation. +! +! <P> _FOLDER_ << {comp.mail.pine; pine-info; pine-alpha} -> pine <BR> +! Any message in the folders "comp.mail.pine", "pine-info" or "pine-alpha" +! will be saved to the folder "pine". +! +! <P> _FROM_ << {Pine Master} -> pine <BR> +! Any message whose From field contains +! "Pine Master" will be saved in the folder pine. +! +! <P> _FOLDER_ << {Lynx; pine-info; comp.mail.pine} => +! _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} => _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_ << {Lynx; comp.mail.pine; pine_info; pine-alpha} => +! _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_ << {Lynx} => _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_ >> {Name (Comment)} => _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_ == {} => _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} => _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_ >> {bug report} && _SUBJECT_ !> {Re: } => _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> + <End of help on this topic> +*************** +*** 21032,21037 **** +--- 22186,22227 ---- + <End of help on this topic> + </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> ++ <End of help on this topic> ++ </BODY> ++ </HTML> + ====== h_config_display_filters ===== + <HTML> + <HEAD> +*************** +*** 21850,21855 **** +--- 23040,23077 ---- + <End of help on this topic> + </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> ++ <End of help on this topic> ++ </BODY> ++ </HTML> + ====== h_config_incoming_folders ===== + <HTML> + <HEAD> +*************** +*** 24123,24128 **** +--- 25345,25420 ---- + <End of help on this topic> + </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> ++ <End of help on this topic> ++ </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> ++ <End of help on this topic> ++ </BODY> ++ </HTML> + ====== h_config_pruning_rule ===== + <HTML> + <HEAD> +*************** +*** 24416,24421 **** +--- 25708,25758 ---- + <End of help on this topic> + </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 "automatic". ++ ++ <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> ++ <End of help on this topic> ++ </BODY> ++ </HTML> + ====== h_config_browser ===== + <HTML> + <HEAD> +*************** +*** 25490,25495 **** +--- 26827,26909 ---- + <End of help on this topic> + </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 ---- + <End of help on this topic> + </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> ++ <End of help on this topic> ++ </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 ---- + <End of help on this topic> + </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 "S Strip Sig", it means that if you press the letter ++ "S" the signature will be stripped off the message you are ++ replying. Observer that the menu will change to ++ "S No Strip", which means that if you press "S", 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> ++ <End of help on this topic> ++ </BODY> ++ </HTML> + ====== h_config_del_from_dot ===== + <HTML> + <HEAD> +*************** +*** 27077,27082 **** +--- 28586,28634 ---- + <End of help on this topic> + </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 "#mc/" ++ prefix instead of the "#md/" 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 "folder[.]", or as two entries in the ++ list by "folder" and "folder.". ++ <P> ++ If this option is disabled, Pine will list local folders that are in Courier ++ style format, as "folder", and those that are also directories as ++ "folder[.]". 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 "foo" simply add "foo.bar" directly. This will ++ create the directory "foo" and the subfolder "bar" 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> ++ <End of help on this topic> ++ </BODY> ++ </HTML> + ====== h_config_verbose_post ===== + <HTML> + <HEAD> +*************** +*** 27228,27233 **** +--- 28780,28808 ---- + <End of help on this topic> + </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">"read-message-folder"</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">"save-rules"</A> and mark ++ them as deleted in the INBOX. Messages in the INBOX marked with an ++ "N" (meaning New, or unseen) are not affected. ++ <P> ++ <UL> ++ <LI><A HREF="h_finding_help">Finding more information and requesting help</A> ++ </UL><P> ++ <End of help on this topic> ++ </BODY> ++ </HTML> + ====== h_config_auto_fcc_only ===== + <HTML> + <HEAD> +*************** +*** 27616,27621 **** +--- 29191,29213 ---- + <End of help on this topic> + </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> ++ <End of help on this topic> ++ </BODY> ++ </HTML> + ====== h_config_news_cross_deletes ===== + <HTML> + <HEAD> +*************** +*** 28224,28229 **** +--- 29816,29842 ---- + <End of help on this topic> + </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">"auto-open-next-unread"</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> ++ <End of help on this topic> ++ </BODY> ++ </HTML> + ====== h_config_auto_include_reply ===== + <HTML> + <HEAD> +*************** +*** 28715,28720 **** +--- 30328,30357 ---- + <End of help on this topic> + </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> ++ <End of help on this topic> ++ </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 index b8a11639a6..87cf602c96 100644 --- a/packages/pine/pine_4.63.bb +++ b/packages/pine/pine_4.63.bb @@ -1,59 +1,82 @@ -DESCRIPTION = "Pine(R) - a Program for Internet News & Email" -SECTION = "console/network" -LICENSE = "Pine" -DEPENDS = "ncurses" -RDEPENDS_pine = "pico" -HOMEPAGE = "http://www.washington.edu/pine/" -MAINTAINER = "Michael 'Mickey' Lauer <mickey@Vanille.de>" +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${PV}.tar.bz2" -S = "${WORKDIR}/pine${PV}" +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" -inherit autotools +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 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 -} - -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" +# +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" |