Submitted By: BLFS Book <blfs-book@linuxfromscratch.org>
Date: 2006-02-23
Initial Package Version: 4.64
Origin: http://www.suse.de/~bk/pine/4.64/2006-02-23/bigpatch.diff
Upstream Status: Mostly applied.
Description: Allows PINE UTF-8 and charset conversion

$LastChangedBy: bdubbs $
$Date: 2006-05-16 13:25:45 -0600 (Tue, 16 May 2006) $

--- 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 @@
 &lt;End of Configuration Notes&gt;
 </BODY>
 </HTML>
+====== h_patches ======
+<html>
+<head>
+<TITLE>Information on patches added to this release</TITLE>
+</head>
+<body>
+<H1>Information on patches added to this release</H1>
+<P>
+This version of Pine has been modified by including patches from
+<A HREF="http://www.math.washington.edu/~chappa/pine/">
+http://www.math.washington.edu/~chappa/pine/</A>. These patches include
+new features and bug fixes. More complete information on each patch
+included in this version can be found in the web.
+
+<P>If you have any problems with this release of Pine, please contact 
+Eduardo Chappa &lt;chappa@math.washington.edu&gt;. Include the word 
+&quot;Pine&quot; in the subject of the message to bypass spam filters.
+
+<P>The list of patches included in this release are:
+
+<P>New Features:
+
+<UL>
+ <LI> Maildir Patch. <A HREF="h_config_maildir">(more...)</A>
+ <LI> Enhanced fancy thread interface. 
+<A HREF="h_config_enhanced_thread">(more...)</A>
+ <LI> Pine justifies paragraphs with more than one level of indentation. 
+<A HREF="h_compose_justify">(more...)</A>
+ <LI> Rules patch, to make Pine flexible. 
+<A HREF="h_config_new_rules">(more...)</A>
+ <LI> Send mail from the command line.
+ <LI> Automatic check of new mail in incoming folders.
+<A HREF="h_config_enable_check_incoming">(more...)</A>
+ <LI> Write accents like &aacute;&eacute; or other foreing characters: &ntilde; etc.
+ <LI> Tab check folders on cycles.
+<A HREF="h_config_circular_tab">(more...)</A>
+ <LI> Get the number of new messages when opening a folder.
+ <LI> Reinsert the pattern you searched for last.
+ <LI> New Reply command menu.
+<A HREF="h_config_alt_reply_menu">(more...)</A>
+ <LI> Change your From header without any effort!
+ <LI> Choose a role when composing a message from a mailto: link.
+ <LI> Paint special text in the body of the message in any custom color.
+<A HREF="h_config_special_text_to_color">(more...)</A>
+ <LI> Select messages by the content of an arbitrary header.
+ <LI> Delete until the the end of a file, or message (press ^W^X).
+ <LI> Get the QUOTA information from an IMAP server (if such server supports
+   the QUOTA command).
+ <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 @@
 &lt;End of help on this topic&gt;
 </BODY>
 </HTML>
+======= h_thread_index_sort_arrival =======
+<HTML>
+<HEAD>
+<TITLE>SORT OPTION: Arrival</TITLE>
+</HEAD>
+<BODY>
+<H1>SORT OPTION: Arrival</H1>
+
+The <EM>Arrival</EM> sort option arranges threads according to the last 
+time that a message was added to it. In this order the last thread 
+contains the most recent message in the folder.
+
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+======= h_thread_index_sort_date =======
+<HTML>
+<HEAD>
+<TITLE>SORT OPTION: Date</TITLE>
+</HEAD>
+<BODY>
+<H1>SORT OPTION: Date</H1>
+
+The <EM>Date</EM> sort option in the THREAD&nbsp;INDEX screen is the same
+as sorting by thread, the most likely thing is that you won't see Pine
+sorting the folder, because it's already sorted.
+
+<P>
+On a folder like INBOX, sorting by &quot;Date&quot; should be almost
+identical to sorting by &quot;Arrival&quot;.
+
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+======= h_thread_index_sort_subj =======
+<HTML>
+<HEAD>
+<TITLE>SORT OPTION: Subject</TITLE>
+</HEAD>
+<BODY>
+<H1>SORT OPTION: Subject</H1>
+
+The <EM>Subject</EM> sort option has not been defined yet.
+
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+======= h_thread_index_sort_ordsubj =======
+<HTML>
+<HEAD>
+<TITLE>SORT OPTION: OrderedSubject</TITLE>
+</HEAD>
+<BODY>
+<H1>SORT OPTION: OrderedSubject</H1>
+
+The <EM>OrderedSubject</EM> sort option in the THREAD&nbsp;INDEX screen is
+the same as sorting by <A HREF="h_thread_index_sort_subj">Subject</A>.
+
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+======= h_thread_index_sort_thread =======
+<HTML>
+<HEAD>
+<TITLE>SORT OPTION: Thread</TITLE>
+</HEAD>
+<BODY>
+<H1>SORT OPTION: Thread</H1>
+
+The <EM>Thread</EM> sort option in the THREAD&nbsp;INDEX screen sorts all 
+messages by the proposed algorithm by Crispin and Murchison. In this 
+method of sorting once threads have been isolated they are sorted by the 
+date of their parents, or if that is missing, the first message in that 
+thread.
+
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+======= h_thread_index_sort_from =======
+<HTML>
+<HEAD>
+<TITLE>SORT OPTION: From</TITLE>
+</HEAD>
+<BODY>
+<H1>SORT OPTION: From</H1>
+
+The <EM>From</EM> sort option has not been defined yet.
+
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+======= h_thread_index_sort_size =======
+<HTML>
+<HEAD>
+<TITLE>SORT OPTION: Size</TITLE>
+</HEAD>
+<BODY>
+<H1>SORT OPTION: Size</H1>
+
+The <EM>Size</EM> sort option has not been defined yet.
+
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+======= h_thread_index_sort_score =======
+<HTML>
+<HEAD>
+<TITLE>SORT OPTION: Score</TITLE>
+</HEAD>
+<BODY>
+<H1>SORT OPTION: Score</H1>
+
+The <EM>Score</EM> sort option has not been defined yet.
+
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+======= h_thread_index_sort_to =======
+<HTML>
+<HEAD>
+<TITLE>SORT OPTION: To</TITLE>
+</HEAD>
+<BODY>
+<H1>SORT OPTION: To</H1>
+
+The <EM>To</EM> sort option has not been defined yet.
+
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+======= h_thread_index_sort_cc =======
+<HTML>
+<HEAD>
+<TITLE>SORT OPTION: Cc</TITLE>
+</HEAD>
+<BODY>
+<H1>SORT OPTION: Cc</H1>
+
+The <EM>Cc</EM> sort option has not been defined yet.
+
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
 ======= h_index_cmd_whereis =======
 <HTML>
 <HEAD>
