Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 164195 Details for
Bug 236322
Pine 4.64 has Trouble converting other charcatersetups to UTF-8 by default
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
Collection of pine patches, most importantly fixes convertion to UTF-8 to work
bigpatch.diff (text/plain), 711.89 KB, created by
J.O. Aho
on 2008-09-01 04:40:20 UTC
(
hide
)
Description:
Collection of pine patches, most importantly fixes convertion to UTF-8 to work
Filename:
MIME Type:
Creator:
J.O. Aho
Created:
2008-09-01 04:40:20 UTC
Size:
711.89 KB
patch
obsolete
>--- pine4.64/imap/src/c-client/imap4r1.c 2005-05-26 08:15:11.000000000 +0200 >+++ pine4.64.SuSE/imap/src/c-client/imap4r1.c 2006-02-14 14:45:22.000000000 +0100 >@@ -4395,6 +4395,7 @@ > 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? */ >@@ -4449,6 +4450,7 @@ > 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 -ru pine4.64/imap/src/c-client/mail.c pine4.64.SuSE/imap/src/c-client/mail.c >--- pine4.64/imap/src/c-client/mail.c 2005-09-15 18:57:31.000000000 +0200 >+++ pine4.64.SuSE/imap/src/c-client/mail.c 2006-02-14 14:45:22.000000000 +0100 >@@ -979,6 +979,7 @@ > (((*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 -ru pine4.64/imap/src/c-client/mail.h pine4.64.SuSE/imap/src/c-client/mail.h >--- pine4.64/imap/src/c-client/mail.h 2005-02-09 00:44:54.000000000 +0100 >+++ pine4.64.SuSE/imap/src/c-client/mail.h 2006-02-14 14:45:22.000000000 +0100 >@@ -149,6 +149,8 @@ > #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,6 +313,8 @@ > #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,6 +626,7 @@ > /* 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,6 +795,7 @@ > 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 -ru pine4.64/imap/src/c-client/rfc822.c pine4.64.SuSE/imap/src/c-client/rfc822.c >--- pine4.64/imap/src/c-client/rfc822.c 2005-01-18 21:41:09.000000000 +0100 >+++ pine4.64.SuSE/imap/src/c-client/rfc822.c 2006-02-14 14:45:22.000000000 +0100 >@@ -354,6 +354,7 @@ > 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,6 +444,9 @@ > *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 -ru pine4.64/imap/src/dmail/Makefile pine4.64.SuSE/imap/src/dmail/Makefile >--- pine4.64/imap/src/dmail/Makefile 2002-11-19 01:43:31.000000000 +0100 >+++ pine4.64.SuSE/imap/src/dmail/Makefile 2006-02-14 14:45:25.000000000 +0100 >@@ -24,7 +24,7 @@ > # Get local definitions from c-client directory > > CC = `cat $C/CCTYPE` >-CFLAGS = -I$C `cat $C/CFLAGS` >+CFLAGS = $(EXTRACFLAGS) -I$C `cat $C/CFLAGS` > LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS` > > dmail: $(CCLIENTLIB) dmail.o >diff -ru pine4.64/imap/src/imapd/Makefile pine4.64.SuSE/imap/src/imapd/Makefile >--- pine4.64/imap/src/imapd/Makefile 2004-06-29 23:26:28.000000000 +0200 >+++ pine4.64.SuSE/imap/src/imapd/Makefile 2006-02-14 14:45:25.000000000 +0100 >@@ -47,7 +47,7 @@ > C = ../c-client > CCLIENTLIB = $C/c-client.a > CC = `cat $C/CCTYPE` >-CFLAGS = -I$C `cat $C/CFLAGS` $(NSBD) $(ENBD) -DANOFILE=\"$(ANO)\" \ >+CFLAGS = $(EXTRACFLAGS) -I$C `cat $C/CFLAGS` $(NSBD) $(ENBD) -DANOFILE=\"$(ANO)\" \ > -DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" \ > -DUSERALERTFILE=\"$(USERALERT)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\" > LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS` >diff -ru pine4.64/imap/src/ipopd/Makefile pine4.64.SuSE/imap/src/ipopd/Makefile >--- pine4.64/imap/src/ipopd/Makefile 2000-10-25 01:55:07.000000000 +0200 >+++ pine4.64.SuSE/imap/src/ipopd/Makefile 2006-02-14 14:45:25.000000000 +0100 >@@ -25,7 +25,7 @@ > # Get local definitions from c-client directory > > CC = `cat $C/CCTYPE` >-CFLAGS = -I$C `cat $C/CFLAGS` >+CFLAGS = $(EXTRACFLAGS) -I$C `cat $C/CFLAGS` > LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS` > > ipopd: ipop2d ipop3d >diff -ru pine4.64/imap/src/mailutil/Makefile pine4.64.SuSE/imap/src/mailutil/Makefile >--- pine4.64/imap/src/mailutil/Makefile 2002-11-19 01:41:46.000000000 +0100 >+++ pine4.64.SuSE/imap/src/mailutil/Makefile 2006-02-14 14:45:25.000000000 +0100 >@@ -25,7 +25,7 @@ > # Get local definitions from c-client directory > > CC = `cat $C/CCTYPE` >-CFLAGS = -I$C `cat $C/CFLAGS` >+CFLAGS = $(EXTRACFLAGS) -I$C `cat $C/CFLAGS` > LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS` > > mailutil: $(CCLIENTLIB) mailutil.o >diff -ru pine4.64/imap/src/mailutil/mailutil.c pine4.64.SuSE/imap/src/mailutil/mailutil.c >--- pine4.64/imap/src/mailutil/mailutil.c 2005-02-09 00:50:49.000000000 +0100 >+++ pine4.64.SuSE/imap/src/mailutil/mailutil.c 2006-02-14 14:45:22.000000000 +0100 >@@ -29,6 +29,7 @@ > > /* 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,6 +160,7 @@ > 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,6 +181,10 @@ > 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,7 +671,9 @@ > username[NETMAXUSER-1] = '\0'; > if (s = strchr (username,'\n')) *s = '\0'; > } >- strcpy (password,getpass ("password: ")); >+ mm_userpwd(mb, &username, &password); >+ if (!password || !*password) >+ strcpy (password,getpass ("password: ")); > } > > >diff -ru pine4.64/imap/src/mlock/Makefile pine4.64.SuSE/imap/src/mlock/Makefile >--- pine4.64/imap/src/mlock/Makefile 2002-11-19 01:42:42.000000000 +0100 >+++ pine4.64.SuSE/imap/src/mlock/Makefile 2006-02-14 14:45:25.000000000 +0100 >@@ -23,7 +23,7 @@ > # Get local definitions from c-client directory > > CC = `cat $C/CCTYPE` >-CFLAGS = `cat $C/CFLAGS` >+CFLAGS = $(EXTRACFLAGS) `cat $C/CFLAGS` > > all: mlock > >diff -ru pine4.64/imap/src/mlock/mlock.c pine4.64.SuSE/imap/src/mlock/mlock.c >--- pine4.64/imap/src/mlock/mlock.c 2004-06-22 03:05:42.000000000 +0200 >+++ pine4.64.SuSE/imap/src/mlock/mlock.c 2006-02-14 14:45:25.000000000 +0100 >@@ -32,6 +32,7 @@ > #include <netdb.h> > #include <ctype.h> > #include <strings.h> >+#include <string.h> > > #define LOCKTIMEOUT 5 /* lock timeout in minutes */ > #define LOCKPROTECTION 0775 >diff -ru pine4.64/imap/src/mtest/Makefile pine4.64.SuSE/imap/src/mtest/Makefile >--- pine4.64/imap/src/mtest/Makefile 2000-10-25 01:55:39.000000000 +0200 >+++ pine4.64.SuSE/imap/src/mtest/Makefile 2006-02-14 14:45:25.000000000 +0100 >@@ -25,7 +25,7 @@ > # Get local definitions from c-client directory > > CC = `cat $C/CCTYPE` >-CFLAGS = -I$C `cat $C/CFLAGS` >+CFLAGS = $(EXTRACFLAGS) -I$C `cat $C/CFLAGS` > LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS` > > all: mtest >diff -ru pine4.64/imap/src/osdep/unix/Makefile pine4.64.SuSE/imap/src/osdep/unix/Makefile >--- pine4.64/imap/src/osdep/unix/Makefile 2005-04-30 22:51:13.000000000 +0200 >+++ pine4.64.SuSE/imap/src/osdep/unix/Makefile 2006-02-14 14:45:24.000000000 +0100 >@@ -119,7 +119,7 @@ > # Standard distribution build parameters > > DEFAULTAUTHENTICATORS=md5 pla log >-DEFAULTDRIVERS=imap nntp pop3 mh mx mbx tenex mtx mmdf unix news phile >+DEFAULTDRIVERS=maildir courier imap nntp pop3 mh mx mbx tenex mtx mmdf unix news phile > > > # Normally no need to change any of these >@@ -128,7 +128,7 @@ > 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 >+ 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,7 +257,7 @@ > > cyg: # Cygwin - note that most local file drivers don't work!! > $(BUILD) `$(CAT) SPECIALS` OS=$@ \ >- DEFAULTDRIVERS="imap nntp pop3 mbx unix phile" \ >+ 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,7 +846,7 @@ > 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 -ru pine4.64/imap/src/osdep/unix/dummy.c pine4.64.SuSE/imap/src/osdep/unix/dummy.c >--- pine4.64/imap/src/osdep/unix/dummy.c 2004-11-11 01:16:23.000000000 +0100 >+++ pine4.64.SuSE/imap/src/osdep/unix/dummy.c 2006-02-14 14:45:22.000000000 +0100 >@@ -104,6 +104,7 @@ > { > 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,7 +365,10 @@ > 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; >+ (d != &dummydriver)){ >+ attributes &= ~LATT_NOSELECT; >+ attributes |= LATT_NOINFERIORS; >+ } > if (!contents || /* notify main program */ > (!(attributes & LATT_NOSELECT) && (csiz = strlen (contents)) && > (s = mailboxfile (tmp,name)) && >@@ -385,6 +389,8 @@ > { > 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,6 +456,14 @@ > { > 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,6 +490,9 @@ > { > 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 -ru pine4.64/imap/src/osdep/unix/env_unix.c pine4.64.SuSE/imap/src/osdep/unix/env_unix.c >--- pine4.64/imap/src/osdep/unix/env_unix.c 2004-09-13 23:31:19.000000000 +0200 >+++ pine4.64.SuSE/imap/src/osdep/unix/env_unix.c 2006-02-14 14:45:22.000000000 +0100 >@@ -24,6 +24,7 @@ > > /* 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,6 +42,7 @@ > 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,6 +217,13 @@ > 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,3 +1647,77 @@ > } > 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); >+ } >+} >Only in pine4.64.SuSE/imap/src/osdep/unix: maildir.c >Only in pine4.64.SuSE/imap/src/osdep/unix: maildir.h >diff -ru pine4.64/imap/src/osdep/unix/mh.c pine4.64.SuSE/imap/src/osdep/unix/mh.c >--- pine4.64/imap/src/osdep/unix/mh.c 2004-11-05 02:46:54.000000000 +0100 >+++ pine4.64.SuSE/imap/src/osdep/unix/mh.c 2006-02-14 14:45:24.000000000 +0100 >@@ -28,6 +28,7 @@ > #include <pwd.h> > #include <sys/stat.h> > #include <sys/time.h> >+#include <time.h> > #include "mh.h" > #include "misc.h" > #include "dummy.h" >diff -ru pine4.64/imap/src/osdep/unix/mx.c pine4.64.SuSE/imap/src/osdep/unix/mx.c >--- pine4.64/imap/src/osdep/unix/mx.c 2004-11-05 02:49:37.000000000 +0100 >+++ pine4.64.SuSE/imap/src/osdep/unix/mx.c 2006-02-14 14:45:24.000000000 +0100 >@@ -28,6 +28,7 @@ > #include <pwd.h> > #include <sys/stat.h> > #include <sys/time.h> >+#include <time.h> > #include "mx.h" > #include "misc.h" > #include "dummy.h" >diff -ru pine4.64/imap/src/osdep/unix/news.c pine4.64.SuSE/imap/src/osdep/unix/news.c >--- pine4.64/imap/src/osdep/unix/news.c 2004-07-08 23:14:20.000000000 +0200 >+++ pine4.64.SuSE/imap/src/osdep/unix/news.c 2006-02-14 14:45:25.000000000 +0100 >@@ -27,6 +27,7 @@ > #include "osdep.h" > #include <sys/stat.h> > #include <sys/time.h> >+#include <time.h> > #include "misc.h" > #include "newsrc.h" > >diff -ru pine4.64/imap/src/osdep/unix/os_cyg.h pine4.64.SuSE/imap/src/osdep/unix/os_cyg.h >--- pine4.64/imap/src/osdep/unix/os_cyg.h 2004-04-19 17:22:07.000000000 +0200 >+++ pine4.64.SuSE/imap/src/osdep/unix/os_cyg.h 2006-02-14 14:45:22.000000000 +0100 >@@ -39,6 +39,7 @@ > #define setpgrp setpgid > > #define SYSTEMUID 18 /* Cygwin returns this for SYSTEM */ >+#define FLAGSEP ';' > #define geteuid Geteuid > uid_t Geteuid (void); > >diff -ru pine4.64/imap/src/osdep/unix/os_slx.c pine4.64.SuSE/imap/src/osdep/unix/os_slx.c >--- pine4.64/imap/src/osdep/unix/os_slx.c 2005-04-21 02:49:42.000000000 +0200 >+++ pine4.64.SuSE/imap/src/osdep/unix/os_slx.c 2006-02-14 14:45:25.000000000 +0100 >@@ -33,6 +33,7 @@ > extern int errno; /* just in case */ > #include <pwd.h> > #include <shadow.h> >+#include <crypt.h> > #include "misc.h" > > >diff -ru pine4.64/imap/src/osdep/unix/phile.c pine4.64.SuSE/imap/src/osdep/unix/phile.c >--- pine4.64/imap/src/osdep/unix/phile.c 2004-04-27 22:00:47.000000000 +0200 >+++ pine4.64.SuSE/imap/src/osdep/unix/phile.c 2006-02-14 14:45:25.000000000 +0100 >@@ -29,6 +29,7 @@ > #include <pwd.h> > #include <sys/stat.h> > #include <sys/time.h> >+#include <time.h> > #include "rfc822.h" > #include "misc.h" > #include "dummy.h" >diff -ru pine4.64/imap/src/tmail/Makefile pine4.64.SuSE/imap/src/tmail/Makefile >--- pine4.64/imap/src/tmail/Makefile 2002-11-19 01:45:14.000000000 +0100 >+++ pine4.64.SuSE/imap/src/tmail/Makefile 2006-02-14 14:45:25.000000000 +0100 >@@ -24,7 +24,7 @@ > # Get local definitions from c-client directory > > CC = `cat $C/CCTYPE` >-CFLAGS = -I$C `cat $C/CFLAGS` >+CFLAGS = $(EXTRACFLAGS) -I$C `cat $C/CFLAGS` > LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS` > > tmail: $(CCLIENTLIB) tmail.o >Only in pine4.64.SuSE/: ldap >diff -ru pine4.64/pico/basic.c pine4.64.SuSE/pico/basic.c >--- pine4.64/pico/basic.c 2004-05-07 23:43:40.000000000 +0200 >+++ pine4.64.SuSE/pico/basic.c 2006-02-14 14:45:23.000000000 +0100 >@@ -266,8 +266,8 @@ > gotobop(f, n) > int f, n; /* default Flag & Numeric argument */ > { >- int quoted, qlen; >- char qstr[NLINE], qstr2[NLINE]; >+ int quoted, qlen, j; >+ char qstr[NLINE], qstr2[NLINE], ind_str[NLINE], pqstr[NLINE]; > > if (n < 0) /* the other way...*/ > return(gotoeop(f, -n)); >@@ -279,6 +279,14 @@ > curwp->w_dotp = lback(curwp->w_dotp); > curwp->w_doto = 0; > } >+ >+ if (indent_match(default_qstr(), curwp->w_dotp,ind_str, NLINE, 0)){ >+ if (n){ /* look for another paragraph ? */ >+ curwp->w_dotp = lback(curwp->w_dotp); >+ continue; >+ } >+ break; >+ } > > /* scan line by line until we come to a line ending with > * a <NL><NL> or <NL><TAB> or <NL><SPACE> >@@ -286,23 +294,60 @@ > * PLUS: if there's a quote string, a quoted-to-non-quoted > * line transition. > */ >- 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; >+ quoted = quote_match(default_qstr(), 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 >- && ((glo_quote_str || (Pmaster && Pmaster->quote_str)) >- ? (quoted == quote_match(glo_quote_str ? glo_quote_str >- : Pmaster->quote_str, >- lback(curwp->w_dotp), >- qstr2, NLINE) >- && !strcmp(qstr, qstr2)) >- : 1) >+ && (quoted == quote_match(default_qstr(), >+ lback(curwp->w_dotp), qstr2, NLINE, 0)) >+ && !strcmp(qstr, qstr2) /* processed string */ >+ && (quoted == quote_match(default_qstr(), >+ lback(curwp->w_dotp), qstr2, NLINE, 1)) >+ && !strcmp(qstr, qstr2) /* raw string */ >+ && !indent_match(default_qstr(), >+ 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 i, j; >+ >+ /* >+ * First we test if the preceding line is indented. >+ * for the following test we need to have the raw values, >+ * not the processed values >+ */ >+ quote_match(default_qstr(), curwp->w_dotp, qstr, NLINE, 1); >+ quote_match(default_qstr(), lback(curwp->w_dotp), qstr2, NLINE, 1); >+ 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 ((indent_match(default_qstr(), lback(curwp->w_dotp), >+ ind_str, NLINE, 1) >+ && (strlenis(qstr2) + strlenis(ind_str) >= strlenis(qstr))) >+ || (lback(curwp->w_dotp) != curbp->b_linep >+ && llength(lback(curwp->w_dotp)) > qlen >+ && (quoted == quote_match(default_qstr(), >+ lback(curwp->w_dotp), pqstr, NLINE, 0)) >+ && !strcmp(qstr, pqstr) >+ && lgetc(curwp->w_dotp, qlen).c != TAB >+ && lgetc(curwp->w_dotp, qlen).c != ' ' >+ && (strlenis(qstr2) > strlenis(qstr))) >+ && !qstr2[i] && !qstr[j]) >+ curwp->w_dotp = lback(curwp->w_dotp); >+ } >+ > if(n){ > /* keep looking */ > if(lback(curwp->w_dotp) == curbp->b_linep) >@@ -329,18 +374,210 @@ > return(TRUE); > } > >- >+GetAccent() >+{ >+ char c,d; >+ unsigned char ch, saved; >+ 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(); >+ ch = (unsigned char) accent(c,d); >+ if (gmode & P_UNICODE){ >+ saved = 0x80 | (ch & 0x3f); >+ ch = 0xc0 | ((ch >> 6) & 0x3f); >+ execute(ch,0, 1); >+ execute(saved,0, 1); >+ ch = 0; >+ } >+ return (int) ch; >+} >+ >+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 forword to the end of the current paragraph >+ * go forward to the end of the current paragraph > * here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE> > * combination to delimit the begining of a paragraph > */ > gotoeop(f, n) > int f, n; /* default Flag & Numeric argument */ >- > { >- int quoted, qlen; >- char qstr[NLINE], qstr2[NLINE]; >+ int quoted, qlen, indented, changeqstr = 0; >+ int i,j, fli = 0; /* fli = first line indented a boolean variable */ >+ char qstr[NLINE], qstr2[NLINE], ind_str[NLINE]; > > if (n < 0) /* the other way...*/ > return(gotobop(f, -n)); >@@ -353,26 +590,68 @@ > 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){ >+ quote_match(default_qstr(), curwp->w_dotp, qstr, NLINE, 1); >+ quote_match(default_qstr(), lforw(curwp->w_dotp), qstr2, NLINE, 1); >+ indented = indent_match(default_qstr(), 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){ >+ fli++; >+ if (indent_match(default_qstr(), lforw(curwp->w_dotp), >+ ind_str, NLINE, 0)){ >+ if (n){ /* look for another paragraph ? */ >+ curwp->w_dotp = lforw(curwp->w_dotp); >+ continue; >+ } >+ } >+ else{ >+ if (!lisblank(lforw(curwp->w_dotp))) >+ curwp->w_dotp = lforw(curwp->w_dotp); >+ } >+ } >+ } >+ > /* scan line by line until we come to a line ending with > * a <NL><NL> or <NL><TAB> or <NL><SPACE> > * > * PLUS: if there's a quote string, a quoted-to-non-quoted > * line transition. > */ >- 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); >+ /* if the first line is indented (fli == 1), then the test below >+ is on the second line, and in that case we will need the raw >+ string, not the processed string >+ */ >+ quoted = quote_match(default_qstr(), curwp->w_dotp, qstr, NLINE, fli); > qlen = quoted ? strlen(qstr) : 0; >- >+ > while(curwp->w_dotp != curbp->b_linep > && llength(lforw(curwp->w_dotp)) > qlen >- && ((glo_quote_str || (Pmaster && Pmaster->quote_str)) >- ? (quoted == quote_match(glo_quote_str ? glo_quote_str >- : Pmaster->quote_str, >- lforw(curwp->w_dotp), >- qstr2, NLINE) >- && !strcmp(qstr, qstr2)) >- : 1) >+ && (quoted == quote_match(default_qstr(), >+ lforw(curwp->w_dotp), qstr2, NLINE, fli)) >+ && !strcmp(qstr, qstr2) >+ && (quoted == quote_match(default_qstr(), >+ lforw(curwp->w_dotp), qstr2, NLINE, 1)) >+ && !strcmp(qstr, qstr2) >+ && !indent_match(default_qstr(), >+ 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,7 +932,47 @@ > 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 -ru pine4.64/pico/composer.c pine4.64.SuSE/pico/composer.c >--- pine4.64/pico/composer.c 2005-03-17 20:07:47.000000000 +0100 >+++ pine4.64.SuSE/pico/composer.c 2006-02-14 14:45:23.000000000 +0100 >@@ -344,7 +344,189 @@ > return(TRUE); > } > >+/* >+ * check_utf8 - check for UTF-8 bytes >+ * Takes two arguments: >+ * char *c - a byte of the stream >+ * char *utf_seq - a status array holding the function's state >+ * utf_seq must be provided by the caller this way: >+ * (static) char utf_seq[7] = ""; (content must be retained over calls) >+ * and must be initialized at start using: utf_seq[0] = 0; >+ * >+ * Returns NULL if an UTF-8 sequence has been started and is not completed. >+ * If an UTF-8 sequence is complete, it returns a pointer to a static string >+ * which is valid until the next use of the function. >+ * If the character is a double width character, a space(' ') is prepended >+ * to the returned string. >+ * If a character < 128 is passed, the UTF-8 state in utf_seq[] is cleared, >+ * because a valid UTF-8 sequence only consists of bytes >= 0x80. The pointer >+ * returned points to the address of the passed character to indicate this. >+ * Features: Supports UTF-8 seqencies up to 4 bytes. >+ * Todo: Instead of passing a pointer to the char and comparing the returned >+ * pointer to this address afterwards, the Interface could be changed >+ * to just pass the character as simple char(thus not requesting the >+ * address of a variable which might be declared as register) and replace >+ * the check of the return value with a check of (c & 0x80) and if this >+ * is not the case, assuming that (utf_seq[0] == 0) means that this last >+ * non-ASCII byte completed the UTF-8 sequence, while having >+ * utf_seq[0] != 0 means having an incomplete UTF-8 sequence. >+ */ >+char * >+check_utf8(c, utf_seq, sizeof_utf_seq) >+ char *c; >+ char *utf_seq; >+ size_t sizeof_utf_seq; >+{ >+ static char char_string[8]; /* (six UTF-8 sequence bytes + ' ' + '\0') */ >+ int ix; >+ unsigned char dbl_wide[7][2][4] = {0xe1,0x84,0x80,0x00, 0xe1,0x85,0x9F,0x00, >+ 0xe2,0x8c,0xa9,0x00, 0xe2,0x8c,0xaa,0x00, >+ 0xe2,0xba,0x80,0x00, 0xed,0x9e,0xa3,0x00, >+ 0xef,0xa4,0x80,0x00, 0xef,0xa9,0xaa,0x00, >+ 0xef,0xb8,0xb0,0x00, 0xef,0xb9,0xa8,0x00, >+ 0xef,0xbc,0x81,0x00, 0xef,0xbd,0xad,0x00, >+ 0xef,0xbf,0xa0,0x00, 0xef,0xbf,0xa6,0x00}; >+ if (*c & 0x80) { >+ char_string[0] = *c; >+ char_string[1] = 0; >+ if (strlen(utf_seq) == sizeof_utf_seq - 1) >+ utf_seq[0] = 0; /* don't allow a overlong UTF-8 sequence */ >+ if ((*c & 0xF0) >= 0xC0) { >+ strncpy(utf_seq, char_string, sizeof_utf_seq); >+ return NULL; /* possible UTF-8 sequence, need next byte */ >+ } else if (utf_seq[0]) { >+ strncat(utf_seq, char_string, sizeof_utf_seq); /* append to string */ >+ switch (utf_seq[0] & 0xF0) { >+ case 0xC0 : >+ case 0xD0 : >+ strncpy(char_string, utf_seq, sizeof(char_string)); >+ utf_seq[0] = 0; /* sequence complete, clear for next */ >+ return char_string; /* pass the new UTF-8 sequence on */ >+ case 0xE0 : >+ if (strlen(utf_seq) < 3) >+ return NULL; // 3-byte UTF-8, need next byte >+ char_string[0] = '\0'; // init >+ for (ix = 0; ix < 7; ix++) >+ if (strcmp(utf_seq, &dbl_wide[ix][0][0]) >= 0 >+ && strcmp(utf_seq, &dbl_wide[ix][1][0]) <= 0) { >+ char_string[0] = ' '; /* flag as double-width char */ >+ break; >+ } >+ strncat(char_string, utf_seq, sizeof(char_string)); >+ utf_seq[0] = 0; // this sequence is over, clear for restart >+ return char_string; // process this UTF-8 char... >+ case 0xF0 : >+ if (strlen(utf_seq) < 4) >+ return NULL; /* 4-byte UTF-8 sequence, need next byte */ >+ char_string[0] = '\0'; /* init the sequence space */ >+ if ((utf_seq[1] & 0xF0) == 0xA0) >+ char_string[0] = ' '; /* flag as double-width UTF-8 char */ >+ strncat(char_string, utf_seq, sizeof(char_string)); >+ utf_seq[0] = 0; /* sequence complete, clear for next */ >+ return char_string; /* pass the new UTF-8 sequence on */ >+ } >+ } >+ } >+ utf_seq[0] = 0; /* clear sequence buffer in case of an invalid sequence */ >+ return c; /* single-byte, NON-UTF-8 chars are process it as usual */ >+} >+ >+/* >+ * wrapper to check_utf8 for pico, if not in UTF-8 mode, do not check UTF-8 >+ */ >+char * >+pico_check_utf8(c, utf_seq, sizeof_utf_seq) >+ char *c; >+ char *utf_seq; >+ size_t sizeof_utf_seq; >+{ >+ if(!(Pmaster->pine_flags & P_UNICODE)) >+ return c; >+ return check_utf8(c, utf_seq, sizeof_utf_seq); >+} >+ >+/* >+ * Get the number of columns which are filled by the text in the current >+ * line of LineEdit(from the start of the line to the current position) >+ */ >+static int >+count_screencols(void) >+{ >+ char utf_seq[7] = "", *cp, *r; >+ int seq = 0, w = 0; >+ >+ for(cp = ods.cur_l->text; *cp && cp < ods.cur_l->text + ods.p_off; >+ cp++) { >+ if (!(r = pico_check_utf8(cp, utf_seq, sizeof(utf_seq)))) { >+ seq = 1; >+ continue; >+ } >+ if (seq) >+ w++; >+ seq = 0; >+ if (r == cp) >+ w++; >+ else if (*r == ' ') >+ w++; >+ } >+ return w; >+} > >+/* >+ * Get the offset in screen positions which must be subsctracted from the >+ * byte count in the LineEdit line in order to reach the line position on >+ * screen(because of double wide characters and multible UTF-8 bytes) >+ */ >+static int >+offset_on_screen(void) >+{ >+ return ods.p_off - count_screencols(); >+} >+ >+/* >+ * Move current position in LineEdit one character left, return the number >+ * of byte positons which were neccesary to jump left in order to >+ * arrive at the start of the previous multibyte character(UTF-8). >+ */ >+static int >+LineEditCharLeft() >+{ >+ int col_right = ods.p_off, cols = count_screencols(); >+ >+ do >+ if (--ods.p_off < 0) >+ break; >+ while (count_screencols() - cols == -1); >+ >+ ods.p_off++; >+ >+ if (col_right - ods.p_off > 0) >+ return col_right - ods.p_off; >+ >+ do >+ if (--ods.p_off < 0) >+ break; >+ while (count_screencols() - cols == -2); >+ >+ ods.p_off++; >+ >+ return col_right - ods.p_off; >+} >+ >+/* >+ * Move current position in LineEdit one character right, if UTF-8 >+ * mode is active, the ods.p_off is assumed to be at the start of >+ * a UTF-8 sequence or at a normal ASCII character. It is moved to >+ * the next character, jumping past the end of the current UTF-8 >+ * sequence, if UTF8 mode is active. >+ */ >+static void >+LineEditCharRight() >+{ >+ char utf_seq[7] = ""; >+ while(ods.p_off < ods.p_len && ods.cur_l->text[ods.p_off] && >+ !pico_check_utf8(ods.cur_l->text + ods.p_off++, utf_seq, sizeof(utf_seq))); >+} > > /* > * ResizeHeader - Handle resizing display when SIGWINCH received. >@@ -397,7 +579,7 @@ > PaintBody(0); > > if(ComposerEditing) >- movecursor(ods.p_line, ods.p_off+headents[ods.cur_e].prlen); >+ HeaderPaintCursor(); > > (*term.t_flush)(); > return(TRUE); >@@ -1560,6 +1742,8 @@ > } > > UpdateHeader(0); >+ if(sendnow) >+ return(status !=0); > PaintHeader(COMPOSER_TOP_LINE, status != 0); > PaintBody(1); > return(status != 0); >@@ -1594,6 +1778,7 @@ > int skipmove = 0; > char *strng; > int last_key; /* last keystroke */ >+ unsigned char utf_seq[7] = ""; > > strng = ods.cur_l->text; /* initialize offsets */ > ods.p_len = strlen(strng); >@@ -1676,7 +1861,7 @@ > } > > clearcursor(); >- movecursor(ods.p_line, ods.p_off+headents[ods.cur_e].prlen); >+ HeaderPaintCursor(); > if(ch == NODATA) /* GetKey timed out */ > continue; > >@@ -1686,12 +1871,12 @@ > if(mpresf){ /* blast old messages */ > if(mpresf++ > NMMESSDELAY){ /* every few keystrokes */ > mlerase(); >- movecursor(ods.p_line, ods.p_off+headents[ods.cur_e].prlen); >+ HeaderPaintCursor(); > } > } > > 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 >@@ -1732,12 +1917,40 @@ > > /* > * then find out where things fit... >+ * >+ * For UTF-8, the < LINELEN check should need to do it's >+ * calculation based on count_screencols() plus the width >+ * of the new char as provided by pico_check_utf8. >+ * The buffer size may need to be increased for this. > */ > if(ods.p_len < LINELEN()){ > CELL c; >+ char tmp, *chp; > >- c.c = ch; > c.a = 0; >+ if(Pmaster->pine_flags & P_UNICODE) { >+ tmp = ch; >+ chp = pico_check_utf8(&tmp, utf_seq, sizeof(utf_seq)); >+ if (chp == NULL) >+ continue; /* on to the next! */ >+ if (chp != &tmp && *chp == ' ') >+ chp++; >+ if (*chp & 0x80) { >+ while (*chp && ods.p_len < LINELEN()) { >+ c.c = *chp++; >+ pinsert(c); /* add char to str */ >+ } >+ /* update the display: */ >+ PaintHeader(COMPOSER_TOP_LINE, TRUE); >+ /* If end char was inserted, set physical .. */ >+ if (ods.p_off == ods.p_len) >+ /* cursor pos on next movecursor_offset: */ >+ movecursor_offset(-1, 0, 0); >+ continue; /* on to the next! */ >+ } >+ } >+ >+ c.c = ch; > if(pinsert(c)){ /* add char to str */ > skipmove++; /* must'a been optimal */ > continue; /* on to the next! */ >@@ -1774,7 +1987,15 @@ > } > } > else { /* interpret ch as a command */ >+ utf_seq[0] = '\0'; > 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])) >@@ -1859,9 +2080,7 @@ > case (CTRL|'F') : > case KEY_RIGHT: /* move character right */ > if(ods.p_off < ods.p_len){ >- pputc(pscr(ods.p_line, >- (ods.p_off++)+headents[ods.cur_e].prlen)->c,0); >- skipmove++; >+ LineEditCharRight(); > continue; > } > else if(gmode & MDHDRONLY) >@@ -1873,7 +2092,7 @@ > case (CTRL|'B') : > case KEY_LEFT : /* move character left */ > if(ods.p_off > 0){ >- ods.p_off--; >+ LineEditCharLeft(); > continue; > } > if(ods.p_line != COMPOSER_TOP_LINE) >@@ -1908,7 +2127,8 @@ > continue; > } > >- pputc(strng[ods.p_off++], 0); /* drop through and rubout */ >+ LineEditCharRight(); /* jump to next char */ >+ /* and fall thru */ > > case DEL : /* blast previous char */ > case (CTRL|'H') : >@@ -1922,20 +2142,27 @@ > continue; > } > >- if(ods.p_off > 0){ /* just shift left one char */ >- ods.p_len--; >+ if(ods.p_off > 0){ /* shift left one char */ >+ int todelete = LineEditCharLeft(); >+ >+ ods.p_len -= todelete; >+ > headents[ods.cur_e].dirty = 1; > if(ods.p_len == 0) > headents[ods.cur_e].sticky = 0; > else > headents[ods.cur_e].sticky = 1; > >- tbufp = &strng[--ods.p_off]; >- while(*tbufp++ != '\0') >- tbufp[-1] = *tbufp; > tbufp = &strng[ods.p_off]; >+ >+ while(*tbufp++ != '\0') >+ tbufp[-1] = tbufp[todelete-1]; >+ > if(pdel()) /* physical screen delete */ > skipmove++; /* must'a been optimal */ >+ >+ /* needed if pine bgcolor != terminal background color */ >+ PaintHeader(ods.p_line, TRUE); > } > else{ /* may have work to do */ > if(ods.cur_l->prev == NULL){ >@@ -1946,18 +2173,16 @@ > ods.p_line--; > ods.cur_l = ods.cur_l->prev; > strng = ods.cur_l->text; >- if((i=strlen(strng)) > 0){ >- strng[i-1] = '\0'; /* erase the character */ >- ods.p_off = i-1; >+ if((ods.p_off=strlen(strng)) > 0){ >+ ods.p_off -= LineEditCharLeft() - 1; >+ strng[ods.p_off] = '\0'; /* erase the character */ > } >- else{ >+ else > headents[ods.cur_e].sticky = 0; >- ods.p_off = 0; >- } >- >- tbufp = &strng[ods.p_off]; > } > >+ tbufp = &strng[ods.p_off]; >+ > if((status = FormatLines(ods.cur_l, "", LINELEN(), > headents[ods.cur_e].break_on_comma,0))==-1){ > (*term.t_beep)(); >@@ -1982,7 +2207,7 @@ > PaintBody(1); > } > >- movecursor(ods.p_line, ods.p_off+headents[ods.cur_e].prlen); >+ HeaderPaintCursor(); > > if(skipmove) > continue; >@@ -2007,7 +2232,8 @@ > void > HeaderPaintCursor() > { >- movecursor(ods.p_line, ods.p_off+headents[ods.cur_e].prlen); >+ movecursor_offset(ods.p_line, ods.p_off + headents[ods.cur_e].prlen, >+ offset_on_screen()); > } > > >@@ -2955,6 +3181,9 @@ > { > register char *bufp; > >+ if (sendnow) >+ return; >+ > if(ComposerTopLine - 1 >= BOTTOM()) /* silently forget it */ > return; > >@@ -3004,6 +3233,9 @@ > 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,6 +4116,9 @@ > 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 -ru pine4.64/pico/display.c pine4.64.SuSE/pico/display.c >--- pine4.64/pico/display.c 2004-05-07 23:43:40.000000000 +0200 >+++ pine4.64.SuSE/pico/display.c 2006-02-14 14:45:23.000000000 +0100 >@@ -133,6 +133,201 @@ > #define ISCONTROL(C) ((C) < 0x20 || (C) == 0x7F \ > || ((gmode & P_HICTRL) && ((C) > 0x7F && (C) < 0xA0))) > >+/* >+ * This is an implementation of wcwidth() (defined in IEEE Std 1002.1-2001) >+ * for Unicode: >+ * >+ * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html >+ * >+ * In fixed-width output devices, Latin characters all occupy a single >+ * "cell" position of equal width, whereas ideographic CJK characters >+ * occupy two such cells. Interoperability between terminal-line >+ * applications and (teletype-style) character terminals using the >+ * UTF-8 encoding requires agreement on which character should advance >+ * the cursor by how many cell positions. No established formal >+ * standards exist at present on which Unicode character shall occupy >+ * how many cell positions on character terminals. These routines are >+ * a first attempt of defining such behavior based on simple rules >+ * applied to data provided by the Unicode Consortium. >+ * >+ * For some graphical characters, the Unicode standard explicitly >+ * defines a character-cell width via the definition of the East Asian >+ * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes. >+ * In all these cases, there is no ambiguity about which width a >+ * terminal shall use. For characters in the East Asian Ambiguous (A) >+ * class, the width choice depends purely on a preference of backward >+ * compatibility with either historic CJK or Western practice. >+ * Choosing single-width for these characters is easy to justify as >+ * the appropriate long-term solution, as the CJK practice of >+ * displaying these characters as double-width comes from historic >+ * implementation simplicity (8-bit encoded characters were displayed >+ * single-width and 16-bit ones double-width, even for Greek, >+ * Cyrillic, etc.) and not any typographic considerations. >+ * >+ * Much less clear is the choice of width for the Not East Asian >+ * (Neutral) class. Existing practice does not dictate a width for any >+ * of these characters. It would nevertheless make sense >+ * typographically to allocate two character cells to characters such >+ * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be >+ * represented adequately with a single-width glyph. The following >+ * routines at present merely assign a single-cell width to all >+ * neutral characters, in the interest of simplicity. This is not >+ * entirely satisfactory and should be reconsidered before >+ * establishing a formal standard in this area. At the moment, the >+ * decision which Not East Asian (Neutral) characters should be >+ * represented by double-width glyphs cannot yet be answered by >+ * applying a simple rule from the Unicode database content. Setting >+ * up a proper standard for the behavior of UTF-8 character terminals >+ * will require a careful analysis not only of each Unicode character, >+ * but also of each presentation form, something the author of these >+ * routines has avoided to do so far. >+ * >+ * http://www.unicode.org/unicode/reports/tr11/ >+ * >+ * Markus Kuhn -- 2003-05-20 (Unicode 4.0) >+ * >+ * Permission to use, copy, modify, and distribute this software >+ * for any purpose and without fee is hereby granted. The author >+ * disclaims all warranties with regard to this software. >+ * >+ * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c >+ * >+ * Adapted for pine by Bernhard Kaindl >+ */ >+ >+struct interval { >+ int first; >+ int last; >+}; >+ >+/* auxiliary function for binary search in interval table */ >+static int bisearch(int ucs, const struct interval *table, int max) { >+ int min = 0; >+ int mid; >+ >+ if (ucs < table[0].first || ucs > table[max].last) >+ return 0; >+ while (max >= min) { >+ mid = (min + max) / 2; >+ if (ucs > table[mid].last) >+ min = mid + 1; >+ else if (ucs < table[mid].first) >+ max = mid - 1; >+ else >+ return 1; >+ } >+ >+ return 0; >+} >+ >+ >+/* The following two functions define the column width of an ISO 10646 >+ * character as follows: >+ * >+ * - The null character (U+0000) has a column width of 0. >+ * >+ * - Other C0/C1 control characters and DEL will lead to a return >+ * value of -1. >+ * >+ * - Non-spacing and enclosing combining characters (general >+ * category code Mn or Me in the Unicode database) have a >+ * column width of 0. >+ * >+ * - SOFT HYPHEN (U+00AD) has a column width of 1. >+ * >+ * - Other format characters (general category code Cf in the Unicode >+ * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. >+ * >+ * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) >+ * have a column width of 0. >+ * >+ * - Spacing characters in the East Asian Wide (W) or East Asian >+ * Full-width (F) category as defined in Unicode Technical >+ * Report #11 have a column width of 2. >+ * >+ * - All remaining characters (including all printable >+ * ISO 8859-1 and WGL4 characters, Unicode control characters, >+ * etc.) have a column width of 1. >+ * >+ * This implementation assumes that ucs characters are encoded >+ * in ISO 10646. >+ */ >+ >+int mk_wcwidth(int ucs) >+{ >+ /* sorted list of non-overlapping intervals of non-spacing characters */ >+ /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ >+ static const struct interval combining[] = { >+ { 0x0300, 0x0357 }, { 0x035D, 0x036F }, { 0x0483, 0x0486 }, >+ { 0x0488, 0x0489 }, { 0x0591, 0x05A1 }, { 0x05A3, 0x05B9 }, >+ { 0x05BB, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, >+ { 0x05C4, 0x05C4 }, { 0x0600, 0x0603 }, { 0x0610, 0x0615 }, >+ { 0x064B, 0x0658 }, { 0x0670, 0x0670 }, { 0x06D6, 0x06E4 }, >+ { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, { 0x070F, 0x070F }, >+ { 0x0711, 0x0711 }, { 0x0730, 0x074A }, { 0x07A6, 0x07B0 }, >+ { 0x0901, 0x0902 }, { 0x093C, 0x093C }, { 0x0941, 0x0948 }, >+ { 0x094D, 0x094D }, { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, >+ { 0x0981, 0x0981 }, { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, >+ { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, >+ { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, >+ { 0x0A4B, 0x0A4D }, { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, >+ { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, >+ { 0x0ACD, 0x0ACD }, { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, >+ { 0x0B3C, 0x0B3C }, { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, >+ { 0x0B4D, 0x0B4D }, { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, >+ { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, >+ { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, >+ { 0x0CBC, 0x0CBC }, { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, >+ { 0x0CCC, 0x0CCD }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, >+ { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, >+ { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, >+ { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, >+ { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, >+ { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, >+ { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, >+ { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, >+ { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, >+ { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x1712, 0x1714 }, >+ { 0x1732, 0x1734 }, { 0x1752, 0x1753 }, { 0x1772, 0x1773 }, >+ { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD }, { 0x17C6, 0x17C6 }, >+ { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD }, { 0x180B, 0x180D }, >+ { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 }, { 0x1927, 0x1928 }, >+ { 0x1932, 0x1932 }, { 0x1939, 0x193B }, { 0x200B, 0x200F }, >+ { 0x202A, 0x202E }, { 0x2060, 0x2063 }, { 0x206A, 0x206F }, >+ { 0x20D0, 0x20EA }, { 0x302A, 0x302F }, { 0x3099, 0x309A }, >+ { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, { 0xFE20, 0xFE23 }, >+ { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }, { 0x1D167, 0x1D169 }, >+ { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD }, >+ { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F }, { 0xE0100, 0xE01EF } >+ }; >+ >+ /* test for 8-bit control characters */ >+ if (ucs == 0) >+ return 0; >+ if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) >+ return -1; >+ >+ /* binary search in table of non-spacing characters */ >+ if (bisearch(ucs, combining, >+ sizeof(combining) / sizeof(struct interval) - 1)) >+ return 0; >+ >+ /* if we arrive here, ucs is not a combining or C0/C1 control character */ >+ >+ return 1 + >+ (ucs >= 0x1100 && >+ (ucs <= 0x115f || /* Hangul Jamo init. consonants */ >+ ucs == 0x2329 || ucs == 0x232a || >+ (ucs >= 0x2e80 && ucs <= 0xa4cf && >+ ucs != 0x303f) || /* CJK ... Yi */ >+ (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ >+ (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ >+ (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ >+ (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ >+ (ucs >= 0xffe0 && ucs <= 0xffe6) || >+ (ucs >= 0x20000 && ucs <= 0x2fffd) || >+ (ucs >= 0x30000 && ucs <= 0x3fffd))); >+} > > /* > * Initialize the data structures used by the display code. The edge vectors >@@ -282,6 +477,10 @@ > } > else > vp->v_text[vtcol++] = c; >+ if (gmode & P_UNICODE && mk_wcwidth(c.c) == 2) { >+ ac.c = 0xfedc0000; // dirty trick, ttputc uses char (signed..) and checks >127, to be done properly... >+ vtputc(ac); >+ } > } > > >@@ -322,6 +521,10 @@ > vp->v_text[vtcol] = c; > ++vtcol; > } >+ if (gmode & P_UNICODE && mk_wcwidth(c.c) == 2) { >+ ac.c = 0xfedc0000; // dirty trick, ttputc uses char (signed..) and checks >127, to be done properly... >+ vtputc(ac); >+ } > } > > >@@ -362,6 +565,9 @@ > register int scroll = 0; > CELL c; > >+ if (sendnow) >+ return; >+ > #if TYPEAH > if (typahead()) > return; >@@ -608,6 +814,9 @@ > curcol |= 0x07; > else if (ISCONTROL(c.c)) > ++curcol; >+ else if (gmode & P_UNICODE) { >+ curcol += mk_wcwidth(c.c) - 1; >+ } > > ++curcol; > } >@@ -1086,7 +1295,22 @@ > } > } > >+void >+movecursor_offset(row, col, offs) >+int row, col, offs; >+{ >+ static int force_next = 0; > >+ if(row == -1) { >+ force_next = row; >+ return; >+ } >+ if(row!=ttrow || col!=ttcol || force_next) { >+ (*term.t_move)(row, col - offs); >+ ttrow = row; >+ ttcol = col; >+ } >+} > > /* > * Send a command to the terminal to move the hardware cursor to row "row" >@@ -1400,6 +1624,7 @@ > > 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,6 +1685,19 @@ > 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,6 +1753,11 @@ > b--; > continue; > >+ case (CTRL|'\\'): >+ if (c = GetAccent()) >+ goto text; >+ continue; >+ > case KEY_RIGHT: > if(*b != '\0') > b++; >@@ -1566,6 +1809,7 @@ > #endif > > default : >+text: > if(strlen(buf) >= maxl){ /* contain the text */ > (*term.t_beep)(); > continue; >@@ -1604,22 +1848,26 @@ > b[i+1] = b[i]; > while(i-- > 0); > >- pputc(*b++ = c, 0); >+ if(sendnow) >+ *b++ = c; >+ else >+ pputc(*b++ = c, 0); > } > } > >- pputs(b, 1); /* show default */ >+ 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(ttcol <= i) >+ while(!sendnow && ttcol <= i) > pputc(' ', 0); > } > > ret: >- if(km_popped){ >+ if(!sendnow && km_popped){ > term.t_mrow = 0; > movecursor(term.t_nrow, 0); > peeol(); >@@ -1745,6 +1993,8 @@ > register int c; > register char *ap; > >+ if(sendnow) >+ return 0; > /* > * the idea is to only highlight if there is something to show > */ >@@ -2472,6 +2722,9 @@ > char nbuf[NLINE]; > #endif > >+ if(sendnow) >+ return; >+ > #ifdef _WINDOWS > pico_config_menu_items (keymenu); > #endif >diff -ru pine4.64/pico/ebind.h pine4.64.SuSE/pico/ebind.h >--- pine4.64/pico/ebind.h 2004-05-07 23:43:40.000000000 +0200 >+++ pine4.64.SuSE/pico/ebind.h 2006-02-14 14:45:22.000000000 +0100 >@@ -105,7 +105,9 @@ > {CTRL|'^', setmark}, > {CTRL|'_', alt_editor}, > {0x7F, backdel}, >- {0, NULL} >+ {CTRL|'\\', pineaccent}, >+ {0, >+NULL} > }; > > >diff -ru pine4.64/pico/edef.h pine4.64.SuSE/pico/edef.h >--- pine4.64/pico/edef.h 2004-10-14 03:27:01.000000000 +0200 >+++ pine4.64.SuSE/pico/edef.h 2006-02-14 14:45:22.000000000 +0100 >@@ -43,6 +43,7 @@ > > /* 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,6 +97,7 @@ > > /* 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 -ru pine4.64/pico/efunc.h pine4.64.SuSE/pico/efunc.h >--- pine4.64/pico/efunc.h 2004-06-16 00:22:35.000000000 +0200 >+++ pine4.64.SuSE/pico/efunc.h 2006-02-14 14:45:23.000000000 +0100 >@@ -65,6 +65,7 @@ > 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,6 +74,9 @@ > 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)); >@@ -114,6 +118,7 @@ > extern VARS_TO_SAVE *save_pico_state PROTO((void)); > extern void restore_pico_state PROTO((VARS_TO_SAVE *)); > extern void free_pico_state PROTO((VARS_TO_SAVE *)); >+extern char *check_utf8 PROTO((char *, char *, size_t)); > extern void HeaderPaintCursor PROTO((void)); > extern void PaintBody PROTO((int)); > >@@ -337,6 +342,13 @@ > 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)); >+extern int quote_match PROTO((char *, LINE *, char *, int, int)); >+extern char *default_qstr PROTO((void)); >+extern void flatten_qstring PROTO((QSTRING_S *, char *, int)); >+extern void free_qs PROTO((QSTRING_S **)); >+extern QSTRING_S *do_quote_match PROTO((char *,char *, char *, char *, char *, int, int)); >+extern QSTRING_S *copy_qs PROTO((QSTRING_S *)); >+extern QSTRING_S *do_raw_quote_match PROTO((char *, char *, char *, char *, QSTRING_S **, QSTRING_S **)); >+ > > #endif /* EFUNC_H */ >diff -ru pine4.64/pico/estruct.h pine4.64.SuSE/pico/estruct.h >--- pine4.64/pico/estruct.h 2004-12-01 01:37:37.000000000 +0100 >+++ pine4.64.SuSE/pico/estruct.h 2006-02-14 14:45:23.000000000 +0100 >@@ -290,7 +290,7 @@ > * and short if there are problems... > */ > typedef struct CELL { >- unsigned int c : 8; /* Character value in cell */ >+ unsigned int c : 32; /* Character value in cell */ > unsigned int a : 8; /* Its attributes */ > } CELL; > >@@ -354,6 +354,7 @@ > #define lgetc(lp, n) ((lp)->l_text[(n)]) > #define lputc(lp, n, c) ((lp)->l_text[(n)]=(c)) > #define llength(lp) ((lp)->l_used) >+#define cell_isspace(lp,n) Pisspace(lgetc(lp, n).c) > > /* > * The editor communicates with the display using a high level interface. A >diff -ru pine4.64/pico/file.c pine4.64.SuSE/pico/file.c >--- pine4.64/pico/file.c 2004-06-11 23:49:40.000000000 +0200 >+++ pine4.64.SuSE/pico/file.c 2006-02-14 14:45:23.000000000 +0100 >@@ -425,11 +425,11 @@ > for(p = (glo_quote_str ? glo_quote_str > : (Pmaster ? Pmaster->quote_str : NULL)); > p && *p; p++) >- if(!linsert(1, *p)) >+ if(!linsert_byte(1, *p)) > return(0); > } > else if(c != '\r') /* ignore CR (likely CR of CRLF) */ >- return(linsert(1, c)); >+ return(linsert_byte(1, c)); > > return(1); > } >@@ -493,7 +493,7 @@ > > case FIOLNG : > for(linep = line; charsread-- > 0; linep++) >- linsert(1, (unsigned char) *linep); >+ linsert_byte(1, *linep); > > break; > >@@ -910,7 +910,7 @@ > > case FIOLNG : > for(linep = line; charsread-- > 0; linep++) >- linsert(1, (unsigned char) *linep); >+ linsert_byte(1, *linep); > > break; > >diff -ru pine4.64/pico/fileio.c pine4.64.SuSE/pico/fileio.c >--- pine4.64/pico/fileio.c 2002-02-12 23:53:53.000000000 +0100 >+++ pine4.64.SuSE/pico/fileio.c 2006-02-14 14:45:23.000000000 +0100 >@@ -71,9 +71,20 @@ > { > register int i; > >- for (i = 0; i < nbuf; ++i) >+ for (i = 0; i < nbuf; ++i) { >+ if (gmode & P_UNICODE && buf[i].c & 0xffffff80) { >+ if (buf[i].c & 0xf800) { >+ fputc(0xe0 | (buf[i].c >> 12), g_pico_fio.fp); >+ fputc(0x80 | ((buf[i].c >> 6) & 0x3f), g_pico_fio.fp); >+ } >+ else >+ fputc(0xc0 | ((buf[i].c >> 6) & 0x3f), g_pico_fio.fp); >+ if (fputc(0x80 | (buf[i].c & 0x3f), g_pico_fio.fp) == EOF) >+ break; >+ } else > if(fputc(buf[i].c&0xFF, g_pico_fio.fp) == EOF) > break; >+ } > > if(i == nbuf) > fputc('\n', g_pico_fio.fp); >diff -ru pine4.64/pico/line.c pine4.64.SuSE/pico/line.c >--- pine4.64/pico/line.c 2004-05-07 23:43:40.000000000 +0200 >+++ pine4.64.SuSE/pico/line.c 2006-02-14 14:45:23.000000000 +0100 >@@ -51,7 +51,7 @@ > */ > struct pkchunk { > short used; /* # of bytes used in this buffer*/ >- char bufp[KBLOCK]; /* buffer containing text */ >+ int bufp[KBLOCK]; /* buffer containing text */ > struct pkchunk *next; /* pointer to next chunk */ > }; > >@@ -210,6 +210,83 @@ > backchar(f, n); > } > >+/* Return UCS-4 character from UTF-8 string >+ * (Based on code from pine-4.61/imap/src/c-client/utf8.c) >+ * Accepts: pointer to string, remaining octets in string >+ * Returns: UCS-4 character or negative if error >+ */ >+unsigned int utf8_get_ucs_string(unsigned char **s, unsigned int i) >+{ >+ unsigned char c; >+ unsigned int ret = 0; >+ int more = 0; >+ while (i--) { >+ if (((c = *(*s)++) > 0x7f) && (c < 0xc0)) { /* UTF-8 continuation? */ >+ if (!more) /* continuation outside of UTF-8 sequence? */ >+ return '?'; /* bad sequence, put replacement character */ >+ ret <<= 6; >+ ret |= c & 0x3f; >+ if (!--more) /* last octet reached? */ >+ return ret; /* return UTC-4 code */ >+ } >+ else if (more) /* in sequence, but not a continuation byte */ >+ return '?'; /* bad sequence, put replacement character */ >+ else if (c < 0x80) /* U+0000 - U+007f */ >+ return c; >+ else if (c < 0xe0) { /* U+0080 - U+07ff */ >+ ret = c & 0x1f; /* first 5 bits of 12 */ >+ more = 1; >+ } >+ else if (c < 0xf0) { /* U+1000 - U+ffff */ >+ ret = c & 0x0f; /* first 4 bits of 16 */ >+ more = 2; >+ } /* non-BMP Unicode */ >+ else if (c < 0xf8) { /* U+10000 - U+10ffff (U+1fffff) */ >+ ret = c & 0x07; /* first 3 bits of 20.5 (21) */ >+ more = 3; >+ } >+ else if (c < 0xfc) { /* ISO 10646 200000 - 3fffffff */ >+ ret = c & 0x03; /* first 2 bits of 26 */ >+ more = 4; >+ } >+ else if (c < 0xfe) { /* ISO 10646 4000000-7fffffff */ >+ ret = c & 0x01; /* first bit of 31 */ >+ more = 5; >+ } else >+ return '?'; /* not in ISO 10646 -> replacement character */ >+ } /* end of input, but sequnece not complete */ >+ return 0; >+} >+unsigned int utf8_get_ucs(unsigned char *s, unsigned int i) >+{ >+ unsigned char *l = s; >+ return utf8_get_ucs_string(&l, i); >+} >+ >+/* >+ * Insert "n" copies of the character "c" at the current location of dot. >+ * The real work is done by linsert(). This is a wrapper does: >+ * In UTF-8 mode, decode byte sequencies and if a sequence is complete, >+ * insert the resulting Unicode(UCS4) value as cell value into the buffer. >+ */ >+int linsert_byte(n, c) >+unsigned int n, c; >+{ >+ static char linsert_buf[6], linsert_buf_count = 0; >+ if (n == 1 && gmode & P_UNICODE && c & 0x80) { >+ if (linsert_buf_count >= sizeof(linsert_buf)) >+ linsert_buf_count = 0; >+ linsert_buf[linsert_buf_count++] = c; >+ c = 0; >+ if (linsert_buf_count > 1) >+ c = utf8_get_ucs(linsert_buf, linsert_buf_count); >+ if (!c) >+ return 1; >+ } >+ linsert_buf_count = 0; >+ return linsert(n, c); >+} >+ > /* > * Insert "n" copies of the character "c" at the current location of dot. In > * the easy case all that happens is the text is stored in the line. In the >@@ -294,7 +371,7 @@ > lp1->l_bp = lp2; > *doto = n; > *dotp = lp1; >- ac.c = ((char)c & 0xff); >+ ac.c = c; > cp1 = &(*dotp)->l_text[0]; > while(n--) > *cp1++ = ac; >@@ -342,7 +419,7 @@ > *--cp2 = *--cp1; > } > >- ac.c = ((char)c & 0xff); >+ ac.c = c; > while(n--) /* add the chars */ > (*dotp)->l_text[(*doto)++] = ac; > >@@ -633,10 +710,7 @@ > int n = 0; > char qstr[NLINE]; > >- 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; >+ n = quote_match(default_qstr(), line, qstr, NLINE, 1); > > for(; n < llength(line); n++) > if(!isspace((unsigned char) lgetc(line, n).c)) >@@ -767,7 +841,7 @@ > if(!(p = p->next)) > return(-1); > >- return(p->bufp[n % KBLOCK] & 0xff); >+ return(p->bufp[n % KBLOCK]); > } > else > return(-1); >diff -ru pine4.64/pico/main.c pine4.64.SuSE/pico/main.c >--- pine4.64/pico/main.c 2004-03-26 23:36:45.000000000 +0100 >+++ pine4.64.SuSE/pico/main.c 2006-02-14 14:45:25.000000000 +0100 >@@ -119,7 +119,6 @@ > #endif > "\t +[line#] \tLine - start on line# line, default=1", > "\t -v \t\tView - view file", >-"\t -setlocale_ctype\tdo setlocale(LC_CTYPE) if available", > "\t -no_setlocale_collate\tdo not do setlocale(LC_COLLATE)", > "\t -version\tPico version number", > "", >@@ -146,9 +145,10 @@ > int viewflag = FALSE; /* are we starting in view mode?*/ > int starton = 0; /* where's dot to begin with? */ > int setlocale_collate = 1; >- int setlocale_ctype = 0; >+ int setlocale_ctype = 1; /* if a problem shows up, should be fixed */ > 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 */ >@@ -247,7 +247,7 @@ > curwp->w_flag |= WFMODE; /* and force an update */ > > if(timeoutset) >- emlwrite("Checking for new mail every %D seconds", (void *)timeo); >+ emlwrite("Checking for new mail every %d seconds", (void *)timeo); > > forwline(0, starton - 1); /* move dot to specified line */ > >@@ -306,6 +306,12 @@ > 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,14 +333,30 @@ > mlerase(); > } > >- f = FALSE; >+ 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 -ru pine4.64/pico/makefile.lnx pine4.64.SuSE/pico/makefile.lnx >--- pine4.64/pico/makefile.lnx 2001-10-24 00:18:36.000000000 +0200 >+++ pine4.64.SuSE/pico/makefile.lnx 2006-02-14 14:45:25.000000000 +0100 >@@ -36,7 +36,7 @@ > RM= rm -f > LN= ln -s > MAKE= make >-OPTIMIZE= # -O >+OPTIMIZE= -pipe > PROFILE= # -pg > DEBUG= -g -DDEBUG > >diff -ru pine4.64/pico/osdep/makefile pine4.64.SuSE/pico/osdep/makefile >--- pine4.64/pico/osdep/makefile 2001-02-23 23:45:24.000000000 +0100 >+++ pine4.64.SuSE/pico/osdep/makefile 2006-02-14 14:45:25.000000000 +0100 >@@ -21,7 +21,7 @@ > all: includer $(ALL) > > includer: includer.c >- $(CC) -o includer includer.c >+ $(CC) $(EXTRACFLAGS) -o includer includer.c > > clean: > $(RM) $(ALL) includer >diff -ru pine4.64/pico/osdep/makefile.bas pine4.64.SuSE/pico/osdep/makefile.bas >--- pine4.64/pico/osdep/makefile.bas 2000-12-30 00:01:57.000000000 +0100 >+++ pine4.64.SuSE/pico/osdep/makefile.bas 2006-02-14 14:45:25.000000000 +0100 >@@ -21,7 +21,7 @@ > all: includer $(ALL) > > includer: includer.c >- $(CC) -o includer includer.c >+ $(CC) $(EXTRACFLAGS) -o includer includer.c > > clean: > $(RM) $(ALL) includer >diff -ru pine4.64/pico/osdep/os-lnx.h pine4.64.SuSE/pico/osdep/os-lnx.h >--- pine4.64/pico/osdep/os-lnx.h 2004-01-23 23:48:50.000000000 +0100 >+++ pine4.64.SuSE/pico/osdep/os-lnx.h 2006-02-14 14:45:25.000000000 +0100 >@@ -25,6 +25,9 @@ > #include <string.h> > #include <sys/types.h> > >+/* Added for GLIBC port */ >+#include <sys/ioctl.h> >+ > #define USE_DIRENT > #include <sys/dir.h> > #include <unistd.h> >@@ -187,8 +190,10 @@ > /* > * Make sys_errlist visible > */ >-/* extern char *sys_errlist[]; */ >-/* extern int sys_nerr; */ >+#ifndef __GLIBC__ >+extern char *sys_errlist[]; >+extern int sys_nerr; >+#endif > > > #endif /* _PICO_OS_INCLUDED */ >diff -ru pine4.64/pico/osdep/term.cap pine4.64.SuSE/pico/osdep/term.cap >--- pine4.64/pico/osdep/term.cap 2004-07-22 00:06:24.000000000 +0200 >+++ pine4.64.SuSE/pico/osdep/term.cap 2006-02-14 14:45:22.000000000 +0100 >@@ -438,6 +438,12 @@ > { > 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 -ru pine4.64/pico/osdep/unix pine4.64.SuSE/pico/osdep/unix >--- pine4.64/pico/osdep/unix 2005-04-19 23:29:12.000000000 +0200 >+++ pine4.64.SuSE/pico/osdep/unix 2006-02-14 14:45:24.000000000 +0100 >@@ -1,3 +1,7 @@ >+#ifdef LC_CTYPE >+#include <langinfo.h> >+#endif >+ > int timeo = 0; > time_t time_of_last_input; > int (*pcollator)(); >@@ -221,6 +225,15 @@ > */ > ttputc(c) > { >+ if (gmode & P_UNICODE && c > 127) { >+ if (c & 0xf800) { >+ putc(0xe0 | (c >> 12), stdout); >+ putc(0x80 | ((c >> 6) & 0x3f), stdout); >+ } >+ else >+ putc(0xc0 | ((c >> 6) & 0x3f), stdout); >+ return putc(0x80 | (c & 0x3f), stdout); >+ } > return(putc(c, stdout)); > } > >@@ -362,6 +375,26 @@ > GetKey() > { > int ch, status, cc; >+ static int saved; >+ >+ 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 (saved) { >+ ch = saved; >+ saved = 0; >+ return ch; >+ } > > if(!ReadyForKey(FUDGE-5)) > return(NODATA); >@@ -399,6 +432,10 @@ > } > > ch = i; >+ if (gmode & P_UNICODE) { >+ saved = 0x80 | (ch & 0x3f); >+ ch = 0xc0 | ((ch >> 6) & 0x3f); >+ } > } > else{ > if(islower((unsigned char)ch)) /* canonicalize if alpha */ >@@ -2199,7 +2236,7 @@ > #ifdef SIGCHLD > (void) signal(SIGCHLD, SIG_DFL); > #endif >- if(execl("/bin/sh", "sh", "-c", eb, 0) < 0) >+ if(execl("/bin/sh", "sh", "-c", eb,(void*)0) < 0) > exit(-1); > } > else { /* error! */ >@@ -3871,6 +3908,9 @@ > #ifdef LC_CTYPE > if(ctype){ > (void)setlocale(LC_CTYPE, ""); >+ /* For reference, see: "The Single UNIX(R) Specification, Version 2" */ >+ if (!strcmp(nl_langinfo(CODESET), "UTF-8")) >+ gmode ^= P_UNICODE; > } > #endif > } >diff -ru pine4.64/pico/pico.c pine4.64.SuSE/pico/pico.c >--- pine4.64/pico/pico.c 2005-03-31 19:08:28.000000000 +0200 >+++ pine4.64.SuSE/pico/pico.c 2006-02-14 14:45:24.000000000 +0100 >@@ -138,6 +138,15 @@ > 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); > >@@ -540,7 +549,7 @@ > > /* do the appropriate insertion */ > /* pico never does C mode, this is simple */ >- status = linsert(n, c); >+ status = linsert_byte(n, c); > > /* > * Check to make sure we didn't go off of the screen >@@ -552,7 +561,7 @@ > register int k; > > for(j = k = 0; j < llength(curwp->w_dotp); j++, k++) >- if(isspace((unsigned char)lgetc(curwp->w_dotp, j).c)){ >+ if(cell_isspace(curwp->w_dotp, j)){ > if(lgetc(curwp->w_dotp, j).c == TAB) > while(k+1 & 0x07) > k++; >@@ -686,6 +695,17 @@ > 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) >@@ -810,7 +830,7 @@ > is_cursor_line = (cursor_dotp == (*lp)); > /* trim trailing whitespace, to be added back if flowing */ > for(i = llength(*lp); i; i--) >- if(!isspace(lgetc(*lp, i - 1).c)) >+ if(!cell_isspace(*lp, i - 1)) > break; > if(i != llength(*lp)){ > int flow_line = 0; >@@ -818,7 +838,7 @@ > if(Pmaster && !Pmaster->strip_ws_before_send > && lforw(*lp) != curbp->b_linep > && llength(lforw(*lp)) >- && !(isspace(lgetc(lforw(*lp), 0).c) >+ && !(cell_isspace(lforw(*lp), 0) > || isquotedspace(lforw(*lp))) > && !(llength(lforw(*lp)) == 3 > && lgetc(lforw(*lp), 0).c == '-' >@@ -833,7 +853,7 @@ > ldelete(llength(*lp) - i, NULL); > } > } >- else if(flow_line && i && isspace(lgetc(*lp, i).c)){ >+ else if(flow_line && i && cell_isspace(*lp, i)){ > /* flowed line ending with whitespace other than space*/ > curwp->w_doto = i; > ldelete(llength(*lp) - i, NULL); >@@ -845,7 +865,7 @@ > } > } > if(Pmaster && Pmaster->allow_flowed_text >- && llength(*lp) && isspace(lgetc(*lp, 0).c)){ >+ && llength(*lp) && cell_isspace(*lp, 0)){ > /* space-stuff only if flowed */ > curwp->w_doto = 0; > if(is_cursor_line && cursor_doto) >@@ -867,30 +887,6 @@ > } > > /* >- * Remove all trailing white space from the text >- */ >-int >-stripwhitespace() >-{ >- int i; >- LINE *cur_line = lforw(curbp->b_linep); >- >- do{ >- /* we gotta test for the sigdash case here */ >- if(!(cur_line->l_used == 3 && >- lgetc(cur_line, 0).c == '-' && >- lgetc(cur_line, 1).c == '-' && >- lgetc(cur_line, 2).c == ' ')) >- for(i = cur_line->l_used - 1; i >= 0; i--) >- if(isspace(lgetc(cur_line, i).c)) >- cur_line->l_used--; >- else >- break; >- }while((cur_line = lforw(cur_line)) != curbp->b_linep); >- return 0; >-} >- >-/* > * Abort. > * Beep the beeper. Kill off any keyboard macro, etc., that is in progress. > * Sometimes called as a routine, to do general aborting of stuff. >@@ -1451,6 +1447,7 @@ > LINE *dotp; > int doto; > short crinread; >+ char readch[6]; > } PICOTEXT; > > #define PT(X) ((PICOTEXT *)(X)) >@@ -1504,6 +1501,8 @@ > * pico_readc - return char at current point. Up to calling routines > * to keep cumulative count of chars. > */ >+#define PUTC(w, c) PT(w)->readch[PT(w)->crinread++] = c; >+#define GETC(w) PT(w)->readch[--PT(w)->crinread]; > int > pico_readc(w, c) > void *w; >@@ -1512,12 +1511,20 @@ > int rv = 0; > > if(PT(w)->crinread){ >- *c = '\012'; /* return LF */ >- PT(w)->crinread = 0; >+ *c = GETC(w); > rv++; > } > else if(PT(w)->doto < llength(PT(w)->dotp)){ /* normal char to return */ >- *c = (unsigned char) lgetc(PT(w)->dotp, (PT(w)->doto)++).c; >+ int ch = lgetc(PT(w)->dotp, (PT(w)->doto)++).c; >+ if (gmode & P_UNICODE && ch & 0xff80) { >+ PUTC(w, 0x80 | (ch & 0x3f)) >+ if (ch & 0xf800) { /* three byte code */ >+ *c = 0xe0 | (ch >> 12); >+ PUTC(w, 0x80 | ((ch >> 6) & 0x3f)) >+ } else >+ *c = 0xc0 | ((ch >> 6) & 0x3f); >+ } else >+ *c = ch; > rv++; > } > else if(PT(w)->dotp != PT(w)->linep){ /* return line break */ >@@ -1525,7 +1532,7 @@ > PT(w)->doto = 0; > #if defined(DOS) || defined(OS2) > *c = '\015'; >- PT(w)->crinread++; >+ PUTC(w, '\012') > #else > *c = '\012'; /* return local eol! */ > #endif >@@ -1584,8 +1591,20 @@ > > rv++; > } >- else >+ else { >+ if (gmode & P_UNICODE && c & 0xffffff80) { >+ if (PT(w)->crinread >= 6) >+ PT(w)->crinread = 0; >+ PUTC(w, c); >+ c = 0; >+ if (PT(w)->crinread > 1) >+ c = utf8_get_ucs(PT(w)->readch, PT(w)->crinread); >+ if (!c) >+ return 1; >+ } >+ PT(w)->crinread = 0; > rv = geninsert(&PT(w)->dotp, &PT(w)->doto, PT(w)->linep, c, 0, 1, NULL); >+ } > > return((rv) ? 1 : 0); /* return number written */ > } >diff -ru pine4.64/pico/pico.h pine4.64.SuSE/pico/pico.h >--- pine4.64/pico/pico.h 2005-03-31 00:44:40.000000000 +0200 >+++ pine4.64.SuSE/pico/pico.h 2006-02-14 14:45:23.000000000 +0100 >@@ -219,6 +219,7 @@ > 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,6 +343,22 @@ > 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) >@@ -356,7 +373,7 @@ > #define P_HICTRL 0x80000000 /* overwrite mode */ > #define P_CHKPTNOW 0x40000000 /* do the checkpoint on entry */ > #define P_DELRUBS 0x20000000 /* map ^H to forwdel */ >-#define P_LOCALLF 0x10000000 /* use local vs. NVT EOL */ >+#define P_UNICODE 0x10000000 /* run in Unicode mode */ > #define P_BODY 0x08000000 /* start composer in body */ > #define P_HEADEND 0x04000000 /* start composer at end of header */ > #define P_VIEW MDVIEW /* read-only */ >diff -ru pine4.64/pico/pilot.c pine4.64.SuSE/pico/pilot.c >--- pine4.64/pico/pilot.c 2004-06-11 23:49:40.000000000 +0200 >+++ pine4.64.SuSE/pico/pilot.c 2006-02-14 14:45:25.000000000 +0100 >@@ -131,7 +131,7 @@ > > curbp->b_mode |= gmode; /* and set default modes*/ > if(timeo) >- emlwrite("Checking for new mail every %D seconds", (void *) timeo); >+ emlwrite("Checking for new mail every %d seconds", (void *) timeo); > > set_browser_title(PILOT_VERSION); > FileBrowse(filedir, NSTRING, filename, NSTRING, NULL, 0, NULL); >diff -ru pine4.64/pico/random.c pine4.64.SuSE/pico/random.c >--- pine4.64/pico/random.c 2004-05-07 23:43:40.000000000 +0200 >+++ pine4.64.SuSE/pico/random.c 2006-02-14 14:45:23.000000000 +0100 >@@ -141,6 +141,11 @@ > return(linsert(tabsize - (getccol(FALSE) % tabsize), ' ')); > } > >+int Pisspace(int c) { >+ if (gmode & P_UNICODE && c > 127) /* to be extended when time permits */ >+ return 0; >+ return isspace((unsigned char)c); >+} > > /* > * Insert a newline. Bound to "C-M". >@@ -170,7 +175,7 @@ > /* pico's never in C mode */ > > if(Pmaster && Pmaster->allow_flowed_text && curwp->w_doto >- && isspace(lgetc(curwp->w_dotp, curwp->w_doto - 1).c) >+ && cell_isspace(curwp->w_dotp, curwp->w_doto - 1) > && !(curwp->w_doto == 3 > && lgetc(curwp->w_dotp, 0).c == '-' > && lgetc(curwp->w_dotp, 1).c == '-' >@@ -181,7 +186,7 @@ > */ > int i, dellen; > for(i = curwp->w_doto - 1; >- i && isspace(lgetc(curwp->w_dotp, i - 1).c); >+ i && cell_isspace(curwp->w_dotp, i - 1); > i--); > dellen = curwp->w_doto - i; > curwp->w_doto = i; >@@ -364,7 +369,8 @@ > else{ > backchar(FALSE, 1); > dotp = curwp->w_dotp; >- gotobop(FALSE, 1); /* then go to the top of the para */ >+ 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 -ru pine4.64/pico/search.c pine4.64.SuSE/pico/search.c >--- pine4.64/pico/search.c 2004-07-01 23:33:30.000000000 +0200 >+++ pine4.64.SuSE/pico/search.c 2006-02-14 14:45:23.000000000 +0100 >@@ -78,6 +78,10 @@ > "\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.", >@@ -113,6 +117,8 @@ > forwsearch(f, n) > int f, n; > { >+ LINE *lastline; /* line position before scan */ >+ int lastoff; /* last position within line */ > register int status; > int wrapt = FALSE, wrapt2 = FALSE; > int repl_mode = FALSE; >@@ -235,10 +241,20 @@ > 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); >@@ -259,26 +275,15 @@ > } > } > >+ lastline = curwp->w_dotp; /* line position before scan */ >+ lastoff = curwp->w_doto; /* last position within line */ >+ > /* >- * This code is kind of dumb. What I want is successive C-W 's to >- * move dot to successive occurences of the pattern. So, if dot is >- * already sitting at the beginning of the pattern, then we'll move >- * forward a char before beginning the search. We'll let the >- * automatic wrapping handle putting the dot back in the right >- * place... >+ * Successive C-W 's should move the dot to successive occurences >+ * of the pattern. So move the dot forward one char before the search >+ * and if the seach fails, put it back were it was. > */ >- status = 0; /* using "status" as int temporarily! */ >- while(1){ >- if(defpat[status] == '\0'){ >- forwchar(0, 1); >- break; /* find next occurence! */ >- } >- >- 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++; >- } >+ forwchar(0, 1); > > /* search for the pattern */ > >@@ -290,6 +295,8 @@ > /* and complain if not there */ > if (status == FALSE){ > emlwrite("\"%s\" not found", defpat); >+ curwp->w_dotp = lastline; /* line position before scan */ >+ curwp->w_doto = lastoff; /* last position within line */ > } > else if((gmode & MDREPLACE) && repl_mode == TRUE){ > status = replace_pat(defpat, &wrapt2); /* replace pattern */ >@@ -499,7 +506,7 @@ > register int s; > int i = 0; > char tpat[NPAT+20]; >- EXTRAKEYS menu_pat[8]; >+ EXTRAKEYS menu_pat[10]; > > menu_pat[i = 0].name = "^Y"; > menu_pat[i].label = "FirstLine"; >@@ -517,6 +524,11 @@ > 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,6 +544,11 @@ > 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,7 +647,7 @@ > register int s; > int i; > char tpat[NPAT+20]; >- EXTRAKEYS menu_pat[7]; >+ EXTRAKEYS menu_pat[9]; > > menu_pat[i = 0].name = "^Y"; > menu_pat[i].label = "FirstLine"; >@@ -643,6 +660,11 @@ > 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,6 +680,11 @@ > 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'); >@@ -705,9 +732,19 @@ > register int c; /* character at current position */ > register LINE *matchline; /* current line during matching */ > register int matchoff; /* position in matching line */ >- register char *patptr; /* pointer into pattern */ >+ register char *patptr = patrn; /* pointer into pattern */ >+ unsigned char *tmp; > register int stopoff; /* offset to stop search */ > register LINE *stopline; /* line to stop search */ >+ unsigned int ucspat[NPAT], ucspos = 0, match; >+ >+ /* In Unicode mode, we've to create an UCS-4 vector from the pattern: */ >+ while (gmode & P_UNICODE && *patptr != 0 && ucspos < NPAT) { >+ tmp = patptr; >+ ucspat[ucspos++] = utf8_get_ucs_string(&tmp, strlen(patptr)); >+ patptr = tmp; >+ } >+ ucspat[ucspos] = 0; /* terminate the int vector with a zero int */ > > *wrapt = FALSE; > >@@ -759,15 +796,23 @@ > else > c = lgetc(curline, curoff++).c; /* get the char */ > >+ if (gmode & P_UNICODE) { >+ match = ucspat[ucspos=0]; >+ } else >+ match = patrn[0]; >+ > /* test it against first char in pattern */ >- if (eq(c, patrn[0]) != FALSE) { /* if we find it..*/ >+ if (eq(c, match) != FALSE) { /* if we find it..*/ > /* setup match pointers */ > matchline = curline; > matchoff = curoff; > patptr = &patrn[0]; > > /* scan through patrn for a match */ >- while (*++patptr != 0) { >+ while (1) { >+ if (!(match = *++patptr) || (gmode & P_UNICODE && >+ !(match = ucspat[++ucspos]))) >+ break; > /* advance all the pointers */ > if (matchoff == llength(matchline)) { > /* advance past EOL */ >@@ -781,7 +826,7 @@ > return(FALSE); > > /* and test it against the pattern */ >- if (eq(*patptr, c) == FALSE) >+ if (eq(match, c) == FALSE) > goto fail; > } > >@@ -820,10 +865,10 @@ > int maxlength; /* maximum chars in destination */ > > { >- char c; /* current char to translate */ >+ unsigned char c; /* current char to translate */ > > /* scan through the string */ >- while ((c = *srcstr++) != 0) { >+ while ((c = (unsigned char) *srcstr++) != 0) { > if (c == '\n') { /* its an EOL */ > *deststr++ = '<'; > *deststr++ = 'N'; >diff -ru pine4.64/pico/word.c pine4.64.SuSE/pico/word.c >--- pine4.64/pico/word.c 2004-05-07 23:45:04.000000000 +0200 >+++ pine4.64.SuSE/pico/word.c 2006-02-14 14:45:23.000000000 +0100 >@@ -54,7 +54,7 @@ > return(FALSE); > > for(bp = cnt = i = 0; cnt < llength(curwp->w_dotp) && !bp; cnt++, i++){ >- if(isspace((unsigned char) lgetc(curwp->w_dotp, cnt).c)){ >+ if(cell_isspace(curwp->w_dotp, cnt)){ > first = 0; > if(lgetc(curwp->w_dotp, cnt).c == TAB) > while(i+1 & 0x07) >@@ -84,7 +84,7 @@ > if(!(curbp->b_flag & BFWRAPOPEN) > && lforw(curwp->w_dotp) != curbp->b_linep > && llength(lforw(curwp->w_dotp)) >- && !isspace((unsigned char) lgetc(lforw(curwp->w_dotp), 0).c) >+ && !cell_isspace(lforw(curwp->w_dotp), 0) > && (llength(curwp->w_dotp) + llength(lforw(curwp->w_dotp)) < fillcol)){ > gotoeol(0, 1); /* then pull text up from below */ > if(lgetc(curwp->w_dotp, curwp->w_doto - 1).c != ' ') >@@ -360,44 +360,1172 @@ > && isalnum((unsigned char)lgetc(curwp->w_dotp, curwp->w_doto).c)); > } > >+/* Support of indentation of paragraphs */ >+#define UCH(c) ((unsigned char) (c)) >+#define NBSP UCH('\240') >+#define ISspace(c) (UCH(c) == ' ' || UCH(c) == TAB || UCH(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)); >+int get_indent_raw_line PROTO((char *, char *, char *, int, 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 iscontrol(c) (iscntrl(((int) (c)) & 0x7f) ? 1 : 0) >+#define forbidden(c) (((c) == '\"') || ((c) == '\'') || ((c) == '$') ||\ >+ ((c) == ',') || ((c) == '.') || ((c) == '-') ||\ >+ ((c) == LPAREN) || ((c) == '/')|| ((c) == '`') ||\ >+ ((c) == '{') || ((c) == '\\') || (iscontrol((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 *)); >+QSTRING_S *qs_quote_match PROTO((char *, LINE *, char *, int)); >+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 linencpy PROTO((char *, LINE *, int)); >+ >+char * >+default_qstr() >+{ >+ return (glo_quote_str ? glo_quote_str >+ : (Pmaster && Pmaster->quote_str) ? Pmaster->quote_str : ""); >+} >+ >+/* >+ * 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(*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(cl->value[i])) >+ i--; >+ i += (i < l) ? 2 : 1; >+ cl->value[i] = '\0'; >+ } >+ } >+ >+ return cl; >+} > > /* >- * Return number of quotes if whatever starts the line matches the quote string >+ * 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. > */ >-quote_match(q, l, buf, buflen) >+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, bufflen) >+ QSTRING_S *qs; >+ char *buff; >+ int bufflen; >+{ >+ int i, j; >+ >+ if(!buff || bufflen <= 0) >+ return; >+ >+ for (i = 0; qs; qs = qs->next) >+ for (j = 0; i < bufflen - 1 >+ && (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(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, rqstr, rqstrlen) >+ char *q; >+ LINE *l; >+ char *rqstr; >+ int rqstrlen; >+{ >+ 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; >+ int plb = 1; >+ >+ linencpy(GLine, l, NSTRING); >+ >+ if (nl) >+ linencpy(NLine, nl, NSTRING); >+ >+ if (pl){ >+ linencpy(PLine, pl, NSTRING); >+ if(lback(pl) != curbp->b_linep){ >+ char PPLine[NSTRING] = {'\0'}; >+ >+ linencpy(PPLine, lback(pl), NSTRING); >+ plb = line_isblank(q, PLine, GLine, PPLine, NSTRING); >+ } >+ } >+ >+ return do_quote_match(q, GLine, NLine, PLine, rqstr, rqstrlen, plb); >+} >+ >+/* >+ * Return number of quotes if whatever starts the line matches the quote >+ * string. >+ * rqstring is pointer to raw qstring, buf points to processed qstring >+ */ >+quote_match(q, l, buf, buflen, raw) > char *q; > LINE *l; > char *buf; > int buflen; >+ int raw; > { >- register int i, n, j, qb; >+ QSTRING_S *qs; >+ char rqstr[NSTRING] = {'\0'}; > >- *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'; >- } >+ qs = qs_quote_match(q, l, rqstr, NSTRING); >+ flatten_qstring(qs, buf, buflen); >+ if (qs) >+ free_qs(&qs); >+ >+ if(raw){ >+ strncpy(buf, rqstr, buflen < NSTRING ? buflen : NSTRING); >+ buf[buflen-1] = '\0'; >+ } >+ >+ 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); >+} >+ >+line_isblank(q, GLine, NLine, PLine, buflen) >+ char *q, *GLine, *PLine, *NLine; >+ int buflen; >+{ >+ int n = 0; >+ QSTRING_S *cl; >+ char qstr[NSTRING]; >+ >+ cl = do_raw_quote_match(q, GLine, NLine, PLine, NULL, NULL); >+ >+ flatten_qstring(cl, qstr, NSTRING); >+ >+ free_qs(&cl); >+ >+ for(n = strlen(qstr); n < buflen && GLine[n]; n++) >+ if(!isspace((unsigned char) GLine[n])) >+ return(FALSE); >+ >+ return(TRUE); >+} >+ >+ >+QSTRING_S * >+do_raw_quote_match(q, GLine, NLine, PLine, nlp, plp) >+ char *q, *GLine, *NLine, *PLine; >+ QSTRING_S **nlp, **plp; >+{ >+ QSTRING_S *cl, *nl = NULL, *pl = NULL; >+ char nbuf[NSTRING], pbuf[NSTRING], buf[NSTRING]; >+ int emptypl = 0, emptynl = 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(nlp) >+ *nlp = nl; >+ } >+ if (PLine && PLine[0]){ >+ pl = is_quote(q, PLine, 0); /* Previous Line */ >+ if(plp) >+ *plp = pl; >+ } >+ >+ /* >+ * 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, NSTRING); >+ emptypl = (!PLine || !PLine[0] || >+ (pl && value_is_space(pbuf)) && !PLine[strlen(pbuf)]) ? 1 : 0; >+ if (emptypl){ >+ flatten_qstring(nl, nbuf, NSTRING); >+ 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); >+ if(nlp) *nlp = NULL; >+ if(plp) *plp = NULL; >+ >+ 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); >+ >+ if(nlp) *nlp = nl; >+ if(plp) *plp = pl; >+ >+ return cl; >+} >+ >+QSTRING_S * >+do_quote_match(q, GLine, NLine, PLine, rqstr, rqstrlen, plb) >+ char *q, *GLine, *NLine, *PLine, *rqstr; >+ int rqstrlen, plb; >+{ >+ QSTRING_S *cl, *nl = NULL, *pl = NULL; >+ int c, n, p,i, j, NewP, NewC, NewN, clength, same = 0; >+ char nbuf[NSTRING], pbuf[NSTRING], buf[NSTRING]; >+ >+ cl = do_raw_quote_match(q, GLine, NLine, PLine, &nl, &pl); >+ >+ if (!cl) /* if nothing in, nothing out */ >+ return cl; >+ >+ flatten_qstring(cl, rqstr, rqstrlen); >+ flatten_qstring(cl, buf, NSTRING); >+ flatten_qstring(nl, nbuf, NSTRING); >+ flatten_qstring(pl, pbuf, NSTRING); >+ >+ /* >+ * 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) >+ */ >+ >+ NewP = strlenis(pbuf); >+ 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){ >+ int agree = 0; >+ for (j = 0; (j < n) && (GLine[j] == NLine[j]); j++); >+ clength = j; >+ /* clength is the common length in which Gline and Nline agree */ >+ /* j < n means that they do not agree fully */ >+ /* GLine = " \tText" >+ NLine = " Text" */ >+ if(j == n) >+ agree++; >+ if (clength < n){ /* see if buf and nbuf are padded with spaces and tabs */ >+ for (i = clength; i < n && ISspace(NLine[i]); i++); >+ if (i == n){/* padded NLine until the end of spaces? */ >+ for (i = clength; i < c && ISspace(GLine[i]); i++); >+ if (i == c) /* Padded CLine until the end of spaces? */ >+ agree++; >+ } > } >- if(j > llength(l)) >- return(n); >- else if(qb && lgetc(l, j).c == ' ') >- j++; >+ if (agree){ >+ for (j = clength; j < c && ISspace(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. >+ * Example when it should not free_qs(cl) >+ * " Text in Paragraph 1" (PLine) >+ * " Text in Paragraph 1" (GLine) >+ * " Other Paragraph Number 2" (NLine) >+ * >+ * Example when it should free_qs(cl): >+ * ":) " (PLine) p = 3, j = 3 >+ * ":) Text" (GLine) c = 5 >+ * ":) More text" (NLine) n = 3 >+ * >+ * Example when it should free_qs(cl): >+ * ":) " (PLine) p = 3, j = 3 >+ * ":) > > > Text" (GLine) c = 11 >+ * ":) > > > More text" (NLine) n = 9 >+ * >+ * Example when it should free_qs(cl): >+ * ":) :) " (PLine) p = 6, j = 3 >+ * ":) > > > Text" (GLine) c = 11 >+ * ":) > > > More text" (NLine) n = 9 >+ * >+ * Example when it should free_qs(cl): >+ * ":) > > > " (PLine) p = 13, j = 11 >+ * ":) > > > Text" (GLine) c = 11 >+ * ":) > > > More text" (NLine) n = 9 >+ * >+ * The following example is very interesting. The "Other Text" >+ * line below should free the quote string an make it equal to the >+ * quote string of the line below it, but any algorithm trying >+ * to advance past that line should make it stop there, so >+ * we need one more check, to check the raw quote string and the >+ * processed quote string at the same time. >+ * FREE qs in this example. >+ * " Some Text" (PLine) p = 3, j = 0 >+ * "\tOther Text" (GLine) c = 1 >+ * " More Text" (NLine) n = 3 >+ * >+ */ >+ >+ for (j = 0; (j < p) && (GLine[j] == PLine[j]); j++); >+ if (((p == c) && ((j != p) && NLine[n])) >+ || ((p != c) && NLine[n])){ >+ if(!get_indent_raw_line(q, PLine, nbuf, NSTRING, p, plb) >+ || NewP + strlenis(nbuf) != NewC){ >+ 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; > } >- return(n); /* never reached */ >+ 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; >+ >+ for (i = 0; qstr && 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,11 +1602,13 @@ > 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]; >+ 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 */ >@@ -496,17 +1625,75 @@ > return(FALSE); > > eopline = curwp->w_dotp; /* first line of para */ >- > /* and back to the beginning of the paragraph */ > gotobop(FALSE, 1); >+ setimark(FALSE, 1); /* Remember this spot in case we unjustify */ > >- /* 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; >+ /* >+ * 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(default_qstr(), curwp->w_dotp, ind_str, NSTRING, 0); >+ qstrfl = (quote_match(default_qstr(), curwp->w_dotp, qstrfl2, NSTRING, 0) >+ && *qstrfl2) ? qstrfl2 : NULL; >+ if (qstrfl) >+ for (; (i < NSTRING) && (quoid[i] = qstrfl[i]); i++); >+ 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(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 = quote_match(default_qstr(), 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(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(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,18 +1711,38 @@ > return(FALSE); > > /* Now insert it back wrapped */ >- spaces = word_len = line_len = same_word = 0; >+ spaces = word_len = line_len = same_word = i = 0; > > /* Beginning with leading quoting... */ >- if(qstr){ >- while(qstr[line_len]) >- linsert(1, qstr[line_len++]); >+ 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 = qlen; (c = fremove(i)) == ' ' || c == TAB; i++){ >+ for(i; (c = fremove(i)) == ' ' || c == TAB; i++){ > linsert(1, line_last = c); > line_len += ((c == TAB) ? (~line_len & 0x07) + 1 : 1); > } >@@ -558,15 +1765,15 @@ > > default : > if(spaces){ /* flush word? */ >- if((line_len - qlen > 0) >+ if((line_len - qlenis > 0) > && line_len + word_len + 1 > fillcol >- && ((isspace((unsigned char)line_last)) >+ && ((Pisspace(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)){ >+ if(line_len && !Pisspace(line_last)){ > linsert(1, ' '); /* need padding? */ > line_len++; > } >@@ -588,8 +1795,8 @@ > > 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)) >+ if((line_len - qlenis > 0) && !same_word++){ >+ if(!Pisspace(line_last)) > linsert(1, ' '); > line_len = fpnewline(qstr); > } >@@ -608,12 +1815,13 @@ > } > > if(word_len){ >- if((line_len - qlen > 0) && (line_len + word_len + 1 > fillcol)){ >- if(!isspace((unsigned char) line_last)) >+ if((line_len - qlenis > 0) && (line_len + word_len + 1 > fillcol)){ >+ if(!Pisspace(line_last)) > linsert(1, ' '); >- (void) fpnewline(qstr); >+ if (line_len && (line_len != qlenis)) >+ (void) fpnewline(qstr); > } >- else if(line_len && !isspace((unsigned char) line_last)) >+ else if(line_len && !Pisspace(line_last)) > linsert(1, ' '); > > for(j = 0; j < word_len; j++) >@@ -634,11 +1842,155 @@ > fpnewline(quote) > char *quote; > { >- int len; >+ int i; > > lnewline(); >- for(len = 0; quote && *quote; quote++, len++) >- linsert(1, *quote); >+ for(i = 0; quote && quote[i]; i++) >+ linsert(1, quote[i]); > >- return(len); >+ return strlenis(quote); > } >+ >+int >+is_indent (word, plb) >+ char word[NSTRING]; >+ int plb; >+{ >+ int i = 0, finished = 0, c, nxt, j, k, digit = 0, bdigits = -1, alpha = 0; >+ >+ if (!word || !word[0]) >+ return i; >+ >+ for (i = 0, j = 0; ISspace(word[i]); i++, j++); >+ while ((i < NSTRING - 2) && !finished){ >+ switch (c = now(word,i)){ >+ case NBSP: >+ case TAB : >+ case ' ' : for (; ISspace(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) && alpha) >+ || ((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)){ >+ alpha++; >+ 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, 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(lgetc(lback(l), i).c); i--); >+ if (EOLchar(lgetc(lback(l), i).c)) >+ plb++; >+ } >+ >+ return get_indent_raw_line(q, GLine, buf, buflen, k, plb); >+} >+ >+int >+get_indent_raw_line(q, GLine, buf, buflen, k, plb) >+ char *q; >+ char *GLine; >+ char *buf; >+ int buflen; >+ int k; >+ int plb; >+{ >+ int i, j; >+ >+ i = is_indent(GLine+k, plb); >+ >+ for (j = 0; (j < i) && (j < buflen) && (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 -ru pine4.64/pine/addrbook.c pine4.64.SuSE/pine/addrbook.c >--- pine4.64/pine/addrbook.c 2005-09-13 00:04:25.000000000 +0200 >+++ pine4.64.SuSE/pine/addrbook.c 2006-02-14 14:45:22.000000000 +0100 >@@ -6659,10 +6659,11 @@ > *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[4]; >+ ESCKEY_S ekey[5]; > PerAddrBook *pab; > long nl; > >@@ -6677,17 +6678,22 @@ > 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[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[3].ch = -1; >+ ekey[4].ch = -1; > > flags = OE_APPEND_CURRENT | OE_KEEP_TRAILING_SPACE; > while(1){ >@@ -6698,6 +6704,9 @@ > 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 */ >@@ -6725,7 +6734,7 @@ > } > } > >- if(rc != 4) >+ if(rc != 4 && rc != 9) > break; > } > >@@ -6738,6 +6747,9 @@ > 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 -ru pine4.64/pine/adrbkcmd.c pine4.64.SuSE/pine/adrbkcmd.c >--- pine4.64/pine/adrbkcmd.c 2005-09-27 23:27:55.000000000 +0200 >+++ pine4.64.SuSE/pine/adrbkcmd.c 2006-02-14 14:45:22.000000000 +0100 >@@ -3866,6 +3866,8 @@ > * 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,6 +3875,7 @@ > 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 -ru pine4.64/pine/args.c pine4.64.SuSE/pine/args.c >--- pine4.64/pine/args.c 2005-03-10 02:10:08.000000000 +0100 >+++ pine4.64.SuSE/pine/args.c 2006-02-14 14:45:22.000000000 +0100 >@@ -74,6 +74,7 @@ > char args_err_non_abs_passfile[] = "argument to \"-passfile\" should be fully-qualified"; > char args_err_missing_lu[] = "missing argument for option \"-create_lu\"\nUsage: pine -create_lu <addrbook_file> <addrbook_sort_type>"; > char args_err_missing_sort[] = "missing argument for option \"-sort\""; >+char args_err_missing_thread_sort[] = "missing argument for option \"-threadsort\""; > char args_err_missing_flag_arg[] = "missing argument for flag \"%c\""; > char args_err_missing_flag_num[] = "Non numeric argument for flag \"%c\""; > char args_err_missing_debug_num[] = "Non numeric argument for \"%s\""; >@@ -117,6 +118,7 @@ > " -z \t\tSuspend - allow use of ^Z suspension", > " -r \t\tRestricted - can only send mail to oneself", > " -sort <sort>\tSort - Specify sort order of folder:", >+" -threadsort <sort>\tSort - Specify sort order of thread index screen:", > "\t\t subject, arrival, date, from, size, /reverse", > " -i\t\tIndex - Go directly to index, bypassing main menu", > " -I <keystroke_list> Initial keystrokes to be executed", >@@ -202,6 +204,7 @@ > 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,6 +392,18 @@ > > 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,6 +511,12 @@ > 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 -ru pine4.64/pine/bldaddr.c pine4.64.SuSE/pine/bldaddr.c >--- pine4.64/pine/bldaddr.c 2005-09-27 23:27:55.000000000 +0200 >+++ pine4.64.SuSE/pine/bldaddr.c 2006-02-14 14:45:22.000000000 +0100 >@@ -1,5 +1,5 @@ > #if !defined(lint) && !defined(DOS) >-static char rcsid[] = "$Id: bldaddr.c 14092 2005-09-27 21:27:55Z hubert@u.washington.edu $"; >+static char rcsid[] = "$Id: bldaddr.c 14099 2005-10-04 22:47:31Z hubert@u.washington.edu $"; > #endif > /*---------------------------------------------------------------------- > >@@ -2306,8 +2306,14 @@ > if(as.cur >= as.how_many_personals) > pab->type |= GLOBAL; > >- pab->access = adrbk_access(pab); >- >+ if(ps_global->mail_stream && >+ ps_global->mail_stream->lock && (pab->type & REMOTE_VIA_IMAP)){ >+ as.initialized = 0; >+ pab->access = NoAccess; >+ } >+ else{ >+ pab->access = adrbk_access(pab); >+ } > /* global address books are forced readonly */ > if(pab->type & GLOBAL && pab->access != NoAccess) > pab->access = ReadOnly; >@@ -7424,14 +7430,17 @@ > int abook_num; > { > ADDRESS *addr; >- char *a_string; >+ char *a_string, *ret = NULL; > int return_nick = 1; >+ AdrBk_Entry *abe_copy = NULL; > > if(!dl || !abe) > return(cpystr("")); > >+ abe_copy = copy_ae(abe); >+ > if(!(dl->type == Simple || dl->type == ListHead) >- || !(abe->nickname && abe->nickname[0])) >+ || !(abe_copy->nickname && abe_copy->nickname[0])) > return_nick = 0; > > if(return_nick){ >@@ -7455,7 +7464,8 @@ > * Also, if the other entry with the same nickname is in this > * same addressbook and comes before this entry, same deal. > */ >- fname = addr_lookup(abe->nickname, &which_addrbook, -1, &found_abe); >+ fname = addr_lookup(abe_copy->nickname, &which_addrbook, -1, >+ &found_abe); > found_it = (fname != NULL); > if(fname) > fs_give((void **) &fname); >@@ -7466,31 +7476,31 @@ > /* if the returned abe is not the same as abe don't use the nickname */ > if(return_nick && found_it && which_addrbook == abook_num){ > if(found_abe >- && ((found_abe->tag != abe->tag) >- || (found_abe->fullname && !abe->fullname) >- || (!found_abe->fullname && abe->fullname) >- || strcmp(found_abe->fullname, abe->fullname) >- || (found_abe->fcc && !abe->fcc) >- || (!found_abe->fcc && abe->fcc) >- || strcmp(found_abe->fcc, abe->fcc) >- || (found_abe->extra && !abe->extra) >- || (!found_abe->extra && abe->extra) >- || strcmp(found_abe->extra, abe->extra) >- || (abe->tag == Single && strcmp(found_abe->addr.addr ? found_abe->addr.addr : "", abe->addr.addr ? abe->addr.addr : "")))) >+ && ((found_abe->tag != abe_copy->tag) >+ || (found_abe->fullname && !abe_copy->fullname) >+ || (!found_abe->fullname && abe_copy->fullname) >+ || strcmp(found_abe->fullname, abe_copy->fullname) >+ || (found_abe->fcc && !abe_copy->fcc) >+ || (!found_abe->fcc && abe_copy->fcc) >+ || strcmp(found_abe->fcc, abe_copy->fcc) >+ || (found_abe->extra && !abe_copy->extra) >+ || (!found_abe->extra && abe_copy->extra) >+ || strcmp(found_abe->extra, abe_copy->extra) >+ || (abe_copy->tag == Single && strcmp(found_abe->addr.addr ? found_abe->addr.addr : "", abe_copy->addr.addr ? abe_copy->addr.addr : "")))) > return_nick = 0; > > /* I suppose we ought to check for the lists being the same */ >- if(return_nick && abe->tag == List && found_abe){ >+ if(return_nick && abe_copy->tag == List && found_abe){ > char **p, **q; > int i, n1, n2; > >- for(p = abe->addr.list; p && *p; p++) >+ for(p = abe_copy->addr.list; p && *p; p++) > ; > > if(p == NULL) > n1 = 0; > else >- n1 = p - abe->addr.list; >+ n1 = p - abe_copy->addr.list; > > for(p = found_abe->addr.list; p && *p; p++) > ; >@@ -7502,7 +7512,7 @@ > > if(n1 == n2){ > for(i = 0; i < n1 && return_nick; i++) >- if(strcmp(abe->addr.list[i], found_abe->addr.list[i])) >+ if(strcmp(abe_copy->addr.list[i],found_abe->addr.list[i])) > return_nick = 0; > } > else >@@ -7515,9 +7525,10 @@ > } > > if(return_nick) >- return(cpystr(abe->nickname)); >+ ret = cpystr(abe_copy->nickname); > else{ >- addr = abe_to_address(abe, dl, as.adrbks[abook_num].address_book, NULL); >+ addr = abe_to_address(abe_copy, dl, as.adrbks[abook_num].address_book, >+ NULL); > > /* always returns a string */ > a_string = addr_list_string(addr, NULL, 0, 0); >@@ -7525,8 +7536,13 @@ > if(addr) > mail_free_address(&addr); > >- return(a_string); >+ ret = a_string; > } >+ >+ if(abe_copy) >+ free_ae(&abe_copy); >+ >+ return(ret); > } > > >Only in pine4.64.SuSE/pine: date.c >diff -ru pine4.64/pine/filter.c pine4.64.SuSE/pine/filter.c >--- pine4.64/pine/filter.c 2005-08-30 02:08:19.000000000 +0200 >+++ pine4.64.SuSE/pine/filter.c 2006-02-14 14:45:24.000000000 +0100 >@@ -65,6 +65,9 @@ > > > #include "headers.h" >+#ifdef HAVE_ICONV >+#include <iconv.h> >+#endif > > > /* >@@ -204,6 +207,10 @@ > 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 */ >@@ -705,6 +712,7 @@ > #define FL_SIG 17 > #define STOP_DECODING 18 > #define SPACECR 19 >+#define UTF8 20 > > > >@@ -2266,6 +2274,110 @@ > } > } > >+#ifdef HAVE_ICONV >+/* >+ * This filter converts the input buffer in the MIME charset of >+ * a message, for example) to another (the user's display charset) >+ * using iconv(3), POSIX/Single Unix Standard API. >+ */ >+void >+gf_convert_utf8_charset(f, flg) >+ FILTER_S *f; >+ int flg; >+{ >+ static iconv_t iconv_desc; >+ static int einval_inbytesleft; >+ GF_INIT(f, f->next); >+ >+ switch (flg) { >+ case GF_DATA: { >+ size_t conv, inbytesleft = eob - op, outbytesleft = eib - ip; >+ /* >+ * If einval_inbytesleft is set, iconv() encountered an incomplete >+ * multibyte sequence and we asked for more input. In case the number >+ * of chars left to convert did not change, we should be at the end >+ * of input and we have an incomplete multibyte sequence at the end >+ * end of input. We only mark this and ignore the incomplete data. >+ */ >+ if (inbytesleft == einval_inbytesleft) { >+ char *einval_error = "[invalid multibyte seq at end of input]"; >+ dprint(8,(debugfile, "inval multibyte seq at end of input\n")); >+ for (;*einval_error;einval_error++) >+ GF_PUTC(f->next, *einval_error); >+ GF_FLUSH(f->next); >+ op = eob; /* throw the remaing unusable bytes away */ >+ GF_CH_RESET(f); >+ break; >+ } >+ while (1) { >+ if (!outbytesleft || !inbytesleft) { >+ GF_FLUSH(f->next); >+ outbytesleft = eib - ip; >+ } >+ if (!inbytesleft) { >+ GF_CH_RESET(f); >+ break; >+ } >+ einval_inbytesleft = -1; >+ conv = iconv(iconv_desc, (char **)&op, &inbytesleft, >+ (char **)&ip, &outbytesleft); >+ if (conv != (size_t) (-1)) { /* iconv succeeded */ >+ dprint(9,(debugfile, "irres. conv. count: %d, il: %d, ol: %d\n", >+ conv, inbytesleft, outbytesleft)); >+ /* iconv failed. check errno */ >+ } else if (errno == E2BIG){ >+ dprint(9,(debugfile, "e2big: outbytesleft=%d\n", outbytesleft)); >+ outbytesleft = 0; >+ } else if (errno == EILSEQ){ >+ char hexout[3]; >+ dprint(9,(debugfile, "eilseq: ill.octet=0x%02x, il=%d, ol=%d\n", >+ *op, inbytesleft, outbytesleft)); >+ sprintf(hexout, "%2x", *op++); >+ inbytesleft--; >+ GF_PUTC(f->next, '['); >+ GF_PUTC(f->next, hexout[0]); >+ GF_PUTC(f->next, hexout[1]); >+ GF_PUTC(f->next, ']'); >+ outbytesleft = eib - ip; >+ iconv(iconv_desc, NULL, NULL, NULL, NULL); >+ } else if (errno == EINVAL){ >+ /* >+ * We have to return from this function now because our input >+ * buffer contains an incomplete multibyte character which we >+ * can't complete without the next bytes of input. >+ */ >+ dprint(9,(debugfile, >+ "einval: %d, ol: %d, incomplete input: 0x%02x\n", >+ inbytesleft, outbytesleft, (unsigned char) *op)); >+ /* >+ * Before we abort here, we need to flush already converted >+ * output to the filter chain, otherwise we may loose this >+ * already converted content. >+ */ >+ GF_FLUSH(f->next); >+ /* >+ * In case we are at the end of all input, and we have >+ * an incomplete multibyte sequence left, we must find >+ * a way to not fall into a loop, remember the bytes left: >+ */ >+ einval_inbytesleft = inbytesleft; >+ break; /* Take the straigt way out now */ >+ } /* errno check */ >+ } /* while (1) */ >+ GF_END(f, f->next); >+ break; >+ } /* GF_DATA */ >+ case GF_RESET: >+ iconv_desc = (iconv_t)(f->opt); >+ iconv(iconv_desc, NULL, NULL, NULL, NULL); >+ einval_inbytesleft = -1; >+ break; >+ case GF_EOD: >+ GF_FLUSH(f->next); >+ (*f->next->f)(f->next, GF_EOD); >+ } /* switch (flg) */ >+} >+#else > > /* > * This filter converts characters in UTF-8 to an 8-bit or 16-bit charset. >@@ -2369,6 +2481,7 @@ > f->n = 0L; > } > } >+#endif > > > /* >@@ -6767,8 +6880,15 @@ > wrap_max, > margin_l, > margin_r, >+ offset, > indent; >+ char utf_seq[8]; > 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) >@@ -6788,6 +6908,7 @@ > #define WRAP_USE_CLR(F) (((WRAP_S *)(F)->opt)->use_color) > #define WRAP_STATE(F) (((WRAP_S *)(F)->opt)->state) > #define WRAP_QUOTED(F) (((WRAP_S *)(F)->opt)->quoted) >+#define WRAP_UTF_SEQ(F) (((WRAP_S *)(F)->opt)->utf_seq) > #define WRAP_TAGS(F) (((WRAP_S *)(F)->opt)->tags) > #define WRAP_BOLD(F) (((WRAP_S *)(F)->opt)->bold) > #define WRAP_ULINE(F) (((WRAP_S *)(F)->opt)->uline) >@@ -6803,6 +6924,12 @@ > #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; \ >@@ -6867,7 +6994,7 @@ > GF_INIT(f, f->next); > > if(flg == GF_DATA){ >- register unsigned char c; >+ unsigned char c, *ch, *cm; > register int state = f->f1; > register int x; > >@@ -6877,6 +7004,8 @@ > 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 */ > /* >@@ -6968,7 +7097,10 @@ > > case BOL : > if(WRAP_FLOW(f)){ >- if(c == '>'){ >+ 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 */ > } >@@ -6982,7 +7114,16 @@ > } > > /* quote level change implies new paragraph */ >- if(WRAP_FL_QD(f)){ >+ 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; >@@ -7034,8 +7175,11 @@ > break; > > case FL_QLEV : >- if(c == '>'){ /* another level */ >- WRAP_FL_QC(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)++; /* another level */ > } > else { > /* if EMBEDed, process it and return here */ >@@ -7047,7 +7191,16 @@ > } > > /* quote level change signals new paragraph */ >- if(WRAP_FL_QC(f) != WRAP_FL_QD(f)){ >+ 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 */ >@@ -7104,6 +7257,12 @@ > 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 */ >@@ -7120,7 +7279,7 @@ > &eob); /* note any embedded*/ > wrap_eol(f, 1, &ip, &eib, > &op, &eob); /* plunk down newline */ >- wrap_bol(f, 1, 1, &ip, &eib, >+ wrap_bol(f, 1, WRAP_FLOW(f), &ip, &eib, > &op, &eob); /* write any prefix */ > } > >@@ -7276,8 +7435,42 @@ > > break; > >+ case UTF8 : >+ if(!(ch = cm = pine_check_utf8(&c, WRAP_UTF_SEQ(f), sizeof(WRAP_UTF_SEQ(f))))) >+ break; /* sequence not complete, need next byte */ >+ state = DFL; /* end of sequence, leave the UTF-8 mode */ >+ if(ch != &c) { /* seq. complete, wrap and write it */ >+ if(f->n + f->f2 + WRAP_SPC_LEN(f) >+ > WRAP_COL(f) - (*ch == ' '?2:1)) { >+ dprint(8, (debugfile, "UTF8: newline\n")); >+ wrap_flush(f, &ip, &eib, &op, &eob); /* write everything */ >+ wrap_eol(f, 0, &ip, &eib, &op, &eob); /* no fit, the end */ >+ wrap_bol(f,1,1, &ip, &eib, &op, &eob); /* start w/prefix */ >+ } >+ f->n++; >+ if(*ch == ' ') { /* double-wide UTF-8 char, check space */ >+ ch++; /* ' ' was just a flag, skip over it */ >+ f->n++; >+ } >+ dprint(9, (debugfile, "UTF8: free room: %02d char: '%s'\n", >+ (WRAP_COL(f) - f->n - f->f2 - WRAP_SPC_LEN(f)), ch)); >+ f->n -= strlen(ch); >+ WRAP_PUTC(f, *ch++, 1); >+ while(*ch) >+ WRAP_PUTC(f, *ch++, 1); >+ if(*cm == ' ') >+ wrap_flush(f, &ip, &eib, &op, &eob); /* write everything */ >+ break; >+ } >+ WRAP_PUTC(f, '?', 1); /* in place of invalid sequence */ >+ /* fall thru to process new char */ >+ wrap_flush(f, &ip, &eib, &op, &eob); /* write everything */ > case_dfl : > case DFL : >+ if (!pine_check_utf8(&c, WRAP_UTF_SEQ(f), sizeof(WRAP_UTF_SEQ(f)))) { >+ state = UTF8; /* Change to UTF-8 mode */ >+ break; /* Process next char in UTF-8 mode */ >+ } > if(WRAP_SPEC(f, c)){ > switch(c){ > default : >@@ -7425,7 +7618,7 @@ > 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, >+ wrap_bol(f,1,WRAP_FLOW(f), &ip, &eib, &op, > &eob); /* write any prefix */ > } > >@@ -7483,6 +7676,13 @@ > 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 */ >@@ -7804,7 +8004,8 @@ > { > int j, i; > COLOR_PAIR *col = NULL; >- char *prefix = NULL, *last_prefix = 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); >@@ -7813,10 +8014,22 @@ > last_prefix = NULL; > } > } >- >- for(j = 0; j < WRAP_FL_QD(f); j++){ >+ >+ 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((j % 3) == 0 >+ 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, >@@ -7824,7 +8037,7 @@ > && pico_is_good_colorpair(col)){ > GF_COLOR_PUTC(f, col); > } >- else if((j % 3) == 1 >+ 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, >@@ -7832,7 +8045,7 @@ > && pico_is_good_colorpair(col)){ > GF_COLOR_PUTC(f, col); > } >- else if((j % 3) == 2 >+ 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, >@@ -7845,45 +8058,54 @@ > col = NULL; > } > } >+ if (j > 1 && wrap_qstr[j-1] == ' ') >+ j -= 1; > >- 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; >- } >+ 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{ >- GF_PUTC_GLO(f->next, '>'); >- f->n += 1; >+ 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 && last_prefix){ >+ 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 += strlen(last_prefix); >+ 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; > } > >@@ -7914,6 +8136,12 @@ > 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); > } >@@ -8335,7 +8563,184 @@ > } \ > } > >+#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 >@@ -8360,7 +8765,12 @@ > if(state){ > state = 0; > if(c == '\012'){ >- int done; >+ 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); > >@@ -8422,6 +8832,7 @@ > 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 -ru pine4.64/pine/folder.c pine4.64.SuSE/pine/folder.c >--- pine4.64/pine/folder.c 2005-09-13 00:04:25.000000000 +0200 >+++ pine4.64.SuSE/pine/folder.c 2006-02-14 14:45:22.000000000 +0100 >@@ -94,7 +94,7 @@ > #define FLW_SLCT 0x02 > #define FLW_LIST 0x04 > >- >+static int max_slot_size = 0; > > > /*---------------------------------------------------------------------- >@@ -224,6 +224,8 @@ > 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)); > 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,7 +471,7 @@ > > HELP_MENU, > OTHER_MENU, >- NULL_MENU, >+ {"^H","ChkIncFld",{MC_FORCECHECK,1,ctrl('H')}, KS_NONE}, > NULL_MENU, > NULL_MENU, > NULL_MENU, >@@ -1708,6 +1710,7 @@ > 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,6 +1845,7 @@ > *fs->cache_streamp = NULL; > } > >+ ps->in_fld_list = 0; > return(folder_proc_data.rv); > } > >@@ -1944,6 +1948,9 @@ > gf_puts("\n", pc); > } > >+ if(!selected_folders(c_list) && (c_list->use & CNTXT_ZOOM)) >+ c_list->use &= ~CNTXT_ZOOM; >+ > if(c_list->use & CNTXT_ZOOM){ > sprintf(tmp_20k_buf, "[ ZOOMED on %d (of %d) %ss ]", > selected_folders(c_list), >@@ -1955,6 +1962,18 @@ > 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)){ >+ strcpy(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,8 +2011,22 @@ > 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)){ >+ if(F_OFF(F_ENABLE_FAST_RECENT, ps_global)){ >+ len += strlen(comatose(f->countrecent)); >+ len += strlen(comatose(f->messages)); >+ len += 4; /* "[/]" + "."/"_"/"~"/" " */ >+ } >+ else >+ len += 1; /* " " */ >+ } >+ len += 1; >+ > if(slot_size < len) > slot_size = len; >+ max_slot_size = slot_size; > } > > if(F_ON(F_SINGLE_FOLDER_LIST, ps_global)){ >@@ -2098,7 +2131,7 @@ > int flags; > { > char buf[256]; >- int l = 0; >+ int l = 0, s = 0; > FOLDER_S *fp; > HANDLE_S *h; > >@@ -2121,6 +2154,11 @@ > && (*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, >+ (ps_global->last_folder_checked == fnum) >+ ? 1 >+ : ((ps_global->first_folder_checked == fnum) >+ ? -1 : 0))) >= 0 > && ((fp->isdir && fp->isfolder) ? (*pc)('[') : 1) > && ((fp->isdir) ? (*pc)(ctxt->dir->delim) : 1) > && ((fp->isdir && fp->isfolder) ? (*pc)(']') : 1)) >@@ -2128,7 +2166,7 @@ > && (h ? ((*pc)(TAG_EMBED) && (*pc)(TAG_BOLDOFF) > && (*pc)(TAG_EMBED) && (*pc)(TAG_INVOFF)) : 1)){ > if(fp){ >- l += strlen(FLDR_NAME(fp)); >+ l += strlen(FLDR_NAME(fp)) + s; > if(fp->isdir) > l += (fp->isfolder) ? 3 : 1; > } >@@ -2139,6 +2177,49 @@ > return(l); > } > >+int >+folder_list_write_count(f, ctxt, pc, l, is_last) >+ FOLDER_S *f; >+ CONTEXT_S *ctxt; >+ gf_io_t pc; >+ int l, is_last; >+{ >+ int rv = 0, i; >+ >+ if (ctxt->use & CNTXT_INCMNG && >+ F_ON(F_ENABLE_INCOMING_CHECK,ps_global) && >+ F_ON(F_ENABLE_INCOMING,ps_global)){ >+ rv = max_slot_size - strlen(FLDR_NAME(f)) - l; >+ if(F_OFF(F_ENABLE_FAST_RECENT, ps_global)){ >+ rv -= strlen(comatose(f->countrecent)); >+ rv -= strlen(comatose(f->messages)); >+ rv -= 3; >+ } >+ if(f->skipped) >+ gf_puts(".", pc); >+ else if(is_last > 0) >+ gf_puts("_", pc); >+ else if (is_last < 0) >+ gf_puts("~", pc); >+ if(f->skipped || is_last) >+ rv--; >+ >+ rv -= 1; /* len += 1 was added as space between folders */ >+ if(F_OFF(F_ENABLE_FAST_RECENT, ps_global)){ >+ 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 - 1; >+ } >+ else >+ rv = max_slot_size - strlen(FLDR_NAME(f)) - l - 1 - rv; >+ } >+ return rv; >+} >+ > > int > folder_list_write_prefix(f, flags, pc) >@@ -2224,6 +2305,19 @@ > 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,7 +2556,16 @@ > "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 & IF_REFRESH_STRONG)) ? 1 : 0; >+ ps_global->refresh_list &= IF_REFRESH_NONE; >+ break; >+ > > /*-------------- Delete --------------------*/ > case MC_DELETE : >@@ -2737,10 +2840,14 @@ > tot = strm->nmsgs; > rec = strm->recent; > } >+ if(folder->origrecent > rec) >+ folder->origrecent = rec; >+ folder->countrecent = rec > folder->origrecent >+ ? rec - folder->origrecent : 0L; > } > else{ > tot = strm->nmsgs; >- rec = sp_recent_since_visited(strm); >+ rec = folder->countrecent = sp_recent_since_visited(strm); > } > } > /* >@@ -2759,6 +2866,10 @@ > && mm_status_result.flags & SA_RECENT){ > tot = mm_status_result.messages; > rec = mm_status_result.recent; >+ if(folder->origrecent > rec) >+ folder->origrecent = rec; >+ folder->countrecent = rec > folder->origrecent >+ ? rec - folder->origrecent : 0L; > gotit++; > } > } >@@ -2771,6 +2882,10 @@ > if(strm){ > tot = strm->nmsgs; > rec = strm->recent; >+ if(folder->origrecent > rec) >+ folder->origrecent = rec; >+ folder->countrecent = rec > folder->origrecent >+ ? rec - folder->origrecent : 0L; > gotit++; > pine_mail_close(strm); > } >@@ -2783,10 +2898,16 @@ > if(we_cancel) > cancel_busy_alarm(-1); > >- if(gotit) >+ if(gotit){ > sprintf(tmp_output, > "%lu total message%.2s, %lu of them recent", > tot, plural(tot), rec); >+ ps_global->refresh_list |= IF_REFRESH_STRONG; >+ if (rec > 0L) >+ folder->notified = 1; >+ folder->selected = folder->countrecent > 0L >+ ? 1 : folder->user_selected; >+ } > } > }else > strncpy(tmp_output, "No folder to check! Can't get recent info", >@@ -3323,8 +3444,10 @@ > case 'f' : /* flip selection */ > n = folder_total(FOLDERS(context)); > for(total = i = 0; i < n; i++) >- if(f = folder_entry(i, FOLDERS(context))) >+ if(f = folder_entry(i, FOLDERS(context))){ > f->selected = !f->selected; >+ f->user_selected = f->selected; >+ } > > return(1); /* repaint */ > >@@ -3467,15 +3590,64 @@ > CONTEXT_S *context; > { > int i, n, total; >+ FOLDER_S *f; > > n = folder_total(FOLDERS(context)); >- for(total = i = 0; i < n; i++) >- if(folder_entry(i, FOLDERS(context))->selected) >+ 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,6 +4376,7 @@ > > if(f = folder_entry(index, FOLDERS(context))){ > f->selected = !f->selected; >+ f->user_selected = f->selected; > return((*func)(context, index)); > } > return 1; >@@ -7223,6 +7396,9 @@ > 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 |= IF_REFRESH_STRONG; > } > > >@@ -8406,11 +8582,17 @@ > long *find_recent; > int *did_cancel; > { >- int index, recent = 0, failed_status = 0, try_fast; >+ 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,7 +8603,9 @@ > if(find_recent) > *find_recent = 0L; > >- for(index = folder_index(current, cntxt, FI_FOLDER) + 1; >+ >+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,6 +8616,11 @@ > 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,19 +8772,196 @@ > } > } > >- if(f && (!find_recent || recent)) >+ 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 | SP_RO_OK)) != NULL) >+ || ((stream = already_open_stream(tmp, AOS_NONE)) != NULL)){ >+ *opstrm = 1; >+ (void) pine_mail_ping(stream); >+ if(stream == ps_global->mail_stream){ >+ next = new_mail_in_open_stream(stream, find_recent, find_messages); >+ if(f->origrecent > *find_recent) >+ f->origrecent = *find_recent; >+ if(ps_global->in_fld_list) >+ f->notified = f->countrecent == 0 >+ ? (*find_recent == f->recent) >+ && (*find_messages == f->messages) >+ : 1; >+ f->countrecent = *find_recent > f->origrecent >+ ? *find_recent - f->origrecent : 0L; >+ } >+ else{ >+ *find_recent = f->countrecent = sp_recent_since_visited(stream); >+ *find_messages = stream->nmsgs; >+ next = *find_recent ? STREAMNAME(stream) : NULL; >+ } >+ 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{ >+ /* We failed, so return old data, even if this is wrong. >+ We can not zero out the values because the failure may >+ be temporary and in this case when the folder is back >+ we would find new mail that simply does not exist in >+ the folder. >+ */ >+ mm_status_result.messages = f->messages; >+ mm_status_result.recent = f->recent; >+ } >+ 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(f->origrecent > *find_recent) >+ f->origrecent = *find_recent; >+ if(rv & FEX_ISMARKED){ >+ next = f ? FLDR_NAME(f) : NULL; >+ free_folder_list(cntxt); >+ f->countrecent = *find_recent > f->origrecent >+ ? *find_recent - f->origrecent : 0L; >+ 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 -ru pine4.64/pine/help.c pine4.64.SuSE/pine/help.c >--- pine4.64/pine/help.c 2004-11-23 19:29:47.000000000 +0100 >+++ pine4.64.SuSE/pine/help.c 2006-02-14 14:45:22.000000000 +0100 >@@ -168,7 +168,7 @@ > int flags; > { > char **shown_text; >- int cmd = MC_NONE; >+ int cmd = MC_NONE, in_fld_list; > long offset = 0L; > char *error = NULL, tmp_title[MAX_SCREEN_COLS + 1]; > STORE_S *store; >@@ -181,6 +181,8 @@ > > dprint(1, (debugfile, "\n\n ---- HELPER ----\n")); > >+ in_fld_list = ps_global->in_fld_list; >+ ps_global->in_fld_list = 0; > #ifdef HELPFILE > if(otext) > shown_text = otext; >@@ -396,6 +398,7 @@ > free_list_array(&dynamic_text); > #endif > >+ ps_global->in_fld_list = in_fld_list; > return(cmd); > } > >diff -ru pine4.64/pine/imap.c pine4.64.SuSE/pine/imap.c >--- pine4.64/pine/imap.c 2005-09-13 00:04:25.000000000 +0200 >+++ pine4.64.SuSE/pine/imap.c 2006-02-14 14:45:22.000000000 +0100 >@@ -694,6 +694,7 @@ > int len, rc, q_line, flags; > int oespace, avail, need, save_dont_use; > struct servent *sv; >+ time_t now; > #define NETMAXPASSWD 100 > > dprint(9, (debugfile, "mm_login trial=%ld user=%s service=%s%s%s\n", >@@ -702,9 +703,10 @@ > mb->port ? " port=" : "", > mb->port ? comatose(mb->port) : "")); > q_line = -(ps_global->ttyo ? ps_global->ttyo->footer_rows : 3); >+ now = time(0); > > /* make sure errors are seen */ >- if(ps_global->ttyo) >+ if(ps_global->ttyo && !ps_global->checking_incfld) > flush_status_messages(0); > > /* >@@ -1026,12 +1028,13 @@ > /* default */ > if(rc == 0 && !*user) > strncpy(user, defuser, NETMAXUSER); >- >+ > if(rc != 4) > break; > } > > if(rc == 1 || !user[0]) { >+ ps_global->cancelproc = (rc == 1); > user[0] = '\0'; > pwd[0] = '\0'; > } >@@ -1213,10 +1216,12 @@ > } > > if(rc == 1 || !pwd[0]) { >+ ps_global->cancelproc = (rc == 1); > user[0] = pwd[0] = '\0'; > return; > } > >+ ps_global->login_time = time(0) - now; > nopwpmt: > /* remember the password for next time */ > if(F_OFF(F_DISABLE_PASSWORD_CACHING,ps_global)) >@@ -1570,7 +1575,7 @@ > > } > >- if(mail_status(stream, source, flags)){ >+ if(!ps_global->cancelproc && mail_status(stream, source, flags)){ > DRIVER *d; > int is_news = 0; > >@@ -1770,13 +1775,14 @@ > || !strucmp(d->name, "nntp"))) > flags |= SA_MULNEWSRC; > } >- >- ret = mail_status(stream, mailbox, flags); /* non #move case */ >+ if(!ps_global->cancelproc) >+ ret = mail_status(stream, mailbox, flags); /* non #move case */ > } > > if(ourstream) > pine_mail_close(ourstream); > >+ ps_global->cancelproc = 0; > return ret; > } > >@@ -1950,11 +1956,17 @@ > #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') >+ if(want_to(pmt, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){ >+ ps_global->cancelproc = 1; > return(0L); >+ } >+ } >+ else >+ rv = 0L; > } > > return(rv); >@@ -1996,6 +2008,7 @@ > 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(); >@@ -2009,13 +2022,18 @@ > fflush(stdout); > flush_input(); > ch = read_char(7); >- if(ch == 'y' || ch == 'Y') >+ if(ch == 'y' || ch == 'Y'){ >+ ps_global->cancelproc = 1; > rv = 0L; >+ } > > if(clear_inverse) > EndInverse(); > > ClearLine(ps_global->ttyo->screen_rows - FOOTER_ROWS(ps_global)); >+ } >+ else >+ rv = 0L; > } > > if(rv == 1L){ /* just warn 'em something's up */ >@@ -2032,6 +2050,36 @@ > 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 -ru pine4.64/pine/init.c pine4.64.SuSE/pine/init.c >--- pine4.64/pine/init.c 2005-09-12 20:53:17.000000000 +0200 >+++ pine4.64.SuSE/pine/init.c 2006-02-14 14:45:25.000000000 +0100 >@@ -66,11 +66,15 @@ > > #include "headers.h" > #include "../c-client/imap4r1.h" /* for LEVELSTATUS() */ >+#ifdef LC_CTYPE >+# include <langinfo.h> >+#endif > > > 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,6 +162,8 @@ > > 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,12 +220,52 @@ > > 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_assumed_charset[] = "When MIME charset information is missing in Content-Type header field.\n# Message is assumed to be in this charset. Default: US-ASCII. Typical values\n# include ISO-8859-x, ISO-2022-JP, EUC-KR, GB2312, and Big5. The value of\n# header fields which are not encoded per RFC 2047\n# is also assumed to be\n# in this charset."; >+ >+CONF_TXT_T cf_text_charset_aliases[] = "List of charset aliases. Each alias is a pair of charsets delimetered by a\n# single colon, the first one being an alias to the second one. The latter is\n# usually standard/prefered MIME name while the former is non-standard name used\n# by some email clients. For instance, you may have 'x-big5:big5,euc-cn:gb2312'"; >+ >+#ifdef HAVE_ICONV >+CONF_TXT_T cf_text_iconv_aliases[] = "List of charset aliases to use with iconv(). Each alias is a pair of\n# charsets delimetered by a single colon, the first one being an alias to the\n# second one. The former is usually standard/prefered MIME name while the\n# latter is non-standard name used by iconv(3) on your system.\n#For example,\n# your iconv may use non-standard 'UTF8' for the standard 'UTF-8'. In that\n# case, you can put 'UTF-8:UTF8' here."; >+ >+CONF_TXT_T cf_text_send_charset[] = "Specifies the MIME charset that a message will be sent in. If not set,\n# the value of character set will be used."; >+#endif >+ > CONF_TXT_T cf_text_editor[] = "Specifies the program invoked by ^_ in the Composer,\n# or the \"enable-alternate-editor-implicitly\" feature."; > > CONF_TXT_T cf_text_speller[] = "Specifies the program invoked by ^T in the Composer."; >@@ -228,6 +274,8 @@ > > 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,6 +290,8 @@ > > 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,6 +428,8 @@ > > 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,6 +470,9 @@ > > 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,6 +526,8 @@ > 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,6 +568,8 @@ > 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,6 +578,8 @@ > 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,14 +594,54 @@ > 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}, >+#ifdef ENABLE_SEND_CHARSET >+{"send-charset", 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, >+ cf_text_send_charset}, >+#endif >+{"assumed-charset", 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, >+ cf_text_assumed_charset}, >+{"charset-aliases", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, >+ cf_text_charset_aliases}, >+#ifdef HAVE_ICONV >+{"iconv-aliases", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, >+ cf_text_iconv_aliases}, >+#endif > {"editor", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, > cf_text_editor}, > {"speller", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, > 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,6 +706,8 @@ > 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,6 +776,8 @@ > 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,6 +877,8 @@ > {"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,7 +1582,7 @@ > 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; >+ obs_save_by_sender, i, def_sort_rev, thread_def_sort_rev; > long rvl; > PINERC_S *fixedprc = NULL; > FeatureLevel obs_feature_level; >@@ -1484,6 +1591,15 @@ > > /*--- The defaults here are defined in os-xxx.h so they can vary > per machine ---*/ >+#ifdef LC_CTYPE >+ setlocale(LC_CTYPE, ""); /* needed for using nl_langinfo */ >+ GLO_CHAR_SET = cpystr(nl_langinfo(CODESET)); >+ /* if codeset indicates that we are in an US-ASCII locale, */ >+ if (!strcmp(GLO_CHAR_SET, "ANSI_X3.4-1968")) { >+ fs_give((void **) &(GLO_CHAR_SET)); >+ cpystr("US-ASCII"); /* default to US-ASCII */ >+ } >+#endif > > GLO_PRINTER = cpystr(DF_DEFAULT_PRINTER); > GLO_ELM_STYLE_SAVE = cpystr(DF_ELM_STYLE_SAVE); >@@ -1497,6 +1613,7 @@ > 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,6 +1624,7 @@ > 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); >@@ -1862,8 +1980,20 @@ > 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); >@@ -2082,6 +2212,13 @@ > 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); >@@ -2096,6 +2233,10 @@ > 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]) >@@ -2117,6 +2258,9 @@ > set_current_val(&vars[V_OLD_STYLE_REPLY], TRUE, TRUE); > obs_old_style_reply = !strucmp(VAR_OLD_STYLE_REPLY, "yes"); > >+ /* needed in process_feature_list */ >+ set_current_val(&vars[V_CHAR_SET], TRUE, TRUE); >+ > set_feature_list_current_val(&vars[V_FEATURE_LIST]); > process_feature_list(ps, VAR_FEATURE_LIST, > (obs_feature_level == Seasoned) ? 1 : 0, >@@ -2125,6 +2269,14 @@ > set_current_val(&vars[V_SIGNATURE_FILE], TRUE, TRUE); > set_current_val(&vars[V_LITERAL_SIG], TRUE, TRUE); > set_current_val(&vars[V_CHAR_SET], TRUE, TRUE); >+#ifdef ENABLE_SEND_CHARSET >+ set_current_val(&vars[V_SEND_CHARSET], TRUE, TRUE); >+#endif >+ set_current_val(&vars[V_ASSUMED_CHAR_SET], TRUE, TRUE); >+ set_current_val(&vars[V_CHAR_SET_ALIASES], TRUE, TRUE); >+#ifdef HAVE_ICONV >+ set_current_val(&vars[V_ICONV_ALIASES], TRUE, TRUE); >+#endif > set_current_val(&vars[V_GLOB_ADDRBOOK], TRUE, TRUE); > set_current_val(&vars[V_ADDRESSBOOK], TRUE, TRUE); > set_current_val(&vars[V_FORCED_ABOOK_ENTRY], TRUE, TRUE); >@@ -2329,8 +2481,9 @@ > 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) == -1){ >+ 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; >@@ -2339,6 +2492,17 @@ > 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++) >@@ -2366,11 +2530,14 @@ > 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]){ >@@ -2424,6 +2591,7 @@ > 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){ >@@ -2613,6 +2781,8 @@ > 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", >@@ -2647,6 +2817,8 @@ > 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", >@@ -2667,6 +2839,10 @@ > 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", >@@ -2683,6 +2859,8 @@ > 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", >@@ -2699,6 +2877,8 @@ > /* 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", >@@ -2721,6 +2901,8 @@ > 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", >@@ -2744,6 +2926,9 @@ > #endif > {"quell-charset-warning", > F_QUELL_CHARSET_WARNING, h_config_quell_charset_warning, PREF_VIEW}, >+ {"quell-displaying-flowed-text", >+ F_QUELL_DISPLAYING_FLOWED_TEXT, h_config_quell_displaying_flowed_text, >+ PREF_VIEW}, > > /* News */ > {"compose-sets-newsgroup-without-confirm", >@@ -2818,14 +3003,12 @@ > F_QUELL_FULL_HDR_RESET, h_config_quell_full_hdr_reset, PREF_ACMD}, > > /* Adv user prefs */ >-#if !defined(DOS) && !defined(OS2) >- {"allow-talk", >- F_ALLOW_TALK, h_config_allow_talk, PREF_MISC}, >-#endif > {"assume-slow-link", > 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", >@@ -3097,6 +3280,9 @@ > F_SET(feat->id, ps, 0); > > >+ /* flowed text has some problems, disable it by default (bug #45364) */ >+ F_TURN_ON(F_QUELL_FLOWED_TEXT, ps_global); >+ > /* backwards compatibility */ > if(hir) > F_TURN_ON(F_INCLUDE_HEADER, ps); >@@ -3109,6 +3295,10 @@ > if(old_growth) > set_old_growth_bits(ps, 0); > >+ if(ps_global->VAR_CHAR_SET >+ && !strucmp(ps_global->VAR_CHAR_SET, "UTF-8")) >+ F_TURN_ON(F_QUELL_CHARSET_WARNING, ps_global); /* if not user-off */ >+ > /* now run through the list (global, user, and cmd_line lists are here) */ > if(list){ > for(p = list; (q = *p) != NULL; p++){ >@@ -3160,6 +3350,11 @@ > #ifdef _WINDOWS > ps->pass_ctrl_chars = 1; > #else >+ if(ps_global->VAR_CHAR_SET >+ && !strucmp(ps_global->VAR_CHAR_SET, "UTF-8")) { >+ F_TURN_ON(F_PASS_C1_CONTROL_CHARS, ps_global); /* global see below */ >+ F_TURN_ON(F_ENABLE_SETLOCALE_CTYPE, ps); /* for setting gmode */ >+ } > ps->pass_ctrl_chars = F_ON(F_PASS_CONTROL_CHARS,ps_global) ? 1 : 0; > ps->pass_c1_ctrl_chars = F_ON(F_PASS_C1_CONTROL_CHARS,ps_global) ? 1 : 0; > >@@ -3773,6 +3968,23 @@ > ? &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) >@@ -4207,10 +4419,15 @@ > 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] = i_cmds[j]; >- >- ps->initial_cmds[i] = 0; >+ 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; > } > } >@@ -6448,23 +6665,24 @@ > * argument also means arrival/reverse. > */ > int >-decode_sort(sort_spec, def_sort, def_sort_rev) >+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, reverse; >+ int x = 0, reverse; > > if(!sort_spec || !*sort_spec){ >- *def_sort = SortArrival; >+ *def_sort = thread ? SortThread : SortArrival; > *def_sort_rev = 0; > return(0); > } > > if(struncmp(sort_spec, "reverse", strlen(sort_spec)) == 0){ >- *def_sort = SortArrival; >+ *def_sort = thread ? SortThread : SortArrival; > *def_sort_rev = 1; > return(0); > } >@@ -6487,13 +6705,19 @@ > 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 = ps_global->sort_types[x]; >+ *def_sort = (thread && ps_global->sort_types[x] == SortDate) >+ ? SortThread : ps_global->sort_types[x]; > *def_sort_rev = reverse; > return(0); > } >@@ -9062,7 +9286,7 @@ > */ > if(!err && !add_only_first_msg){ > char *tempfile = NULL; >- int fd; >+ int fd = 0; > > if(rd->flags & NO_FILE){ > if(so_truncate(rd->sonofile, 0L) == 0) >@@ -11053,6 +11277,14 @@ > 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 -ru pine4.64/pine/mailcap.c pine4.64.SuSE/pine/mailcap.c >--- pine4.64/pine/mailcap.c 2004-11-03 21:11:00.000000000 +0100 >+++ pine4.64.SuSE/pine/mailcap.c 2006-02-14 14:45:25.000000000 +0100 >@@ -1,3 +1,4 @@ >+ > #if !defined(lint) && !defined(DOS) > static char rcsid[] = "$Id: mailcap.c 13858 2004-11-03 20:11:00Z hubert $"; > #endif >@@ -993,14 +994,18 @@ > * have to put those outside of the single quotes. > * (The parm+1000 nonsense is to protect against > * malicious mail trying to overlow our buffer.) >+ * >+ * TCH - Change 2/8/1999 >+ * Also quote the ` slash to prevent execution of arbirtrary code > */ > for(p = parm; *p && p < parm+1000; p++){ >- if(*p == '\''){ >+ if((*p == '\'')||(*p=='`')){ > *to++ = '\''; /* closing quote */ > *to++ = '\\'; >- *to++ = '\''; /* below will be opening quote */ >- } >- *to++ = *p; >+ *to++ = *p; /* quoted character */ >+ *to++ = '\''; /* opening quote */ >+ } else >+ *to++ = *p; > } > > fs_give((void **) &parm); >@@ -1042,7 +1047,7 @@ > */ > if(!used_tmp_file && tmp_file) > sprintf(to, MC_ADD_TMP, tmp_file); >- >+ > return(cpystr(tmp_20k_buf)); > } > >diff -ru pine4.64/pine/mailcmd.c pine4.64.SuSE/pine/mailcmd.c >--- pine4.64/pine/mailcmd.c 2005-09-13 00:04:25.000000000 +0200 >+++ pine4.64.SuSE/pine/mailcmd.c 2006-02-14 14:45:25.000000000 +0100 >@@ -58,6 +58,7 @@ > /* > * 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,11 +90,14 @@ > 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 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,6 +113,27 @@ > 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,6 +144,12 @@ > 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,6 +172,9 @@ > #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; >@@ -254,9 +288,9 @@ > > > static char *sel_text = >- "Select based on To, From, Cc, Recip, Partic, Subject fields or All msg text ? "; >+ "Select based on To, From, Cc, Recip, Partic, Subject, Body or All msg text ? "; > static char *sel_not_text = >- "Select based on NOT To, From, Cc, Recip, Partic, Subject or All msg text ? "; >+ "Select based on NOT To, From, Cc, Recip, Partic, Subject, Body or All msg text ? "; > static ESCKEY_S sel_text_opt[] = { > {'f', 'f', "F", "From"}, > {'s', 's', "S", "Subject"}, >@@ -267,6 +301,7 @@ > {'r', 'r', "R", "Recipient"}, > {'p', 'p', "P", "Participant"}, > {'b', 'b', "B", "Body"}, >+ {'h', 'h', "H", "Header"}, > {-1, 0, NULL, NULL} > }; > >@@ -936,7 +971,7 @@ > state->context_current, &recent_cnt, > F_ON(F_TAB_NO_CONFIRM,state) > ? NULL : &did_cancel))){ >- if(!in_inbox){ >+ if(!in_inbox && F_OFF(F_AUTO_CIRCULAR_TAB,state)){ > static ESCKEY_S inbox_opt[] = { > {'y', 'y', "Y", "Yes"}, > {'n', 'n', "N", "No"}, >@@ -1186,6 +1221,10 @@ > 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,6 +1295,7 @@ > 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,6 +1338,9 @@ > */ > 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,7 +1477,7 @@ > if(any_messages(msgmap, NULL, NULL)){ > if(any_lflagged(msgmap, MN_SLCT) > 0L){ > if(apply_command(state, stream, msgmap, 0, >- AC_NONE, question_line) >+ AC_NONE, question_line, 1) > && F_ON(F_AUTO_UNZOOM, state)) > unzoom_index(state, stream, msgmap); > } >@@ -1447,18 +1490,25 @@ > > /*-------- 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)){ >+ 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); > >- sort_folder(stream, msgmap, sort, rev, SRT_VRB|SRT_MAN); >+ 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,6 +1583,12 @@ > 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,6 +1996,168 @@ > } > > >+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) + 19; >+ 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++; /* 1 = '\0', 3 = " KB" */ >+ storagelen = strlen(long2string(imapquota->limit)) + 1 + 3; >+ storageuse = imapquota->usage; >+ storagelim = imapquota->limit; >+ } >+ if(!strucmp(imapquota->name,"MESSAGE")){ >+ message++; /* " messages" = 9 */ >+ messagelen = strlen(long2string(imapquota->limit)) + 1 + 9; >+ 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 + 8; >+ 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 + 9; >+ 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 > >@@ -2931,6 +3149,7 @@ > if(agg && !pseudo_selected(msgmap)) > return; > >+ 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) >@@ -3178,7 +3397,7 @@ > { > 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 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; >@@ -3187,6 +3406,9 @@ > 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"); >@@ -3217,6 +3439,13 @@ > 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) >@@ -4137,7 +4366,7 @@ > *date = '\0'; > > rv = save_fetch_append(stream, mn_m2raw(msgmap, i), >- NULL, save_stream, save_folder, context, >+ NULL, save_stream, folder, context, > mc ? mc->rfc822_size : 0L, flags, date, so); > > if(sp_expunge_count(stream)) >@@ -7268,6 +7497,65 @@ > 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 >@@ -7325,6 +7613,212 @@ > 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 >@@ -7359,7 +7853,7 @@ > 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; >+ *old_folder, *old_path, *p, *report; > long openmode, rflags = 0L, pc = 0L, cur, raw; > ENVELOPE *env = NULL; > char status_msg[81]; >@@ -7693,15 +8187,20 @@ > 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); >- 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))); >+ 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 >@@ -8002,6 +8501,7 @@ > > clear_index_cache(); > reset_index_format(); >+ setup_threading_index_style(); > > /* > * Start news reading with messages the user's marked deleted >@@ -8021,8 +8521,16 @@ > 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", >+ 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), >@@ -8032,20 +8540,15 @@ > && sp_flagged(ps_global->mail_stream, SP_PERMLOCKED)) > ? " (StayOpen)" : "", > READONLY_FOLDER(ps_global->mail_stream) >- ? " READONLY" : ""); >+ ? " READONLY" : "", >+ report); >+ if (report) >+ fs_give((void **)&report); > > #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. >@@ -8109,7 +8612,10 @@ > > if(!cur_already_set && mn_get_total(ps_global->msgmap) > 0L){ > >- perfolder_startup_rule = reset_startup_rule(ps_global->mail_stream); >+ perfolder_startup_rule = get_perfolder_startup_rule(ps_global->mail_stream, >+ V_STARTUP_RULES, newfolder); >+ >+ reset_startup_rule(ps_global->mail_stream); > > if(ps_global->start_entry > 0){ > mn_set_cur(ps_global->msgmap, mn_get_revsort(ps_global->msgmap) >@@ -8131,140 +8637,24 @@ > 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; >+ find_startup_position(use_this_startup_rule, m, pc); > >- 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, >+ } >+ 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)); >- } >- 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)); >- } >+ } >+ 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); > } >@@ -8287,7 +8677,10 @@ > PAT_S *pat; > int we_set_it = 0; > >- if(ps_global->mail_stream && nonempty_patterns(rflags, &pstate)){ >+ 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)) >@@ -8317,10 +8710,27 @@ > 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 = ps_global->def_sort_rev; >+ 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)){ >@@ -8332,12 +8742,18 @@ > 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_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); >+ the_sort_order, sort_is_rev, flags, 1); > } > > >@@ -8423,6 +8839,7 @@ > 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]; >@@ -8439,7 +8856,7 @@ > } > > if(stream != NULL){ >- context = sp_context(stream); >+ context = ps_global->context_current; > folder = STREAMNAME(stream); > > dprint(2, (debugfile, "expunge_and_close: \"%s\"%s\n", >@@ -8452,6 +8869,14 @@ > 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->origrecent), &(f->messages)); >+ f->notified = 0; >+ f->countrecent = f->recent = 0L; >+ f->selected = f->user_selected; >+ } >+ > if(!stream->rdonly){ > > if(!no_close){ >@@ -8479,9 +8904,11 @@ > /* Save read messages? */ > if(VAR_READ_MESSAGE_FOLDER && VAR_READ_MESSAGE_FOLDER[0] > && sp_flagged(stream, SP_INBOX) >- && (seen_not_del = count_flagged(stream, F_SEEN | F_UNDEL))){ >+ && (F_ON(F_AUTO_READ_MSGS_RULES, ps_global) || >+ (seen_not_del = count_flagged(stream, F_SEEN | F_UNDEL)))){ > > if(F_ON(F_AUTO_READ_MSGS,ps_global) >+ || F_ON(F_AUTO_READ_MSGS_RULES, ps_global) > || 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, >@@ -10136,6 +10563,9 @@ > 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; >@@ -10177,8 +10607,9 @@ > 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) >+ 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); >@@ -10189,6 +10620,143 @@ > 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; >+} > > > /*---------------------------------------------------------------------- >@@ -10235,7 +10803,9 @@ > && ((context_isambig(folder) > && folder_is_nick(folder, FOLDERS(context), 0)) > || folder_index(folder, context, FI_FOLDER) > 0) >- && (seen_undel = count_flagged(stream, F_SEEN | F_UNDEL))){ >+ && ((seen_undel = count_flagged(stream, F_SEEN | F_UNDEL)) >+ || (F_ON(F_AUTO_READ_MSGS,ps_global) && >+ F_ON(F_AUTO_READ_MSGS_RULES, ps_global)))){ > > for(; f && *archive; archive++){ > char *p; >@@ -11517,13 +12087,14 @@ > > ----*/ > int >-apply_command(state, stream, msgmap, preloadkeystroke, flags, q_line) >+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, >@@ -11650,9 +12221,19 @@ > collapse_or_expand(state, stream, msgmap, > F_ON(F_SLASH_COLL_ENTIRE, ps_global) > ? 0L >- : mn_get_cur(msgmap)); >+ : 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; >@@ -12170,6 +12751,7 @@ > SEARCHSET **msgset; > { > PINETHRD_S *nthrd, *bthrd; >+ unsigned long next, branch; > > if(!(stream && thrd)) > return; >@@ -12178,14 +12760,14 @@ > && (!(msgset && *msgset) || in_searchset(*msgset, thrd->rawno))) > mm_searched(stream, thrd->rawno); > >- if(thrd->next){ >- nthrd = fetch_thread(stream, thrd->next); >+ if(next= get_next(stream, thrd)){ >+ nthrd = fetch_thread(stream, next); > if(nthrd) > set_search_bit_for_thread(stream, nthrd, msgset); > } > >- if(thrd->branch){ >- bthrd = fetch_thread(stream, thrd->branch); >+ if(branch = get_branch(stream, thrd)){ >+ bthrd = fetch_thread(stream, branch); > if(bthrd) > set_search_bit_for_thread(stream, bthrd, msgset); > } >@@ -12393,7 +12975,7 @@ > { > 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 namehdr[80], *sval = NULL, *cset = NULL, *charset = NULL; > char buftmp[MAILTMPLEN]; > ESCKEY_S ekey[4]; > ENVELOPE *env = NULL; >@@ -12467,6 +13049,40 @@ > 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; > >@@ -12590,6 +13206,9 @@ > } > > 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 */ >@@ -13767,14 +14386,15 @@ > Returns 0 if it was cancelled, 1 otherwise. > ----*/ > int >-select_sort(state, ql, sort, rev) >+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; >+ int s, i, j; > int deefault = 'a', retval = 1; > HelpType help; > ESCKEY_S sorts[14]; >@@ -13808,17 +14428,27 @@ > 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; >+ 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'; >@@ -13843,7 +14473,7 @@ > if(s == 'r') > *rev = !mn_get_revsort(state->msgmap); > else >- *sort = state->sort_types[s]; >+ *sort = state->sort_types[thread ? (s == 0 ? 1 : 9) : s]; > > if(F_ON(F_SHOW_SORT, ps_global)) > ps_global->mangled_header = 1; >@@ -14531,3 +15161,699 @@ > 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 -ru pine4.64/pine/mailindx.c pine4.64.SuSE/pine/mailindx.c >--- pine4.64/pine/mailindx.c 2005-05-04 00:00:53.000000000 +0200 >+++ pine4.64.SuSE/pine/mailindx.c 2006-02-14 14:45:24.000000000 +0100 >@@ -112,9 +112,22 @@ > RCOMPOSE_MENU, > HOMEKEY_MENU, > ENDKEY_MENU, >- NULL_MENU, >+ {"K","Sort Thread",{MC_SORTHREAD,1,{'k'}},KS_NONE}, > {"/","Collapse/Expand",{MC_COLLAPSE,1,{'/'}},KS_NONE}, >- NULL_MENU, >+ {"{","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,9 +210,22 @@ > RCOMPOSE_MENU, > HOMEKEY_MENU, > ENDKEY_MENU, >- NULL_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,12 +341,17 @@ > > 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,6 +377,14 @@ > 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,17 +429,19 @@ > struct pass_along > *sort_thread_flatten PROTO((THREADNODE *, MAILSTREAM *, > struct pass_along *, >- PINETHRD_S *, unsigned)); >+ 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, 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,9 +633,12 @@ > 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,19 +746,29 @@ > MAILSTREAM *stream; > MSGNO_S *msgmap; > { >- int ch, cmd, which_keys, force, >+ 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; >+ 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; /* Yes, we want new mail only */ >+ f->skipped = 0; /* Erase the ".", if any */ >+ f->last_check_time = 0; /* and assume no delay for now */ >+ if(!selected_folders(cntxt) && (cntxt->use & CNTXT_ZOOM)) >+ cntxt->use &= ~CNTXT_ZOOM; /* exit zoom mode if necessary */ >+ } > ch = 'x'; /* For displaying msg 1st time thru */ > force = 0; > km_popped = 0; >@@ -749,9 +803,24 @@ > } > > /*------- Check for new mail -------*/ >- new_mail(force, NM_TIMING(ch), NM_STATUS_MSG); >- force = 0; /* may not need to next time around */ >- >+ 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 = 0; >+ f->selected = f->user_selected; >+ f->recent = rec; >+ f->messages = tot; >+ } >+ ps_global->refresh_list &= IF_REFRESH_NONE; >+ 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,6 +1012,9 @@ > break; > } > >+ if ((cmd != MC_NONE) && (cmd != MC_FORCECHECK)) >+ state->force_check_now = 0; >+ > /*----------- Execute the command ------------------*/ > switch(cmd){ > >@@ -958,6 +1030,7 @@ > > /*---------- Scroll line up ----------*/ > case MC_CHARUP : >+previtem: > (void) process_cmd(state, stream, msgmap, MC_PREVITEM, > (style == MsgIndex > || style == MultiMsgIndex >@@ -975,6 +1048,7 @@ > > /*---------- Scroll line down ----------*/ > case MC_CHARDOWN : >+nextitem: > /* > * Special Page framing handling here. If we > * did something that should scroll-by-a-line, frame >@@ -1192,6 +1266,7 @@ > > > case MC_THRDINDX : >+mc_thrdindx: > msgmap->top = msgmap->top_after_thrd; > if(unview_thread(state, stream, msgmap)){ > ps_global->redrawer = NULL; >@@ -1239,7 +1314,7 @@ > && mp.col == id.plus_col > && style != ThreadIndex){ > collapse_or_expand(state, stream, msgmap, >- mn_get_cur(msgmap)); >+ mn_get_cur(msgmap), 1); > } > else if (mp.doubleclick){ > if(mp.button == M_BUTTON_LEFT){ >@@ -1309,6 +1384,8 @@ > reset_index_border(); > break; > >+ case MC_QUOTA: >+ cmd_quota(state); > > /*---------- Redraw ----------*/ > case MC_REPAINT : >@@ -1333,9 +1410,106 @@ > > > case MC_COLLAPSE : >- thread_command(state, stream, msgmap, ch, -FOOTER_ROWS(state)); >+ 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,13 +1530,12 @@ > if(rawno) > thrd = fetch_thread(stream, rawno); > >- collapsed = thrd && thrd->next >- && get_lflag(stream, NULL, rawno, MN_COLL); >+ collapsed = thread_is_kolapsed(ps_global, stream, msgmap, rawno); > } > > if(collapsed){ > thread_command(state, stream, msgmap, >- ch, -FOOTER_ROWS(state)); >+ ch, -FOOTER_ROWS(state),1); > /* increment current */ > if(cmd == MC_DELETE){ > advance_cur_after_delete(state, stream, msgmap, >@@ -1401,7 +1574,10 @@ > } > /* 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: >@@ -2051,6 +2227,9 @@ > int uc, ac, do_arrow; > int i, drew_X = 0, cols = ps_global->ttyo->screen_cols; > int inverse_hack = 0, need_inverse_hack = 0, lim; >+ int seq = 0, w = 0; >+ char utf_seq[7], *cp, *r; >+ > > if(uc=pico_usingcolor()) > lastc = pico_get_cur_color(); >@@ -2130,9 +2309,26 @@ > draw[acol+i] = '>'; > } > >+ cp = NULL; > if(pcol >= 0 && pcol < cols){ >- save_pchar = draw[pcol]; >- draw[pcol] = h->plus; >+ memset(utf_seq, 0, sizeof(utf_seq)); >+ for(cp = draw; *cp; cp++) { >+ if (!(r = pine_check_utf8(cp, utf_seq, sizeof(utf_seq)))) { >+ seq = 1; >+ continue; >+ } >+ if (seq) >+ w++; >+ seq = 0; >+ if (r == cp) >+ w++; >+ else if (*r == ' ') >+ w++; >+ if (w > pcol) >+ break; >+ } >+ save_pchar = *cp; >+ *cp = h->plus; > } > > if(h->offs[0].offset < 0 || h->offs[0].offset >= cols){ >@@ -2295,8 +2491,8 @@ > if(!ac && cur) > EndInverse(); > >- if(pcol >= 0 && pcol < cols) >- draw[pcol] = save_pchar; >+ if(cp) >+ *cp = save_pchar; > > if(do_arrow && cur){ > int i; >@@ -2772,6 +2968,7 @@ > 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,11 +3037,12 @@ > > /* n is the end of this thread */ > while(thrd){ >+ unsigned long next = 0L, branch = 0L; > 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); >+ 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,6 +3196,7 @@ > case iSTime: > case iKSize: > case iSize: >+ case iSizeThread: > (*answer)[column].req_width = 7; > break; > case iS1Date: >@@ -3034,14 +3233,15 @@ > static INDEX_PARSE_T itokens[] = { > {"STATUS", iStatus, FOR_INDEX}, > {"MSGNO", iMessNo, FOR_INDEX}, >- {"DATE", iDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, >+ {"DATE", iDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE}, > {"FROMORTO", iFromTo, FOR_INDEX}, > {"FROMORTONOTNEWS", iFromToNotNews, FOR_INDEX}, > {"SIZE", iSize, FOR_INDEX}, > {"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}, >+ {"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,26 +3251,29 @@ > {"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}, >+ {"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,46 +3282,55 @@ > {"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}, >+ {"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_FILT}, >- {"CURDATEISO", iCurDateIso, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, >- {"CURDATEISOS", iCurDateIsoS, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, >- {"CURTIME24", iCurTime24, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, >- {"CURTIME12", iCurTime12, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, >- {"CURDAY", iCurDay, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, >- {"CURDAY2DIGIT", iCurDay2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, >- {"CURDAYOFWEEK", iCurDayOfWeek, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, >+ {"CURDATE", iCurDate, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_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_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}, >+ 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_FILT}, >- {"LASTYEAR", iLstYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, >- {"LASTYEAR2DIGIT", iLstYear2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, >+ FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_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,7 +3498,7 @@ > */ > static IndexColType fixed_ctypes[] = { > iArrow, iMessNo, iStatus, iFStatus, iIStatus, iDate, iSDate, iSDateTime, >- iSTime, iLDate, >+ iSTime, iLDate, iSizeThread, > iS1Date, iS2Date, iS3Date, iS4Date, iDateIso, iDateIsoS, > iSize, iSizeComma, iSizeNarrow, iKSize, iDescripSize, > iAtt, iTime24, iTime12, iTimezone, iMonAbb, iYear, iYear2Digit, >@@ -3457,6 +3669,7 @@ > case iTime12: > case iSize: > case iKSize: >+ case iSizeThread: > cdesc->actual_length = 7; > cdesc->adjustment = Right; > break; >@@ -3521,7 +3734,7 @@ > cdesc->ctype != iNothing; > cdesc++) > if(cdesc->ctype == iSize || cdesc->ctype == iKSize || >- cdesc->ctype == iSizeNarrow || >+ 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,6 +4026,80 @@ > } > } > >+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,10 +4232,11 @@ > > /* 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->nextthd) >- thrd = fetch_thread(stream, thrd->nextthd); >+ else if(!mn_get_revsort(msgmap) && thrd->branch) >+ thrd = fetch_thread(stream, thrd->branch); > else > thrd = NULL; > } while(thrd >@@ -4363,6 +4651,58 @@ > return(doy); > } > >+static char * >+rfc_1522_check_charset(chp) >+ char *chp; >+{ >+ static char *subj_cs = NULL; >+ char *cs, *enc; >+ >+ while(chp && (chp = strstr(chp, "=?"))) >+ if(rfc1522_valid(chp++, 1, &cs, &enc, NULL, NULL)){ >+ int cs_len = enc - cs - 1; >+ >+ if(subj_cs) >+ fs_give((void **)&subj_cs); >+ >+ strncpy(subj_cs = fs_get(cs_len + 1), cs, cs_len); >+ subj_cs[cs_len] = 0; >+ >+ return subj_cs; >+ } >+ return NULL; >+} >+ >+static void >+rfc1522_decode_width(dest, source, width, idata) >+ char *dest; >+ char *source; >+ int width; >+ INDEXDATA_S *idata; >+{ >+ char *subj_cs, *assumed_save = NULL, *dummy = NULL, *tmp; >+ >+ if(idata && (subj_cs = rfc_1522_check_charset(fetch_subject(idata)))){ >+ assumed_save = ps_global->VAR_ASSUMED_CHAR_SET; >+ ps_global->VAR_ASSUMED_CHAR_SET = subj_cs; >+ } >+ >+ tmp = (char *) rfc1522_decode((unsigned char *) tmp_20k_buf, >+ SIZEOF_20KBUF, source, &dummy); >+ if(idata){ >+ if(tmp == source) >+ strncpy(tmp = tmp_20k_buf, source, SIZEOF_20KBUF); >+ >+ removing_leading_and_trailing_white_space(tmp); >+ >+ if(subj_cs) >+ ps_global->VAR_ASSUMED_CHAR_SET = assumed_save; >+ } >+ charset_istrncpy(dest, tmp, width, 0); >+ >+ if(dummy) >+ fs_give((void **)&dummy); >+} > > > /*---------------------------------------------------------------------- >@@ -4379,7 +4719,8 @@ > format_index_index_line(idata) > INDEXDATA_S *idata; > { >- char str_buf[MAXIFLDS][MAX_SCREEN_COLS+1], to_us, status, *field, >+#define STRLEN MAX_SCREEN_COLS*6 >+ char str_buf[MAXIFLDS][STRLEN+1], to_us, status, *field, > *buffer, *s_tmp, *p, *str, *newsgroups; > int width, i, j, smallest, which_array = 0, collapsed = 0, > offsets_set = 0, cur_offset = 0, noff = 0, noff_was; >@@ -4404,11 +4745,9 @@ > } > > /* is this a collapsed thread index line? */ >+ thrd = fetch_thread(idata->stream, idata->rawno); > if(!idata->bogus && THREADING()){ >- thrd = fetch_thread(idata->stream, idata->rawno); >- collapsed = thrd && thrd->next >- && get_lflag(idata->stream, NULL, >- idata->rawno, MN_COLL); >+ collapsed = thrd && thread_is_kolapsed(ps_global, idata->stream, ps_global->msgmap, idata->rawno); > } > > /* calculate contents of the required fields */ >@@ -4866,7 +5205,7 @@ > case iFrom: > case iAddress: > case iMailbox: >- from_str(cdesc->ctype, idata, width, str); >+ from_str(cdesc->ctype, idata, min(width*6,STRLEN), str); > break; > > case iTo: >@@ -4940,7 +5279,31 @@ > > 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); >@@ -5159,12 +5522,12 @@ > break; > > case iSubject: >- subj_str(idata, width, str, NoKW, NULL, NULL); >+ subj_str(idata, min(width*6,STRLEN), str, NoKW, NULL, NULL); > break; > > case iSubjKey: > noff_was = noff; >- subj_str(idata, width, str, KW, hline->offs, &noff); >+ subj_str(idata, min(width*6,STRLEN), str, KW, hline->offs, &noff); > /* fix offsets which are now relative to str */ > for(i = noff_was; i < noff; i++) > if(hline->offs[i].offset >= 0) >@@ -5345,34 +5708,11 @@ > } > > if(cdesc->adjustment == Left) >- sprintf(p, "%-*.*s", width, width, str); >+ charset_istrncpy(p, str, width, 1); > else > sprintf(p, "%*.*s", width, width, str); > >- /* >- * Make sure there are no nulls in the part we were supposed to >- * have just written. This may happen if sprintf returns an >- * error, but we don't want to check for that because some >- * sprintfs don't return anything. If there are nulls, rewrite it. >- */ >- for(q = p; q < p+width; q++) >- if(*q == '\0') >- break; >- >- if(q < p+width){ >- strncpy(p, repeat_char(width, ' '), width); >- p[width] = '\0'; >- /* throw a ? in there too */ >- if(width > 4){ >- p[(width-1)/2 - 1] = '?'; >- p[(width-1)/2 ] = '?'; >- p[(width-1)/2 + 1] = '?'; >- } >- else if(width > 2) >- p[(width-1)/2] = '?'; >- } >- >- p += width; >+ p += strlen(p); > } > > >@@ -5401,7 +5741,7 @@ > } > > /* Truncate it to be sure not too wide */ >- buffer[min(ps_global->ttyo->screen_cols, i_cache_width())] = '\0'; >+ buffer[i_cache_width()] = '\0'; > hline->id = line_hash(buffer); > dprint(9, (debugfile, "INDEX(%p) -->%s<-- (%d), 0x%lx>\n", > hline, >@@ -6251,21 +6591,12 @@ > if(addr && !addr->next /* only one address */ > && addr->host /* not group syntax */ > && addr->personal && addr->personal[0]){ /* there is a personal name */ >- char *dummy = NULL; >- char buftmp[MAILTMPLEN]; > int l; > > if(l = prefix ? strlen(prefix) : 0) > strcpy(s, prefix); > >- sprintf(buftmp, "%.75s", addr->personal); >- p = (char *) rfc1522_decode((unsigned char *) tmp_20k_buf, >- SIZEOF_20KBUF, buftmp, &dummy); >- removing_leading_and_trailing_white_space(p); >- istrncpy(s + l, p, width - l); >- s[width] = '\0'; >- if(dummy) >- fs_give((void **)&dummy); >+ rfc1522_decode_width(s + l, addr->personal, width - l, idata); > > if(*(s+l)) > return(TRUE); >@@ -6286,8 +6617,13 @@ > if(l = prefix ? strlen(prefix) : 0) > strcpy(s, prefix); > >- istrncpy(s + l, a_string, width - l); >- s[width] = '\0'; >+ if (p = rfc_1522_check_charset(fetch_subject(idata))) { >+ char *dest = s + l; >+ conv_sstrncpy(p, NULL, &dest, a_string, width); >+ } else { >+ istrncpy(s + l, a_string, width - l); >+ s[width] = '\0'; >+ } > > fs_give((void **)&a_string); > return(TRUE); >@@ -7031,11 +7367,19 @@ > unsigned long rawno; > unsigned char buf[MAILTMPLEN]; > OFFCOLOR_S myoffs[OFFS]; >- int mynoff = 0; >+ int mynoff = 0, we_clear = 0; >+ char *rule_result; > > memset(str, 0, (width+1) * sizeof(*str)); > origstr = str; >- origsubj = fetch_subject(idata); >+ 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,8 +7404,8 @@ > 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); >+ 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,6 +7660,8 @@ > > 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,8 +7889,8 @@ > 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); >+ 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,16 +7981,30 @@ > ? "To" > : (addr = fetch_cc(idata)) > ? "Cc" >- : NULL)) >- && set_index_addr(idata, field, addr, "To: ", >- width, fptr)) >- break; >- >+ : 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){ >- sprintf(fptr, "To: %-*.*s", width-4, width-4, >- 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,8 +8017,17 @@ > break; > > case iFrom: >- set_index_addr(idata, "From", fetch_from(idata), >- NULL, width, fptr); >+ { 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,6 +8110,24 @@ > 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,9 +8152,11 @@ > 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,6 +8203,8 @@ > : 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,7 +8242,7 @@ > break; > } > >- if(rc != 4) /* redraw */ >+ if(rc != 4 && rc != 9) /* redraw */ > break; /* redraw */ > } > >@@ -7868,6 +8259,9 @@ > 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,6 +8448,43 @@ > : ((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,12 +8500,13 @@ > causes the sort to happen if it is still needed. > ----*/ > void >-sort_folder(stream, msgmap, new_sort, new_rev, flags) >+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,6 +8516,15 @@ > 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,6 +8887,7 @@ > > thrd = fetch_head_thread(stream); > for(j = msgmap->max_thrdno; thrd && j >= 1L; j--){ >+ unsigned long branch; > thrd->thrdno = j; > > if(thrd->nextthd) >@@ -8512,7 +8954,7 @@ > MESSAGECACHE *mc; > PINELT_S *peltp; > >- if(!(stream && stream->spare)) >+ if(!(stream && stream->spare) || !erase_thread_info) > return; > > ps_global->view_skipped_index = 0; >@@ -8574,7 +9016,7 @@ > unsigned long msgno, rawno, set_in_thread, in_thread; > int bail, this_is_vis; > int un_view_thread = 0; >- long raw_current; >+ long raw_current, branch; > > > dprint(2, (debugfile, "sort_thread_callback\n")); >@@ -8593,9 +9035,11 @@ > * 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); >+ 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,12 +9204,14 @@ > 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) >- set_lflag(stream, g_sort.msgmap, msgno, MN_CHID, 0); >+ 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,9 +9225,10 @@ > MN_COLL)); > } > >- if(thrd->nextthd) >+ while (thrd && top_thread(stream, thrd->rawno) == top >+ && thrd->nextthd) > thrd = fetch_thread(stream, thrd->nextthd); >- else >+ if (!(thrd && thrd->nextthd)) > thrd = NULL; > } > } >@@ -8802,10 +9249,17 @@ > PINETHRD_S *not_this_thread; > { > PINETHRD_S *thrd = NULL, *nthrd; >- unsigned long msgno; >+ 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,7 +9294,7 @@ > int a_parent_is_collapsed; > { > PINETHRD_S *nthrd, *bthrd; >- unsigned long msgno; >+ unsigned long msgno, next, branch; > > if(!thrd) > return; >@@ -8858,8 +9312,8 @@ > set_lflag(stream, msgmap, msgno, MN_CHID, 0); > } > >- if(thrd->next){ >- nthrd = fetch_thread(stream, thrd->next); >+ if(next = get_next(stream, thrd)){ >+ nthrd = fetch_thread(stream, next); > if(nthrd) > make_thrdflags_consistent(stream, msgmap, nthrd, > a_parent_is_collapsed >@@ -8868,8 +9322,8 @@ > MN_COLL)); > } > >- if(thrd->branch){ >- bthrd = fetch_thread(stream, thrd->branch); >+ if(branch = get_branch(stream, thrd)){ >+ bthrd = fetch_thread(stream, branch); > if(bthrd) > make_thrdflags_consistent(stream, msgmap, bthrd, > a_parent_is_collapsed); >@@ -8882,7 +9336,7 @@ > MAILSTREAM *stream; > { > PINETHRD_S *thrd = NULL; >- long vis = 0L; >+ long vis = 0L, branch; > > thrd = fetch_head_thread(stream); > while(thrd){ >@@ -8899,47 +9353,86 @@ > > > struct pass_along * >-sort_thread_flatten(node, stream, entry, thrd, flags) >+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; >+ PINETHRD_S *newthrd = NULL, *save_thread = NULL; > > if(node){ >- if(node->num){ /* holes happen */ >+ 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; >- } >- >- /* >- * 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) >+ 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); >- >+ 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); >+ 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,6 +9440,26 @@ > 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. >@@ -10101,7 +10614,7 @@ > { > long j; > size_t newsize = sizeof(HLINE_S) >- + ((max(ps_global->ttyo->screen_cols, 80)+1) * sizeof(char)); >+ + ((max(ps_global->ttyo->screen_cols, 80)+1)*6*sizeof(char)); > > if(j = (newsize % sizeof(long))) /* alignment hack */ > newsize += (sizeof(long) - (size_t)j); >@@ -10179,7 +10692,7 @@ > > dprint(2, (debugfile, "Called get_index_cache with msgno=%ld\n", > msgno)); >- big_enough = sizeof(HLINE_S) + (MAX_SCREEN_COLS * sizeof(char)) >+ big_enough = sizeof(HLINE_S) + (MAX_SCREEN_COLS * sizeof(char) * 6) > + sizeof(long); > if(!dummy_to_protect_ourselves) > dummy_to_protect_ourselves = (HLINE_S *) fs_get(big_enough); >@@ -10708,12 +11221,13 @@ > > > void >-thread_command(state, stream, msgmap, preloadkeystroke, q_line) >+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; >@@ -10762,7 +11276,7 @@ > cancel_busy_alarm(0); > > (void ) apply_command(state, stream, msgmap, preloadkeystroke, flags, >- q_line); >+ q_line, display); > > /* restore the original flags */ > copy_lflags(stream, msgmap, MN_STMP, MN_SLCT); >@@ -10800,20 +11314,21 @@ > 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(thrd->next){ >- nthrd = fetch_thread(stream, thrd->next); >+ if(next = get_next(stream,thrd)){ >+ nthrd = fetch_thread(stream, next); > if(nthrd) > set_flags_for_thread(stream, msgmap, f, nthrd, v); > } > >- if(thrd->branch){ >- bthrd = fetch_thread(stream, thrd->branch); >+ if(branch = get_branch(stream, thrd)){ >+ bthrd = fetch_thread(stream, branch); > if(bthrd) > set_flags_for_thread(stream, msgmap, f, bthrd, v); > } >@@ -10868,11 +11383,12 @@ > * index. > */ > void >-collapse_or_expand(state, stream, msgmap, msgno) >+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; >@@ -10926,7 +11442,7 @@ > if(!thrd) > return; > >- collapsed = get_lflag(stream, NULL, thrd->rawno, MN_COLL) && thrd->next; >+ collapsed = this_thread_is_kolapsed(ps_global, stream, msgmap, thrd->rawno); > > if(collapsed){ > msgno = mn_raw2m(msgmap, thrd->rawno); >@@ -10944,13 +11460,13 @@ > 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)) >+ if((thrd->next) && (nthrd = fetch_thread(stream, thrd->next))) > set_thread_subtree(stream, nthrd, msgmap, 1, MN_CHID); > > clear_index_cache_ent(msgno); > } > } >- else >+ else if (display) > q_status_message(SM_ORDER, 0, 1, > "No thread to collapse or expand on this line"); > >@@ -11032,18 +11548,19 @@ > 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(thrd->next){ >- nthrd = fetch_thread(stream, thrd->next); >+ if(next = get_next(stream, thrd)){ >+ nthrd = fetch_thread(stream, next); > if(nthrd) > count += count_flags_in_thread(stream, nthrd, flags); > } > >- if(thrd->branch){ >- bthrd = fetch_thread(stream, thrd->branch); >+ if(branch = get_branch(stream, thrd)){ >+ bthrd = fetch_thread(stream, branch); > if(bthrd) > count += count_flags_in_thread(stream, bthrd, flags); > } >@@ -11074,20 +11591,20 @@ > MSGNO_S *msgmap; > int flags; /* flag to count */ > { >- unsigned long rawno, count = 0; >+ unsigned long rawno, count = 0, next, branch; > 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(next = get_next(stream, thrd)){ >+ nthrd = fetch_thread(stream, next); > if(nthrd) > count += count_lflags_in_thread(stream, nthrd, msgmap, flags); > } > >- if(thrd->branch){ >- bthrd = fetch_thread(stream, thrd->branch); >+ if(branch = get_branch(stream, thrd)){ >+ bthrd = fetch_thread(stream, branch); > if(bthrd) > count += count_lflags_in_thread(stream, bthrd, msgmap,flags); > } >@@ -11109,7 +11626,7 @@ > MAILSTREAM *stream; > PINETHRD_S *thrd; > { >- unsigned long rawno, count = 0; >+ unsigned long rawno, count = 0, next, branch; > PINETHRD_S *nthrd, *bthrd; > > if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs) >@@ -11118,14 +11635,14 @@ > if(get_lflag(stream, NULL, thrd->rawno, MN_HIDE) == 0) > return 1; > >- if(thrd->next){ >- nthrd = fetch_thread(stream, thrd->next); >+ if(next = get_next(stream, thrd)){ >+ nthrd = fetch_thread(stream, next); > if(nthrd && thread_has_some_visible(stream, nthrd)) > return 1; > } > >- if(thrd->branch){ >- bthrd = fetch_thread(stream, thrd->branch); >+ if(branch = get_branch(stream, thrd)){ >+ bthrd = fetch_thread(stream, branch); > if(bthrd && thread_has_some_visible(stream, bthrd)) > return 1; > } >@@ -11200,20 +11717,21 @@ > 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(thrd->next){ >- nthrd = fetch_thread(stream, thrd->next); >+ if(next = get_next(stream, thrd)){ >+ nthrd = fetch_thread(stream, next); > if(nthrd) > count += mark_msgs_in_thread(stream, nthrd, msgmap); > } > >- if(thrd->branch){ >- bthrd = fetch_thread(stream, thrd->branch); >+ if(branch = get_branch(stream, thrd)){ >+ bthrd = fetch_thread(stream, branch); > if(bthrd) > count += mark_msgs_in_thread(stream, bthrd, msgmap); > } >@@ -11247,7 +11765,7 @@ > int flags; /* flags to set or clear */ > int v; /* set or clear? */ > { >- unsigned long rawno, msgno; >+ unsigned long rawno, msgno, next, branch; > PINETHRD_S *nthrd, *bthrd; > > if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs) >@@ -11273,14 +11791,14 @@ > && v == 1 && get_index_cache(msgno)->line[0]) > clear_index_cache_ent(msgno); > >- if(thrd->next){ >- nthrd = fetch_thread(stream, thrd->next); >+ if(next = get_next(stream, thrd)){ >+ nthrd = fetch_thread(stream, next); > if(nthrd) > set_thread_lflags(stream, nthrd, msgmap, flags, v); > } > >- if(thrd->branch){ >- bthrd = fetch_thread(stream, thrd->branch); >+ if(branch = get_branch(stream,thrd)){ >+ bthrd = fetch_thread(stream, branch); > if(bthrd) > set_thread_lflags(stream, bthrd, msgmap, flags, v); > } >@@ -11367,19 +11885,20 @@ > { > 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(thrd->next){ >- nthrd = fetch_thread(stream, thrd->next); >+ 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 == ' ' && thrd->branch){ >- bthrd = fetch_thread(stream, thrd->branch); >+ 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); > } >@@ -11414,7 +11933,7 @@ > break; > } > >- if(to_us != '+' && resent_to_us(&idata)) >+ if(to_us != '+' && !idata.bogus && resent_to_us(&idata)) > to_us = '+'; > > if(to_us == ' ' && F_ON(F_MARK_FOR_CC,ps_global)) >@@ -11450,7 +11969,7 @@ > int flags; /* flags to set or clear */ > { > int hiding; >- unsigned long rawno, msgno; >+ unsigned long rawno, msgno, next, branch; > PINETHRD_S *nthrd, *bthrd; > > hiding = (flags == MN_CHID) && v; >@@ -11462,7 +11981,8 @@ > > set_lflag(stream, msgmap, msgno, flags, v); > >- if(thrd->next && (hiding || !get_lflag(stream,NULL,thrd->rawno,MN_COLL))){ >+ 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); >@@ -11506,8 +12026,8 @@ > if(rawno) > thrd = fetch_thread(stream, rawno); > >- if(thrd && thrd->top && thrd->top != thrd->rawno) >- thrd = fetch_thread(stream, thrd->top); >+ if(thrd && thrd->top && top_thread(stream,thrd->top) != thrd->rawno) >+ thrd = fetch_thread(stream, top_thread(stream,thrd->top)); > > if(!thrd) > return 0; >@@ -11523,8 +12043,9 @@ > set_thread_lflags(stream, thrd, msgmap, MN_CHID2, 1); > } > >- if(current_index_state) >- msgmap->top_after_thrd = current_index_state->msg_at_top; >+/* 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 >@@ -11577,7 +12098,7 @@ > thrd = fetch_thread(stream, rawno); > > if(thrd && thrd->top) >- topthrd = fetch_thread(stream, thrd->top); >+ topthrd = fetch_thread(stream, top_thread(stream,thrd->top)); > > if(!topthrd) > return 0; >@@ -11714,3 +12235,338 @@ > } > } > } >+ >+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 -ru pine4.64/pine/mailpart.c pine4.64.SuSE/pine/mailpart.c >--- pine4.64/pine/mailpart.c 2005-04-27 20:53:45.000000000 +0200 >+++ pine4.64.SuSE/pine/mailpart.c 2006-02-14 14:45:24.000000000 +0100 >@@ -815,8 +815,14 @@ > /*--- 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,18 +835,23 @@ > int flags = OE_APPEND_CURRENT | OE_SEQ_SENSITIVE; > > rc = optionally_enter(buf,-FOOTER_ROWS(ps),0,sizeof(buf), >- tmp,NULL,help,&flags); >+ tmp,ekey,help,&flags); > if(rc == 3) > help = help == NO_HELP ? h_attach_index_whereis : NO_HELP; >- else if(rc == 0 || rc == 1 || !buf[0]){ >+ else if(rc == 0 || rc == 1 || rc == 9 || !buf[0]){ > if(rc == 0 && !buf[0] && last[0]) > strcpy(buf, last); >- >- break; >+ 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,7 +3474,7 @@ > /* > * For consistency, the first question is always "include text?" > */ >- if((include_text = reply_text_query(ps_global, 1, &prefix)) >= 0 >+ 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, >@@ -4113,7 +4124,8 @@ > fs_give((void **) &p); > } > else >- passed = !strucmp(test + 9, "us-ascii"); >+ passed = !strucmp(test + 9, >+ ps_global->VAR_ASSUMED_CHAR_SET ? ps_global->VAR_ASSUMED_CHAR_SET : "us-ascii"); > } > else > dprint(1, (debugfile, >diff -ru pine4.64/pine/mailview.c pine4.64.SuSE/pine/mailview.c >--- pine4.64/pine/mailview.c 2005-09-20 20:26:20.000000000 +0200 >+++ pine4.64.SuSE/pine/mailview.c 2006-02-14 14:45:25.000000000 +0100 >@@ -75,6 +75,15 @@ > int len; > } SCRLFILE_S; > >+#include <regex.h> >+ >+#define REGERROR 128 >+ >+typedef struct IVAL { >+ int start; >+ int end; >+ struct IVAL *next; >+} IVAL_S; > > /* > * Struct to help write lines do display as they're decoded >@@ -152,6 +161,7 @@ > #define SS_CUR 2 > #define SS_FREE 3 > >+static ACTION_S *role_chosen = NULL; > > /* > * Def's to help page reframing based on handles >@@ -182,6 +192,8 @@ > #define CHARSET_DISCLAIMER_2 "display is set" > #define CHARSET_DISCLAIMER_3 \ > " for the \"%.40s\" character set. \015\012Some %.40scharacters may be displayed incorrectly." >+#define CHARSET_DISCLAIMER_4 \ >+ " for the \"%.40s\" character set. \015\012Error: character set unkown or conversion not supported." > #define ENCODING_DISCLAIMER \ > "The following text contains the unknown encoding type \"%.20s\". \015\012Some or all of the text may be displayed incorrectly." > >@@ -235,12 +247,12 @@ > HOMEKEY_MENU, > ENDKEY_MENU, > RCOMPOSE_MENU, >- NULL_MENU, >- NULL_MENU, >- NULL_MENU, >- NULL_MENU, >- NULL_MENU, >- NULL_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,7 +280,12 @@ > {"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,6 +379,16 @@ > 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,6 +413,8 @@ > 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,6 +449,7 @@ > HANDLE_S *handles = NULL; > SCROLL_S scrollargs; > SourceType src = CharStar; >+ FOLDER_S *f = NULL; > > dprint(1, (debugfile, "\n\n ----- MAIL VIEW -----\n")); > >@@ -473,6 +503,17 @@ > 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,6 +675,8 @@ > } > while(ps->next_screen == SCREEN_FUN_NULL); > >+ if (prefix && *prefix) >+ fs_give((void **)&prefix); > if(we_cancel) > cancel_busy_alarm(-1); > >@@ -1590,6 +1633,14 @@ > 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,8 +1651,10 @@ > && 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)); >+ 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 >@@ -2109,9 +2162,14 @@ > *p = '\0'; > } > >- sprintf(p, CHARSET_DISCLAIMER_3, >+ if (quality == CV_NO_TRANSLATE_POSSIBLE) >+ sprintf(p, CHARSET_DISCLAIMER_4, >+ ps_global->VAR_CHAR_SET ? ps_global->VAR_CHAR_SET : "US-ASCII"); >+ else { >+ sprintf(p, CHARSET_DISCLAIMER_3, > ps_global->VAR_CHAR_SET ? ps_global->VAR_CHAR_SET : "US-ASCII", > (quality == CV_LOSES_SPECIAL_CHARS) ? "special " : ""); >+ } > > return(format_editorial(buf, width, pc) == NULL > && gf_puts(NEWLINE, pc) && gf_puts(NEWLINE, pc)); >@@ -2691,6 +2749,8 @@ > {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,11 +2861,41 @@ > * 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 >+ !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,6 +2904,7 @@ > (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, >@@ -2821,6 +2912,29 @@ > 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)(); >+ break; >+ } >+ > case 'u' : > strncpy(tmp, handle->h.url.path, sizeof(tmp)-1); > tmp[sizeof(tmp)-1] = '\0'; >@@ -3482,6 +3596,35 @@ > 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) >@@ -3504,6 +3647,73 @@ > 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; >@@ -3511,19 +3721,25 @@ > LT_INS_S **ins; > void *is_flowed_msg; > { >- int countem = 0; >+ 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; >- if(!is_flowed) >- while(isspace((unsigned char)*p)) >- p++; >+ for(i = 0; isspace((unsigned char)buf[i]); i++) >+ p++; /*(i = is_flowed ? (buf[j] ? j : 0): j);*/ > >- if(p[0] == '>'){ >+ if(buf[i]){ > struct quote_colors *c; > > /* >@@ -3572,7 +3788,7 @@ > free_color_pair(&col); > > cp = NULL; >- while(*p == '>'){ >+ while(buf[i]){ > cp = (cp && cp->next) ? cp->next : colors; > > if(countem > 0) >@@ -3582,10 +3798,9 @@ > > countem = (countem == 1) ? 0 : countem; > >- p++; >- if(!is_flowed) >- for(; isspace((unsigned char)*p); p++) >- ; >+ i = next_level_quote(buf, &p, i, is_flowed); >+ for (; isspace((unsigned char)*p); p++); >+ for (; isspace((unsigned char)buf[i]); i++); > } > > if(colors){ >@@ -3649,6 +3864,78 @@ > 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, plb; >+ char rqstr[NSTRING] = {'\0'}; >+ char buf[NSTRING] = {'\0'}; >+ char GLine[NSTRING] = {'\0'}; >+ char PLine[NSTRING] = {'\0'}; >+ char PPLine[NSTRING] = {'\0'}; >+ char NLine[NSTRING] = {'\0'}; >+ static char GLine1[NSTRING] = {'\0'}; >+ static char PLine1[NSTRING] = {'\0'}; >+ static char PPLine1[NSTRING] = {'\0'}; >+ static char GLine2[NSTRING] = {'\0'}; >+ static char PLine2[NSTRING] = {'\0'}; >+ static char PPLine2[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); >+ strncpy(PPLine, (who ? PPLine1 : PPLine2), buflen); >+ >+ if (linenum > 0) >+ strncpy(PLine, GLine, buflen); >+ >+ strncpy(NLine, tmp_20k_buf, buflen); >+ >+ if (line) >+ strncpy(GLine, line, buflen); >+ else >+ GLine[0] = '\0'; >+ >+ plb = line_isblank((prefix && *prefix ? prefix : ">"), >+ PLine, GLine, PPLine, NSTRING); >+ >+ qs = do_quote_match((prefix && *prefix ? prefix : ">"), >+ GLine, NLine, PLine, rqstr, NSTRING, plb); >+ if (raw) >+ strncpy(buf, rqstr, NSTRING); >+ else >+ flatten_qstring(qs, buf, NSTRING); >+ 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); >+ if (linenum > 0) >+ strncpy((who ? PPLine1 : PPLine2), PLine, buflen); >+ strncpy((who ? GLine1 : GLine2), GLine, buflen); >+ strncpy((who ? PLine1 : PLine2), PLine, buflen); >+ return -1; >+} > > /* > * Paint the signature. >@@ -3661,27 +3948,86 @@ > void *is_in_sig; > { > struct variable *vars = ps_global->vars; >- int *in_sig_block; >+ int *in_sig_block, i, j,same_qstr = 0, plb; > COLOR_PAIR *col = NULL; >+ static char GLine[NSTRING] = {'\0'}; >+ static char PLine[NSTRING] = {'\0'}; >+ static char PPLine[NSTRING] = {'\0'}; >+ char NLine[NSTRING] = {'\0'}; >+ char rqstr[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'; >+ plb = line_isblank((prefix && *prefix ? prefix : ">"), >+ PLine, GLine, PPLine); >+ qs = do_quote_match((prefix && *prefix ? prefix : ">"), >+ GLine, NLine, PLine, rqstr, NSTRING, plb); >+ if(linenum > 0) >+ strncpy(PPLine, PLine, NSTRING); >+ strncpy(buf2, rqstr, NSTRING); >+ 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(!strcmp(line, SIGDASHES)) >- *in_sig_block = START_SIG_BLOCK; >- else if(*line == '\0') >+ >+ 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 = (*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, >@@ -3752,6 +4098,247 @@ > 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 >@@ -3844,7 +4431,7 @@ > { > DELQ_S *dq; > char *lp; >- int i, lines, not_a_quote = 0; >+ int i, lines, not_a_quote = 0, code, feedback; > size_t len; > > dq = (DELQ_S *) local; >@@ -3854,6 +4441,7 @@ > 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. >@@ -3864,6 +4452,9 @@ > 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 >@@ -3903,17 +4494,16 @@ > } > } > >- /* 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++; >+ 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){ >+ if(dq->in_quote > lines+1 && feedback){ > char tmp[500]; > > /* >@@ -5018,7 +5514,7 @@ > fs_give((void **) &urlp); > > rflags = ROLE_COMPOSE; >- if(nonempty_patterns(rflags, &dummy)){ >+ 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); >@@ -5094,6 +5590,7 @@ > > free_redraft_pos(&redraft_pos); > free_action(&role); >+ free_action(&role_chosen); > > return(rv); > } >@@ -5666,7 +6163,7 @@ > 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_flowed_msg = 0, add_me = 1; > int is_delsp_yes = 0; > int filt_only_c0 = 0; > char *parmval; >@@ -5687,7 +6184,8 @@ > && !strucmp(att->body->subtype, "plain") > && (parmval = rfc2231_get_param(att->body->parameter, > "format", NULL, NULL))){ >- if(!strucmp(parmval, "flowed")) >+ if(!strucmp(parmval, "flowed") && >+ F_OFF(F_QUELL_DISPLAYING_FLOWED_TEXT, ps_global)) > is_flowed_msg = 1; > fs_give((void **) &parmval); > >@@ -5774,6 +6272,15 @@ > 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. >@@ -5801,9 +6308,9 @@ > && 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); >+ 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")){ >@@ -5826,11 +6333,7 @@ > /*BUG: sniff the params for "version=2.0" ala draft-ietf-html-spec-01 */ > int opts = 0; > >- if(flags & FM_DISPLAY){ >- if(handlesp) /* pass on handles awareness */ >- opts |= GFHP_HANDLES; >- } >- else >+ if(!(flags & FM_DISPLAY)) > opts |= GFHP_STRIPPED; /* don't embed anything! */ > > wrapit = 0; /* wrap already handled! */ >@@ -5873,6 +6376,12 @@ > } > } > >+ 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) || ((flags & FM_WRAPFLOWED) && is_flowed_msg))){ > int margin = 0, wrapflags = (flags & FM_DISPLAY) ? GFW_HANDLES : 0; > >@@ -5920,7 +6429,7 @@ > dq.saved_line = &free_this; > dq.handlesp = handlesp; > >- filters[filtcnt].filter = gf_line_test; >+ filters[filtcnt].filter = gf_quote_test; > filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq); > } > >@@ -6446,8 +6955,20 @@ > format_addr_string(s, n, sect, "Return-Path: ", e->return_path, > flags, pc); > >- if((which & FE_NEWSGROUPS) && e->newsgroups) >+ if((which & FE_NEWSGROUPS) && e->newsgroups){ >+ int bogus = NIL; > format_newsgroup_string("Newsgroups: ", e->newsgroups, flags, pc); >+ if (!e->ngpathexists && e->message_id && >+ strncmp (e->message_id,"<Pine.",6) && >+ strncmp (e->message_id,"<MS-C.",6) && >+ strncmp (e->message_id,"<MailManager.",13) && >+ strncmp (e->message_id,"<EasyMail.",11) && >+ strncmp (e->message_id,"<ML-",4)) bogus = T; >+ >+ if(bogus) >+ q_status_message(SM_ORDER, 0, 3, >+ "Unverified Newsgroup header -- Message MAY or MAY NOT have been posted"); >+ } > > if((which & FE_FOLLOWUPTO) && e->followup_to) > format_newsgroup_string("Followup-To: ", e->followup_to, flags, pc); >@@ -7215,7 +7736,7 @@ > 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; >+ cursor_row, cursor_col, km_popped, nm; > long jn; > struct key_menu *km; > HANDLE_S *next_handle; >@@ -7422,7 +7943,8 @@ > > /*============ Check for New Mail and CheckPoint ============*/ > if(!sparms->quell_newmail && >- new_mail(force, NM_TIMING(ch), NM_STATUS_MSG) >= 0){ >+ (nm = new_mail(force, NM_TIMING(ch), NM_STATUS_MSG)) >= 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, >@@ -7430,6 +7952,21 @@ > > ps_global->mangled_footer = 0; > } >+ ps_global->in_pico = 0; >+ >+ if (!sparms->quell_newmail && !ps_global->skip_ifcheck) >+ new_mail_incfolder(ps_global, MC_IFAUTOCHECK); >+ ps_global->skip_ifcheck = 0; >+ if (ps_global->refresh_list){ >+ if(ps_global->in_fld_list && >+ ((ps_global->refresh_list & IF_REFRESH_STRONG) >+ || (ps_global->refresh_list & IF_REFRESH_WEAK >+ && (sparms->text.handles->h.f.context->use & CNTXT_INCMNG)))) >+ cmd = MC_RESIZE; >+ ps_global->refresh_list &= IF_REFRESH_NONE; >+ if(cmd == MC_RESIZE) >+ goto end; >+ } > > /* > * If an expunge of the current message happened during the >@@ -7564,6 +8101,7 @@ > break; > } > >+ ps_global->force_check_now = (((cmd == MC_NONE) || (cmd == MC_FORCECHECK)) ? 1 : 0); > > /*============= Execute command =======================*/ > switch(cmd){ >@@ -8276,6 +8814,52 @@ > 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 : >@@ -8308,7 +8892,27 @@ > > 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){ >+ if(ps_global->in_fld_list && >+ ((ps_global->refresh_list & IF_REFRESH_STRONG) >+ || (ps_global->refresh_list & IF_REFRESH_WEAK >+ && (sparms->text.handles->h.f.context->use >+ & CNTXT_INCMNG)))) >+ cmd = MC_RESIZE; >+ ps_global->refresh_list &= IF_REFRESH_NONE; >+ if(cmd == MC_RESIZE) >+ goto end; >+ } >+ break; > >+ case MC_TAB: >+ ps_global->skip_ifcheck++; >+ /* do not check for new mail in inc fldrs and fall through */ >+ > /*------- Standard commands ------*/ > default: > whereis_pos.row = 0; >@@ -8380,6 +8984,7 @@ > > } /* 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); >@@ -8488,8 +9093,10 @@ > 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} >@@ -8511,6 +9118,9 @@ > 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); >@@ -8520,7 +9130,7 @@ > return(-5); > } > >- if(rc != 4) >+ if(rc != 4 && rc != 9) > break; > } > >@@ -8532,6 +9142,9 @@ > 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 -ru pine4.64/pine/makefile.lnx pine4.64.SuSE/pine/makefile.lnx >--- pine4.64/pine/makefile.lnx 2003-11-25 07:46:01.000000000 +0100 >+++ pine4.64.SuSE/pine/makefile.lnx 2006-02-14 14:45:25.000000000 +0100 >@@ -45,9 +45,9 @@ > RM= rm -f > LN= ln -s > MAKE= make >-OPTIMIZE= # -O2 >+OPTIMIZE= -O2 -pipe > PROFILE= # -pg >-DEBUG= -g -DDEBUG -DDEBUGJOURNAL >+DEBUG= -g # -DDEBUG -DDEBUGJOURNAL > > CCLIENTDIR= ../c-client > PICODIR= ../pico >diff -ru pine4.64/pine/newmail.c pine4.64.SuSE/pine/newmail.c >--- pine4.64/pine/newmail.c 2005-01-14 01:43:13.000000000 +0100 >+++ pine4.64.SuSE/pine/newmail.c 2006-02-14 14:45:23.000000000 +0100 >@@ -48,6 +48,8 @@ > > #include "headers.h" > >+static long incoming_folders_new_mail = 0L; >+ > > /* > * Internal prototypes >@@ -840,6 +842,8 @@ > > if(subject) > fs_give((void **) &subject); >+ >+ ps_global->skip_ifcheck = 0; > } > > >@@ -1095,6 +1099,11 @@ > 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,3 +1308,296 @@ > } > } > #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 i, j; >+ int checks, indx, f_indx, first_check; >+ int nflds = 0, tlflds = 0, newflds = 0, tflds; >+ int save_state, last_fld_chkd = state->last_folder_checked; >+ int tcp_query_timeout = state->tcp_query_timeout; >+ int tcp_open_timeout = 30; >+ int offset = F_ON(F_ENABLE_FAST_RECENT, state) ? 1 : 0; >+ static int index = -1; >+ static int check_started = 0; >+ time_t start_check, this_check, total_check; >+ static time_t now, old = 0; >+ 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) && >+ (now - old < timeo)) >+ 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)); >+ >+ /* Someone removed a folder between checks among other things */ >+ if(index >= tflds) >+ index = -1; >+ >+ if(index < folder_index(state->inbox_name, ctxt, FI_FOLDER) >+ + offset) >+ index = folder_index(state->inbox_name, ctxt, FI_FOLDER) + offset; >+ >+ f_indx = index; >+ if(state->first_folder_checked != f_indx) >+ state->refresh_list |= IF_REFRESH_WEAK; >+ state->first_folder_checked = f_indx; >+ this_check = total_check = 0; >+ for(checks = 0; checks < tflds - offset >+ && (f = folder_entry(index, FOLDERS(ctxt))) >+ && !f->isdir; index++, checks++){ >+ >+ if(checks == 0) >+ first_check = 0; >+ >+ if(F_OFF(F_ENABLE_INCOMING_RECHECK,state) >+ && (command != MC_FORCECHECK) >+ && (f->last_check_time != 0) /* do a full first check */ >+ && total_check > state->incfld_timeout) >+ break; >+ >+ state->login_time = 0; /* modified in mm_login */ >+ start_check = time(0); >+ if(F_ON(F_ENABLE_INCOMING_RECHECK, state) >+ || (command == MC_FORCECHECK) >+ || (f->last_check_time == 0) /* first call? */ >+ || (start_check - f->last_check_time > f->last_check_length*timeo)){ >+ if(first_check == 0){ >+ first_check++; >+ state->first_folder_checked = index; >+ } >+ state->last_folder_checked = index; >+ fslctd = next_folder_check(&nxtstrm, ctxt, &rec, &tot, f, &opstrm); >+ this_check = time(0) - start_check - state->login_time; >+ f->last_check_time = start_check + this_check + state->login_time; >+ f->interesting = fslctd; >+ f->opstrm = opstrm; >+ f->last_check_length = this_check + 1; >+ state->refresh_list |= f->skipped ? IF_REFRESH_WEAK : IF_REFRESH_NONE; >+ f->skipped = 0; >+ } >+ else{ >+ fslctd = f->interesting; >+ opstrm = f->opstrm; >+ rec = f->recent; /* use the old data */ >+ tot = f->messages; >+ this_check = 0; >+ state->refresh_list |= f->skipped ? IF_REFRESH_NONE : IF_REFRESH_WEAK; >+ f->skipped = 1; >+ } >+ total_check += this_check; >+ >+ 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 |= IF_REFRESH_STRONG; >+ >+ 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 ? IF_REFRESH_NONE : IF_REFRESH_STRONG; >+ f->selected = 1; >+ 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 ? IF_REFRESH_NONE : IF_REFRESH_STRONG; >+ if (f->notified) >+ f->selected = f->user_selected ? 1 : 0; >+ f->notified = f->new_mail = 0; /* reset */ >+ } >+ if(index == tflds - 1) >+ index = folder_index(state->inbox_name, ctxt, FI_FOLDER) >+ + offset - 1; >+ } >+ >+ if(nxtstrm) >+ pine_mail_close(nxtstrm); >+ >+ if(ps_global->last_folder_checked != last_fld_chkd) >+ state->refresh_list |= IF_REFRESH_WEAK; >+ >+ 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 |= IF_REFRESH_STRONG; >+ strcpy(MSG(tlflds),"New mail in folder"); >+ strcat(MSG(tlflds),(NMVAR() > 1) ? "s " : " "); >+ for(i = 0, j = 0, indx = f_indx; >+ j < checks && (f = folder_entry(indx, FOLDERS(ctxt))); j++, indx++){ >+ 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(indx == tflds - 1) >+ indx = folder_index(state->inbox_name, ctxt,FI_FOLDER)+ offset - 1; >+ } >+ 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 mail 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 = total_check; >+ 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 = stream->recent; >+ } >+ >+ return *rec ? STREAMNAME(stream) : NULL; >+} >diff -ru pine4.64/pine/osdep/makefile pine4.64.SuSE/pine/osdep/makefile >--- pine4.64/pine/osdep/makefile 2004-04-03 01:14:27.000000000 +0200 >+++ pine4.64.SuSE/pine/osdep/makefile 2006-02-14 14:45:25.000000000 +0100 >@@ -20,7 +20,7 @@ > all: includer $(ALL) > > includer: includer.c >- $(CC) -o includer includer.c >+ $(CC) $(EXTRACFLAGS) -o includer includer.c > > clean: > $(RM) $(ALL) includer >--- pine4.64/pine/osdep/os-lnx.h 2003-05-23 18:05:21.000000000 +0200 >+++ pine4.64.SuSE/pine/osdep/os-lnx.h 2006-02-14 14:45:25.000000000 +0100 >@@ -214,6 +214,9 @@ > ----*/ > #define DF_DEFAULT_PRINTER ANSI_PRINTER > >+/* all recent Linux distributions come with glibc 2.x. with an excellent >+ * iconv implementation */ >+#define HAVE_ICONV > > > /*----- The usual sendmail configuration for sending mail on Unix ------*/ >@@ -250,6 +253,11 @@ > #define MAX_SCREEN_COLS (170) > #define MAX_SCREEN_ROWS (200) > >+/*---------------------------------------------------------------------- >+ File name used to store the user's server/id/password triple between >+ session. It is rooted in the same directory as the PINERC. >+ ----*/ >+#define PASSFILE ".pinepw" > > /*---------------------------------------------------------------------- > Where to put the output of pine in debug mode. Files are created >diff -ru pine4.64/pine/osdep/pipe pine4.64.SuSE/pine/osdep/pipe >--- pine4.64/pine/osdep/pipe 2004-09-22 21:31:52.000000000 +0200 >+++ pine4.64.SuSE/pine/osdep/pipe 2006-02-14 14:45:25.000000000 +0100 >@@ -266,7 +266,7 @@ > shellpath[sizeof(shellpath)-1] = '\0'; > } > >- execl(shellpath, shell, command ? "-c" : 0, command, 0); >+ execl(shellpath, shell, command ? "-c" : NULL, command, NULL); > } > > fprintf(stderr, "Can't exec %s\nReason: %s", >diff -ru pine4.64/pine/osdep/termin.gen pine4.64.SuSE/pine/osdep/termin.gen >--- pine4.64/pine/osdep/termin.gen 2004-12-01 19:56:45.000000000 +0100 >+++ pine4.64.SuSE/pine/osdep/termin.gen 2006-02-14 14:45:24.000000000 +0100 >@@ -6,6 +6,23 @@ > 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 >@@ -122,14 +139,93 @@ > static struct display_line { > int row, col; /* where display starts */ > int dlen; /* length of display line */ >- char *dl; /* line on display */ >- char *vl; /* virtual line */ >+ int *dl; /* line on display */ >+ int *vl; /* virtual line */ > int vlen; /* length of virtual line */ > int vused; /* length of virtual line in use */ > int vbase; /* first virtual char on display */ > } dline; > >+/* >+ * In UTF-8 mode, decode byte sequencies and if a sequence is complete, >+ * insert the resulting Unicode(UCS4) value as cell value into the buffer. >+ */ >+static int insert_byte(offset, c) >+unsigned int offset, c; >+{ >+ int *s2; >+ static char linsert_buf[6], linsert_buf_count = 0; >+ if (gmode & P_UNICODE && c & 0x80) { >+ if (linsert_buf_count >= sizeof(linsert_buf)) >+ linsert_buf_count = 0; >+ linsert_buf[linsert_buf_count++] = c; >+ c = 0; >+ if (linsert_buf_count > 1) >+ c = utf8_get_ucs(linsert_buf, linsert_buf_count); >+ if (!c) >+ return 0; >+ } >+ linsert_buf_count = 0; >+ for(s2 = &dline.vl[++dline.vused]; s2 - dline.vl > offset; s2--) >+ *s2 = *(s2-1); >+ dline.vl[offset] = c; >+ return 1; >+} >+ >+/*---------------------------------------------------------------------- >+ Write a character to the screen, keeping track of cursor position >+ >+ Args: ch -- character to output > >+ Result: character output >+ cursor position variables updated >+ ----*/ >+void >+Writechar_UCS4(c) >+ register unsigned int c; >+{ >+ if (gmode & P_UNICODE && c > 127) { >+ if (c & 0xf800) { >+ Writechar(0xe0 | (c >> 12), 0); >+ Writechar(0x80 | ((c >> 6) & 0x3f), 0); >+ } >+ else >+ Writechar(0xc0 | ((c >> 6) & 0x3f), 0); >+ Writechar(0x80 | (c & 0x3f), 0); >+ return; >+ } >+ Writechar(c, 0); >+} >+ >+/*---------------------------------------------------------------------- >+ ----*/ >+void >+UCS4vektor_to_UTF8string(c, inchars, utf8, ospace) >+int *c; >+size_t inchars; >+unsigned char *utf8; >+int ospace; >+{ >+ for(;inchars > 0 && ospace > 3 && *c; c++) { >+ if (gmode & P_UNICODE && *c > 127) { >+ if (*c & 0xf800) { >+ *utf8++ = 0xe0 | (*c >> 12); >+ *utf8++ = 0x80 | ((*c >> 6) & 0x3f); >+ ospace -= 3; >+ } >+ else { >+ ospace -= 2; >+ *utf8++ = 0xc0 | ((*c >> 6) & 0x3f); >+ } >+ *utf8++ = 0x80 | (*c & 0x3f); >+ } >+ else { >+ *utf8++ = *c; >+ ospace--; >+ } >+ } >+ *utf8 = '\0'; >+} > > static struct key oe_keys[] = > {{"^G","Help",KS_SCREENHELP}, {"^C","Cancel",KS_NONE}, >@@ -200,12 +296,13 @@ > int x_base, y_base, field_len; > int *flags; > { >- register char *s2; >+ register int *s2; > register int field_pos; > int i, j, return_v, cols, ch, prompt_len, too_thin, > real_y_base, km_popped, passwd; > char *saved_original = NULL, *k, *kb; >- char *kill_buffer = NULL; >+ int *kill_buffer = NULL; >+ size_t kb_len; > char **help_text; > int fkey_table[12]; > struct key_menu *km; >@@ -227,7 +324,7 @@ > (escape_list && escape_list[0].ch != -1) > ? escape_list[0].label: "")); > >- if(!ps_global->ttyo) >+ if((!ps_global->ttyo) || (ps_global->send_immediately)) > return(pre_screen_config_opt_enter(string, field_len, prompt, > escape_list, help, flags)); > >@@ -366,11 +463,14 @@ > dline.dlen = 5; > } > >- dline.dl = fs_get((size_t)dline.dlen + 1); >- memset((void *)dline.dl, 0, (size_t)(dline.dlen + 1) * sizeof(char)); >+ dline.dl = fs_get((size_t)dline.dlen*4 + 4); >+ memset((void *)dline.dl, 0, (size_t)(dline.dlen*4 + 4) * sizeof(char)); > dline.row = real_y_base; > dline.col = x_base + prompt_len; >- dline.vl = string; >+ >+ dline.vl = fs_get((size_t)field_len*4 + 4); >+ memset((void *)dline.vl, 0, (size_t)(field_len*4 + 4) * sizeof(char)); >+ > dline.vlen = --field_len; /* -1 for terminating NULL */ > dline.vbase = field_pos = 0; > >@@ -382,12 +482,12 @@ > /* make sure passed in string is shorter than field_len */ > /* and adjust field_pos.. */ > >- while((flags && *flags & OE_APPEND_CURRENT) && >- field_pos < field_len && string[field_pos] != '\0') >- field_pos++; >+ if(flags && *flags & OE_APPEND_CURRENT) >+ for(kb = string; (i=strlen(kb)) > 0 && field_pos < field_len;) >+ dline.vl[field_pos++] = utf8_get_ucs_string(&kb, i); > > string[field_pos] = '\0'; >- dline.vused = (int)(&string[field_pos] - string); >+ dline.vused = field_pos; > passwd = (flags && *flags & OE_PASSWD) ? 1 : 0; > line_paint(field_pos, &passwd); > >@@ -458,7 +558,7 @@ > /*--------------- KEY RIGHT ---------------*/ > case ctrl('F'): > case KEY_RIGHT: >- if(field_pos >= field_len || string[field_pos] == '\0') >+ if(field_pos >= field_len || dline.vl[field_pos] == 0) > goto bleep; > > line_paint(++field_pos, &passwd); >@@ -482,13 +582,13 @@ > */ > > /* skip thru current word */ >- while(string[field_pos] >- && isalnum((unsigned char) string[field_pos])) >+ while(dline.vl[field_pos] >+ && isalnum((unsigned char) dline.vl[field_pos])) > field_pos++; > > /* skip thru current white space to next word */ >- while(string[field_pos] >- && !isalnum((unsigned char) string[field_pos])) >+ while(dline.vl[field_pos] >+ && !isalnum((unsigned char) dline.vl[field_pos])) > field_pos++; > > line_paint(field_pos, &passwd); >@@ -518,11 +618,11 @@ > /*-------------------- Delete char --------------------*/ > case ctrl('D'): > case KEY_DEL: >- if(field_pos >= field_len || !string[field_pos]) >+ if(field_pos >= field_len || !dline.vl[field_pos]) > goto bleep; > > dline.vused--; >- for(s2 = &string[field_pos]; *s2 != '\0'; s2++) >+ for(s2 = &dline.vl[field_pos]; *s2 != 0; s2++) > *s2 = s2[1]; > > *s2 = '\0'; /* Copy last NULL */ >@@ -538,14 +638,15 @@ > if(kill_buffer != NULL) > fs_give((void **)&kill_buffer); > >- if(field_pos != 0 || string[0]){ >- if(!passwd && F_ON(F_DEL_FROM_DOT, ps_global)) >- dline.vused -= strlen(&string[i = field_pos]); >- else >- dline.vused = i = 0; >+ if(field_pos != 0 || dline.vl[0]){ >+ if(passwd || !F_ON(F_DEL_FROM_DOT, ps_global)) >+ field_pos = 0; >+ kb_len = (dline.vused - field_pos)*4+4; >+ kill_buffer = fs_get(kb_len); >+ dline.vused = field_pos; > >- kill_buffer = cpystr(&string[field_pos = i]); >- string[field_pos] = '\0'; >+ memcpy(kill_buffer, &dline.vl[field_pos], kb_len); >+ dline.vl[field_pos] = 0; > line_paint(field_pos, &passwd); > if(flags) /* record change if requested */ > *flags |= OE_USER_MODIFIED; >@@ -559,7 +660,7 @@ > if(kill_buffer == NULL) > goto bleep; > >- /* Make string so it will fit */ >+ /* Make string so it will fit > kb = cpystr(kill_buffer); > dprint(2, (debugfile, > "Undelete: %d %d\n", strlen(string), field_len)); >@@ -567,24 +668,24 @@ > kb[field_len - strlen(string)] = '\0'; > dprint(2, (debugfile, > "Undelete: %d %d\n", field_len - strlen(string), >- strlen(kb))); >+ strlen(kb))); */ > >- if(string[field_pos] == '\0') { >+ if(dline.vl[field_pos] == 0) { > /*--- adding to the end of the string ----*/ >- for(k = kb; *k; k++) >- string[field_pos++] = *k; >- >- string[field_pos] = '\0'; >+ if ((field_len-field_pos)*4 < kb_len) >+ goto bleep; >+ memcpy(&dline.vl[field_pos], kill_buffer, kb_len); >+ field_pos = kb_len/4-1; >+ dline.vl[field_pos] = 0; > } else { > goto bleep; > /* To lazy to do insert in middle of string now */ > } > >- if(*kb && flags) /* record change if requested */ >+ if(flags) /* record change if requested */ > *flags |= OE_USER_MODIFIED; > >- dline.vused = strlen(string); >- fs_give((void **)&kb); >+ dline.vused = field_pos; > line_paint(field_pos, &passwd); > break; > >@@ -650,8 +751,8 @@ > y_base = -3; > dline.row = real_y_base = y_base + ps_global->ttyo->screen_rows; > PutLine0(real_y_base, x_base, prompt); >- fs_resize((void **)&dline.dl, (size_t)dline.dlen + 1); >- memset((void *)dline.dl, 0, (size_t)(dline.dlen + 1)); >+ fs_resize((void **)&dline.dl, (size_t)dline.dlen*4 + 4); >+ memset((void *)dline.dl, 0, (size_t)(dline.dlen*4 + 4)); > line_paint(field_pos, &passwd); > break; > } >@@ -748,8 +849,8 @@ > } else { > dline.col = x_base + prompt_len; > dline.dlen = cols - (x_base + prompt_len + 1); >- fs_resize((void **)&dline.dl, (size_t)dline.dlen + 1); >- memset((void *)dline.dl, 0, (size_t)(dline.dlen + 1)); >+ fs_resize((void **)&dline.dl, (size_t)dline.dlen*4 + 4); >+ memset((void *)dline.dl, 0, (size_t)(dline.dlen*4 + 4)); > line_paint(field_pos, &passwd); > } > fflush(stdout); >@@ -785,7 +886,7 @@ > break; > } > >- if(iscntrl(ch & 0x7f)){ >+ if(iscntrl(ch)){ > bleep: > putc(BELL, stdout); > continue; >@@ -796,14 +897,11 @@ > if(dline.vused >= field_len) > goto bleep; > >- /*---- extending the length of the string ---*/ >- for(s2 = &string[++dline.vused]; s2 - string > field_pos; s2--) >- *s2 = *(s2-1); >- >- string[field_pos++] = ch; >- line_paint(field_pos, &passwd); >- if(flags) /* record change if requested */ >- *flags |= OE_USER_MODIFIED; >+ if (insert_byte(field_pos, ch)) { >+ line_paint(++field_pos, &passwd); >+ if(flags) /* record change if requested */ >+ *flags |= OE_USER_MODIFIED; >+ } > > } /*---- End of switch on char ----*/ > } >@@ -813,6 +911,10 @@ > mswin_showcaret(0); > #endif > >+ UCS4vektor_to_UTF8string(dline.vl, dline.vused, string, field_len); >+ dprint(10, (debugfile, "converted: '%s'\n", string)); >+ >+ fs_give((void **)&dline.vl); > fs_give((void **)&dline.dl); > if(saved_original) > fs_give((void **)&saved_original); >@@ -857,8 +959,8 @@ > int offset; /* current dot offset into line */ > int *passwd; /* flag to hide display of chars */ > { >- register char *pfp, *pbp; >- register char *vfp, *vbp; >+ register int *pfp, *pbp; >+ register int *vfp, *vbp; > int extra = 0; > #define DLEN (dline.vbase + dline.dlen) > >@@ -891,15 +993,15 @@ > if(dline.vbase){ /* off screen cue left */ > vfp = &dline.vl[dline.vbase+1]; > pfp = &dline.dl[1]; >- if(dline.dl[0] != '<'){ >+ if(dline.dl[0] != 60 /* '<' */ ){ > MoveCursor(dline.row, dline.col); >- Writechar(dline.dl[0] = '<', 0); >+ Writechar(dline.dl[0] = 60 /* '<' */ , 0); > } > } > else{ > vfp = dline.vl; > pfp = dline.dl; >- if(dline.dl[0] == '<'){ >+ if(dline.dl[0] == 60 /* '<' */ ){ > MoveCursor(dline.row, dline.col); > Writechar(dline.dl[0] = ' ', 0); > } >@@ -908,16 +1010,16 @@ > if(dline.vused > DLEN){ /* off screen right... */ > vbp = vfp + (long)(dline.dlen-(dline.vbase ? 2 : 1)); > pbp = pfp + (long)(dline.dlen-(dline.vbase ? 2 : 1)); >- if(pbp[1] != '>'){ >+ if(pbp[1] != 62 /* '>' */ ){ > MoveCursor(dline.row, dline.col+dline.dlen); >- Writechar(pbp[1] = '>', 0); >+ Writechar(pbp[1] = 62 /* '>' */ , 0); > } > } > else{ > extra = dline.dlen - (dline.vused - dline.vbase); > vbp = &dline.vl[max(0, dline.vused-1)]; > pbp = &dline.dl[dline.dlen]; >- if(pbp[0] == '>'){ >+ if(pbp[0] == 62 /* '>' */ ){ > MoveCursor(dline.row, dline.col+dline.dlen); > Writechar(pbp[0] = ' ', 0); > } >@@ -949,9 +1051,9 @@ > MoveCursor(dline.row, dline.col + (int)(pfp - dline.dl)); > > do >- Writechar((unsigned char)((vfp <= vbp && *vfp) >+ Writechar_UCS4(((vfp <= vbp && *vfp) > ? ((*pfp = *vfp++) == TAB) ? ' ' : *pfp >- : (*pfp = ' ')), 0); >+ : (*pfp = ' '))); > while(++pfp <= pbp); > } > >@@ -1030,6 +1132,7 @@ > 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,7 +1142,7 @@ > } > > if(firsttime) { >- firsttime = 0; >+ 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 -ru pine4.64/pine/osdep/termin.unx pine4.64.SuSE/pine/osdep/termin.unx >--- pine4.64/pine/osdep/termin.unx 2004-08-03 23:46:57.000000000 +0200 >+++ pine4.64.SuSE/pine/osdep/termin.unx 2006-02-14 14:45:25.000000000 +0100 >@@ -46,66 +46,17 @@ > 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(); > #endif /* MOUSE */ > >- /* turn off talk permission by default */ >- >- if(F_ON(F_ALLOW_TALK, ps)) >- allow_talk(ps); >- else >- disallow_talk(ps); >- > return(PineRaw(1)); > } > > >- >-/*---------------------------------------------------------------------- >- Set or clear the specified tty mode >- >- Args: ps -- struct pine >- mode -- mode bits to modify >- clear -- whether or not to clear or set >- >- Result: tty driver mode change. >- ----------------------------------------------------------------------*/ >-void >-tty_chmod(ps, mode, func) >- struct pine *ps; >- int mode; >- int func; >-{ >- char *tty_name; >- int new_mode; >- struct stat sbuf; >- static int saved_mode = -1; >- >- /* if no problem figuring out tty's name & mode? */ >- if((((tty_name = (char *) ttyname(STDIN_FD)) != NULL >- && fstat(STDIN_FD, &sbuf) == 0) >- || ((tty_name = (char *) ttyname(STDOUT_FD)) != NULL >- && fstat(STDOUT_FD, &sbuf) == 0)) >- && !(func == TMD_RESET && saved_mode < 0)){ >- new_mode = (func == TMD_RESET) >- ? saved_mode >- : (func == TMD_CLEAR) >- ? (sbuf.st_mode & ~mode) >- : (sbuf.st_mode | mode); >- /* assign tty new mode */ >- if(chmod(tty_name, new_mode) == 0){ >- if(func == TMD_RESET) /* forget we knew */ >- saved_mode = -1; >- else if(saved_mode < 0) >- saved_mode = sbuf.st_mode; /* remember original */ >- } >- } >-} >- >- >- > /*---------------------------------------------------------------------- > End use of the tty, put it back into it's normal mode (UNIX) > >@@ -125,7 +76,6 @@ > fflush(stdout); > dprint(2, (debugfile, "about to end_tty_driver\n")); > >- tty_chmod(ps, 0, TMD_RESET); > PineRaw(0); > } > >@@ -264,11 +214,17 @@ > int time_out; > { > int ch, status, cc; >+ static int saved; > > /* Get input from initial-keystrokes */ > if(process_config_input(&ch)) > return(ch); > >+ if (saved) { >+ ch = saved; >+ saved = 0; >+ return ch; >+ } > /* > * We only check for timeouts at the start of read_char, not in the > * middle of escape sequences. >@@ -310,6 +266,10 @@ > } > > ch = i; >+ if (gmode & P_UNICODE) { >+ saved = 0x80 | (ch & 0x3f); >+ ch = 0xc0 | ((ch >> 6) & 0x3f); >+ } > } > else{ > if(islower((unsigned char)ch)) /* canonicalize if alpha */ >@@ -573,6 +533,9 @@ > 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,6 +554,9 @@ > 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 -ru pine4.64/pine/osdep/termout.unx pine4.64.SuSE/pine/osdep/termout.unx >--- pine4.64/pine/osdep/termout.unx 2004-11-30 18:54:05.000000000 +0100 >+++ pine4.64.SuSE/pine/osdep/termout.unx 2006-02-14 14:45:23.000000000 +0100 >@@ -160,6 +160,9 @@ > void > init_screen() > { >+ if(ps_global->send_immediately) >+ return; >+ > if(_termcap_init) /* init using termcap's rule */ > tputs(_termcap_init, 1, outchar); > >@@ -267,6 +270,9 @@ > { > int footer_rows_was_one = 0; > >+ if(ps_global->send_immediately) >+ return; >+ > if(!panicking){ > > dprint(9, (debugfile, "end_screen called\n")); >@@ -321,7 +327,7 @@ > _line = 0; /* clear leaves us at top... */ > _col = 0; > >- if(ps_global->in_init_seq) >+ if(ps_global->in_init_seq || ps_global->send_immediately) > return; > > mark_status_unknown(); >@@ -744,7 +750,8 @@ > register unsigned int ch; > int new_esc_len; > { >- static int esc_len = 0; >+ static int esc_len = 0, seq = 0; >+ static unsigned char utf_seq[7] = ""; > > if(ps_global->in_init_seq /* silent */ > || (F_ON(F_BLANK_KEYMENU, ps_global) /* or bottom, */ >@@ -753,6 +760,35 @@ > && _col + 1 == ps_global->ttyo->screen_cols)) > return; > >+ /* Treat UTF-8 sequences if we are not in a special escape sequence */ >+ if(esc_len <= 0) { >+ unsigned char *chp; >+ char tmp; >+ tmp = (char)ch; >+ if ((chp = pine_check_utf8(&tmp, utf_seq, sizeof(utf_seq))) == NULL) { >+ seq = 1; /* flag that we are in a open UTF-8 sequence */ >+ return; /* UTF-8 sequence not complete, need next char */ >+ } >+ if (chp != (unsigned char*)&tmp) { >+ seq = 0; /* flag that we are not in a open UTF-8 sequence */ >+ _col++; >+ if (*chp == ' ') { >+ if(++_col > ps_global->ttyo->screen_cols) { >+ printf("\342\200\246"); /* UTF-8 points... */ >+ goto wrap; >+ } >+ chp++; >+ } >+ while(*chp) >+ putchar(*chp++); >+ return; >+ } >+ if (seq) { /* incomplete UTF-8 sequence */ >+ seq = 0; /* flag that we are not in a open UTF-8 sequence */ >+ putchar('?'); /* print question mark at place of sequence */ >+ } >+ } >+ > if(ch == LINE_FEED || ch == RETURN || ch == BACKSPACE || ch == BELL > || ch == TAB || ch == ESCAPE){ > switch(ch){ >@@ -830,7 +866,9 @@ > like case 1. A little expensive but worth it to avoid problems > with terminals configured so they don't match termcap > */ >- if(_col == ps_global->ttyo->screen_cols) { >+ if(_col >= ps_global->ttyo->screen_cols) { >+wrap: >+ dprint(9, (debugfile, "%d,%02d, wrap(%x)\n",_line,_col,ch)); > _col = 0; > if(_line + 1 < ps_global->ttyo->screen_rows) > _line++; >diff -ru pine4.64/pine/other.c pine4.64.SuSE/pine/other.c >--- pine4.64/pine/other.c 2005-09-13 00:04:25.000000000 +0200 >+++ pine4.64.SuSE/pine/other.c 2006-02-14 14:45:25.000000000 +0100 >@@ -362,8 +362,8 @@ > 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 *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,7 +1608,7 @@ > if(lv < (j = strlen(sort_name(ps->sort_types[i])))) > lv = j; > >- decode_sort(pval, &def_sort, &def_sort_rev); >+ 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,6 +1623,56 @@ > } > } > } >+ 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,6 +1724,7 @@ > || 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,6 +1830,15 @@ > } > } > >+ 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,6 +1859,7 @@ > 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,6 +1889,8 @@ > 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,7 +1996,8 @@ > CONF_S *ctmp; > > if(!(cl && *cl && >- ((*cl)->var == &ps->vars[V_SORT_KEY] || >+ (((*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,6 +2063,7 @@ > case V_TCPREADWARNTIMEO : > case V_TCPWRITEWARNTIMEO : > case V_TCPQUERYTIMEO : >+ case V_INCFLDTIMEO : > case V_RSHCMD : > case V_RSHPATH : > case V_RSHOPENTIMEO : >@@ -6471,7 +6536,7 @@ > int multicol; > { > char tmp[MAXPATH+1]; >- int cmd, i, j, ch = 'x', done = 0, changes = 0; >+ 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; >@@ -6518,6 +6583,7 @@ > } > > /*----------- 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; > >@@ -6547,6 +6613,7 @@ > mark_status_unknown(); > } > >+ } /* send_immediately */ > if(ps->mangled_footer || km != screen->current->keymenu){ > bitmap_t bitmap; > >@@ -6618,6 +6685,7 @@ > } > } > >+ 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 */ >@@ -6636,6 +6704,14 @@ > #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); > >@@ -7057,10 +7133,12 @@ > #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}}; >@@ -7079,13 +7157,22 @@ > 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]){ >+ 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); > >- break; >+ 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]){ >@@ -7297,7 +7384,7 @@ > break; > } > } >- >+end: > screen->current = first_confline(screen->current); > free_conflines(&screen->current); > return(retval); >@@ -7440,6 +7527,8 @@ > 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 : >@@ -7478,12 +7567,52 @@ > 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); >+#ifdef ENABLE_SEND_CHARSET >+ case V_SEND_CHARSET : >+ return(h_config_send_char_set); >+#endif >+ case V_ASSUMED_CHAR_SET : >+ return(h_config_assumed_charset); >+ case V_CHAR_SET_ALIASES : >+ return(h_config_charset_aliases); >+#ifdef HAVE_ICONV >+ case V_ICONV_ALIASES : >+ return(h_config_iconv_aliases); >+#endif > case V_EDITOR : > return(h_config_editor); > case V_SPELLER : >@@ -7514,6 +7643,8 @@ > 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 : >@@ -7524,6 +7655,8 @@ > 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 : >@@ -7606,6 +7739,8 @@ > 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: >@@ -7632,6 +7767,8 @@ > 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) >@@ -7663,6 +7800,9 @@ > 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); >@@ -8056,6 +8196,10 @@ > 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] || >@@ -9382,7 +9526,7 @@ > } > > set_current_val((*cl)->var, TRUE, TRUE); >- if(decode_sort(ps->VAR_SORT_KEY, &def_sort, &def_sort_rev) != -1){ >+ 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; > } >@@ -9391,6 +9535,37 @@ > 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."); >@@ -10915,7 +11090,9 @@ > 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)); >+ 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]) >@@ -11584,19 +11761,21 @@ > > > char * >-sort_pretty_value(ps, cl) >+sort_pretty_value(ps, cl, thread) > struct pine *ps; > CONF_S *cl; >+ int thread; > { >- return(generalized_sort_pretty_value(ps, cl, 1)); >+ return(generalized_sort_pretty_value(ps, cl, 1, thread)); > } > > > char * >-generalized_sort_pretty_value(ps, cl, default_ok) >+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; >@@ -11646,7 +11825,7 @@ > } > else if(fixed){ > pval = v->fixed_val.p; >- decode_sort(pval, &var_sort, &var_sort_rev); >+ 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", >@@ -11657,9 +11836,9 @@ > is_the_one ? " (value is fixed)" : ""); > } > else if(is_set_for_this_level){ >- decode_sort(pval, &var_sort, &var_sort_rev); >+ 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); >+ 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", >@@ -11677,7 +11856,7 @@ > } > else{ > if(pvalexc){ >- decode_sort(pvalexc, &exc_sort, &exc_sort_rev); >+ 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", >@@ -11688,7 +11867,7 @@ > } > else{ > pval = v->current_val.p; >- decode_sort(pval, &var_sort, &var_sort_rev); >+ 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); >@@ -11886,6 +12065,19 @@ > > 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... >@@ -11896,6 +12088,10 @@ > 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; >@@ -12000,14 +12196,6 @@ > > #endif > #if !defined(DOS) && !defined(OS2) >- case F_ALLOW_TALK : >- if(F_ON(f->id, ps)) >- allow_talk(ps); >- else >- disallow_talk(ps); >- >- break; >- > case F_PASS_CONTROL_CHARS : > ps->pass_ctrl_chars = F_ON(F_PASS_CONTROL_CHARS,ps_global) ? 1 : 0; > break; >@@ -12015,6 +12203,9 @@ > case F_PASS_C1_CONTROL_CHARS : > ps->pass_c1_ctrl_chars = F_ON(F_PASS_C1_CONTROL_CHARS,ps_global) > ? 1 : 0; >+ if(ps_global->VAR_CHAR_SET >+ && !strucmp(ps_global->VAR_CHAR_SET, "UTF-8")) >+ ps->pass_c1_ctrl_chars = 1; > break; > #endif > #ifdef MOUSE >@@ -12695,6 +12886,27 @@ > 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(); >@@ -12861,6 +13073,12 @@ > 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) >@@ -12902,6 +13120,11 @@ > 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)){ >@@ -12967,6 +13190,10 @@ > (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); >@@ -13013,9 +13240,15 @@ > else if(revert && var == &ps->vars[V_SORT_KEY]){ > int def_sort_rev; > >- decode_sort(VAR_SORT_KEY, &ps->def_sort, &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]){ >@@ -13772,12 +14005,16 @@ > > if(!(nonempty_patterns(rflags, &pstate) && > first_pattern(&pstate))){ >- q_status_message(SM_ORDER, 0, 3, >+ 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', >@@ -17995,7 +18232,7 @@ > > pval = PVAL(&sort_act_var, ew); > if(pval) >- decode_sort(pval, &def_sort, &def_sort_rev); >+ decode_sort(pval, &def_sort, &def_sort_rev, 0); > > /* allow user to set their default sort order */ > new_confline(&ctmp)->var = &sort_act_var; >@@ -18005,7 +18242,7 @@ > ctmp->tool = role_sort_tool; > ctmp->valoffset = 12; > ctmp->varmem = -1; >- ctmp->value = generalized_sort_pretty_value(ps, ctmp, 0); >+ 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++){ >@@ -18017,7 +18254,7 @@ > ctmp->valoffset = 12; > ctmp->varmem = i + (j * EndofList); > ctmp->value = generalized_sort_pretty_value(ps, ctmp, >- 0); >+ 0, 0); > } > } > >@@ -18922,7 +19159,7 @@ > (*result)->patgrp->stat_boy = PAT_STAT_EITHER; > > if(sort_act){ >- decode_sort(sort_act, &def_sort, &def_sort_rev); >+ 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); >@@ -21350,6 +21587,11 @@ > 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)); > >@@ -24152,6 +24394,7 @@ > 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); >@@ -24702,3 +24945,5 @@ > return(TRUE); > } > #endif /* _WINDOWS */ >+ >+#include "rules.c" >diff -ru pine4.64/pine/pine-use.c pine4.64.SuSE/pine/pine-use.c >--- pine4.64/pine/pine-use.c 1996-03-15 08:17:22.000000000 +0100 >+++ pine4.64.SuSE/pine/pine-use.c 2006-02-14 14:45:25.000000000 +0100 >@@ -45,7 +45,7 @@ > #include <sys/stat.h> > > #ifndef MAILSPOOLPCTS >-#define MAILSPOOLPCTS "/usr/spool/mail/%s" >+#define MAILSPOOLPCTS "/var/mail/%s" > /* #define MAILSPOOLPCTS "/usr/mail/%s" */ > #endif > >diff -ru pine4.64/pine/pine.c pine4.64.SuSE/pine/pine.c >--- pine4.64/pine/pine.c 2005-09-13 00:04:25.000000000 +0200 >+++ pine4.64.SuSE/pine/pine.c 2006-02-14 14:45:23.000000000 +0100 >@@ -87,6 +87,7 @@ > /* > * 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,6 +253,7 @@ > 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,6 +266,8 @@ > 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,7 +346,7 @@ > pine_args(pine_state, argc, argv, &args); > > #ifndef _WINDOWS >- if(!isatty(0)){ >+ if((!pine_state->send_immediately) && !isatty(0)){ > /* > * monkey with descriptors so our normal tty i/o routines don't > * choke... >@@ -366,12 +370,15 @@ > 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); >@@ -523,12 +530,20 @@ > 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)); > >@@ -734,6 +749,7 @@ > > > /*--- output side ---*/ >+ if (!ps_global->send_immediately){ > rv = config_screen(&(pine_state->ttyo)); > #if !defined(DOS) && !defined(OS2) /* always succeeds under DOS! */ > if(rv){ >@@ -758,6 +774,9 @@ > exit(-1); > } > #endif >+ } >+ else >+ fake_config_screen(&(pine_state->ttyo)); > > if(F_ON(F_BLANK_KEYMENU,ps_global)) > FOOTER_ROWS(ps_global) = 1; >@@ -804,7 +823,7 @@ > goodnight_gracey(pine_state, exit_val); > } > >- if(args.action == aaFolder >+ 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, >@@ -958,6 +977,12 @@ > 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; >@@ -993,7 +1018,7 @@ > memset(&fcc, 0, sizeof(fcc)); > > if(good_addr){ >- compose_mail(addr, fcc.tptr, NULL, >+ compose_mail(addr, fcc.tptr, role, > args.data.mail.attachlist, stdin_getc); > } > else{ >@@ -1026,6 +1051,7 @@ > > pine_state->mail_stream = NULL; > pine_state->mangled_screen = 1; >+ pine_state->subject = NULL; > > if(args.action == aaURL){ > url_tool_t f; >@@ -1115,6 +1141,7 @@ > "mail folder"); > } > >+ if (!pine_state->send_immediately) > fflush(stdout); > > #if !defined(DOS) && !defined(OS2) && !defined(LEAVEOUTFIFO) >@@ -3181,7 +3208,8 @@ > { > int quit = 0; > >- dprint(1, (debugfile, "\n\n ---- QUIT SCREEN ----\n")); >+ 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 >@@ -3226,6 +3254,7 @@ > 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(); >@@ -3328,6 +3357,7 @@ > 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(); >@@ -3365,6 +3395,8 @@ > 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) >@@ -3426,6 +3458,9 @@ > > 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); >@@ -3973,14 +4008,15 @@ > > 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))){ >- thrd = fetch_thread(stream, rawno); > if(thrd && thrd->top){ >- if(thrd->top == thrd->rawno) >+ if(top_thread(stream,thrd->top) == thrd->rawno) > topthrd = thrd; > else >- topthrd = fetch_thread(stream, thrd->top); >+ topthrd = fetch_thread(stream, top_thread(stream,thrd->top)); > } > > if(topthrd){ >@@ -4429,6 +4465,11 @@ > char **lock_these; > static unsigned long streamcounter = 0; > >+ if(ps_global->cancelproc){ >+ dprint(7, (debugfile, "pine_mail_open: cancelled by user\n")); >+ return retstream; >+ } >+ > dprint(7, (debugfile, > "pine_mail_open: opening \"%s\"%s openflags=0x%x %s%s%s%s%s%s%s%s%s (%s)\n", > mailbox ? mailbox : "(NULL)", >@@ -6337,6 +6378,91 @@ > 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 -ru pine4.64/pine/pine.h pine4.64.SuSE/pine/pine.h >--- pine4.64/pine/pine.h 2005-09-16 02:39:42.000000000 +0200 >+++ pine4.64.SuSE/pine/pine.h 2006-02-14 14:45:25.000000000 +0100 >@@ -68,6 +68,7 @@ > #define PHONE_HOME_HOST "docserver.cac.washington.edu" > > #define UNKNOWN_CHARSET "X-UNKNOWN" >+#define US_ASCII_CHARSET "US-ASCII" > > #define OUR_HDRS_LIST "X-Our-Headers" > >@@ -178,7 +179,6 @@ > #define GER_ALLPARTS 0x04 /* AllParts toggle is on */ > > #define GFHP_STRIPPED 0x01 >-#define GFHP_HANDLES 0x02 > #define GFHP_LOCAL_HANDLES 0x04 > > #define GFW_HANDLES 0x01 >@@ -232,6 +232,9 @@ > #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 >@@ -620,6 +623,7 @@ > , V_SMTP_SERVER > , V_NNTP_SERVER > , V_INBOX_PATH >+ , V_INCOMING_FOLDERS_CHECK > , V_ARCHIVED_FOLDERS > , V_PRUNED_FOLDERS > , V_DEFAULT_FCC >@@ -640,10 +644,12 @@ > , 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 >@@ -651,10 +657,32 @@ > , 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 >+#ifdef ENABLE_SEND_CHARSET >+ , V_SEND_CHARSET >+#endif >+ , V_ASSUMED_CHAR_SET >+ , V_CHAR_SET_ALIASES >+#ifdef HAVE_ICONV >+ , V_ICONV_ALIASES >+#endif > , V_EDITOR > , V_SPELLER > , V_FILLCOL >+ , V_SPECIAL_TEXT > , V_REPLY_STRING > , V_REPLY_INTRO > , V_QUOTE_REPLACE_STRING >@@ -687,6 +715,7 @@ > , V_NEWSRC_PATH > , V_NEWS_ACTIVE_PATH > , V_NEWS_SPOOL_DIR >+ , V_MAILDIR_LOCATION > , V_UPLOAD_CMD > , V_UPLOAD_CMD_PREFIX > , V_DOWNLOAD_CMD >@@ -724,6 +753,7 @@ > , V_TCPREADWARNTIMEO > , V_TCPWRITEWARNTIMEO > , V_TCPQUERYTIMEO >+ , V_INCFLDTIMEO > , V_RSHCMD > , V_RSHPATH > , V_RSHOPENTIMEO >@@ -785,6 +815,8 @@ > , 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 >@@ -841,6 +873,8 @@ > #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 >@@ -895,16 +929,66 @@ > #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 >+#ifdef ENABLE_SEND_CHARSET >+#define VAR_SEND_CHARSET vars[V_SEND_CHARSET].current_val.p >+#endif >+#define VAR_ASSUMED_CHAR_SET vars[V_ASSUMED_CHAR_SET].current_val.p >+#define VAR_CHAR_SET_ALIASES vars[V_CHAR_SET_ALIASES].current_val.l >+#ifdef HAVE_ICONV >+#define VAR_ICONV_ALIASES vars[V_ICONV_ALIASES].current_val.l >+#endif > #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 >@@ -989,6 +1073,8 @@ > #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 >@@ -1033,6 +1119,7 @@ > #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,6 +1132,8 @@ > #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,6 +1211,8 @@ > #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,6 +1242,7 @@ > 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,6 +1260,7 @@ > 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,6 +1277,8 @@ > 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,10 +1301,12 @@ > 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,10 +1411,12 @@ > 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, >@@ -1331,6 +1430,7 @@ > F_SORT_DEFAULT_FCC_ALPHA, > F_SORT_DEFAULT_SAVE_ALPHA, > F_QUOTE_REPLACE_NOFLOW, >+ F_QUELL_DISPLAYING_FLOWED_TEXT, > #ifdef _WINDOWS > F_ENABLE_TRAYICON, > F_QUELL_SSL_LARGEBLOCKS, >@@ -1547,6 +1647,13 @@ > #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 >@@ -1761,20 +1868,6 @@ > > > /* >- * Macros to aid hack to turn off talk permission. >- * Bit 020 is usually used to turn off talk permission, we turn off >- * 002 also for good measure, since some mesg commands seem to do that. >- */ >-#define TALK_BIT 020 /* mode bits */ >-#define GM_BIT 002 >-#define TMD_CLEAR 0 /* functions */ >-#define TMD_SET 1 >-#define TMD_RESET 2 >-#define allow_talk(p) tty_chmod((p), TALK_BIT, TMD_SET) >-#define disallow_talk(p) tty_chmod((p), TALK_BIT|GM_BIT, TMD_CLEAR) >- >- >-/* > * Macros to help set numeric pinerc variables. Defined here are the > * allowed min and max values as well as the name of the var as it > * should be displayed in error messages. >@@ -1830,6 +1923,10 @@ > #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,7 +2027,7 @@ > SortSubject2, SortScore, SortThread, EndofList} SortOrder; > > #define refresh_sort(S,M,F) sort_folder((S), (M), mn_get_sort(M), \ >- mn_get_revsort(M), (F)) >+ mn_get_revsort(M), (F), 1) > > /* > * The two structs below hold all knowledge regarding >@@ -1974,13 +2071,13 @@ > 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 toploose; /* top of this thread, if is loose */ > unsigned long head; /* head of the whole thread list */ > } PINETHRD_S; > >@@ -2571,10 +2668,22 @@ > 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 */ >+ time_t last_check_time; /* elapsed time in last check */ >+ int notified; /* notified the change? */ >+ int new_mail; /* folder has new mail */ >+ int last_check_length; /* elapsed time in last check */ >+ int skipped; /* skipped test? */ >+ int opstrm; /* open stream? */ >+ long interesting; /* result of last test */ >+ 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,12 +2709,15 @@ > iLstYear, iLstYear2Digit, > iMessNo, iAtt, iMsgID, iSubject, > iSubjKey, iSubjKeyInit, iKey, iKeyInit, >- iSize, iSizeComma, iSizeNarrow, iDescripSize, >+ 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,13 +2734,24 @@ > } 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 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,11 +3115,26 @@ > #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,7 +3232,9 @@ > #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))) >@@ -3538,6 +3678,7 @@ > } data; > } REPLY_S; > >+#define pico(F) call_pico(F) > #define REPLY_PSEUDO 1 > #define REPLY_FORW 2 /* very similar to REPLY_PSEUDO */ > #define REPLY_MSGNO 3 >@@ -3683,8 +3824,60 @@ > #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 >@@ -3832,6 +4025,7 @@ > PrivateAffector *affector; > } PrivateTop; > >+#define DF_THREAD_SORT_KEY "thread" > > typedef enum {OpenFolder, SaveMessage, FolderMaint, GetFcc, > Subscribe, PostNews} FolderFun; >@@ -3978,6 +4172,8 @@ > 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]; >@@ -4039,7 +4235,6 @@ > } ATABLE_S; > > >-#define TAG_EMBED '\377' /* Announces embedded data in text string */ > #define TAG_INVON '\001' /* Supported character attributes */ > #define TAG_INVOFF '\002' > #define TAG_BOLDON '\003' >@@ -4049,6 +4244,7 @@ > #define TAG_FGCOLOR '\010' /* Change to this foreground color */ > #define TAG_BGCOLOR '\011' /* Change to this background color */ > #define TAG_HANDLE '\020' /* indicate's a handle to an action */ >+#define TAG_EMBED '\021' /* Announces embedded data in text string */ > #define TAG_HANDLEOFF '\030' /* indicate's end of handle text */ > > >@@ -4217,7 +4413,9 @@ > RFC2369DATA_S data[MLCMD_MAXDATA]; > } RFC2369_S; > >- >+#define IF_REFRESH_NONE 0x00 >+#define IF_REFRESH_WEAK 0x01 >+#define IF_REFRESH_STRONG 0x10 > > /*---------------------------------------------------------------------- > This structure sort of takes the place of global variables or perhaps >@@ -4243,6 +4441,7 @@ > 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 */ >@@ -4250,10 +4449,25 @@ > 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 last_folder_checked; >+ int first_folder_checked; >+ int skip_ifcheck; >+ time_t login_time; >+ int delay; > ATTACH_S *atmts; > int atmts_allocated; > int remote_abook_validity; /* minutes, -1=never, 0=only on opens */ >@@ -4277,6 +4491,8 @@ > 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; >@@ -4287,6 +4503,7 @@ > 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; >@@ -4378,6 +4595,9 @@ > > 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 */ > >@@ -4414,6 +4634,9 @@ > 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; >@@ -4426,8 +4649,13 @@ > > int nmw_width; > >+ char *subject; >+ int send_immediately; >+ > int hours_to_timeout; > >+ int cancelproc; /* cancel this process now */ >+ > int tcp_query_timeout; > > time_t check_interval_for_noncurr; >@@ -4447,6 +4675,7 @@ > INIT_ERR_S *init_errs; > > PRINT_S *print; >+ PRULELIST_S *rule_list; > > struct variable *vars; > }; >@@ -4574,6 +4803,7 @@ > 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)); >@@ -4610,12 +4840,17 @@ > 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, >@@ -4637,6 +4872,7 @@ > #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)); >@@ -4669,7 +4905,7 @@ > 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 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)); >@@ -4700,6 +4936,7 @@ > 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)); >@@ -4742,10 +4979,11 @@ > 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, int)); > int menu_command PROTO((int, struct key_menu *)); > void menu_init_binding PROTO((struct key_menu *, int, int, > char *, char *, int)); >@@ -4788,6 +5026,7 @@ > 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 **, >@@ -4812,6 +5051,7 @@ > #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 *)); >@@ -4842,7 +5082,7 @@ > MSGNO_S *, IndexType, int *, int)); > char *sort_name PROTO((SortOrder)); > void sort_folder PROTO((MAILSTREAM *, MSGNO_S *, >- SortOrder, int, unsigned)); >+ SortOrder, int, unsigned, int)); > int percent_sorted PROTO((void)); > void msgno_init PROTO((MSGNO_S **, long)); > void msgno_give PROTO((MSGNO_S **)); >@@ -4866,7 +5106,7 @@ > void free_pine_elt PROTO((void **)); > SEARCHSET *build_searchset PROTO((MAILSTREAM *)); > void collapse_or_expand PROTO((struct pine *, MAILSTREAM *, MSGNO_S *, >- unsigned long)); >+ 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)); >@@ -4914,6 +5154,8 @@ > 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)); >@@ -4960,6 +5202,8 @@ > 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 *)); >@@ -5145,12 +5389,14 @@ > 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 *)); >@@ -5161,7 +5407,7 @@ > ENVELOPE *, ADDRESS **, ADDRESS **, > ADDRESS **, ADDRESS **,int *)); > int reply_news_test PROTO((ENVELOPE *, ENVELOPE *)); >-int reply_text_query PROTO((struct pine *, long, char **)); >+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 **)); >@@ -5208,6 +5454,46 @@ > 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)); >@@ -5333,6 +5619,7 @@ > 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 *)); >@@ -5452,6 +5739,9 @@ > int rfc2369_parse_fields PROTO((char *, RFC2369_S *)); > unsigned char *trans_euc_to_2022_jp PROTO((unsigned char *)); > unsigned char *trans_2022_jp_to_euc PROTO((unsigned char *, unsigned int *)); >+unsigned char* resolve_charset_alias PROTO((char *, char **)); >+char *pine_check_utf8 PROTO((char *, char *, size_t)); >+unsigned char *trans_with_iconv PROTO((unsigned char *, char *, char *)); > char *keyword_to_nick PROTO((char *)); > void find_8bitsubj_in_messages PROTO((MAILSTREAM *, SEARCHSET *, > int, int)); >@@ -5514,6 +5804,7 @@ > 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)); >Only in pine4.64.SuSE/pine: pine.h.orig >diff -ru pine4.64/pine/pine.hlp pine4.64.SuSE/pine/pine.hlp >--- pine4.64/pine/pine.hlp 2005-09-28 19:56:29.000000000 +0200 >+++ pine4.64.SuSE/pine/pine.hlp 2006-02-14 14:45:25.000000000 +0100 >@@ -492,6 +492,7 @@ > <P> > Some topics of current interest include: > <UL> >+<P><LI> Information on <A HREF="h_patches">patches for this release</A> > <P><LI> <A HREF="h_maildrop">Mail Drops</A> > <P><LI> Information on <A HREF="h_info_on_locking">Folder Locking</A> > <P><LI> Information on <A HREF="h_info_on_mbox">Missing mail and the mbox driver</A> >@@ -1116,6 +1117,66 @@ > <End of Configuration Notes> > </BODY> > </HTML> >+====== h_patches ====== >+<html> >+<head> >+<TITLE>Information on patches added to this release</TITLE> >+</head> >+<body> >+<H1>Information on patches added to this release</H1> >+<P> >+This version of Pine has been modified by including patches from >+<A HREF="http://www.math.washington.edu/~chappa/pine/"> >+http://www.math.washington.edu/~chappa/pine/</A>. These patches include >+new features and bug fixes. More complete information on each patch >+included in this version can be found in the web. >+ >+<P>If you have any problems with this release of Pine, please contact >+Eduardo Chappa <chappa@math.washington.edu>. Include the word >+"Pine" in the subject of the message to bypass spam filters. >+ >+<P>The list of patches included in this release are: >+ >+<P>New Features: >+ >+<UL> >+ <LI> Maildir Patch. <A HREF="h_config_maildir">(more...)</A> >+ <LI> Enhanced fancy thread interface. >+<A HREF="h_config_enhanced_thread">(more...)</A> >+ <LI> Pine justifies paragraphs with more than one level of indentation. >+<A HREF="h_compose_justify">(more...)</A> >+ <LI> Rules patch, to make Pine flexible. >+<A HREF="h_config_new_rules">(more...)</A> >+ <LI> Send mail from the command line. >+ <LI> Automatic check of new mail in incoming folders. >+<A HREF="h_config_enable_check_incoming">(more...)</A> >+ <LI> Write accents like áé or other foreing characters: ñ etc. >+ <LI> Tab check folders on cycles. >+<A HREF="h_config_circular_tab">(more...)</A> >+ <LI> Get the number of new messages when opening a folder. >+ <LI> Reinsert the pattern you searched for last. >+ <LI> New Reply command menu. >+<A HREF="h_config_alt_reply_menu">(more...)</A> >+ <LI> Change your From header without any effort! >+ <LI> Choose a role when composing a message from a mailto: link. >+ <LI> Paint special text in the body of the message in any custom color. >+<A HREF="h_config_special_text_to_color">(more...)</A> >+ <LI> Select messages by the content of an arbitrary header. >+ <LI> Delete until the the end of a file, or message (press ^W^X). >+ <LI> Get the QUOTA information from an IMAP server (if such server supports >+ the QUOTA command). >+ <LI> Cancel opening a connection when pressing ^C. >+</UL> >+ >+<P> Bug Fixes: >+<UL> >+ <LI> Fixed a bug that makes Pine crash if certain characters appear in >+the entries of a nickname in the addressbook. By Steve Hubert of the >+Pine team. >+</UL> >+ >+</body> >+</html> > ====== h_news_legal ====== > <html> > <head> >@@ -3128,7 +3189,9 @@ > <li><a href="h_config_alt_role_menu">FEATURE: Alternate-Role-Menu</a> > <li><a href="h_config_force_low_speed">FEATURE: Assume-Slow-Link</a> > <li><a href="h_config_auto_read_msgs">FEATURE: Auto-Move-Read-Msgs</a> >+<li><a href="h_config_auto_read_msgs_rules">FEATURE: auto-move-read-msgs-using-rules</a> > <li><a href="h_config_auto_open_unread">FEATURE: Auto-Open-Next-Unread</a> >+<li><a href="h_config_circular_tab">FEATURE: enable-circular-tab</a> > <li><a href="h_config_auto_unzoom">FEATURE: Auto-Unzoom-After-Apply</a> > <li><a href="h_config_auto_zoom">FEATURE: Auto-Zoom-After-Select</a> > <li><a href="h_config_check_mail_onquit">FEATURE: Check-Newmail-When-Quitting</a> >@@ -3260,6 +3323,7 @@ > <li><a href="h_config_quell_charset_warning">FEATURE: Quell-Charset-Warning</a> > <li><a href="h_config_quell_content_id">FEATURE: Quell-Content-ID</a> > <li><a href="h_config_quell_dead_letter">FEATURE: Quell-Dead-Letter-On-Cancel</a> >+<li><a href="h_config_quell_displaying_flowed_text">FEATURE: Quell-Displaying-Flowed-Text</a> > <li><a href="h_config_quell_empty_dirs">FEATURE: Quell-Empty-Directories</a> > <li><a href="h_config_quell_post_prompt">FEATURE: Quell-Extra-Post-Prompt</a> > <li><a href="h_config_quell_filtering_done_message">FEATURE: Quell-Filtering-Done-Message</a> >@@ -3387,6 +3451,7 @@ > <li><a href="h_config_abook_formats">OPTION: Addressbook-Formats</a> > <li><a href="h_config_alt_addresses">OPTION: Alt-Addresses</a> > <li><a href="h_config_char_set">OPTION: Character-Set</a> >+<li><a href="h_config_special_text_to_color">OPTION: Special Text to Color</a> > <li><a href="h_config_color_style">OPTION: Color-Style</a> > <li><a href="h_config_composer_wrap_column">OPTION: Composer-Wrap-Column</a> > <li><a href="h_config_index_color_style">OPTION: Current-Indexline-Style</a> >@@ -3487,9 +3552,11 @@ > <li><a href="h_config_sending_filter">OPTION: Sending-Filters</a> > <li><a href="h_config_sendmail_path">OPTION: Sendmail-Path</a> > <li><a href="h_config_signature_color">OPTION: Signature Color</a> >+<li><a href="h_config_special_text_color">OPTION: Special Text Color</a> > <li><a href="h_config_signature_file">OPTION: Signature-File</a> > <li><a href="h_config_smtp_server">OPTION: SMTP-Server</a> > <li><a href="h_config_sort_key">OPTION: Sort-Key</a> >+<li><a href="h_config_thread_sort_key">OPTION: Thread-Sort-Key</a> > <li><a href="h_config_speller">OPTION: Speller</a> > <li><a href="h_config_sshcmd">OPTION: Ssh-Command</a> > <li><a href="h_config_ssh_open_timeo">OPTION: Ssh-Open-Timeout</a> >@@ -5337,6 +5404,159 @@ > <End of help on this topic> > </BODY> > </HTML> >+======= h_thread_index_sort_arrival ======= >+<HTML> >+<HEAD> >+<TITLE>SORT OPTION: Arrival</TITLE> >+</HEAD> >+<BODY> >+<H1>SORT OPTION: Arrival</H1> >+ >+The <EM>Arrival</EM> sort option arranges threads according to the last >+time that a message was added to it. In this order the last thread >+contains the most recent message in the folder. >+ >+<P> >+<End of help on this topic> >+</BODY> >+</HTML> >+======= h_thread_index_sort_date ======= >+<HTML> >+<HEAD> >+<TITLE>SORT OPTION: Date</TITLE> >+</HEAD> >+<BODY> >+<H1>SORT OPTION: Date</H1> >+ >+The <EM>Date</EM> sort option in the THREAD INDEX screen is the same >+as sorting by thread, the most likely thing is that you won't see Pine >+sorting the folder, because it's already sorted. >+ >+<P> >+On a folder like INBOX, sorting by "Date" should be almost >+identical to sorting by "Arrival". >+ >+<P> >+<End of help on this topic> >+</BODY> >+</HTML> >+======= h_thread_index_sort_subj ======= >+<HTML> >+<HEAD> >+<TITLE>SORT OPTION: Subject</TITLE> >+</HEAD> >+<BODY> >+<H1>SORT OPTION: Subject</H1> >+ >+The <EM>Subject</EM> sort option has not been defined yet. >+ >+<P> >+<End of help on this topic> >+</BODY> >+</HTML> >+======= h_thread_index_sort_ordsubj ======= >+<HTML> >+<HEAD> >+<TITLE>SORT OPTION: OrderedSubject</TITLE> >+</HEAD> >+<BODY> >+<H1>SORT OPTION: OrderedSubject</H1> >+ >+The <EM>OrderedSubject</EM> sort option in the THREAD INDEX screen is >+the same as sorting by <A HREF="h_thread_index_sort_subj">Subject</A>. >+ >+<P> >+<End of help on this topic> >+</BODY> >+</HTML> >+======= h_thread_index_sort_thread ======= >+<HTML> >+<HEAD> >+<TITLE>SORT OPTION: Thread</TITLE> >+</HEAD> >+<BODY> >+<H1>SORT OPTION: Thread</H1> >+ >+The <EM>Thread</EM> sort option in the THREAD INDEX screen sorts all >+messages by the proposed algorithm by Crispin and Murchison. In this >+method of sorting once threads have been isolated they are sorted by the >+date of their parents, or if that is missing, the first message in that >+thread. >+ >+<P> >+<End of help on this topic> >+</BODY> >+</HTML> >+======= h_thread_index_sort_from ======= >+<HTML> >+<HEAD> >+<TITLE>SORT OPTION: From</TITLE> >+</HEAD> >+<BODY> >+<H1>SORT OPTION: From</H1> >+ >+The <EM>From</EM> sort option has not been defined yet. >+ >+<P> >+<End of help on this topic> >+</BODY> >+</HTML> >+======= h_thread_index_sort_size ======= >+<HTML> >+<HEAD> >+<TITLE>SORT OPTION: Size</TITLE> >+</HEAD> >+<BODY> >+<H1>SORT OPTION: Size</H1> >+ >+The <EM>Size</EM> sort option has not been defined yet. >+ >+<P> >+<End of help on this topic> >+</BODY> >+</HTML> >+======= h_thread_index_sort_score ======= >+<HTML> >+<HEAD> >+<TITLE>SORT OPTION: Score</TITLE> >+</HEAD> >+<BODY> >+<H1>SORT OPTION: Score</H1> >+ >+The <EM>Score</EM> sort option has not been defined yet. >+ >+<P> >+<End of help on this topic> >+</BODY> >+</HTML> >+======= h_thread_index_sort_to ======= >+<HTML> >+<HEAD> >+<TITLE>SORT OPTION: To</TITLE> >+</HEAD> >+<BODY> >+<H1>SORT OPTION: To</H1> >+ >+The <EM>To</EM> sort option has not been defined yet. >+ >+<P> >+<End of help on this topic> >+</BODY> >+</HTML> >+======= h_thread_index_sort_cc ======= >+<HTML> >+<HEAD> >+<TITLE>SORT OPTION: Cc</TITLE> >+</HEAD> >+<BODY> >+<H1>SORT OPTION: Cc</H1> >+ >+The <EM>Cc</EM> sort option has not been defined yet. >+ >+<P> >+<End of help on this topic> >+</BODY> >+</HTML> > ======= h_index_cmd_whereis ======= > <HTML> > <HEAD> >@@ -6555,6 +6775,46 @@ > not preserved. > > <P> >+This version of Pine contains an enhanced algorithm for justification, >+which allows you to justify text that contains more complicated quote >+strings. This algorithm is based on pragmatics, rather than on a theory, >+and seems to work well with most messages. Below you will find technical >+information on how this algorithm works. >+ >+<P> >+When justifying, Pine goes through each line of the text and tries to >+determine for each line what the quote string of that line is. The quote >+string you provided is always recognized. Among other characters >+recognized is ">". >+ >+<P> >+Some other constructions of quote strings are recognized only if they >+appear enough in the text. For example "Peter :" is only >+recognized if it appears in two consecutive lines. >+ >+<P> >+Additionaly, Pine recognizes indent-strings and justifies text in a >+paragraph to the right of indent-string, padding with spaces if necessary. >+An indent string is one which you use to delimit elements of a list. For >+example, if you were to write a list of groceries, one may write: >+ >+<UL> >+<LI> Fruit >+<LI> Bread >+<LI> Eggs >+</UL> >+ >+<P> >+In this case the character "*" is the indent-string. Pine >+recognizes numbers (0, 1, 2.5, etc) also as indent-strings, and certain >+combinations of spaces, periods, and parenthesis. In any case, numbers are >+recognized <B>ONLY</B> if the line preceeding the given line is empty or >+ends in one of the characters "." or ":". >+In addition to the explanation of what constitutes a paragraph above, a >+new paragraph is recognized when an indent-string is found in it (and >+validated according to the above stated rules). >+ >+<P> > <End of help on this topic> > </BODY> > </HTML> >@@ -17396,6 +17656,7 @@ > <A HREF="h_config_index_format">"Index-Format"</A> option, > in the <A HREF="h_config_reply_intro">"Reply-Leadin"</A> option, > in signature files, >+in the <A HREF="h_config_reply_leadin_rules">"new-rules" option</A>, > in template files used in > <A HREF="h_rules_roles">"roles"</A>, and in the folder name > that is the target of a Filter Rule. >@@ -17408,7 +17669,7 @@ > <P> > <P> > >-<H1><EM>Tokens Available for all Cases (except Filter Rules)</EM></H1> >+<H1><EM>Tokens Available for all Cases (except Filter Rules or in some cases for new-rules)</EM></H1> > > <DL> > <DT>SUBJECT</DT> >@@ -17430,6 +17691,15 @@ > For example, "mailbox@domain". > </DD> > >+<DT>ADDRESSTO</DT> >+<DD> >+This is similar to the "TO" token, only it is always the >+email address of all people listed in the TO: field of the messages. Addresses >+are separated by a blank space. Example, "mailbox@domain" when >+the e-mail message contains only one person in the To: field, or >+"peter@flintstones.com president@world.com". >+</DD> >+ > <DT>MAILBOX</DT> > <DD> > This is the same as the "ADDRESS" except that the >@@ -17477,6 +17747,15 @@ > message's "Cc:" header field. > </DD> > >+<DT>ADDRESSCC</DT> >+<DD> >+This is similar to the "CC" token, only it is always the >+email address of all people listed in the Cc: field of the messages. Addresses >+are separated by a blank space. Example: "mailbox@domain" when >+the e-mail message contains only one person in the Cc: field, or >+"peter@flintstones.com president@world.com". >+</DD> >+ > <DT>RECIPS</DT> > <DD> > This token represents the personal names (or email addresses if the names >@@ -17485,6 +17764,14 @@ > the message's "Cc:" header field. > </DD> > >+<DT>ADDRESSRECIPS</DT> >+<DD> >+This token represent the e-mail addresses of the people in the To: and >+Cc: fields, exactly in that order separated by a space. It is almost obtained >+by concatenating the ADDRESSTO and ADDRESSCC tokens. >+</DD> >+ >+ > <DT>NEWSANDRECIPS</DT> > <DD> > This token represents the newsgroups from the >@@ -17857,6 +18144,14 @@ > <P> > </DD> > >+<DT>SIZETHREAD</DT> >+<DD> >+This token represents the total size of the thread for a collapsed thread >+or the size of the branch for an expanded thread. The field is omitted for >+messages that are not top of threads nor branches and it defaults to >+the SIZE token when your folders is not sorted by thread. >+</DD> >+ > <DT>SIZENARROW</DT> > <DD> > This token represents the total size, in bytes, of the message. >@@ -18212,6 +18507,78 @@ > </DL> > > <P> >+<H1><EM>Tokens Available Only for New-Rules</EM></H1> >+ >+<DL> >+<DT>FOLDER</DT> >+<DD> >+Name of the folder where the rule will be applied >+</DD> >+</DL> >+ >+<DL> >+<DT>COLLECTION</DT> >+<DD> >+Name of the collection list where the rule will be applied. >+</DD> >+</DL> >+ >+<DL> >+<DT>ROLE</DT> >+<DD> >+Name of the Role used to reply a message. >+</DD> >+</DL> >+ >+<DL> >+<DT>BCC</DT> >+<DD> >+Not implemented yet, but it will be implemented in future versions. It will >+be used for <A HREF="h_config_compose_rules">compose</A> >+<A HREF="h_config_reply_rules">reply</A> >+<A HREF="h_config_forward_rules">forward</A> >+rules. >+</DD> >+</DL> >+ >+<DL> >+<DT>LCC</DT> >+<DD> >+This is the value of the Lcc: field at the moment that you start the composition. >+</DD> >+</DL> >+ >+<DL> >+<DT>FORWARDFROM</DT> >+<DD> >+This corresponds to the personal name (or address if there's no personal >+name) of the person who sent the message that you are forwarding. >+</DD> >+</DL> >+ >+<DL> >+<DT>FORWARDADDRESS</DT> >+<DD> >+This is the address of the person that sent the message that you >+are forwarding. >+</DD> >+</DL> >+ >+ >+ >+ >+<DL> >+<DT>FLAG</DT> >+<DD> >+A string containing the value of all the flags associated to a specific >+message. The possible values of allowed flags are "*" for Important, "N" >+for recent or new, "U" for unseen or unread, "R" for seen or read, "A" for >+answered and "D" for deleted. See an example of its use in the >+<A HREF="h_config_new_rules">new rules</A> explanation and example help. >+</DD> >+</DL> >+ >+<P> > <H1><EM>Token Available Only for Templates and Signatures</EM></H1> > > <DL> >@@ -18964,6 +19331,23 @@ > be combined with the other fields if you'd like. > > <End of help on this topic> >+====== h_config_check_inc_fld ====== >+<HTML> >+<HEAD> >+<TITLE>OPTION: incoming-folders-to-check</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: incoming-folders-to-check</H1> >+<P> >+if you set this option and <A HREF="h_config_enable_check_incoming"> >+enable-check-incoming-folders</A> then you can use this option to write a space >+separate list of incoming folders where you want new mail to be >+checked. If you want all your incoming folders to be checked just write a >+"*" as the value for this option. >+<P> >+<End of help on this topic> >+</BODY> >+</HTML> > ======= h_address_format ======= > <HTML> > <HEAD> >@@ -20086,61 +20470,157 @@ > <End of help on this topic> > </BODY> > </HTML> >-====== h_config_literal_sig ===== >+====== h_config_maildir_location ====== > <HTML> > <HEAD> >-<TITLE>OPTION: Literal-Signature</TITLE> >+<TITLE>OPTION: maildir-location</TITLE> > </HEAD> > <BODY> >-<H1>OPTION: Literal-Signature</H1> >+<H1>OPTION: maildir-location</H1> > >-With this option your actual signature, as opposed to >-the name of a file containing your signature, >-is stored in the Pine configuration file. >-If this is defined it takes precedence over the Signature-File option. > <P> >+This 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 is simply a different way to store the signature. >-The signature is stored inside your Pine configuration file instead of in >-a separate file. >-Tokens work the same way they do with the >-<A HREF="h_config_signature_file">Signature-File</A> so look there for >-help. > <P> >+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 Setup/Signature command on Pine's Main Menu will edit >-the "Literal-Signature" by default. However, if no >-"Literal-Signature" is defined and the file named in the >-"Signature-File" option exists, then the latter will be used >-instead. > <P> >- >-The two character sequence \n (backslash followed by >-the character n) will be used to signify a line-break in your signature. >-You don't have to enter the \n, but it will be visible in the >-SETUP CONFIGURATION window after you are done editing the signature. >+The value of this option is prefixed with the "~/" string to determine the >+full path to your INBOX. > > <P> >-<UL> >+You should probably <A HREF="h_config_maildir">read</A> a few tips that >+teach you how to configure your maildir for optimal performance. This >+version also has <A HREF="h_config_courier_list">support</A> for the >+Courier style file system when a maildir collection is accessed locally. >+ >+<P><UL> > <LI><A HREF="h_finding_help">Finding more information and requesting help</A> >-</UL><P> >+</UL> >+<P> > <End of help on this topic> > </BODY> > </HTML> >-====== h_config_signature_file ===== >+====== h_config_maildir ===== > <HTML> > <HEAD> >-<TITLE>OPTION: Signature-File</TITLE> >+<TITLE>Maildir Support</TITLE> > </HEAD> > <BODY> >-<H1>OPTION: Signature-File</H1> >+<H1>Maildir Support</H1> > >-If a <A HREF="h_config_literal_sig">Literal-Signature</A> option is defined, >-then this "Signature-File" option will be ignored. >-You can tell that that is the case because the value of the >-"Signature-File" will show up as >-<P> >-<CENTER><SAMP><Ignored: using Literal-Signature instead></SAMP></CENTER> >+This version of Pine has been enhanced with Maildir support. This text is >+intended to be a reference on its support. >+<P> >+ >+A Maildir folder is a directory that contains three directories called >+cur, tmp and new. A program that delivers mail (e.g. postfix) will put new >+mail in the new directory. A program that reads mail will look for for old >+messages in the cur directory, while it will look for new mail in the new >+directory. >+<P> >+ >+In order to use maildir support it is better to set your inbox-path to the >+value "#md/inbox" (without quotes). This assumes that your mail >+delivery agent is delivering new mail to ~/Maildir/new. If the directory >+where new mail is being delivered is not called "Maildir", you can set the >+name of the subdirectory of home where it is being delivered in the <A >+HREF="h_config_maildir_location">maildir-location</A> configuration >+variable. Most of the time you will not have to worry about the >+maildir-location variable, because it will probably be set by your >+administrator in the pine.conf configuration file. >+<P> >+ >+One of the advantages of the Maildir support of this version of Pine is >+that you do not have to stop using folders in another styles (mbox, mbx, >+etc.). This is desirable since the usage of a specific mail storage system >+is a personal decision. Folders in the maildir format that are part of the >+Mail collection will be recognized without any extra configuration of your >+part. If your mail/ collection is located under the mail/ directory, then >+creating a new maildir folder in this collection is done by pressing "A" >+and entering the string "#driver.md/mail/newfolder". Observe that adding a >+new folder as "newfolder" may not create such folder in maildir format. >+ >+<P> >+If you would like to have all folders created in the maildir format by >+default, you do so by adding a Maildir Collection. In order to convert >+your current mail/ collection into a maildir collection, edit the >+collection and change the path variable from "mail/" to >+"#md/mail". In a maildir collection folders of any other format >+are ignored. >+ >+<P> Finally, This version also has >+<A HREF="h_config_courier_list">support</A> for the Courier style file system >+when a maildir collection is accessed locally. >+ >+<P> >+<UL> >+<LI><A HREF="h_finding_help">Finding more information and requesting help</A> >+</UL><P> >+<End of help on this topic> >+</BODY> >+</HTML> >+====== h_config_literal_sig ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Literal-Signature</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Literal-Signature</H1> >+ >+With this option your actual signature, as opposed to >+the name of a file containing your signature, >+is stored in the Pine configuration file. >+If this is defined it takes precedence over the Signature-File option. >+<P> >+ >+This is simply a different way to store the signature. >+The signature is stored inside your Pine configuration file instead of in >+a separate file. >+Tokens work the same way they do with the >+<A HREF="h_config_signature_file">Signature-File</A> so look there for >+help. >+<P> >+ >+The Setup/Signature command on Pine's Main Menu will edit >+the "Literal-Signature" by default. However, if no >+"Literal-Signature" is defined and the file named in the >+"Signature-File" option exists, then the latter will be used >+instead. >+<P> >+ >+The two character sequence \n (backslash followed by >+the character n) will be used to signify a line-break in your signature. >+You don't have to enter the \n, but it will be visible in the >+SETUP CONFIGURATION window after you are done editing the signature. >+ >+<P> >+<UL> >+<LI><A HREF="h_finding_help">Finding more information and requesting help</A> >+</UL><P> >+<End of help on this topic> >+</BODY> >+</HTML> >+====== h_config_signature_file ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Signature-File</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Signature-File</H1> >+ >+If a <A HREF="h_config_literal_sig">Literal-Signature</A> option is defined, >+then this "Signature-File" option will be ignored. >+You can tell that that is the case because the value of the >+"Signature-File" will show up as >+<P> >+<CENTER><SAMP><Ignored: using Literal-Signature instead></SAMP></CENTER> > <P> > You may either use all Literal Signatures (signatures stored in your > configuration file) throughout Pine, or all signature files. >@@ -20853,6 +21333,41 @@ > <End of help on this topic> > </BODY> > </HTML> >+====== h_config_thread_sort_key ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Thread-Sort-Key</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Thread-Sort-Key</H1> >+ >+This option determines the order in which threads will be displayed. You >+can choose from the following options. >+ >+<P> >+<UL> >+ <LI> <A HREF="h_thread_index_sort_arrival">Arrival</A> >+<!-- <LI> <A HREF="h_thread_index_sort_date">Date</A> >+ <LI> <A HREF="h_thread_index_sort_subj">Subject</A> >+ <LI> <A HREF="h_thread_index_sort_ordsubj">OrderedSubj</A>--> >+ <LI> <A HREF="h_thread_index_sort_thread">Thread</A> >+<!-- <LI> <A HREF="h_thread_index_sort_from">From</A> >+ <LI> <A HREF="h_thread_index_sort_size">Size</A> >+ <LI> <A HREF="h_thread_index_sort_score">Score</A> >+ <LI> <A HREF="h_thread_index_sort_to">To</A> >+ <LI> <A HREF="h_thread_index_sort_cc">Cc</A>--> >+</UL> >+ >+<P> Each type of sort may also be reversed. Normal default is by >+"Thread". >+ >+<P> >+<UL> >+<LI><A HREF="h_finding_help">Finding more information and requesting help</A> >+</UL><P> >+<End of help on this topic> >+</BODY> >+</HTML> > ====== h_config_other_startup ===== > <HTML> > <HEAD> >@@ -21001,6 +21516,650 @@ > <End of help on this topic> > </BODY> > </HTML> >+====== h_config_compose_rules ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Compose-Rule</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Compose-Rule</H1> >+ >+<P> At this time, this option is used to generate values for signature >+files that is not possible to do with the use of >+<A HREF="h_rules_roles">roles</A>. >+ >+<P> For example, you can have a rule like:<BR> >+_TO_ >> {Peter Flinstones} => _SIGNATURE_{~/.petersignature} >+ >+<P> This configuration option is just one of many that allow you to >+override the value of some global configurations within Pine. There is a >+help text explaining how to define all of them, which you can read by >+following this <A HREF="h_config_new_rules">link</A>. >+ >+<P><End of help on this topic> >+</BODY> >+</HTML> >+====== h_config_forward_rules ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Forward-Rule</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Forward-Rule</H1> >+ >+<P> At this time this option can be used to trim values of some fields, >+for example it can be used in the following way: >+ >+<P> >+_ROLE_ == {work} => _LCC_ := _TRIM_{_FORWARDFROM_ <_FORWARDADDRESS_>} >+ >+<P> This configuration option is just one of many that allow you to >+override the value of some global configurations within Pine. There is a >+help text explaining how to define all of them, which you can read by >+following this <A HREF="h_config_new_rules">link</A>. >+ >+<P><End of help on this topic> >+</BODY> >+</HTML> >+====== h_config_index_rules ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Index-Rule</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Index-Rule</H1> >+ >+<P> This option is used to supercede the value of the option <A >+HREF="h_config_index_format">index-format</A> for specific folders. In >+this form you can have different index-formats for different folders. For >+example an entry here may be: >+ >+<P> >+_FOLDER_ == {INBOX} => _INDEX_{IMAPSTATUS DATE FROM(33%) SIZE SUBJECT(67%)} >+ >+<P> This configuration option is just one of many that allow you to >+override the value of some global configurations within Pine. There is a >+help text explaining how to define all of them, which you can read by >+following this <A HREF="h_config_new_rules">link</A>. >+ >+<P><End of help on this topic> >+</BODY> >+</HTML> >+====== h_config_replace_rules ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Replace-Rule</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Replace-Rule</H1> >+ >+<P> This option is used to have Pine print different values for specific >+tokens in the <A HREF="h_config_index_format">index-format</A>. For example you >+can replace strings like "To: newsgroup" by your name. >+ >+<P> Here are examples of possible rules:<BR> >+_FOLDER_ != {sent-mail} && _NICK_ != {} => _FROM_ := _REPLACE_{_FROM_ (_NICK_)} >+ >+<P> or if you receive messages with tags that contain arbitrary numbers, and >+you want them removed from the index (but not from the subject), use a rule >+like the following<BR> >+_FOLDER_ == {INBOX} => _SUBJECT_ := _REXTRIM_{\[some-tag-here #[0-9].*\]} >+ >+<P> You can also use this configuration option to remove specific strings of >+the index display screen, so that you can trim unnecessary information in >+your index. >+ >+<P> This configuration option is just one of many that allow you to >+override the value of some global configurations within Pine. There is a >+help text explaining how to define all of them, which you can read by >+following this <A HREF="h_config_new_rules">link</A>. >+ >+<P><End of help on this topic> >+</BODY> >+</HTML> >+====== h_config_reply_leadin_rules ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Reply-Leadin-Rule</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Reply-Leadin-Rule</H1> >+ >+<P> This option is used to have Pine generate a different >+<A HREF="h_config_reply_intro">reply-leadin</A> string dependent either on >+the person you are replying to, or the folder where the message is being >+replied is in, or both. >+ >+<P> Here there are examples of how this can be used. One can use the definition >+below to post to newsgroups and the pine-info mailing list, say: >+<P> >+_FOLDER_ << {pine-info;_NEWS_} => _REPLY_{*** _FROM_ _ADDRESS_("_FROM_" "" "(_ADDRESS_) ")wrote in_NEWS_("" " the" "") _FOLDER_ _NEWS_("" "list " "")_SMARTDATE_("Today" "today" "on _LONGDATE_"):} >+ >+<P> Here there is an example that one can use to change the reply indent string >+to reply people that speak spanish. >+<P> >+_FROM_{Condorito;Quico} => _REPLY_{*** _FROM_ (_ADDRESS_) escribió _SMARTDATE_("Today" "hoy" "en _LONGDATE_"):} >+ >+<P> This configuration option is just one of many that allow you to >+override the value of some global configurations within Pine. There is a >+help text explaining how to define all of them, which you can read by >+following this <A HREF="h_config_new_rules">link</A>. >+ >+<P><End of help on this topic> >+</BODY> >+</HTML> >+====== h_config_resub_rules ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Replace-Subject-Rule</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Replace-Subject-Rule</H1> >+ >+<P> This option is used to have Pine generate a different subject when >+replying rather than the one Pine would generate automatically. >+ >+<P> Here there are a couple of examples about how to use this >+configuration option: >+ >+<P> In order to have messages with empty subject to be replied with the message >+"your message" use the rule<BR> >+<center>_SUBJECT_ == {} => _RESUB_{Re: your message}</center> >+ >+<P> If you want to trim some parts of the subject when you reply use the >+rule<BR> >+<center>_SUBJECT_ >> {[one];two} => _SUBJECT_ := _TRIM_{[;];two}</center> >+ >+<P>this rule removes the brackets "[" and "]" whenever the string "[one]" >+appears in it, it also removes the word "two" from it. >+ >+<P>Another example where you may want to use this rule is when you >+correspond with people that change the reply string from "Re:" >+to "AW:" or "Sv:". In this case a rule like<BR> >+<center>_SUBJECT_ >> {Sv: ;AW: } => _SUBJECT_ := _TRIM_{Sv: ;AW: }</center> >+<P> >+would eliminate undesired strings in replies. >+ >+<P> You can also use this configuration option to customize reply subjects >+according to the sender of the message. >+ >+<P> This configuration option is just one of many that allow you to >+override the value of some global configurations within Pine. There is a >+help text explaining how to define all of them, which you can read by >+following this <A HREF="h_config_new_rules">link</A>. >+ >+<P><End of help on this topic> >+</BODY> >+</HTML> >+====== h_config_sort_rules ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Sort-Rule</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Sort-Rule</H1> >+ >+<P> This option is used to have Pine sort different folders in different orders >+and thus override the value already set in the >+<A HREF="h_config_sort_key">sort-key</A> configuration option. >+ >+<P> Here's an example of the way it can be used. In this case all incoming >+folders are mailing lists, except for INBOX, so we sort INBOX by arrival >+(which is the default type of sort), but we want all the rest of mailing >+lists and newsgroups to be sorted by thread. >+ >+<P> >+_COLLECTION_ >> {Incoming-Folders;News} && _FOLDER_ != {INBOX} => _SORT_{tHread} >+ >+<P> Another example could be<BR> >+_FOLDER_ == {Mailing List} => _SORT_{Reverse tHread} >+ >+<P> This configuration option is just one of many that allow you to >+override the value of some global configurations within Pine. There is a >+help text explaining how to define all of them, which you can read by >+following this <A HREF="h_config_new_rules">link</A>. >+ >+<P><End of help on this topic> >+ >+</BODY> >+</HTML> >+====== h_config_save_rules ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Save-Rules</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Save-Rules</H1> >+ >+<P> This option is used to specify which folder should be used to save a >+message depending either on the folder the message is in, who the message >+is from, or text that the message contains in specific headers (Cc:, >+Subject:, etc). >+ >+<P> If this option is set and the >+<A HREF="h_config_auto_read_msgs">auto-move-read-msgs</A> configuration >+option is also set then these definitions will be used to move messages >+from your INBOX when exiting Pine. >+ >+<P>Here there are some examples<BR> >+_FLAG_ >> {D} -> Trash<BR> >+_FROM_ == {U2} -> Bono<BR> >+_FOLDER_ == {comp.mail.pine} -> pine-stuff<BR> >+_NICK_ != {} -> _NICK_/_NICK_<BR> >+_DATEISO_ >> {02-10;02-11} -> archive-oct-nov-2002 >+ >+<P> This configuration option is just one of many that allow you to >+override the value of some global configurations within Pine. There is a >+help text explaining how to define all of them, which you can read by >+following this <A HREF="h_config_new_rules">link</A>. >+ >+<P><End of help on this topic> >+ >+</BODY> >+</HTML> >+====== h_config_reply_indent_rules ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Reply-indent-Rule</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Reply-indent-Rule</H1> >+ >+<P> This option is used to specify which reply-indent-string is to be used >+when replying to an e-mail. If none of the rules are successful, the result in >+the variable <a href="h_config_reply_indent_string">reply-indent-string</a> >+is used. >+ >+<P> The associated function to this configuration option is called "RESTR" (for >+REply STRing). Some examples of its use are:<BR> >+_FROM_ == {Your Boss} => _RESTR_{"> "}<BR> >+_FROM_ == {My Wife} => _RESTR_{":* "}<BR> >+_FROM_ == {Perter Flinstone;Wilma Flinstone} => _RESTR_{"_INIT_ > "}<BR> >+ >+<P> This configuration option is just one of many that allow you to >+override the value of some global configurations within Pine. There is a >+help text explaining how to define all of them, which you can read by >+following this <A HREF="h_config_new_rules">link</A>. >+ >+<P><End of help on this topic> >+ >+</BODY> >+</HTML> >+====== h_config_smtp_rules ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: SMTP-Rule</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: SMTP-Rule</H1> >+ >+<P> This option is used to specify which SMTP server should be used when >+sending a message, if this rule is not defined, or the execution of the rule >+results in no server selected, then Pine will look for >+the value from the role that is being used to compose the message. If no smtp >+server is defined in that role or you are not using a role, then Pine will get >+the name of the server from the >+<A HREF="h_config_smtp_server">"smtp-server"</A> configuration >+option according to the rules used in that variable. >+ >+<P> The function associated to this configuration option is _SMTP_, an example >+of the use of this function is<BR> >+_ADDRESSTO_ == {peter@bedrock.com} => _SMTP_{smtp.bedrock.com} >+ >+<P> This configuration option is just one of many that allow you to >+override the value of some global configurations within Pine. There is a >+help text explaining how to define all of them, which you can read by >+following this <A HREF="h_config_new_rules">link</A>. >+ >+<P><End of help on this topic> >+ >+</BODY> >+</HTML> >+====== h_config_startup_rules ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Startup-Rule</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Startup-Rule</H1> >+ >+<P> This option is used when a folder is being opened. You can use it to >+specify its <A HREF="h_config_inc_startup">incoming-startup-rule</A> and override >+Pine's global value set for all folders. >+ >+<P> An example of the usage of this option is:<BR> >+_FOLDER_ == {Lynx;pine-info;_NEWS_} => _STARTUP_{first-unseen} >+ >+<P> This configuration option is just one of many that allow you to >+override the value of some global configurations within Pine. There is a >+help text explaining how to define all of them, which you can read by >+following this <A HREF="h_config_new_rules">link</A>. >+ >+<P><End of help on this topic> >+ >+</BODY> >+</HTML> >+====== h_config_new_rules ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: New Rules Explained</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: New Rules Explained</H1> >+ >+This is a quite powerful option. Here you can define rules that override >+the values of any other global rule you have globally set in pine. >+ >+<P> >+ For example, you can set your folders to be sorted in a certain way when >+you open them (say by Arrival). You may not want to be this the behavior >+of, say, a Newsgroup, maybe you would like there to have your folder to be >+automatically ordered by Ordered Subject. The purpose of this feature is >+to accomplish exactly that. You can use this option for defining such >+exception and make Pine automatically sort your favorite Newsgroup by >+Ordered Subject. >+ >+<P> >+ On the other hand you may be suscribed to a mailing list, and maybe you >+don't care to see in the index the size of the messages, however in other >+lists you may want to see the size of the messages. You can use this >+configuration for changing the way the index is displayed in a folder. >+ >+<P> >+ Also there may be a mailing list that identifies itself by adding a >+certain string to its subject which makes difficult to read the total >+subject, so you may want to delete that string from the subject whenever >+it appears. You can do that also with this configuration. >+ >+<P> >+ You may also want to make your reply-leadin-string person or folder >+dependent. You can do this with this feature (part of this feature can be >+accomplised with the roles definitions, but roles are not the right tool >+to do this as you will see). >+ >+<P> >+ Every rule has three parts, a condition, a separator and an action. The >+action is what will happen if the condition of the rule is satisified. >+ >+<P> >+ Here is an example: >+ >+<P> >+ _FROM_ == {Fred Flinstone} => _SAVE_{Fred} >+ >+<P> >+ Here the separator is "=>". Whatever is to the left of the separator >+is the condition (that is to say _FROM_ == {Fred Flinstone}) and to the >+right is the action (_SAVE_{Fred}). The condition means that the rule will >+be applied only if the message that you are reading is from "Fred >+Flinstone", and the action will be that you will be offered to save it in >+the folder "Fred", whenever you press the letter "S" to save a message. >+ >+<P> >+ The separator is always "=>", with one exception to be seen later. >+But for the most part this will be the only one you'll ever need. >+ >+<P> >+ Now let us see how to do it. There are 12 functions already defined for >+you. These are: _INDEX_, _REPLACE_, _REPLY_, _RESUB_, _SAVE_, _SIGNATURE_, >+_SORT_, _STARTUP_, _TRIM_, _REXTRIM_, _THREADSTYLE and _THREADINDEX_. The >+parameter of a function has to be enclosed between "{" and "}", so for >+example you can specify _SAVE_{saved-messages} as a valid sentence. >+ >+<P> >+ At the end of the document you will find more examples.Here is a short >+description of what each function does: >+ >+<P> >+<UL> >+<LI> _INDEX_ : This function takes as an argument an index-format, and >+makes that the index-format for the specified folder. >+<LI> _REPLACE_ : This function replaces the subject/from of the given e-mail by >+another subject/from only when displaying the index. >+<LI> _REPLY_ : This function takes as an argument a definition of a >+reply-leadin-string and makes this the reply-leading-string of the >+specified folder or person. >+<LI> _RESTR_ : This function takes as an argument the value of the >+reply-indent-string to be used to answer the message being replied to. >+<LI> _RESUB_ : This function replaces the subject of the given e-mail by >+another subject only when replying to a message. >+<LI> _SAVE_ : The save function takes as an argument the name of a >+possibly non existing folder, whenever you want to save a message, that >+folder will be offered for you to save. >+<LI> _SIGNATURE_ : This function takes as an argument a signature file and >+uses that file as the signature for the message you are about to >+compose/reply/forward. >+<LI> _SMTP_ : This function takes as an argument the definition of a >+SMTP server. >+<LI> _SORT_ : This function takes as an argument a Sort Style, and sorts a >+specified folder in that sort order. >+<LI> _TRIM_ : This function takes as an argument a list of strings that >+you want removed from another string. At this time this only works for >+_FROM_ and _SUBJECT_. >+<LI> _REXTRIM_ : Same as _TRIM_ but its argument is one and >+only one extended regular expression. >+<LI> _STARTUP_ : This function takes as an argument an >+incoming-startup-rule, and open an specified folder using that rule. >+<LI> _THREADSTYLE_ : This function takes as an argument a >+threading-display-style and uses it to display threads in a folder. >+<LI> _THREADINDEX_ : This function takes as an argument a >+threading-index-style and uses it to display threads in a folder. >+</UL> >+ >+<P> >+You must me wondering how to define the person/folder over who to apply >+the action. This is done in the condition. When you specify a rule, the >+rule is only executed if the condition is satisfied. In another words for >+the rule: >+ >+<P> >+ _FROM_ == {Fred Flinstone} => _SAVE_{Fred} >+ >+<P> >+it will only be applied if the from is "Fred Flinstone", if the From is >+"Wilma Flinstone" the rule will be skipped. >+ >+<P> In order to test a condition you can use the following tokens (in >+alphabetical order): _ADDRESS_,_CC_, _FOLDER_, _FROM_,_NICK_, _ROLE, >+_SENDER_, _SUBJECT_ and _TO_. The token will always be tested against what >+it is between "{" and "}" in the condition, this part of the condition is >+called the "condition set". The definition of each token can be found >+<A HREF="h_index_tokens">here</A>. >+ >+<P> >+You can also test in different ways, you can >+use the following "test operands": <<, !<, >>, !>, == >+and !=. All of them are two strings long. Here is the meaning of them: >+ >+<P> >+<UL> >+<LI> << : It tests if the value of the token is contained in >+the condition set. Here for example if the condition set were equal to >+"Freddy", then the condition: _NICK_ << {Freddy}, would be true if >+the value of _NICK_ were "Fred", "red" or "Freddy". You are just looking >+for substrings here. >+<LI> >> : It tests if the value of the token contains the value of >+the condition set. Here for example if the condittion set were equal to >+"Fred", then the condition: _FROM_ >> {Fred}, would be true if >+the value of _FROM_ were "Fred Flinstone" or "Fred P. Flinstone" or "Freddy". >+<LI> == : It tests if the value of the token is exactly equal to the value >+of the set condition. For example _NICK_ == {Fred} will be false if the value >+of _NICK_ is "Freddy" or "red". >+<LI> !< : This is true only when << is false and viceversa. >+<LI> !> : This is true only when >> is false and viceversa. >+<LI> != : This is true only when == is false and viceversa. >+</UL> >+ >+<P> >+ Now let us say that you want the same action to be applied to more than >+one person or folder, say you want "folder1" and "folder2" to be sorted by >+Ordered Subject upon entering. Then you can list them all of them in the >+condition part separting them by a ";". Here is the way to do it. >+ >+<P> >+ _FOLDER_ << {folder1; folder2} => _SORT_{OrderedSubj} >+ >+<P> >+ Here is the first subtelty about these definitions. Notice that the >+following rule: >+ >+<P> >+ _FOLDER_ == {folder1; folder2} => _SORT_{Reverse OrderedSubj} >+ >+<P> works only for "folder1" but not for "folder2". This is because the >+comparison of the name of the folder is done with whatever is in between >+"{", ";" or "}", so in the above rule you would be testing <BR> >+"folder2" == " folder2". The extra space makes the difference. >+The reason why the first rule does not fail is because >+"folder2" << " folder2" is actually >+true. If something ever fails this may be something to look into. >+ >+<P> >+ Here are a few examples of what we have talked about before. >+ >+<P> >+_NICK_ == {lisa;kika} => _SAVE_{_NICK_/_NICK_} <BR> >+This means that if the nick is lisa, it will >+save the message in the folder "lisa/lisa", and if the nick >+is "kika", it will save the message in the folder "kika/kika" >+ >+<P> >+_FOLDER_ == {Lynx} -> lynx <BR> >+This, is an abreviation of the following rule:<BR> >+_FOLDER_ == {Lynx} => _SAVE_{lynx} <BR> >+(note the change in separator from "=>" to "->"). In the future >+I will use that abreviation. >+ >+<P> _FOLDER_ << {comp.mail.pine; pine-info; pine-alpha} -> pine <BR> >+Any message in the folders "comp.mail.pine", "pine-info" or "pine-alpha" >+will be saved to the folder "pine". >+ >+<P> _FROM_ << {Pine Master} -> pine <BR> >+Any message whose From field contains >+"Pine Master" will be saved in the folder pine. >+ >+<P> _FOLDER_ << {Lynx; pine-info; comp.mail.pine} => >+_INDEX_{IMAPSTATUS MSGNO DATE FROMORTO(33%) SUBJECT(66%)} <BR> Use a >+different index-format for the folders "Lynx", "pine-info" and >+"comp.mail.pine", where the size is not present. >+ >+<P> _FOLDER_ == {Lynx;pine-info} => _REPLY_{*** _FROM_ (_ADDRESS_) >+wrote in the _FOLDER_ list _SMARTDATE_("Today" "today" "on >+_LONGDATE_"):}<BR> If a message is in one of the incoming folders "Lynx" >+or "pine-info", create a reply-leadin-string that acknowledges that. Note >+the absence of "," in the function _SMARTDATE_. For example answering to a >+message in the pine-info list would look like: >+ >+<P> >+*** Steve Hubert (hubert@cac.washington.edu) wrote in the pine-info list today: >+ >+<P> >+However replying for a message in the Lynx list would look: >+ >+<P> >+*** mattack@area.com (mattack@area.com) wrote in the Lynx list today: >+ >+<P> >+If you write in more than one language you can use this feature to create >+Reply-leadin-strings in different languages. >+ >+<P> Note that at least for people you can create particular >+reply-leadin-string using the role features, but it does not work as this >+one does. This seems to be the right way to do it. >+ >+<P> _FOLDER_ << {Lynx; comp.mail.pine; pine_info; pine-alpha} => >+_SORT_{OrderedSubj}<BR> This means upon opening, sort the folders "Lynx", >+"comp.mail.pine", etc in ordered subject. All the others use the default >+sort order. You can not sort in reverse in this form. The possible >+arguments of this function are listed in the definition of the >+default-sort-rule (Arrival, scorE, siZe, etc). >+ >+<P> The last examples use the function _TRIM_ which has a special form. >+This function can only be used in the index list. >+ >+<P> _FOLDER_ << {Lynx} => _SUBJECT_ := _TRIM_{lynx-dev }<BR> In >+the folder "Lynx" eliminate from the subject the string "lynx-dev " (with >+the space at the end). For example a message whose subject is "Re: >+lynx-dev unvisited Visited Links", would be shown in the index with >+subject: "Re: unvisited Visited Links", making the subject shorter and >+giving the same information. >+ >+<P> _FROM_ >> {Name (Comment)} => _FROM_ := >+_TRIM_{ (Comment)}<BR> Remove the part " (Comment)" >+from the _FROM_, so when displaying in the index the real From "Name" >+will appear. >+ >+<P> _SUBJECT_ == {} => _RESUB_{Re: your mail without subject} >+If there is no subject in the message, use the subject "Re: your mail >+wiyhout subject" as a subject for the reply message. >+ >+<P> You can add more complexity to your rules by checking more than one >+conditions before a rule is executed. For example: Assume that you want to >+answer every email that contains the string "bug report", with the subject >+"Re: About your bug report", you could make >+ >+<P> >+_SUBJECT_ == {bug report} => _RESUB_{Re: About your _SUBJECT_} >+ >+<P> The problem with this construction is that if the person emails you >+back, then the next time you answer the message the subject will be: "Re: >+About your Re: About your bug report", so it grew. You may want to avoid >+this growth by using the following rule: >+ >+<P> >+_SUBJECT_ >> {bug report} && _SUBJECT_ !> {Re: } => _RESUB_{Re: About your _SUBJECT_}<BR> >+ >+<P> >+which will only add the string "Re: About your" only the first time the >+message is replied. >+ >+<P> >+ Say your personal name is "Fred Flinstones", and assume that you don't >+like to see "To: comp.mail.pine" in every post you make to this newsgroup, >+but instead would like to see it as everyone else sees it. <BR> >+_FOLDER_ == {comp.mail.pine} && _FROM_ == {Fred Flinstones} => _FROM_ := _REPLACE_{_FROM_} >+ >+<P> >+ You can also list your index by nick, in the following way:<BR> >+_NICK_ != {} => _FROM_ := _REPLACE_{_NICK_} >+ >+<P> >+ If you want to open the folder "pine-info" in the first non-read message >+use the rule:<BR> >+_FOLDER_ == {pine-info} => _STARTUP_{first-unseen} >+ >+<P> >+ If you want to move your deleted messages to a folder, called "Trash", use >+the following rule:<BR> >+_FLAG_ >> {D} -> Trash >+ >+<P> >+The reason why the above test is not "_FLAG_ == {D}" is because that would mean >+that this is the only flag set in the message. It's better to test by containment in this case. >+ >+<P> If you want to use a specific signature when you are in a specific collection >+use the following rule:<BR> >+_COLLECTION_ == {Mail} => _SIGNATURE_{/full/path/to/.signature} >+ >+<P> Finally about the question of which rule will be executed. Only the >+first rule that matches will be executed. It is important to notice though >+that "saving" rules do not compete with "sorting" rules. So the first >+"saving" rule that matches will be executed in the case of saving and so >+on. >+ >+<P> Here are some things to do still: >+<UL> >+<LI> To make _TRIM_ compatible with more tokens (_TO_, _SENDER_, etc) >+<LI> To make this list dissapear! >+</UL> >+ >+<P> >+<UL> >+<LI><A HREF="h_finding_help">Finding more information and requesting help</A> >+</UL><P> >+<End of help on this topic> >+</BODY> >+</HTML> > ====== h_config_char_set ===== > <HTML> > <HEAD> >@@ -21049,14 +22208,118 @@ > labeled as "US-ASCII", independent of this option's value. > > <P> >-If this option is <EM>not</EM> set and the message text you are sending >-or any text attachments are found to contain non US-ASCII >-(or "8-bit") characters, then Pine >-will label the text as "X-UNKNOWN". >+If this option is <EM>not</EM> set and the message text you are sending >+or any text attachments are found to contain non US-ASCII >+(or "8-bit") characters, then Pine >+will label the text as "X-UNKNOWN". >+ >+<P> >+<UL> >+<LI><A HREF="h_finding_help">Finding more information and requesting help</A> >+</UL><P> >+<End of help on this topic> >+</BODY> >+</HTML> >+====== h_config_charset_aliases ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Charset-Aliases</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Charset-Aliases</H1> >+ >+List of charset aliases. >+ >+<P> >+Each alias is a pair of charsets delimetered by a single colon, >+the first one being an alias to the second one. >+ >+<P> >+The latter is usually standard/prefered MIME name while the former >+is a non-standard name used by some email clients. >+ >+<P> >+For instance, you may set it to: 'x-big5:big5,euc-cn:gb2312' >+ >+<P> >+<UL> >+<LI><A HREF="h_finding_help">Finding more information and requesting >+help</A> >+</UL><P> >+<End of help on this topic> >+</BODY> >+</HTML> >+====== h_config_iconv_aliases ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Iconv-Aliases</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Iconv-Aliases</H1> >+ >+List of charset aliases to use with iconv(). >+ >+<P> >+Each alias is a pair of charsets delimetered by a single colon, >+the first one being an alias to the second one. >+ >+<P> >+The former is usually standard/prefered MIME name while the latter >+is a non-standard name used by iconv(3) on your system. >+ >+<P> >+For example, your iconv may use non-standard 'UTF8' for the standard >+'UTF-8'. In that case, you can put 'UTF-8:UTF8' here. >+ >+<P> >+<UL> >+<LI><A HREF="h_finding_help">Finding more information and requesting >+help</A> >+</UL><P> >+<End of help on this topic> >+</BODY> >+</HTML> >+====== h_config_assumed_charset ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Assumed-Charset</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Assumed-Charset</H1> >+ >+When MIME charset information is missing in Content-Type header field >+the Message is assumed to be in this charset. Default: US-ASCII. >+Typical values include ISO-8859-x, ISO-2022-JP, EUC-KR, GB2312, and Big5. >+Header fields which are not encoded per RFC 2047 is also assumed to be >+in this charset. >+ >+<P> >+<UL> >+<LI><A HREF="h_finding_help">Finding more information and requesting >+help</A> >+</UL><P> >+<End of help on this topic> >+</BODY> >+</HTML> >+====== h_config_send_char_set ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Send-Charset</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Send-Charset</H1> >+ >+If it's set, the headers and the body of an outgoing message is converted >+from the value of character-set (display/terminal charset) to the value >+of this option. You have to set this option if your terminal/display charset >+(say, UTF-8) is different from the charset you want your outgoing messsages >+to be in (say, ISO-8859-1, EUC-KR, Big5, GB2312) because your correspondents >+can't handle emails in UTF-8. > > <P> >-<UL> >-<LI><A HREF="h_finding_help">Finding more information and requesting help</A> >+<UL> >+<LI><A HREF="h_finding_help">Finding more information and requesting >+help</A> > </UL><P> > <End of help on this topic> > </BODY> >@@ -21135,6 +22398,42 @@ > <End of help on this topic> > </BODY> > </HTML> >+====== h_config_special_text_to_color ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Special Text to Color</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Specil Text to Color</H1> >+ >+Use this option to enter patterns (text or regular expressions) that Pine >+will highlight in the body of the text that is not part of a handle (and >+internal or external link that Pine paints in a different color). >+ >+<P> >+Enter each pattern in a different line. Pine will internally merge these >+patterns (by adding a "|" character), or you can add them all in one line >+by separating them by a "|" character. >+ >+<P> >+Pine will use the colors defined in the >+<A HREF="h_config_special_text_color"> Special Text Color</A> variable. >+to paint any match. >+ >+<P> >+If the Special Text Color is not set, setting this variable will not >+cause that special text to be indicated in any special way. It will look >+like any normal text. You must set those colors in order to make Pine >+paint the screen differently when it finds the patterns specified in this >+variable. >+ >+<P> >+<UL> >+<LI><A HREF="h_finding_help">Finding more information and requesting help</A> >+</UL><P> >+<End of help on this topic> >+</BODY> >+</HTML> > ====== h_config_display_filters ===== > <HTML> > <HEAD> >@@ -21953,6 +23252,38 @@ > <End of help on this topic> > </BODY> > </HTML> >+====== h_config_inc_fld_timeo ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: inc-fld-timeout</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: inc-fld-timeout</H1> >+ >+When Pine is checking for new mail in an external incoming folder, and the >+amount of time specified in this variable has elapsed without Pine being >+able to connect to the server holding that mailbox, Pine will drop the >+connection to that server and continue checking for new mail in other >+incoming folders, if any. >+ >+<P> >+Observe that Pine will not print an error message in this case, but it >+will silently drop the connection. If your connections are fast setting >+this to a large value will not cause you any problem, but if your >+connections are slow setting this to a small value will make Pine speed >+checking for new mail, although it is possible that not all of your >+incoming folders will be checked for new mail. >+ >+<P> >+The default is 5 seconds, which is also the minimum and the maximum is 60. >+ >+<P> >+<UL> >+<LI><A HREF="h_finding_help">Finding more information and requesting help</A> >+</UL><P> >+<End of help on this topic> >+</BODY> >+</HTML> > ====== h_config_incoming_folders ===== > <HTML> > <HEAD> >@@ -24226,6 +25557,76 @@ > <End of help on this topic> > </BODY> > </HTML> >+====== h_config_thread_display_style_rule ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Threading-Display-Style-Rule</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Threading-Display-Style-Rule</H1> >+ >+This option is very similar to <A HREF="h_config_thread_disp_style"> >+threading-display-style</A>, but it is a rule which specifies the >+display styles for a thread that you want displayed in a specific >+folder or collection. >+<P> >+The token to be used in this function is _THREADSTYLE_. Here there is >+an example of its use >+<P> >+_FOLDER_ == {pine-info} => _THREADSTYLE_{mutt-like} >+<P> >+The values that can be given for the _THREADSTYLE_ function are the >+values of the threading-display-style function, which can be found >+listed in the <A HREF="h_config_thread_disp_style">threading-display-style</A> >+configuration option. >+ >+<P> This configuration option is just one of many that allow you to >+override the value of some global configurations within Pine. There is a >+help text explaining how to define all of them, which you can read by >+following this <A HREF="h_config_new_rules">link</A>. >+ >+<P> >+<UL> >+<LI><A HREF="h_finding_help">Finding more information and requesting help</A> >+</UL><P> >+<End of help on this topic> >+</BODY> >+</HTML> >+====== h_config_thread_index_style_rule ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Threading-Index-Style-Rule</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Threading-Index-Style-Rule</H1> >+ >+This option is very similar to <A HREF="h_config_thread_index_style"> >+threading-index-style</A>, but it is a rule which specifies the >+index styles for a thread that you want displayed in a specific >+folder or collection. >+<P> >+The token to be used in this function is _THREADINDEX_. Here there is >+an example of its use >+<P> >+_FOLDER_ == {pine-info} => _THREADINDEX_{regular-index-with-expanded-threads} >+<P> >+The values that can be given for the _THREADINDEX_ function are the >+values of the threading-index-display function, which can be found >+listed in the <A HREF="h_config_thread_index_style">threading-index-display</A> >+configuration option. >+ >+<P> This configuration option is just one of many that allow you to >+override the value of some global configurations within Pine. There is a >+help text explaining how to define all of them, which you can read by >+following this <A HREF="h_config_new_rules">link</A>. >+ >+<P> >+<UL> >+<LI><A HREF="h_finding_help">Finding more information and requesting help</A> >+</UL><P> >+<End of help on this topic> >+</BODY> >+</HTML> > ====== h_config_pruning_rule ===== > <HTML> > <HEAD> >@@ -24519,6 +25920,51 @@ > <End of help on this topic> > </BODY> > </HTML> >+====== h_config_inc_rule ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Incoming-Check-Rule</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Incoming-Check-Rule</H1> >+ >+This value affects Pine's behavior when starting Pine. It determines >+how and when Pine will check for new mail in your incoming folders. The >+default value is "automatic". >+ >+<P> >+The three possible values for this option are: >+ >+<DL> >+<DT>automatic</DT> >+<DD>This is the default. When this is selected the first check for new >+mail will be done when Pine is starting up and you either go to the >+INDEX or FOLDER LIST screens. >+</DD> >+ >+<DT>automatic-after-first-manual-check</DT> >+<DD>Similar to the default, but no check is done until you force the first >+one by pressing CTRL-H. All checks are automatic after the first one. Observe >+that this feature does not work once an automatic check has been done. >+</DD> >+ >+<DT>manual-only</DT> >+<DD>This forces Pine to do only manual checks. This will probably speed >+Pine, since checks will only happen when they are forced by pressing CTRL-H. >+</DD> >+</DL> >+ >+<P> >+If you just want to stop Pine from checking in one folder, then simply >+select that folder. Checks on that folder will be skipped. >+ >+<P> >+<UL> >+<LI><A HREF="h_finding_help">Finding more information and requesting help</A> >+</UL><P> >+<End of help on this topic> >+</BODY> >+</HTML> > ====== h_config_browser ===== > <HTML> > <HEAD> >@@ -25593,6 +27039,81 @@ > <End of help on this topic> > </BODY> > </HTML> >+====== h_config_enable_check_incoming ====== >+<HTML> >+<HEAD> >+<TITLE>FEATURE: enable-check-incoming-folders</TITLE> >+</HEAD> >+<BODY> >+<H1>FEATURE: enable-check-incoming-folders</H1> >+If you have enabled <A HREF="h_config_enable_incoming">incoming >+folders</A> then setting this feature allows you to check for new mail in >+these. A message stating that new mail was received and in which folders >+will be written in the screen. You can decide which incoming folders you >+want to check for new mail, and the list of them has to be entered in the >+setting <A HREF="h_config_check_inc_fld">incoming-folders-to-check</A>. >+ >+<P> If you have the option >+<A HREF="h_config_fast_recent">enable-fast-recent-test</A> >+<B>disabled</B>, but have this feature enabled, then a full report on the >+total number of messages, and the number of new messages in the folder is >+printed in the <A HREF="h_folder_maint">FOLDER LIST</A> screen >+for each folder listed in the variable >+<A HREF="h_config_check_inc_fld">incoming-folders-to-check</A>. The report for each >+folder is made in the format >+ >+<P> >+folder-name [Number of new messages/Number of messages in the folder] >+ >+<P> >+If an incoming folder is not listed in the variable >+<A HREF="h_config_check_inc_fld">incoming-folders-to-check</A>, then only >+the name of the folder and no other report is made about that folder. >+ >+<P> >+Other important features related to this feature are: >+<OL> >+<LI><A HREF="h_config_enable_recheck_incoming">recheck-all-incoming-folders</A>, >+which allows you to decide if you want to check all folders in every check. >+<LI><A HREF="h_config_inc_rule">incoming-check-rule</A>, which determines >+how and when Pine will check for new mail in your incoming folders. >+</OL> >+ >+<P> >+<UL> >+<LI><A HREF="h_finding_help">Finding more information and requesting help</A> >+</UL> >+</BODY> >+</HTML> >+====== h_config_enable_recheck_incoming ====== >+<HTML> >+<HEAD> >+<TITLE>FEATURE: recheck-all-incoming-folders</TITLE> >+</HEAD> >+<BODY> >+<H1>FEATURE: recheck-all-incoming-folders</H1> >+If you have enabled <A HREF="h_config_enable_incoming">incoming folders</A> >+and <A HREF="h_config_enable_check_incoming">enable-check-incoming-folder</A> >+then setting this feature will force Pine to check <B>all</B> incoming folders >+for new mail in every check. The normal behavior (when this feature >+is not enabled) is that Pine will skip checking for new mail in folders >+where it already found new mail, or it will skip folders where checking >+for new mail takes too long. This is done to speed checking for new mail. >+ >+<P> >+One of the problems that the default behavior causes is if you use two >+programs (or copies of Pine) 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 <B>DO</B> contain new mail. >+ >+<P> >+<UL> >+<LI><A HREF="h_finding_help">Finding more information and requesting help</A> >+</UL> >+</BODY> >+</HTML> > ====== h_config_attach_in_reply ====== > <HTML> > <HEAD> >@@ -25891,6 +27412,22 @@ > <End of help on this topic> > </BODY> > </HTML> >+====== h_config_use_domain ===== >+<HTML> >+<HEAD> >+<TITLE>FEATURE: return-path-uses-domain-name </TITLE> >+</HEAD> >+<BODY> >+<H1>FEATURE: return-path-uses-domain-name</H1> >+ >+If you enable this configuration option Pine will use your domain name and your >+username in that domain name to construct your Return-Path header, if not Pine >+will use the address that you have set in the From: field to construct it. >+ >+<P> >+<End of help on this topic> >+</BODY> >+</HTML> > ====== h_config_use_sender_not_x ===== > <HTML> > <HEAD> >@@ -26192,6 +27729,33 @@ > <A HREF="h_config_tab_uses_unseen">"Tab-Uses-Unseen-For-Next-Folder"</A> > is turned on, then the present feature will have no effect. > >+<P> When this feature is <B>disabled</B>, and the feature >+<A HREF="h_config_enable_check_incoming">enable-check-incoming-folders</A> >+is enabled, then a full report of the number of messages and number of >+new messages in each incoming folder listed in the option >+<A HREF="h_config_check_inc_fld">incoming-folders-to-check</A> is made. This >+report is printed in the <A HREF="h_folder_maint">FOLDER LIST</A> screen. The >+report is given in the form >+ >+<P> >+folder-name [Number of New Messages/Number of messages in the folder] >+ >+<P> If an incoming-folder is not listed in the variable >+<A HREF="h_config_check_inc_fld">incoming-folders-to-check</A>, no check for >+that folder is made, so only the folder name, and no other information is >+printed about that folder. >+ >+<P> If this feature is enabled and the feature >+<A HREF="h_config_enable_recheck_incoming">recheck-all-incoming-folders</A> >+is disabled, then selecting a folder will cancel further checks on that >+folder. This is useful if checks to a particular incoming folder are slow >+and want to be avoided (until the folder is unselected and a new cycle of >+checks is done) without changing the list of folders to be checked. >+Selecting a folder in order to avoid checks for new mail does not work in >+other cases, since it is either explicitly requested this way or because >+it is necessary to update the count of new and total number of messages of >+every requested folder. >+ > <P> > <UL> > <LI><A HREF="h_finding_help">Finding more information and requesting help</A> >@@ -26435,6 +27999,58 @@ > <End of help on this topic> > </BODY> > </HTML> >+====== h_config_alt_reply_menu ===== >+<HTML> >+<HEAD> >+<TITLE>FEATURE: alternate-reply-menu</TITLE> >+</HEAD> >+<BODY> >+<H1>FEATURE: alternate-reply-menu</H1> >+ >+This feature controls the menu that is displayed when Reply is selected. >+If set, a list of options will be presented, with each option representing >+the type of composition that could be used. This feature is most useful >+for users who want to avoid being prompted with each option separately, or >+would like to override some defaults set in your configuration for the >+message that you are replying (e.g. you may have set the option to strip >+signatures, but for the message you are answering you would like not to do >+that) >+ >+<P> >+The way this feature works is as follows. Initially you get the question >+if you want to include the message, and in the menu you will see several >+options, each option is accompanied by some text explaining what will >+happen if you press the associated command. For example, if you read the >+text "S Strip Sig", it means that if you press the letter >+"S" the signature will be stripped off the message you are >+replying. Observer that the menu will change to >+"S No Strip", which means that if you press "S", the >+signature will not be stripped off from the message. Your choices are >+activated when you press RETURN. >+ >+<P> >+Another way to remember what Pine will do, is that what will be done is >+exactly the opposite of what you read in the menu. >+ >+<P> >+The possible options are: >+ >+<OL> >+<LI> F: To decide if you want to send flowed text or not. This option appears >+unless you have quelled sending flowed text. >+ >+<LI> S: To strip the signature from a message, only available is the feature >+ <a href="h_config_sigdashes">enable-sigdashes</a> or the >+<a href="h_config_strip_sigdashes">strip-from-sigdashes-on-reply</a> option are >+enabled. >+ >+<LI> R: To set a role, if you do not want Pine to set one automatically for you >+or would like to set one when you can not select any. >+</OL> >+<P> >+<End of help on this topic> >+</BODY> >+</HTML> > ====== h_config_del_from_dot ===== > <HTML> > <HEAD> >@@ -27000,6 +28616,26 @@ > <End of help on this topic> > </BODY> > </HTML> >+====== h_config_quell_displaying_flowed_text ===== >+<HTML> >+<HEAD> >+<TITLE>FEATURE: Quell-Displaying-Flowed-Text</TITLE> >+</HEAD> >+<BODY> >+<H1>FEATURE: Quell-Displaying-Flowed-Text</H1> >+ >+Beginning with version 4.60, Pine displays flowed text where possible. The >+method for viewing flowed text is defined by >+<A HREF="http://www.ietf.org/rfc/rfc2646.txt">RFC 2646</A>; for more >+information, see <A HREF="h_config_quell_flowed_text">Quell-Flowed-Text</A>. >+<P> >+If this option is set, then Pine will not display flowed text when viewing >+messages. >+ >+<P> >+<End of help on this topic> >+</BODY> >+</HTML> > ====== h_config_prefer_plain_text ===== > <HTML> > <HEAD> >@@ -27180,6 +28816,49 @@ > <End of help on this topic> > </BODY> > </HTML> >+====== h_config_courier_list ===== >+<HTML> >+<HEAD> >+<TITLE>FEATURE: Courier-Folder-List</TITLE> >+</HEAD> >+<BODY> >+<H1>FEATURE: Courier-Folder-List</H1> >+ >+In a maildir collection, a folder could be used as a directory to store >+folders. In the Courier server if you create a folder, then a directory >+with the same name is created. If you use this patch to access a >+collection created by the Courier server, then the display of such >+collection will look confusing. The best way to access a maildir >+collection created by the Courier server is by using the "#mc/" >+prefix instead of the "#md/" prefix. If you use this alternate >+prefix, then this feature applies to you, otherwise you can safely ignore >+the text that follows. >+<P> >+Depending on if you have enabled the option >+<a href="h_config_separate_yold_dir_view">separate-folder-and-firectory-entries</a> >+a folder may be listed as "folder[.]", or as two entries in the >+list by "folder" and "folder.". >+<P> >+If this option is disabled, Pine will list local folders that are in Courier >+style format, as "folder", and those that are also directories as >+"folder[.]". This makes the default display cleaner. >+<P> >+If this feature is enabled then creating folders in a maildir collection >+will create a directory with the same name. If this feature is disabled, then >+a folder is considered a directory only if it contains subfolders, so you can >+not create a directory with the same name as an exisiting folder unless >+you create a subfolder of that folder first (e.g. if you have a folder >+called "foo" simply add "foo.bar" directly. This will >+create the directory "foo" and the subfolder "bar" of it). >+<P> >+Observe that this feature works only for maildir collections that are accessed >+locally. If a collection is accessed remotely then this feature has no value, >+as the report is created in a server, and Pine only reports what received >+from the server in this case. >+<P> >+<End of help on this topic> >+</BODY> >+</HTML> > ====== h_config_verbose_post ===== > <HTML> > <HEAD> >@@ -27331,6 +29010,29 @@ > <End of help on this topic> > </BODY> > </HTML> >+====== h_config_auto_read_msgs_rules ===== >+<HTML> >+<HEAD> >+<TITLE>FEATURE: auto-move-read-msgs-using-rules</TITLE> >+</HEAD> >+<BODY> >+<H1>FEATURE: auto-move-read-msgs-using-rules</H1> >+This feature controls an aspect of Pine's behavior upon quitting. If set, >+and the >+<A HREF="h_config_read_message_folder">"read-message-folder"</A> >+option is also set, then Pine will automatically transfer all read >+messages to the designated folder using the rules that you have defined in >+your >+<A HREF="h_config_save_rules">"save-rules"</A> and mark >+them as deleted in the INBOX. Messages in the INBOX marked with an >+"N" (meaning New, or unseen) are not affected. >+<P> >+<UL> >+<LI><A HREF="h_finding_help">Finding more information and requesting help</A> >+</UL><P> >+<End of help on this topic> >+</BODY> >+</HTML> > ====== h_config_auto_fcc_only ===== > <HTML> > <HEAD> >@@ -27719,6 +29421,23 @@ > <End of help on this topic> > </BODY> > </HTML> >+====== h_config_enhanced_thread ===== >+<HTML> >+<HEAD> >+<TITLE>FEATURE: enhanced-fancy-thread-support</TITLE> >+</HEAD> >+<BODY> >+<H1>FEATURE: enhanced-fancy-thread-support</H1> >+ >+If this option is set certain commands in Pine will operate in loose >+threads too. For example, the command ^D marks a thread deleted, but if >+this feature is set, it will remove all threads that share the same missing >+parent with this thread. >+ >+<P> >+<End of help on this topic> >+</BODY> >+</HTML> > ====== h_config_news_cross_deletes ===== > <HTML> > <HEAD> >@@ -28327,6 +30046,27 @@ > <End of help on this topic> > </BODY> > </HTML> >+====== h_config_circular_tab ===== >+<HTML> >+<HEAD> >+<TITLE>FEATURE: enable-circular-tab</TITLE> >+</HEAD> >+<BODY> >+<H1>FEATURE: enable-circular-tab</H1> >+ >+<P> >+This Feature is like >+<A HREF="h_config_auto_open_unread">"auto-open-next-unread"</A>, >+in the sense that you can use TAB to browse through all of your Incoming >+Folders checking for new mail. Once it gets to the last folder of the >+collection it goes back to check again until it returns to the original >+folder where it started. >+<UL> >+<LI><A HREF="h_finding_help">Finding more information and requesting help</A> >+</UL><P> >+<End of help on this topic> >+</BODY> >+</HTML> > ====== h_config_auto_include_reply ===== > <HTML> > <HEAD> >@@ -28818,6 +30558,30 @@ > <End of help on this topic> > </BODY> > </HTML> >+====== h_config_special_text_color ===== >+<HTML> >+<HEAD> >+<TITLE>OPTION: Special Text Color</TITLE> >+</HEAD> >+<BODY> >+<H1>OPTION: Special Text Color</H1> >+ >+Sets the color Pine uses for coloring any text in the body of the message >+that is not part of a handle (and internal or external link that Pine >+paints in a different color). By default, this variable is not defined, >+which means that text that matches the pattern is not painted in any >+particular way. This variable must be set in a special form if you >+want text to be painted. >+ >+<P> >+<A HREF="h_color_setup">Descriptions of the available commands</A> >+<P> >+Look <A HREF="h_edit_nav_cmds">here</A> >+to see the available Editing and Navigation commands. >+<P> >+<End of help on this topic> >+</BODY> >+</HTML> > ====== h_config_prompt_color ===== > <HTML> > <HEAD> >--- pine4.64/pine/reply.c 2005-09-13 00:04:25.000000000 +0200 >+++ pine4.64.SuSE/pine/reply.c 2006-02-14 14:45:23.000000000 +0100 >@@ -62,6 +62,8 @@ > > #include "headers.h" > >+static ACTION_S *role_chosen; >+static int strip, send_flowed = 1; > > > /* >@@ -276,7 +278,7 @@ > if(!times){ /* only first time */ > char *p = cpystr(prefix); > >- if((include_text=reply_text_query(pine_state,totalm,&prefix)) < 0) >+ if((include_text=reply_text_query(pine_state,totalm,env,&prefix)) < 0) > goto done_early; > > /* edited prefix? */ >@@ -319,8 +321,19 @@ > outgoing->subject = cpystr("Re: several messages"); > } > } >- else >- outgoing->subject = reply_subject(env->subject, NULL, 0); >+ else{ >+ RULE_RESULT *rule; >+ rule = get_result_rule(V_RESUB_RULES, >+ FOR_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,13 +344,18 @@ > if(sp_expunge_count(pine_state->mail_stream)) /* cur msg expunged */ > goto done_early; > >+ if (ps_global->role) >+ fs_give((void **)&ps_global->role); >+ > /* Setup possible role */ >- if(role_arg) >- role = copy_action(role_arg); >+ if (role_chosen) >+ role = role_chosen; >+ else if(role_arg) >+ role = copy_action(role_arg); > > if(!role){ > rflags = ROLE_REPLY; >- if(nonempty_patterns(rflags, &dummy)){ >+ if(!role_chosen && nonempty_patterns(rflags, &dummy)){ > /* setup default role */ > nrole = NULL; > j = mn_first_cur(pine_state->msgmap); >@@ -364,6 +382,9 @@ > } > } > >+ if (role) >+ ps_global->role = cpystr(role->nick); /* remember the role */ >+ > /* > * Reply_seed may call c-client in get_fcc_based_on_to, so env may > * no longer be valid. Get it again. >@@ -995,8 +1016,9 @@ > prompt_fodder); > } > >- cmd = radio_buttons(prompt, -FOOTER_ROWS(ps_global), ekey, >- 'y', 'x', help, RB_NORM, NULL); >+ cmd = ps_global->send_immediately ? 'n' : >+ radio_buttons(prompt, -FOOTER_ROWS(ps_global), ekey, >+ 'y', 'x', help, RB_NORM, NULL); > > switch(cmd){ > case 'y': /* Accept */ >@@ -1544,18 +1566,32 @@ > && (decoded[0] == 'R' || decoded[0] == 'r') > && (decoded[1] == 'E' || decoded[1] == 'e')){ > >- if(decoded[2] == ':') >- sprintf(buf, "%.*s", buflen-1, subject); >+ if(decoded[2] == ':'){ >+ strncpy(buf, subject, l); >+ buf[l]='\0'; >+ } > else if((decoded[2] == '[') && (p = strchr(decoded, ']'))){ > p++; > while(*p && isspace((unsigned char)*p)) p++; >- if(p[0] == ':') >- sprintf(buf, "%.*s", buflen-1, subject); >+ if(p[0] == ':'){ >+ strncpy(buf, subject, l); >+ buf[l]='\0'; >+ } > } > } >- if(!buf[0]) >- sprintf(buf, "Re: %.*s", buflen-1, >- (subject && *subject) ? subject : "your mail"); >+ if(!buf[0]) { >+ /* >+ * Used to be >+ * sprintf(buf, "Re: %.200s", (subject && *subject) ? subject : >+ * "your mail"); >+ * Some implementations of sprintf() are locale-dependent and >+ * don't pass through an invalid sequence of bytes blindly. >+ * Use strncpy() instead: >+ */ >+ strcpy(buf,"Re: "); >+ strncpy(buf+4, (subject && *subject) ? subject : "your mail", l); >+ buf[l+4]='\0'; >+ } > > fs_give((void **) &tmp); > return(buf); >@@ -1623,8 +1659,27 @@ > 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, ps_global->VAR_REPLY_STRING, sizeof(buf)-1); >+ strncpy(buf, reply_string, sizeof(buf)-1); > buf[sizeof(buf)-1] = '\0'; > > /* set up the prefix to quote included text */ >@@ -1680,10 +1735,30 @@ > 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))); >+ 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,46 +1768,101 @@ > * 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, prefix) >+reply_text_query(ps, many, env, prefix) > struct pine *ps; > long many; >+ ENVELOPE *env; > 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} >- }; >+ 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_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? ", >+ 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) ? "\")" : ""); > >- 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; >+ 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, >- rtq_opts, >+ compose_style, > (edited || F_ON(F_AUTO_INCLUDE_IN_REPLY, ps)) > ? 'y' : 'n', > 'x', NO_HELP, RB_SEQ_SENSITIVE, NULL)){ >@@ -1740,6 +1870,37 @@ > 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,8 +1924,14 @@ > if(flags & OE_USER_MODIFIED){ > fs_give((void **)prefix); > removing_double_quotes(*prefix = cpystr(buf)); >- edited = 1; >- } >+ 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; >+ } > > done++; > break; >@@ -2251,6 +2418,10 @@ > buf[0] = '\0'; > > switch(type){ >+ case iFfrom: >+ addr = env && env->sparep ? env->sparep : NULL; >+ break; >+ > case iFrom: > addr = env ? env->from : NULL; > break; >@@ -2682,21 +2853,121 @@ > > 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 iRoleNick: >- if(role && role->nick){ >- strncpy(buf, role->nick, maxlen); >- buf[maxlen] = '\0'; >- } >- 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,6 +2986,11 @@ > > 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,7 +3102,19 @@ > if(!env) > return; > >- strncpy(buf, ps_global->VAR_REPLY_INTRO, MAX_DELIM); >+ { 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,9 +3276,6 @@ > } > 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); >@@ -3051,6 +3336,8 @@ > > 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,14 +3351,25 @@ > * there is no reason to mix them, so we don't provide support to > * do so. > */ >- if(role && role->litsig) >- literal_sig = role->litsig; >- else if(ps_global->VAR_LITERAL_SIG) >- literal_sig = ps_global->VAR_LITERAL_SIG; >- else if(role && role->sig) >- sigfile = role->sig; >- else >- sigfile = ps_global->VAR_SIGNATURE_FILE; >+ { RULE_RESULT *rule; >+ rule = get_result_rule(V_COMPOSE_RULES, FOR_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,7 +3567,7 @@ > } > } > } >- else if(pt->what_for & FOR_REPLY_INTRO) >+ else if(pt->what_for & (FOR_REPLY_INTRO|FOR_RULE)) > repl = get_reply_data(env, role, pt->ctype, > subbuf, sizeof(subbuf)-1); > >@@ -3747,9 +4045,14 @@ > } > } > >- if(role) >+ 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,6 +4256,7 @@ > #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); >@@ -4294,6 +4599,11 @@ > body = mail_newbody(); > body->type = TYPETEXT; > body->contents.text.data = msgtext; >+ /* >+ * For giving get_body_part_text the charset from which it has >+ * to convert from, reset afterwards to prevent double free! >+ */ >+ body->parameter = part->body.parameter; > > if(!(flags & FWD_ANON)){ > forward_delimiter(pc); >@@ -4305,6 +4611,12 @@ > sect_prefix ? "." : "", flags & FWD_NESTED ? "1." : "", > partnum); > get_body_part_text(stream, body, msgno, tmp_buf, pc, NULL); >+ /* >+ * Reset it, otherwise send thinks it's not converted, and since >+ * the parameter list was not copied, only the pointer to it, it >+ * it needed to be reset to prevent a second, double free later! >+ */ >+ body->parameter = NULL; > } > else > q_status_message(SM_ORDER | SM_DING, 3, 3, >@@ -4557,6 +4861,9 @@ > ENVELOPE *outgoing; > BODY *body = NULL; > MESSAGECACHE *mc; >+#ifdef ENABLE_SEND_CHARSET >+ char *temp_send_cset = NULL; >+#endif > > outgoing = mail_newenvelope(); > outgoing->message_id = generate_message_id(); >@@ -4640,6 +4947,17 @@ > > gf_clear_so_writec((STORE_S *) msgtext); > >+#ifdef ENABLE_SEND_CHARSET >+ /* >+ * reset VAR_SEND_CHARSET to '' temporarily NOT to >+ * apply the charset conversion to a bounced message. >+ */ >+ if (ps_global->VAR_SEND_CHARSET && *(ps_global->VAR_SEND_CHARSET)){ >+ temp_send_cset = (char *)fs_get(strlen(ps_global->VAR_SEND_CHARSET)+1); >+ strcpy(temp_send_cset, ps_global->VAR_SEND_CHARSET); >+ (ps_global->VAR_SEND_CHARSET)[0] = '\0'; >+ } >+#endif > if(pine_simple_send(outgoing, &body, role, pmt_who, pmt_cnf, to, > !(to && *to) ? SS_PROMPTFORTO : 0) < 0){ > errstr = ""; /* p_s_s() better have explained! */ >@@ -4650,6 +4968,12 @@ > mail_flag(stream, long2string(rawno), "\\SEEN", 0); > } > >+#ifdef ENABLE_SEND_CHARSET >+ if (temp_send_cset){ >+ strcpy(ps_global->VAR_SEND_CHARSET, temp_send_cset); >+ fs_give((void **)&temp_send_cset); >+ } >+#endif > /* Just for good measure... */ > mail_free_envelope(&outgoing); > pine_free_body(&body); >@@ -4873,9 +5197,12 @@ > * tied our hands, alter the prefix to continue flowed > * formatting... > */ >- if(flow_res) >+ 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,8 +5236,9 @@ > * We also want to fold "> " quotes so we get the > * attributions correct. > */ >- if(flow_res && prefix && !strucmp(prefix, "> ")) >+ 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,8 +5266,8 @@ > } > > if(prefix){ >- if(F_ON(F_ENABLE_SIGDASHES, ps_global) || >- F_ON(F_ENABLE_STRIP_SIGDASHES, ps_global)){ >+ 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); >@@ -6356,6 +6684,9 @@ > && ps_global->VAR_EDITOR[0] > && ps_global->VAR_EDITOR[0][0])) > ? P_ADVANCED : 0L) >+ | ((ps_global->VAR_CHAR_SET >+ && !strucmp(ps_global->VAR_CHAR_SET, "UTF-8")) >+ ? P_UNICODE : 0L) > | ((!ps_global->VAR_CHAR_SET > || !strucmp(ps_global->VAR_CHAR_SET, "US-ASCII")) > ? P_HIBITIGN : 0L)); >--- pine4.64/pine/send.c 2005-09-13 00:04:25.000000000 +0200 >+++ pine4.64.SuSE/pine/send.c 2006-02-14 14:45:24.000000000 +0100 >@@ -377,6 +377,11 @@ > 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,8 +586,12 @@ > } > ps_global->next_screen = prev_screen; > ps_global->redrawer = redraw; >- if(role) >+ if (ps_global->role) >+ fs_give((void **)&ps_global->role); >+ if(role){ > role = combine_inherited_role(role); >+ ps_global->role = cpystr(role->nick); >+ } > } > break; > case 'f': >@@ -675,6 +684,11 @@ > > 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,6 +789,11 @@ > > 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,6 +883,7 @@ > 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,9 +914,15 @@ > } > } > >- if(role) >+ 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,7 +2221,7 @@ > 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}, >+ 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,7 +2328,8 @@ > #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,7 +2337,7 @@ > /* 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}, >+ {"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,7 +2486,7 @@ > strncpy(pf->name, "Sender", 7); > > pf->type = pf_template[i].type; >- pf->canedit = pf_template[i].canedit; >+ 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; >@@ -3177,6 +3204,9 @@ > 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 >@@ -3664,6 +3694,11 @@ > 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; >@@ -3771,6 +3806,24 @@ > 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); >@@ -4276,9 +4329,12 @@ > /* 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) >@@ -4287,7 +4343,12 @@ > #ifdef _WINDOWS > mswin_setwindowmenu (MENU_DEFAULT); > #endif >- fix_windsize(ps_global); >+ 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 >@@ -4347,7 +4408,9 @@ > if(outgoing->return_path) > mail_free_address(&outgoing->return_path); > >- outgoing->return_path = rfc822_cpy_adr(outgoing->from); >+ 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. >@@ -4949,10 +5012,16 @@ > if(sending_filter_requested > && !filter_message_text(sending_filter_requested, outgoing, > *body, &orig_so, &header)){ >- q_status_message1(SM_ORDER, 3, 3, >+ if (!ps_global->send_immediately){ >+ q_status_message1(SM_ORDER, 3, 3, > "Problem filtering! Nothing sent%.200s.", > fcc ? " or saved to fcc" : ""); >- continue; >+ continue; >+ } >+ else{ >+ fprintf(stderr, "Problem filtering! Nothing sent or saved to Fcc\n"); >+ exit(-1); >+ } > } > > /*------ Actually post -------*/ >@@ -5173,6 +5242,8 @@ > /*----- 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){ > /* >@@ -5207,6 +5278,7 @@ > 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)); > >@@ -5791,7 +5863,7 @@ > if(background_posting(FALSE)) > return("Can't send while background posting. Use postpone."); > >- if(F_ON(F_SEND_WO_CONFIRM, ps_global)) >+ if(!ps_global->send_immediately && F_ON(F_SEND_WO_CONFIRM, ps_global)) > return(NULL); > > ps_global->redrawer = redraw_pico; >@@ -5942,7 +6014,8 @@ > > opts[i].ch = -1; > >- fix_windsize(ps_global); >+ if (!ps_global->send_immediately) >+ fix_windsize(ps_global); > > while(1){ > if(filters && filters->filter && (p = strindex(filters->filter, ' '))) >@@ -6077,7 +6150,8 @@ > > 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, >+ 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 : >@@ -6086,7 +6160,8 @@ > h_send_prompt, > RB_NORM); > else >- rv = radio_buttons(tmp_20k_buf, -FOOTER_ROWS(ps_global), opts, >+ 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) >@@ -6575,6 +6650,54 @@ > } > } > >+#ifdef ENABLE_SEND_CHARSET >+/* >+ * Take the PicoText pointed to and replace it with PicoText which has been >+ * filtered to change the 'character-set' (display/terminal-charset) to >+ * 'send-charset'. (based on filter_msgtxt_euc_to_2022_jp, above) >+ */ >+void >+filter_msgtxt_to_send_charset(body) >+ BODY *body; >+{ >+ STORE_S **so = (STORE_S **)((body->type == TYPEMULTIPART) >+ ? &body->nested.part->body.contents.text.data >+ : &body->contents.text.data); >+ STORE_S *filtered_so = NULL; >+ gf_io_t pc, gc; >+ char *errstr; >+ CONV_TABLE *ct; >+ char * assumed_save = ps_global->VAR_ASSUMED_CHAR_SET; >+ >+ ps_global->VAR_ASSUMED_CHAR_SET = NULL; >+ ct = conversion_table(ps_global->VAR_CHAR_SET, ps_global->VAR_SEND_CHARSET); >+ ps_global->VAR_ASSUMED_CHAR_SET = assumed_save; >+ >+ if(ct->table && (filtered_so = so_get(PicoText, NULL, EDIT_ACCESS))){ >+ so_seek(*so, 0L, 0); >+ gf_filter_init(); >+ gf_link_filter(ct->convert, ct->table); >+ gf_set_so_readc(&gc, *so); >+ gf_set_so_writec(&pc, filtered_so); >+ if(errstr = gf_pipe(gc, pc)){ >+ so_give(&filtered_so); >+ dprint(1, (debugfile, >+ "Error with converting to send-charset %s:%s\n", >+ ps_global->VAR_SEND_CHARSET, errstr)); >+ return; >+ } >+ >+ gf_clear_so_readc(*so); >+ gf_clear_so_writec(filtered_so); >+ >+ so_give(so); >+ *so = filtered_so; >+ } >+ dprint(5, (debugfile, >+ "Succeeded in converting %s to %s for outgoing email\n", >+ ps_global->VAR_CHAR_SET, ps_global->VAR_SEND_CHARSET)); >+} >+#endif > > /*---------------------------------------------------------------------- > Pass the first text segment of the message thru the "send filter" >@@ -6673,9 +6796,11 @@ > 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 (!ps_global->send_immediately){ >+ suspend_busy_alarm(); >+ ClearScreen(); >+ fflush(stdout); >+ } > if(tmpf){ > PIPE_S *fpipe; > >@@ -6781,9 +6906,10 @@ > b->encoding = ENCOTHER; > set_mime_type_by_grope(b, NULL); > } >- >- ClearScreen(); >- resume_busy_alarm(0); >+ if (!ps_global->send_immediately){ >+ ClearScreen(); >+ resume_busy_alarm(0); >+ } > } > else > errstr = "Can't create space for filtered text."; >@@ -6814,10 +6940,16 @@ > if(tmp_so) > so_give(&tmp_so); > >- q_status_message1(SM_ORDER | SM_DING, 3, 6, "Problem filtering: %.200s", >+ 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", >+ dprint(1, (debugfile, "Filter FAILED: %s\n", > errstr ? errstr : "?")); >+ } >+ else{ >+ fprintf(stderr, "Filter FAILED: %s\n", errstr ? errstr : "?"); >+ exit(-1); >+ } > } > > return(errstr == NULL); >@@ -6973,9 +7105,9 @@ > char error_buf[200], *error_mess = NULL, *postcmd; > ADDRESS *a; > ENVELOPE *fake_env = NULL; >- int addr_error_count, we_cancel = 0; >+ int addr_error_count, we_cancel = 0, choice, num_rules = 0, added_rules = -1; > long smtp_opts = 0L; >- char *verbose_file = NULL; >+ char *verbose_file = NULL, **smtp_list; > BODY *bp = NULL; > PINEFIELD *pf; > >@@ -7103,19 +7235,50 @@ > * 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); >+ >+ /* 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++; >+ } >+ } >+ } > } >- else if(ps_global->VAR_SMTP_SERVER && ps_global->VAR_SMTP_SERVER[0] >- && ps_global->VAR_SMTP_SERVER[0][0]){ >+ >+ 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\n")); >+ dprint(4, (debugfile, "call_mailer: via TCP (%s)\n", >+ smtp_list[0])); > TIME_STAMP("smtp-open start (tcp)", 1); >- sending_stream = smtp_open(ps_global->VAR_SMTP_SERVER, smtp_opts); >+ 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]; >@@ -7315,6 +7478,8 @@ > > 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{ >@@ -7809,7 +7974,12 @@ > src = pf->scratch ? pf->scratch > : (*pf->text) ? *pf->text : ""; > >+#ifndef ENABLE_SEND_CHARSET > len = strlen(src)+1; >+#else >+ /* multiplyer 5 should be enough for EUC-JP -> ISO-2022-JP */ >+ len = strlen(src)*5+1; >+#endif > p = (char *)fs_get(len * sizeof(char)); > if(rfc1522_decode((unsigned char *)p, len, src, &charset) > == (unsigned char *) p){ >@@ -7924,7 +8094,7 @@ > if(!the_address) > the_address = pf->scratch; > >- rfc822_parse_adrlist(&new_addr, the_address, >+ rfc822_parse_adrlist(&new_addr, pf->scratch, > (F_ON(F_COMPOSE_REJECTS_UNQUAL, ps_global)) > ? fakedomain : ps_global->maildomain); > resolve_encoded_entries(new_addr, *pf->addr); >@@ -7945,6 +8115,13 @@ > !strucmp(ps_global->VAR_CHAR_SET, "iso-2022-jp")) > *pf->text = > (char *) trans_euc_to_2022_jp((unsigned char *) (pf->scratch)); >+#ifdef ENABLE_SEND_CHARSET >+ else if(ps_global->VAR_CHAR_SET && ps_global->VAR_SEND_CHARSET && >+ !strucmp(ps_global->VAR_CHAR_SET, ps_global->VAR_SEND_CHARSET)) >+ *pf->text = >+ (char *) trans_with_iconv((unsigned char *) (pf->scratch), >+ ps_global->VAR_CHAR_SET, ps_global->VAR_SEND_CHARSET); >+#endif > else > *pf->text = cpystr(pf->scratch); > } >@@ -7995,6 +8172,10 @@ > SIZEOF_20KBUF, buftmp, &charset); > > q = (char *) trans_euc_to_2022_jp((unsigned char *)(a->personal)); >+#ifdef ENABLE_SEND_CHARSET >+ q = (char *) trans_with_iconv((unsigned char *)(a->personal), >+ ps_global->VAR_CHAR_SET, ps_global->VAR_SEND_CHARSET); >+#endif > > if(p == tmp_20k_buf /* personal was decoded */ > && !strcmp(q, p)){ /* still matches what it was */ >@@ -8119,6 +8300,10 @@ > rfc1522_encode(tmp_20k_buf, > SIZEOF_20KBUF, > (unsigned char *) pa->description, >+#ifdef ENABLE_SEND_CHARSET >+ ps_global->VAR_SEND_CHARSET ? >+ ps_global->VAR_SEND_CHARSET : >+#endif > ps_global->VAR_CHAR_SET)); > } > if(charset) >@@ -8183,6 +8368,10 @@ > p->body.description = cpystr(rfc1522_encode(tmp_20k_buf, > SIZEOF_20KBUF, > (unsigned char *) pa->description, >+#ifdef ENABLE_SEND_CHARSET >+ ps_global->VAR_SEND_CHARSET ? >+ ps_global->VAR_SEND_CHARSET : >+#endif > ps_global->VAR_CHAR_SET)); > > /* Add name attribute for backward compatibility */ >@@ -8593,6 +8782,22 @@ > if(new_encoding != ENCBINARY) > new_encoding = ENC8BIT; /* short lines, < 30% 8 bit chars */ > } >+ else if(max_line < 300L || (eight_bit_chars * 100L)/len < 80L){ >+ /* >+ * The previous test misses East Asian, Greek and Russian text >+ * in ISO-8859-7, KOI8-R, EUC-KR, Big5, and GB2312 >+ * with a lot higher percentage of 8bit chars than Western European text >+ * in ISO-8859-x. For them, use a relaxed condition for the >+ * percentage of 8bit chars along with a more strict condition >+ * on the maximum line length. >+ */ >+ can_be_ascii--; >+ if(body->type == TYPEOTHER) >+ body->type = TYPETEXT; >+ >+ if(new_encoding != ENCBINARY) >+ new_encoding = ENC8BIT; /* short lines, < 30% 8 bit chars */ >+ } > else{ > can_be_ascii--; > if(body->type == TYPEOTHER){ >@@ -8656,7 +8861,11 @@ > else > set_mime_charset(pm, > can_be_ascii > 0, >+#ifndef ENABLE_SEND_CHARSET > charset ? charset : ps_global->VAR_CHAR_SET); >+#else >+ charset); >+#endif > } > > if(body->encoding == ENCOTHER) >@@ -8741,7 +8950,11 @@ > > set_mime_charset(pm, > can_be_ascii > 0, >+#ifndef ENABLE_SEND_CHARSET > charset ? charset : ps_global->VAR_CHAR_SET); >+#else >+ charset); >+#endif > > if(we_cancel) > cancel_busy_alarm(-1); >@@ -8772,6 +8985,11 @@ > if(pm->value && (!*pm->value || strucmp(pm->value, us_ascii) == 0)) > fs_give((void **)&pm->value); > >+ cs = cs ? cs >+#ifdef ENABLE_SEND_CHARSET >+ : ps_global->VAR_SEND_CHARSET ? ps_global->VAR_SEND_CHARSET >+#endif >+ : ps_global->VAR_CHAR_SET; > /* see if cs is a special non_ascii charset */ > for(excl = non_ascii; cs && *excl && strucmp(*excl, cs); excl++) > ; >@@ -8856,8 +9074,16 @@ > char *value, *folded = NULL; > > >+#ifdef ENABLE_SEND_CHARSET >+ text = (char *) trans_with_iconv(text, ps_global->VAR_CHAR_SET, >+ ps_global->VAR_SEND_CHARSET); >+#endif > value = encode_header_value(tmp_20k_buf, SIZEOF_20KBUF, > (unsigned char *) text, >+#ifdef ENABLE_SEND_CHARSET >+ ps_global->VAR_SEND_CHARSET ? >+ ps_global->VAR_SEND_CHARSET : >+#endif > ps_global->VAR_CHAR_SET, > encode_whole_header(field, header)); > >@@ -8922,6 +9148,10 @@ > fs_give((void **)&folded); > } > >+#ifdef ENABLE_SEND_CHARSET >+ if (text) >+ fs_give((void **)&text); >+#endif > return(ret); > } > >@@ -11002,3 +11232,16 @@ > { > return(0L); > } >+ >+int >+call_pico (ps) >+ struct pico_struct * ps; >+{ >+ int ret; >+ char * assumed_save = ps_global->VAR_ASSUMED_CHAR_SET; >+ ps_global->VAR_ASSUMED_CHAR_SET = NULL; >+#undef pico >+ ret = pico(ps); >+ ps_global->VAR_ASSUMED_CHAR_SET = assumed_save; >+ return ret; >+} >diff -ru pine4.64/pine/signals.c pine4.64.SuSE/pine/signals.c >--- pine4.64/pine/signals.c 2004-11-04 23:31:46.000000000 +0100 >+++ pine4.64.SuSE/pine/signals.c 2006-02-14 14:45:23.000000000 +0100 >@@ -673,7 +673,8 @@ > > add_review_message(buf, -1); > } >- else{ >+ else if (!ps_global->send_immediately >+ && !ps_global->checking_incfld){ > q_status_message(SM_ORDER, 0, 1, progress); > > /* >@@ -683,18 +684,20 @@ > * its min display time yet. In that case, we don't want > * to force out the initial message. > */ >- display_message('x'); >+ 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)) >+ if(F_OFF(F_DISABLE_ALARM, ps_global) && !ps_global->send_immediately >+ && !ps_global->checking_incfld) > alarm(seconds); > > return(retval); >@@ -731,18 +734,22 @@ > > 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); >+ 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); >+ message_pri+2, progress);} > } > } > else >diff -ru pine4.64/pine/status.c pine4.64.SuSE/pine/status.c >--- pine4.64/pine/status.c 2005-09-13 00:04:25.000000000 +0200 >+++ pine4.64.SuSE/pine/status.c 2006-02-14 14:45:23.000000000 +0100 >@@ -142,6 +142,9 @@ > 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,7 +1187,7 @@ > char *q2; > int rv; > >- if(!ps_global->ttyo) >+ 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 -ru pine4.64/pine/strings.c pine4.64.SuSE/pine/strings.c >--- pine4.64/pine/strings.c 2005-08-30 02:08:19.000000000 +0200 >+++ pine4.64.SuSE/pine/strings.c 2006-02-14 14:45:24.000000000 +0100 >@@ -82,6 +82,9 @@ > > #include "headers.h" > #include "../c-client/utf8.h" >+#ifdef HAVE_ICONV >+#include <iconv.h> >+#endif > > typedef struct role_args { > char *ourcharset; >@@ -682,6 +685,151 @@ > (*d)++; > } > >+/* ------------------------- UTF-8 functions -------------------------- */ >+ >+char * >+pine_check_utf8(c, utf_seq, sizeof_utf_seq) >+ char *c; >+ char *utf_seq; >+ size_t sizeof_utf_seq; >+{ >+ if(!ps_global->VAR_CHAR_SET >+ || strucmp(ps_global->VAR_CHAR_SET, "UTF-8")) >+ return c; >+ return check_utf8(c, utf_seq, sizeof_utf_seq); >+} >+ >+/* >+ * Like istrncpy but since it's used in the mail index, it also converts >+ * line feed and tab to space to prevent odd effects in mail index paint. >+ * >+ * If charset is UTF-8, do not count bytes for the string width but real >+ * screen widths. The control char and escape sequence filter is also not >+ * active inside UTF-8 sequencies there because UTF-8 requires bytes in >+ * the range from 0x80 to 0x9f to be processed. If a series of not recognized >+ * characters in the range of 0x80 to 0xff is encountered, '?' is copied. >+ */ >+void >+charset_istrncpy(dest, source, width, padding) >+ char *dest; >+ char *source; /* const */ >+ int width; >+ int padding; >+{ >+ char *cp, *chp, *destp = dest; >+ int seq = 0, screencols=0; >+ unsigned char utf_seq[10] = ""; >+ >+ for(cp = source; *cp && screencols < width; cp++){ >+ if((chp = pine_check_utf8(cp, utf_seq, sizeof(utf_seq))) == NULL){ >+ seq = 1; >+ continue; >+ } >+ if(chp != cp){ >+ seq = 0; >+ screencols++; >+ if(*chp == ' '){ >+ if(screencols >= width){ >+ sstrcpy(&destp, "\342\200\246"); >+ break; /* UTF-8 points... */ >+ } >+ screencols++; >+ chp++; >+ } >+ while(*chp) >+ *destp++ = *chp++; >+ *destp = '\0'; >+ continue; >+ } >+ if(seq){ >+ seq = 0; >+ screencols++; >+ *destp++ = '?'; >+ } >+ screencols++; >+ if(*cp && FILTER_THIS(*cp) >+ && !(*(cp+1) && *cp == ESCAPE && match_escapes(cp+1))){ >+ *destp++ = '^'; >+ if(screencols < width){ >+ screencols++; >+ *destp++ = (*cp & 0x7f) + '@'; >+ } >+ } >+ else if(*cp == '\n' || *cp == '\t') >+ *destp++ = ' '; >+ else >+ *destp++ = *cp; >+ *destp = '\0'; >+ } >+ if(padding == 1) >+ while(screencols < width){ >+ screencols++; >+ *destp++ = ' '; >+ } >+ *destp = '\0'; >+} >+ >+/* >+ * Like istrncpy but do not remove UTF-8 sequencies. >+ * >+ * The control char and escape sequence filter is also not active inside >+ * UTF-8 sequencies because UTF-8 requires bytes in the range from 0x80 >+ * to 0x9f to be processed. If a series of not recognized characters in >+ * the range of 0x80 to 0xff is encountered, '?' is copied. >+ */ >+static char * >+utf8_istrncpy(dest, cp, length) >+ char *dest; >+ char *cp; /* const */ >+ int length; >+{ >+ char *chp, *destp = dest; >+ int seq = 0; >+ unsigned char utf_seq[7] = ""; >+ >+ *destp = '\0'; >+ for(; length > 0 && *cp; cp++){ >+ if((chp = check_utf8(cp, utf_seq, sizeof(utf_seq))) == NULL) { >+ seq = 1; >+ continue; >+ } >+ if(chp != cp){ >+ seq = 0; >+ if(*chp == ' ') >+ chp++; >+ if(strlen(chp) < length){ >+ while(*chp && length--) >+ *destp++ = *chp++; >+ *destp = '\0'; >+ continue; >+ } >+ while(length--) >+ *destp++ = '.'; >+ *destp = '\0'; >+ break; >+ } >+ if(seq){ >+ *destp++ = '?'; >+ length--; >+ seq = 0; >+ } >+ if(*cp && FILTER_THIS(*cp) >+ && !(*(cp+1) && *cp == ESCAPE && match_escapes(cp+1))){ >+ if(length-- > 0){ >+ *destp++ = '^'; >+ >+ if(length-- > 0) >+ *destp++ = (*cp & 0x7f) + '@'; >+ } >+ } >+ else if(length-- > 0) >+ *destp++ = *cp; >+ *destp = '\0'; >+ } >+ >+ return dest; >+} >+ > > /*---------------------------------------------------------------------- > copy at most n chars of the source string onto the destination string >@@ -720,6 +868,10 @@ > /* src is either original source or the translation string */ > s = src; > >+ if(!ps_global->pass_ctrl_chars && ps_global->VAR_CHAR_SET >+ && !strucmp(ps_global->VAR_CHAR_SET, "UTF-8")) >+ return utf8_istrncpy(d, s, n); >+ > /* copy while escaping evil chars */ > do > if(*s && FILTER_THIS(*s)){ >@@ -748,6 +900,205 @@ > > > /* >+ * * * * * * * Character set translation helpers * * * * * * * * >+ */ >+ >+#ifdef HAVE_ICONV >+static iconv_t >+make_iconv_d(toset, fromset) >+ char *toset; >+ char *fromset; >+{ >+ iconv_t iconv_d; >+ char * tocode = NULL; >+ >+ /* make private copy of toset and append //TRANSLIT if feasible */ >+ if(strucmp(toset, "UTF-8")){ >+ tocode = (char *)fs_get((size_t)(strlen(toset)) + 11); >+ strcpy(tocode, toset); >+ strcat(tocode, "//TRANSLIT"); >+ } >+ >+ if((iconv_d = iconv_open(tocode?tocode:toset, fromset)) == (iconv_t)-1){ >+ dprint(7, (debugfile,"iconv open failed:")); >+ iconv_d = NULL; >+ } >+ dprint(7, (debugfile, "from %s to %s\n", fromset, toset)); >+ >+ /* free local copy for //TRANSLIT */ >+ if(tocode) >+ fs_give((void **) &tocode); >+ >+ return iconv_d; >+} >+ >+static >+iconv_t >+get_iconv_d(tocset, fromcset, local_iconvd) >+ char *tocset; >+ char *fromcset; >+ iconv_t *local_iconvd; >+{ >+ static char *s_fromcset = NULL, *s_tocset = NULL; >+ static iconv_t s_iconv_d = 0; >+ >+ /* no conversion if charset missing, from=ASCII or charets are equal */ >+ if(!tocset || (fromcset && tocset && !strucmp(fromcset, tocset))) >+ return NULL; >+ >+ dprint(6, (debugfile,"charsets %s -> %s\n", fromcset, tocset)); >+ >+ fromcset = resolve_charset_alias(fromcset, >+ ps_global->VAR_CHAR_SET_ALIASES); >+ fromcset = resolve_charset_alias(fromcset, >+ ps_global->VAR_ICONV_ALIASES); >+ tocset = resolve_charset_alias(tocset, >+ ps_global->VAR_CHAR_SET_ALIASES); >+ tocset = resolve_charset_alias(tocset, >+ ps_global->VAR_ICONV_ALIASES); >+ >+ if(local_iconvd){ >+ if (strucmp(fromcset, US_ASCII_CHARSET)) >+ *local_iconvd = make_iconv_d(tocset, fromcset); >+ return NULL; >+ } >+ >+ if(s_iconv_d && !strucmp(fromcset, US_ASCII_CHARSET) >+ && s_tocset && !strucmp(s_tocset, tocset)) { >+ dprint(6, (debugfile,"use charsets %s -> %s\n", s_fromcset, tocset)); >+ iconv(s_iconv_d, NULL, NULL, NULL, NULL); >+ } else { >+ >+ if (ps_global->VAR_ASSUMED_CHAR_SET >+ && (!fromcset || !*fromcset || !strucmp(UNKNOWN_CHARSET, fromcset))) >+ fromcset = ps_global->VAR_ASSUMED_CHAR_SET; >+ >+ if(!strucmp(fromcset, US_ASCII_CHARSET)) >+ return NULL; >+ >+ if(s_fromcset && strucmp(s_fromcset, fromcset)) >+ fs_give((void **)&s_fromcset); >+ >+ if(s_tocset && strucmp(s_tocset, tocset)) >+ fs_give((void **)&s_tocset); >+ >+ if(!s_fromcset || !s_tocset) { >+ if (s_iconv_d) >+ iconv_close(s_iconv_d); >+ s_fromcset = cpystr(fromcset); >+ s_tocset = cpystr(tocset); >+ s_iconv_d = make_iconv_d(tocset, fromcset); >+ } >+ else if(s_iconv_d) >+ iconv(s_iconv_d, NULL, NULL, NULL, NULL); >+ } >+ >+ return s_iconv_d; >+} >+#endif >+ >+/* >+ * Like sstrncpy, but with charset conversion(if possible) and null termination. >+ * *dest is left pointing a the terminating zero byte. It will not write >+ * more than length bytes. To copy the whole string, the output buffer and >+ * the length passed must be strlen(source)+1 in order to get a full copy. >+ * >+ * fromcset -- charset to convert from >+ * tocset -- charset ro convert to >+ * **dest -- address of a pointer which points to the destination buffer >+ * *src -- address of the start of the rfc2047-decoded source buffer >+ * len -- maximum number of bytes to write at **dest and increase *dest >+ * __including__ the terminating null. >+ */ >+void >+conv_sstrncpy(fromcset, tocset, dest, src, length) >+ char *fromcset; >+ char *tocset; >+ char **dest; >+ char *src; >+ size_t length; >+{ >+#ifdef HAVE_ICONV >+ iconv_t iconv_desc = NULL; >+ >+ if((!fromcset || !*fromcset) && (!tocset || !*tocset)) >+ goto noconv; >+ >+ fromcset = (fromcset && *fromcset) ? fromcset : ps_global->VAR_CHAR_SET; >+ tocset = (tocset && *tocset) ? tocset : ps_global->VAR_CHAR_SET; >+ >+ iconv_desc = get_iconv_d(tocset, fromcset, NULL); >+ >+ if(iconv_desc){ >+ size_t inbytesleft = strlen(src); >+ char * buf = *dest; int ret; >+ >+ length--; /* reserve a byte for '\0' */ >+ ret = iconv(iconv_desc, &src, &inbytesleft, dest, &length); >+ **dest = '\0'; /* terminate the output string */ >+ dprint(9, (debugfile, "iconv ret=%3d: >%s<\n", ret, buf)); >+ return; >+ } >+#endif >+noconv: >+ dprint(9, (debugfile,"no convert: >%s<(%d)\n", src, length)); >+ sstrncpy(dest, src, length); >+ **dest = '\0'; /* ensure that the output string is terminated */ >+} >+ >+unsigned char* >+resolve_charset_alias(cs, aliases) >+ char *cs; >+ char **aliases; >+{ >+ int i; >+ char *bdry; >+ >+ if(!aliases) >+ return cs; >+ for(i=0; aliases[i] && *(aliases[i]); i++) >+ if(bdry=strchr(aliases[i],':')){ >+ *bdry='\0'; >+ if (!strucmp(aliases[i], cs)) { >+ *bdry=':'; >+ return *(bdry+1) ? bdry+1 : cs; >+ } >+ *bdry=':'; >+ } >+ return cs; >+} >+ >+#ifdef HAVE_ICONV >+/* >+ * Converts the source string in fromcset to tocset and copy the result >+ * into allocated space. >+ * Caller is responsible for freeing the result. >+ */ >+unsigned char * >+trans_with_iconv(src, fromcset, tocset) >+ unsigned char *src; >+ char *fromcset; >+ char *tocset; >+{ >+ size_t len; >+ unsigned char *rv, *pstr; >+ if (!src) >+ return NULL; >+ >+ dprint(5, (debugfile, "translating from %s to %s\n",fromcset, tocset)); >+ >+ /* >+ * XXX: multiplier of 5 should be sufficient for virtually all >+ * cases (EUC-JP -> ISO-2022-JP) >+ */ >+ len = strlen((char *) src) * 5 + 1; >+ pstr = rv = (unsigned char *) fs_get(sizeof(char) * len); >+ conv_sstrncpy(fromcset, tocset, (char **) &pstr, src, len); >+ return rv; >+} >+#endif >+ >+/* > * Copies the source string into allocated space with the 8-bit EUC codes > * (on Unix) or the Shift-JIS (on PC) converted into ISO-2022-JP. > * Caller is responsible for freeing the result. >@@ -3205,12 +3556,35 @@ > char **)); > int rfc1522_valtok PROTO((int)); > int rfc1522_valenc PROTO((int)); >-int rfc1522_valid PROTO((char *, char **, char **, char **, >+int rfc1522_valid PROTO((char *, int, char **, char **, char **, > char **)); > char *rfc1522_8bit PROTO((void *, int)); > char *rfc1522_binary PROTO((void *, int)); > unsigned char *rfc1522_encoded_word PROTO((unsigned char *, int, char *)); > >+unsigned char * >+rfc2047_decode(d, len, s, charset) >+ unsigned char *d; >+ size_t len; /* length of d */ >+ char *s; >+ char **charset; >+{ >+ unsigned char *t; >+ char *assumed_charset = NULL; >+#ifdef HAVE_ICONV >+ /* >+ * reset VAR_ASSUMED_CHAR_SET temporarily avoid double conversions: >+ */ >+ assumed_charset = ps_global->VAR_ASSUMED_CHAR_SET; >+ if (ps_global->VAR_ASSUMED_CHAR_SET && *(ps_global->VAR_ASSUMED_CHAR_SET)) >+ ps_global->VAR_ASSUMED_CHAR_SET = UNKNOWN_CHARSET; >+#endif >+ t = rfc1522_decode(d, len, s, charset); >+#ifdef HAVE_ICONV >+ ps_global->VAR_ASSUMED_CHAR_SET = assumed_charset; >+#endif >+ return t; >+} > > /* > * rfc1522_decode - try to decode the given source string ala RFC 2047 >@@ -3253,6 +3627,7 @@ > unsigned long l; > int i, described_charset_once = 0; > int translate_2022_jp = 0; >+ unsigned char *cset_r; /* cset with alias resolution */ > > *d = '\0'; /* init destination */ > if(charset) >@@ -3260,7 +3635,7 @@ > > while(s && (sw = strstr(s, RFC1522_INIT))){ > /* validate the rest of the encoded-word */ >- if(rfc1522_valid(sw, &cset, &enc, &txt, &ew)){ >+ if(rfc1522_valid(sw, 1, &cset, &enc, &txt, &ew)){ > if(!rv) > rv = d; /* remember start of dest */ > >@@ -3293,6 +3668,7 @@ > if(lang = strchr(cset, '*')) > *lang++ = '\0'; > >+ cset_r =resolve_charset_alias(cset,ps_global->VAR_CHAR_SET_ALIASES); > /* Insert text explaining charset if we don't know what it is */ > if(!strucmp((char *) cset, "iso-2022-jp")){ > translate_2022_jp++; >@@ -3327,6 +3703,8 @@ > if(!cs) > cs = cpystr(cset); > >+ if (!ps_global->VAR_CHAR_SET) { >+ /* We don't know where to convert to, so do a charset tag: */ > if(charset){ > if(!*charset) /* only write first charset */ > *charset = cpystr(cset); >@@ -3343,6 +3721,7 @@ > *d++ = SPACE; > } > } >+ } > } > > /* based on encoding, write the encoded text to output buffer */ >@@ -3368,12 +3747,8 @@ > q = NULL; > > if(p = rfc822_qprint((unsigned char *)txt, strlen(txt), &l)){ >- strncpy((char *) d, (char *) p, min(l,len-1-(d-rv))); >- d[min(l,len-1-(d-rv))] = '\0'; >+ conv_sstrncpy(cset_r, NULL, &d, p, len-(d-rv)); > fs_give((void **)&p); /* free encoded buf */ >- d += l; /* advance dest ptr to EOL */ >- if(d-rv > len-1) >- d = rv+len-1; > } > else{ > if(q) >@@ -3403,12 +3778,8 @@ > * embedded nulls don't make sense in this context and > * won't work correctly anyway, it is really a no-op. > */ >- strncpy((char *) d, (char *) p, min(l,len-1-(d-rv))); >- d[min(l,len-1-(d-rv))] = '\0'; >+ conv_sstrncpy(cset_r, NULL, &d, p, len-(d-rv)); > fs_give((void **)&p); /* free encoded buf */ >- d += l; /* advance dest ptr to EOL */ >- if(d-rv > len-1) >- d = rv+len-1; > } > else > goto bogus; >@@ -3435,28 +3806,30 @@ > else{ > > /* >- * Found intro, but bogus data followed, treat it as normal text. >+ * Found intro, but bogus data followed, copy it and continue. > */ >- >+#ifdef HAVE_ICONV >+ if (!rv) >+ rv=d; /* remember start of dest */ >+#endif >+ l = min(len-(d-rv),(sw-s)+ RFC1522_INIT_L); /* data to copy */ > /* if already copying to destn, copy it */ >- if(rv){ >- strncpy((char *) d, s, >- (int) min((l = (sw - s) + RFC1522_INIT_L), >- len-1-(d-rv))); >- d += l; /* advance d, tie off text */ >- if(d-rv > len-1) >- d = rv+len-1; >- *d = '\0'; >- s += l; /* advance s beyond intro */ >- } >- else /* probably won't have to copy it at all, wait */ >- s += ((sw - s) + RFC1522_INIT_L); >+ if(rv) >+ conv_sstrncpy(ps_global->VAR_ASSUMED_CHAR_SET, NULL, >+ (char **)&d, s, (int) l); >+ s += l; /* advance s beyond intro */ > } > } > >- if(rv && *s) /* copy remaining text */ >- strncat((char *) rv, s, len - 1 - strlen((char *) rv)); >- >+#ifdef HAVE_ICONV >+ if (!rv) >+ rv=d; /* remember start of dest */ >+#endif >+ if (rv && s) >+ conv_sstrncpy(ps_global->VAR_ASSUMED_CHAR_SET, NULL, >+ (char **)&d, s, len - strlen((char *)rv)); >+ >+#ifndef HAVE_ICONV /* with iconv, we are done, we have converted during copy */ > if(translate_2022_jp){ > char *qq; > >@@ -3511,6 +3884,7 @@ > } > } > } >+#endif > > if(cs) > fs_give((void **) &cs); >@@ -3580,10 +3954,14 @@ > > /* > * rfc1522_valid - validate the given string as to it's rfc1522-ness >+ * if relaxchk is true, double the maximum length of an encoded word. >+ * this is necessary to decode overlong encoded words generated by >+ * numerous non-compliant implementations of RFC 2047 (1522). > */ > int >-rfc1522_valid(s, charset, enc, txt, endp) >+rfc1522_valid(s, relaxchk, charset, enc, txt, endp) > char *s; >+ int relaxchk; > char **charset; > char **enc; > char **txt; >@@ -3595,7 +3973,11 @@ > rv = rfc1522_token(c = s+RFC1522_INIT_L, rfc1522_valtok, RFC1522_DLIM, &e) > && rfc1522_token(++e, rfc1522_valtok, RFC1522_DLIM, &t) > && rfc1522_token(++t, rfc1522_valenc, RFC1522_TERM, &p) >- && p - s <= RFC1522_MAXW; >+ && p - s <= RFC1522_MAXW * (relaxchk ? 2 : 1); >+ /* >+ * relax the length condition by doubling the max length of an >+ * encoded word. It's is needed for some longer encoded words. >+ */ > > if(charset) > *charset = c; >@@ -3646,7 +4028,7 @@ > } > else if(*p == RFC1522_INIT[0] > && !strncmp((char *) p, RFC1522_INIT, RFC1522_INIT_L)){ >- if(rfc1522_valid((char *) p, NULL, NULL, NULL, (char **) &q)) >+ if(rfc1522_valid((char *) p, 0, NULL, NULL, NULL, (char **) &q)) > p = q + RFC1522_TERM_L - 1; /* advance past encoded gunk */ > } > else if(*p == ESCAPE && match_escapes((char *)(p+1))){ >@@ -3823,6 +4205,27 @@ > CHARSET *from, *to; > static CONV_TABLE null_tab; > >+#ifndef HAVE_ICONV >+ /* >+ * Another idea would be to check if the subject had charset tags >+ * and use this charset (we could use the last charset variable from >+ * conv_sstrcpy() in mailview.c) >+ */ >+ if (ps_global->VAR_ASSUMED_CHAR_SET >+ && (!from_cs || !*from_cs || !strucmp(UNKNOWN_CHARSET, from_cs) >+ || !strucmp(US_ASCII_CHARSET, from_cs))) >+ from_cs = ps_global->VAR_ASSUMED_CHAR_SET; >+ >+ /* >+ * Lets do user-specified charset aliasing before starting work: >+ */ >+ from_cs = resolve_charset_alias(from_cs, ps_global->VAR_CHAR_SET_ALIASES); >+ to_cs = resolve_charset_alias(to_cs, ps_global->VAR_CHAR_SET_ALIASES); >+#endif >+ >+ /* >+ * Check if we need conversion for this pair. If not, it's easy: >+ */ > if(!(from_cs && *from_cs && to_cs && *to_cs) || !strucmp(from_cs, to_cs)){ > memset(&null_tab, 0, sizeof(null_tab)); > null_tab.quality = CV_NO_TRANSLATE_NEEDED; >@@ -3854,6 +4257,12 @@ > if(ct){ > if(ct->table && (ct->convert != gf_convert_utf8_charset)) > fs_give((void **) &ct->table); >+#ifdef HAVE_ICONV >+ if(ct->table && (ct->convert == gf_convert_utf8_charset)) { >+ iconv_close((iconv_t)ct->table); >+ ct->table = NULL; >+ } >+#endif > > if(ct->from_charset) > fs_give((void **) &ct->from_charset); >@@ -3868,6 +4277,16 @@ > > ct->from_charset = cpystr(from_cs); > ct->to_charset = cpystr(to_cs); >+#ifdef HAVE_ICONV >+ ct->convert = gf_convert_utf8_charset; >+ get_iconv_d(to_cs, from_cs, (iconv_t *)&ct->table); >+ ct->quality = ct->table ? CV_LOSES_SPECIAL_CHARS:CV_NO_TRANSLATE_POSSIBLE; >+// The code could be changed to falls thru if iconv fails for some reason, but >+// this should be also changed to use the quality info from the c-client >+// as a hint. >+// if (ct->table) >+// return(ct); >+#else > ct->quality = CV_NO_TRANSLATE_POSSIBLE; > > /* >@@ -4002,6 +4421,7 @@ > } > } > } >+#endif > > return(ct); > } >@@ -6106,7 +6526,7 @@ > SortOrder def_sort; > int def_sort_rev; > >- if(decode_sort(p, &def_sort, &def_sort_rev) != -1){ >+ 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); >@@ -9687,6 +10107,12 @@ > 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++; > >@@ -11480,3 +11906,35 @@ > > 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 -ru pine4.64/pine/takeaddr.c pine4.64.SuSE/pine/takeaddr.c >--- pine4.64/pine/takeaddr.c 2005-09-13 00:04:25.000000000 +0200 >+++ pine4.64.SuSE/pine/takeaddr.c 2006-02-14 14:45:23.000000000 +0100 >@@ -1784,10 +1784,12 @@ > 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}}; >@@ -1808,17 +1810,21 @@ > 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]){ >+ 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'; > } >- >- break; >+ 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, >--- pine4.64/imap/src/osdep/unix/maildir.h 1970-01-01 01:00:00.000000000 +0100 >+++ pine4.64.SuSE/imap/src/osdep/unix/maildir.h 2006-02-14 14:45:22.000000000 +0100 >@@ -0,0 +1,189 @@ >+/* >+ * 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); >+char *myrootdir (char *name); >+char *mdirpath (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); >+ >+/* Courier server support */ >+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); >+void courier_list_info(COURIER_S **cdirp, char *data, int i); >--- pine4.64/imap/src/osdep/unix/maildir.c 1970-01-01 01:00:00.000000000 +0100 >+++ pine4.64.SuSE/imap/src/osdep/unix/maildir.c 2006-02-14 14:45:25.000000000 +0100 >@@ -0,0 +1,2097 @@ >+/* >+ * Maildir driver for Pine4.63 >+ * >+ * Written by Eduardo Chappa <chappa@math.washington.edu> >+ * Last Update: August 03, 2005 >+ * >+ * The IMAP toolkit provided in this Distribution is >+ * Copyright 2004 University of Washington. >+ * The full text of our legal notices is contained in the file called >+ * CPYRIGHT, included with this Distribution. >+ */ >+ >+#include <stdio.h> >+#include <ctype.h> >+#include <errno.h> >+extern int errno; /* just in case */ >+#include "mail.h" >+#include "osdep.h" >+#include <pwd.h> >+#include <sys/stat.h> >+#include <sys/time.h> >+#include "maildir.h" >+#include "rfc822.h" >+#include "fdstring.h" >+#include "misc.h" >+#include "dummy.h" >+ >+/* Driver dispatch used by MAIL */ >+DRIVER maildirdriver = { >+ "md", /* driver name, yes it's md, not maildir */ >+ /* driver flags */ >+ DR_MAIL|DR_LOCAL|DR_NAMESPACE|DR_NOSTICKY, >+ (DRIVER *) NIL, /* next driver */ >+ maildir_valid, /* mailbox is valid for us */ >+ maildir_parameters, /* manipulate parameters */ >+ NIL, /* scan mailboxes */ >+ maildir_list, /* find mailboxes */ >+ maildir_lsub, /* find subscribed mailboxes */ >+ maildir_sub, /* subscribe to mailbox */ >+ maildir_unsub, /* unsubscribe from mailbox */ >+ maildir_create, /* create mailbox */ >+ maildir_delete, /* delete mailbox */ >+ maildir_rename, /* rename mailbox */ >+ mail_status_default, /* status of mailbox */ >+ maildir_open, /* open mailbox */ >+ maildir_close, /* close mailbox */ >+ maildir_fast, /* fetch message "fast" attributes */ >+ NIL, /* fetch message flags */ >+ NIL, /* fetch overview */ >+ NIL, /* fetch message structure */ >+ maildir_header, /* fetch message header */ >+ maildir_text, /* fetch message body */ >+ NIL, /* fetch partial message text */ >+ NIL, /* unique identifier */ >+ NIL, /* message number */ >+ NIL, /* modify flags */ >+ maildir_flagmsg, /* per-message modify flags */ >+ NIL, /* search for message based on criteria */ >+ NIL, /* sort messages */ >+ NIL, /* thread messages */ >+ maildir_ping, /* ping mailbox to see if still alive */ >+ maildir_check, /* check for new messages */ >+ maildir_expunge, /* expunge deleted messages */ >+ maildir_copy, /* copy messages to another mailbox */ >+ maildir_append, /* append string message to mailbox */ >+ NIL /* garbage collect stream */ >+}; >+ >+ >+DRIVER courierdriver = { >+ "mc", /* Why a separate driver? So that >+ createproto will work */ >+ /* driver flags */ >+ DR_MAIL|DR_LOCAL|DR_NAMESPACE|DR_NOSTICKY, >+ (DRIVER *) NIL, /* next driver */ >+ maildir_valid, /* mailbox is valid for us */ >+ maildir_parameters, /* manipulate parameters */ >+ NIL, /* scan mailboxes */ >+ courier_list, /* find mailboxes */ >+ maildir_lsub, /* find subscribed mailboxes */ >+ maildir_sub, /* subscribe to mailbox */ >+ maildir_unsub, /* unsubscribe from mailbox */ >+ maildir_create, /* create mailbox */ >+ maildir_delete, /* delete mailbox */ >+ maildir_rename, /* rename mailbox */ >+ mail_status_default, /* status of mailbox */ >+ maildir_open, /* open mailbox */ >+ maildir_close, /* close mailbox */ >+ maildir_fast, /* fetch message "fast" attributes */ >+ NIL, /* fetch message flags */ >+ NIL, /* fetch overview */ >+ NIL, /* fetch message structure */ >+ maildir_header, /* fetch message header */ >+ maildir_text, /* fetch message body */ >+ NIL, /* fetch partial message text */ >+ NIL, /* unique identifier */ >+ NIL, /* message number */ >+ NIL, /* modify flags */ >+ maildir_flagmsg, /* per-message modify flags */ >+ NIL, /* search for message based on criteria */ >+ NIL, /* sort messages */ >+ NIL, /* thread messages */ >+ maildir_ping, /* ping mailbox to see if still alive */ >+ maildir_check, /* check for new messages */ >+ maildir_expunge, /* expunge deleted messages */ >+ maildir_copy, /* copy messages to another mailbox */ >+ maildir_append, /* append string message to mailbox */ >+ NIL /* garbage collect stream */ >+}; >+ >+MAILSTREAM maildirproto = {&maildirdriver}; /* prototype stream */ >+MAILSTREAM courierproto = {&courierdriver}; /* prototype stream */ >+ >+void >+md_domain_name(void) >+{ >+ int i; >+ >+ strcpy(mdlocaldomain,mylocalhost ()); >+ for (i = 0; mdlocaldomain[i] ; i++) >+ if(mdlocaldomain[i] == '/') >+ mdlocaldomain[i] = '\057'; >+ else if (mdlocaldomain[i] == ':') >+ mdlocaldomain[i] = '\072'; >+} >+ >+char * >+myrootdir(char *name) >+{ >+return myhomedir(); >+} >+ >+char * >+mdirpath(void) >+{ >+ char *path = maildir_parameters(GET_INBOXPATH,NIL); >+ return path ? (*path ? path : ".") : "Maildir"; >+} >+ >+/* 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 = mdirpath(); >+ 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(myrootdir(name)) + >+ max(strlen(name), strlen(maildirpath)) > 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", myrootdir (name), >+ strncmp (ucase (strcpy (tmp, name)), "INBOX", 5) >+ ? name : maildirpath, >+ 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, myrootdir (*name), strlen(myrootdir(*name)))){ >+ (*name) += strlen(myrootdir(*name)); >+ 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 = mdirpath(); >+ 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 = mdirpath(); >+ 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]; >+ char realpat[MAILTMPLEN]; >+ int i; >+ char *maildirpath = mdirpath(); >+ >+ sprintf(curdir,"%s/%s/", myrootdir(pat), dir ? dir : maildirpath); >+ if (dp = opendir (curdir)){ >+ if (dir) sprintf (name,"%s%s/",MDPREFIX(CCLIENT),dir); >+ else strcpy (name, pat); >+ >+ if (level == 0 && !strpbrk(pat,"%*")){ >+ if(maildir_valid(pat)){ >+ i = maildir_contains_folder(pat, NULL) >+ ? LATT_HASCHILDREN >+ : (maildir_is_dir(pat, NULL) >+ ? LATT_HASNOCHILDREN : LATT_NOINFERIORS); >+ maildir_file_path(pat, realpat); >+ i += maildir_any_new_msgs(realpat) >+ ? LATT_MARKED : LATT_UNMARKED; >+ mm_list (stream,'/', pat, i); >+ } >+ else >+ mm_list (stream,'/', pat, 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", myrootdir(d->d_name), >+ (dir ? dir : maildirpath), 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]; >+ char fakepat[MAILTMPLEN]; >+ int i, j, scand; >+ long style = (long) maildir_parameters(GET_COURIERSTYLE, NIL); >+ char *maildirpath = mdirpath(); >+ COURIER_S *cdir; >+ >+ if(!strpbrk(pat,"%*")){ /* a mailbox */ >+ maildir_file_path(pat, curdir); >+ i = strlen(curdir) - 1; >+ if(curdir[i] == '/') >+ curdir[i] = '\0'; >+ cdir = courier_list_dir(curdir); >+ if(cdir){ >+ if(maildir_valid(curdir)){ >+ if(cdir->data[0]->name) >+ j = LATT_HASCHILDREN; >+ else >+ j = (style == COURIER) ? LATT_HASNOCHILDREN : LATT_NOINFERIORS; >+ } >+ else >+ j = LATT_NOSELECT; >+ j += maildir_any_new_msgs(curdir) ? LATT_MARKED : LATT_UNMARKED; >+ mm_list (stream, '.',pat, j); >+ courier_free_cdir(&cdir); >+ } >+ return; >+ } >+ >+ strcpy(tmp,pat + 4); /* a directory */ >+ 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", (dir ? "" : myrootdir(pat)), (dir ? "" : "/"), >+ (dir ? realname : maildirpath), (dir ? "" : ".")); >+ sprintf(tmp, "%s%s/.", MDPREFIX(COURIER), dir ? dir : maildirpath); >+ 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); >+ courier_list_info(&cdir, tmp, i); >+ 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 = mdirpath(); >+ >+ maildir_file_path(dirname, tmp2); >+ if(name){ >+ strcat(tmp2,"/"); >+ strcat(tmp2, 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 = mdirpath(); >+ >+ maildir_file_path(dirname, tmp); >+ if(name){ >+ strcat(tmp,"/"); >+ strcat(tmp,name); >+ } >+ strcat(tmp,"/"); >+ strcat(tmp,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 = localtime (&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 *)); >+ memset(cdir->data, 0, 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 = NULL; >+ char tmp[MAILTMPLEN], tmp2[MAILTMPLEN], pathname[MAILTMPLEN], >+ realname[MAILTMPLEN]; >+ char *maildirpath = mdirpath(); >+ int i, j, scand, td; >+ >+ /* 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++){ >+ td = realname[strlen(realname) - 1] == '.' >+ && *names[i]->d_name == '.'; >+ sprintf(tmp2,"%s%s", tmp, names[i]->d_name+1); >+ sprintf(pathname,"%s%s", realname, names[i]->d_name + td); >+ 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; >+ } >+ if(cdir->total == 0) >+ courier_free_cdir(&cdir); >+ return cdir; >+} >+ >+void >+courier_list_info(COURIER_S **cdirp, char *data, int i) >+{ >+ long style = (long) maildir_parameters(GET_COURIERSTYLE, NIL); >+ COURIER_S *cdir = *cdirp; >+ >+ if(maildir_valid(cdir->data[i]->name)){ >+ if(courier_search_list(cdir->data, data, 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; >+} >--- pine4.64/pine/rules.c 1970-01-01 01:00:00.000000000 +0100 >+++ pine4.64.SuSE/pine/rules.c 2006-02-14 14:45:24.000000000 +0100 >@@ -0,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 = 0; >+ 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 -rNu pine4.64/pine/rules.h pine4.64.SuSE/pine/rules.h >--- pine4.64/pine/rules.h 1970-01-01 01:00:00.000000000 +0100 >+++ pine4.64.SuSE/pine/rules.h 2006-02-14 14:45:23.000000000 +0100 >@@ -0,0 +1,204 @@ >+#include "headers.h" >+#ifndef _REGEX_H_ >+#include <regex.h> >+#endif >+ >+int is_save; /* this rule has the form condition -> folder */ >+typedef struct { >+ char *value; >+ int type; >+} RULE_ACTION; >+ >+ >+RULE_RESULT *get_result_rule PROTO ((int, int, ENVELOPE *)); >+char *test_rule PROTO ((RULELIST *, int, ENVELOPE *, int *)); >+char *process_rule PROTO ((RULE_S *, int, ENVELOPE *)); >+int test_condition PROTO ((CONDITION_S *, int, ENVELOPE *)); >+int test_in PROTO ((CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int)); >+int test_ni PROTO ((CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int)); >+int test_not_in PROTO ((CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int)); >+int test_not_ni PROTO ((CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int)); >+int test_eq PROTO ((CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int)); >+int test_not_eq PROTO ((CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int)); >+char *trim PROTO ((RULEACTION_S *, int, ENVELOPE *)); >+char *rextrim PROTO ((RULEACTION_S *, int, ENVELOPE *)); >+char *raw_value PROTO ((RULEACTION_S *, int, ENVELOPE *)); >+char *extended_value PROTO ((RULEACTION_S *, int, ENVELOPE *)); >+char *expand PROTO((char *, char *)); >+char *get_name_token PROTO((char *)); >+char *advance_to_char PROTO ((char *, char, int, int *)); >+ >+/* Separators: >+ * >+ * A separator is a string that separates the rule condition with the rule >+ * action. Below is the list of separators >+ * >+ */ >+ >+#define SAVE_TO_SEP "->" >+#define APPLY_SEP "=>" >+ >+/*------- Definitions of tokens -------*/ >+/*------ Keep the list alphabetically sorted, thanks -------*/ >+ >+#define ADDR_TOKEN "_ADDRESS_" >+#define ADDCC_TOKEN "_ADDRESSCC_" >+#define ADDRECIP_TOKEN "_ADDRESSRECIPS_" >+#define ADDTO_TOKEN "_ADDRESSTO_" >+#define BCC_TOKEN "_BCC_" >+#define CC_TOKEN "_CC_" >+#define COLLECT_TOKEN "_COLLECTION_" >+#define FLAG_TOKEN "_FLAG_" >+#define FOLDER_TOKEN "_FOLDER_" >+#define FADDRESS_TOKEN "_FORWARDADDRESS_" >+#define FFROM_TOKEN "_FORWARDFROM_" >+#define FROM_TOKEN "_FROM_" >+#define LCC_TOKEN "_LCC_" >+#define NICK_TOKEN "_NICK_" >+#define ROLE_TOKEN "_ROLE_" >+#define SEND_TOKEN "_SENDER_" >+#define SUBJ_TOKEN "_SUBJECT_" >+#define THDDSPSTY_TOKEN "_THREADSTYLE_" >+#define THDNDXSTY_TOKEN "_THREADINDEX_" >+#define TO_TOKEN "_TO_" >+ >+/* Mail related tokens >+ * >+ * The following is an array with the list of tokens. >+ */ >+ >+char* token_rules[] = { >+ FROM_TOKEN, >+ NICK_TOKEN, >+ ROLE_TOKEN, >+ FOLDER_TOKEN, >+ SUBJ_TOKEN, >+ THDDSPSTY_TOKEN, >+ THDNDXSTY_TOKEN, >+ FLAG_TOKEN, >+ COLLECT_TOKEN, >+ THDDSPSTY_TOKEN, >+ ADDR_TOKEN, >+ TO_TOKEN, >+ ADDTO_TOKEN, >+ ADDCC_TOKEN, >+ ADDRECIP_TOKEN, >+ SEND_TOKEN, >+ CC_TOKEN, >+ LCC_TOKEN, >+ BCC_TOKEN, >+ FFROM_TOKEN, >+ FADDRESS_TOKEN, >+ NULL >+}; >+ >+#define NTOKENS (sizeof(token_rules)/sizeof(token_rules[0]) - 1) >+ >+/*------ Definitions of relational operands -------------*/ >+ >+typedef struct { >+ char *value; >+ TestType ttype; >+ int (*execute)(); >+} REL_TOKEN; >+ >+/* Relational Operands */ >+#define AND_REL "&&" /* For putting more than one condition */ >+#define IN_REL "<<" /* For belonging relation */ >+#define NI_REL ">>" /* For contain relation */ >+#define NOT_IN_REL "!<" /* Negation of IN_REL */ >+#define NOT_NI_REL "!>" /* Negation of NI_REL */ >+#define EQ_REL "==" /* Test of equality */ >+#define NOT_EQ_REL "!=" /* Test of inequality */ >+#define OPEN_SET "{" /* Braces to open a set */ >+#define CLOSE_SET "}" /* Braces to close a set*/ >+ >+REL_TOKEN rel_rules_test[] = { >+ {EQ_REL, Equal, test_eq}, >+ {IN_REL, Subset, test_in}, >+ {NI_REL, Includes, test_ni}, >+ {NOT_EQ_REL, NotEqual, test_not_eq}, >+ {NOT_IN_REL, NotSubset, test_not_in}, >+ {NOT_NI_REL, NotIncludes, test_not_ni}, >+ {NULL, EndTypes, NULL} >+}; >+ >+#define NREL (sizeof(rel_rules_test)/sizeof(rel_rules_test[0]) - 1) >+ >+/*--- Context in which these variables can be used ---*/ >+ >+typedef struct use_context { >+ char *name; >+ int what_for; >+} USE_IN_CONTEXT; >+ >+ >+static USE_IN_CONTEXT tokens_use[] = { >+ {NICK_TOKEN, FOR_SAVE}, >+ {FROM_TOKEN, FOR_SAVE}, >+ {ROLE_TOKEN, FOR_COMPOSE}, >+ {FOLDER_TOKEN, FOR_SAVE|FOR_FOLDER|FOR_THREAD}, >+ {SUBJ_TOKEN, FOR_SAVE|FOR_FOLDER}, >+ {FLAG_TOKEN, FOR_SAVE|FOR_FLAG}, >+ {COLLECT_TOKEN, FOR_SAVE|FOR_COMPOSE|FOR_FOLDER|FOR_THREAD}, >+ {THDDSPSTY_TOKEN, FOR_THREAD}, >+ {THDNDXSTY_TOKEN, FOR_THREAD}, >+ {ADDR_TOKEN, FOR_SAVE|FOR_FOLDER}, >+ {TO_TOKEN, FOR_SAVE}, >+ {ADDTO_TOKEN, FOR_SAVE|FOR_COMPOSE}, >+ {ADDCC_TOKEN, FOR_SAVE|FOR_COMPOSE}, >+ {ADDRECIP_TOKEN, FOR_SAVE|FOR_COMPOSE}, >+ {SEND_TOKEN, FOR_SAVE}, >+ {CC_TOKEN, FOR_SAVE}, >+ {BCC_TOKEN, FOR_COMPOSE}, >+ {LCC_TOKEN, FOR_COMPOSE}, >+ {FFROM_TOKEN, FOR_COMPOSE}, >+ {FADDRESS_TOKEN, FOR_COMPOSE}, >+ {NULL, FOR_NOTHING} >+}; >+ >+ >+typedef struct { >+ char *name; >+ char* (*execute)(); >+ int what_for; >+} RULE_FCN; >+ >+#define INDEX_FCN "_INDEX_" >+#define REPLACE_FCN "_REPLACE_" >+#define REPLYSTR_FCN "_RESTR_" >+#define REPLY_FCN "_REPLY_" >+#define RESUB_FCN "_RESUB_" >+#define REXTRIM_FCN "_REXTRIM_" >+#define SAVE_FCN "_SAVE_" >+#define SIGNATURE_FCN "_SIGNATURE_" >+#define SMTP_FCN "_SMTP_" >+#define SORT_FCN "_SORT_" >+#define STARTUP_FCN "_STARTUP_" >+#define THRDSTYLE_FCN "_THREADSTYLE_" >+#define THRDINDEX_FCN "_THREADINDEX_" >+#define TRIM_FCN "_TRIM_" >+ >+ >+RULE_FCN rule_fcns[] = { >+{SAVE_FCN, extended_value, FOR_SAVE}, >+{REPLY_FCN, extended_value, FOR_REPLY_INTRO}, >+{TRIM_FCN, trim, FOR_TRIM | FOR_RESUB}, >+{REPLACE_FCN, extended_value, FOR_REPLACE}, >+{SORT_FCN, raw_value, FOR_SORT}, >+{INDEX_FCN, raw_value, FOR_INDEX}, >+{REPLYSTR_FCN, raw_value, FOR_COMPOSE}, >+{SIGNATURE_FCN, raw_value, FOR_COMPOSE}, >+{RESUB_FCN, extended_value, FOR_RESUB}, >+{STARTUP_FCN, raw_value, FOR_STARTUP}, >+{REXTRIM_FCN, rextrim, FOR_TRIM | FOR_RESUB}, >+{THRDSTYLE_FCN, raw_value, FOR_THREAD}, >+{THRDINDEX_FCN, raw_value, FOR_THREAD}, >+{SMTP_FCN, raw_value, FOR_COMPOSE} >+}; >+ >+#define NFCN (sizeof(rule_fcns)/sizeof(rule_fcns[0])) >+ >+#define STRICT 0x1 >+#define RELAXED 0x2 >+
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 236322
: 164195 |
164196