summaryrefslogtreecommitdiff
path: root/pith
diff options
context:
space:
mode:
authorEduardo Chappa <chappa@washington.edu>2013-05-31 17:08:22 -0600
committerEduardo Chappa <chappa@washington.edu>2013-05-31 17:08:22 -0600
commit81e994d7907f850506ddc248f84761a54995e58c (patch)
tree3bc4993b48ddeec45dee51323437200ab975887c /pith
parent077522d7e058133f9de99d0d74481566b21c5a98 (diff)
downloadalpine-81e994d7907f850506ddc248f84761a54995e58c.tar.xz
* Fix not allow remote execution by adding PIPE_NOSHELL to the opening of a url by
a browser.
Diffstat (limited to 'pith')
-rw-r--r--pith/Makefile.am2
-rw-r--r--pith/Makefile.in5
-rw-r--r--pith/adrbklib.c10
-rw-r--r--pith/charconv/utf8.c50
-rw-r--r--pith/charconv/utf8.h1
-rw-r--r--pith/color.c113
-rw-r--r--pith/color.h19
-rw-r--r--pith/conf.c183
-rw-r--r--pith/conf.h57
-rw-r--r--pith/conftype.h34
-rw-r--r--pith/detoken.c33
-rw-r--r--pith/filter.c378
-rw-r--r--pith/filter.h1
-rw-r--r--pith/filttype.h2
-rw-r--r--pith/flag.c6
-rw-r--r--pith/imap.c11
-rw-r--r--pith/imap.h1
-rw-r--r--pith/indxtype.h34
-rw-r--r--pith/init.c3
-rw-r--r--pith/mailcap.c66
-rw-r--r--pith/mailcap.h1
-rw-r--r--pith/mailcmd.c435
-rw-r--r--pith/mailcmd.h8
-rw-r--r--pith/mailindx.c440
-rw-r--r--pith/mailindx.h3
-rw-r--r--pith/mailview.c465
-rw-r--r--pith/mailview.h16
-rw-r--r--pith/makefile.wnt4
-rw-r--r--pith/msgno.c3
-rw-r--r--pith/osdep/color.c1256
-rw-r--r--pith/osdep/color.h25
-rw-r--r--pith/pattern.c28
-rw-r--r--pith/pine.hlp1825
-rw-r--r--pith/pineelt.h1
-rw-r--r--pith/reply.c264
-rw-r--r--pith/save.c3
-rw-r--r--pith/send.c71
-rw-r--r--pith/send.h2
-rw-r--r--pith/sort.c88
-rw-r--r--pith/sort.h8
-rw-r--r--pith/state.c14
-rw-r--r--pith/state.h37
-rw-r--r--pith/store.c8
-rw-r--r--pith/string.c58
-rw-r--r--pith/string.h2
-rw-r--r--pith/text.c45
-rw-r--r--pith/thread.c787
-rw-r--r--pith/thread.h23
-rw-r--r--pith/url.c7
49 files changed, 6447 insertions, 489 deletions
diff --git a/pith/Makefile.am b/pith/Makefile.am
index ce6c78a3..7def45ef 100644
--- a/pith/Makefile.am
+++ b/pith/Makefile.am
@@ -25,7 +25,7 @@ libpith_a_SOURCES = ablookup.c abdlc.c addrbook.c addrstring.c adrbklib.c bldadd
filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c imap.c init.c \
keyword.c ldap.c list.c mailcap.c mailcmd.c mailindx.c maillist.c mailview.c \
margin.c mimedesc.c mimetype.c msgno.c newmail.c news.c pattern.c pipe.c \
- readfile.c remote.c reply.c rfc2231.c save.c search.c sequence.c send.c sort.c \
+ readfile.c remote.c reply.c rfc2231.c rules.c save.c search.c sequence.c send.c sort.c \
state.c status.c store.c stream.c string.c strlst.c takeaddr.c tempfile.c text.c \
thread.c adjtime.c url.c util.c helptext.c smkeys.c smime.c
diff --git a/pith/Makefile.in b/pith/Makefile.in
index 322291b0..708abccf 100644
--- a/pith/Makefile.in
+++ b/pith/Makefile.in
@@ -83,7 +83,7 @@ am_libpith_a_OBJECTS = ablookup.$(OBJEXT) abdlc.$(OBJEXT) \
margin.$(OBJEXT) mimedesc.$(OBJEXT) mimetype.$(OBJEXT) \
msgno.$(OBJEXT) newmail.$(OBJEXT) news.$(OBJEXT) \
pattern.$(OBJEXT) pipe.$(OBJEXT) readfile.$(OBJEXT) \
- remote.$(OBJEXT) reply.$(OBJEXT) rfc2231.$(OBJEXT) \
+ remote.$(OBJEXT) reply.$(OBJEXT) rfc2231.$(OBJEXT) rules.$(OBJEXT) \
save.$(OBJEXT) search.$(OBJEXT) sequence.$(OBJEXT) \
send.$(OBJEXT) sort.$(OBJEXT) state.$(OBJEXT) status.$(OBJEXT) \
store.$(OBJEXT) stream.$(OBJEXT) string.$(OBJEXT) \
@@ -319,7 +319,7 @@ libpith_a_SOURCES = ablookup.c abdlc.c addrbook.c addrstring.c adrbklib.c bldadd
filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c imap.c init.c \
keyword.c ldap.c list.c mailcap.c mailcmd.c mailindx.c maillist.c mailview.c \
margin.c mimedesc.c mimetype.c msgno.c newmail.c news.c pattern.c pipe.c \
- readfile.c remote.c reply.c rfc2231.c save.c search.c sequence.c send.c sort.c \
+ readfile.c remote.c reply.c rfc2231.c rules.c save.c search.c sequence.c send.c sort.c \
state.c status.c store.c stream.c string.c strlst.c takeaddr.c tempfile.c text.c \
thread.c adjtime.c url.c util.c helptext.c smkeys.c smime.c
@@ -451,6 +451,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rules.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
diff --git a/pith/adrbklib.c b/pith/adrbklib.c
index 01d00353..904928b8 100644
--- a/pith/adrbklib.c
+++ b/pith/adrbklib.c
@@ -5136,8 +5136,14 @@ init_addrbooks(OpenStatus want_status, int reset_to_top, int open_if_only_one, i
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;
diff --git a/pith/charconv/utf8.c b/pith/charconv/utf8.c
index 411e1ddd..bca0d26b 100644
--- a/pith/charconv/utf8.c
+++ b/pith/charconv/utf8.c
@@ -1049,6 +1049,56 @@ utf8_width(char *str)
/*
+ * Returns the screen cells width of the UTF-8 string argument, treating tabs
+ * in a special way.
+ */
+unsigned
+utf8_widthis(char *str)
+{
+ unsigned width = 0;
+ int this_width;
+ UCS ucs;
+ unsigned long remaining_octets;
+ char *readptr;
+
+ if(!(str && *str))
+ return(width);
+
+ readptr = str;
+ remaining_octets = readptr ? strlen(readptr) : 0;
+
+ while(remaining_octets > 0 && *readptr){
+
+ ucs = (UCS) utf8_get((unsigned char **) &readptr, &remaining_octets);
+
+ if(ucs & U8G_ERROR){
+ /*
+ * This should not happen, but do something to handle it anyway.
+ * Treat each character as a single width character, which is what should
+ * probably happen when we actually go to write it out.
+ */
+ remaining_octets--;
+ readptr++;
+ this_width = 1;
+ }
+ else{
+ this_width = (ucs == TAB) ? ((~width & 0x07) + 1) : wcellwidth(ucs);
+
+ /*
+ * If this_width is -1 that means we can't print this character
+ * with our current locale. Writechar will print a '?'.
+ */
+ if(this_width < 0)
+ this_width = 1;
+ }
+
+ width += (unsigned) this_width;
+ }
+
+ return(width);
+}
+
+/*
* Copy UTF-8 characters from src into dst.
* This is intended to be used if you want to truncate a string at
* the start instead of the end. For example, you have a long string
diff --git a/pith/charconv/utf8.h b/pith/charconv/utf8.h
index d22a8a7c..09a2a95c 100644
--- a/pith/charconv/utf8.h
+++ b/pith/charconv/utf8.h
@@ -81,6 +81,7 @@ UCS *ucs4_strncat(UCS *ucs4dst, UCS *ucs4src, size_t n);
UCS *ucs4_strchr(UCS *s, UCS c);
UCS *ucs4_strrchr(UCS *s, UCS c);
unsigned utf8_width(char *);
+unsigned utf8_widthis(char *);
size_t utf8_to_width_rhs(char *, char *, size_t, unsigned);
int utf8_snprintf(char *, size_t, char *, ...);
size_t utf8_to_width(char *, char *, size_t, unsigned, unsigned *);
diff --git a/pith/color.c b/pith/color.c
index 9794294b..b5dc320c 100644
--- a/pith/color.c
+++ b/pith/color.c
@@ -21,7 +21,8 @@ static char rcsid[] = "$Id: color.c 769 2007-10-24 00:15:40Z hubert@u.washington
#include "../pith/state.h"
#include "../pith/conf.h"
#include "../pith/filter.h"
-
+#include "../pith/mailview.h"
+#include "../pico/estruct.h"
char *
color_embed(char *fg, char *bg)
@@ -70,23 +71,110 @@ struct quote_colors {
struct quote_colors *next;
};
+int
+is_word (buf, i, j)
+ char buf[NSTRING];
+ int i, 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, 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
+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(long int linenum, char *line, 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 *p, buf[NSTRING] = {'\0'};
struct quote_colors *colors = NULL, *cp, *next;
COLOR_PAIR *col = NULL;
int is_flowed = is_flowed_msg ? *((int *)is_flowed_msg) : 0;
+ int code;
+
+ code = (is_flowed ? IS_FLOWED : NO_FLOWED) | COLORAQUO;
+ select_quote(linenum, line, ins, (void *) &code);
+ strncpy(buf, tmp_20k_buf, NSTRING < SIZEOF_20KBUF ? NSTRING : SIZEOF_20KBUF);
+ buf[sizeof(buf)-1] = '\0';
p = line;
- if(!is_flowed)
- while(isspace((unsigned char)*p))
- p++;
+ for(i = 0; isspace((unsigned char)buf[i]); i++, p++);
- if(p[0] == '>'){
+ if(buf[i]){
struct quote_colors *c;
/*
@@ -135,7 +223,7 @@ color_a_quote(long int linenum, char *line, LT_INS_S **ins, void *is_flowed_msg)
free_color_pair(&col);
cp = NULL;
- while(*p == '>'){
+ while(buf[i]){
cp = (cp && cp->next) ? cp->next : colors;
if(countem > 0)
@@ -145,10 +233,9 @@ color_a_quote(long int linenum, char *line, LT_INS_S **ins, void *is_flowed_msg)
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){
@@ -211,7 +298,7 @@ color_a_quote(long int linenum, char *line, LT_INS_S **ins, void *is_flowed_msg)
}
}
- return(0);
+ return(1);
}
diff --git a/pith/color.h b/pith/color.h
index b90d82cf..01bbbb58 100644
--- a/pith/color.h
+++ b/pith/color.h
@@ -21,6 +21,24 @@
#include "../pith/pattern.h"
#include "../pith/osdep/color.h"
+#define NO_FLOWED 0x0000
+#define IS_FLOWED 0x0001
+#define DELETEQUO 0x0010
+#define COLORAQUO 0x0100
+#define RAWSTRING 0x1000
+
+/* This is needed for justification, I will move it to a better place later
+ * or maybe not
+ */
+#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) == ']'))
typedef struct spec_color_s {
int inherit; /* this isn't a color, it is INHERIT */
@@ -80,6 +98,7 @@ typedef struct spec_color_s {
/* exported protoypes */
char *color_embed(char *, char *);
int colorcmp(char *, char *);
+int next_level_quote(char *, char **, int, int);
int color_a_quote(long, char *, LT_INS_S **, void *);
void free_spec_colors(SPEC_COLOR_S **);
diff --git a/pith/conf.c b/pith/conf.c
index 18eaf8f0..876667e5 100644
--- a/pith/conf.c
+++ b/pith/conf.c
@@ -29,6 +29,7 @@ static char rcsid[] = "$Id: conf.c 1266 2009-07-14 18:39:12Z hubert@u.washington
#include "../pith/remote.h"
#include "../pith/keyword.h"
#include "../pith/mailview.h"
+#include "../pith/rules.h"
#include "../pith/list.h"
#include "../pith/status.h"
#include "../pith/ldap.h"
@@ -206,6 +207,8 @@ CONF_TXT_T cf_text_fcc_name_rule[] = "Determines default name for Fcc...\n# Choi
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\".";
@@ -222,12 +225,44 @@ CONF_TXT_T cf_text_unk_character_set[] = "Defaults to nothing, which is equivale
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_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 supersede global index format variable in designated folders.";
+
+CONF_TXT_T cf_text_key_def_rules[] = "Allows a user to override keystrokes in certain screens.";
+
+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_speller[] = "Specifies the program invoked by ^T in the Composer.";
CONF_TXT_T cf_text_deadlets[] = "Specifies the number of dead letter files to keep when canceling.";
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.";
@@ -340,6 +375,8 @@ CONF_TXT_T cf_text_stat_msg_delay[] = "The number of seconds to sleep after writ
CONF_TXT_T cf_text_busy_cue_rate[] = "Number of times per-second to update busy cue messages";
+CONF_TXT_T cf_text_sleep[] = "The number of seconds between a viewer finishing opening a file and removing\n#it. See more details in configuration screen. Default: 0";
+
CONF_TXT_T cf_text_mailcheck[] = "The approximate number of seconds between checks for new mail";
CONF_TXT_T cf_text_mailchecknoncurr[] = "The approximate number of seconds between checks for new mail in folders\n# other than the current folder and inbox.\n# Default is same as mail-check-interval";
@@ -430,6 +467,9 @@ CONF_TXT_T cf_text_window_position[] = "Window position in the format: CxR+X+Y\n
CONF_TXT_T cf_text_newsrc_path[] = "Full path and name of NEWSRC file";
+#ifndef _WINDOWS
+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\"";
+#endif
/*----------------------------------------------------------------------
These are the variables that control a number of pine functions. They
@@ -520,6 +560,8 @@ static struct variable variables[] = {
NULL, cf_text_fcc_name_rule},
{"sort-key", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
NULL, cf_text_sort_key},
+{"thread-sort-key", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
+ NULL, cf_text_thread_sort_key},
{"addrbook-sort-rule", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
"Address Book Sort Rule", cf_text_addrbook_sort_rule},
{"folder-sort-rule", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
@@ -542,6 +584,34 @@ static struct variable variables[] = {
NULL, cf_text_thread_exp_char},
{"threading-lastreply-character", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
"Threading Last Reply Character", cf_text_thread_lastreply_char},
+{"threading-display-style-rule", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
+ "Threading Display Style Rule", cf_text_thread_displaystyle_rule},
+{"threading-index-style-rule", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
+ "Threading Index Style Rule", cf_text_thread_indexstyle_rule},
+{"compose-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
+ "Compose Rules", cf_text_compose_rules},
+{"forward-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
+ "Forward Rules", cf_text_forward_rules},
+{"index-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
+ "Index Rules", cf_text_index_rules},
+{"key-definition-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
+ "Key Definition Rules", cf_text_key_def_rules},
+{"replace-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
+ "Replace Rules", cf_text_replace_rules},
+{"reply-indent-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
+ "Reply Indent Rules", cf_text_reply_indent_rules},
+{"reply-leadin-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
+ "Reply Leadin Rules", cf_text_reply_leadin_rules},
+{"reply-subject-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
+ "Reply Subject Rules", cf_text_reply_subject_rules},
+{"save-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
+ "Save Rules", cf_text_save_rules},
+{"smtp-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
+ "Smtp Rules", cf_text_smtp_rules},
+{"sort-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
+ "Sort Rules", cf_text_sort_rules},
+{"startup-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
+ "Startup Rules", cf_text_startup_rules},
#ifndef _WINDOWS
{"display-character-set", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
NULL, cf_text_disp_char_set},
@@ -560,6 +630,8 @@ static struct variable variables[] = {
NULL, cf_text_speller},
{"composer-wrap-column", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
NULL, cf_text_fillcol},
+{"special-text-color", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
+ NULL, cf_special_text_color},
{"reply-indent-string", 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0,
NULL, cf_text_replystr},
{"reply-leadin", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
@@ -616,6 +688,8 @@ static struct variable variables[] = {
NULL, cf_text_stat_msg_delay},
{"busy-cue-rate", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
NULL, cf_text_busy_cue_rate},
+{"sleep-interval-length", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
+ NULL, cf_text_sleep},
{"mail-check-interval", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
NULL, cf_text_mailcheck},
{"mail-check-interval-noncurrent", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
@@ -630,6 +704,10 @@ static struct variable variables[] = {
NULL, cf_text_news_active},
{"news-spool-directory", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
NULL, cf_text_news_spooldir},
+#ifndef _WINDOWS
+{"maildir-location", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
+ "Maildir Location", cf_text_maildir_location},
+#endif
{"upload-command", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
NULL, cf_text_upload_cmd},
{"upload-command-prefix", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
@@ -817,6 +895,8 @@ static struct variable variables[] = {
{"incoming-unseen-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"signature-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"signature-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+{"special-text-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+{"special-text-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"prompt-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"prompt-background-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"header-general-foreground-color", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
@@ -1566,7 +1646,7 @@ init_vars(struct pine *ps, void (*cmds_f) (struct pine *, char **))
register struct variable *vars = ps->vars;
int obs_header_in_reply = 0, /* the obs_ variables are to */
obs_old_style_reply = 0, /* 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;
@@ -1591,6 +1671,7 @@ init_vars(struct pine *ps, void (*cmds_f) (struct pine *, char **))
GLO_FEATURE_LEVEL = cpystr("sappling");
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);
@@ -1615,6 +1696,7 @@ init_vars(struct pine *ps, void (*cmds_f) (struct pine *, char **))
GLO_LOCAL_FULLNAME = cpystr(DF_LOCAL_FULLNAME);
GLO_LOCAL_ADDRESS = cpystr(DF_LOCAL_ADDRESS);
GLO_OVERLAP = cpystr(DF_OVERLAP);
+ GLO_SLEEP = cpystr("0");
GLO_MAXREMSTREAM = cpystr(DF_MAXREMSTREAM);
GLO_MARGIN = cpystr(DF_MARGIN);
GLO_FILLCOL = cpystr(DF_FILLCOL);
@@ -1985,6 +2067,8 @@ init_vars(struct pine *ps, void (*cmds_f) (struct pine *, char **))
set_current_val(&vars[V_FORM_FOLDER], 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);
+ regex_pattern(VAR_SPECIAL_TEXT);
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);
@@ -2069,6 +2153,13 @@ init_vars(struct pine *ps, void (*cmds_f) (struct pine *, char **))
}
}
+ set_current_val(&vars[V_SLEEP], TRUE, TRUE);
+ ps->sleep = i = 0;
+ if(SVAR_SLEEP(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
+ init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
+ else
+ ps->sleep = i;
+
set_current_val(&vars[V_OVERLAP], TRUE, TRUE);
ps->viewer_overlap = i = atoi(DF_OVERLAP);
if(SVAR_OVERLAP(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
@@ -2258,6 +2349,12 @@ init_vars(struct pine *ps, void (*cmds_f) (struct pine *, char **))
mail_parameters(NULL, SET_NEWSSPOOL,
(void *)VAR_NEWS_SPOOL_DIR);
+#ifndef _WINDOWS
+ set_current_val(&vars[V_MAILDIR_LOCATION], TRUE, TRUE);
+ if(VAR_MAILDIR_LOCATION && VAR_MAILDIR_LOCATION[0])
+ mail_parameters(NULL, SET_MDINBOXPATH, (void *)VAR_MAILDIR_LOCATION);
+#endif
+
/* guarantee a save default */
set_current_val(&vars[V_DEFAULT_SAVE_FOLDER], TRUE, TRUE);
if(!VAR_DEFAULT_SAVE_FOLDER || !VAR_DEFAULT_SAVE_FOLDER[0])
@@ -2497,7 +2594,7 @@ init_vars(struct pine *ps, void (*cmds_f) (struct pine *, char **))
set_current_val(&vars[V_ARCHIVED_FOLDERS], TRUE, TRUE);
set_current_val(&vars[V_INCOMING_FOLDERS], TRUE, TRUE);
set_current_val(&vars[V_SORT_KEY], TRUE, TRUE);
- if(decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev) == -1){
+ if(decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev,0) == -1){
snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Sort type \"%.200s\" is invalid", VAR_SORT_KEY);
init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
ps->def_sort = SortArrival;
@@ -2506,6 +2603,17 @@ init_vars(struct pine *ps, void (*cmds_f) (struct pine *, char **))
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++)
@@ -2592,6 +2700,7 @@ init_vars(struct pine *ps, void (*cmds_f) (struct pine *, char **))
if(cmds_f)
(*cmds_f)(ps, VAR_INIT_CMD_LIST);
+ (void)create_rule_list(ps_global->vars);
#ifdef _WINDOWS
mswin_set_quit_confirm (F_OFF(F_QUIT_WO_CONFIRM, ps_global));
#endif /* _WINDOWS */
@@ -2795,6 +2904,8 @@ feature_list(int index)
F_ALWAYS_SPELL_CHECK, h_config_always_spell_check, PREF_COMP, 0},
/* Reply Prefs */
+ {"alternate-reply-menu", NULL,
+ F_ALT_REPLY_MENU, h_config_alt_reply_menu, PREF_RPLY, 0},
{"copy-to-address-to-from-if-it-is-us", "Copy To Address to From if it is Us",
F_COPY_TO_TO_FROM, h_config_copy_to_to_from, PREF_RPLY, 0},
{"enable-reply-indent-string-editing", NULL,
@@ -2839,6 +2950,8 @@ feature_list(int index)
F_NO_FCC_ATTACH, h_config_no_fcc_attach, PREF_SEND, 0},
{"fcc-on-bounce", "Include Fcc When Bouncing Messages",
F_FCC_ON_BOUNCE, h_config_fcc_on_bounce, PREF_SEND, 0},
+ {"return-path-uses-domain-name", NULL,
+ F_USE_DOMAIN_NAME, h_config_use_domain, PREF_SEND, 0},
{"mark-fcc-seen", NULL,
F_MARK_FCC_SEEN, h_config_mark_fcc_seen, PREF_SEND, 0},
{"fcc-only-without-confirm", "Send to Fcc Only Without Confirming",
@@ -2885,6 +2998,10 @@ feature_list(int index)
F_SORT_DEFAULT_SAVE_ALPHA, h_config_sort_save_alpha, PREF_FLDR, 0},
{"vertical-folder-list", "Use Vertical Folder List",
F_VERTICAL_FOLDER_LIST, h_config_vertical_list, PREF_FLDR, 0},
+#ifndef _WINDOWS
+ {"use-courier-folder-list", "Courier Style Folder List",
+ F_COURIER_FOLDER_LIST, h_config_courier_list, PREF_FLDR, 0},
+#endif
/* Addr book */
{"combined-addrbook-display", "Combined Address Book Display",
@@ -2901,6 +3018,8 @@ feature_list(int index)
/* Index prefs */
{"auto-open-next-unread", NULL,
F_AUTO_OPEN_NEXT_UNREAD, h_config_auto_open_unread, PREF_INDX, 0},
+ {"enable-circular-tab", NULL,
+ F_AUTO_CIRCULAR_TAB, h_config_circular_tab, PREF_INDX, 0},
{"continue-tab-without-confirm", "Continue NextNew Without Confirming",
F_TAB_NO_CONFIRM, h_config_tab_no_prompt, PREF_INDX, 0},
{"convert-dates-to-localtime", NULL,
@@ -2913,6 +3032,8 @@ feature_list(int index)
F_ENABLE_SPACE_AS_TAB, h_config_cruise_mode, PREF_INDX, 0},
{"enable-cruise-mode-delete", "Enable Cruise Mode With Deleting",
F_ENABLE_TAB_DELETES, h_config_cruise_mode_delete, PREF_INDX, 0},
+ {"mark-for-me-in-group", "Mark for Group Message to Me",
+ F_MARK_FOR_GROUP, h_config_mark_for_group, PREF_INDX, 1},
{"mark-for-cc", "Mark for CC",
F_MARK_FOR_CC, h_config_mark_for_cc, PREF_INDX, 1},
{"next-thread-without-confirm", "Read Next Thread Without Confirming",
@@ -2929,6 +3050,8 @@ feature_list(int index)
F_COLOR_LINE_IMPORTANT, h_config_color_thrd_import, PREF_INDX, 0},
{"thread-sorts-by-arrival", "Thread Sorts by Arrival",
F_THREAD_SORTS_BY_ARRIVAL, h_config_thread_sorts_by_arrival, PREF_INDX, 0},
+ {"enhanced-fancy-thread-support", "Enhanced Fancy Thread Support",
+ F_ENHANCED_THREAD, h_config_enhanced_thread, PREF_INDX, 0},
/* Viewer prefs */
{"enable-msg-view-addresses", "Enable Message View Address Links",
@@ -2939,6 +3062,8 @@ feature_list(int index)
F_VIEW_SEL_URL, h_config_enable_view_url, PREF_VIEW, 1},
{"enable-msg-view-web-hostnames", "Enable Message View Web Hostname Links",
F_VIEW_SEL_URL_HOST, h_config_enable_view_web_host, PREF_VIEW, 1},
+ {"enable-msg-view-long-url", "Enable Recognition of Long URLS without Delimiter",
+ F_VIEW_LONG_URL, h_config_enable_long_url, PREF_VIEW, 0},
{"enable-msg-view-forced-arrows", "Enable Message View Forced Arrows",
F_FORCE_ARROWS, h_config_enable_view_arrows, PREF_VIEW, 0},
/* set to TRUE for windows */
@@ -3036,6 +3161,8 @@ feature_list(int index)
F_FORCE_LOW_SPEED, h_config_force_low_speed, PREF_OS_LWSD, 0},
{"auto-move-read-msgs", "Auto Move Read Messages",
F_AUTO_READ_MSGS, h_config_auto_read_msgs, PREF_MISC, 0},
+ {"auto-move-read-msgs-using-rules", "Auto Move Read Messages Using Rules",
+ F_AUTO_READ_MSGS_RULES, h_config_auto_read_msgs_rules, PREF_MISC, 0},
{"auto-unselect-after-apply", NULL,
F_AUTO_UNSELECT, h_config_auto_unselect, PREF_MISC, 0},
{"auto-unzoom-after-apply", NULL,
@@ -3097,6 +3224,8 @@ feature_list(int index)
F_FULL_AUTO_EXPUNGE, h_config_full_auto_expunge, PREF_MISC, 0},
{"force-arrow-cursor", NULL,
F_FORCE_ARROW, h_config_force_arrow, PREF_MISC, 0},
+ {"ignore-size-changes", NULL,
+ F_IGNORE_SIZE, h_config_ignore_size, PREF_MISC, 0},
{"maildrops-preserve-state", NULL,
F_MAILDROPS_PRESERVE_STATE, h_config_maildrops_preserve_state,
PREF_MISC, 0},
@@ -6442,6 +6571,7 @@ set_current_color_vals(struct pine *ps)
set_color_val(&vars[V_IND_OP_FORE_COLOR], 0);
set_color_val(&vars[V_INCUNSEEN_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_INDEX_TOKEN_COLORS], TRUE, TRUE);
set_current_val(&ps->vars[V_VIEW_HDR_COLORS], TRUE, TRUE);
@@ -6964,6 +7094,12 @@ toggle_feature(struct pine *ps, struct variable *var, FEATURE_S *f,
break;
+#ifndef _WINDOWS
+ 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 */
+#endif
+
case F_COLOR_LINE_IMPORTANT :
case F_DATES_TO_LOCAL :
clear_index_cache(ps->mail_stream, 0);
@@ -6975,6 +7111,7 @@ toggle_feature(struct pine *ps, struct variable *var, FEATURE_S *f,
break;
case F_MARK_FOR_CC :
+ case F_MARK_FOR_GROUP :
clear_index_cache(ps->mail_stream, 0);
if(THREADING() && sp_viewing_a_thread(ps->mail_stream))
unview_thread(ps, ps->mail_stream, ps->msgmap);
@@ -7569,10 +7706,40 @@ config_help(int var, int feature)
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_KEY_RULES:
+ return(h_config_key_macro_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_POST_CHAR_SET :
return(h_config_post_char_set);
case V_UNK_CHAR_SET :
@@ -7613,6 +7780,8 @@ config_help(int var, int feature)
return(h_config_incoming_second_interv);
case V_INCCHECKLIST :
return(h_config_incoming_list);
+ case V_SLEEP :
+ return(h_config_sleep);
case V_OVERLAP :
return(h_config_viewer_overlap);
case V_MAXREMSTREAM :
@@ -7623,6 +7792,8 @@ config_help(int var, int feature)
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 :
@@ -7745,6 +7916,10 @@ config_help(int var, int feature)
return(h_config_newmailwidth);
case V_NEWSRC_PATH :
return(h_config_newsrc_path);
+#ifndef _WINDOWS
+ case V_MAILDIR_LOCATION :
+ return(h_config_maildir_location);
+#endif
case V_BROWSER :
return(h_config_browser);
#if defined(DOS) || defined(OS2)
@@ -7788,6 +7963,9 @@ config_help(int var, int feature)
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);
@@ -8271,3 +8449,4 @@ pcpine_general_help(titlebuf)
}
#endif /* _WINDOWS */
+
diff --git a/pith/conf.h b/pith/conf.h
index 54c23ff5..2761d65b 100644
--- a/pith/conf.h
+++ b/pith/conf.h
@@ -144,10 +144,53 @@
#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_KEY_RULES vars[V_KEY_RULES].current_val.l
+#define GLO_KEY_RULES vars[V_KEY_RULES].global_val.l
+#define USR_KEY_RULES vars[V_KEY_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
#ifndef _WINDOWS
#define VAR_CHAR_SET vars[V_CHAR_SET].current_val.p
#define GLO_CHAR_SET vars[V_CHAR_SET].global_val.p
@@ -161,6 +204,8 @@
#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
@@ -229,6 +274,8 @@
#define GLO_OPENING_SEP vars[V_OPENING_SEP].global_val.p
#define VAR_ABOOK_FORMATS vars[V_ABOOK_FORMATS].current_val.l
#define VAR_INDEX_FORMAT vars[V_INDEX_FORMAT].current_val.p
+#define VAR_SLEEP vars[V_SLEEP].current_val.p
+#define GLO_SLEEP vars[V_SLEEP].global_val.p
#define VAR_OVERLAP vars[V_OVERLAP].current_val.p
#define GLO_OVERLAP vars[V_OVERLAP].global_val.p
#define VAR_MAXREMSTREAM vars[V_MAXREMSTREAM].current_val.p
@@ -250,6 +297,10 @@
#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
+#ifndef _WINDOWS
+#define VAR_MAILDIR_LOCATION vars[V_MAILDIR_LOCATION].current_val.p
+#define GLO_MAILDIR_LOCATION vars[V_MAILDIR_LOCATION].global_val.p
+#endif
#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
@@ -456,6 +507,8 @@
#define GLO_SIGNATURE_FORE_COLOR vars[V_SIGNATURE_FORE_COLOR].global_val.p
#define VAR_SIGNATURE_BACK_COLOR vars[V_SIGNATURE_BACK_COLOR].current_val.p
#define GLO_SIGNATURE_BACK_COLOR vars[V_SIGNATURE_BACK_COLOR].global_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
@@ -671,6 +724,10 @@
*/
#define Q_SUPP_LIMIT (4)
#define Q_DEL_ALL (-10)
+#define SVAR_SLEEP(ps,n,e,el) strtoval((ps)->VAR_SLEEP, \
+ &(n), 0, 120, 0, (e), \
+ (el), \
+ "Sleep-Interval-Length")
#define SVAR_OVERLAP(ps,n,e,el) strtoval((ps)->VAR_OVERLAP, \
&(n), 0, 20, 0, (e), \
(el), \
diff --git a/pith/conftype.h b/pith/conftype.h
index c654f6c5..496a616f 100644
--- a/pith/conftype.h
+++ b/pith/conftype.h
@@ -59,6 +59,7 @@ typedef enum { V_PERSONAL_NAME = 0
, 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
@@ -70,6 +71,20 @@ typedef enum { V_PERSONAL_NAME = 0
, 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_KEY_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
#ifndef _WINDOWS
, V_CHAR_SET
, V_OLD_CHAR_SET
@@ -80,6 +95,7 @@ typedef enum { V_PERSONAL_NAME = 0
, V_EDITOR
, V_SPELLER
, V_FILLCOL
+ , V_SPECIAL_TEXT
, V_REPLY_STRING
, V_REPLY_INTRO
, V_QUOTE_REPLACE_STRING
@@ -108,6 +124,7 @@ typedef enum { V_PERSONAL_NAME = 0
, V_MARGIN
, V_STATUS_MSG_DELAY
, V_ACTIVE_MSG_INTERVAL
+ , V_SLEEP
, V_MAILCHECK
, V_MAILCHECKNONCURR
, V_MAILDROPCHECK
@@ -115,6 +132,9 @@ typedef enum { V_PERSONAL_NAME = 0
, V_NEWSRC_PATH
, V_NEWS_ACTIVE_PATH
, V_NEWS_SPOOL_DIR
+#ifndef _WINDOWS
+ , V_MAILDIR_LOCATION
+#endif
, V_UPLOAD_CMD
, V_UPLOAD_CMD_PREFIX
, V_DOWNLOAD_CMD
@@ -230,6 +250,8 @@ typedef enum { V_PERSONAL_NAME = 0
, V_INCUNSEEN_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_HEADER_GENERAL_FORE_COLOR
@@ -327,6 +349,7 @@ typedef enum {
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,
@@ -342,9 +365,11 @@ typedef enum {
F_FORCE_ARROW,
F_PRUNE_USES_ISO,
F_ALT_ED_NOW,
+ F_IGNORE_SIZE,
F_SHOW_DELAY_CUE,
F_CANCEL_CONFIRM,
F_AUTO_OPEN_NEXT_UNREAD,
+ F_AUTO_CIRCULAR_TAB,
F_DISABLE_INDEX_LOCALE_DATES,
F_SELECTED_SHOWN_BOLD,
F_QUOTE_ALL_FROMS,
@@ -388,10 +413,14 @@ typedef enum {
F_PASS_C1_CONTROL_CHARS,
F_SINGLE_FOLDER_LIST,
F_VERTICAL_FOLDER_LIST,
+#ifndef _WINDOWS
+ F_COURIER_FOLDER_LIST,
+#endif
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,
@@ -408,6 +437,7 @@ typedef enum {
F_FIRST_SEND_FILTER_DFLT,
F_ALWAYS_LAST_FLDR_DFLT,
F_TAB_TO_NEW,
+ F_MARK_FOR_GROUP,
F_MARK_FOR_CC,
F_WARN_ABOUT_NO_SUBJECT,
F_WARN_ABOUT_NO_FCC,
@@ -443,6 +473,7 @@ typedef enum {
F_VIEW_SEL_ATTACH,
F_VIEW_SEL_URL,
F_VIEW_SEL_URL_HOST,
+ F_VIEW_LONG_URL,
F_SCAN_ADDR,
F_FORCE_ARROWS,
F_PREFER_PLAIN_TEXT,
@@ -501,11 +532,13 @@ typedef enum {
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_QUELL_USERAGENT,
F_COLOR_LINE_IMPORTANT,
+ F_ENHANCED_THREAD,
F_SLASH_COLL_ENTIRE,
F_ENABLE_FULL_HDR_AND_TEXT,
F_QUELL_FULL_HDR_RESET,
@@ -713,5 +746,6 @@ typedef struct smime_stuff {
/* exported protoypes */
+#define DF_THREAD_SORT_KEY "thread"
#endif /* PITH_CONFTYPE_INCLUDED */
diff --git a/pith/detoken.c b/pith/detoken.c
index 6f0584ab..0546cf04 100644
--- a/pith/detoken.c
+++ b/pith/detoken.c
@@ -24,7 +24,7 @@ static char rcsid[] = "$Id: detoken.c 769 2007-10-24 00:15:40Z hubert@u.washingt
#include "../pith/reply.h"
#include "../pith/mailindx.h"
#include "../pith/options.h"
-
+#include "../pith/rules.h"
/*
* Hook to read signature from local file
@@ -90,6 +90,8 @@ detoken(ACTION_S *role, ENVELOPE *env, int prenewlines, int postnewlines,
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;
@@ -103,14 +105,25 @@ detoken(ACTION_S *role, ENVELOPE *env, int prenewlines, int postnewlines,
* 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_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;
@@ -301,7 +314,7 @@ top:
}
}
}
- 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);
diff --git a/pith/filter.c b/pith/filter.c
index 692d6319..32309882 100644
--- a/pith/filter.c
+++ b/pith/filter.c
@@ -46,6 +46,7 @@ static char rcsid[] = "$Id: filter.c 1266 2009-07-14 18:39:12Z hubert@u.washingt
#include "../pith/conf.h"
#include "../pith/store.h"
#include "../pith/color.h"
+#include "../pith/osdep/color.h"
#include "../pith/escapes.h"
#include "../pith/pipe.h"
#include "../pith/status.h"
@@ -1375,14 +1376,24 @@ gf_b64_binary(FILTER_S *f, int flg)
register unsigned char t = f->t;
register int n = (int) f->n;
register int state = f->f1;
+ register unsigned char lastc;
while(GF_GETC(f, c)){
+ lastc = c;
+ if(f->f2){
+ GF_PUTC(f->next, c);
+ continue;
+ }
+
if(state){
state = 0;
if (c != '=') {
- gf_error("Illegal '=' in base64 text");
- /* NO RETURN */
+ f->f2++;
+ GF_PUTC(f->next, c);
+ q_status_message(SM_ORDER,3,3,
+ _("Warning: Illegal '=' in base64 text"));
+ continue;
}
}
@@ -1399,8 +1410,11 @@ gf_b64_binary(FILTER_S *f, int flg)
break;
default: /* impossible quantum position */
- gf_error("Internal base64 decoder error");
- /* NO RETURN */
+ f->f2++;
+ GF_PUTC(f->next, lastc);
+ q_status_message(SM_ORDER,3,3,
+ _("Warning: Internal base64 decode error"));
+ break;
}
}
}
@@ -1441,6 +1455,7 @@ gf_b64_binary(FILTER_S *f, int flg)
dprint((9, "-- gf_reset b64_binary\n"));
f->n = 0L; /* quantum position */
f->f1 = 0; /* state holder: equal seen? */
+ f->f2 = 0; /* No errors when we start */
}
}
@@ -7599,6 +7614,7 @@ html_element_comment(FILTER_S *f, char *s)
char *p, buf[MAILTMPLEN];
ADDRESS *adr;
extern char datestamp[];
+ extern char plevstamp[];
if(!strcmp(s = removing_quotes(s + 4), "ALPINE_VERSION")){
p = ALPINE_VERSION;
@@ -7612,6 +7628,9 @@ html_element_comment(FILTER_S *f, char *s)
else if(!strcmp(s, "ALPINE_COMPILE_DATE")){
p = datestamp;
}
+ else if(!strcmp(s, "ALPINE_PATCHLEVEL")){
+ p = plevstamp;
+ }
else if(!strcmp(s, "ALPINE_TODAYS_DATE")){
rfc822_date(p = buf);
}
@@ -9167,6 +9186,11 @@ typedef struct wrap_col_s {
margin_r,
indent;
char special[256];
+ long curlinenum; /* current line number */
+ int curqstrpos; /* current position in quote string */
+ long linenum; /* line number */
+ long qstrlen; /* multiples of 100 */
+ char **qstrln; /* qstrln[i] = quote string line i - 1 */
} WRAP_S;
#define WRAP_MARG_L(F) (((WRAP_S *)(F)->opt)->margin_l)
@@ -9208,6 +9232,12 @@ typedef struct wrap_col_s {
#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,W) { \
if((F)->linep == WRAP_LASTC(F)){ \
size_t offset = (F)->linep - (F)->line; \
@@ -9285,6 +9315,8 @@ gf_wrap(FILTER_S *f, int flg)
case CCR : /* CRLF or CR in text ? */
state = BOL; /* either way, handle start */
+ WRAP_CURLINE(f)++;
+ WRAP_CURPOS(f) = 0;
if(WRAP_FLOW(f)){
/* wrapped line? */
if(f->f2 == 0 && WRAP_SPC_LEN(f) && WRAP_TRL_SPC(f)){
@@ -9378,7 +9410,11 @@ gf_wrap(FILTER_S *f, int flg)
case BOL :
if(WRAP_FLOW(f)){
- if(c == '>'){
+ if(WRAP_CURLINE(f) < WRAP_QSTRLEN(f)
+ && 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 */
}
@@ -9392,7 +9428,16 @@ gf_wrap(FILTER_S *f, int flg)
}
/* 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;
@@ -9444,8 +9489,12 @@ gf_wrap(FILTER_S *f, int flg)
break;
case FL_QLEV :
- if(c == '>'){ /* another level */
- WRAP_FL_QC(f)++;
+ if(WRAP_CURLINE(f) < WRAP_QSTRLEN(f)
+ && 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 */
@@ -9457,7 +9506,16 @@ gf_wrap(FILTER_S *f, int flg)
}
/* 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 */
@@ -9514,6 +9572,13 @@ gf_wrap(FILTER_S *f, int flg)
state = FL_SIG;
break;
+ case ' ' : /* what? */
+ if (WRAP_CURLINE(f) < WRAP_QSTRLEN(f)
+ && 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 */
@@ -9530,7 +9595,7 @@ gf_wrap(FILTER_S *f, int flg)
&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 */
}
@@ -10027,7 +10092,7 @@ gf_wrap(FILTER_S *f, int flg)
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 */
}
@@ -10100,6 +10165,13 @@ gf_wrap(FILTER_S *f, int flg)
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 */
@@ -10450,7 +10522,8 @@ wrap_quote_insert(FILTER_S *f, unsigned char **ipp, unsigned char **eibp,
{
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);
@@ -10459,10 +10532,22 @@ wrap_quote_insert(FILTER_S *f, unsigned char **ipp, unsigned char **eibp,
last_prefix = NULL;
}
}
+
+ if(WRAP_CURLINE(f) < WRAP_QSTRLEN(f) && WRAP_QSTR(f, WRAP_CURLINE(f)))
+ wrap_qstr = cpystr(WRAP_QSTR(f, WRAP_CURLINE(f)));
+ len = wrap_qstr ? strlen(wrap_qstr) : 0;
- for(j = 0; j < WRAP_FL_QD(f); j++){
+ 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,
@@ -10470,7 +10555,7 @@ wrap_quote_insert(FILTER_S *f, unsigned char **ipp, unsigned char **eibp,
&& 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,
@@ -10478,7 +10563,7 @@ wrap_quote_insert(FILTER_S *f, unsigned char **ipp, unsigned char **eibp,
&& 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,
@@ -10492,43 +10577,60 @@ wrap_quote_insert(FILTER_S *f, unsigned char **ipp, unsigned char **eibp,
}
}
+ if (j > 1 && wrap_qstr[j-1] == ' ')
+ j -= 1;
+
if(!WRAP_LV_FLD(f)){
if(!WRAP_FOR_CMPS(f) && ps_global->VAR_QUOTE_REPLACE_STRING && prefix){
for(i = 0; prefix[i]; i++)
GF_PUTC_GLO(f->next, prefix[i]);
- f->n += utf8_width(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;
+ f->n += utf8_widthis(prefix);
}
else{
- GF_PUTC_GLO(f->next, '>');
- GF_PUTC_GLO(f->next, ' ');
- f->n += 2;
+ for (i = oldj; i < j; i++)
+ GF_PUTC_GLO(f->next, wrap_qstr[i]);
+ f->n += j - oldj;
}
}
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 += utf8_width(last_prefix);
+ f->n += utf8_widthis(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;
}
@@ -10560,6 +10662,12 @@ gf_wrap_filter_opt(int width, int width_max, int *margin, int indent, int flags)
wrap->hdr_color = (GFW_HDRCOLOR & flags) == GFW_HDRCOLOR;
wrap->for_compose = (GFW_FORCOMPOSE & flags) == GFW_FORCOMPOSE;
wrap->handle_soft_hyphen = (GFW_SOFTHYPHEN & flags) == GFW_SOFTHYPHEN;
+ 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);
}
@@ -11003,7 +11111,215 @@ typedef struct _linetest_s {
} \
}
+#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)++; \
+ } \
+}
+
+int end_of_line(char *line)
+{
+ int i;
+
+ for(i= 0; line && line[i]; i++){
+ if((line[i] == '\015' && line[i+1] == '\012') || line[i] == '\012')
+ break;
+ }
+ return i;
+}
+
+/* This macro is used in gf_quote_test. It receives a return code
+ from a filter. All filters that will print something must send
+ return code 0, except color_a_quote which must send return code
+ 1
+ */
+
+#define GF_ADD_QUOTED_LINE(F, line) \
+{ \
+ LT_INS_S *ins = NULL, *insp; \
+ int done; \
+ char *gline, *cline;\
+ unsigned char ch;\
+ register char *cp;\
+ register int l;\
+ \
+ for (gline = cline = line; gline && cline; ){\
+ if(cline = strchr(gline,'\012'))\
+ *cline = '\0';\
+ done = (*((LINETEST_S *) (F)->opt)->f)((F)->n++, gline, &ins,\
+ ((LINETEST_S *) (F)->opt)->local);\
+ if (done < 2){ \
+ if(done == 1)\
+ ADD_QUOTE_STRING((F));\
+ for(insp = ins, cp = gline; *cp ; ){\
+ if(insp && cp == insp->where){\
+ if(insp->len > 0){ \
+ for(l = 0; l < insp->len; l++){\
+ ch = (unsigned char) insp->text[l];\
+ GF_PUTC((F)->next, ch);\
+ }\
+ insp = insp->next;\
+ continue; \
+ } else if(insp->len < 0){ \
+ cp -= insp->len; \
+ insp = insp->next; \
+ continue; \
+ } \
+ }\
+ 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);\
+ if(cline){ \
+ *cline = '\012';\
+ gline += cline - gline + 1;\
+ }\
+ 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';\
+ i = end_of_line((F)->oldline); \
+ if (((F)->oldline)[i]){\
+ i += (((F)->oldline)[i] == '\015') ? 2 : 1;\
+ line = (F)->oldline + i;\
+ i = end_of_line(line); \
+ if(line[i])\
+ line[i] = '\0'; \
+ }\
+ 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;\
+ if ((F)->oldline)\
+ fs_give((void **)&(F)->oldline);\
+ (F)->oldline = cpystr(line);\
+ i = end_of_line(line); \
+ if (line[i]){ \
+ j = (line[i] == '\015') ? 2 : 1;\
+ line[i] = '\0'; \
+ i += j; \
+ }\
+ 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)){
+
+ GF_LINE_TEST_ADD(f, c);
+ if(c == '\012')
+ state++;
+ 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;
+ }
+ }
+
+ 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){
+ 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
diff --git a/pith/filter.h b/pith/filter.h
index 9916803d..e4021f23 100644
--- a/pith/filter.h
+++ b/pith/filter.h
@@ -216,6 +216,7 @@ void gf_prepend_editorial(FILTER_S *, int);
void *gf_prepend_editorial_opt(prepedtest_t, char *);
void gf_nvtnl_local(FILTER_S *, int);
void gf_local_nvtnl(FILTER_S *, int);
+void gf_quote_test(FILTER_S *, int);
void *gf_url_hilite_opt(URL_HILITE_S *, HANDLE_S **, int);
diff --git a/pith/filttype.h b/pith/filttype.h
index 21a1bec5..684299ca 100644
--- a/pith/filttype.h
+++ b/pith/filttype.h
@@ -35,6 +35,8 @@ typedef struct filter_s { /* type to hold data for filter function */
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];
diff --git a/pith/flag.c b/pith/flag.c
index b1bbf9c4..cf0ea39a 100644
--- a/pith/flag.c
+++ b/pith/flag.c
@@ -594,14 +594,16 @@ set_lflag(MAILSTREAM *stream, MSGNO_S *msgs, long int n, int f, int v)
was_invisible = (pelt->hidden || pelt->colhid) ? 1 : 0;
+ thrd = fetch_thread(stream, rawno);
+
if((chk_thrd_cnt = ((msgs->visible_threads >= 0L)
&& THRD_INDX_ENABLED() && (f & MN_HIDE) && (pelt->hidden != v))) != 0){
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){
diff --git a/pith/imap.c b/pith/imap.c
index ea4c5b1f..f0b93c9a 100644
--- a/pith/imap.c
+++ b/pith/imap.c
@@ -967,8 +967,18 @@ imap_get_passwd(MMLOGIN_S *m_list, char *passwd, char *user, STRLIST_S *hostlist
&& !strcmp(user, l->user)
&& l->altflag == altflag){
if(passwd){
+ if(l->invalidpwd == 0){
strncpy(passwd, l->passwd, NETMAXPASSWD);
passwd[NETMAXPASSWD-1] = '\0';
+ }
+ else{
+ q_status_message(SM_ORDER | SM_DING, 3, 4,
+ "Failed to login!. Re-enter password.");
+ dprint((9, "imap_get_passwd: reseting password due to login failure.\n"));
+ dprint((10, "imap_get_passwd: Old passwd=\"%s\"\n",
+ passwd ? passwd : "?"));
+ return FALSE;
+ }
}
dprint((9, "imap_get_passwd: match\n"));
dprint((10, "imap_get_passwd: trying passwd=\"%s\"\n",
@@ -1016,6 +1026,7 @@ imap_set_passwd(MMLOGIN_S **l, char *passwd, char *user, STRLIST_S *hostlist,
(*l)->altflag = altflag;
(*l)->ok_novalidate = ok_novalidate;
(*l)->warned = warned;
+ (*l)->invalidpwd = 0; /* assume correct password for now */
if(!(*l)->user)
(*l)->user = cpystr(user);
diff --git a/pith/imap.h b/pith/imap.h
index 86a0b533..a57400b9 100644
--- a/pith/imap.h
+++ b/pith/imap.h
@@ -35,6 +35,7 @@ typedef struct _mmlogin_s {
unsigned altflag:1;
unsigned ok_novalidate:1;
unsigned warned:1;
+ unsigned invalidpwd:1; /* password is invalid, assume valid */
STRLIST_S *hosts;
struct _mmlogin_s *next;
} MMLOGIN_S;
diff --git a/pith/indxtype.h b/pith/indxtype.h
index ee01a9bb..031e5ff5 100644
--- a/pith/indxtype.h
+++ b/pith/indxtype.h
@@ -76,12 +76,15 @@ typedef enum {iNothing, iStatus, iFStatus, iIStatus, iSIStatus,
iKey, iKeyInit,
iPrefDate, iPrefTime, iPrefDateTime,
iCurPrefDate, iCurPrefTime, iCurPrefDateTime,
- 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, iProcid, iScreen, iPkey,
+ iNick, iAddressTo, iAddressCc, iAddressRecip, iBcc, iLcc,
+ iFfrom, iFadd,
iSTime, iKSize,
iRoleNick, iNewLine,
iHeader, iText,
@@ -103,15 +106,26 @@ typedef struct index_parse_tokens {
/* 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 DELIM_COLON 0x40
-
+#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 DELIM_COLON 0x00040
+#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 FOR_KEY 0x20000 /* for rules */
+#define FOR_SAVE 0x40000 /* for rules */
#define DEFAULT_REPLY_INTRO "default"
diff --git a/pith/init.c b/pith/init.c
index d7942dcb..69379bf8 100644
--- a/pith/init.c
+++ b/pith/init.c
@@ -408,6 +408,9 @@ get_mail_list(CONTEXT_S *list_cntxt, char *folder_base)
&& stricmp(filename, folder_base)){
#else
if(strncmp(filename, folder_base, folder_base_len) == 0
+#ifndef _WINDOWS
+ && filename[folder_base_len] != list_cntxt->dir->delim
+#endif
&& strcmp(filename, folder_base)){
#endif
#endif
diff --git a/pith/mailcap.c b/pith/mailcap.c
index 34dce329..44285a8a 100644
--- a/pith/mailcap.c
+++ b/pith/mailcap.c
@@ -53,6 +53,7 @@ typedef struct mcap_entry {
int needsterminal;
char *contenttype;
char *command;
+ char *nametemplate;
char *testcommand;
char *label; /* unused */
char *printcommand; /* unused */
@@ -213,6 +214,9 @@ mc_init(void)
if(mc->printcommand)
dprint((11, " printcommand: %s",
mc->printcommand ? mc->printcommand : "?"));
+ if(mc->nametemplate)
+ dprint((11, " nametemplate: %s",
+ mc->nametemplate ? mc->nametemplate : "?"));
dprint((11, " needsterminal %d\n", mc->needsterminal));
}
}
@@ -488,6 +492,11 @@ mc_build_entry(char **tokens)
dprint((9, "mailcap: printcommand=%s\n",
mc->printcommand ? mc->printcommand : "?"));
}
+ else if(arg && !strucmp(*tokens, "nametemplate")){
+ mc->nametemplate = arg;
+ dprint((9, "mailcap: nametemplate=%s\n",
+ arg ? arg : "?"));
+ }
else if(arg && !strucmp(*tokens, "compose")){
/* not used */
dprint((9, "mailcap: not using compose=%s\n",
@@ -974,3 +983,60 @@ mailcap_free(void)
mail_free_stringlist(&MailcapData.raw);
mc_free_entry(&MailcapData.head);
}
+
+char *
+mc_template(char *tmp_file, BODY *body, int chk_extension)
+{
+ MailcapEntry *mc;
+ int quoted = 0;
+ char *s, *to, *namefile = NULL;
+
+ mc = mc_get_command(body->type, body->subtype, body, chk_extension, NULL);
+ if(!mc || !mc->nametemplate || !tmp_file)
+ return tmp_file;
+
+ /* remove extension if requested for a specific extension */
+ if(mc->nametemplate && tmp_file && (s = strrchr(tmp_file, '.')) != NULL
+ && strchr(s, C_FILESEP) == NULL)
+ *s = '\0';
+
+ to = tmp_20k_buf;
+ if((s = strrchr(tmp_file, C_FILESEP)) != NULL){
+ *s++ = '\0';
+ sstrncpy(&to, tmp_file, SIZEOF_20KBUF-(to-tmp_20k_buf));
+ if(to-tmp_20k_buf < SIZEOF_20KBUF)
+ *to++ = C_FILESEP;
+ namefile = s;
+ }
+
+ for(s = mc->nametemplate; *s; s++)
+ if(quoted){
+ quoted = 0;
+ switch(*s){
+ case '%':
+ if(to-tmp_20k_buf < SIZEOF_20KBUF)
+ *to++ = '%';
+ break;
+
+ case 's':
+ sstrncpy(&to, namefile ? namefile : tmp_file, SIZEOF_20KBUF-(to-tmp_20k_buf));
+ break;
+
+ default:
+ dprint((9,
+ "Ignoring unercognized format code in nametemplate: %%%c\n", *s ));
+ break;
+ }
+ }
+ else if(*s == '%')
+ quoted = 1;
+ else if(to-tmp_20k_buf < SIZEOF_20KBUF)
+ *to++ = *s;
+
+ *to++ = '\0';
+
+ fs_give((void **)&tmp_file);
+ tmp_file = cpystr(tmp_20k_buf);
+ return tmp_file;
+}
+
diff --git a/pith/mailcap.h b/pith/mailcap.h
index 25ccd115..c9f7a256 100644
--- a/pith/mailcap.h
+++ b/pith/mailcap.h
@@ -29,6 +29,7 @@ char *mc_conf_path(char *, char *, char *, int, char *);
int mailcap_can_display(int, char *, BODY *, int);
MCAP_CMD_S *mailcap_build_command(int, char *, BODY *, char *, int *, int);
void mailcap_free(void);
+char *mc_template(char *, BODY *, int);
/* currently mandatory to implement stubs */
diff --git a/pith/mailcmd.c b/pith/mailcmd.c
index 78ba98ad..3838c65d 100644
--- a/pith/mailcmd.c
+++ b/pith/mailcmd.c
@@ -39,6 +39,7 @@ static char rcsid[] = "$Id: mailcmd.c 1142 2008-08-13 17:22:21Z hubert@u.washing
#include "../pith/ablookup.h"
#include "../pith/search.h"
#include "../pith/charconv/utf8.h"
+#include "../pith/rules.h"
#ifdef _WINDOWS
#include "../pico/osdep/mswin.h"
@@ -665,6 +666,7 @@ do_broach_folder(char *newfolder, CONTEXT_S *new_context, MAILSTREAM **streamp,
strncpy(ps_global->cur_folder, p, 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(ps_global->mail_stream, 0);
/* MUST sort before restoring msgno! */
@@ -990,6 +992,7 @@ do_broach_folder(char *newfolder, CONTEXT_S *new_context, MAILSTREAM **streamp,
clear_index_cache(ps_global->mail_stream, 0);
reset_index_format();
+ setup_threading_index_style();
/*
* Start news reading with messages the user's marked deleted
@@ -1113,7 +1116,10 @@ do_broach_folder(char *newfolder, CONTEXT_S *new_context, MAILSTREAM **streamp,
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)
@@ -1135,124 +1141,7 @@ do_broach_folder(char *newfolder, CONTEXT_S *new_context, MAILSTREAM **streamp,
else
use_this_startup_rule = ps_global->inc_startup_rule;
- switch(use_this_startup_rule){
- /*
- * For news in incoming collection we're doing the same thing
- * for first-unseen and first-recent. In both those cases you
- * get first-unseen if FAKE_NEW is off and first-recent if
- * FAKE_NEW is on. If FAKE_NEW is on, first unseen is the
- * same as first recent because all recent msgs are unseen
- * and all unrecent msgs are seen (see pine_mail_open).
- */
- case IS_FIRST_UNSEEN:
-first_unseen:
- mn_set_cur(ps_global->msgmap,
- (sp_first_unseen(m)
- && mn_get_sort(ps_global->msgmap) == SortArrival
- && !mn_get_revsort(ps_global->msgmap)
- && !get_lflag(ps_global->mail_stream, NULL,
- sp_first_unseen(m), MN_EXLD)
- && (n = mn_raw2m(ps_global->msgmap,
- sp_first_unseen(m))))
- ? n
- : first_sorted_flagged(F_UNSEEN | F_UNDEL, m, pc,
- THREADING() ? 0 : FSF_SKIP_CHID));
- break;
-
- case IS_FIRST_RECENT:
-first_recent:
- /*
- * We could really use recent for news but this is the way
- * it has always worked, so we'll leave it. That is, if
- * the FAKE_NEW feature is on, recent and unseen are
- * equivalent, so it doesn't matter. If the feature isn't
- * on, all the undeleted messages are unseen and we start
- * at the first one. User controls with the FAKE_NEW feature.
- */
- if(IS_NEWS(ps_global->mail_stream)){
- mn_set_cur(ps_global->msgmap,
- first_sorted_flagged(F_UNSEEN|F_UNDEL, m, pc,
- THREADING() ? 0 : FSF_SKIP_CHID));
- }
- else{
- mn_set_cur(ps_global->msgmap,
- first_sorted_flagged(F_RECENT | F_UNSEEN
- | F_UNDEL,
- m, pc,
- THREADING() ? 0 : FSF_SKIP_CHID));
- }
- break;
-
- case IS_FIRST_IMPORTANT:
- mn_set_cur(ps_global->msgmap,
- first_sorted_flagged(F_FLAG|F_UNDEL, m, pc,
- THREADING() ? 0 : FSF_SKIP_CHID));
- break;
-
- case IS_FIRST_IMPORTANT_OR_UNSEEN:
-
- if(IS_NEWS(ps_global->mail_stream))
- goto first_unseen;
-
- {
- MsgNo flagged, first_unseen;
-
- flagged = first_sorted_flagged(F_FLAG|F_UNDEL, m, pc,
- THREADING() ? 0 : FSF_SKIP_CHID);
- first_unseen = (sp_first_unseen(m)
- && mn_get_sort(ps_global->msgmap) == SortArrival
- && !mn_get_revsort(ps_global->msgmap)
- && !get_lflag(ps_global->mail_stream, NULL,
- sp_first_unseen(m), MN_EXLD)
- && (n = mn_raw2m(ps_global->msgmap,
- sp_first_unseen(m))))
- ? n
- : first_sorted_flagged(F_UNSEEN|F_UNDEL, m, pc,
- THREADING() ? 0 : FSF_SKIP_CHID);
- mn_set_cur(ps_global->msgmap,
- (MsgNo) MIN((int) flagged, (int) first_unseen));
-
- }
-
- break;
-
- case IS_FIRST_IMPORTANT_OR_RECENT:
-
- if(IS_NEWS(ps_global->mail_stream))
- goto first_recent;
-
- {
- MsgNo flagged, first_recent;
-
- flagged = first_sorted_flagged(F_FLAG|F_UNDEL, m, pc,
- THREADING() ? 0 : FSF_SKIP_CHID);
- first_recent = first_sorted_flagged(F_RECENT | F_UNSEEN
- | F_UNDEL,
- m, pc,
- THREADING() ? 0 : FSF_SKIP_CHID);
- mn_set_cur(ps_global->msgmap,
- (MsgNo) MIN((int) flagged, (int) first_recent));
- }
-
- break;
-
- case IS_FIRST:
- mn_set_cur(ps_global->msgmap,
- first_sorted_flagged(F_UNDEL, m, pc,
- THREADING() ? 0 : FSF_SKIP_CHID));
- break;
-
- case IS_LAST:
- mn_set_cur(ps_global->msgmap,
- first_sorted_flagged(F_UNDEL, m, pc,
- FSF_LAST | (THREADING() ? 0 : FSF_SKIP_CHID)));
- break;
-
- default:
- panic("Unexpected incoming startup case");
- break;
-
- }
+ find_startup_position(use_this_startup_rule, m, pc);
}
else if(IS_NEWS(ps_global->mail_stream)){
/*
@@ -1430,9 +1319,11 @@ expunge_and_close(MAILSTREAM *stream, char **final_msg, long unsigned int flags)
/* 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)
|| (pith_opt_read_msg_prompt
&& (*pith_opt_read_msg_prompt)(seen_not_del, VAR_READ_MESSAGE_FOLDER)))
/* move inbox's read messages */
@@ -1703,6 +1594,9 @@ move_read_msgs(MAILSTREAM *stream, char *dstfldr, char *buf, size_t buflen, long
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;
@@ -1742,8 +1636,9 @@ move_read_msgs(MAILSTREAM *stream, char *dstfldr, char *buf, size_t buflen, long
snprintf(buf, buflen, "Moving %s read message%s to \"%s\"",
comatose(searched), plural(searched), dstfldr);
we_cancel = busy_cue(buf, NULL, 0);
- if(save(ps_global, stream, save_context, dstfldr, msgmap,
- SV_DELETE | SV_FIX_DELS | SV_INBOXWOCNTXT) == searched)
+ ps_global->exiting = 1;
+ if((save(ps_global, stream, save_context, dstfldr, msgmap,
+ SV_DELETE | SV_FIX_DELS | SV_INBOXWOCNTXT) == searched))
strncpy(bufp = buf + 1, "Moved", MIN(5,buflen)); /* change Moving to Moved */
buf[buflen-1] = '\0';
@@ -1781,7 +1676,9 @@ move_read_incoming(MAILSTREAM *stream, CONTEXT_S *context, char *folder,
&& ((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;
@@ -2739,3 +2636,295 @@ get_uname(char *mailbox, char *target, int len)
return(*target ? target : NULL);
}
+
+char *
+move_read_msgs_using_rules(MAILSTREAM *stream, char *dstfldr, char *buf)
+{
+ CONTEXT_S *save_context = NULL;
+ char **folder_to_save = NULL;
+ int num, we_cancel;
+ long i, j, success;
+ MSGNO_S *msgmap = NULL;
+ unsigned long nmsgs = 0L, stream_nmsgs;
+
+ 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);
+ stream_nmsgs = 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(stream, msgmap);
+ sprintf(buf, "Moving %s read message%s to \"%.45s\"",
+ comatose(num), plural(num), folder_to_save[i]);
+ we_cancel = busy_cue(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_cue(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;
+}
+
+char *
+get_folder_to_save(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_SAVE, 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;
+}
+
+unsigned long
+rules_cursor_pos(MAILSTREAM *stream)
+{
+ MSGNO_S *msgmap = sp_msgmap(stream);
+ return rule_curpos != 0L ? rule_curpos : mn_m2raw(msgmap,mn_get_cur(msgmap));
+}
+
+void
+setup_threading_index_style(void)
+{
+ RULE_RESULT *rule;
+ NAMEVAL_S *v;
+ int i;
+
+ rule = get_result_rule(V_THREAD_INDEX_STYLE_RULES, FOR_THREAD, 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);
+ }
+ }
+}
+
+unsigned
+get_perfolder_startup_rule(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_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;
+}
+
+void
+find_startup_position(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;
+
+ }
+}
diff --git a/pith/mailcmd.h b/pith/mailcmd.h
index 9e99c6f3..d590b7c1 100644
--- a/pith/mailcmd.h
+++ b/pith/mailcmd.h
@@ -42,6 +42,8 @@
#define DB_FROMTAB 0x02 /* opening because of TAB command */
#define DB_INBOXWOCNTXT 0x04 /* interpret inbox as one true inbox */
+static MAILSTREAM *saved_stream;
+static unsigned long rule_curpos = 0L;
/*
* generic "is aggregate message command?" test
@@ -63,7 +65,13 @@ int do_broach_folder(char *, CONTEXT_S *, MAILSTREAM **, unsigned long);
void expunge_and_close(MAILSTREAM *, char **, unsigned long);
void agg_select_all(MAILSTREAM *, MSGNO_S *, long *, int);
char *move_read_msgs(MAILSTREAM *, char *, char *, size_t, long);
+char *move_read_msgs_using_rules (MAILSTREAM *, char *, char *);
+unsigned get_perfolder_startup_rule (MAILSTREAM *, int, char *);
+void setup_threading_index_style (void);
+void find_startup_position (int, MAILSTREAM *, long);
+char *get_folder_to_save (MAILSTREAM *, long, char *);
char *move_read_incoming(MAILSTREAM *, CONTEXT_S *, char *, char **, char *, size_t);
+unsigned long rules_cursor_pos (MAILSTREAM *);
void cross_delete_crossposts(MAILSTREAM *);
long zoom_index(struct pine *, MAILSTREAM *, MSGNO_S *, int);
int unzoom_index(struct pine *, MAILSTREAM *, MSGNO_S *);
diff --git a/pith/mailindx.c b/pith/mailindx.c
index 09cdc2c8..12fbb5d2 100644
--- a/pith/mailindx.c
+++ b/pith/mailindx.c
@@ -17,6 +17,7 @@ static char rcsid[] = "$Id: mailindx.c 1266 2009-07-14 18:39:12Z hubert@u.washin
#include "../pith/headers.h"
#include "../pith/mailindx.h"
+#include "../pith/pineelt.h"
#include "../pith/mailview.h"
#include "../pith/flag.h"
#include "../pith/icache.h"
@@ -40,6 +41,7 @@ static char rcsid[] = "$Id: mailindx.c 1266 2009-07-14 18:39:12Z hubert@u.washin
#include "../pith/send.h"
#include "../pith/options.h"
#include "../pith/ablookup.h"
+#include "../pith/rules.h"
#ifdef _WINDOWS
#include "../pico/osdep/mswin.h"
#endif
@@ -104,7 +106,6 @@ char *copy_format_str(int, int, char *, int);
void set_print_format(IELEM_S *, int, int);
void set_ielem_widths_in_field(IFIELD_S *);
-
#define BIGWIDTH 2047
@@ -228,6 +229,7 @@ init_index_format(char *format, INDEX_COL_S **answer)
case iSTime:
case iKSize:
case iSize:
+ case iSizeThread:
case iPrioAlpha:
(*answer)[column].req_width = 7;
break;
@@ -374,6 +376,13 @@ reset_index_format(void)
PAT_STATE pstate;
PAT_S *pat;
int we_set_it = 0;
+ char *rule;
+
+ if(rule = get_rule_result(FOR_INDEX, ps_global->cur_folder, V_INDEX_RULES)){
+ init_index_format(rule, &ps_global->index_disp_format);
+ fs_give((void **)&rule);
+ return;
+ }
if(ps_global->mail_stream && nonempty_patterns(rflags, &pstate)){
for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)){
@@ -447,14 +456,15 @@ free_hdrtok(HEADER_TOK_S **hdrtok)
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},
{"SHORTIMAPSTATUS", iSIStatus, FOR_INDEX},
@@ -463,55 +473,58 @@ static INDEX_PARSE_T itokens[] = {
{"SUBJECTTEXT", iSubjectText, FOR_INDEX},
{"SUBJKEYTEXT", iSubjKeyText, FOR_INDEX},
{"SUBJKEYINITTEXT", iSubjKeyInitText, FOR_INDEX},
- {"OPENINGTEXT", iOpeningText, FOR_INDEX},
- {"OPENINGTEXTNQ", iOpeningTextNQ, FOR_INDEX},
- {"KEY", iKey, FOR_INDEX},
- {"KEYINIT", iKeyInit, FOR_INDEX},
+ {"OPENINGTEXT", iOpeningText, FOR_INDEX|FOR_RULE|FOR_SAVE|FOR_TRIM},
+ {"OPENINGTEXTNQ", iOpeningTextNQ, FOR_INDEX|FOR_RULE|FOR_SAVE|FOR_TRIM},
+ {"KEY", iKey, FOR_INDEX|FOR_RULE|FOR_SAVE|FOR_COMPOSE},
+ {"KEYINIT", iKeyInit, FOR_INDEX|FOR_RULE|FOR_SAVE|FOR_COMPOSE},
{"DESCRIPSIZE", iDescripSize, FOR_INDEX},
{"ATT", iAtt, FOR_INDEX},
{"SCORE", iScore, FOR_INDEX},
{"PRIORITY", iPrio, FOR_INDEX},
{"PRIORITYALPHA", iPrioAlpha, FOR_INDEX},
- {"PRIORITY!", iPrioBang, 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},
- {"SMARTDATEISO", iSDateIso, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATESHORTISO",iSDateIsoS, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATES1", iSDateS1, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATES2", iSDateS2, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATES3", iSDateS3, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATES4", iSDateS4, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATETIME", iSDateTime, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATETIMEISO",iSDateTimeIso, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATETIMESHORTISO",iSDateTimeIsoS,FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATETIMES1", iSDateTimeS1, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATETIMES2", iSDateTimeS2, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATETIMES3", iSDateTimeS3, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATETIMES4", iSDateTimeS4, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATETIME24", iSDateTime24, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATETIMEISO24", iSDateTimeIso24,FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATETIMESHORTISO24",iSDateTimeIsoS24,FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATETIMES124", iSDateTimeS124, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATETIMES224", iSDateTimeS224, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATETIMES324", iSDateTimeS324, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"SMARTDATETIMES424", iSDateTimeS424, 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},
+ {"PRIORITY!", iPrioBang, FOR_INDEX},
+ {"LONGDATE", iLDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SHORTDATE1", iS1Date, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SHORTDATE2", iS2Date, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SHORTDATE3", iS3Date, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SHORTDATE4", iS4Date, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"DATEISO", iDateIso, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SHORTDATEISO", iDateIsoS, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATE", iSDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTTIME", iSTime, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATEISO", iSDateIso, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATESHORTISO",iSDateIsoS, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATES1", iSDateS1, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATES2", iSDateS2, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATES3", iSDateS3, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATES4", iSDateS4, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATETIME", iSDateTime, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATETIMEISO",iSDateTimeIso, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATETIMESHORTISO",iSDateTimeIsoS,FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATETIMES1", iSDateTimeS1, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATETIMES2", iSDateTimeS2, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATETIMES3", iSDateTimeS3, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATETIMES4", iSDateTimeS4, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATETIME24", iSDateTime24, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATETIMEISO24", iSDateTimeIso24,FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATETIMESHORTISO24",iSDateTimeIsoS24,FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATETIMES124", iSDateTimeS124, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATETIMES224", iSDateTimeS224, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATETIMES324", iSDateTimeS324, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"SMARTDATETIMES424", iSDateTimeS424, 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_RULE|FOR_COMPOSE},
+ {"TO", iTo, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_COMPOSE},
+ {"SENDER", iSender, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"CC", iCc, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_SAVE|FOR_SAVE},
+ {"ADDRESSTO", iAddressTo, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"ADDRESSCC", iAddressCc, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"ADDRESSRECIPS", iAddressRecip, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
{"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},
@@ -520,56 +533,68 @@ static INDEX_PARSE_T itokens[] = {
{"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},
- {"PREFDATE", iPrefDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"PREFTIME", iPrefTime, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
- {"PREFDATETIME", iPrefDateTime, 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},
+ {"PREFDATE", iPrefDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"PREFTIME", iPrefTime, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
+ {"PREFDATETIME", iPrefDateTime, 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_FILT|FOR_RULE|FOR_SAVE},
+ {"CURDATEISO", iCurDateIso, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"CURDATEISOS", iCurDateIsoS, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"CURTIME24", iCurTime24, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"CURTIME12", iCurTime12, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"CURDAY", iCurDay, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"CURDAY2DIGIT", iCurDay2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"CURDAYOFWEEK", iCurDayOfWeek, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
{"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},
- {"CURPREFDATE", iCurPrefDate, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
- {"CURPREFTIME", iCurPrefTime, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
+ FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"CURMONTH", iCurMon, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"CURMONTH2DIGIT", iCurMon2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"CURMONTHLONG", iCurMonLong, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"CURMONTHABBREV", iCurMonAbb, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"CURYEAR", iCurYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"CURYEAR2DIGIT", iCurYear2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"CURPREFDATE", iCurPrefDate, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"CURPREFTIME", iCurPrefTime, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
{"CURPREFDATETIME", iCurPrefDateTime,
- 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_FILT|FOR_RULE|FOR_SAVE},
+ {"LASTMONTH", iLstMon, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"LASTMONTH2DIGIT", iLstMon2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"LASTMONTHLONG", iLstMonLong, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"LASTMONTHABBREV", iLstMonAbb, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"LASTMONTHYEAR", iLstMonYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
{"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_FILT|FOR_RULE|FOR_SAVE},
+ {"LASTYEAR", iLstYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
+ {"LASTYEAR2DIGIT", iLstYear2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE},
{"HEADER", iHeader, FOR_INDEX},
{"TEXT", iText, FOR_INDEX},
{"ARROW", iArrow, FOR_INDEX},
{"NEWLINE", iNewLine, FOR_REPLY_INTRO},
{"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},
+ {"PROCID", iProcid, FOR_RULE|FOR_RESUB|FOR_FLAG|FOR_COMPOSE|FOR_TRIM|FOR_TEMPLATE},
+ {"PKEY", iPkey, FOR_RULE|FOR_KEY},
+ {"SCREEN", iScreen, FOR_RULE|FOR_KEY},
+ {"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}
};
@@ -943,7 +968,7 @@ static IndexColType fixed_ctypes[] = {
iSDateTimeS1, iSDateTimeS2, iSDateTimeS3, iSDateTimeS4,
iSDateTimeIso24, iSDateTimeIsoS24,
iSDateTimeS124, iSDateTimeS224, iSDateTimeS324, iSDateTimeS424,
- iSize, iSizeComma, iSizeNarrow, iKSize, iDescripSize,
+ iSize, iSizeComma, iSizeNarrow, iKSize, iDescripSize, iSizeThread,
iPrio, iPrioBang, iPrioAlpha, iInit,
iAtt, iTime24, iTime12, iTimezone, iMonAbb, iYear, iYear2Digit,
iDay2Digit, iMon2Digit, iDayOfWeekAbb, iScore, iMonLong, iDayOfWeek
@@ -1136,6 +1161,7 @@ setup_index_header_widths(MAILSTREAM *stream)
case iTime12:
case iSize:
case iKSize:
+ case iSizeThread:
cdesc->actual_length = 7;
cdesc->adjustment = Right;
break;
@@ -1229,7 +1255,7 @@ setup_index_header_widths(MAILSTREAM *stream)
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 */
@@ -1612,10 +1638,12 @@ build_header_work(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap,
/* 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);
+ /*branch = get_branch(stream,thrd)*/
+ else if(!mn_get_revsort(msgmap) && thrd->branch)
+ thrd = fetch_thread(stream, thrd->branch);
else
thrd = NULL;
} while(thrd
@@ -2027,13 +2055,10 @@ format_index_index_line(INDEXDATA_S *idata)
*/
ice = copy_ice(ice);
+ thrd = fetch_thread(idata->stream, idata->rawno);
/* is this a collapsed thread index line? */
- if(!idata->bogus && THREADING()){
- thrd = fetch_thread(idata->stream, idata->rawno);
- collapsed = thrd && thrd->next
- && get_lflag(idata->stream, NULL,
- idata->rawno, MN_COLL);
- }
+ if(!idata->bogus && THREADING())
+ collapsed = thrd && thread_is_kolapsed(ps_global, idata->stream, ps_global->msgmap, idata->rawno);
/* calculate contents of the required fields */
for(cdesc = ps_global->index_disp_format; cdesc->ctype != iNothing; cdesc++)
@@ -2075,10 +2100,15 @@ format_index_index_line(INDEXDATA_S *idata)
if(to_us == ' ')
to_us = '+';
+ if(to_us == '+'
+ && F_ON(F_MARK_FOR_GROUP,ps_global) &&
+ (addr->next || addr != fetch_to(idata)))
+ to_us = '.';
+
break;
}
- if(to_us != '+' && resent_to_us(idata)){
+ if(to_us == ' ' && resent_to_us(idata)){
ice->to_us = 1;
if(to_us == ' ')
to_us = '+';
@@ -2132,7 +2162,7 @@ format_index_index_line(INDEXDATA_S *idata)
ielem->color = new_color_pair(VAR_IND_IMP_FORE_COLOR, VAR_IND_IMP_BACK_COLOR);
}
}
- else if(str[0] == '+' || str[0] == '-'){
+ else if(str[0] == '+' || str[0] == '-' || str[0] == '.'){
if(VAR_IND_PLUS_FORE_COLOR && VAR_IND_PLUS_BACK_COLOR){
ielem = ifield->ielem;
ielem->freecolor = 1;
@@ -2188,6 +2218,12 @@ format_index_index_line(INDEXDATA_S *idata)
for(addr = fetch_to(idata); addr; addr = addr->next)
if(address_is_us(addr, ps_global)){
to_us = '+';
+
+ if(to_us == '+'
+ && F_ON(F_MARK_FOR_GROUP,ps_global) &&
+ (addr->next || addr != fetch_to(idata)))
+ to_us = '.';
+
break;
}
@@ -2283,7 +2319,7 @@ format_index_index_line(INDEXDATA_S *idata)
if(pico_usingcolor()){
- if(str[0] == '+' || str[0] == '-'){
+ if(str[0] == '+' || str[0] == '-' || str[0] == '.'){
if(start == 0
&& VAR_IND_PLUS_FORE_COLOR
&& VAR_IND_PLUS_BACK_COLOR){
@@ -2465,6 +2501,24 @@ format_index_index_line(INDEXDATA_S *idata)
from_str(cdesc->ctype, idata, str, sizeof(str), ice);
break;
+ case iAddressTo:
+ case iAddressCc:
+ case iAddressRecip:
+ {ENVELOPE *env;
+ int we_clear;
+ env = rules_fetchenvelope(idata, &we_clear);
+ sprintf(str, "%-*.*s", ifield->width, ifield->width,
+ detoken_src((cdesc->ctype == iAddressTo
+ ? "_ADDRESSTO_"
+ : (cdesc->ctype == iAddressCc
+ ? "_ADRESSCC_"
+ : "_ADRESSRECIPS_")), FOR_INDEX,
+ env, NULL, NULL, NULL));
+ if(we_clear)
+ mail_free_envelope(&env);
+ }
+ break;
+
case iTo:
if(((field = ((addr = fetch_to(idata))
? "To"
@@ -2531,7 +2585,30 @@ format_index_index_line(INDEXDATA_S *idata)
break;
+ case iSizeThread:
+ if (!THREADING()){
+ goto getsize;
+ } else if (collapsed){
+ l = count_flags_in_thread(idata->stream, thrd, F_NONE);
+ snprintf(str, sizeof(str), "(%lu)", l);
+ }
+ else{
+ thrd = fetch_thread(idata->stream, idata->rawno);
+ if(!thrd)
+ snprintf(str, sizeof(str), "%s", "Error");
+ else{
+ long lengthb;
+ lengthb = get_length_branch(idata->stream, idata->rawno);
+ if (lengthb > 0L)
+ snprintf(str, sizeof(str), "(%lu)", lengthb);
+ else
+ snprintf(str,sizeof(str), "%s", " ");
+ }
+ }
+ break;
+
case iSize:
+getsize:
/* 0 ... 9999 */
if((l = fetch_size(idata)) < 10*1000L)
snprintf(str, sizeof(str), "(%lu)", l);
@@ -2785,7 +2862,6 @@ format_index_index_line(INDEXDATA_S *idata)
if(first_text){
strncpy(str, first_text, BIGWIDTH);
str[BIGWIDTH] = '\0';
- fs_give((void **) &first_text);
}
}
@@ -3107,7 +3183,7 @@ format_thread_index_line(INDEXDATA_S *idata)
tice->linecolor = new_color_pair(VAR_IND_IMP_FORE_COLOR,
VAR_IND_IMP_BACK_COLOR);
}
- else if((to_us == '+' || to_us == '-')
+ else if((to_us == '+' || to_us == '-' || to_us == '.')
&& VAR_IND_PLUS_FORE_COLOR && VAR_IND_PLUS_BACK_COLOR){
ielem = ifield->ielem;
ielem->freecolor = 1;
@@ -3710,6 +3786,26 @@ fetch_firsttext(INDEXDATA_S *idata, int delete_quotes)
gf_io_t pc;
long partial_fetch_len = 0L;
SEARCHSET *ss, **sset;
+ MESSAGECACHE *mc;
+ PINELT_S *pelt;
+
+ /* we cache the result we get from this function, so that we do not have to
+ * refetch the text in case there is a change. We could cache in the envelope
+ * but c-client does not have a special field for that, nor we want to use the
+ * sparep pointer, since there could be other uses for sparep later, and even
+ * if we add a pointer to the ENVELOPE structure, we would be caching the same
+ * text twice (one in a private pointer, and the new pointer) and that would
+ * not make sense. Instead we will use an elt for this
+ */
+
+ if((mc = mail_elt(idata->stream, idata->rawno))
+ && ((pelt = (PINELT_S *) mc->sparep) == NULL)){
+ pelt = (PINELT_S *) fs_get(sizeof(PINELT_S));
+ memset(pelt, 0, sizeof(PINELT_S));
+ }
+
+ if(pelt && pelt->firsttext != NULL)
+ return(pelt->firsttext);
try_again:
@@ -3803,7 +3899,17 @@ try_again:
if(p > buf){
size_t l;
-
+ ENVELOPE *env;
+ char *rule_result;
+
+ if(rule_result = find_value((delete_quotes
+ ? "_OPENINGTEXTNQ_" : "_OPENINGTEXT_"),
+ buf, PROCESS_SP, idata, 4)){
+ collspaces(rule_result);
+ strncpy(buf, rule_result, sizeof(buf));
+ buf[sizeof(buf) - 1] = '\0';
+ fs_give((void **) &rule_result);
+ }
l = strlen(buf);
l += 100;
firsttext = fs_get((l+1) * sizeof(char));
@@ -3827,6 +3933,8 @@ try_again:
goto try_again;
}
}
+ if(mc && pelt)
+ pelt->firsttext = firsttext;
}
}
}
@@ -5267,10 +5375,10 @@ subj_str(INDEXDATA_S *idata, char *str, size_t strsize, SubjKW kwtype, int openi
{
char *subject, *origsubj, *origstr, *rawsubj, *sptr = NULL;
char *p, *border, *q = NULL, *free_subj = NULL;
- char *sp;
+ char *sp, *rule_result;
size_t len;
int width = -1;
- int depth = 0, mult = 2;
+ int depth = 0, mult = 2, collapsed, i, we_clear = 0;
int save;
int do_subj = 0, truncated_tree = 0;
PINETHRD_S *thd, *thdorig;
@@ -5324,7 +5432,13 @@ subj_str(INDEXDATA_S *idata, char *str, size_t strsize, SubjKW kwtype, int openi
* origsubj is the original subject but it has been decoded. We need
* to free it at the end of this routine.
*/
-
+ if (rule_result = find_value("_SUBJECT_", origsubj, PROCESS_SP, idata, 4)){
+ if(origsubj)
+ fs_give((void **)&origsubj);
+ we_clear++;
+ origsubj = cpystr(rule_result);
+ fs_give((void **)&rule_result);
+ }
/*
* prepend_keyword will put the keyword stuff before the subject
@@ -5412,10 +5526,8 @@ subj_str(INDEXDATA_S *idata, char *str, size_t strsize, SubjKW kwtype, int openi
if(pith_opt_condense_thread_cue)
width = (*pith_opt_condense_thread_cue)(thd, ice, &str, &strsize, width,
- thd && thd->next
- && get_lflag(idata->stream,
- NULL,idata->rawno,
- MN_COLL));
+ this_thread_is_kolapsed(ps_global, idata->stream, ps_global->msgmap, idata->rawno) &&
+ (count_thread(ps_global,idata->stream, ps_global->msgmap, idata->rawno) != 1));
/*
* width is < available strsize and
@@ -5765,6 +5877,9 @@ subj_str(INDEXDATA_S *idata, char *str, size_t strsize, SubjKW kwtype, int openi
if(free_subj)
fs_give((void **) &free_subj);
+
+ if (we_clear && origsubj)
+ fs_give((void **)&origsubj);
}
@@ -6043,11 +6158,8 @@ from_str(IndexColType ctype, INDEXDATA_S *idata, char *str, size_t strsize, ICE_
border = str + width;
if(pith_opt_condense_thread_cue)
width = (*pith_opt_condense_thread_cue)(thd, ice, &str, &strsize, width,
- thd && thd->next
- && get_lflag(idata->stream,
- NULL,idata->rawno,
- MN_COLL));
-
+ this_thread_is_kolapsed(ps_global, idata->stream, ps_global->msgmap, idata->rawno) &&
+ (count_thread(ps_global,idata->stream, ps_global->msgmap, idata->rawno) != 1));
fptr = str;
if(thd)
@@ -6133,16 +6245,33 @@ from_str(IndexColType ctype, INDEXDATA_S *idata, char *str, size_t strsize, ICE_
? "To"
: (addr = fetch_cc(idata))
? "Cc"
- : NULL))
- && set_index_addr(idata, field, addr, "To: ",
- strsize-1, fptr))
- break;
+ : NULL))){
+ char *rule_result;
+ rule_result = find_value("_FROM_", NULL, 0, idata, 1);
+ if (!rule_result)
+ set_index_addr(idata, field, addr, "To: ",
+ strsize-1, fptr);
+ else{
+ sprintf(str, "%-*.*s", strsize-1, strsize-1,
+ rule_result);
+ fs_give((void **)&rule_result);
+ }
+ break;
+ }
if(ctype == iFromTo &&
(newsgroups = fetch_newsgroups(idata)) &&
*newsgroups){
- snprintf(fptr, strsize, "To: %-*.*s", strsize-1-4, strsize-1-4,
- newsgroups);
+ char *rule_result;
+ rule_result = find_value("_FROM_", NULL, 0, idata, 1);
+ if (!rule_result)
+ sprintf(str, "To: %-*.*s", strsize-1-4,
+ strsize-1-4, newsgroups);
+ else{
+ sprintf(str, "%-*.*s", strsize-1, strsize-1,
+ rule_result);
+ fs_give((void **)&rule_result);
+ }
break;
}
@@ -6155,7 +6284,15 @@ from_str(IndexColType ctype, INDEXDATA_S *idata, char *str, size_t strsize, ICE_
break;
case iFrom:
- set_index_addr(idata, "From", fetch_from(idata), NULL, strsize-1, fptr);
+ { char *rule_result;
+ rule_result = find_value("_FROM_", NULL, 0, idata, 4);
+ if (!rule_result)
+ set_index_addr(idata, "From", fetch_from(idata), NULL, strsize-1, fptr);
+ else{
+ sprintf(str, "%-*.*s", strsize-1, strsize-1, rule_result);
+ fs_give((void **)&rule_result);
+ }
+ }
break;
case iAddress:
@@ -6452,3 +6589,64 @@ set_print_format(IELEM_S *ielem, int width, int leftadj)
}
}
}
+
+void
+setup_threading_display_style(void)
+{
+ RULE_RESULT *rule;
+ NAMEVAL_S *v;
+ int i;
+
+ rule = get_result_rule(V_THREAD_DISP_STYLE_RULES, FOR_THREAD, 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);
+ }
+ }
+}
+
+char *
+find_value(char *token, char *use_this, int flag, INDEXDATA_S *idata, int nfcn)
+{
+ int n = 0, i, rule_context, we_clear;
+ char *rule_result = NULL, **list;
+ ENVELOPE *env;
+ RULELIST *rule;
+ RULE_S *prule;
+
+ env = rules_fetchenvelope(idata, &we_clear);
+ if(env && env->sparep)
+ fs_give((void **)&env->sparep);
+ if(we_clear)
+ mail_free_envelope(&env);
+ if(rule = get_rulelist_from_code(V_REPLACE_RULES, ps_global->rule_list)){
+ list = functions_for_token(token);
+ while(rule_result == NULL && (prule = get_rule(rule,n++))){
+ rule_context = 0;
+ if (prule->action->token && !strcmp(prule->action->token, token)){
+ for (i = 0; i < nfcn; i++)
+ if(list[i+1] && !strcmp(prule->action->function, list[i+1]))
+ rule_context |= context_for_function(list[i+1]);
+ if (rule_context){
+ env = rules_fetchenvelope(idata, &we_clear);
+ if(use_this)
+ env->sparep = get_sparep_for_rule(use_this, flag);
+ rule_result = process_rule(prule, rule_context, env);
+ if(env->sparep)
+ free_sparep_for_rule(&env->sparep);
+ if(we_clear)
+ mail_free_envelope(&env);
+ }
+ }
+ }
+ }
+ return rule_result;
+}
diff --git a/pith/mailindx.h b/pith/mailindx.h
index 8eb23033..fdea552c 100644
--- a/pith/mailindx.h
+++ b/pith/mailindx.h
@@ -30,6 +30,9 @@ extern void (*setup_header_widths)(MAILSTREAM *);
/* exported prototypes */
+SortOrder translate (char *, int);
+char *find_value (char *, char *, int, INDEXDATA_S *, int);
+void setup_threading_display_style (void);
int msgline_hidden(MAILSTREAM *, MSGNO_S *, long, int);
void adjust_cur_to_visible(MAILSTREAM *, MSGNO_S *);
unsigned long line_hash(char *);
diff --git a/pith/mailview.c b/pith/mailview.c
index 40728aab..5df0dbdb 100644
--- a/pith/mailview.c
+++ b/pith/mailview.c
@@ -52,7 +52,11 @@ static char rcsid[] = "$Id: mailview.c 1266 2009-07-14 18:39:12Z hubert@u.washin
#include "../pith/escapes.h"
#include "../pith/keyword.h"
#include "../pith/smime.h"
-
+#include "../pith/osdep/color.h"
+#include "../pico/osdep/color.h"
+#include "../pico/estruct.h"
+#include "../pico/pico.h"
+#include "../pico/efunc.h"
#define FBUF_LEN (50)
@@ -282,9 +286,17 @@ format_body(long int msgno, BODY *body, HANDLE_S **handlesp, HEADER_S *hp, int f
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));
+ gf_link_filter(gf_quote_test, gf_line_test_opt(color_signature, &is_in_sig));
}
if((flgs & FM_DISPLAY)
@@ -292,8 +304,10 @@ format_body(long int msgno, BODY *body, HANDLE_S **handlesp, HEADER_S *hp, int f
&& 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));
if(!(flgs & FM_NOWRAP)){
wrapflags = (flgs & FM_DISPLAY) ? (GFW_HANDLES|GFW_SOFTHYPHEN) : GFW_NONE;
@@ -1098,27 +1112,88 @@ int
color_signature(long int linenum, char *line, LT_INS_S **ins, 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'};
+ char *p, *q;
+ static char *buf, buf2[NSTRING] = {'\0'};
+ QSTRING_S *qs;
+ static int qstrlen = 0;
if(is_in_sig == NULL)
return 0;
+ if (linenum > 0){
+ strncpy(PLine, GLine, sizeof(PLine));
+ PLine[sizeof(PLine)-1] = '\0';
+ }
+
+ if(p = strchr(tmp_20k_buf, '\015')) *p = '\0';
+ strncpy(NLine, tmp_20k_buf, sizeof(NLine));
+ NLine[sizeof(NLine) - 1] = '\0';
+ if (p) *p = '\015';
+
+ strncpy(GLine, line, sizeof(GLine));
+ GLine[sizeof(GLine) - 1] = '\0';
+
+ ps_global->list_qstr = default_qstr(ps_global->prefix && *ps_global->prefix
+ ? (void *) ps_global->prefix : (void *) ">", 0);
+ plb = line_isblank(ps_global->list_qstr, PLine, GLine, PPLine, NSTRING);
+ qs = do_quote_match(ps_global->list_qstr, 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 : 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,
@@ -1482,18 +1557,78 @@ color_headers(long int linenum, char *line, LT_INS_S **ins, void *local)
return(0);
}
+int
+incomplete_url(char *up, int n, int delim)
+{
+ char *line, *line2;
+ int rv = 0, len;
+
+ if(*(up + n) != '\0')
+ return 0;
+
+ if(delim > 0)
+ return 1;
+
+ if(F_ON(F_VIEW_LONG_URL, ps_global)){
+ line = up;
+ if(!strncmp(line, "http://", 7))
+ line += 7;
+ else if(!strncmp(line, "https://", 8))
+ line += 8;
+ if(strchr(line, '/') != NULL && (line = strrchr(line, '/')) != NULL){
+ line++;
+ line2 = strrchr(line, '.');
+ rv = (strpbrk(line,"+#?=&") != NULL)
+ || (!line2 || line-line2 > 4);
+ }
+ }
+ return rv;
+}
+
int
url_hilite(long int linenum, char *line, LT_INS_S **ins, void *local)
{
register char *lp, *up = NULL, *urlp = NULL,
*weburlp = NULL, *mailurlp = NULL;
- int n, n1, n2, n3, l;
+ char *use_this_line, c, *begin_line, *end_line;
+ static int scannextline, delim = -1;
+ int n, n1, n2, n3, l, len;
+ int we_clear = 0, newhandle = 1, tie_off = 0;
char buf[256], color[256];
HANDLE_S *h;
URL_HILITE_S *uh;
- for(lp = line; ; lp = up + n){
+ uh = (URL_HILITE_S *) local;
+ if((uh && uh->handlesp && ((h = *(uh->handlesp)) == NULL) || h->key == 0) ||
+ (!line || !*line) || linenum == 0)
+ scannextline = 0; /* initialize scannextline */
+
+ if(scannextline != 0){
+ up = rfc1738_scan(line, &n1);
+
+ /* if we found a url in the current line, but it is not at the beginning of
+ * the next line, or if there is no url in this line, we check if the url
+ * in the previous line continues in this line.
+ */
+
+ if(line != up){
+ if(*uh->handlesp == NULL)
+ h = new_handle(uh->handlesp);
+ for(h = *uh->handlesp; h->next; h = h->next); /* get last handle */
+ len = h->h.url.path ? strlen(h->h.url.path) : 0;
+ use_this_line = (char *) fs_get((len + strlen(line) + 1)*sizeof(char));
+ sprintf(use_this_line,"%s%s", (h->h.url.path ? h->h.url.path : ""), line);
+ we_clear++;
+ newhandle = 0;
+ }
+ else
+ use_this_line = line;
+ }
+ else
+ use_this_line = line;
+
+ for(lp = use_this_line; ; lp = up + n){
/* scan for all of them so we can choose the first */
if(F_ON(F_VIEW_SEL_URL,ps_global))
urlp = rfc1738_scan(lp, &n1);
@@ -1503,6 +1638,10 @@ url_hilite(long int linenum, char *line, LT_INS_S **ins, void *local)
mailurlp = mail_addr_scan(lp, &n3);
if(urlp || weburlp || mailurlp){
+ if(scannextline == 0){
+ newhandle++;
+ delim = -1;
+ }
up = urlp ? urlp :
weburlp ? weburlp : mailurlp;
if(up == urlp && weburlp && weburlp < up)
@@ -1511,7 +1650,16 @@ url_hilite(long int linenum, char *line, LT_INS_S **ins, void *local)
up = mailurlp;
if(up == urlp){
+ if(delim < 0)
+ delim = up > use_this_line && *(up - 1) == '<';
n = n1;
+ if(incomplete_url(up,n, delim))
+ scannextline++;
+ else{
+ if(scannextline)
+ tie_off++;
+ scannextline = 0;
+ }
weburlp = mailurlp = NULL;
}
else if(up == weburlp){
@@ -1528,36 +1676,58 @@ url_hilite(long int linenum, char *line, LT_INS_S **ins, void *local)
uh = (URL_HILITE_S *) local;
- h = new_handle(uh->handlesp);
- h->type = URL;
- h->h.url.path = (char *) fs_get((n + 10) * sizeof(char));
- snprintf(h->h.url.path, n+10, "%s%.*s",
+ if(tie_off){
+ tie_off = 0; /* do only once */
+ begin_line = line;
+ end_line = line + n - strlen(h->h.url.path);
+ fs_give((void **)&h->h.url.path);
+ c = *(use_this_line + n);
+ *(use_this_line+n) = '\0';
+ h->h.url.path = cpystr(use_this_line);
+ *(use_this_line+n) = c;
+ }
+ else{
+ if(newhandle){
+ h = new_handle(uh->handlesp);
+ h->type = URL;
+ }
+ begin_line = newhandle ? (we_clear ? line + strlen(line) - strlen(up)
+ : up) : line;
+ end_line = newhandle ? begin_line + n : line + strlen(line);
+ if(scannextline && h->h.url.path)
+ fs_give((void **)&h->h.url.path);
+ h->h.url.path = (char *) fs_get((n + 10) * sizeof(char));
+ snprintf(h->h.url.path, n+10, "%s%.*s",
weburlp ? "http://" : (mailurlp ? "mailto:" : ""), n, up);
- h->h.url.path[n+10-1] = '\0';
+ h->h.url.path[n+10-1] = '\0';
+ }
if(handle_start_color(color, sizeof(color), &l, uh->hdr_color))
- ins = gf_line_test_new_ins(ins, up, color, l);
+ ins = gf_line_test_new_ins(ins, begin_line, color, l);
else if(F_OFF(F_SLCTBL_ITEM_NOBOLD, ps_global))
- ins = gf_line_test_new_ins(ins, up, url_embed(TAG_BOLDON), 2);
+ ins = gf_line_test_new_ins(ins, begin_line, url_embed(TAG_BOLDON), 2);
buf[0] = TAG_EMBED;
buf[1] = TAG_HANDLE;
snprintf(&buf[3], sizeof(buf)-3, "%d", h->key);
buf[sizeof(buf)-1] = '\0';
buf[2] = strlen(&buf[3]);
- ins = gf_line_test_new_ins(ins, up, buf, (int) buf[2] + 3);
+ ins = gf_line_test_new_ins(ins, begin_line, buf, (int) buf[2] + 3);
/* in case it was the current selection */
- ins = gf_line_test_new_ins(ins, up + n, url_embed(TAG_INVOFF), 2);
+ ins = gf_line_test_new_ins(ins, end_line, url_embed(TAG_INVOFF), 2);
if(scroll_handle_end_color(color, sizeof(color), &l, uh->hdr_color))
- ins = gf_line_test_new_ins(ins, up + n, color, l);
+ ins = gf_line_test_new_ins(ins, end_line, color, l);
else
- ins = gf_line_test_new_ins(ins, up + n, url_embed(TAG_BOLDOFF), 2);
+ ins = gf_line_test_new_ins(ins, end_line, url_embed(TAG_BOLDOFF), 2);
urlp = weburlp = mailurlp = NULL;
}
+ if(we_clear)
+ fs_give((void **)&use_this_line);
+
return(0);
}
@@ -1678,6 +1848,77 @@ pad_to_right_edge(long int linenum, char *line, LT_INS_S **ins, void *local)
}
+/* 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(long linenum, char *line, LT_INS_S **ins, void *local)
+{
+ int i, plb, *code;
+ char rqstr[NSTRING] = {'\0'}, buf[NSTRING] = {'\0'};
+ char GLine[NSTRING] = {'\0'}, PLine[NSTRING] = {'\0'};
+ char PPLine[NSTRING] = {'\0'}, 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, raw;
+
+ code = (int *)local;
+ who = code ? (*code & COLORAQUO) : 0; /* may I ask who is calling? */
+ raw = code ? (*code & RAWSTRING) : 0; /* 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';
+
+ ps_global->list_qstr = default_qstr(ps_global->prefix && *ps_global->prefix
+ ? (void *) ps_global->prefix : (void *) ">", 0);
+ plb = line_isblank(ps_global->list_qstr, PLine, GLine, PPLine, NSTRING);
+
+ qs = do_quote_match(ps_global->list_qstr, GLine, NLine, PLine, rqstr, NSTRING, plb);
+ if (raw)
+ strncpy(buf, rqstr, NSTRING);
+ else
+ flatten_qstring(qs, buf, NSTRING);
+ if(qs)
+ record_quote_string(qs);
+ 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;
+}
+
#define UES_LEN 12
#define UES_MAX 32
@@ -2503,6 +2744,190 @@ hdr_color(char *fieldname, char *value, SPEC_COLOR_S *speccolor)
return(color_pair);
}
+void
+interval_free(IVAL_S **ival)
+{
+ if (!(*ival))
+ return;
+
+ if ((*ival)->next)
+ interval_free(&((*ival)->next));
+
+ fs_give((void **)(ival));
+}
+
+IVAL_S *
+compute_interval (char *string, int endm)
+{
+ IVAL_S *ival = NULL;
+ regmatch_t pmatch;
+
+ if(ps_global->paterror == 0 &&
+ regexec(&ps_global->colorpat, string + endm, 1, &pmatch, 0) == 0){
+ ival = (IVAL_S *) fs_get(sizeof(IVAL_S));
+ ival->start = endm + pmatch.rm_so;
+ ival->end = endm + pmatch.rm_eo;
+ ival->next = compute_interval(string, ival->end);
+ }
+ return ival;
+}
+
+void
+regex_pattern(char **plist)
+{
+ int i = 0, j = 0, len = 0;
+ char *pattern = NULL;
+ regex_t preg;
+
+ if(ps_global->paterror == 0)
+ regfree(&ps_global->colorpat);
+
+ if(plist && *plist && *plist){
+ for (i = 0; plist[i] && plist[i][0]; i++)
+ len += strlen(plist[i]) + 1;
+ pattern = (char *) fs_get(len * sizeof(char));
+ *pattern = '\0';
+ for (j = 0; j < i; j++){
+ strcat(pattern, plist[j]);
+ strcat(pattern, (j < i - 1) ? "|" : "");
+ }
+ if ((ps_global->paterror = regcomp(&preg, pattern, REG_EXTENDED)) != 0)
+ regfree(&preg);
+ else
+ ps_global->colorpat = preg;
+ }
+ if(pattern)
+ fs_give((void **)&pattern);
+}
+
+LT_INS_S **
+insert_color_special_text(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(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(char *p)
+{
+ int rv = 0;
+ char *orig = p;
+ while (*p && !rv)
+ if (*p++ == TAG_EMBED)
+ rv = p - orig;
+ return rv;
+}
+
+void
+remove_spaces_ival(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(long linenum, char *line, LT_INS_S **ins, void *local)
+{
+ struct variable *vars = ps_global->vars;
+ COLOR_PAIR *col = NULL;
+ char *p;
+ int i = 0;
+ static char *pattern = NULL;
+
+/* select_quote(linenum, line, ins, (void *) &i);
+ for (i = 0; tmp_20k_buf[i] != '\0'; i++); */
+ p = line + i;
+
+ 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(ps_global->VAR_SPECIAL_TEXT && *ps_global->VAR_SPECIAL_TEXT
+ && **ps_global->VAR_SPECIAL_TEXT && 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, 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, 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;
+}
/*
* The argument fieldname is something like "Subject:..." or "Subject".
diff --git a/pith/mailview.h b/pith/mailview.h
index a89f3f95..5d2fe171 100644
--- a/pith/mailview.h
+++ b/pith/mailview.h
@@ -30,6 +30,12 @@
#include "../pith/color.h"
+typedef struct IVAL {
+ int start;
+ int end;
+ struct IVAL *next;
+} IVAL_S;
+
/* format_message flags */
#define FM_DISPLAY 0x0001 /* result is headed for display */
#define FM_NEW_MESS 0x0002 /* a new message so zero out attachment descrip */
@@ -126,6 +132,15 @@ char *format_body(long int, BODY *, HANDLE_S **, HEADER_S *, int, int, gf_io_t);
int url_hilite(long, char *, LT_INS_S **, void *);
int handle_start_color(char *, size_t, int *, int);
int handle_end_color(char *, size_t, int *);
+IVAL_S *compute_interval(char *, int);
+void remove_spaces_ival(IVAL_S **, char *);
+void interval_free(IVAL_S **);
+void regex_pattern(char **);
+LT_INS_S **insert_color_special_text(LT_INS_S **, char **, IVAL_S *,
+ int, COLOR_PAIR *);
+int any_color_in_string(char *);
+int length_color(char *, int);
+int color_this_text(long, char *, LT_INS_S **, void *);
/*
* BUG: BELOW IS UNIX/PC ONLY since config'd browser means nothing to webpine
@@ -142,6 +157,7 @@ COLOR_PAIR *hdr_color(char *, char *, SPEC_COLOR_S *);
char *display_parameters(PARAMETER *);
char *pine_fetch_header(MAILSTREAM *, long, char *, char **, long);
int color_signature(long, char *, LT_INS_S **, void *);
+int select_quote(long, char *, LT_INS_S **, void *);
int scroll_handle_start_color(char *, size_t, int *);
int scroll_handle_end_color(char *, size_t, int *, int);
int width_at_this_position(unsigned char *, unsigned long);
diff --git a/pith/makefile.wnt b/pith/makefile.wnt
index d9316dba..b9464cd4 100644
--- a/pith/makefile.wnt
+++ b/pith/makefile.wnt
@@ -44,7 +44,7 @@ HFILES= ../include/system.h ../include/general.h \
init.h keyword.h ldap.h list.h mailcap.h mailcmd.h mailindx.h maillist.h \
mailpart.h mailview.h margin.h mimedesc.h mimetype.h msgno.h newmail.h news.h \
options.h pattern.h pineelt.h pipe.h readfile.h remote.h remtype.h repltype.h reply.h \
- rfc2231.h save.h savetype.h search.h send.h sequence.h signal.h sort.h sorttype.h \
+ rfc2231.h rules.h save.h savetype.h search.h send.h sequence.h signal.h sort.h sorttype.h \
state.h status.h store.h stream.h string.h strlst.h takeaddr.h tempfile.h text.h \
thread.h url.h user.h util.h
@@ -53,7 +53,7 @@ OFILES= ablookup.obj abdlc.obj addrbook.obj addrstring.obj adrbklib.obj bldaddr.
filter.obj flag.obj folder.obj handle.obj help.obj helptext.obj hist.obj icache.obj imap.obj init.obj \
keyword.obj ldap.obj list.obj mailcap.obj mailcmd.obj mailindx.obj maillist.obj mailview.obj \
margin.obj mimedesc.obj mimetype.obj msgno.obj newmail.obj news.obj pattern.obj pipe.obj \
- readfile.obj remote.obj reply.obj rfc2231.obj save.obj search.obj sequence.obj send.obj sort.obj state.obj \
+ readfile.obj remote.obj reply.obj rfc2231.obj rules.obj save.obj search.obj sequence.obj send.obj sort.obj state.obj \
status.obj store.obj stream.obj string.obj strlst.obj takeaddr.obj tempfile.obj text.obj \
thread.obj adjtime.obj url.obj util.obj
diff --git a/pith/msgno.c b/pith/msgno.c
index 465a42e0..e72ee0d3 100644
--- a/pith/msgno.c
+++ b/pith/msgno.c
@@ -933,6 +933,9 @@ free_pine_elt(void **sparep)
if((*peltp)->pthrd)
fs_give((void **) &(*peltp)->pthrd);
+ if((*peltp)->firsttext)
+ fs_give((void **) &(*peltp)->firsttext);
+
if((*peltp)->ice)
free_ice(&(*peltp)->ice);
diff --git a/pith/osdep/color.c b/pith/osdep/color.c
index faf3c675..cad5502e 100644
--- a/pith/osdep/color.c
+++ b/pith/osdep/color.c
@@ -31,7 +31,7 @@ static char rcsid[] = "$Id: color.c 761 2007-10-23 22:35:18Z hubert@u.washington
#include <system.h>
#include "./color.h"
-
+#include "./collate.h"
/*
@@ -91,3 +91,1257 @@ pico_set_colorp(COLOR_PAIR *col, int flags)
{
return(pico_set_colors(col ? col->fg : NULL, col ? col->bg : NULL, flags));
}
+
+
+ /*
+ * Extended Justification support also does not belong here
+ * but otherwise webpine will not build, so we move everything
+ * here. Hopefully this will be the permanent place for these
+ * routines. These routines used to be in pico/word.c
+ */
+#define NSTRING 256
+#include "../../include/general.h"
+
+/* Support of indentation of paragraphs */
+#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)
+
+
+/* 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')) || ((c) == '?'))
+#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_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))
+#define qs_allowed(a) (((a)->qstype != qsGdb) && ((a)->qstype != qsProg))
+
+/* Internal justification functions */
+QSTRING_S *is_quote(char **, char *, int);
+QSTRING_S *qs_normal_part(QSTRING_S *);
+QSTRING_S *qs_remove_trailing_spaces(QSTRING_S *);
+QSTRING_S *trim_qs_from_cl(QSTRING_S *, QSTRING_S *, QSTRING_S *);
+QSTRING_S *fix_qstring(QSTRING_S *, QSTRING_S *, QSTRING_S *);
+QSTRING_S *fix_qstring_allowed(QSTRING_S *, QSTRING_S *, QSTRING_S *);
+QSTRING_S *qs_add(char **, char *, QStrType, int, int, int, int);
+QSTRING_S *remove_qsword(QSTRING_S *);
+QSTRING_S *do_raw_quote_match(char **, char *, char *, char *, QSTRING_S **, QSTRING_S **);
+void free_qs(QSTRING_S **);
+int word_is_prog(char *);
+int qstring_is_normal(QSTRING_S *);
+int exists_good_part(QSTRING_S *);
+int strcmp_qs(char *, char *);
+int count_levels_qstring(QSTRING_S *);
+int same_qstring(QSTRING_S *, QSTRING_S *);
+int isaword(char *,int ,int);
+int isamailbox(char *,int ,int);
+int double_check_qstr(char *);
+
+int
+word_is_prog(char *word)
+{
+ static char *list1[] = {"#include",
+ "#define",
+ "#ifdef",
+ "#ifndef",
+ "#elif",
+ "#if",
+ NULL};
+ static char *list2[] = {"#else",
+ "#endif",
+ NULL};
+ int i, j = strlen(word), k, rv = 0;
+
+ for(i = 0; rv == 0 && list1[i] && (k = strlen(list1[i])) && k < j; i++)
+ if(!strncmp(list1[i], word, k) && ISspace(word[k]))
+ rv++;
+
+ if(rv)
+ return rv;
+
+ for(i = 0; rv == 0 && list2[i] && (k = strlen(list2[i])) && k <= j; i++)
+ if(!strncmp(list2[i], word, k) && (!word[k] || ISspace(word[k])))
+ rv++;
+
+ return rv;
+}
+
+/*
+ * 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(char **qs, char word[NSTRING], QStrType typeqs, int beginw, int endw,
+ int offset, int neednext)
+{
+ QSTRING_S *qstring, *nextqs;
+ 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;
+ }
+
+ nextqs = neednext ? is_quote(qs, word+beginw, 1) : NULL;
+
+ 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(QSTRING_S *cl)
+{
+ for (;cl && (cl->qstype == qsNormal); cl = cl->next);
+ return cl ? 0 : 1;
+}
+
+/*
+ * 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(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;
+}
+
+/*
+ * 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(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;
+}
+
+/*
+ * 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(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(QSTRING_S *cl)
+{
+ int count;
+ for (count = 0; cl ; count++, cl = cl->next);
+
+ return count;
+}
+
+int
+value_is_space(char *value)
+{
+ for (; value && *value && ISspace(*value); value++);
+
+ return value && *value ? 0 : 1;
+}
+
+void
+free_qs(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;
+}
+
+/*
+ * This function returns the number of agreements between
+ * cl and nl. The call is not symmetric. cl must be the line
+ * preceding nl.
+ */
+int
+same_qstring(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(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(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 really 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 && cl->qstype == pl->qstype
+ && !strucmp(cl->value, pl->value)){
+ cl = cl->next;
+ pl = pl->next;
+ }
+ if (pl && cl && cl->qstype == pl->qstype
+ && 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;
+}
+
+QSTRING_S *
+fix_qstring_allowed(QSTRING_S *cl, QSTRING_S *nl, QSTRING_S *pl)
+{
+ if(!cl)
+ return (QSTRING_S *) NULL;
+
+ if (qs_allowed(cl))
+ cl->next = fix_qstring_allowed(cl->next, (nl ? nl->next : NULL),
+ (pl ? pl->next : NULL));
+ else
+ if((nl && cl->qstype == nl->qstype) || (pl && cl->qstype == pl->qstype)
+ || (!nl && !pl))
+ free_qs(&cl);
+ return cl;
+}
+
+/*
+ * This function flattens the quote string returned to us by is_quote. A
+ * crash in this function implies a bug elsewhere.
+ */
+void
+flatten_qstring(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';
+}
+
+extern int list_len;
+
+
+int
+double_check_qstr(char *q)
+{
+ if(!q || !*q)
+ return 0;
+
+ return (*q == '#') ? 1 : 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 (char **qs,char *word, int been_here)
+{
+ int i = 0, j, nxt, prev, finished = 0, offset;
+ unsigned char c;
+ QSTRING_S *qstring = (QSTRING_S *) NULL;
+
+ if (word == NULL || word[0] == '\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!.
+ */
+ for(j = 0; j < list_len; j++){
+ if(!double_check_qstr(qs[j])){
+ i += advance_quote_string(qs[j], word, i);
+ if (!word[i]) /* went too far? */
+ return qs_add(qs, word, qsNormal, 0, i, 0, 0);
+ }
+ else
+ break;
+ }
+
+ switch (c = (unsigned char) now(word,i)){
+ case NBSP:
+ case TAB :
+ case ' ' : { QSTRING_S *nextqs, *d;
+
+ for (; ISspace(word[i]); i++); /* FIX ME */
+ 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 "^ ^").
+ */
+ i += nextqs && nextqs->qstype == qsNormal
+ ? strlen(nextqs->value) : 0;
+ 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;
+ if(nextqs && nextqs->qstype == qsNormal){
+ d = nextqs->next;
+ nextqs->next = NULL;
+ qstring->next = d;
+ free_qs(&nextqs);
+ }
+ else
+ qstring->next = nextqs;
+
+ 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 ':': /* colon */
+ case '~': nxt = next(word,i);
+ if ((is_tilde(c) && (nxt == '/'))
+ || (is_colon(c) && !is_cquote(nxt)
+ && !is_cword(nxt) && nxt != RPAREN))
+ finished++;
+ else if (is_cquote(c)
+ || is_cquote(nxt)
+ || (c != '~' && nxt == RPAREN)
+ || (i != 0 && ISspace(nxt))
+ || is_cquote(prev = before(word,i))
+ || (ISspace(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 */
+ (ISspace(nxt) && is_rarrow(next(word,i+1))))
+ i++;
+ else
+ finished++;
+ break;
+
+ case '^' :
+ case '!' :
+ case '%' : if (next(word,i) != c)
+ return qs_add(qs, word, qsChar, i, i+1, 0, 1);
+ else
+ finished++;
+ break;
+
+ case '_' : if(ISspace(next(word, i)))
+ return qs_add(qs, word, qsChar, i, i+1, 0, 1);
+ else
+ finished++;
+ break;
+
+ case '#' : { QStrType qstype = qsChar;
+ if((nxt = next(word, i)) != c){
+ if(isdigit((int) nxt))
+ qstype = qsGdb;
+ else
+ if(word_is_prog(word))
+ qstype = qsProg;
+ return qs_add(qs, word, qstype, 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))
+ && !(ISspace(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
+ : ((ISspace(c)
+ && is_cquote(next(word,j+1))) ? 3 : -1);
+
+ qstype = (is_cquote(c) || (c == RPAREN))
+ ? (is_qsword(c) ? qsWord : qsString)
+ : ((ISspace(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(i > 0)
+ return qs_add(qs, word, qsNormal, 0, i, 0, 1);
+ 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;
+}
+
+int
+isaword(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(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 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(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 (QSTRING_S *cl)
+{
+ return (cl ? (((cl->qstype != qsWord) && (cl->qstype != qsChar)
+ && qs_allowed(cl) && !value_is_space(cl->value))
+ ? 1 : exists_good_part(cl->next))
+ : 0);
+}
+
+int
+line_isblank(char **q, char *GLine, char *NLine, char *PLine, 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(char **q, char *GLine, char *NLine, char *PLine, QSTRING_S **nlp, QSTRING_S **plp)
+{
+ QSTRING_S *cl, *nl = NULL, *pl = NULL;
+ char nbuf[NSTRING], pbuf[NSTRING], buf[NSTRING];
+ int emptypl = 0, emptynl = 0;
+
+ if (!(cl = is_quote(q, GLine, 0))) /* if nothing in, nothing out */
+ return cl;
+
+ nl = is_quote(q, NLine, 0); /* Next Line */
+ if (nlp) *nlp = nl;
+ 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);
+ if((cl = fix_qstring_allowed(cl, NULL, NULL)) != NULL)
+ 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((cl = fix_qstring_allowed(cl, nl, pl)) != NULL){
+ nl = trim_qs_from_cl(cl, nl, NULL);
+ pl = trim_qs_from_cl(cl, NULL, pl);
+ }
+ else{
+ free_qs(&nl);
+ free_qs(&pl);
+ }
+ if(nlp)
+ *nlp = nl;
+ else
+ free_qs(&nl);
+ if(plp)
+ *plp = pl;
+ else
+ free_qs(&pl);
+ return cl;
+}
+
+QSTRING_S *
+do_quote_match(char **q, char *GLine, char *NLine, char *PLine, char *rqstr,
+int rqstrlen, int 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];
+
+ if(rqstr)
+ *rqstr = '\0';
+
+ /* if nothing in, nothing out */
+ cl = do_raw_quote_match(q, GLine, NLine, PLine, &nl, &pl);
+ if(cl == NULL){
+ free_qs(&nl);
+ free_qs(&pl);
+ 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 (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])
+ if(!get_indent_raw_line(q, PLine, nbuf, NSTRING, p, plb)
+ || NewP + strlenis(nbuf) != NewC){
+ free_qs(&cl);
+ free_qs(&pl);
+ return 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(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; ISspace(l[i + k]); k++);
+ k -= k % es;
+ return k;
+ }
+ for (is = 0; ISspace(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; ISspace(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; ISspace(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(char *qstr)
+{
+ int i, rv = 0;
+ for (i = 0; qstr && qstr[i]; i++)
+ rv += ((qstr[i] == TAB) ? (~rv & 0x07) + 1 : 1);
+ return rv;
+}
+
+int
+is_indent (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;
+}
+
+int
+get_indent_raw_line(char **q, char *GLine, char *buf, int buflen, int k, int plb)
+{
+ int i, j;
+ char testline[1024];
+
+ if(k > 0){
+ for(j = 0; GLine[j] != '\0'; j++){
+ testline[j] = GLine[j];
+ testline[j+1] = '\0';
+ if(strlenis(testline) >= strlenis(buf))
+ break;
+ }
+ k = ++j; /* reset k */
+ }
+ i = is_indent(GLine+k, plb);
+
+ for (j = 0; j < i && j < buflen && (buf[j] = GLine[j + k]); j++);
+ buf[j] = '\0';
+
+ return i;
+}
+
+/* support for remembering quote strings across messages */
+char **allowed_qstr = NULL;
+int list_len = 0;
+
+void
+free_allowed_qstr(void)
+{
+ int i;
+ char **q = allowed_qstr;
+
+ if(q == NULL)
+ return;
+
+ for(i = 0; i < list_len; i++)
+ fs_give((void **)&q[i]);
+
+ fs_give((void **)q);
+ list_len = 0;
+}
+
+void
+add_allowed_qstr(void *q, int type)
+{
+ int i;
+
+ if(allowed_qstr == NULL){
+ allowed_qstr = malloc(sizeof(char *));
+ list_len = 0;
+ }
+
+ if(type == 0){
+ allowed_qstr[list_len] = malloc((1+strlen((char *)q))*sizeof(char));
+ strcpy(allowed_qstr[list_len], (char *)q);
+ }
+ else
+ allowed_qstr[list_len] = (char *) ucs4_to_utf8_cpystr((UCS *)q);
+
+ fs_resize((void **)&allowed_qstr, (++list_len + 1)*sizeof(char *));
+ allowed_qstr[list_len] = NULL;
+}
+
+void
+record_quote_string (QSTRING_S *qs)
+{
+ int i, j, k;
+
+ for(; qs && qs->value; qs = qs->next){
+ j = 0;
+ for (; ;){
+ k = j;
+ for(i = 0; i < list_len; i++){
+ j += advance_quote_string(allowed_qstr[i], qs->value, j);
+ for(; ISspace(qs->value[j]); j++);
+ }
+ if(k == j)
+ break;
+ }
+ if(qs->value[j] != '\0')
+ add_allowed_qstr((void *)(qs->value + j), 0);
+ }
+}
+
+/* type utf8: code 0; ucs4: code 1. */
+char **
+default_qstr(void *q, int type)
+{
+ if(allowed_qstr == NULL)
+ add_allowed_qstr(q, type);
+
+ return allowed_qstr;
+}
+
diff --git a/pith/osdep/color.h b/pith/osdep/color.h
index 32c86242..929389a2 100644
--- a/pith/osdep/color.h
+++ b/pith/osdep/color.h
@@ -17,6 +17,24 @@
#ifndef PITH_OSDEP_COLOR_INCLUDED
#define PITH_OSDEP_COLOR_INCLUDED
+/*
+ * 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, qsGdb, qsProg, qsText} QStrType;
+
+typedef struct QSTRING {
+ char *value; /* possible quote string */
+ QStrType qstype; /* type of quote string */
+ struct QSTRING *next; /* possible continuation */
+} QSTRING_S;
+
+#define UCH(c) ((unsigned char) (c))
+#define NBSP UCH('\240')
+#define ISspace(c) (UCH(c) == ' ' || UCH(c) == TAB || UCH(c) == NBSP)
#define RGBLEN 11
#define MAXCOLORLEN 11 /* longest string a color can be */
@@ -93,6 +111,11 @@ char *pico_get_last_fg_color(void);
char *pico_get_last_bg_color(void);
char *color_to_canonical_name(char *);
int pico_count_in_color_table(void);
-
+int is_indent(char *, int);
+int get_indent_raw_line (char **, char *, char *, int, int, int);
+int line_isblank(char **, char *, char *, char *, int);
+int strlenis(char *);
+int value_is_space(char *);
+int advance_quote_string(char *, char *, int);
#endif /* PITH_OSDEP_COLOR_INCLUDED */
diff --git a/pith/pattern.c b/pith/pattern.c
index 84a32c41..9d09462a 100644
--- a/pith/pattern.c
+++ b/pith/pattern.c
@@ -1756,7 +1756,7 @@ parse_action_slash(char *str, ACTION_S *action)
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);
@@ -5483,6 +5483,15 @@ match_pattern_folder_specific(PATTERN_S *folders, MAILSTREAM *stream, int flags)
break;
case '#':
+#ifndef _WINDOWS
+ if(!struncmp(patfolder, "#md/", 4)
+ || !struncmp(patfolder, "#mc/", 4)){
+ maildir_file_path(patfolder, tmp1, sizeof(tmp1));
+ if(!strcmp(patfolder, stream->mailbox))
+ match++;
+ break;
+ }
+#endif
if(!strcmp(patfolder, stream->mailbox))
match++;
@@ -7903,7 +7912,7 @@ move_filtered_msgs(MAILSTREAM *stream, MSGNO_S *msgmap, char *dstfldr,
int we_cancel = 0, width;
CONTEXT_S *save_context = NULL;
char buf[MAX_SCREEN_COLS+1], sbuf[MAX_SCREEN_COLS+1];
- char *save_ref = NULL;
+ char *save_ref = NULL, *save_dstfldr = NULL, *save_dstfldr2 = NULL;
#define FILTMSG_MAX 30
if(!stream)
@@ -7937,6 +7946,16 @@ move_filtered_msgs(MAILSTREAM *stream, MSGNO_S *msgmap, char *dstfldr,
if(F_OFF(F_QUELL_FILTER_MSGS, ps_global))
we_cancel = busy_cue(buf, NULL, 0);
+#ifndef _WINDOWS
+ if(!struncmp(dstfldr, "#md/", 4) || !struncmp(dstfldr, "#mc/", 4)){
+ char tmp1[MAILTMPLEN];
+ maildir_file_path(dstfldr, tmp1, sizeof(tmp1));
+ save_dstfldr2 = dstfldr;
+ save_dstfldr = cpystr(tmp1);
+ dstfldr = save_dstfldr;
+ }
+#endif
+
if(!is_absolute_path(dstfldr)
&& !(save_context = default_save_context(ps_global->context_list)))
save_context = ps_global->context_list;
@@ -8000,6 +8019,11 @@ move_filtered_msgs(MAILSTREAM *stream, MSGNO_S *msgmap, char *dstfldr,
if(we_cancel)
cancel_busy_cue(buf[0] ? 0 : -1);
+ if(save_dstfldr){
+ fs_give((void **)&save_dstfldr);
+ dstfldr = save_dstfldr2;
+ }
+
return(buf[0] != '\0');
}
diff --git a/pith/pine.hlp b/pith/pine.hlp
index 82872f19..6fbe15ac 100644
--- a/pith/pine.hlp
+++ b/pith/pine.hlp
@@ -89,6 +89,7 @@ Where "variable" is one of either:
ALPINE_VERSION
ALPINE_REVISION
ALPINE_COMPILE_DATE
+ ALPINE_PATCHLEVEL
ALPINE_TODAYS_DATE
C_CLIENT_VERSION
_LOCAL_FULLNAME_
@@ -159,6 +160,14 @@ Version <!--#echo var="ALPINE_VERSION"-->(<!--#echo var="ALPINE_REVISION"-->)
</DIV>
<P>
+This version was modified from its original source code. More information
+about some of the patches applied to this version can be found <A HREF="h_patches">here</A>.
+<!--chtml if pinemode="running"-->
+The patch level of this version, including creation date of the patch is:
+<!--#echo var=ALPINE_PATCHLEVEL-->.
+<!--chtml endif-->
+
+<P>
Alpine is an &quot;Alternatively Licensed Program for Internet
News and Email&quot; produced until 2008 by the University of Washington.
It is intended to be an easy-to-use program for
@@ -198,7 +207,7 @@ message, as specified by original sender.
Bugs that have been addressed include:
<P>
<UL>
- <LI> Proper quote of shell characters in urls.
+ <LI> Do not use a shell to open a browser.
<LI> Configure script did not test for crypto or pam libraries.
<LI> Fix Cygwin separator to &quot;/&quot;.
<LI> Crash when a non-compliant SMTP server closes a connection without a QUIT command.
@@ -3183,9 +3192,11 @@ There are also additional details on
<li><a href="h_config_alt_role_menu">FEATURE: <!--#echo var="FEAT_alternate-role-menu"--></a>
<li><a href="h_config_force_low_speed">FEATURE: <!--#echo var="FEAT_assume-slow-link"--></a>
<li><a href="h_config_auto_read_msgs">FEATURE: <!--#echo var="FEAT_auto-move-read-msgs"--></a>
+<li><a href="h_config_auto_read_msgs_rules">FEATURE: <!--#echo var="FEAT_auto-move-read-msgs-using-rules"--></a>
<li><a href="h_config_auto_open_unread">FEATURE: <!--#echo var="FEAT_auto-open-next-unread"--></a>
<li><a href="h_config_auto_unselect">FEATURE: <!--#echo var="FEAT_auto-unselect-after-apply"--></a>
<li><a href="h_config_auto_unzoom">FEATURE: <!--#echo var="FEAT_auto-unzoom-after-apply"--></a>
+<li><a href="h_config_circular_tab">FEATURE: <!--#echo var="FEAT_enable-circular-tab"--></a>
<li><a href="h_config_auto_zoom">FEATURE: <!--#echo var="FEAT_auto-zoom-after-select"--></a>
<li><a href="h_config_use_boring_spinner">FEATURE: <!--#echo var="FEAT_busy-cue-spinner-only"--></a>
<li><a href="h_config_check_mail_onquit">FEATURE: <!--#echo var="FEAT_check-newmail-when-quitting"--></a>
@@ -3285,6 +3296,7 @@ There are also additional details on
<li><a href="h_config_full_auto_expunge">FEATURE: <!--#echo var="FEAT_expunge-without-confirm-everywhere"--></a>
<li><a href="h_config_no_fcc_attach">FEATURE: <!--#echo var="FEAT_fcc-without-attachments"--></a>
<li><a href="h_config_force_arrow">FEATURE: <!--#echo var="FEAT_force-arrow-cursor"--></a>
+<li><a href="h_config_ignore_size">FEATURE: <!--#echo var="FEAT_ignore-size-changes"--></a>
<li><a href="h_config_forward_as_attachment">FEATURE: <!--#echo var="FEAT_forward-as-attachment"--></a>
<li><a href="h_config_preserve_field">FEATURE: <!--#echo var="FEAT_preserve-original-fields"--></a>
<li><a href="h_config_quell_empty_dirs">FEATURE: <!--#echo var="FEAT_quell-empty-directories"--></a>
@@ -3298,6 +3310,7 @@ There are also additional details on
<li><a href="h_config_add_ldap">FEATURE: <!--#echo var="FEAT_ldap-result-to-addrbook-add"--></a>
<li><a href="h_config_maildrops_preserve_state">FEATURE: <!--#echo var="FEAT_maildrops-preserve-state"--></a>
<li><a href="h_config_mark_fcc_seen">FEATURE: <!--#echo var="FEAT_mark-fcc-seen"--></a>
+<li><a href="h_config_mark_for_group">FEATURE: <!--#echo var="FEAT_mark-for-me-in-group"--></a>
<li><a href="h_config_mark_for_cc">FEATURE: <!--#echo var="FEAT_mark-for-cc"--></a>
<li><a href="h_config_mulnews_as_typed">FEATURE: <!--#echo var="FEAT_mult-newsrc-hostnames-as-typed"--></a>
<li><a href="h_config_news_uses_recent">FEATURE: <!--#echo var="FEAT_news-approximates-new-status"--></a>
@@ -3500,6 +3513,7 @@ There are also additional details on
<li><a href="h_config_image_viewer">OPTION: <!--#echo var="VAR_image-viewer"--></a>
<li><a href="h_config_inbox_path">OPTION: <!--#echo var="VAR_inbox-path"--></a>
<li><a href="h_config_archived_folders">OPTION: <!--#echo var="VAR_incoming-archive-folders"--></a>
+<li><a href="h_config_sleep">OPTION: <!--#echo var="VAR_sleep-interval-length"--></a>
<li><a href="h_config_incoming_interv">OPTION: <!--#echo var="VAR_incoming-check-interval"--></a>
<li><a href="h_config_incoming_second_interv">OPTION: <!--#echo var="VAR_incoming-check-interval-secondary"--></a>
<li><a href="h_config_incoming_list">OPTION: <!--#echo var="VAR_incoming-check-list"--></a>
@@ -3552,6 +3566,7 @@ There are also additional details on
<li><a href="h_config_print_cat">OPTION: <!--#echo var="VAR_personal-print-category"--></a>
<li><a href="h_config_print_command">OPTION: <!--#echo var="VAR_personal-print-command"--></a>
<li><a href="h_config_post_char_set">OPTION: <!--#echo var="VAR_posting-character-set"--></a>
+<li><a href="h_config_special_text_to_color">OPTION: <!--#echo var="VAR_h_config_special_text_to_color"--></a>
<li><a href="h_config_postponed_folder">OPTION: <!--#echo var="VAR_postponed-folder"--></a>
<li><a href="h_config_print_font_char_set">OPTION: Print-Font-Char-Set</a>
<li><a href="h_config_print_font_name">OPTION: Print-Font-Name</a>
@@ -3580,9 +3595,11 @@ There are also additional details on
<li><a href="h_config_sending_filter">OPTION: <!--#echo var="VAR_sending-filters"--></a>
<li><a href="h_config_sendmail_path">OPTION: <!--#echo var="VAR_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: <!--#echo var="VAR_signature-file"--></a>
<li><a href="h_config_smtp_server">OPTION: <!--#echo var="VAR_smtp-server"--></a>
<li><a href="h_config_sort_key">OPTION: <!--#echo var="VAR_sort-key"--></a>
+<li><a href="h_config_thread_sort_key">OPTION: <!--#echo var="VAR_thread-sort-key"--></a>
<li><a href="h_config_speller">OPTION: <!--#echo var="VAR_speller"--></a>
<li><a href="h_config_sshcmd">OPTION: <!--#echo var="VAR_ssh-command"--></a>
<li><a href="h_config_ssh_open_timeo">OPTION: <!--#echo var="VAR_ssh-open-timeout"--></a>
@@ -4442,6 +4459,10 @@ thread:
message in the thread was sent to you as a cc:. This symbol will only show up if
the feature
&quot;<A HREF="h_config_mark_for_cc"><!--#echo var="FEAT_mark-for-cc"--></A>&quot; is turned on (which is the default).
+ <LI> &quot;.&quot; for messages that were sent to you as part of a group message, regardless
+ of if all addresses in the To: field are yours or not. This symbol will only show up if
+ the feature
+ &quot;<A HREF="h_config_mark_for_group"><!--#echo var="FEAT_mark-for-me-in-group"--></A>&quot; is turned on (which is the default).
<LI> &quot;X&quot; for selected. You have selected at least one message in the thread by using the
&quot;select&quot; command. (Some systems may optionally allow selected
messages to be denoted by the index line being displayed in bold
@@ -4601,6 +4622,10 @@ message:
message was sent to you as a cc:. This symbol will only show up if
the feature
&quot;<A HREF="h_config_mark_for_cc"><!--#echo var="FEAT_mark-for-cc"--></A>&quot; is turned on (which is the default).
+ <LI> &quot;.&quot; for messages that were sent to you as part of a group message, regardless
+ of if all addresses in the To: field are yours or not. This symbol will only show up if
+ the feature
+ &quot;<A HREF="h_config_mark_for_group"><!--#echo var="FEAT_mark-for-me-in-group"--></A>&quot; is turned on (which is the default).
<LI> &quot;X&quot; for selected. You have selected the message by using the
&quot;select&quot; command. (Some systems may optionally allow selected
messages to be denoted by the index line being displayed in bold
@@ -5515,6 +5540,163 @@ the names of the carbon copy addresses of the message.
&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 sorts
+threads by the date in which messages were sent. The thread containing the
+last message in this order is displayed last.
+<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 sorts threads by their size (the number
+of messages in the thread). This could be used to find conversations
+where no reply has been sent by any of the participants in the thread
+(e.g. those whose length is equal to one). Longer threads appear
+below shorter ones.
+
+<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 means that threads are sorted according to
+the maximum score of a message in that thread. A thread all of whose
+messages contain a smaller score than a message in some other thread is
+placed in an earlier place in the list of messages for that folder; that
+is, threads with the highest scores appear at the bottom of the index
+list.
+
+<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>
@@ -6738,6 +6920,46 @@ hold down the &quot;Control&quot; key on your keyboard. The second &quot;^&quot
&quot;type the character ^&quot;.
<P>
+This version of Alpine 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, Alpine 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, Alpine 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. Aline
+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>
@@ -18300,6 +18522,7 @@ This set of special tokens may be used in the
<A HREF="h_config_index_format">&quot;<!--#echo var="VAR_index-format"-->&quot;</A> option,
in the <A HREF="h_config_reply_intro">&quot;<!--#echo var="VAR_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.
@@ -18312,7 +18535,7 @@ and in the target of Filter Rules.
<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>
@@ -18345,6 +18568,15 @@ email address, never the personal name.
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
@@ -18392,6 +18624,15 @@ are unavailable) of the persons specified in the
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
@@ -18400,6 +18641,14 @@ message's &quot;To:&quot; header field and
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
@@ -18745,7 +18994,11 @@ aspects of the message's state.
The first character is either blank,
a '*' for message marked Important, or a '+' indicating a message
addressed directly to you (as opposed to your having received it via a
-mailing list, for example).
+mailing list, for example). The symbol '.' will be used
+for messages that were sent to you as part of a group message, regardless
+of if all addresses in the To: field are yours or not. This symbol will only show up if
+the feature
+&quot;<A HREF="h_config_mark_for_group"><!--#echo var="FEAT_mark-for-me-in-group"--></A>&quot; is turned on (which is the default).
When the feature
&quot;<A HREF="h_config_mark_for_cc"><!--#echo var="FEAT_mark-for-cc"--></A>&quot;
is set, if the first character would have been
@@ -18881,6 +19134,14 @@ The progression of sizes used looks like:
<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.
@@ -19496,6 +19757,78 @@ This is an end of line marker.
</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>
@@ -20420,6 +20753,53 @@ give up and consider it a failed connection.
&lt;End of help on this topic&gt;
</BODY>
</HTML>
+====== h_config_sleep ======
+<HTML>
+<HEAD>
+<TITLE>OPTION: <!--#echo var="VAR_sleep-interval-length"--> (UNIX Alpine only)</TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: <!--#echo var="VAR_sleep-interval-length"--> (UNIX Alpine only)</H1>
+
+<P>
+When you open an attachment, Alpine goes through a list of viewers either
+in your .mailcap file, or some other mailcap file in your system. The
+normal behavior is that Alpine opens a local copy of the attachment, which
+is removed from the system <B>after</B> the viewer has completed
+displaying it. For example, if you open an attachment on a viewer and
+later close the viewer, then control will return to the system and the
+copy of the attachment will be removed from the system. This is the normal
+behavior and has been accepted for years as the correct behavior.
+
+<P>
+However, if an instance of the viewer is already open, the viewer may
+return control to the system <B>before</B> it reads the copy of the
+attachment. Given that Alpine removes the copy of the attachment after
+control is returned to the system, this may cause Alpine to remove the
+copy of the attachment <B>before</B> it is actually opened by the viewer.
+
+<P>
+Since Alpine has no control over when a viewer returns from opening a file,
+and viewers should not return before they read the file, Alpine has no control
+over when the viewer will read the file and avoid the problem described above.
+
+<P>
+The value of this option is the number of seconds that Alpine will wait
+between the time that the viewer returns control to the system and the
+when it will remove it from the system. You will not notice this
+delay, since this will happen in the background. The default value is
+0 which means that no delay will occur, and it is a value which may trigger
+the problem described above with some viewers. By modifying the value of
+this option you can set Alpine to wait longer. A reasonable small value is 5,
+which works with all viewers tested to date. The maximum value is 120
+(2 minutes).
+<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_interv ======
<HTML>
<HEAD>
@@ -21484,6 +21864,102 @@ your account's home directory).
&lt;End of help on this topic&gt;
</BODY>
</HTML>
+====== h_config_maildir_location ======
+<HTML>
+<HEAD>
+<TITLE>OPTION: <!--#echo var="VAR_maildir-location"--></TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: <!--#echo var="VAR_maildir-location"--></H1>
+
+<P>
+This option should be used only if you have a Maildir folder which you
+want to use as your INBOX. If this is not your case (or don't know what
+this is), you can safely ignore this option.
+
+<P>
+This option overrides the default directory Pine uses to find the location of
+your INBOX, in case this is in Maildir format. The default value of this
+option is "Maildir", but in some systems, this directory could have been
+renamed (e.g. to ".maildir"). If this is your case use this option to change
+the default.
+
+<P>
+The value of this option is prefixed with the "~/" string to determine the
+full path to your INBOX.
+
+<P>
+You should probably <A HREF="h_config_maildir">read</A> a few tips that
+teach you how to configure your maildir for optimal performance. This
+version also has <A HREF="h_config_courier_list">support</A> for the
+Courier style file system when a maildir collection is accessed locally.
+
+<P><UL>
+<LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+</UL>
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+====== h_config_maildir =====
+<HTML>
+<HEAD>
+<TITLE>Maildir Support</TITLE>
+</HEAD>
+<BODY>
+<H1>Maildir Support</H1>
+
+This version of Alpine 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"><!--#echo var="VAR_maildir-location"--></A> configuration
+variable. Most of the time you will not have to worry about the
+<!--#echo var="VAR_maildirlocation"--> 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 Alpine 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>
@@ -22246,6 +22722,45 @@ command, then it will not be re-sorted until the next time it is opened.
&lt;End of help on this topic&gt;
</BODY>
</HTML>
+====== h_config_thread_sort_key =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: <!--#echo var="VAR_thread-sort-key--></TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: <!--#echo var="VAR_thread-sort-key--></TITLE></H1>
+
+This option determines the order in which threads will be displayed. You
+can choose from the options listed below. Each folder is sorted in one of
+the sort orders displayed below first, then the thread containing the last
+message of that sorted list is put at the end of the index. All messages
+of that thread are &quot;removed&quot; from the sorted list and the
+process is repeated with the remaining messages in that list.
+
+<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>
@@ -22516,6 +23031,898 @@ character sets Alpine knows about by using the &quot;T&quot; ToCharsets command.
&lt;End of help on this topic&gt;
</BODY>
</HTML>
+====== h_config_procid =====
+<HTML>
+<HEAD>
+<TITLE>Token: PROCID</TITLE>
+</HEAD>
+<BODY>
+<H1>TOKEN: PROCID explained</H1>
+
+<P>
+The PROCID token is a way in which the user and the program can differentiate
+between different parts of a program. It allows the user to tell the
+program when to use a specific rule, and only use it at that specific
+moment.
+
+<P> The normal way in which this is done is by adding a new configuration
+variable. The idea behind the PROCID token is that instead of adding a new
+configuration variable (which means the user has to go through more
+configuration variables just to tune the program to his liking), we reuse
+an old variable and let the user look inside that variable for the desired
+behavior, which is actually set by setting the PROCID token.
+
+<P>
+Consider the following examples for forward-rules:
+
+<P>
+_ROLE_ == {work} =&gt; _SUBJECT_ := _COPY_{[tag] _SUBJECT_}
+
+<P>
+and
+
+<P>
+_ROLE_ == {work} =&gt; _LCC_ := _TRIM_{_FORWARDFROM_ &lt;_FORWARDADDRESS_&gt;}
+
+<P>
+both are triggered by the same condition. Since both are configured in the
+same variable, only one of them will be executed all the time (whichever
+is first). Therefore in order to differentiate, we add a _PROCID_ token.
+So, for example, the first example above will be executed only when we are
+determining the subject. In this case, the following rule will accomplish
+this task
+
+<P>
+_PROCID_ == {fwd-subject} && _ROLE_ == {work} =&gt; _SUBJECT_ := _COPY_{[tag] _SUBJECT_}
+
+<P>
+In this case, this rule will be tested fully only when we are determining
+the subject line of a forwarded message, not otherwise.
+
+<P>
+It is wise to add the _PROCID_ token as the first condition in a rule, so
+that other conditions will not be tested in a long list of rules.
+
+<P>&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+====== h_config_compose_rules =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: <!--#echo var="VAR_compose-rules"--></TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: <!--#echo var="VAR_compose-rules"--></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 Alpine. 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: <!--#echo var="VAR_forward-rules"--></TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: <!--#echo var="VAR_forward-rules"--></H1>
+
+<P> This option has several uses. This feature uses the PROCID function
+to identify different features of forwarding. You can read more about PROCID
+by following <A HREF="h_config_procid">this link</A>.
+
+<P> If you want to edit the subject of a forwarded message, use the
+PROCID <I>fwd-subject</I>. For example you could have a rule like
+
+<P>
+_ROLE_ == {admin} && _SUBJECT_ !&gt; {[tag] } =&gt; _COPY_{[tag] _SUBJECT_}
+
+<P> Another way in which this option can be used, is to trim the values of
+some fields. For this application the PROCID is <I>fwd-lcc</I>. For
+example it can be used in the following way:
+
+<P>
+_ROLE_ == {work} => _LCC_ := _TRIM_{_FORWARDFROM_ &lt;_FORWARDADDRESS_&gt;}
+
+<P> Other functions that can be used in this option are _EXEC_ and _REXTRIM_.
+
+<P> You can also use the _EXEC_ function. The documentation for this function
+is in the
+<A HREF="h_config_resub_rules"><!--#echo var="VAR_reply-subject-rules"--></A>
+help text.
+
+<P> This configuration option is just one of many that allow you to
+override the value of some global configurations within Alpine. 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: <!--#echo var="VAR_index-rules"--></TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: <!--#echo var="VAR_index-rules"--></H1>
+
+<P> This option is used to supersede the value of the option <A
+HREF="h_config_index_format"><!--#echo var="VAR_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 Alpine. 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_pretty_command =====
+<HTML>
+<HEAD>
+<TITLE>Pretty-Command Explained</TITLE>
+</HEAD>
+<BODY>
+<H1>Pretty Command Explained</H1>
+
+<P> This text explains how to encode keys so that they will be recognized
+by Alpine in the _PKEY_ token. Most direct keystrokes are recognized in the
+same way. For example, the key ~ is recognized by the same character. The
+issue is how control, or functions keys are recognized. The internal code
+is most times easy to find out. If the key you want to use is not already
+recognized by Alpine simply press it. Alpine will print its code. For example,
+the return key is not recognized in this screen, so if you press it, you
+will see the following message.
+
+<P> [Command &quot;RETURN&quot; not defined for this screen. Use ? for help]
+
+<P> from here you can guess that the code for the return command is
+RETURN. You can try other commands, like Control-C, the TAB key, F4, etc.
+to see their codes.
+
+<P>&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+====== h_config_key_macro_rules =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: <!--#echo var="VAR_key-definition-rules"--></TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: <!--#echo var="VAR_key-definition-rules"--></H1>
+
+<P> This option can be used to define macros, that is, to define a key that
+when pressed executes a group of predetermined keystrokes. Since Alpine is
+a menu driven program, sometimes the same key may have different meanings
+in different screens, so a global redefinition of a key although possible
+is not advisable.
+
+<P> <B>Always use the _SCREEN_ token as defined below.</B>. You have been
+warned!
+
+<P> In each screen, every time you press a recognized key a command is
+activated. In order to understand this feature, think of commands instead
+of keystrokes. For example, you can think of the sort by thread command.
+This command is associated to the keystrokes $ and h. You may want to
+associate this command to a specific keystroke, like ~, so every time you
+press the ~ key, Alpine understand the $ and h keystrokes, which activates
+the sort by thread command.
+
+<P> Therefore, in order to use this option you must think of three
+components. The screen where you will use the macro, the keystroke you
+want to use and the set of keystrokes used by Alpine to accomplish the task
+you want to accomplish. We will talk about these three components in what
+follows.
+
+<P> First you must decide in which screen the macro will be used. This
+feature is currently only available for the screen where your messages
+are listed in index form (<A HREF="h_mail_index">MESSAGE INDEX</A>),
+the screen where your message is displayed
+(<A HREF="h_mail_view">MESSAGE TEXT</A>) and the screen where the list of
+folders is displayed (<A HREF="h_folder_maint">FOLDER LIST</A>). The
+internal names of these screens for this patch are &quot;index&quot;,
+&quot;text&quot; and
+&quot;folder&quot; respectively. Please note that the internal names are
+all in lowercase are are case sensitive.
+
+<P> In order to define the screen, you use the _SCREEN_ token, so for
+example, you can write _SCREEN_ == {index}.
+
+<P> Second you must think of which key you will use to activate the macro.
+Here you can use any key of your choice. The token you use to designate a
+key is the _PKEY_ token (PKEY stands for &quot;pressed key&quot;). For
+example you could use _PKEY_ == {~}, to designate the &quot;~&quot;
+character to activate the command. Some keystrokes (like control, or
+function keys) are encoded in special ways. You should read the
+<A HREF="h_config_pretty_command">full explanation</A> on how to find
+out the encoding for each keystroke.
+
+<P> Last, you must think of the list of keys you will use to accomplish
+the task you want Alpine to perform. Say for example you want to have the
+folder sorted by thread. That means you want Aline to execute the keys
+&quot;$&quot; and &quot;h&quot;. You use the _COMMAND_ function to specify
+this. The syntax in this case is _COMMAND_{$,h}.
+
+<P> Observe that in the above example the different inputs are separated
+by commas. This is the standard way in which the
+<A HREF="h_config_init_cmd_list"><!--#echo var="VAR_initial-keystroke-list"--></A> command works from
+the command line. Due to restrictions in the way Alpine works, a comma is a
+special character, which when added to a configuration option like this
+will cause the configuration to split into several lines in the
+configuration screen. This has the effect of producing several
+configuration options, all of which are incorrect. This is undesirable
+because what you want is to have it all in one line. In order to force the
+configuration into one line you must quote the comma. The best way to
+accomplish this is by quoting the full definition of the rule. For
+example.
+
+<P>
+&quot;_SCREEN_ == {index} && _PKEY_ == {~} => _COMMAND_{$,h}&quot;
+
+<P> Another way to accomplish the same effect is by quoting the command and
+not using quotes for the full command, nor commas to separate the
+keystrokes in the command, for example
+
+<P>
+_SCREEN_ == {index} && _PKEY_ == {~} => _COMMAND_{&quot;$h&quot;}
+
+<P> For more information on how to define the argument of the _COMMAND_
+token see the help of
+<A HREF="h_config_init_cmd_list"><!--#echo var="VAR_initial-keystroke-list"--></A>.
+
+<P> Because the $ command can also be used as the first character in the
+definition of an environemnt variable, no expansion of environment variables
+is done when parsing this variable. The $ character does not need quoting
+and quoting it will make Alpine fail to produce the correct result.
+
+<P> This configuration option is just one of many that allow you to
+override the value of some global configurations within Alpine. 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: <!--#echo var="VAR_replace-rules"--></TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: <!--#echo var="VAR_replace-rules"--></H1>
+
+<P> This option is used to have Alpine print different values for specific
+tokens in the <A HREF="h_config_index_format"><!--#echo var="VAR_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, like the reply leadin string in the OPENINGTEXTNQ token of the index.
+<BR>
+_FOLDER_ == {mailing-list} => _OPENINGTEXTNQ_ := _REXTRIM_{On.*wrote: }
+
+<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>
+
+<P> You can also use the _EXEC_ function. The documentation for this function
+is in the
+<A HREF="h_config_resub_rules"><!--#echo var="VAR_reply-subject-rules"--></A>
+help text.
+
+<P> This configuration option is just one of many that allow you to
+override the value of some global configurations within Alpine. 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: <!--#echo var="VAR_reply-leadin-rules"--></TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: <!--#echo var="VAR_reply-leadin-rules"--></H1>
+
+<P> This option is used to have Alpine generate a different
+<A HREF="h_config_reply_intro"><!--#echo var="VAR_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 Alpine. 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: <!--#echo var="VAR_reply-subject-rules"--></TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: <!--#echo var="VAR_reply-subject-rules"--></H1>
+
+<P> This option is used to have Alpine generate a different subject when
+replying rather than the one Alpine 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> Another interesting use of this option is the use of the _EXEC_ function.
+This function takes as an argument a program or a script. This program
+must take as the input a file, and write its output to that file. For example,
+below is a sample of a script that removes the letter &quot;a&quot; of a file.
+
+<PRE>
+#!/bin/sh
+sed 's/a//g' $1 > /tmp/mytest
+mv /tmp/mytest $1
+</PRE>
+
+<P>
+As you can see this script took &quot;$1&quot; as input file, the sed program
+wrote its output to /tmp/mytest, and then the move program moved the file
+/tmp/mytest to the input file &quot;$1&quot;. This is the kind of behavior
+that your program is expected to have.
+
+<P>
+The content of the input file (&quot;$1&quot; above) is the value of a token
+like _SUBJECT_. In order to indicate this, we use the notation
+
+<P>
+_SUBJECT_ := _EXEC_{/path/to/script}
+
+<P> for the action. So for example
+
+<P>
+_FOLDER_ := {sent-mail} =&gt; _SUBJECT_ := _EXEC_{/path/to/script}
+
+<P> is a valid rule.
+
+<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 Alpine. 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: <!--#echo var="VAR_sort-rules"--></TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: <!--#echo var="VAR_sort-rules"--></H1>
+
+<P> This option is used to have Alpine sort different folders in different orders
+and thus override the value already set in the
+<A HREF="h_config_sort_key"><!--#echo var="VAR_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 Alpine. 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: <!--#echo var="VAR_save-rules"--></TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: <!--#echo var="VAR_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"><!--#echo var="FEAT_auto-move-read-msgs"--></A> configuration
+option is also enabled then these definitions will be used to move messages
+from your INBOX when exiting Alpine.
+
+<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 Alpine. 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: <!--#echo var="VAR_reply-indent-rules"--></TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: <!--#echo var="VAR_reply-indent-rules"--></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"><!--#echo var="VAR_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 Alpine. 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: <!--#echo var="VAR_smtp-rules"--></TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: <!--#echo var="VAR_smtp-rules"--></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 Alpine 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 Alpine will get
+the name of the server from the
+<A HREF="h_config_smtp_server">&quot;<!--#echo var="VAR_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 Alpine. 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: <!--#echo var="VAR_startup-rules"--></TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: <!--#echo var="VAR_startup-rules"--></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"><!--#echo var="VAR_incoming-startup-rule"--></A> and override
+Alpine'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 Alpine. 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 option you have set in Alpine.
+
+<P>
+ For example, you can set your folders to be sorted in a certain way when
+you open them (say by Arrival). You may want, however, your newsgroups to
+be sorted by thread. The set of &quot;rules&quot; options allows you to
+configure this and many other options, including the index-format for
+specific folders, the way the subject is displayed in the index screen or
+the reply-leadin-string, to name a few.
+
+<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 _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 &quot;Fred
+Flinstone&quot;, and the action will be that you will be offered to save
+it in the folder &quot;Fred&quot;, whenever you press the letter
+&quot;S&quot; to save a message.
+
+<P>
+ The separator is always &quot;=&gt;&quot;, with one exception to be seen
+later. But for the most part this will be the only one you will ever need.
+
+<P>
+ Now let us see how to do it. There are 13 functions already defined for
+you. These are: _EXEC_, _INDEX_, _REPLACE_, _REPLY_, _RESUB_, _SAVE_,
+_SIGNATURE_, _SORT_, _STARTUP_, _TRIM_, _REXTRIM_, _THREADSTYLE and
+_THREADINDEX_. The parameter of a function has to be enclosed between
+&quot;{&quot; and &quot;}&quot;, so for example you can specify
+_SAVE_{saved-messages} as a valid sentence.
+
+<P>
+ Later in the document you will find examples. Here is a short
+description of what each function does:
+
+<P>
+<UL>
+<LI> _EXEC_ : This function takes as an argument a program. This program
+gets as the input a file and must rewrite its output to that file, which
+is then taken as the value to replace from the contents of that file. You
+can use this function with
+<A HREF="h_config_resub_rules"><!--#echo var="VAR_reply-subject-rules"--></A>,
+<A HREF="h_config_replace_rules"><!--#echo var="VAR_replace-rules"--></A> and
+<A HREF="h_config_forward_rules"><!--#echo var="VAR_forward-rules"--></A>.
+See the help of those options for examples of how to use this function
+and configure these rules.
+<BR>&nbsp;<BR>
+<LI> _INDEX_ : This function takes as an argument an index-format, and
+makes that the index-format for the specified folder.
+<BR>&nbsp;<BR>
+<LI> _REPLACE_ : This function replaces the subject/from of the given e-mail by
+another subject/from only when displaying the index.
+<BR>&nbsp;<BR>
+<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.
+<BR>&nbsp;<BR>
+<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.
+<BR>&nbsp;<BR>
+<LI> _RESUB_ : This function replaces the subject of the given e-mail by
+another subject only when replying to a message.
+<BR>&nbsp;<BR>
+<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.
+<BR>&nbsp;<BR>
+<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.
+<BR>&nbsp;<BR>
+<LI> _SMTP_ : This function takes as an argument the definition of a
+SMTP server.
+<BR>&nbsp;<BR>
+<LI> _SORT_ : This function takes as an argument a Sort Style, and sorts a
+specified folder in that sort order.
+<BR>&nbsp;<BR>
+<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_.
+<BR>&nbsp;<BR>
+<LI> _REXTRIM_ : Same as _TRIM_ but its argument is one and
+only one extended regular expression.
+<BR>&nbsp;<BR>
+<LI> _STARTUP_ : This function takes as an argument an
+incoming-startup-rule, and open an specified folder using that rule.
+<BR>&nbsp;<BR>
+<LI> _THREADSTYLE_ : This function takes as an argument a
+threading-display-style and uses it to display threads in a folder.
+<BR>&nbsp;<BR>
+<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 &quot;Fred Flinstone&quot;. If
+the From is &quot;Wilma Flinstone&quot; 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 &quot;{&quot; and &quot;}&quot; in the condition, this part
+of the condition is called the &quot;condition set&quot;. The definition
+of each token can be found <A HREF="h_index_tokens">here</A>.
+
+<P> A special testing token called _PROCID_ can be used to differentiate
+inside a rule, between two rules that are triggered by the same condition.
+A full explanation of the _PROCID_ token can be found in
+<A HREF="h_config_procid">this link</A>.
+
+<P> There are two more tokens related to the option
+<A HREF="h_config_key_macro_rules">key-definition-rules</A>. Those tokens
+are only specific to that option, and hence are not explained here.
+
+<P> You can also test in different ways, you can use the following
+&quot;test operands&quot;: &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
+&quot;Freddy&quot;, then the condition: _NICK_ &lt;&lt; {Freddy}, would be true if
+the value of _NICK_ were &quot;Fred&quot;, &quot;red&quot; or &quot;Freddy&quot;. 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
+&quot;Fred&quot;, then the condition: _FROM_ &gt;&gt; {Fred}, would be true if
+the value of _FROM_ were &quot;Fred Flinstone&quot; or &quot;Fred P. Flinstone&quot; or &quot;Freddy&quot;.
+<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 &quot;Freddy&quot; or &quot;red&quot;.
+<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 &quot;folder1&quot; and &quot;folder2&quot; to be sorted by
+Ordered Subject upon entering. Then you can list them all of them in the
+condition part separting them by a &quot;;&quot;. 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 &quot;folder1&quot; but not for &quot;folder2&quot;. This is because the
+comparison of the name of the folder is done with whatever is in between
+&quot;{&quot;, &quot;;&quot; or &quot;}&quot;, so in the above rule you would be testing <BR>
+&quot;folder2&quot; == &quot; folder2&quot;. The extra space makes the difference.
+The reason why the first rule does not fail is because
+&quot;folder2&quot; &lt;&lt; &quot; folder2&quot; 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 &quot;lisa/lisa&quot;, and if the nick
+is &quot;kika&quot;, it will save the message in the folder &quot;kika/kika&quot;
+
+<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 &quot;=&gt;&quot; to &quot;-&gt;&quot;). 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 &quot;comp.mail.pine&quot;, &quot;pine-info&quot; or &quot;pine-alpha&quot;
+will be saved to the folder &quot;pine&quot;.
+
+<P> _FROM_ &lt;&lt; {Pine Master} -&gt; pine <BR>
+Any message whose From field contains
+&quot;Pine Master&quot; 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 &quot;Lynx&quot;, &quot;pine-info&quot; and
+&quot;comp.mail.pine&quot;, where the size is not present.
+
+<P> _FOLDER_ == {Lynx;pine-info} =&gt; _REPLY_{*** _FROM_ (_ADDRESS_)
+wrote in the _FOLDER_ list _SMARTDATE_(&quot;Today&quot; &quot;today&quot; &quot;on
+_LONGDATE_&quot;):}<BR> If a message is in one of the incoming folders &quot;Lynx&quot;
+or &quot;pine-info&quot;, create a reply-leadin-string that acknowledges that. Note
+the absence of &quot;,&quot; 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 &quot;Lynx&quot;,
+&quot;comp.mail.pine&quot;, 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 &quot;Lynx&quot; eliminate from the subject the string &quot;lynx-dev &quot; (with
+the space at the end). For example a message whose subject is &quot;Re:
+lynx-dev unvisited Visited Links&quot;, would be shown in the index with
+subject: &quot;Re: unvisited Visited Links&quot;, making the subject shorter and
+giving the same information.
+
+<P> _FROM_ &gt;&gt; {Name (Comment)} =&gt; _FROM_ :=
+_TRIM_{ (Comment)}<BR> Remove the part &quot; (Comment)&quot;
+from the _FROM_, so when displaying in the index the real From &quot;Name&quot;
+will appear.
+
+<P> _SUBJECT_ == {} =&gt; _RESUB_{Re: your mail without subject}
+If there is no subject in the message, use the subject &quot;Re: your mail
+wiyhout subject&quot; 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 &quot;bug report&quot;, with the subject
+&quot;Re: About your bug report&quot;, 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: &quot;Re:
+About your Re: About your bug report&quot;, 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 &quot;Re: About your&quot; only the first time the
+message is replied.
+
+<P>
+ Say your personal name is &quot;Fred Flinstones&quot;, and assume that you don't
+like to see &quot;To: comp.mail.pine&quot; 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 &quot;pine-info&quot; 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 &quot;Trash&quot;, use
+the following rule:<BR>
+_FLAG_ >> {D} -> Trash
+
+<P>
+The reason why the above test is not &quot;_FLAG_ == {D}&quot; 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 &quot;saving&quot; rules do not compete with &quot;sorting&quot; rules. So the first
+&quot;saving&quot; rule that matches will be executed in the case of saving and so
+on.
+
+<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>
@@ -22827,6 +24234,43 @@ That won't work because spell works in a different way.
&lt;End of help on this topic&gt;
</BODY>
</HTML>
+====== h_config_special_text_to_color =====
+<HTML>
+<HEAD>
+<TITLE>OPTION: <!--#echo var="VAR_special-text-color"--></TITLE>
+</HEAD>
+<BODY>
+<H1>OPTION: <!--#echo var="VAR_special-text-color"--></H1>
+
+Use this option to enter patterns (text or regular expressions) that
+Alpine will highlight in the body of the text that is not part of a handle
+(an internal or external link that Alpine 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. There is only a <A
+HREF="h_regex_text">set</A> of regular expressions that are matched.
+
+<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>
@@ -22991,6 +24435,12 @@ specified.
Command Modifying Tokens:
<DL>
+<DT>_ADDRESS_</DT>
+<DD>When the command is executed, this token is replaced
+with the address of the person sending the message in the format
+mailbox@host.
+</DD>
+
<DT>_RECIPIENTS_</DT>
<DD>When the command is executed, this token is replaced
with the space delimited list of recipients of the
@@ -26103,6 +27553,76 @@ the From field is used to show the relationships instead of the Subject field.
&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">
+<!--#echo var="VAR_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 Alpine. 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">
+<!--#echo var="VAR_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"><!--#echo var="VAR_threading-index-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 Alpine. 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>
@@ -28009,6 +29529,22 @@ See also <A HREF="h_config_allow_chg_from">&quot;<!--#echo var="FEAT_allow-chang
&lt;End of help on this topic&gt;
</BODY>
</HTML>
+====== h_config_use_domain =====
+<HTML>
+<HEAD>
+<TITLE>FEATURE: <!--#echo var="FEAT_return-path-uses-domain-name"--> </TITLE>
+</HEAD>
+<BODY>
+<H1>FEATURE: <!--#echo var="FEAT_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>
@@ -28605,6 +30141,71 @@ of flowed text.
&lt;End of help on this topic&gt;
</BODY>
</HTML>
+====== h_config_alt_reply_menu =====
+<HTML>
+<HEAD>
+<TITLE>FEATURE: <!--#echo var="FEAT_alternate-reply-menu"--></TITLE>
+</HEAD>
+<BODY>
+<H1>FEATURE: <!--#echo var="FEAT_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> A: This determines if Pine will include or not the attachments sent to
+you in the message that you are replying. By default Pine will use the value
+of the configuration option
+<A HREF="h_config_attach_in_reply"><!--#echo var="FEAT_include-attachments-in-reply"--></A>, but
+you can use this option to override such behavior in a per message basis.
+
+<LI> F: To decide if you want to send flowed text or not. This option appears
+unless you have quelled sending flowed text.
+
+<LI> H: This option determines if the headers of a message are to be
+included in the body of the message that is being replied. By default Pine
+will use the value of the configuration option
+<A HREF="h_config_include_header"><!--#echo var="FEAT_include-header-in-reply"--></A>, but
+you can use this option to override such behavior in a per message basis.
+
+<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.
+
+<LI> S: To strip the signature from a message, only available is the feature
+ <a href="h_config_sigdashes"><!--#echo var="FEAT_enable-sigdashes"--></a> or the
+<a href="h_config_strip_sigdashes"><!--#echo var="FEAT_strip-from-sigdashes-on-reply"--></a> option are
+enabled.
+
+</OL>
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
====== h_config_del_from_dot =====
<HTML>
<HEAD>
@@ -29128,6 +30729,38 @@ Ctrl-B key can be used to select the previous web hostnames in the same way.
&lt;End of help on this topic&gt;
</BODY>
</HTML>
+====== h_config_enable_long_url =====
+<HTML>
+<HEAD>
+<TITLE>FEATURE: <!--#echo var="FEAT_enable-msg-view-long-url"--></TITLE>
+</HEAD>
+<BODY>
+<H1>FEATURE: <!--#echo var="FEAT_enable-msg-view-long-url"--></H1>
+
+This feature modifies the behavior of Alpine's MESSAGE TEXT screen. When this feature
+is set alpine will attempt to recognize long urls (those that spread over several
+lines in the text) for the HTTP protocol, even when they have not been enclosed between
+delimiters &quot;&lt;&quot; and &quot;&gt;&quot;.
+
+<P>The normal behavior in Alpine is that if a URL is preceeded by the &quot;&lt;&quot;
+character and this URL was not finished before the end of the line, then a
+continuation of the URL is searched in the following line(s). Normally, this type of
+URLs will be ended by the &quot;&gt;&quot; character, and if it is not, there is a
+possibility of including erroneous text into the URL.
+
+<P>Enabling this feature will make Alpine search for a continuation of certain URLs in
+lines following its location. This will be of great help most times, but in some cases
+the algorithm will catch some text into the URL that is not part of the URL.
+
+<P>If you find that Alpine failed to recognize correctly a URL simply edit the URL before
+passing it to your browser.
+
+<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_enable_view_addresses =====
<HTML>
<HEAD>
@@ -29162,6 +30795,27 @@ Ctrl-B key can be used to select the previous web hostnames in the same way.
&lt;End of help on this topic&gt;
</BODY>
</HTML>
+====== h_config_circular_tab =====
+<HTML>
+<HEAD>
+<TITLE>FEATURE: <!--#echo var="FEAT_enable-circular-tab"--></TITLE>
+</HEAD>
+<BODY>
+<H1>FEATURE: <!--#echo var="FEAT_enable-circular-tab"--></H1>
+
+<P>
+This Feature is like
+<A HREF="h_config_auto_open_unread">&quot;<!--#echo var="FEAT_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_enable_view_arrows =====
<HTML>
<HEAD>
@@ -29435,6 +31089,49 @@ than across the columns as is the default.
&lt;End of help on this topic&gt;
</BODY>
</HTML>
+====== h_config_courier_list =====
+<HTML>
+<HEAD>
+<TITLE>FEATURE: <!--#echo var="FEAT_courier-folder-list"--></TITLE>
+</HEAD>
+<BODY>
+<H1>FEATURE: <!--#echo var="FEAT_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_fold_dir_view"><!--#echo var="FEAT_separate-folder-and-directory-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>
@@ -29589,6 +31286,29 @@ them as deleted in the INBOX. Messages in the INBOX marked with an
&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 Alpine's behavior upon quitting. If set,
+and the
+<A HREF="h_config_read_message_folder">&quot;<!--#echo var="VAR_read-message-folder"-->&quot;</A>
+option is also set, then Alpine 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;<!--#echo var="VAR_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>
@@ -30039,6 +31759,23 @@ Reply Use, Forward Use, and Compose Use.
&lt;End of help on this topic&gt;
</BODY>
</HTML>
+====== h_config_enhanced_thread =====
+<HTML>
+<HEAD>
+<TITLE>FEATURE: <!--#echo var="FEAT_enhanced-fancy-thread-support"--></TITLE>
+</HEAD>
+<BODY>
+<H1>FEATURE: <!--#echo var="FEAT_enhanced-fancy-thread-support"--></H1>
+
+If this option is set certain commands in Pine will operate in loose
+threads too. For example, the command ^R 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>
@@ -30517,6 +32254,40 @@ but that is not implemented.
&lt;End of help on this topic&gt;
</BODY>
</HTML>
+====== h_config_ignore_size =====
+<HTML>
+<HEAD>
+<TITLE>FEATURE: <!--#echo var="FEAT_ignore-size-changes"--></TITLE>
+</HEAD>
+<BODY>
+<H1>FEATURE: <!--#echo var="FEAT_ignore-size-changes"--></H1>
+
+When you have an account residing in an IMAP server, Alpine gets the size of
+each message from the server. However, when Alpine saves a message residing
+in an IMAP server, Alpine computes the size of the message independently. If
+these two numbers do not match for a message, Alpine asks you if you still
+want to take the risk of saving the message, since data corruption or loss
+of data could result of this save.
+
+<P>
+Sometimes the root of this problem is that the server is defective, and
+there will not be loss of information when saving such message. Enabling
+this feature will make Aline ignore such error and continue saving the
+message. If you can determine that this is the case, enable this feature
+so that the saving operation will succeed. An example of a defective server
+is the Gmail IMAP server. Another example is some versions of the Exchange
+server.
+
+<P>
+It is recommended that this feature be disabled most of the time and only
+enabled when you find a server which you can determine that has the above
+mentioned defect, but be disabled again after making this operation
+succeed.
+
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
====== h_config_force_low_speed =====
<HTML>
<HEAD>
@@ -31204,6 +32975,30 @@ to see the available Editing and Navigation commands.
&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_index_arrow_color =====
<HTML>
<HEAD>
@@ -33013,6 +34808,28 @@ messages.
&lt;End of help on this topic&gt;
</BODY>
</HTML>
+====== h_config_mark_for_group =====
+<HTML>
+<HEAD>
+<TITLE>FEATURE: <!--#echo var="FEAT_mark-for-me-in-group"--></TITLE>
+</HEAD>
+<BODY>
+<H1>FEATURE: <!--#echo var="FEAT_mark-for-me-in-group"--></H1>
+
+This feature affects Alpine's MESSAGE INDEX display.
+By default, a '+' is displayed in the first column if the
+message is addressed directly to you.
+When this feature is set and the message is addressed to you as part of a group message
+(that is, your address appears in the To: field, but there is more than one recipient), then a
+'.' character is displayed instead.
+
+<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_mark_for_cc =====
<HTML>
<HEAD>
@@ -33022,7 +34839,7 @@ messages.
<H1>FEATURE: <!--#echo var="FEAT_mark-for-cc"--></H1>
This feature affects Alpine's MESSAGE INDEX display.
-By default, a '+' is displayed in the first column if the
+By default, a '+' or a '.' is displayed in the first column if the
message is addressed directly to you.
When this feature is set and the message is not addressed to you, then a
'-' character is displayed if the message is instead Cc'd directly
diff --git a/pith/pineelt.h b/pith/pineelt.h
index e44ae37a..d88f5fb9 100644
--- a/pith/pineelt.h
+++ b/pith/pineelt.h
@@ -40,6 +40,7 @@ typedef struct pine_elt {
PINETHRD_S *pthrd;
PARTEX_S *exceptions;
ICE_S *ice;
+ char *firsttext;
/* per-message pine state bits */
unsigned int hidden:1;
unsigned int excluded:1;
diff --git a/pith/reply.c b/pith/reply.c
index 3445097f..348ebf26 100644
--- a/pith/reply.c
+++ b/pith/reply.c
@@ -46,6 +46,8 @@ static char rcsid[] = "$Id: reply.c 1074 2008-06-04 00:08:43Z hubert@u.washingto
#include "../pith/ablookup.h"
#include "../pith/mailcmd.h"
#include "../pith/margin.h"
+#include "../pith/copyaddr.h"
+#include "../pith/rules.h"
/*
@@ -814,8 +816,27 @@ char *
reply_quote_str(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_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 */
@@ -867,10 +888,29 @@ reply_quote_str(ENVELOPE *env)
int
reply_quote_str_contains_tokens(void)
{
- 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_COMPOSE, 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)));
}
@@ -972,7 +1012,7 @@ reply_body(MAILSTREAM *stream, ENVELOPE *env, struct mail_bodystruct *orig_body,
if(!orig_body
|| orig_body->type == TYPETEXT
|| reply_raw_body
- || F_OFF(F_ATTACHMENTS_IN_REPLY, ps_global)){
+ || !ps_global->reply.attach){
char *charset = NULL;
/*------ Simple text-only message ----*/
@@ -980,7 +1020,7 @@ reply_body(MAILSTREAM *stream, ENVELOPE *env, struct mail_bodystruct *orig_body,
body->type = TYPETEXT;
body->contents.text.data = msgtext;
reply_delimiter(env, role, pc);
- if(F_ON(F_INCLUDE_HEADER, ps_global))
+ if(ps_global->reply.inchdr)
reply_forward_header(stream, msgno, sect_prefix,
env, pc, prefix);
@@ -1038,7 +1078,7 @@ reply_body(MAILSTREAM *stream, ENVELOPE *env, struct mail_bodystruct *orig_body,
if(reply_body_text(orig_body, &tmp_body)){
reply_delimiter(env, role, pc);
- if(F_ON(F_INCLUDE_HEADER, ps_global))
+ if(ps_global->reply.inchdr)
reply_forward_header(stream, msgno, sect_prefix,
env, pc, prefix);
@@ -1076,7 +1116,7 @@ reply_body(MAILSTREAM *stream, ENVELOPE *env, struct mail_bodystruct *orig_body,
body->nested.part->body.subtype = cpystr("Plain");
}
reply_delimiter(env, role, pc);
- if(F_ON(F_INCLUDE_HEADER, ps_global))
+ if(ps_global->reply.inchdr)
reply_forward_header(stream, msgno, sect_prefix,
env, pc, prefix);
@@ -1099,7 +1139,7 @@ reply_body(MAILSTREAM *stream, ENVELOPE *env, struct mail_bodystruct *orig_body,
int partnum;
reply_delimiter(env, role, pc);
- if(F_ON(F_INCLUDE_HEADER, ps_global))
+ if(ps_global->reply.inchdr)
reply_forward_header(stream, msgno, sect_prefix,
env, pc, prefix);
@@ -1334,6 +1374,10 @@ get_addr_data(ENVELOPE *env, IndexColType type, char *buf, size_t maxlen)
buf[0] = '\0';
switch(type){
+ case iFfrom:
+ addr = env && env->sparep ? env->sparep : NULL;
+ break;
+
case iFrom:
addr = env ? env->from : NULL;
break;
@@ -1719,21 +1763,150 @@ get_reply_data(ENVELOPE *env, ACTION_S *role, IndexColType type, char *buf, size
break;
+ case iProcid:
+ if(ps_global->procid){
+ strncpy(buf, ps_global->procid, maxlen);
+ buf[maxlen] = '\0';
+ }
+ break;
+
+ case iRole:
+ if (ps_global->role){
+ strncpy(buf, ps_global->role, maxlen);
+ buf[maxlen] = '\0';
+ }
+ break;
+
+ case iRoleNick:
+ if(role && role->nick){
+ strncpy(buf, role->nick, maxlen);
+ buf[maxlen] = '\0';
+ }
+ break;
+
+ case iPkey:
+ if(ps_global->pressed_key){
+ strcpy(buf, ps_global->pressed_key);
+ buf[maxlen] = '\0';
+ }
+ break;
+
+ case iScreen:
+ if(ps_global->screen_name){
+ strncpy(buf, ps_global->screen_name, 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:
+ if(ps_global->cur_folder){
+ strncpy(buf,ps_global->cur_folder, maxlen);
+ buf[maxlen] = '\0';
+ }
+ break;
+
+ case iCollection:
+ if(ps_global->context_current->nickname){
+ strncpy(buf,ps_global->context_current->nickname, maxlen);
+ buf[maxlen] = '\0';
+ }
+ break;
+
+ case iFlag:
+ {MAILSTREAM *stream = ps_global->mail_stream;
+ MSGNO_S *msgmap = NULL;
+ long msgno;
+ MESSAGECACHE *mc;
+ strncpy(buf, "_FLAG_", maxlen); /* default value */
+ if (stream){
+ msgmap = sp_msgmap(stream);
+ 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" : "" );
+ }
+ buf[maxlen] = '\0';
+ }
+ 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 iNewLine:
if(maxlen >= strlen(NEWLINE)){
@@ -1762,6 +1935,11 @@ get_reply_data(ENVELOPE *env, ACTION_S *role, IndexColType type, char *buf, size
break;
+ case iLcc: /* fake it, there are not enough spare pointers */
+ if (env && env->date)
+ sprintf(buf,"%s",env->date);
+ break;
+
case iNews:
case iCurNews:
get_news_data(env, type, buf, maxlen);
@@ -1811,6 +1989,14 @@ get_reply_data(ENVELOPE *env, ACTION_S *role, IndexColType type, char *buf, size
break;
+ case iOpeningText:
+ case iOpeningTextNQ:
+ if(env && env->sparep){
+ strncpy(buf, ((SPAREP_S *)env->sparep)->value, maxlen);
+ buf[maxlen] = '\0';
+ }
+ break;
+
case iSubject:
if(env && env->subject){
size_t n, len;
@@ -1869,7 +2055,18 @@ reply_delimiter(ENVELOPE *env, ACTION_S *role, gf_io_t pc)
if(!env)
return;
- strncpy(buf, ps_global->VAR_REPLY_INTRO, MAX_DELIM);
+ { RULE_RESULT *rule;
+ rule = get_result_rule(V_REPLY_LEADIN_RULES, 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)){
@@ -2128,6 +2325,7 @@ forward_subject(ENVELOPE *env, int flags)
{
size_t l;
char *p, buftmp[MAILTMPLEN];
+ RULE_RESULT *rule;
if(!env)
return(NULL);
@@ -2135,9 +2333,20 @@ forward_subject(ENVELOPE *env, int flags)
dprint((9, "checking subject: \"%s\"\n",
env->subject ? env->subject : "NULL"));
- if(env->subject && env->subject[0]){ /* add (fwd)? */
- snprintf(buftmp, sizeof(buftmp), "%s", env->subject);
- buftmp[sizeof(buftmp)-1] = '\0';
+ buftmp[0] = '\0';
+ ps_global->procid = cpystr("fwd-subject");
+ if (rule = get_result_rule(V_FORWARD_RULES,FOR_COMPOSE, env)){
+ sprintf(buftmp, "%.200s", rule->result);
+ if(rule->result)
+ fs_give((void **)&rule->result);
+ fs_give((void **)&rule);
+ }
+ else if(env->subject)
+ sprintf(buftmp, "%.200s", env->subject);
+ buftmp[sizeof(buftmp)-1] = '\0';
+ fs_give((void **)&ps_global->procid);
+
+ if(buftmp[0]){ /* add (fwd)? */
/* decode any 8bit (copy to the temp buffer if decoding doesn't) */
if(rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf,
SIZEOF_20KBUF, buftmp) == (unsigned char *) buftmp)
@@ -2638,9 +2847,12 @@ get_body_part_text(MAILSTREAM *stream, struct mail_bodystruct *body,
* tied our hands, alter the prefix to continue flowed
* formatting...
*/
- if(flow_res)
+ if(flow_res && !ps_global->reply.no_send_flowed)
wrapflags |= GFW_FLOW_RESULT;
+ filters[filtcnt].filter = gf_quote_test;
+ filters[filtcnt++].data = gf_line_test_opt(select_quote, NULL);
+
filters[filtcnt].filter = gf_wrap;
/*
* The 80 will cause longer lines than what is likely
@@ -2674,9 +2886,9 @@ get_body_part_text(MAILSTREAM *stream, struct mail_bodystruct *body,
* We also want to fold "> " quotes so we get the
* attributions correct.
*/
- if(flow_res && prefix && !strucmp(prefix, "> "))
+ if(flow_res && !ps_global->reply.no_send_flowed && prefix && !strucmp(prefix, "> "))
*(prefix_p = prefix + 1) = '\0';
-
+ ps_global->reply.no_send_flowed = 0; /* reset for next call */
if(!(wrapflags & GFW_FLOWED)
&& flow_res){
filters[filtcnt].filter = gf_line_test;
@@ -2709,9 +2921,7 @@ get_body_part_text(MAILSTREAM *stream, struct mail_bodystruct *body,
}
if(prefix){
- if(ps_global->full_header != 2
- && (F_ON(F_ENABLE_SIGDASHES, ps_global)
- || F_ON(F_ENABLE_STRIP_SIGDASHES, ps_global))){
+ if(ps_global->reply.strip){
dashdata = 0;
filters[filtcnt].filter = gf_line_test;
filters[filtcnt++].data = gf_line_test_opt(sigdash_strip, &dashdata);
@@ -2736,7 +2946,7 @@ get_body_part_text(MAILSTREAM *stream, struct mail_bodystruct *body,
dq.do_color = 0;
dq.delete_all = 1;
- filters[filtcnt].filter = gf_line_test;
+ filters[filtcnt].filter = gf_quote_test;
filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq);
}
diff --git a/pith/save.c b/pith/save.c
index 957e163b..22cfa4a6 100644
--- a/pith/save.c
+++ b/pith/save.c
@@ -954,7 +954,7 @@ save(struct pine *state, MAILSTREAM *stream, CONTEXT_S *context, char *folder,
*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(flags)
@@ -1157,6 +1157,7 @@ long save_fetch_append_cb(MAILSTREAM *stream, void *data, char **flags,
snprintf(buf, sizeof(buf),
"Message to save shrank: source msg # %ld may be saved incorrectly",
mn_raw2m(pkg->msgmap, raw));
+ if(F_OFF(F_IGNORE_SIZE, ps_global))
q_status_message(SM_ORDER, 0, 3, buf);
}
else{
diff --git a/pith/send.c b/pith/send.c
index a0c60439..3cca3365 100644
--- a/pith/send.c
+++ b/pith/send.c
@@ -44,6 +44,7 @@ static char rcsid[] = "$Id: send.c 1204 2009-02-02 19:54:23Z hubert@u.washington
#include "../pith/ablookup.h"
#include "../pith/sort.h"
#include "../pith/smime.h"
+#include "../pith/rules.h"
#include "../c-client/smtp.h"
#include "../c-client/nntp.h"
@@ -53,7 +54,7 @@ static char rcsid[] = "$Id: send.c 1204 2009-02-02 19:54:23Z hubert@u.washington
/* name::type::canedit::writehdr::localcopy::rcptto */
PINEFIELD pf_template[] = {
{"X-Auth-Received", FreeText, 0, 1, 1, 0}, /* N_AUTHRCVD */
- {"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},
@@ -257,6 +258,13 @@ postponed_stream(MAILSTREAM **streamp, char *mbox, char *type, int checknmsgs)
if(exists & FEX_ISFILE){
context_apply(tmp, p_cntxt, mbox, sizeof(tmp));
+#ifndef _WINDOWS
+ if (!struncmp(tmp, "#md/",4) || !struncmp(tmp, "#mc/", 4)){
+ char tmp2[MAILTMPLEN];
+ maildir_file_path(tmp, tmp2, sizeof(tmp2));
+ strcpy(tmp, tmp2);
+ }
+#endif
if(!(IS_REMOTE(tmp) || is_absolute_path(tmp))){
/*
* The mbox is relative to the home directory.
@@ -1229,7 +1237,7 @@ pine_new_env(ENVELOPE *outgoing, char **fccp, char ***tobufpp, PINEFIELD *custom
*p = *(p+4);
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;
@@ -1738,9 +1746,9 @@ call_mailer(METAENV *header, struct mail_bodystruct *body, char **alt_smtp_serve
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;
BODY *origBody = body;
@@ -1893,20 +1901,49 @@ call_mailer(METAENV *header, struct mail_bodystruct *body, char **alt_smtp_serve
* OK, who posts what? We tried an mta_handoff above, but there
* was either none specified or we decided not to use it. So,
* if there's an smtp-server defined anywhere,
+ * First we check for rules and make a list using the rules.
*/
- if(alt_smtp_servers && alt_smtp_servers[0] && alt_smtp_servers[0][0]){
- /*---------- SMTP ----------*/
- dprint((4, "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);
+ 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, j;
+
+ added_rules = 0;
+ smtp_list = (char **) fs_get ((num_rules + 1)*sizeof(char*));
+ for (i = 0, j = 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_COMPOSE, header->env);
+ if(rule_result && *rule_result){
+ smtp_list[j++] = cpystr(rule_result);
+ added_rules++;
+ }
+ }
+ }
+ }
+
+ if (added_rules < 0){
+ smtp_list = (char **) fs_get (sizeof(char*));
+ added_rules = 0;
}
- else if(ps_global->VAR_SMTP_SERVER && ps_global->VAR_SMTP_SERVER[0]
- && ps_global->VAR_SMTP_SERVER[0][0]){
- /*---------- SMTP ----------*/
- dprint((4, "call_mailer: via TCP\n"));
- TIME_STAMP("smtp-open start (tcp)", 1);
- sending_stream = smtp_open(ps_global->VAR_SMTP_SERVER, smtp_opts);
+ 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, "call_mailer: via TCP (%s)\n",smtp_list[0]));
+ TIME_STAMP("smtp-open start (tcp)", 1);
+ sending_stream = smtp_open(choice == 3 ? smtp_list
+ : (choice == 2 ? alt_smtp_servers
+ : ps_global->VAR_SMTP_SERVER), smtp_opts);
}
else if((postcmd = smtp_command(ps_global->c_client_error, sizeof(ps_global->c_client_error))) != NULL){
char *cmdlist[2];
@@ -2142,6 +2179,8 @@ call_mailer(METAENV *header, struct mail_bodystruct *body, char **alt_smtp_serve
if(error_mess){
q_status_message(SM_ORDER | SM_DING, 4, 7, error_mess);
dprint((1, "call_mailer ERROR: %s\n", error_mess));
+ if (ps_global->send_immediately)
+ printf("%s\n",error_mess);
}
return(-1);
diff --git a/pith/send.h b/pith/send.h
index 69d763fc..ee3245e5 100644
--- a/pith/send.h
+++ b/pith/send.h
@@ -159,6 +159,8 @@ struct local_message_copy {
unsigned text_written:1;
};
+#define CAN_EDIT(x) (!((x)->never_allow_changing_from) && \
+ F_ON(F_ALLOW_CHANGING_FROM, (x)))
#define TONAME "To"
#define CCNAME "cc"
diff --git a/pith/sort.c b/pith/sort.c
index 68a9c10c..4d75012f 100644
--- a/pith/sort.c
+++ b/pith/sort.c
@@ -30,7 +30,7 @@ static char rcsid[] = "$Id: sort.c 1142 2008-08-13 17:22:21Z hubert@u.washington
#include "../pith/signal.h"
#include "../pith/busy.h"
#include "../pith/icache.h"
-
+#include "../pith/rules.h"
/*
* global place to store mail_sort and mail_thread results
@@ -91,7 +91,7 @@ Args: msgmap --
----*/
void
sort_folder(MAILSTREAM *stream, MSGNO_S *msgmap, SortOrder new_sort,
- int new_rev, unsigned int flags)
+ int new_rev, unsigned int flags, int first)
{
long raw_current, i, j;
unsigned long *sort = NULL;
@@ -101,6 +101,15 @@ sort_folder(MAILSTREAM *stream, MSGNO_S *msgmap, SortOrder new_sort,
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, "Sorting by %s%s\n",
sort_name(new_sort), new_rev ? "/reverse" : ""));
@@ -530,20 +539,20 @@ percent_sorted(void)
* argument also means arrival/reverse.
*/
int
-decode_sort(char *sort_spec, SortOrder *def_sort, int *def_sort_rev)
+decode_sort(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);
}
@@ -572,7 +581,7 @@ decode_sort(char *sort_spec, SortOrder *def_sort, int *def_sort_rev)
if(ps_global->sort_types[x] == EndofList)
return(-1);
- *def_sort = ps_global->sort_types[x];
+ *def_sort = ps_global->sort_types[x];
*def_sort_rev = reverse;
return(0);
}
@@ -686,10 +695,26 @@ reset_sort_order(unsigned int flags)
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_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)){
@@ -702,9 +727,52 @@ reset_sort_order(unsigned int flags)
&& 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(the_sort_order == SortThread && !(flags & SRT_MAN))
+ 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);
}
+
+SortOrder translate(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;
+}
+
diff --git a/pith/sort.h b/pith/sort.h
index ce383a04..2dfcde71 100644
--- a/pith/sort.h
+++ b/pith/sort.h
@@ -22,7 +22,7 @@
#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)
struct global_sort_data {
MSGNO_S *msgmap;
@@ -41,9 +41,9 @@ extern struct global_sort_data g_sort;
/* exported protoypes */
char *sort_name(SortOrder);
-void sort_folder(MAILSTREAM *, MSGNO_S *, SortOrder, int, unsigned);
-int decode_sort(char *, SortOrder *, int *);
+void sort_folder(MAILSTREAM *, MSGNO_S *, SortOrder, int, unsigned, int);
+int decode_sort(char *, SortOrder *, int *, int);
void reset_sort_order(unsigned);
-
+SortOrder translate(char *, int);
#endif /* PITH_SORT_INCLUDED */
diff --git a/pith/state.c b/pith/state.c
index fd2b4f71..6d1d8455 100644
--- a/pith/state.c
+++ b/pith/state.c
@@ -33,7 +33,7 @@ static char rcsid[] = "$Id: state.c 1074 2008-06-04 00:08:43Z hubert@u.washingto
#include "../pith/remote.h"
#include "../pith/list.h"
#include "../pith/smime.h"
-
+#include "../pith/rules.h"
/*
* Globals referenced throughout pine...
@@ -74,6 +74,7 @@ new_pine_struct(void)
p = (struct pine *)fs_get(sizeof (struct pine));
memset((void *) p, 0, sizeof(struct pine));
+ p->thread_def_sort = SortDate;
p->def_sort = SortArrival;
p->sort_types[0] = SortSubject;
p->sort_types[1] = SortArrival;
@@ -116,6 +117,9 @@ free_pine_struct(struct pine **pps)
if(!(pps && (*pps)))
return;
+ if((*pps)->subject != NULL)
+ fs_give((void **)&(*pps)->subject);
+
if((*pps)->hostname != NULL)
fs_give((void **)&(*pps)->hostname);
@@ -131,6 +135,9 @@ free_pine_struct(struct pine **pps)
if((*pps)->folders_dir != NULL)
fs_give((void **)&(*pps)->folders_dir);
+ if((*pps)->paterror == 0)
+ regfree(&(*pps)->colorpat);
+
if((*pps)->ui.homedir)
fs_give((void **)&(*pps)->ui.homedir);
@@ -192,6 +199,8 @@ free_pine_struct(struct pine **pps)
if((*pps)->kw_colors)
free_spec_colors(&(*pps)->kw_colors);
+ free_allowed_qstr();
+
if((*pps)->atmts){
int i;
@@ -206,6 +215,9 @@ free_pine_struct(struct pine **pps)
if((*pps)->msgmap)
msgno_give(&(*pps)->msgmap);
+ if((*pps)->rule_list)
+ free_parsed_rule_list(&(*pps)->rule_list);
+
free_vars(*pps);
fs_give((void **) pps);
diff --git a/pith/state.h b/pith/state.h
index 47e97ce4..6dbdd025 100644
--- a/pith/state.h
+++ b/pith/state.h
@@ -33,7 +33,7 @@
#include "../pith/stream.h"
#include "../pith/color.h"
#include "../pith/user.h"
-
+#include "../pith/rulestype.h"
/*
* Printing control structure
@@ -105,6 +105,11 @@ struct pine {
MAILSTREAM *mail_stream; /* ptr to current folder stream */
MSGNO_S *msgmap; /* ptr to current message map */
+ char screen_name[10]; /* name of current screen */
+ char *role; /* role used when composing */
+ char *procid; /* procedure id when needed */
+ int exiting;
+
unsigned read_predicted:1;
char cur_folder[MAXPATH+1];
@@ -137,6 +142,8 @@ struct pine {
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;
@@ -244,10 +251,23 @@ struct pine {
SPEC_COLOR_S *hdr_colors; /* list of configed colors for view */
SPEC_COLOR_S *index_token_colors; /* list of configed colors for index */
+ char *prefix; /* prefix for fillpara */
+ char **list_qstr; /* list of known quote strings */
short init_context;
+ struct {
+ ACTION_S *role_chosen;
+ int attach;
+ int strip;
+ int no_send_flowed;
+ int inchdr;
+ } reply;
+
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 */
@@ -285,6 +305,9 @@ struct pine {
EditWhich ew_for_srch_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 preserve;
@@ -301,10 +324,16 @@ struct pine {
int nmw_width;
+ char *subject;
+ int send_immediately;
+ int failed_read;
+
int hours_to_timeout;
int tcp_query_timeout;
+ int sleep; /* time in seconds to sleep before removing temp file */
+
int inc_check_timeout;
int inc_check_interval; /* for local and IMAP */
int inc_second_check_interval; /* for other */
@@ -323,6 +352,8 @@ struct pine {
char *display_charmap; /* needs to be freed */
char *keyboard_charmap; /* needs to be freed */
void *input_cs;
+ regex_t colorpat;
+ int paterror;
char *posting_charmap; /* needs to be freed */
@@ -334,6 +365,7 @@ struct pine {
struct {
char *(*display_filter)(char *, STORE_S *, gf_io_t, FILTLIST_S *);
char *(*display_filter_trigger)(BODY *, char *, size_t);
+ char *(*exec_rule)(char *, gf_io_t, gf_io_t);
} tools;
KEYWORD_S *keywords;
@@ -344,6 +376,9 @@ struct pine {
char last_error[500];
INIT_ERR_S *init_errs;
+ PRULELIST_S *rule_list;
+ char *pressed_key;
+
PRINT_S *print;
#ifdef SMIME
diff --git a/pith/store.c b/pith/store.c
index e8508257..58154c53 100644
--- a/pith/store.c
+++ b/pith/store.c
@@ -171,6 +171,14 @@ so_get(SourceType source, char *name, int rtype)
if(source == TmpFileStar)
our_unlink(so->name);
+ if (ps_global->send_immediately){
+ ps_global->failed_read++;
+ if(ps_global->failed_read == 5){
+ printf("No configurationf file found. Where is your .pinerc file?\n");
+ exit(1);
+ }
+ }
+
fs_give((void **)&so->name);
fs_give((void **)&so); /* so freed & set to NULL */
}
diff --git a/pith/string.c b/pith/string.c
index 84717c3e..2cd43d7d 100644
--- a/pith/string.c
+++ b/pith/string.c
@@ -20,6 +20,7 @@ static char rcsid[] = "$Id: string.c 910 2008-01-14 22:28:38Z hubert@u.washingto
string.c
Misc extra and useful string functions
- rplstr replace a substring with another string
+ - collspaces consecutive spaces are reduced to one space.
- sqzspaces Squeeze out the extra blanks in a string
- sqznewlines Squeeze out \n and \r.
- removing_trailing_white_space
@@ -132,6 +133,31 @@ rplstr(char *os, size_t oslen, int dl, char *is)
return(x3);
}
+/*----------------------------------------------------------------------
+ collapse blank space
+ ----------------------------------------------------------------------*/
+void
+collspaces(char *string)
+{
+ char *p = string;
+ int only_one_space = 0;
+
+ if(!string)
+ return;
+
+ for(;isspace(*p); p++);
+
+ while(*string = *p++)
+ if(!isspace((unsigned char)*string)){
+ only_one_space = 0;
+ string++;
+ }
+ else if(!only_one_space){
+ string++;
+ only_one_space++;
+ }
+ *string = '\0';
+}
/*----------------------------------------------------------------------
@@ -2860,3 +2886,35 @@ free_strlist(STRLIST_S **strp)
fs_give((void **) strp);
}
}
+
+
+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 --git a/pith/string.h b/pith/string.h
index 11c4d45f..e6ee6497 100644
--- a/pith/string.h
+++ b/pith/string.h
@@ -86,12 +86,14 @@ struct date {
/* exported protoypes */
char *rplstr(char *, size_t, int, char *);
+void collspaces(char *);
void sqzspaces(char *);
void sqznewlines(char *);
void removing_leading_white_space(char *);
void removing_trailing_white_space(char *);
void removing_leading_and_trailing_white_space(char *);
int removing_double_quotes(char *);
+void removing_extra_stuff (char *);
char *skip_white_space(char *);
char *skip_to_white_space(char *);
char *removing_quotes(char *);
diff --git a/pith/text.c b/pith/text.c
index 5de53e51..2857ddad 100644
--- a/pith/text.c
+++ b/pith/text.c
@@ -92,7 +92,7 @@ decode_text(ATTACH_S *att,
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, doraw = RAWSTRING;
int is_delsp_yes = 0;
int filt_only_c0 = 0;
char *parmval;
@@ -171,6 +171,15 @@ decode_text(ATTACH_S *att,
gf_url_hilite_opt(&uh,handlesp,0));
}
+ 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.
@@ -180,7 +189,7 @@ decode_text(ATTACH_S *att,
&& pico_usingcolor()
&& VAR_SIGNATURE_FORE_COLOR
&& VAR_SIGNATURE_BACK_COLOR){
- filters[filtcnt].filter = gf_line_test;
+ filters[filtcnt].filter = gf_quote_test;
filters[filtcnt++].data = gf_line_test_opt(color_signature,
&is_in_sig);
}
@@ -198,9 +207,9 @@ decode_text(ATTACH_S *att,
&& 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")){
@@ -281,6 +290,11 @@ decode_text(ATTACH_S *att,
}
}
+ if (add_me){
+ filters[filtcnt].filter = gf_quote_test;
+ filters[filtcnt++].data = gf_line_test_opt(select_quote, &doraw);
+ }
+
/*
* If the message is not flowed, we do the quote suppression before
* the wrapping, because the wrapping does not preserve the quote
@@ -305,7 +319,7 @@ decode_text(ATTACH_S *att,
dq.handlesp = handlesp;
dq.do_color = (!(flags & FM_NOCOLOR) && pico_usingcolor());
- filters[filtcnt].filter = gf_line_test;
+ filters[filtcnt].filter = gf_quote_test;
filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq);
}
if(ps_global->VAR_QUOTE_REPLACE_STRING
@@ -364,7 +378,7 @@ decode_text(ATTACH_S *att,
dq.handlesp = handlesp;
dq.do_color = (!(flags & FM_NOCOLOR) && pico_usingcolor());
- filters[filtcnt].filter = gf_line_test;
+ filters[filtcnt].filter = gf_quote_test;
filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq);
}
@@ -569,7 +583,7 @@ delete_quotes(long int linenum, char *line, LT_INS_S **ins, void *local)
{
DELQ_S *dq;
char *lp;
- int i, lines, not_a_quote = 0;
+ int i, lines, not_a_quote = 0, code;
size_t len;
dq = (DELQ_S *) local;
@@ -589,6 +603,8 @@ delete_quotes(long int linenum, char *line, LT_INS_S **ins, void *local)
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
@@ -628,13 +644,12 @@ delete_quotes(long int linenum, char *line, LT_INS_S **ins, void *local)
}
}
- /* 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 != '>')
+ len = lp - line;
+ if(strlen(tmp_20k_buf) > len)
+ strcpy(tmp_20k_buf, tmp_20k_buf+len);
+ code = (dq->is_flowed ? IS_FLOWED : NO_FLOWED) | DELETEQUO;
+ select_quote(linenum, lp, ins, &code);
+ if (!not_a_quote && !tmp_20k_buf[0])
not_a_quote++;
if(not_a_quote){
diff --git a/pith/thread.c b/pith/thread.c
index ff9bff54..fc0e32b3 100644
--- a/pith/thread.c
+++ b/pith/thread.c
@@ -30,12 +30,18 @@ static char rcsid[] = "$Id: thread.c 942 2008-03-04 18:21:33Z hubert@u.washingto
#include "../pith/mailcmd.h"
#include "../pith/ablookup.h"
+static int erase_thread_info = 1;
+
+typedef struct sizethread_t {
+ int count;
+ long pos;
+} SIZETHREAD_T;
/*
* Internal prototypes
*/
long *sort_thread_flatten(THREADNODE *, MAILSTREAM *, long *,
- char *, long, PINETHRD_S *, unsigned);
+ char *, long, PINETHRD_S *, unsigned, int, long, long);
void make_thrdflags_consistent(MAILSTREAM *, MSGNO_S *, PINETHRD_S *, int);
THREADNODE *collapse_threadnode_tree(THREADNODE *);
THREADNODE *collapse_threadnode_tree_sorted(THREADNODE *);
@@ -43,6 +49,7 @@ THREADNODE *sort_threads_and_collapse(THREADNODE *);
THREADNODE *insert_tree_in_place(THREADNODE *, THREADNODE *);
unsigned long branch_greatest_num(THREADNODE *, int);
long calculate_visible_threads(MAILSTREAM *);
+int pine_compare_size_thread(const qsort_t *, const qsort_t *);
PINETHRD_S *
@@ -95,20 +102,22 @@ void
set_flags_for_thread(MAILSTREAM *stream, MSGNO_S *msgmap, int f, PINETHRD_S *thrd, 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);
}
@@ -122,7 +131,7 @@ erase_threading_info(MAILSTREAM *stream, MSGNO_S *msgmap)
MESSAGECACHE *mc;
PINELT_S *peltp;
- if(!(stream && stream->spare))
+ if(!(stream && stream->spare) || !erase_thread_info)
return;
ps_global->view_skipped_index = 0;
@@ -155,7 +164,7 @@ sort_thread_callback(MAILSTREAM *stream, THREADNODE *tree)
PINETHRD_S *thrd = NULL;
unsigned long msgno, rawno;
int un_view_thread = 0;
- long raw_current;
+ long raw_current, branch;
char *dup_chk = NULL;
@@ -168,10 +177,11 @@ sort_thread_callback(MAILSTREAM *stream, THREADNODE *tree)
* way. If the dummy node is at the top-level, then its children are
* promoted to the top-level as separate threads.
*/
- if(F_ON(F_THREAD_SORTS_BY_ARRIVAL, ps_global))
- collapsed_tree = collapse_threadnode_tree_sorted(tree);
- else
- collapsed_tree = collapse_threadnode_tree(tree);
+ collapsed_tree = F_ON(F_ENHANCED_THREAD, ps_global)
+ ? copy_tree(tree)
+ : (F_ON(F_THREAD_SORTS_BY_ARRIVAL, ps_global)
+ ? collapse_threadnode_tree_sorted(tree)
+ : collapse_threadnode_tree(tree));
/* dup_chk is like sort with an origin of 1 */
dup_chk = (char *) fs_get((mn_get_nmsgs(g_sort.msgmap)+1) * sizeof(char));
@@ -182,7 +192,7 @@ sort_thread_callback(MAILSTREAM *stream, THREADNODE *tree)
(void) sort_thread_flatten(collapsed_tree, stream,
&g_sort.msgmap->sort[1],
dup_chk, mn_get_nmsgs(g_sort.msgmap),
- NULL, THD_TOP);
+ NULL, THD_TOP, 0, 1L, 0L);
/* reset the inverse array */
msgno_reset_isort(g_sort.msgmap);
@@ -340,12 +350,14 @@ sort_thread_callback(MAILSTREAM *stream, THREADNODE *tree)
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;
@@ -359,9 +371,10 @@ sort_thread_callback(MAILSTREAM *stream, THREADNODE *tree)
MN_COLL));
}
- if(thrd->nextthd)
- thrd = fetch_thread(stream, thrd->nextthd);
- else
+ while (thrd && top_thread(stream, thrd->rawno) == top
+ && thrd->nextthd)
+ thrd = fetch_thread(stream, thrd->nextthd);
+ if (!(thrd && thrd->nextthd))
thrd = NULL;
}
}
@@ -412,7 +425,7 @@ make_thrdflags_consistent(MAILSTREAM *stream, MSGNO_S *msgmap, PINETHRD_S *thrd,
int a_parent_is_collapsed)
{
PINETHRD_S *nthrd, *bthrd;
- unsigned long msgno;
+ unsigned long msgno, next, branch;
if(!thrd)
return;
@@ -430,8 +443,8 @@ make_thrdflags_consistent(MAILSTREAM *stream, MSGNO_S *msgmap, PINETHRD_S *thrd,
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
@@ -440,8 +453,8 @@ make_thrdflags_consistent(MAILSTREAM *stream, MSGNO_S *msgmap, PINETHRD_S *thrd,
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);
@@ -488,9 +501,10 @@ calculate_visible_threads(MAILSTREAM *stream)
long *
sort_thread_flatten(THREADNODE *node, MAILSTREAM *stream,
long *entry, char *dup_chk, long maxno,
- PINETHRD_S *thrd, unsigned int flags)
+ PINETHRD_S *thrd, unsigned int flags,
+ int adopted, long top, long threadno)
{
- PINETHRD_S *newthrd = NULL;
+ PINETHRD_S *newthrd = NULL, *save_thread = NULL;
if(node){
if(node->num > 0L && node->num <= maxno){ /* holes happen */
@@ -498,6 +512,9 @@ sort_thread_flatten(THREADNODE *node, MAILSTREAM *stream,
*entry = node->num;
dup_chk[node->num] = 1;
+ if(adopted == 2)
+ top = node->num;
+
/*
* Build a richer threading structure that will help us paint
* and operate on threads and subthreads.
@@ -506,20 +523,51 @@ sort_thread_flatten(THREADNODE *node, MAILSTREAM *stream,
if(newthrd){
entry++;
+ if(adopted == 2)
+ threadno = newthrd->thrdno;
+ if(adopted){
+ newthrd->toploose = top;
+ newthrd->thrdno = threadno;
+ }
+ adopted = adopted ? 1 : 0;
if(node->next)
entry = sort_thread_flatten(node->next, stream,
entry, dup_chk, maxno,
- newthrd, THD_NEXT);
+ newthrd, THD_NEXT, adopted, top, threadno);
if(node->branch)
entry = sort_thread_flatten(node->branch, stream,
entry, dup_chk, maxno,
newthrd,
- (flags == THD_TOP) ? THD_TOP
- : THD_BRANCH);
+ ((flags == THD_TOP) ? THD_TOP
+ : THD_BRANCH),
+ adopted, top, threadno);
}
}
}
+ else{
+ adopted = 2;
+ if(node->next)
+ entry = sort_thread_flatten(node->next, stream, entry, dup_chk,
+ maxno, thrd, THD_TOP, adopted, top, threadno);
+ adopted = 0;
+ if(node->branch){
+ if(entry){
+ long *last_entry = entry;
+
+ do{
+ last_entry--;
+ save_thread = ((PINELT_S *)mail_elt(stream, *last_entry)->sparep)->pthrd;
+ } while (save_thread->parent != 0L);
+ entry = sort_thread_flatten(node->branch, stream, entry, dup_chk,
+ maxno, save_thread, (flags == THD_TOP ? THD_TOP : THD_BRANCH),
+ adopted, top, threadno);
+ }
+ else
+ entry = sort_thread_flatten(node->branch, stream, entry, dup_chk,
+ maxno, NULL, THD_TOP, adopted, top, threadno);
+ }
+ }
}
return(entry);
@@ -788,7 +836,7 @@ msgno_thread_info(MAILSTREAM *stream, long unsigned int rawno,
*/
void
collapse_or_expand(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap,
- long unsigned int msgno)
+ long unsigned int msgno, int display)
{
int collapsed, adjust_current = 0;
PINETHRD_S *thrd = NULL, *nthrd;
@@ -841,7 +889,7 @@ collapse_or_expand(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap,
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);
@@ -859,13 +907,13 @@ collapse_or_expand(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap,
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)) != NULL)
+ if((thrd->next) && ((nthrd = fetch_thread(stream, thrd->next)) != NULL))
set_thread_subtree(stream, nthrd, msgmap, 1, MN_CHID);
clear_index_cache_ent(stream, msgno, 0);
}
}
- else
+ else if(display)
q_status_message(SM_ORDER, 0, 1,
_("No thread to collapse or expand on this line"));
@@ -952,18 +1000,19 @@ count_flags_in_thread(MAILSTREAM *stream, PINETHRD_S *thrd, long int flags)
unsigned long 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);
}
@@ -1051,20 +1100,21 @@ int
mark_msgs_in_thread(MAILSTREAM *stream, PINETHRD_S *thrd, 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);
}
@@ -1098,7 +1148,7 @@ set_thread_lflags(MAILSTREAM *stream, PINETHRD_S *thrd, MSGNO_S *msgmap, int fla
/* flags to set or clear */
/* set or clear? */
{
- unsigned long msgno;
+ unsigned long msgno, next, branch;
PINETHRD_S *nthrd, *bthrd;
if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
@@ -1122,14 +1172,14 @@ set_thread_lflags(MAILSTREAM *stream, PINETHRD_S *thrd, MSGNO_S *msgmap, int fla
if(msgno > 0L && flags == MN_CHID2 && v == 1)
clear_index_cache_ent(stream, msgno, 0);
- 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);
}
@@ -1210,7 +1260,8 @@ status_symbol_for_thread(MAILSTREAM *stream, PINETHRD_S *thrd, IndexColType type
/*
* Symbol is * if some message in thread is important,
* + if some message is to us,
- * - if mark-for-cc and some message is cc to us, else blank.
+ * - if mark-for-cc and some message is cc to us,
+ * . if mark-for-group and some message is to us in a group, else blank.
*/
char
to_us_symbol_for_thread(MAILSTREAM *stream, PINETHRD_S *thrd, int consider_flagged)
@@ -1218,45 +1269,48 @@ to_us_symbol_for_thread(MAILSTREAM *stream, PINETHRD_S *thrd, int consider_flagg
char to_us = ' ';
char branch_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(((consider_flagged && to_us != '*') || (!consider_flagged && to_us != '+'))
- && thrd->branch){
+ && (branch = get_branch(stream, thrd))){
bthrd = fetch_thread(stream, thrd->branch);
if(bthrd)
branch_to_us = to_us_symbol_for_thread(stream, bthrd, consider_flagged);
/* use branch to_us symbol if it has higher priority than what we have so far */
if(to_us == ' '){
- if(branch_to_us == '-' || branch_to_us == '+' || branch_to_us == '*')
+ if(branch_to_us == '-' || branch_to_us == '+'
+ || branch_to_us == '.' || branch_to_us == '*')
to_us = branch_to_us;
}
else if(to_us == '-'){
- if(branch_to_us == '+' || branch_to_us == '*')
+ if(branch_to_us == '+' || branch_to_us == '.' || branch_to_us == '*')
to_us = branch_to_us;
}
- else if(to_us == '+'){
+ else if(to_us == '+' || to_us == '.'){
if(branch_to_us == '*')
to_us = branch_to_us;
}
}
- if((consider_flagged && to_us != '*') || (!consider_flagged && to_us != '+')){
+ if((consider_flagged && to_us != '*')
+ || (!consider_flagged && to_us != '+' && to_us != '.')){
if(consider_flagged && thrd && thrd->rawno > 0L
&& stream && thrd->rawno <= stream->nmsgs
&& (mc = mail_elt(stream, thrd->rawno))
&& FLAG_MATCH(F_FLAG, mc, stream))
to_us = '*';
- else if(to_us != '+' && !IS_NEWS(stream)){
+ else if(to_us != '+' && to_us != '.' && !IS_NEWS(stream)){
INDEXDATA_S idata;
MESSAGECACHE *mc;
ADDRESS *addr;
@@ -1280,7 +1334,7 @@ to_us_symbol_for_thread(MAILSTREAM *stream, PINETHRD_S *thrd, int consider_flagg
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))
@@ -1328,7 +1382,8 @@ set_thread_subtree(MAILSTREAM *stream, PINETHRD_S *thrd, MSGNO_S *msgmap, int v,
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);
@@ -1368,8 +1423,8 @@ view_thread(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, int set_lfl
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;
@@ -1433,7 +1488,7 @@ unview_thread(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap)
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;
@@ -1539,6 +1594,7 @@ void
set_search_bit_for_thread(MAILSTREAM *stream, PINETHRD_S *thrd, SEARCHSET **msgset)
{
PINETHRD_S *nthrd, *bthrd;
+ unsigned long next, branch;
if(!(stream && thrd))
return;
@@ -1547,15 +1603,622 @@ set_search_bit_for_thread(MAILSTREAM *stream, PINETHRD_S *thrd, SEARCHSET **msgs
&& (!(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);
}
}
+
+/*
+ * Make a copy of c-client's THREAD tree
+ */
+THREADNODE *
+copy_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);
+}
+
+long
+top_thread(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(MAILSTREAM *stream, MSGNO_S *msgmap, long rawmsgno)
+{
+ mn_set_cur(msgmap,mn_raw2m(msgmap, top_thread(stream, rawmsgno)));
+}
+
+long
+top_this_thread(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(MAILSTREAM *stream, MSGNO_S *msgmap, long rawmsgno)
+{
+ mn_set_cur(msgmap,mn_raw2m(msgmap, top_this_thread(stream, rawmsgno)));
+}
+
+int
+thread_is_kolapsed(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(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;
+}
+
+/*
+ * This function assumes that it is called at a top of a thread in its
+ * first call
+ */
+
+int
+count_this_thread(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(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;
+}
+
+unsigned long
+get_branch(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(MAILSTREAM *stream, PINETHRD_S *thrd)
+{
+ return thrd->next;
+}
+
+long
+get_length_branch(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;
+}
+
+int pine_compare_size_thread(const qsort_t *a, const qsort_t *b)
+{
+ SIZETHREAD_T *s = (SIZETHREAD_T *) a, *t = (SIZETHREAD_T *) b;
+
+ return s->count == t->count ? s->pos - t->pos : s->count - t->count;
+}
+
+
+
+void
+find_msgmap(MAILSTREAM *stream, MSGNO_S *msgmap, int flags, SortOrder ordersort, unsigned is_rev)
+{
+ long *old_arrival,*new_arrival;
+ long init_thread, end_thread, current;
+ long i, j, k;
+ long tmsg, ntmsg, nthreads;
+ SIZETHREAD_T *l;
+ PINETHRD_S *thrd;
+
+ erase_thread_info = 0;
+ current = mn_m2raw(msgmap, mn_get_cur(msgmap));
+
+ switch(ordersort){
+ case SortSize:
+ sort_folder(stream, msgmap, SortThread, 0, SRT_VRB, 0);
+ tmsg = mn_get_total(msgmap) + 1;
+
+ if(tmsg <= 1)
+ return;
+
+ for (i= 1L, k = 0L; i <= mn_get_total(msgmap); i += count_thread(ps_global, stream, msgmap, msgmap->sort[i]), k++);
+ l = (SIZETHREAD_T *) fs_get(k*sizeof(SIZETHREAD_T));
+ for (j = 0L, i=1L; j < k && i<= mn_get_total(msgmap); ){
+ l[j].count = count_thread(ps_global, stream, msgmap, msgmap->sort[i]);
+ l[j].pos = i;
+ i += l[j].count;
+ j++;
+ }
+ qsort((void *)l, (size_t) k, sizeof(SIZETHREAD_T), pine_compare_size_thread);
+ old_arrival = (long *) fs_get(tmsg * sizeof(long));
+ for(i = 1L, j = 0; j < k; j++){ /* copy thread of length .count */
+ int p;
+ for(p = 0; p < l[j].count; p++)
+ old_arrival[i++] = msgmap->sort[l[j].pos + p];
+ }
+ fs_give((void **)&l);
+ break;
+ default:
+ sort_folder(stream, msgmap, ordersort, 0, SRT_VRB, 0);
+ tmsg = mn_get_total(msgmap) + 1;
+
+ if (tmsg <= 1)
+ return;
+
+ old_arrival = (long *) fs_get(tmsg * sizeof(long));
+ for (i= 1L;(i <= mn_get_total(msgmap)) && (old_arrival[i] = msgmap->sort[i]); i++);
+ /* sort by thread */
+ sort_folder(stream, msgmap, SortThread, 0, SRT_VRB, 0);
+ break;
+
+ }
+
+ 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);
+ /* we copy from the bottom, the last one to be filled is new_arrival[1] */
+ while (new_arrival[1] == 0){
+ int done = 0;
+ long n;
+
+ init_thread = top_thread(stream, old_arrival[i]);
+ thrd = fetch_thread(stream, init_thread);
+ for (n = mn_get_total(msgmap); new_arrival[n] != 0 && !done; n--)
+ done = (new_arrival[n] == init_thread);
+ if (!done){
+ 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;
+ for(k = 1L; k <= j; k++)
+ new_arrival[tmsg - k] = msgmap->sort[end_thread - 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(stream, 0);
+}
+
+void
+move_thread(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(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
+move_next_this_thread(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(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(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;
+}
+
+/* add more keys to this list */
+int
+allowed_thread_key(SortOrder sort)
+{
+ return sort == SortArrival || sort == SortDate
+ || sort == SortScore || sort == SortThread
+ || sort == SortSize;
+}
+
diff --git a/pith/thread.h b/pith/thread.h
index 40b09bb0..4c5f1a97 100644
--- a/pith/thread.h
+++ b/pith/thread.h
@@ -37,6 +37,7 @@ typedef struct pine_thrd {
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;
@@ -92,7 +93,7 @@ void erase_threading_info(MAILSTREAM *, MSGNO_S *);
void sort_thread_callback(MAILSTREAM *, THREADNODE *);
void collapse_threads(MAILSTREAM *, MSGNO_S *, PINETHRD_S *);
PINETHRD_S *msgno_thread_info(MAILSTREAM *, unsigned long, PINETHRD_S *, unsigned);
-void collapse_or_expand(struct pine *, MAILSTREAM *, MSGNO_S *, unsigned long);
+void collapse_or_expand(struct pine *, MAILSTREAM *, MSGNO_S *, unsigned long, int);
void select_thread_stmp(struct pine *, MAILSTREAM *, MSGNO_S *);
unsigned long count_flags_in_thread(MAILSTREAM *, PINETHRD_S *, long);
unsigned long count_lflags_in_thread(MAILSTREAM *, PINETHRD_S *, MSGNO_S *, int);
@@ -106,6 +107,24 @@ int view_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int);
int unview_thread(struct pine *, MAILSTREAM *, MSGNO_S *);
PINETHRD_S *find_thread_by_number(MAILSTREAM *, MSGNO_S *, long, PINETHRD_S *);
void set_search_bit_for_thread(MAILSTREAM *, PINETHRD_S *, SEARCHSET **);
-
+void find_msgmap(MAILSTREAM *, MSGNO_S *, int, SortOrder, unsigned);
+void move_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int);
+void relink_threads(MAILSTREAM *, MSGNO_S *, long *);
+long top_thread(MAILSTREAM *, long);
+long top_this_thread(MAILSTREAM *, long);
+long get_length_branch(MAILSTREAM *, long);
+unsigned long get_next(MAILSTREAM *,PINETHRD_S *);
+unsigned long get_branch(MAILSTREAM *,PINETHRD_S *);
+int count_thread(struct pine *, MAILSTREAM *, MSGNO_S *, long);
+int count_this_thread(MAILSTREAM *, unsigned long);
+int this_thread_is_kolapsed(struct pine *, MAILSTREAM *, MSGNO_S *, long);
+int thread_is_kolapsed(struct pine *, MAILSTREAM *, MSGNO_S *, long);
+int move_prev_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int);
+int move_next_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int);
+int move_next_this_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int);
+void move_top_thread(MAILSTREAM *, MSGNO_S *, long);
+void move_top_this_thread(MAILSTREAM *, MSGNO_S *, long);
+THREADNODE *copy_tree(THREADNODE *);
+int allowed_thread_key(SortOrder sort);
#endif /* PITH_THREAD_INCLUDED */
diff --git a/pith/url.c b/pith/url.c
index 173cb879..114c60bf 100644
--- a/pith/url.c
+++ b/pith/url.c
@@ -53,7 +53,7 @@ char *
rfc1738_scan(char *line, int *len)
{
char *colon, *start, *end;
- int n;
+ int n, delim;
/* process each : in the line */
for(; (colon = strindex(line, ':')) != NULL; line = end){
@@ -137,6 +137,7 @@ rfc1738_scan(char *line, int *len)
if(i != j){
*len = end - start;
+ delim = start > line && *(start - 1) == '<';
/*
* Special case handling for comma.
@@ -146,8 +147,8 @@ rfc1738_scan(char *line, int *len)
* In most cases any way, that's why we have the
* exception.
*/
- if(*(end - 1) == ','
- || (*(end - 1) == '.' && (!*end || *end == ' ')))
+ if(delim == 0 && (*(end - 1) == ','
+ || (*(end - 1) == '.' && (!*end || *end == ' '))))
(*len)--;
if(*len - (colon - start) > 0)