@@ -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 &quot;&gt;&quot;.
+
+<P>
+Some other constructions of quote strings are recognized only if they
+appear enough in the text. For example &quot;Peter :&quot; is only
+recognized if it appears in two consecutive lines.
+
+<P> 
+Additionaly, Pine recognizes indent-strings and justifies text in a
+paragraph to the right of indent-string, padding with spaces if necessary.
+An indent string is one which you use to delimit elements of a list. For
+example, if you were to write a list of groceries, one may write:
+
+<UL>
+<LI> Fruit
+<LI> Bread
+<LI> Eggs
+</UL>
+
+<P> 
+In this case the character &quot;*&quot; is the indent-string. Pine
+recognizes numbers (0, 1, 2.5, etc) also as indent-strings, and certain
+combinations of spaces, periods, and parenthesis. In any case, numbers are
+recognized <B>ONLY</B> if the line preceeding the given line is empty or
+ends in one of the characters &quot;.&quot; or &quot;:&quot;.
+In addition to the explanation of what constitutes a paragraph above, a
+new paragraph is recognized when an indent-string is found in it (and
+validated according to the above stated rules).
+
+<P>
 &lt;End of help on this topic&gt;
 </BODY>
 </HTML>
@@ -17396,6 +17656,7 @@
 <A HREF="h_config_index_format">&quot;Index-Format&quot;</A> option,
 in the <A HREF="h_config_reply_intro">&quot;Reply-Leadin&quot;</A> option,
 in signature files,
+in the <A HREF="h_config_reply_leadin_rules">&quot;new-rules&quot; option</A>,
 in template files used in
 <A HREF="h_rules_roles">&quot;roles&quot;</A>, and in the folder name
 that is the target of a Filter Rule.
@@ -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, &quot;mailbox@domain&quot;.
 </DD>
 
+<DT>ADDRESSTO</DT>
+<DD>
+This is similar to the &quot;TO&quot; token, only it is always the
+email address of all people listed in the TO: field of the messages. Addresses
+are separated by a blank space. Example, &quot;mailbox@domain&quot; when
+the e-mail message contains only one person in the To: field, or
+&quot;peter@flintstones.com president@world.com&quot;.
+</DD>
+
 <DT>MAILBOX</DT>
 <DD>
 This is the same as the &quot;ADDRESS&quot; except that the 
@@ -17477,6 +17747,15 @@
 message's &quot;Cc:&quot; header field.
 </DD>
 
+<DT>ADDRESSCC</DT>
+<DD>
+This is similar to the &quot;CC&quot; token, only it is always the
+email address of all people listed in the Cc: field of the messages. Addresses
+are separated by a blank space. Example: &quot;mailbox@domain&quot; when
+the e-mail message contains only one person in the Cc: field, or
+&quot;peter@flintstones.com president@world.com&quot;.
+</DD>
+
 <DT>RECIPS</DT>
 <DD>
 This token represents the personal names (or email addresses if the names
@@ -17485,6 +17764,14 @@
 the message's &quot;Cc:&quot; header field.
 </DD>
 
+<DT>ADDRESSRECIPS</DT>
+<DD>
+This token represent the e-mail addresses of the people in the To: and
+Cc: fields, exactly in that order separated by a space. It is almost obtained
+by concatenating the ADDRESSTO and ADDRESSCC tokens.
+</DD>
+
+
 <DT>NEWSANDRECIPS</DT>
 <DD>
 This token represents the newsgroups from the
@@ -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>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
 ======= h_address_format =======
 <HTML>
 <HEAD>
@@ -20086,61 +20470,157 @@
 &lt;End of help on this topic&gt;
 </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 &quot;Literal-Signature&quot; by default.  However, if no
-&quot;Literal-Signature&quot; is defined and the file named in the
-&quot;Signature-File&quot; option exists, then the latter will be used
-instead.
 <P>
-
-The two character sequence &#92;n (backslash followed by
-the character n) will be used to signify a line-break in your signature.
-You don't have to enter the &#92;n, but it will be visible in the
-SETUP CONFIGURATION window after you are done editing the signature.
+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>
 &lt;End of help on this topic&gt;
 </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 &quot;Signature-File&quot; option will be ignored.
-You can tell that that is the case because the value of the
-&quot;Signature-File&quot; will show up as
-<P>
-<CENTER><SAMP>&lt;Ignored: using Literal-Signature instead&gt;</SAMP></CENTER>
+This version of Pine has been enhanced with Maildir support. This text is 
+intended to be a reference on its support.
+<P>
+
+A Maildir folder is a directory that contains three directories called 
+cur, tmp and new. A program that delivers mail (e.g. postfix) will put new 
+mail in the new directory. A program that reads mail will look for for old 
+messages in the cur directory, while it will look for new mail in the new 
+directory.
+<P>
+
+In order to use maildir support it is better to set your inbox-path to the 
+value &quot;#md/inbox&quot; (without quotes). This assumes that your mail 
+delivery agent is delivering new mail to ~/Maildir/new. If the directory 
+where new mail is being delivered is not called "Maildir", you can set the 
+name of the subdirectory of home where it is being delivered in the <A 
+HREF="h_config_maildir_location">maildir-location</A> configuration 
+variable. Most of the time you will not have to worry about the 
+maildir-location variable, because it will probably be set by your 
+administrator in the pine.conf configuration file.
+<P>
+
+One of the advantages of the Maildir support of this version of Pine is 
+that you do not have to stop using folders in another styles (mbox, mbx, 
+etc.). This is desirable since the usage of a specific mail storage system 
+is a personal decision. Folders in the maildir format that are part of the 
+Mail collection will be recognized without any extra configuration of your 
+part. If your mail/ collection is located under the mail/ directory, then 
+creating a new maildir folder in this collection is done by pressing "A" 
+and entering the string "#driver.md/mail/newfolder". Observe that adding a 
+new folder as "newfolder" may not create such folder in maildir format.
+
+<P>
+If you would like to have all folders created in the maildir format by 
+default, you do so by adding a Maildir Collection. In order to convert 
+your current mail/ collection into a maildir collection, edit the 
+collection and change the path variable from &quot;mail/&quot; to 
+&quot;#md/mail&quot;. In a maildir collection folders of any other format 
+are ignored.
+
+<P> Finally, This version also has 
+<A HREF="h_config_courier_list">support</A> for the Courier style file system 
+when a maildir collection is accessed locally.
+
+<P>
+<UL>   
+<LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+</UL><P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+====== h_config_literal_sig =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: Literal-Signature</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: Literal-Signature</H1>
+
+With this option your actual signature, as opposed to
+the name of a file containing your signature,
+is stored in the Pine configuration file.
+If this is defined it takes precedence over the Signature-File option.
+<P>
+
+This is simply a different way to store the signature.
+The signature is stored inside your Pine configuration file instead of in
+a separate file.
+Tokens work the same way they do with the
+<A HREF="h_config_signature_file">Signature-File</A> so look there for
+help.
+<P>
+
+The Setup/Signature command on Pine's Main Menu will edit
+the &quot;Literal-Signature&quot; by default.  However, if no
+&quot;Literal-Signature&quot; is defined and the file named in the
+&quot;Signature-File&quot; option exists, then the latter will be used
+instead.
+<P>
+
+The two character sequence &#92;n (backslash followed by
+the character n) will be used to signify a line-break in your signature.
+You don't have to enter the &#92;n, but it will be visible in the
+SETUP CONFIGURATION window after you are done editing the signature.
+
+<P>
+<UL>   
+<LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+</UL><P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+====== h_config_signature_file =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: Signature-File</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: Signature-File</H1>
+
+If a <A HREF="h_config_literal_sig">Literal-Signature</A> option is defined,
+then this &quot;Signature-File&quot; option will be ignored.
+You can tell that that is the case because the value of the
+&quot;Signature-File&quot; will show up as
+<P>
+<CENTER><SAMP>&lt;Ignored: using Literal-Signature instead&gt;</SAMP></CENTER>
 <P>
 You may either use all Literal Signatures (signatures stored in your
 configuration file) throughout Pine, or all signature files.
