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 + 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 + * 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 + #include + #include + extern int errno; /* just in case */ + #include "mail.h" + #include "osdep.h" + #include + #include + #include + #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 or or *************** *** 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 or or * 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 or or * 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 or or * *************** *** 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 "; 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 \tSort - Specify sort order of folder:", + " -threadsort \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 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 + + #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,"message_id,"message_id,"message_id,"message_id,"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 ----

Some topics of current interest include:

    +

  • Information on patches for this release

  • Mail Drops

  • Information on Folder Locking

  • Information on Missing mail and the mbox driver *************** *** 1081,1086 **** --- 1082,1143 ---- <End of Configuration Notes> + ====== h_patches ====== + + + Information on patches added to this release + + +

    Information on patches added to this release

    +

    + This version of Pine has been modified by including patches from + + http://www.math.washington.edu/~chappa/pine/. These patches include + new features and bug fixes. More complete information on each patch + included in this version can be found in the web. + +

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

    The list of patches included in this release are: + +

    New Features: + +

      +
    • Maildir Patch. (more...) +
    • Enhanced fancy thread interface. + (more...) +
    • Pine justifies paragraphs with more than one level of indentation. + (more...) +
    • Rules patch, to make Pine flexible. + (more...) +
    • Send mail from the command line. +
    • Automatic check of new mail in incoming folders. + (more...) +
    • Write accents like áé or other foreing characters: ñ etc. +
    • Tab check folders on cycles. + (more...) +
    • Get the number of new messages when opening a folder. +
    • Reinsert the pattern you searched for last. +
    • New Reply command menu. + (more...) +
    • Change your From header without any effort! +
    • Choose a role when composing a message from a mailto: link. +
    • Paint special text in the body of the message in any custom color. + (more...) +
    • Select messages by the content of an arbitrary header. +
    • Delete until the the end of a file, or message (press ^W^X). +
    • Get the QUOTA information from an IMAP server (if such server supports + the QUOTA command). +
    +

    Bug Fixes: +

      +
    • Fix a bug which could make the sort by score be computed incorrectly. +
    + + + ====== h_news_legal ====== *************** *** 3091,3097 **** --- 3148,3156 ----
  • FEATURE: Alternate-Role-Menu
  • FEATURE: Assume-Slow-Link
  • FEATURE: Auto-Move-Read-Msgs +
  • FEATURE: auto-move-read-msgs-using-rules
  • FEATURE: Auto-Open-Next-Unread +
  • FEATURE: enable-circular-tab
  • FEATURE: Auto-Unzoom-After-Apply
  • FEATURE: Auto-Zoom-After-Select
  • FEATURE: Check-Newmail-When-Quitting *************** *** 3349,3354 **** --- 3408,3414 ----
  • OPTION: Addressbook-Formats
  • OPTION: Alt-Addresses
  • OPTION: Character-Set +
  • OPTION: Special Text to Color
  • OPTION: Color-Style
  • OPTION: Composer-Wrap-Column
  • OPTION: Current-Indexline-Style *************** *** 3449,3457 **** --- 3509,3519 ----
  • OPTION: Sending-Filters
  • OPTION: Sendmail-Path
  • OPTION: Signature Color +
  • OPTION: Special Text Color
  • OPTION: Signature-File
  • OPTION: SMTP-Server
  • OPTION: Sort-Key +
  • OPTION: Thread-Sort-Key
  • OPTION: Speller
  • OPTION: Ssh-Command
  • OPTION: Ssh-Open-Timeout *************** *** 5297,5302 **** --- 5359,5517 ---- <End of help on this topic> + ======= h_thread_index_sort_arrival ======= + + + SORT OPTION: Arrival + + +

    SORT OPTION: Arrival

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

    + <End of help on this topic> + + + ======= h_thread_index_sort_date ======= + + + SORT OPTION: Date + + +

    SORT OPTION: Date

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

    + On a folder like INBOX, sorting by "Date" should be almost + identical to sorting by "Arrival". + +

    + <End of help on this topic> + + + ======= h_thread_index_sort_subj ======= + + + SORT OPTION: Subject + + +

    SORT OPTION: Subject

    + + The Subject sort option has not been defined yet. + +

    + <End of help on this topic> + + + ======= h_thread_index_sort_ordsubj ======= + + + SORT OPTION: OrderedSubject + + +

    SORT OPTION: OrderedSubject

    + + The OrderedSubject sort option in the THREAD INDEX screen is + the same as sorting by Subject. + +

    + <End of help on this topic> + + + ======= h_thread_index_sort_thread ======= + + + SORT OPTION: Thread + + +

    SORT OPTION: Thread

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

    + <End of help on this topic> + + + ======= h_thread_index_sort_from ======= + + + SORT OPTION: From + + +

    SORT OPTION: From

    + + The From sort option has not been defined yet. + +

    + <End of help on this topic> + + + ======= h_thread_index_sort_size ======= + + + SORT OPTION: Size + + +

    SORT OPTION: Size

    + + The Size sort option has not been defined yet. + +

    + <End of help on this topic> + + + ======= h_thread_index_sort_score ======= + + + SORT OPTION: Score + + +

    SORT OPTION: Score

    + + The Score sort option has not been defined yet. + +

    + <End of help on this topic> + + + ======= h_thread_index_sort_to ======= + + + SORT OPTION: To + + +

    SORT OPTION: To

    + + The To sort option has not been defined yet. + +

    + <End of help on this topic> + + + ======= h_thread_index_sort_cc ======= + + + SORT OPTION: Cc + + +

    SORT OPTION: Cc

    + + The Cc sort option has not been defined yet. + +

    + <End of help on this topic> + + ======= h_index_cmd_whereis ======= *************** *** 6515,6520 **** --- 6730,6775 ---- not preserved.

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

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

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

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

      +
    • Fruit +
    • Bread +
    • Eggs +
    + +

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

    <End of help on this topic> *************** *** 17318,17323 **** --- 17573,17579 ---- "Index-Format" option, in the "Reply-Leadin" option, in signature files, + in the "new-rules" option, in template files used in "roles", and in the folder name that is the target of a Filter Rule. *************** *** 17330,17336 ****

    !

    Tokens Available for all Cases (except Filter Rules)

    SUBJECT
    --- 17586,17592 ----

    !

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

    SUBJECT
    *************** *** 17352,17357 **** --- 17608,17622 ---- For example, "mailbox@domain". +
    ADDRESSTO
    +
    + This is similar to the "TO" token, only it is always the + email address of all people listed in the TO: field of the messages. Addresses + are separated by a blank space. Example, "mailbox@domain" when + the e-mail message contains only one person in the To: field, or + "peter@flintstones.com president@world.com". +
    +
    MAILBOX
    This is the same as the "ADDRESS" except that the *************** *** 17399,17404 **** --- 17664,17678 ---- message's "Cc:" header field.
    +
    ADDRESSCC
    +
    + This is similar to the "CC" token, only it is always the + email address of all people listed in the Cc: field of the messages. Addresses + are separated by a blank space. Example: "mailbox@domain" when + the e-mail message contains only one person in the Cc: field, or + "peter@flintstones.com president@world.com". +
    +
    RECIPS
    This token represents the personal names (or email addresses if the names *************** *** 17407,17412 **** --- 17681,17694 ---- the message's "Cc:" header field.
    +
    ADDRESSRECIPS
    +
    + This token represent the e-mail addresses of the people in the To: and + Cc: fields, exactly in that order separated by a space. It is almost obtained + by concatenating the ADDRESSTO and ADDRESSCC tokens. +
    + +
    NEWSANDRECIPS
    This token represents the newsgroups from the *************** *** 17779,17784 **** --- 18061,18074 ----

    +
    SIZETHREAD
    +
    + 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. +
    +
    SIZENARROW
    This token represents the total size, in bytes, of the message. *************** *** 18134,18139 **** --- 18424,18501 ----

    +

    Tokens Available Only for New-Rules

    + +
    +
    FOLDER
    +
    + Name of the folder where the rule will be applied +
    +
    + +
    +
    COLLECTION
    +
    + Name of the collection list where the rule will be applied. +
    +
    + +
    +
    ROLE
    +
    + Name of the Role used to reply a message. +
    +
    + +
    +
    BCC
    +
    + Not implemented yet, but it will be implemented in future versions. It will + be used for compose + reply + forward + rules. +
    +
    + +
    +
    LCC
    +
    + This is the value of the Lcc: field at the moment that you start the composition. +
    +
    + +
    +
    FORWARDFROM
    +
    + This corresponds to the personal name (or address if there's no personal + name) of the person who sent the message that you are forwarding. +
    +
    + +
    +
    FORWARDADDRESS
    +
    + This is the address of the person that sent the message that you + are forwarding. +
    +
    + + + + +
    +
    FLAG
    +
    + A string containing the value of all the flags associated to a specific + message. The possible values of allowed flags are "*" for Important, "N" + for recent or new, "U" for unseen or unread, "R" for seen or read, "A" for + answered and "D" for deleted. See an example of its use in the + new rules explanation and example help. +
    +
    + +

    Token Available Only for Templates and Signatures

    *************** *** 18866,18871 **** --- 19228,19250 ---- be combined with the other fields if you'd like. + ====== h_config_check_inc_fld ====== + + + OPTION: incoming-folders-to-check + + +

    OPTION: incoming-folders-to-check

    +

    + if you set this option and + enable-check-incoming-folders 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. +

    + <End of help on this topic> + + ======= h_address_format ======= *************** *** 19988,20048 **** <End of help on this topic> ! ====== h_config_literal_sig ===== ! OPTION: Literal-Signature !

    OPTION: Literal-Signature

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

    - 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 - Signature-File so look there for - help.

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

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

    !

    <End of help on this topic> ! ====== h_config_signature_file ===== ! OPTION: Signature-File !

    OPTION: Signature-File

    ! If a Literal-Signature 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

    !

    <Ignored: using Literal-Signature instead>

    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> ! ====== h_config_maildir_location ====== ! OPTION: maildir-location !

    OPTION: maildir-location

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

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

    ! The value of this option is prefixed with the "~/" string to determine the ! full path to your INBOX.

    ! You should probably read a few tips that ! teach you how to configure your maildir for optimal performance. This ! version also has support for the ! Courier style file system when a maildir collection is accessed locally. ! !

    !

    <End of help on this topic> ! ====== h_config_maildir ===== ! Maildir Support !

    Maildir Support

    ! This version of Pine has been enhanced with Maildir support. This text is ! intended to be a reference on its support.

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

    ! ! 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 maildir-location 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. !

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

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

    Finally, This version also has ! support for the Courier style file system ! when a maildir collection is accessed locally. ! !

    !

    ! <End of help on this topic> ! ! ! ====== h_config_literal_sig ===== ! ! ! OPTION: Literal-Signature ! ! !

    OPTION: Literal-Signature

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

    ! ! 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 ! Signature-File so look there for ! help. !

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

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

    !

    ! <End of help on this topic> ! ! ! ====== h_config_signature_file ===== ! ! ! OPTION: Signature-File ! ! !

    OPTION: Signature-File

    ! ! If a Literal-Signature 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 !

    !

    <Ignored: using Literal-Signature instead>

    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> + ====== h_config_thread_sort_key ===== + + + OPTION: Thread-Sort-Key + + +

    OPTION: Thread-Sort-Key

    + + This option determines the order in which threads will be displayed. You + can choose from the following options. + +

    +

    + +

    Each type of sort may also be reversed. Normal default is by + "Thread". + +

    +

    + <End of help on this topic> + + ====== h_config_other_startup ===== *************** *** 20866,20898 **** This option controls the order in which address book entries will be presented. Choose one of the following: !

    !
    fullname
    !
    use fullname field, lists mixed in !
    !
    fullname-with-lists-last
    !
    use fullname field, but put lists at end !
    !
    nickname
    !
    use nickname field, lists mixed in !
    !
    nickname-with-lists-last
    !
    use nickname field, but put lists at end !
    !
    dont-sort
    !
    don't change order of file !
    !

    ! The normal default is "fullname-with-lists-last".

    !

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

    !
    fullname
    !
    use fullname field, lists mixed in !
    ! !
    fullname-with-lists-last
    !
    use fullname field, but put lists at end !
    ! !
    nickname
    !
    use nickname field, lists mixed in !
    ! !
    nickname-with-lists-last
    !
    use nickname field, but put lists at end !
    ! !
    dont-sort
    !
    don't change order of file !
    !
    ! !

    ! The normal default is "fullname-with-lists-last". ! !

    !

    ! <End of help on this topic> ! ! ! ====== h_config_compose_rules ===== ! ! ! OPTION: Compose-Rule ! ! !

    OPTION: Compose-Rule

    ! !

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

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

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

    <End of help on this topic> ! ! ! ====== h_config_forward_rules ===== ! ! ! OPTION: Forward-Rule ! ! !

    OPTION: Forward-Rule

    ! !

    At this time this option can be used to trim values of some fields, ! for example it can be used in the following way: ! !

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

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

    <End of help on this topic> ! ! ! ====== h_config_index_rules ===== ! ! ! OPTION: Index-Rule ! ! !

    OPTION: Index-Rule

    ! !

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

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

    This configuration option is just one of many that allow you to ! override the value of some global configurations within Pine. There is a ! help text explaining how to define all of them, which you can read by ! following this link. ! !

    <End of help on this topic> ! ! ! ====== h_config_replace_rules ===== ! ! ! OPTION: Replace-Rule ! ! !

    OPTION: Replace-Rule

    ! !

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

    Here are examples of possible rules:
    ! _FOLDER_ != {sent-mail} && _NICK_ != {} => _FROM_ := _REPLACE_{_FROM_ (_NICK_)} ! !

    or if you receive messages with tags that contain arbitrary numbers, and ! you want them removed from the index (but not from the subject), use a rule ! like the following
    ! _FOLDER_ == {INBOX} => _SUBJECT_ := _REXTRIM_{\[some-tag-here #[0-9].*\]} ! !

    You can also use this configuration option to remove specific strings of ! the index display screen, so that you can trim unnecessary information in ! your index. ! !

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

    <End of help on this topic> ! ! ! ====== h_config_reply_leadin_rules ===== ! ! ! OPTION: Reply-Leadin-Rule ! ! !

    OPTION: Reply-Leadin-Rule

    ! !

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

    Here there are examples of how this can be used. One can use the definition ! below to post to newsgroups and the pine-info mailing list, say: !

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

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

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

    This configuration option is just one of many that allow you to ! override the value of some global configurations within Pine. There is a ! help text explaining how to define all of them, which you can read by ! following this link. ! !

    <End of help on this topic> ! ! ! ====== h_config_resub_rules ===== ! ! ! OPTION: Replace-Subject-Rule ! ! !

    OPTION: Replace-Subject-Rule

    ! !

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

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

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

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

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

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

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

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

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

    ! would eliminate undesired strings in replies. ! !

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

    This configuration option is just one of many that allow you to ! override the value of some global configurations within Pine. There is a ! help text explaining how to define all of them, which you can read by ! following this link. ! !

    <End of help on this topic> ! ! ! ====== h_config_sort_rules ===== ! ! ! OPTION: Sort-Rule ! ! !

    OPTION: Sort-Rule

    ! !

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

    Here's an example of the way it can be used. In this case all incoming ! folders are mailing lists, except for INBOX, so we sort INBOX by arrival ! (which is the default type of sort), but we want all the rest of mailing ! lists and newsgroups to be sorted by thread. ! !

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

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

    This configuration option is just one of many that allow you to ! override the value of some global configurations within Pine. There is a ! help text explaining how to define all of them, which you can read by ! following this link. ! !

    <End of help on this topic> ! ! ! ! ====== h_config_save_rules ===== ! ! ! OPTION: Save-Rules ! ! !

    OPTION: Save-Rules

    ! !

    This option is used to specify which folder should be used to save a ! message depending either on the folder the message is in, who the message ! is from, or text that the message contains in specific headers (Cc:, ! Subject:, etc). ! !

    If this option is set and the ! auto-move-read-msgs configuration ! option is also set then these definitions will be used to move messages ! from your INBOX when exiting Pine. ! !

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

    This configuration option is just one of many that allow you to ! override the value of some global configurations within Pine. There is a ! help text explaining how to define all of them, which you can read by ! following this link. ! !

    <End of help on this topic> ! ! ! ! ====== h_config_reply_indent_rules ===== ! ! ! OPTION: Reply-indent-Rule ! ! !

    OPTION: Reply-indent-Rule

    ! !

    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 reply-indent-string ! is used. ! !

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

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

    <End of help on this topic> ! ! ! ! ====== h_config_smtp_rules ===== ! ! ! OPTION: SMTP-Rule ! ! !

    OPTION: SMTP-Rule

    ! !

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

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

    This configuration option is just one of many that allow you to ! override the value of some global configurations within Pine. There is a ! help text explaining how to define all of them, which you can read by ! following this link. ! !

    <End of help on this topic> ! ! ! ! ====== h_config_startup_rules ===== ! ! ! OPTION: Startup-Rule ! ! !

    OPTION: Startup-Rule

    ! !

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

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

    This configuration option is just one of many that allow you to ! override the value of some global configurations within Pine. There is a ! help text explaining how to define all of them, which you can read by ! following this link. ! !

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

    OPTION: New Rules Explained

    ! ! This is a quite powerful option. Here you can define rules that override ! the values of any other global rule you have globally set in pine. ! !

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

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

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

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

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

    ! Here is an example: ! !

    ! _FROM_ == {Fred Flinstone} => _SAVE_{Fred} ! !

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

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

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

    ! At the end of the document you will find more examples.Here is a short ! description of what each function does: ! !

    !

      !
    • _INDEX_ : This function takes as an argument an index-format, and ! makes that the index-format for the specified folder. !
    • _REPLACE_ : This function replaces the subject/from of the given e-mail by ! another subject/from only when displaying the index. !
    • _REPLY_ : This function takes as an argument a definition of a ! reply-leadin-string and makes this the reply-leading-string of the ! specified folder or person. !
    • _RESTR_ : This function takes as an argument the value of the ! reply-indent-string to be used to answer the message being replied to. !
    • _RESUB_ : This function replaces the subject of the given e-mail by ! another subject only when replying to a message. !
    • _SAVE_ : The save function takes as an argument the name of a ! possibly non existing folder, whenever you want to save a message, that ! folder will be offered for you to save. !
    • _SIGNATURE_ : This function takes as an argument a signature file and ! uses that file as the signature for the message you are about to ! compose/reply/forward. !
    • _SMTP_ : This function takes as an argument the definition of a ! SMTP server. !
    • _SORT_ : This function takes as an argument a Sort Style, and sorts a ! specified folder in that sort order. !
    • _TRIM_ : This function takes as an argument a list of strings that ! you want removed from another string. At this time this only works for ! _FROM_ and _SUBJECT_. !
    • _REXTRIM_ : Same as _TRIM_ but its argument is one and ! only one extended regular expression. !
    • _STARTUP_ : This function takes as an argument an ! incoming-startup-rule, and open an specified folder using that rule. !
    • _THREADSTYLE_ : This function takes as an argument a ! threading-display-style and uses it to display threads in a folder. !
    • _THREADINDEX_ : This function takes as an argument a ! threading-index-style and uses it to display threads in a folder. !
    ! !

    ! You must me wondering how to define the person/folder over who to apply ! the action. This is done in the condition. When you specify a rule, the ! rule is only executed if the condition is satisfied. In another words for ! the rule: ! !

    ! _FROM_ == {Fred Flinstone} => _SAVE_{Fred} ! !

    ! it will only be applied if the from is "Fred Flinstone", if the From is ! "Wilma Flinstone" the rule will be skipped. ! !

    In order to test a condition you can use the following tokens (in ! alphabetical order): _ADDRESS_,_CC_, _FOLDER_, _FROM_,_NICK_, _ROLE, ! _SENDER_, _SUBJECT_ and _TO_. The token will always be tested against what ! it is between "{" and "}" in the condition, this part of the condition is ! called the "condition set". The definition of each token can be found ! here. ! !

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

    !

      !
    • << : It tests if the value of the token is contained in ! the condition set. Here for example if the condition set were equal to ! "Freddy", then the condition: _NICK_ << {Freddy}, would be true if ! the value of _NICK_ were "Fred", "red" or "Freddy". You are just looking ! for substrings here. !
    • >> : It tests if the value of the token contains the value of ! the condition set. Here for example if the condittion set were equal to ! "Fred", then the condition: _FROM_ >> {Fred}, would be true if ! the value of _FROM_ were "Fred Flinstone" or "Fred P. Flinstone" or "Freddy". !
    • == : It tests if the value of the token is exactly equal to the value ! of the set condition. For example _NICK_ == {Fred} will be false if the value ! of _NICK_ is "Freddy" or "red". !
    • !< : This is true only when << is false and viceversa. !
    • !> : This is true only when >> is false and viceversa. !
    • != : This is true only when == is false and viceversa. !
    ! !

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

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

    ! Here is the first subtelty about these definitions. Notice that the ! following rule: ! !

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

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

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

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

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

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

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

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

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

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

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

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

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

    Note that at least for people you can create particular ! reply-leadin-string using the role features, but it does not work as this ! one does. This seems to be the right way to do it. ! !

    _FOLDER_ << {Lynx; comp.mail.pine; pine_info; pine-alpha} => ! _SORT_{OrderedSubj}
    This means upon opening, sort the folders "Lynx", ! "comp.mail.pine", etc in ordered subject. All the others use the default ! sort order. You can not sort in reverse in this form. The possible ! arguments of this function are listed in the definition of the ! default-sort-rule (Arrival, scorE, siZe, etc). ! !

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

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

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

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

    You can add more complexity to your rules by checking more than one ! conditions before a rule is executed. 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 ! !

    ! _SUBJECT_ == {bug report} => _RESUB_{Re: About your _SUBJECT_} ! !

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

    ! _SUBJECT_ >> {bug report} && _SUBJECT_ !> {Re: } => _RESUB_{Re: About your _SUBJECT_}
    !

    ! which will only add the string "Re: About your" only the first time the ! message is replied. !

    ! 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.
    ! _FOLDER_ == {comp.mail.pine} && _FROM_ == {Fred Flinstones} => _FROM_ := _REPLACE_{_FROM_} !

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

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

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

    ! The reason why the above test is not "_FLAG_ == {D}" is because that would mean ! that this is the only flag set in the message. It's better to test by containment in this case. ! !

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

    Finally about the question of which rule will be executed. Only the ! first rule that matches will be executed. It is important to notice though ! that "saving" rules do not compete with "sorting" rules. So the first ! "saving" rule that matches will be executed in the case of saving and so ! on. ! !

    Here are some things to do still: !

      !
    • To make _TRIM_ compatible with more tokens (_TO_, _SENDER_, etc) !
    • To make this list dissapear! !
    ! !

    !

    <End of help on this topic> *************** *** 21032,21037 **** --- 22186,22227 ---- <End of help on this topic> + ====== h_config_special_text_to_color ===== + + + OPTION: Special Text to Color + + +

    OPTION: Specil Text to Color

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

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

    + Pine will use the colors defined in the + Special Text Color variable. + to paint any match. + +

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

    +

    + <End of help on this topic> + + ====== h_config_display_filters ===== *************** *** 21850,21855 **** --- 23040,23077 ---- <End of help on this topic> + ====== h_config_inc_fld_timeo ===== + + + OPTION: inc-fld-timeout + + +

    OPTION: inc-fld-timeout

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

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

    + The default is 5 seconds, which is also the minimum and the maximum is 60. + +

    +

    + <End of help on this topic> + + ====== h_config_incoming_folders ===== *************** *** 24123,24128 **** --- 25345,25420 ---- <End of help on this topic> + ====== h_config_thread_display_style_rule ===== + + + OPTION: Threading-Display-Style-Rule + + +

    OPTION: Threading-Display-Style-Rule

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

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

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

    + The values that can be given for the _THREADSTYLE_ function are the + values of the threading-display-style function, which can be found + listed in the threading-display-style + configuration option. + +

    This configuration option is just one of many that allow you to + override the value of some global configurations within Pine. There is a + help text explaining how to define all of them, which you can read by + following this link. + +

    +

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

    OPTION: Threading-Index-Style-Rule

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

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

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

    + The values that can be given for the _THREADINDEX_ function are the + values of the threading-index-display function, which can be found + listed in the threading-index-display + configuration option. + +

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

    +

    + <End of help on this topic> + + ====== h_config_pruning_rule ===== *************** *** 24416,24421 **** --- 25708,25758 ---- <End of help on this topic> + ====== h_config_inc_rule ===== + + + OPTION: Incoming-Check-Rule + + +

    OPTION: Incoming-Check-Rule

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

    + The three possible values for this option are: + +

    +
    automatic
    +
    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. +
    + +
    automatic-after-first-manual-check
    +
    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. +
    + +
    manual-only
    +
    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. +
    +
    + +

    + If you just want to stop Pine from checking in one folder, then simply + select that folder. Checks on that folder will be skipped. + +

    +

    + <End of help on this topic> + + ====== h_config_browser ===== *************** *** 25490,25495 **** --- 26827,26909 ---- <End of help on this topic> + ====== h_config_enable_check_incoming ====== + + + FEATURE: enable-check-incoming-folders + + +

    FEATURE: enable-check-incoming-folders

    + If you have enabled incoming + folders 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 incoming-folders-to-check. + +

    If you have the option + enable-fast-recent-test + disabled, 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 FOLDER LIST screen + for each folder listed in the variable + incoming-folders-to-check. The report for each + folder is made in the format + +

    + folder-name [Number of new messages/Number of messages in the folder] + +

    + If an incoming folder is not listed in the variable + incoming-folders-to-check, then only + the name of the folder and no other report is made about that folder. + +

    + Other important features related to this feature are: +

      +
    1. recheck-all-incoming-folders, + which allows you to decide if you want to check all folders every check, +
    2. incoming-check-rule, which determines + how and when Pine will check for new mail in your incoming folders. +
    + +

    +

    + + + ====== h_config_enable_recheck_incoming ====== + + + FEATURE: recheck-all-incoming-folders + + +

    FEATURE: recheck-all-incoming-folders

    + If you have enabled incoming folders + and enable-check-incoming-folder + 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. + +

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

    If you only use Pine to access your incoming folders, then DO NOT + enable this feature. + +

    +

    + + ====== h_config_attach_in_reply ====== *************** *** 25788,25793 **** --- 27202,27223 ---- <End of help on this topic> + ====== h_config_use_domain ===== + + + FEATURE: return-path-uses-domain-name + + +

    FEATURE: return-path-uses-domain-name

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

    + <End of help on this topic> + + ====== h_config_use_sender_not_x ===== *************** *** 25954,25959 **** --- 27384,27416 ---- successes. You will usually receive the full message back when there is a failure. +

    When this feature is disabled, and the feature + enable-check-incoming-folders + is enabled, then a full report of the number of messages and number of + new messages in each incoming folder listed in the option + incoming-folders-to-check is made. This + report is printed in the FOLDER LIST screen. The + report is given in the form + +

    + folder-name [Number of New Messages/Number of messages in the folder] + +

    If an incoming-folder is not listed in the variable + incoming-folders-to-check, no check for + that folder is made, so only the folder name, and no other information is + printed about that folder. + +

    If this feature is enabled and the feature + recheck-all-incoming-folders + 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. +

    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> + ====== h_config_alt_reply_menu ===== + + + FEATURE: alternate-reply-menu + + +

    FEATURE: alternate-reply-menu

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

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

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

    + The possible options are: + +

      +
    1. F: To decide if you want to send flowed text or not. This option appears + unless you have quelled sending flowed text. + +
    2. S: To strip the signature from a message, only available is the feature + enable-sigdashes or the + strip-from-sigdashes-on-reply option are + enabled. + +
    3. 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. +
    +

    + <End of help on this topic> + + ====== h_config_del_from_dot ===== *************** *** 27077,27082 **** --- 28586,28634 ---- <End of help on this topic> + ====== h_config_courier_list ===== + + + FEATURE: Courier-Folder-List + + +

    FEATURE: Courier-Folder-List

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

    + Depending on if you have enabled the option + separate-folder-and-firectory-entries + a folder may be listed as "folder[.]", or as two entries in the + list by "folder" and "folder.". +

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

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

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

    + <End of help on this topic> + + ====== h_config_verbose_post ===== *************** *** 27228,27233 **** --- 28780,28808 ---- <End of help on this topic> + ====== h_config_auto_read_msgs_rules ===== + + + FEATURE: auto-move-read-msgs-using-rules + + +

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

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

    +

    + <End of help on this topic> + + ====== h_config_auto_fcc_only ===== *************** *** 27616,27621 **** --- 29191,29213 ---- <End of help on this topic> + ====== h_config_enhanced_thread ===== + + + FEATURE: enhanced-fancy-thread-support + + +

    FEATURE: enhanced-fancy-thread-support

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

    + <End of help on this topic> + + ====== h_config_news_cross_deletes ===== *************** *** 28224,28229 **** --- 29816,29842 ---- <End of help on this topic> + ====== h_config_circular_tab ===== + + + FEATURE: enable-circular-tab + + +

    FEATURE: enable-circular-tab

    + +

    + This Feature is like + "auto-open-next-unread", + 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. +

    + <End of help on this topic> + + ====== h_config_auto_include_reply ===== *************** *** 28715,28720 **** --- 30328,30357 ---- <End of help on this topic> + ====== h_config_special_text_color ===== + + + OPTION: Special Text Color + + +

    OPTION: Special Text Color

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

    + Descriptions of the available commands +

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

    + <End of help on this topic> + + ====== h_config_prompt_color ===== 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 + #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,