@@ -20853,6 +21333,41 @@
 &lt;End of help on this topic&gt;
 </BODY>
 </HTML>
+====== h_config_thread_sort_key =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: Thread-Sort-Key</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: Thread-Sort-Key</H1>
+
+This option determines the order in which threads will be displayed. You
+can choose from the following options.
+
+<P>
+<UL>
+ <LI> <A HREF="h_thread_index_sort_arrival">Arrival</A>
+<!-- <LI> <A HREF="h_thread_index_sort_date">Date</A>
+ <LI> <A HREF="h_thread_index_sort_subj">Subject</A>
+ <LI> <A HREF="h_thread_index_sort_ordsubj">OrderedSubj</A>-->
+ <LI> <A HREF="h_thread_index_sort_thread">Thread</A>
+<!-- <LI> <A HREF="h_thread_index_sort_from">From</A>
+ <LI> <A HREF="h_thread_index_sort_size">Size</A>
+ <LI> <A HREF="h_thread_index_sort_score">Score</A>
+ <LI> <A HREF="h_thread_index_sort_to">To</A>
+ <LI> <A HREF="h_thread_index_sort_cc">Cc</A>-->
+</UL>
+
+<P> Each type of sort may also be reversed. Normal default is by
+&quot;Thread&quot;.
+
+<P>
+<UL>   
+<LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+</UL><P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
 ====== h_config_other_startup =====
 <HTML>
 <HEAD>
@@ -21001,6 +21516,650 @@
 &lt;End of help on this topic&gt;
 </BODY>
 </HTML>
+====== h_config_compose_rules =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: Compose-Rule</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: Compose-Rule</H1>
+
+<P> At this time, this option is used to generate values for signature
+files that is not possible to do with the use of 
+<A HREF="h_rules_roles">roles</A>.
+
+<P> For example, you can have a rule like:<BR>
+_TO_ >> {Peter Flinstones} => _SIGNATURE_{~/.petersignature}
+
+<P> This configuration option is just one of many that allow you to
+override the value of some global configurations within Pine. There is a
+help text explaining how to define all of them, which you can read by
+following this <A HREF="h_config_new_rules">link</A>.
+
+<P>&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+====== h_config_forward_rules =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: Forward-Rule</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: Forward-Rule</H1>
+
+<P> At this time this option can be used to trim values of some fields,
+for example it can be used in the following way:
+
+<P>
+_ROLE_ == {work} => _LCC_ := _TRIM_{_FORWARDFROM_ <_FORWARDADDRESS_>}
+
+<P> This configuration option is just one of many that allow you to
+override the value of some global configurations within Pine. There is a
+help text explaining how to define all of them, which you can read by
+following this <A HREF="h_config_new_rules">link</A>.
+
+<P>&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+====== h_config_index_rules =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: Index-Rule</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: Index-Rule</H1>
+
+<P> This option is used to supercede the value of the option <A
+HREF="h_config_index_format">index-format</A> for specific folders. In
+this form you can have different index-formats for different folders. For
+example an entry here may be:
+
+<P>
+_FOLDER_ == {INBOX} => _INDEX_{IMAPSTATUS DATE FROM(33%) SIZE SUBJECT(67%)}
+
+<P> This configuration option is just one of many that allow you to
+override the value of some global configurations within Pine. There is a
+help text explaining how to define all of them, which you can read by
+following this <A HREF="h_config_new_rules">link</A>.
+
+<P>&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+====== h_config_replace_rules =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: Replace-Rule</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: Replace-Rule</H1>
+
+<P> This option is used to have Pine print different values for specific 
+tokens in the <A HREF="h_config_index_format">index-format</A>. For example you
+can replace strings like "To: newsgroup" by your name.
+
+<P> Here are examples of possible rules:<BR>
+_FOLDER_ != {sent-mail} && _NICK_ != {} => _FROM_ := _REPLACE_{_FROM_ (_NICK_)}
+
+<P> or if you receive messages with tags that contain arbitrary numbers, and
+you want them removed from the index (but not from the subject), use a rule
+like the following<BR>
+_FOLDER_ == {INBOX} => _SUBJECT_ := _REXTRIM_{&#92;[some-tag-here #[0-9].*&#92;]}
+
+<P> You can also use this configuration option to remove specific strings of
+the index display screen, so that you can trim unnecessary information in
+your index.
+
+<P> This configuration option is just one of many that allow you to
+override the value of some global configurations within Pine. There is a
+help text explaining how to define all of them, which you can read by
+following this <A HREF="h_config_new_rules">link</A>.
+
+<P>&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+====== h_config_reply_leadin_rules =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: Reply-Leadin-Rule</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: Reply-Leadin-Rule</H1>
+
+<P> This option is used to have Pine generate a different 
+<A HREF="h_config_reply_intro">reply-leadin</A> string dependent either on
+the person you are replying to, or the folder where the message is being
+replied is in, or both.
+
+<P> Here there are examples of how this can be used. One can use the definition
+below to post to newsgroups and the pine-info mailing list, say:
+<P>
+_FOLDER_ << {pine-info;_NEWS_} => _REPLY_{*** _FROM_ _ADDRESS_("_FROM_"  "" "(_ADDRESS_) ")wrote in_NEWS_("" " the" "") _FOLDER_ _NEWS_("" "list " "")_SMARTDATE_("Today" "today" "on _LONGDATE_"):}
+
+<P> Here there is an example that one can use to change the reply indent string
+to reply people that speak spanish.
+<P>
+_FROM_{Condorito;Quico} => _REPLY_{*** _FROM_ (_ADDRESS_) escribi&oacute; _SMARTDATE_("Today" "hoy" "en _LONGDATE_"):}
+
+<P> This configuration option is just one of many that allow you to
+override the value of some global configurations within Pine. There is a
+help text explaining how to define all of them, which you can read by
+following this <A HREF="h_config_new_rules">link</A>.
+
+<P>&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+====== h_config_resub_rules =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: Replace-Subject-Rule</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: Replace-Subject-Rule</H1>
+
+<P> This option is used to have Pine generate a different subject when
+replying rather than the one Pine would generate automatically. 
+
+<P> Here there are a couple of examples about how to use this
+configuration option:
+
+<P> In order to have messages with empty subject to be replied with the message
+"your message" use the rule<BR>
+<center>_SUBJECT_ == {} => _RESUB_{Re: your message}</center>
+
+<P> If you want to trim some parts of the subject when you reply use the
+rule<BR> 
+<center>_SUBJECT_ >> {[one];two} => _SUBJECT_ := _TRIM_{[;];two}</center> 
+
+<P>this rule removes the brackets "[" and "]" whenever the string "[one]"
+appears in it, it also removes the word "two" from it.
+
+<P>Another example where you may want to use this rule is when you 
+correspond with people that change the reply string from &quot;Re:&quot; 
+to &quot;AW:&quot; or &quot;Sv:&quot;. In this case a rule like<BR>
+<center>_SUBJECT_ >> {Sv: ;AW: } => _SUBJECT_ := _TRIM_{Sv: ;AW: }</center> 
+<P>
+would eliminate undesired strings in replies.
+
+<P> You can also use this configuration option to customize reply subjects
+according to the sender of the message.
+
+<P> This configuration option is just one of many that allow you to
+override the value of some global configurations within Pine. There is a
+help text explaining how to define all of them, which you can read by
+following this <A HREF="h_config_new_rules">link</A>.
+
+<P>&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+====== h_config_sort_rules =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: Sort-Rule</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: Sort-Rule</H1>
+
+<P> This option is used to have Pine sort different folders in different orders
+and thus override the value already set in the
+<A HREF="h_config_sort_key">sort-key</A> configuration option.
+
+<P> Here's an example of the way it can be used. In this case all incoming
+folders are mailing lists, except for INBOX, so we sort INBOX by arrival
+(which is the default type of sort), but we want all the rest of mailing
+lists and newsgroups to be sorted by thread.
+
+<P>
+_COLLECTION_ >> {Incoming-Folders;News} && _FOLDER_ != {INBOX} => _SORT_{tHread}
+
+<P> Another example could be<BR>
+_FOLDER_ == {Mailing List} => _SORT_{Reverse tHread}
+
+<P> This configuration option is just one of many that allow you to
+override the value of some global configurations within Pine. There is a
+help text explaining how to define all of them, which you can read by
+following this <A HREF="h_config_new_rules">link</A>.
+
+<P>&lt;End of help on this topic&gt;
+
+</BODY>
+</HTML>
+====== h_config_save_rules =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: Save-Rules</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: Save-Rules</H1>
+
+<P> This option is used to specify which folder should be used to save a
+message depending either on the folder the message is in, who the message
+is from, or text that the message contains in specific headers (Cc:,
+Subject:, etc).
+
+<P> If this option is set and the 
+<A HREF="h_config_auto_read_msgs">auto-move-read-msgs</A> configuration
+option is also set then these definitions will be used to move messages
+from your INBOX when exiting Pine.
+
+<P>Here there are some examples<BR>
+_FLAG_ >> {D} -> Trash<BR>
+_FROM_ == {U2} -> Bono<BR>
+_FOLDER_ == {comp.mail.pine} -> pine-stuff<BR>
+_NICK_ != {} -> _NICK_/_NICK_<BR>
+_DATEISO_ >> {02-10;02-11} -> archive-oct-nov-2002
+
+<P> This configuration option is just one of many that allow you to
+override the value of some global configurations within Pine. There is a
+help text explaining how to define all of them, which you can read by
+following this <A HREF="h_config_new_rules">link</A>.
+
+<P>&lt;End of help on this topic&gt;
+
+</BODY>
+</HTML>
+====== h_config_reply_indent_rules =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: Reply-indent-Rule</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: Reply-indent-Rule</H1>
+
+<P> This option is used to specify which reply-indent-string is to be used
+when replying to an e-mail. If none of the rules are successful, the result in
+the variable <a href="h_config_reply_indent_string">reply-indent-string</a>
+is used.
+
+<P> The associated function to this configuration option is called "RESTR" (for
+REply STRing). Some examples of its use are:<BR>
+_FROM_ == {Your Boss} => _RESTR_{"> "}<BR>
+_FROM_ == {My Wife} => _RESTR_{":* "}<BR>
+_FROM_ == {Perter Flinstone;Wilma Flinstone} => _RESTR_{"_INIT_ > "}<BR>
+
+<P> This configuration option is just one of many that allow you to
+override the value of some global configurations within Pine. There is a
+help text explaining how to define all of them, which you can read by
+following this <A HREF="h_config_new_rules">link</A>.
+
+<P>&lt;End of help on this topic&gt;
+
+</BODY>
+</HTML>
+====== h_config_smtp_rules =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: SMTP-Rule</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: SMTP-Rule</H1>
+
+<P> This option is used to specify which SMTP server should be used when
+sending a message, if this rule is not defined, or the execution of the rule
+results in no server selected, then Pine will look for 
+the value from the role that is being used to compose the message. If no smtp
+server is defined in that role or you are not using a role, then Pine will get
+the name of the server from the
+<A HREF="h_config_smtp_server">&quot;smtp-server&quot;</A> configuration
+option according to the rules used in that variable.
+
+<P> The function associated to this configuration option is _SMTP_, an example
+of the use of this function is<BR>
+_ADDRESSTO_ == {peter@bedrock.com} => _SMTP_{smtp.bedrock.com}
+
+<P> This configuration option is just one of many that allow you to
+override the value of some global configurations within Pine. There is a
+help text explaining how to define all of them, which you can read by
+following this <A HREF="h_config_new_rules">link</A>.
+
+<P>&lt;End of help on this topic&gt;
+
+</BODY>
+</HTML>
+====== h_config_startup_rules =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: Startup-Rule</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: Startup-Rule</H1>
+
+<P> This option is used when a folder is being opened. You can use it to 
+specify its <A HREF="h_config_inc_startup">incoming-startup-rule</A> and override
+Pine's global value set for all folders.
+
+<P> An example of the usage of this option is:<BR>
+_FOLDER_ == {Lynx;pine-info;_NEWS_} => _STARTUP_{first-unseen}
+
+<P> This configuration option is just one of many that allow you to
+override the value of some global configurations within Pine. There is a
+help text explaining how to define all of them, which you can read by
+following this <A HREF="h_config_new_rules">link</A>.
+
+<P>&lt;End of help on this topic&gt;
+
+</BODY>
+</HTML>
+====== h_config_new_rules =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: New Rules Explained</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: New Rules Explained</H1>
+
+This is a quite powerful option. Here you can define rules that override
+the values of any other global rule you have globally set in pine.
+
+<P>
+  For example, you can set your folders to be sorted in a certain way when
+you open them (say by Arrival). You may not want to be this the behavior
+of, say, a Newsgroup, maybe you would like there to have your folder to be
+automatically ordered by Ordered Subject. The purpose of this feature is
+to accomplish exactly that. You can use this option for defining such
+exception and make Pine automatically sort your favorite Newsgroup by
+Ordered Subject.
+
+<P>
+  On the other hand you may be suscribed to a mailing list, and maybe you
+don't care to see in the index the size of the messages, however in other
+lists you may want to see the size of the messages. You can use this
+configuration for changing the way the index is displayed in a folder.
+
+<P>
+  Also there may be a mailing list that identifies itself by adding a
+certain string to its subject which makes difficult to read the total
+subject, so you may want to delete that string from the subject whenever
+it appears. You can do that also with this configuration.
+
+<P>
+  You may also want to make your reply-leadin-string person or folder
+dependent. You can do this with this feature (part of this feature can be
+accomplised with the roles definitions, but roles are not the right tool
+to do this as you will see).
+
+<P>
+  Every rule has three parts, a condition, a separator and an action. The
+action is what will happen if the condition of the rule is satisified.
+
+<P>
+  Here is an example:
+
+<P>
+   _FROM_ == {Fred Flinstone} =&gt; _SAVE_{Fred}
+
+<P>
+  Here the separator is "=&gt;". Whatever is to the left of the separator
+is the condition (that is to say _FROM_ == {Fred Flinstone}) and to the
+right is the action (_SAVE_{Fred}). The condition means that the rule will
+be applied only if the message that you are reading is from "Fred
+Flinstone", and the action will be that you will be offered to save it in
+the folder "Fred", whenever you press the letter "S" to save a message.
+
+<P>
+  The separator is always "=&gt;", with one exception to be seen later.
+But for the most part this will be the only one you'll ever need.
+
+<P>
+  Now let us see how to do it. There are 12 functions already defined for 
+you. These are: _INDEX_, _REPLACE_, _REPLY_, _RESUB_, _SAVE_, _SIGNATURE_, 
+_SORT_, _STARTUP_, _TRIM_, _REXTRIM_, _THREADSTYLE and _THREADINDEX_. The 
+parameter of a function has to be enclosed between "{" and "}", so for 
+example you can specify _SAVE_{saved-messages} as a valid sentence.
+
+<P>
+  At the end of the document you will find more examples.Here is a short
+description of what each function does: 
+
+<P>
+<UL>
+<LI> _INDEX_ : This function takes as an argument an index-format, and
+makes that the index-format for the specified folder.
+<LI> _REPLACE_ : This function replaces the subject/from of the given e-mail by
+another subject/from only when displaying the index.
+<LI> _REPLY_ : This function takes as an argument a definition of a
+reply-leadin-string and makes this the reply-leading-string of the
+specified folder or person.
+<LI> _RESTR_ : This function takes as an argument the value of the 
+reply-indent-string to be used to answer the message being replied to.
+<LI> _RESUB_ : This function replaces the subject of the given e-mail by
+another subject only when replying to a message.
+<LI> _SAVE_ : The save function takes as an argument the name of a
+possibly non existing folder, whenever you want to save a message, that
+folder will be offered for you to save.
+<LI> _SIGNATURE_ : This function takes as an argument a signature file and
+uses that file as the signature for the message you are about to
+compose/reply/forward.
+<LI> _SMTP_ : This function takes as an argument the definition of a
+SMTP server.
+<LI> _SORT_ : This function takes as an argument a Sort Style, and sorts a
+specified folder in that sort order.
+<LI> _TRIM_ : This function takes as an argument a list of strings that
+you want removed from another string. At this time this only works for
+_FROM_ and _SUBJECT_.
+<LI> _REXTRIM_ : Same as _TRIM_ but its argument is one and
+only one extended regular expression.
+<LI> _STARTUP_ : This function takes as an argument an
+incoming-startup-rule, and open an specified folder using that rule.
+<LI> _THREADSTYLE_ : This function takes as an argument a
+threading-display-style and uses it to display threads in a folder.
+<LI> _THREADINDEX_ : This function takes as an argument a
+threading-index-style and uses it to display threads in a folder.
+</UL>
+
+<P>
+You must me wondering how to define the person/folder over who to apply
+the action. This is done in the condition. When you specify a rule, the
+rule is only executed if the condition is satisfied. In another words for
+the rule:
+
+<P>
+   _FROM_ == {Fred Flinstone} =&gt; _SAVE_{Fred}
+
+<P>
+it will only be applied if the from is "Fred Flinstone", if the From is
+"Wilma Flinstone" the rule will be skipped.
+
+<P> In order to test a condition you can use the following tokens (in
+alphabetical order): _ADDRESS_,_CC_, _FOLDER_, _FROM_,_NICK_, _ROLE,
+_SENDER_, _SUBJECT_ and _TO_. The token will always be tested against what
+it is between "{" and "}" in the condition, this part of the condition is
+called the "condition set". The definition of each token can be found 
+<A HREF="h_index_tokens">here</A>.
+
+<P>
+You can also test in different ways, you can
+use the following "test operands": &lt;&lt;, !&lt;, &gt;&gt;, !&gt;, ==
+and !=. All of them are two strings long. Here is the meaning of them:
+
+<P>
+<UL> 
+<LI> &lt;&lt; : It tests if the value of the token is contained in
+the condition set. Here for example if the condition set were equal to
+"Freddy", then the condition: _NICK_ &lt;&lt; {Freddy}, would be true if
+the value of _NICK_ were "Fred", "red" or "Freddy". You are just looking
+for substrings here.
+<LI> &gt;&gt; : It tests if the value of the token contains the value of
+the condition set. Here for example if the condittion set were equal to
+"Fred", then the condition: _FROM_ &gt;&gt; {Fred}, would be true if
+the value of _FROM_ were "Fred Flinstone" or "Fred P. Flinstone" or "Freddy".
+<LI> == : It tests if the value of the token is exactly equal to the value
+of the set condition. For example _NICK_ == {Fred} will be false if the value 
+of _NICK_ is "Freddy" or "red". 
+<LI> !&lt; : This is true only when &lt;&lt; is false and viceversa.
+<LI> !&gt; : This is true only when &gt;&gt; is false and viceversa.
+<LI> != : This is true only when == is false and viceversa.
+</UL>
+
+<P>
+  Now let us say that you want the same action to be applied to more than
+one person or folder, say you want "folder1" and "folder2" to be sorted by
+Ordered Subject upon entering. Then you can list them all of them in the
+condition part separting them by a ";". Here is the way to do it.
+
+<P>
+ _FOLDER_ &lt;&lt; {folder1; folder2} =&gt; _SORT_{OrderedSubj}
+
+<P>
+  Here is the first subtelty about these definitions. Notice that the
+following rule:
+
+<P>
+ _FOLDER_ == {folder1; folder2} =&gt; _SORT_{Reverse OrderedSubj}
+
+<P> works only for "folder1" but not for "folder2". This is because the
+comparison of the name of the folder is done with whatever is in between
+"{", ";" or "}", so in the above rule you would be testing <BR>
+"folder2" == " folder2". The extra space makes the difference. 
+The reason why the first rule does not fail is because 
+"folder2" &lt;&lt; " folder2" is actually
+true. If something ever fails this may be something to look into.
+
+<P>
+ Here are a few examples of what we have talked about before.
+
+<P>
+_NICK_ == {lisa;kika} =&gt; _SAVE_{_NICK_/_NICK_} <BR>
+This means that if the nick is lisa, it will 
+save the message in the folder "lisa/lisa", and if the nick 
+is "kika", it will save the message in the folder "kika/kika"
+
+<P>
+_FOLDER_ == {Lynx} -&gt; lynx <BR>
+This, is an abreviation of the following rule:<BR>
+_FOLDER_ == {Lynx} =&gt; _SAVE_{lynx} <BR>
+(note the change in separator from "=&gt;" to "-&gt;"). In the future 
+I will use that abreviation.
+
+<P> _FOLDER_ &lt;&lt; {comp.mail.pine; pine-info; pine-alpha} -&gt; pine <BR>
+Any message in the folders "comp.mail.pine", "pine-info" or "pine-alpha"
+will be saved to the folder "pine".
+
+<P> _FROM_ &lt;&lt; {Pine Master} -&gt; pine <BR>
+Any message whose From field contains
+"Pine Master" will be saved in the folder pine.
+
+<P> _FOLDER_ &lt;&lt; {Lynx; pine-info; comp.mail.pine} =&gt;
+_INDEX_{IMAPSTATUS MSGNO DATE FROMORTO(33%) SUBJECT(66%)} <BR> Use a
+different index-format for the folders "Lynx", "pine-info" and
+"comp.mail.pine", where the size is not present.
+
+<P> _FOLDER_ == {Lynx;pine-info} =&gt; _REPLY_{*** _FROM_ (_ADDRESS_)
+wrote in the _FOLDER_ list _SMARTDATE_("Today" "today" "on
+_LONGDATE_"):}<BR> If a message is in one of the incoming folders "Lynx"
+or "pine-info", create a reply-leadin-string that acknowledges that. Note
+the absence of "," in the function _SMARTDATE_. For example answering to a
+message in the pine-info list would look like:
+
+<P>
+*** Steve Hubert (hubert@cac.washington.edu) wrote in the pine-info list today:
+
+<P>
+However replying for a message in the Lynx list would look:
+
+<P>
+*** mattack@area.com (mattack@area.com) wrote in the Lynx list today:
+
+<P>
+If you write in more than one language you can use this feature to create
+Reply-leadin-strings in different languages.
+
+<P> Note that at least for people you can create particular
+reply-leadin-string using the role features, but it does not work as this
+one does. This seems to be the right way to do it.
+
+<P> _FOLDER_ &lt;&lt; {Lynx; comp.mail.pine; pine_info; pine-alpha} =&gt;
+_SORT_{OrderedSubj}<BR> This means upon opening, sort the folders "Lynx",
+"comp.mail.pine", etc in ordered subject. All the others use the default
+sort order. You can not sort in reverse in this form. The possible
+arguments of this function are listed in the definition of the
+default-sort-rule (Arrival, scorE, siZe, etc).
+
+<P> The last examples use the function _TRIM_ which has a special form.
+This function can only be used in the index list.
+
+<P> _FOLDER_ &lt;&lt; {Lynx} =&gt; _SUBJECT_ := _TRIM_{lynx-dev }<BR> In
+the folder "Lynx" eliminate from the subject the string "lynx-dev " (with
+the space at the end). For example a message whose subject is "Re:
+lynx-dev unvisited Visited Links", would be shown in the index with
+subject: "Re: unvisited Visited Links", making the subject shorter and
+giving the same information.
+
+<P> _FROM_ &gt;&gt; {Name (Comment)} =&gt; _FROM_ :=
+_TRIM_{ (Comment)}<BR> Remove the part " (Comment)"
+from the _FROM_, so when displaying in the index the real From "Name"
+will appear.
+
+<P> _SUBJECT_ == {} =&gt; _RESUB_{Re: your mail without subject}
+If there is no subject in the message, use the subject "Re: your mail
+wiyhout subject" as a subject for the reply message.
+
+<P> You can add more complexity to your rules by checking more than one
+conditions before a rule is executed. For example: Assume that you want to
+answer every email that contains the string "bug report", with the subject
+"Re: About your bug report", you could make
+
+<P>
+_SUBJECT_ == {bug report} =&gt; _RESUB_{Re: About your _SUBJECT_}
+
+<P> The problem with this construction is that if the person emails you
+back, then the next time you answer the message the subject will be: "Re:
+About your Re: About your bug report", so it grew. You may want to avoid
+this growth by using the following rule:
+
+<P>
+_SUBJECT_ &gt;&gt; {bug report} &&  _SUBJECT_ !&gt; {Re: } =&gt; _RESUB_{Re: About your _SUBJECT_}<BR>
+
+<P>
+which will only add the string "Re: About your" only the first time the
+message is replied.
+
+<P>
+  Say your personal name is "Fred Flinstones", and assume that you don't
+like to see "To: comp.mail.pine" in every post you make to this newsgroup,
+but instead would like to see it as everyone else sees it. <BR> 
+_FOLDER_ == {comp.mail.pine} && _FROM_ == {Fred Flinstones} => _FROM_ := _REPLACE_{_FROM_}
+
+<P> 
+  You can also list your index by nick, in the following way:<BR>
+_NICK_ != {} => _FROM_ := _REPLACE_{_NICK_}
+
+<P>
+  If you want to open the folder "pine-info" in the first non-read message
+use the rule:<BR>
+_FOLDER_ == {pine-info} => _STARTUP_{first-unseen}
+
+<P>
+ If you want to move your deleted messages to a folder, called "Trash", use
+the following rule:<BR>
+_FLAG_ >> {D} -> Trash
+
+<P>
+The reason why the above test is not "_FLAG_ == {D}" is because that would mean
+that this is the only flag set in the message. It's better to test by containment in this case.
+
+<P> If you want to use a specific signature when you are in a specific collection
+use the following rule:<BR>
+_COLLECTION_ == {Mail} => _SIGNATURE_{/full/path/to/.signature}
+
+<P> Finally about the question of which rule will be executed. Only the
+first rule that matches will be executed. It is important to notice though
+that "saving" rules do not compete with "sorting" rules. So the first
+"saving" rule that matches will be executed in the case of saving and so
+on.
+
+<P> Here are some things to do still:
+<UL>
+<LI> To make _TRIM_ compatible with more tokens (_TO_, _SENDER_, etc)
+<LI> To make this list dissapear!
+</UL>
+
+<P>
+<UL>
+<LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+</UL><P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
 ====== h_config_char_set =====
 <HTML>
 <HEAD>
@@ -21049,14 +22208,118 @@
 labeled as &quot;US-ASCII&quot;, 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 &quot;8-bit&quot;) characters, then Pine 
-will label the text as &quot;X-UNKNOWN&quot;.
+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 &quot;8-bit&quot;) characters, then Pine 
+will label the text as &quot;X-UNKNOWN&quot;.
+
+<P>
+<UL>   
+<LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+</UL><P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+====== h_config_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>
+&lt;End of help on this topic&gt;
+</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>
+&lt;End of help on this topic&gt;
+</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>
+&lt;End of help on this topic&gt;
+</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>
 &lt;End of help on this topic&gt;
 </BODY>
@@ -21135,6 +22398,42 @@
 &lt;End of help on this topic&gt;
 </BODY>
 </HTML>
+====== h_config_special_text_to_color =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: Special Text to Color</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: Specil Text to Color</H1>
+
+Use this option to enter patterns (text or regular expressions) that Pine
+will highlight in the body of the text that is not part of a handle (and 
+internal or external link that Pine paints in a different color). 
+
+<P> 
+Enter each pattern in a different line. Pine will internally merge these
+patterns (by adding a "|" character), or you can add them all in one line
+by separating them by a "|" character.
+
+<P>
+Pine will use the colors defined in the 
+<A HREF="h_config_special_text_color"> Special Text Color</A> variable. 
+to paint any match.
+
+<P> 
+If the Special Text Color is not set, setting this variable will not
+cause that special text to be indicated in any special way. It will look
+like any normal text. You must set those colors in order to make Pine
+paint the screen differently when it finds the patterns specified in this
+variable.
+
+<P>
+<UL>   
+<LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+</UL><P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
 ====== h_config_display_filters =====
 <HTML>
 <HEAD>
@@ -21953,6 +23252,38 @@
 &lt;End of help on this topic&gt;
 </BODY>
 </HTML>
+====== h_config_inc_fld_timeo =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: inc-fld-timeout</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: inc-fld-timeout</H1>
+
+When Pine is checking for new mail in an external incoming folder, and the
+amount of time specified in this variable has elapsed without Pine being
+able to connect to the server holding that mailbox, Pine will drop the
+connection to that server and continue checking for new mail in other
+incoming folders, if any.
+
+<P>
+Observe that Pine will not print an error message in this case, but it
+will silently drop the connection. If your connections are fast setting
+this to a large value will not cause you any problem, but if your
+connections are slow setting this to a small value will make Pine speed
+checking for new mail, although it is possible that not all of your
+incoming folders will be checked for new mail.
+
+<P>
+The default is 5 seconds, which is also the minimum and the maximum is 60.
+
+<P>
+<UL>   
+<LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+</UL><P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
 ====== h_config_incoming_folders =====
 <HTML>
 <HEAD>
@@ -24226,6 +25557,76 @@
 &lt;End of help on this topic&gt;
 </BODY>
 </HTML>
+====== h_config_thread_display_style_rule =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: Threading-Display-Style-Rule</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: Threading-Display-Style-Rule</H1>
+
+This option is very similar to <A HREF="h_config_thread_disp_style">
+threading-display-style</A>, but it is a rule which specifies the
+display styles for a thread that you want displayed in a specific
+folder or collection.
+<P>
+The token to be used in this function is _THREADSTYLE_. Here there is
+an example of its use
+<P>
+_FOLDER_ == {pine-info} => _THREADSTYLE_{mutt-like}
+<P>
+The values that can be given for the _THREADSTYLE_ function are the
+values of the threading-display-style function, which can be found
+listed in the <A HREF="h_config_thread_disp_style">threading-display-style</A>
+configuration option.
+
+<P> This configuration option is just one of many that allow you to
+override the value of some global configurations within Pine. There is a
+help text explaining how to define all of them, which you can read by
+following this <A HREF="h_config_new_rules">link</A>.
+
+<P>
+<UL>   
+<LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+</UL><P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+====== h_config_thread_index_style_rule =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: Threading-Index-Style-Rule</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: Threading-Index-Style-Rule</H1>
+
+This option is very similar to <A HREF="h_config_thread_index_style">
+threading-index-style</A>, but it is a rule which specifies the
+index styles for a thread that you want displayed in a specific
+folder or collection.
+<P>
+The token to be used in this function is _THREADINDEX_. Here there is
+an example of its use
+<P>
+_FOLDER_ == {pine-info} => _THREADINDEX_{regular-index-with-expanded-threads}
+<P>
+The values that can be given for the _THREADINDEX_ function are the
+values of the threading-index-display function, which can be found
+listed in the <A HREF="h_config_thread_index_style">threading-index-display</A>
+configuration option.
+
+<P> This configuration option is just one of many that allow you to
+override the value of some global configurations within Pine. There is a
+help text explaining how to define all of them, which you can read by
+following this <A HREF="h_config_new_rules">link</A>.
+
+<P>
+<UL>   
+<LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+</UL><P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
 ====== h_config_pruning_rule =====
 <HTML>
 <HEAD>
@@ -24519,6 +25920,51 @@
 &lt;End of help on this topic&gt;
 </BODY>
 </HTML>
+====== h_config_inc_rule =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: Incoming-Check-Rule</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: Incoming-Check-Rule</H1>
+
+This value affects Pine's behavior when starting Pine. It determines
+how and when Pine will check for new mail in your incoming folders. The
+default value is &quot;automatic&quot;.
+
+<P>
+The three possible values for this option are:
+
+<DL>
+<DT>automatic</DT>
+<DD>This is the default. When this is selected the first check for new
+mail will be done when Pine is starting up and you either go to the
+INDEX or FOLDER LIST screens.
+</DD>
+
+<DT>automatic-after-first-manual-check</DT>
+<DD>Similar to the default, but no check is done until you force the first
+one by pressing CTRL-H. All checks are automatic after the first one. Observe
+that this feature does not work once an automatic check has been done.
+</DD>
+
+<DT>manual-only</DT>
+<DD>This forces Pine to do only manual checks. This will probably speed
+Pine, since checks will  only happen when they are forced by pressing CTRL-H.
+</DD>
+</DL>
+
+<P>
+If you just want to stop Pine from checking in one folder, then simply
+select that folder. Checks on that folder will be skipped.
+
+<P>
+<UL>   
+<LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+</UL><P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
 ====== h_config_browser =====
 <HTML>
 <HEAD>
@@ -25593,6 +27039,81 @@
 &lt;End of help on this topic&gt;
 </BODY>
 </HTML>
+====== h_config_enable_check_incoming ======
+<HTML>
+<HEAD>
+<TITLE>FEATURE: enable-check-incoming-folders</TITLE>
+</HEAD>
+<BODY>
+<H1>FEATURE: enable-check-incoming-folders</H1>
+If you have enabled <A HREF="h_config_enable_incoming">incoming
+folders</A> then setting this feature allows you to check for new mail in
+these. A message stating that new mail was received and in which folders
+will be written in the screen. You can decide which incoming folders you
+want to check for new mail, and the list of them has to be entered in the
+setting <A HREF="h_config_check_inc_fld">incoming-folders-to-check</A>.
+
+<P> If you have the option 
+<A HREF="h_config_fast_recent">enable-fast-recent-test</A>
+<B>disabled</B>, but have this feature enabled, then a full report on the
+total number of messages, and the number of new messages in the folder is
+printed in the <A HREF="h_folder_maint">FOLDER LIST</A> screen 
+for each folder listed in the variable 
+<A HREF="h_config_check_inc_fld">incoming-folders-to-check</A>. The report for each
+folder is made in the format
+
+<P>
+folder-name [Number of new messages/Number of messages in the folder]
+
+<P>
+If an incoming folder is not listed in the variable
+<A HREF="h_config_check_inc_fld">incoming-folders-to-check</A>, then only 
+the name of the folder and no other report is made about that folder.
+
+<P>
+Other important features related to this feature are:
+<OL>
+<LI><A HREF="h_config_enable_recheck_incoming">recheck-all-incoming-folders</A>,
+which allows you to decide if you want to check all folders 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 @@
 &lt;End of help on this topic&gt;
 </BODY>
 </HTML>
+====== h_config_use_domain =====
+<HTML>
+<HEAD>
+<TITLE>FEATURE: return-path-uses-domain-name </TITLE>
+</HEAD>
+<BODY>
+<H1>FEATURE: return-path-uses-domain-name</H1>
+
+If you enable this configuration option Pine will use your domain name and your
+username in that domain name to construct your Return-Path header, if not Pine
+will use the address that you have set in the From: field to construct it.
+
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
 ====== h_config_use_sender_not_x =====
 <HTML>
 <HEAD>
@@ -26192,6 +27729,33 @@
 <A HREF="h_config_tab_uses_unseen">&quot;Tab-Uses-Unseen-For-Next-Folder&quot;</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 @@
 &lt;End of help on this topic&gt;
 </BODY>
 </HTML>
+====== h_config_alt_reply_menu =====
+<HTML>
+<HEAD>
+<TITLE>FEATURE: alternate-reply-menu</TITLE>
+</HEAD>
+<BODY>
+<H1>FEATURE: alternate-reply-menu</H1>
+
+This feature controls the menu that is displayed when Reply is selected.
+If set, a list of options will be presented, with each option representing
+the type of composition that could be used. This feature is most useful
+for users who want to avoid being prompted with each option separately, or
+would like to override some defaults set in your configuration for the
+message that you are replying (e.g. you may have set the option to strip
+signatures, but for the message you are answering you would like not to do
+that)
+
+<P>
+The way this feature works is as follows. Initially you get the question 
+if you want to include the message, and in the menu you will see several 
+options, each option is accompanied by some text explaining what will 
+happen if you press the associated command. For example, if you read the 
+text &quot;S Strip Sig&quot;, it means that if you press the letter 
+&quot;S&quot; the signature will be stripped off the message you are 
+replying. Observer that the menu will change to 
+&quot;S No Strip&quot;, which means that if you press &quot;S&quot;, the 
+signature will not be stripped off from the message. Your choices are
+activated when you press RETURN.
+
+<P>
+Another way to remember what Pine will do, is that what will be done is
+exactly the opposite of what you read in the menu.
+
+<P>
+The possible options are:
+
+<OL>
+<LI> F: To decide if you want to send flowed text or not. This option appears
+unless you have quelled sending flowed text.
+
+<LI> S: To strip the signature from a message, only available is the feature
+        <a href="h_config_sigdashes">enable-sigdashes</a> or the
+<a href="h_config_strip_sigdashes">strip-from-sigdashes-on-reply</a> option are
+enabled.
+
+<LI> R: To set a role, if you do not want Pine to set one automatically for you
+or would like to set one when you can not select any.
+</OL>
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
 ====== h_config_del_from_dot =====
 <HTML>
 <HEAD>
@@ -27000,6 +28616,26 @@
 &lt;End of help on this topic&gt;
 </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>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
 ====== h_config_prefer_plain_text =====
 <HTML>
 <HEAD>
@@ -27180,6 +28816,49 @@
 &lt;End of help on this topic&gt;
 </BODY>
 </HTML>
+====== h_config_courier_list =====
+<HTML>
+<HEAD>
+<TITLE>FEATURE: Courier-Folder-List</TITLE>
+</HEAD>
+<BODY>
+<H1>FEATURE: Courier-Folder-List</H1>
+
+In a maildir collection, a folder could be used as a directory to store 
+folders. In the Courier server if you create a folder, then a directory 
+with the same name is created. If you use this patch to access a 
+collection created by the Courier server, then the display of such 
+collection will look confusing. The best way to access a maildir 
+collection created by the Courier server is by using the &quot;#mc/&quot; 
+prefix instead of the &quot;#md/&quot; prefix. If you use this alternate 
+prefix, then this feature applies to you, otherwise you can safely ignore 
+the text that follows.
+<P>
+Depending on if you have enabled the option 
+<a href="h_config_separate_yold_dir_view">separate-folder-and-firectory-entries</a> 
+a folder may be listed as &quot;folder[.]&quot;, or as two entries in the 
+list by &quot;folder&quot; and &quot;folder.&quot;.
+<P>
+If this option is disabled, Pine will list local folders that are in Courier
+style format, as &quot;folder&quot;, and those that are also directories as
+&quot;folder[.]&quot;. This makes the default display cleaner.
+<P>
+If this feature is enabled then creating folders in a maildir collection
+will create a directory with the same name. If this feature is disabled, then 
+a folder is considered a directory only if it contains subfolders, so you can
+not create a directory with the same name as an exisiting folder unless 
+you create a subfolder of that folder first (e.g. if you have a folder
+called &quot;foo&quot; simply add &quot;foo.bar&quot; directly. This will
+create the directory &quot;foo&quot; and the subfolder &quot;bar&quot; of it).
+<P>
+Observe that this feature works only for maildir collections that are accessed
+locally. If a collection is accessed remotely then this feature has no value,
+as the report is created in a server, and Pine only reports what received
+from the server in this case.
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
 ====== h_config_verbose_post =====
 <HTML>
 <HEAD>
@@ -27331,6 +29010,29 @@
 &lt;End of help on this topic&gt;
 </BODY>
 </HTML>
+====== h_config_auto_read_msgs_rules =====
+<HTML>
+<HEAD>
+<TITLE>FEATURE: auto-move-read-msgs-using-rules</TITLE>
+</HEAD>
+<BODY>
+<H1>FEATURE: auto-move-read-msgs-using-rules</H1>
+This feature controls an aspect of Pine's behavior upon quitting.  If set,
+and the 
+<A HREF="h_config_read_message_folder">&quot;read-message-folder&quot;</A>
+option is also set, then Pine will automatically transfer all read
+messages to the designated folder using the rules that you have defined in
+your
+<A HREF="h_config_save_rules">&quot;save-rules&quot;</A> and mark
+them as deleted in the INBOX.  Messages in the INBOX marked with an 
+&quot;N&quot; (meaning New, or unseen) are not affected.
+<P>
+<UL>   
+<LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+</UL><P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
 ====== h_config_auto_fcc_only =====
 <HTML>
 <HEAD>
@@ -27719,6 +29421,23 @@
 &lt;End of help on this topic&gt;
 </BODY>
 </HTML>
+====== h_config_enhanced_thread =====
+<HTML>
+<HEAD>
+<TITLE>FEATURE: enhanced-fancy-thread-support</TITLE>
+</HEAD>
+<BODY>
+<H1>FEATURE: enhanced-fancy-thread-support</H1>
+
+If this option is set certain commands in Pine will operate in loose
+threads too. For example, the command ^D marks a thread deleted, but if
+this feature is set, it will remove all threads that share the same missing
+parent with this thread.
+
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
 ====== h_config_news_cross_deletes =====
 <HTML>
 <HEAD>
@@ -28327,6 +30046,27 @@
 &lt;End of help on this topic&gt;
 </BODY>
 </HTML>
+====== h_config_circular_tab =====
+<HTML>
+<HEAD>
+<TITLE>FEATURE: enable-circular-tab</TITLE>
+</HEAD>
+<BODY>
+<H1>FEATURE: enable-circular-tab</H1>
+
+<P> 
+This Feature is like 
+<A HREF="h_config_auto_open_unread">&quot;auto-open-next-unread&quot;</A>, 
+in the sense that you can use TAB to browse through all of your Incoming
+Folders checking for new mail. Once it gets to the last folder of the
+collection it goes back to check again until it returns to the original
+folder where it started.
+<UL>   
+<LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+</UL><P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
 ====== h_config_auto_include_reply =====
 <HTML>
 <HEAD>
@@ -28818,6 +30558,30 @@
 &lt;End of help on this topic&gt;
 </BODY>
 </HTML>
+====== h_config_special_text_color =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: Special Text Color</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: Special Text Color</H1>
+
+Sets the color Pine uses for coloring any text in the body of the message
+that is not part of a handle (and internal or external link that Pine 
+paints in a different color). By default, this variable is not defined, 
+which means that text that matches the pattern is not painted in any
+particular way. This variable must be set in a special form if you
+want text to be painted.
+
+<P>
+<A HREF="h_color_setup">Descriptions of the available commands</A>
+<P>
+Look <A HREF="h_edit_nav_cmds">here</A>
+to see the available Editing and Navigation commands.
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
 ====== h_config_prompt_color =====
 <HTML>
 <HEAD>
--- 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
+
