diff -rc alpine-2.00/alpine/adrbkcmd.c alpine-2.00.I.USE/alpine/adrbkcmd.c
*** alpine-2.00/alpine/adrbkcmd.c	2008-05-30 09:52:41.000000000 -0700
--- alpine-2.00.I.USE/alpine/adrbkcmd.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 57,62 ****
--- 57,64 ----
  #include "../pith/send.h"
  #include "../pith/list.h"
  #include "../pith/busy.h"
+ #include "../pith/icache.h"
+ #include "../pith/osdep/color.h"
  
  
  /* internal prototypes */
***************
*** 1146,1151 ****
--- 1148,1155 ----
  	  q_status_message1(SM_INFO, 0, 2, _("Address book %s cancelled"), cmd);
      }
      else if(editor_result & COMP_EXIT){
+ 	if(pico_usingcolor())
+ 	   clear_index_cache(ps_global->mail_stream, 0);
  	removing_leading_and_trailing_white_space(nick);
  	removing_leading_and_trailing_white_space(full);
  	removing_leading_and_trailing_white_space(fcc);
***************
*** 4123,4128 ****
--- 4127,4134 ----
  	 * won't do anything, but will cause compose_mail to think there's
  	 * already a role so that it won't try to confirm the default.
  	 */
+ 	if (ps_global->role)
+ 	   fs_give((void **)&ps_global->role);
  	if(role)
  	  role = copy_action(role);
  	else{
***************
*** 4130,4135 ****
--- 4136,4142 ----
  	    memset((void *)role, 0, sizeof(*role));
  	    role->nick = cpystr("Default Role");
  	}
+ 	ps_global->role = cpystr(role->nick);
      }
  
      compose_mail(addr, fcc, role, NULL, NULL);
diff -rc alpine-2.00/alpine/alpine.c alpine-2.00.I.USE/alpine/alpine.c
*** alpine-2.00/alpine/alpine.c	2008-06-03 15:31:05.000000000 -0700
--- alpine-2.00.I.USE/alpine/alpine.c	2011-02-07 20:33:45.000000000 -0800
***************
*** 193,198 ****
--- 193,199 ----
  #endif
  
      status_message_lock_init();
+     inverse_itokens();
  
  #if	HAVE_SRANDOM
      /*
***************
*** 293,298 ****
--- 294,300 ----
  	exit(-1);
      }
  
+     mail_parameters(NULL, SET_QUOTA, (void *) pine_parse_quota);
      /* set some default timeouts in case pinerc is remote */
      mail_parameters(NULL, SET_OPENTIMEOUT, (void *)(long)30);
      mail_parameters(NULL, SET_READTIMEOUT, (void *)(long)15);
***************
*** 303,308 ****
--- 305,311 ----
      mail_parameters(NULL, SET_SENDCOMMAND, (void *) pine_imap_cmd_happened);
      mail_parameters(NULL, SET_FREESTREAMSPAREP, (void *) sp_free_callback);
      mail_parameters(NULL, SET_FREEELTSPAREP,    (void *) free_pine_elt);
+     mail_parameters(NULL, SET_ERASEPASSWORD, (void *) pine_delete_pwd);
  #ifdef	SMIME
      mail_parameters(NULL, SET_FREEBODYSPAREP,   (void *) free_smime_body_sparep);
  #endif
***************
*** 454,459 ****
--- 457,467 ----
  
      convert_args_to_utf8(pine_state, &args);
  
+     if (args.action == aaFolder && !args.data.folder &&
+ 		ps_global->send_immediately){
+ 	printf(_("No value for To: field specified\n"));
+ 	exit(-1);
+     }
      if(args.action == aaFolder){
  	pine_state->beginning_of_month = first_run_of_month();
  	pine_state->beginning_of_year = first_run_of_year();
***************
*** 462,467 ****
--- 470,476 ----
      /* Set up optional for user-defined display filtering */
      pine_state->tools.display_filter	     = dfilter;
      pine_state->tools.display_filter_trigger = dfilter_trigger;
+     pine_state->tools.exec_rule		     = exec_function_rule;
  
  #ifdef _WINDOWS
      if(ps_global->install_flag){
***************
*** 553,558 ****
--- 562,572 ----
      if(F_ON(F_MAILDROPS_PRESERVE_STATE, ps_global))
        mail_parameters(NULL, SET_SNARFPRESERVE, (void *) TRUE);
  
+ #ifndef _WINDOWS
+     mail_parameters(NULL,SET_COURIERSTYLE,
+                (void *)(F_ON(F_COURIER_FOLDER_LIST, ps_global) ? 1 : 0));
+ #endif
+ 
      rvl = 0L;
      if(pine_state->VAR_NNTPRANGE){
  	if(!SVAR_NNTPRANGE(pine_state, rvl, tmp_20k_buf, SIZEOF_20KBUF))
***************
*** 672,677 ****
--- 686,692 ----
          
  
      /*--- output side ---*/
+     if (!ps_global->send_immediately){
      rv = config_screen(&(pine_state->ttyo));
  #ifndef _WINDOWS	/* always succeeds under _WINDOWS */
      if(rv){
***************
*** 712,723 ****
      /* initialize titlebar in case we use it */
      set_titlebar("", NULL, NULL, NULL, NULL, 0, FolderName, 0, 0, NULL);
  
-     /*
-      * Prep storage object driver for PicoText 
-      */
-     so_register_external_driver(pine_pico_get, pine_pico_give, pine_pico_writec, pine_pico_readc, 
- 				pine_pico_puts, pine_pico_seek, NULL, NULL);
- 
  #ifdef	DEBUG
      if(ps_global->debug_imap > 4 || debug > 9){
  	q_status_message(SM_ORDER | SM_DING, 5, 9,
--- 727,732 ----
***************
*** 725,730 ****
--- 734,752 ----
  	flush_status_messages(0);
      }
  #endif
+     }
+     else{
+      fake_config_screen(&(pine_state->ttyo));
+      init_folders(pine_state);		/* digest folder spec's */
+     }
+ 
+     /*
+      * Prep storage object driver for PicoText 
+      */
+     so_register_external_driver(pine_pico_get, pine_pico_give, 
+ 	(args.noutf8 == 0 ? pine_pico_writec : pine_pico_writec_noucs), 
+ 	(args.noutf8 == 0 ? pine_pico_readc : pine_pico_readc_noucs), 
+ 	(args.noutf8 == 0 ? pine_pico_puts : pine_pico_puts_noucs), pine_pico_seek, NULL, NULL);
  
      if(args.action == aaPrcCopy || args.action == aaAbookCopy){
  	int   exit_val = -1;
***************
*** 900,905 ****
--- 922,933 ----
          int	    len, good_addr = 1;
  	int	    exit_val = 0;
  	BUILDER_ARG fcc;
+         ACTION_S  *role = NULL;
+ 
+         if (pine_state->in_init_seq && pine_state->send_immediately
+ 		&&  (char) *pine_state->initial_cmds++ == '#'
+ 		&&  ++pine_state->initial_cmds_offset)
+             role_select_screen(pine_state, &role, 1);
  
  	if(pine_state->in_init_seq){
  	    pine_state->in_init_seq = pine_state->save_in_init_seq = 0;
***************
*** 938,944 ****
  	  memset(&fcc, 0, sizeof(fcc));
  
  	if(good_addr){
! 	    compose_mail(addr, fcc.tptr, NULL,
  			 args.data.mail.attachlist, stdin_getc);
  	}
  	else{
--- 966,972 ----
  	  memset(&fcc, 0, sizeof(fcc));
  
  	if(good_addr){
! 	    compose_mail(addr, fcc.tptr, role,
  			 args.data.mail.attachlist, stdin_getc);
  	}
  	else{
***************
*** 972,977 ****
--- 1000,1006 ----
              
          pine_state->mail_stream    = NULL;
          pine_state->mangled_screen = 1;
+         pine_state->subject        = NULL;
  
  	if(args.action == aaURL){
  	    url_tool_t f;
***************
*** 1087,1092 ****
--- 1116,1122 ----
  	    }
          }
  
+        if (!pine_state->send_immediately)
          fflush(stdout);
  
  #if !defined(_WINDOWS) && !defined(LEAVEOUTFIFO)
***************
*** 2975,2984 ****
      if(i > 0){
  	ps->initial_cmds = (int *)fs_get((i+1) * sizeof(int));
  	ps->free_initial_cmds = ps->initial_cmds;
  	for(j = 0; j < i; j++)
! 	  ps->initial_cmds[j] = i_cmds[j];
! 
! 	ps->initial_cmds[i] = 0;
  	ps->in_init_seq = ps->save_in_init_seq = 1;
      }
  }
--- 3005,3019 ----
      if(i > 0){
  	ps->initial_cmds = (int *)fs_get((i+1) * sizeof(int));
  	ps->free_initial_cmds = ps->initial_cmds;
+ 	ps->initial_cmds_backup = (int *)fs_get((i+1) * sizeof(int));
+ 	ps->free_initial_cmds_backup = ps->initial_cmds_backup;
  	for(j = 0; j < i; j++)
! 	  ps->initial_cmds[j] = ps->initial_cmds_backup[j] = i_cmds[j];
! #define ctrl_x 24
!       if (i > 1)
! 	ps->send_immediately = i_cmds[i - 2] == ctrl_x
! 			&& ((i_cmds[i - 1] == 'y') || (i_cmds[i-1] == 'Y'));
! 	ps->initial_cmds[i] = ps->initial_cmds_backup[i] = 0;
  	ps->in_init_seq = ps->save_in_init_seq = 1;
      }
  }
***************
*** 3134,3139 ****
--- 3169,3177 ----
      extern KBESC_T *kbesc;
  
      dprint((2, "goodnight_gracey:\n"));    
+     strncpy(pine_state->cur_folder, pine_state->inbox_name, 
+ 					sizeof(pine_state->cur_folder));
+     pine_state->cur_folder[sizeof(pine_state->cur_folder) - 1] = '\0';
  
      /* We want to do this here before we close up the streams */
      trim_remote_adrbks();
diff -rc alpine-2.00/alpine/arg.c alpine-2.00.I.USE/alpine/arg.c
*** alpine-2.00/alpine/arg.c	2008-01-04 14:49:15.000000000 -0800
--- alpine-2.00.I.USE/alpine/arg.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 59,64 ****
--- 59,65 ----
  static char args_err_non_abs_passfile[] =	N_("argument to \"-passfile\" should be fully-qualified");
  #endif
  static char args_err_missing_sort[] =		N_("missing argument for option \"-sort\"");
+ static char args_err_missing_thread_sort[] =	N_("missing argument for option \"-threadsort\"");
  static char args_err_missing_flag_arg[] =	N_("missing argument for flag \"%c\"");
  static char args_err_missing_flag_num[] =	N_("Non numeric argument for flag \"%c\"");
  static char args_err_missing_debug_num[] =	N_("Non numeric argument for \"%s\"");
***************
*** 102,112 ****
--- 103,115 ----
  N_(" -z \t\tSuspend - allow use of ^Z suspension"),
  N_(" -r \t\tRestricted - can only send mail to oneself"),
  N_(" -sort <sort>\tSort - Specify sort order of folder:"),
+ N_(" -threadsort <sort>\tSort - Specify sort order of thread index screen:"),
  N_("\t\t\tarrival, subject, threaded, orderedsubject, date,"),
  N_("\t\t\tfrom, size, score, to, cc, /reverse"),
  N_(" -i\t\tIndex - Go directly to index, bypassing main menu"),
  N_(" -I <keystroke_list>   Initial keystrokes to be executed"),
  N_(" -n <number>\tEntry in index to begin on"),
+ N_(" -noutf8\t Warns Alpine that piped input is not encoded in utf-8"),
  N_(" -o \t\tReadOnly - Open first folder read-only"),
  N_(" -conf\t\tConfiguration - Print out fresh global configuration. The"),
  N_("\t\tvalues of your global configuration affect all Alpine users"),
***************
*** 191,196 ****
--- 194,200 ----
      char *cmd_list            = NULL;
      char *debug_str           = NULL;
      char *sort                = NULL;
+     char *threadsort          = NULL;
      char *pinerc_file         = NULL;
      char *lc		      = NULL;
      int   do_help             = 0;
***************
*** 362,367 ****
--- 366,382 ----
  
  		  goto Loop;
  	      }
+ 	      else if(strcmp(*av, "threadsort") == 0){
+ 	            if(--ac){
+ 	                threadsort = *++av;
+ 	                COM_THREAD_SORT_KEY = cpystr(threadsort);
+ 	            }
+ 	            else{
+ 	                display_args_err(_(args_err_missing_thread_sort), NULL, 1);
+ 	              ++usage;
+ 	          }
+ 	          goto Loop;
+ 	      }
  	      else if(strcmp(*av, "url") == 0){
  		  if(args->action == aaFolder && !args->data.folder){
  		      args->action = aaURL;
***************
*** 468,473 ****
--- 483,492 ----
  
  		  goto Loop;
  	      }
+ 	      else if(strcmp(*av, "noutf8") == 0){
+ 		  args->noutf8++;
+ 		  goto Loop;
+ 	      }
  	      else if(strcmp(*av, "bail") == 0){
  		  pine_state->exit_if_no_pinerc = 1;
  		  goto Loop;
***************
*** 476,481 ****
--- 495,506 ----
  		  do_version = 1;
  		  goto Loop;
  	      }
+               else if(strcmp(*av, "subject") == 0){
+                      if(--ac){
+                         pine_state->subject = cpystr(*++av);
+                         }
+                         goto Loop;
+               }
  #ifdef	_WINDOWS
  	      else if(strcmp(*av, "install") == 0){
  		  pine_state->install_flag = 1;
***************
*** 826,839 ****
        exit(-1);
  
      if(do_version){
! 	extern char datestamp[], hoststamp[];
  	char rev[128];
  
! 	snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Alpine %s (%s %s) built %s on %s",
  		 ALPINE_VERSION,
  		 SYSTYPE ? SYSTYPE : "?",
  		 get_alpine_revision_string(rev, sizeof(rev)),
! 		 datestamp, hoststamp);
  	tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
  	display_args_err(tmp_20k_buf, NULL, 0);
  	exit(0);
--- 851,864 ----
        exit(-1);
  
      if(do_version){
! 	extern char datestamp[], hoststamp[], plevstamp[];
  	char rev[128];
  
! 	snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Alpine %s (%s %s) built %s on %s, using patchlevel %s.",
  		 ALPINE_VERSION,
  		 SYSTYPE ? SYSTYPE : "?",
  		 get_alpine_revision_string(rev, sizeof(rev)),
! 		 datestamp, hoststamp, plevstamp);
  	tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
  	display_args_err(tmp_20k_buf, NULL, 0);
  	exit(0);
diff -rc alpine-2.00/alpine/arg.h alpine-2.00.I.USE/alpine/arg.h
*** alpine-2.00/alpine/arg.h	2006-09-22 13:06:05.000000000 -0700
--- alpine-2.00.I.USE/alpine/arg.h	2011-02-07 20:33:45.000000000 -0800
***************
*** 27,32 ****
--- 27,33 ----
  typedef struct argdata {
      enum	{aaFolder = 0, aaMore, aaURL, aaMail,
  		 aaPrcCopy, aaAbookCopy} action;
+     int	noutf8;
      union {
  	char	  *folder;
  	char	  *file;
diff -rc alpine-2.00/alpine/busy.c alpine-2.00.I.USE/alpine/busy.c
*** alpine-2.00/alpine/busy.c	2007-10-15 14:02:56.000000000 -0700
--- alpine-2.00.I.USE/alpine/busy.c	2011-02-07 20:33:42.000000000 -0800
***************
*** 194,200 ****
  
  	    add_review_message(buf, -1);
  	}
! 	else{
  	    q_status_message(SM_ORDER, 0, 1, progress);
  
  	    /*
--- 194,200 ----
  
  	    add_review_message(buf, -1);
  	}
! 	else if (!ps_global->send_immediately){
  	    q_status_message(SM_ORDER, 0, 1, progress);
  
  	    /*
***************
*** 206,213 ****
  	     */
  	    display_message('x');
  	}
! 	
! 	fflush(stdout);
      }
  
      /*
--- 206,213 ----
  	     */
  	    display_message('x');
  	}
! 	if (!ps_global->send_immediately)   
! 	  fflush(stdout);
      }
  
      /*
***************
*** 255,261 ****
      (*ap)->cf	 = done_busy_cue;
      ap		 = &(*ap)->next;
  
!     start_after(a);		/* launch cue handler */
  
  #ifdef _WINDOWS
      mswin_setcursor(MSWIN_CURSOR_BUSY);
--- 255,262 ----
      (*ap)->cf	 = done_busy_cue;
      ap		 = &(*ap)->next;
  
!     if(!ps_global->send_immediately)
!        start_after(a);		/* launch cue handler */
  
  #ifdef _WINDOWS
      mswin_setcursor(MSWIN_CURSOR_BUSY);
***************
*** 404,409 ****
--- 405,415 ----
  {
      int space_left, slots_used;
  
+     if (ps_global->send_immediately){
+ 	mark_status_dirty();
+ 	return;
+     }
+ 
      if(final_message && final_message_pri >= 0){
  	char progress[MAX_SCREEN_COLS+1];
  
diff -rc alpine-2.00/alpine/colorconf.c alpine-2.00.I.USE/alpine/colorconf.c
*** alpine-2.00/alpine/colorconf.c	2008-02-08 10:39:55.000000000 -0800
--- alpine-2.00.I.USE/alpine/colorconf.c	2011-02-07 20:33:45.000000000 -0800
***************
*** 28,33 ****
--- 28,34 ----
  #include "../pith/color.h"
  #include "../pith/icache.h"
  #include "../pith/mailcmd.h"
+ #include "../pith/mailindx.h"
  #include "../pith/list.h"
  
  
***************
*** 39,45 ****
  SAVED_CONFIG_S *save_color_config_vars(struct pine *);
  void	        free_saved_color_config(struct pine *, SAVED_CONFIG_S **);
  void	        color_config_init_display(struct pine *, CONF_S **, CONF_S **);
! void	        add_header_color_line(struct pine *, CONF_S **, char *, int);
  int     	is_rgb_color(char *);
  char	       *new_color_line(char *, int, int, int);
  int	        color_text_tool(struct pine *, int, CONF_S **, unsigned);
--- 40,46 ----
  SAVED_CONFIG_S *save_color_config_vars(struct pine *);
  void	        free_saved_color_config(struct pine *, SAVED_CONFIG_S **);
  void	        color_config_init_display(struct pine *, CONF_S **, CONF_S **);
! void	        add_header_color_line(struct pine *, CONF_S **, char *, int, int);
  int     	is_rgb_color(char *);
  char	       *new_color_line(char *, int, int, int);
  int	        color_text_tool(struct pine *, int, CONF_S **, unsigned);
***************
*** 141,147 ****
      if((v && v->name &&
          srchstr(v->name, "-foreground-color") &&
  	pvalfg && pvalfg[0] && pvalbg && pvalbg[0]) ||
!        (v == &ps->vars[V_VIEW_HDR_COLORS] || v == &ps->vars[V_KW_COLORS]))
        ret = SAMP1;
  
      return(ret);
--- 142,149 ----
      if((v && v->name &&
          srchstr(v->name, "-foreground-color") &&
  	pvalfg && pvalfg[0] && pvalbg && pvalbg[0]) ||
!        (v == &ps->vars[V_INDEX_TOKEN_COLORS] ||
!         v == &ps->vars[V_VIEW_HDR_COLORS] || v == &ps->vars[V_KW_COLORS]))
        ret = SAMP1;
  
      return(ret);
***************
*** 486,491 ****
--- 488,513 ----
      }
  
      /*
+      * custom index tokens colors
+      */
+     vtmp = &ps->vars[V_INDEX_TOKEN_COLORS];
+     lval = LVAL(vtmp, ew);
+ 
+     if(lval && lval[0] && lval[0][0]){
+ 	for(i = 0; lval && lval[i]; i++)
+ 	  add_header_color_line(ps, ctmp, lval[i], i, V_INDEX_TOKEN_COLORS);
+     }
+     else{
+ 	new_confline(ctmp);		/* Blank line */
+ 	(*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
+ 	new_confline(ctmp);
+ 	(*ctmp)->help			 = NO_HELP;
+ 	(*ctmp)->flags			|= CF_NOSELECT;
+ 	(*ctmp)->value = cpystr(_(ADDINDEXTOKEN_COMMENT));
+ 	(*ctmp)->valoffset		 = COLOR_INDENT;
+     }
+ 
+     /*
       * custom header colors
       */
      new_confline(ctmp);		/* Blank line */
***************
*** 497,503 ****
      new_confline(ctmp);
      (*ctmp)->help			 = NO_HELP;
      (*ctmp)->flags			|= CF_NOSELECT;
!     (*ctmp)->value = cpystr(_("HEADER COLORS"));
      new_confline(ctmp);
      (*ctmp)->help			 = NO_HELP;
      (*ctmp)->flags			|= CF_NOSELECT;
--- 519,525 ----
      new_confline(ctmp);
      (*ctmp)->help			 = NO_HELP;
      (*ctmp)->flags			|= CF_NOSELECT;
!     (*ctmp)->value = cpystr(_(HDR_COLORS));
      new_confline(ctmp);
      (*ctmp)->help			 = NO_HELP;
      (*ctmp)->flags			|= CF_NOSELECT;
***************
*** 526,532 ****
  
      if(lval && lval[0] && lval[0][0]){
  	for(i = 0; lval && lval[i]; i++)
! 	  add_header_color_line(ps, ctmp, lval[i], i);
      }
      else{
  	new_confline(ctmp);		/* Blank line */
--- 548,554 ----
  
      if(lval && lval[0] && lval[0][0]){
  	for(i = 0; lval && lval[i]; i++)
! 	  add_header_color_line(ps, ctmp, lval[i], i, V_VIEW_HDR_COLORS);
      }
      else{
  	new_confline(ctmp);		/* Blank line */
***************
*** 696,701 ****
--- 718,724 ----
      char **lval, *ret = "";
  
      if(var == &ps_global->vars[V_VIEW_HDR_COLORS]
+        || var == &ps_global->vars[V_INDEX_TOKEN_COLORS]
         || var == &ps_global->vars[V_KW_COLORS]){
  	norm    = (LVAL(var, Main) != NULL);
  	exc     = (LVAL(var, ps_global->ew_for_except_vars) != NULL);
***************
*** 722,736 ****
  
  
  void
! add_header_color_line(struct pine *ps, CONF_S **ctmp, char *val, int which)
  {
      struct variable *vtmp;
      SPEC_COLOR_S     *hc;
      char	     tmp[100+1];
      int              l;
  
!     vtmp = &ps->vars[V_VIEW_HDR_COLORS];
!     l = strlen(HEADER_WORD);
  
      /* Blank line */
      new_confline(ctmp);
--- 745,765 ----
  
  
  void
! add_header_color_line(struct pine *ps, CONF_S **ctmp, char *val, int which, int varnum)
  {
      struct variable *vtmp;
      SPEC_COLOR_S     *hc;
      char	     tmp[100+1];
      int              l;
  
!     hc = spec_color_from_var(val, 0);
!     if(varnum == V_INDEX_TOKEN_COLORS){
! 	if(hc == NULL || hc->spec == NULL 
! 		|| itoktype(hc->spec, FOR_INDEX) == NULL)
! 	return;
!     }
!     vtmp = &ps->vars[varnum];
!     l = strlen(varnum == V_VIEW_HDR_COLORS ? HEADER_WORD : TOKEN_WORD);
  
      /* Blank line */
      new_confline(ctmp);
***************
*** 748,754 ****
      /* which is an index into the variable list */
      (*ctmp)->varmem		 = CFC_SET_COLOR(which, 0);
  
-     hc = spec_color_from_var(val, 0);
      if(hc && hc->inherit)
        (*ctmp)->flags = (CF_NOSELECT | CF_INHERIT);
      else{
--- 777,782 ----
***************
*** 759,765 ****
  	 * with all this. It probably doesn't happen in real life.
  	 */
  	utf8_snprintf(tmp, sizeof(tmp), "%s%c%.*w Color%*w %s%s",
! 		HEADER_WORD,
  		(hc && hc->spec) ? (islower((unsigned char)hc->spec[0])
  					    ? toupper((unsigned char)hc->spec[0])
  					    : hc->spec[0]) : '?',
--- 787,793 ----
  	 * with all this. It probably doesn't happen in real life.
  	 */
  	utf8_snprintf(tmp, sizeof(tmp), "%s%c%.*w Color%*w %s%s",
! 		(varnum == V_VIEW_HDR_COLORS ? HEADER_WORD : TOKEN_WORD),
  		(hc && hc->spec) ? (islower((unsigned char)hc->spec[0])
  					    ? toupper((unsigned char)hc->spec[0])
  					    : hc->spec[0]) : '?',
***************
*** 1139,1144 ****
--- 1167,1173 ----
        return(var && var->name &&
  	     (srchstr(var->name, "-foreground-color") ||
  	      srchstr(var->name, "-background-color") ||
+ 	      var == &ps->vars[V_INDEX_TOKEN_COLORS] ||
  	      var == &ps->vars[V_VIEW_HDR_COLORS] ||
  	      var == &ps->vars[V_KW_COLORS]));
  }
***************
*** 1395,1400 ****
--- 1424,1430 ----
  	if(hcolors)
  	  free_spec_colors(&hcolors);
  
+ 	fix_side_effects(ps, (*cl)->var, 0);
  	set_current_color_vals(ps);
  	ClearScreen();
  	rv = ps->mangled_screen = 1;
***************
*** 1803,1808 ****
--- 1833,1839 ----
  	/* get rid of all user set colors */
  	for(v = ps->vars; v->name; v++){
  	    if(!color_holding_var(ps, v)
+ 	       || v == &ps->vars[V_INDEX_TOKEN_COLORS]
  	       || v == &ps->vars[V_VIEW_HDR_COLORS]
  	       || v == &ps->vars[V_KW_COLORS])
  	      continue;
***************
*** 1856,1861 ****
--- 1887,1930 ----
  	      free_spec_colors(&hcolors);
  	}
  
+ 	/* same for index token colors */
+ 	alval = ALVAL(&ps->vars[V_INDEX_TOKEN_COLORS], ew);
+ 	if(alval && *alval){
+ 	    SPEC_COLOR_S *global_hcolors = NULL, *hcg;
+ 
+ 	    v = &ps->vars[V_INDEX_TOKEN_COLORS];
+ 	    if(v->global_val.l && v->global_val.l[0])
+ 	      global_hcolors = spec_colors_from_varlist(v->global_val.l, 0);
+ 
+ 	    hcolors = spec_colors_from_varlist(*alval, 0);
+ 	    for(hc = hcolors; hc; hc = hc->next){
+ 		if(hc->fg)
+ 		  fs_give((void **)&hc->fg);
+ 		if(hc->bg)
+ 		  fs_give((void **)&hc->bg);
+ 
+ 		for(hcg = global_hcolors; hcg; hcg = hcg->next){
+ 		    if(hc->spec && hcg->spec && !strucmp(hc->spec, hcg->spec)){
+ 			hc->fg = hcg->fg;
+ 			hcg->fg = NULL;
+ 			hc->bg = hcg->bg;
+ 			hcg->bg = NULL;
+ 			if(hc->val && !hcg->val)
+ 			  fs_give((void **) &hc->val);
+ 		    }
+ 		}
+ 
+ 		if(global_hcolors)
+ 		  free_spec_colors(&global_hcolors);
+ 	    }
+ 
+ 	    free_list_array(alval);
+ 	    *alval = varlist_from_spec_colors(hcolors);
+ 
+ 	    if(hcolors)
+ 	      free_spec_colors(&hcolors);
+ 	}
+ 
  	/*
  	 * Same for keyword colors.
  	 */
***************
*** 1898,1912 ****
  	rv = 1;
  	break;
  
        case MC_ADD :				/* add custom header color */
  	/* get header field name */
  	help = NO_HELP;
  	while(1){
  	    i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, sizeof(sval),
! 			     _("Enter the name of the header field to be added: "),
  				 NULL, help, NULL);
! 	    if(i == 0)
  	      break;
  	    else if(i == 1){
  		cmd_cancelled("Add");
  		cancel = 1;
--- 1967,1989 ----
  	rv = 1;
  	break;
  
+       case MC_ADDHEADER:			/* add custom index token color */
        case MC_ADD :				/* add custom header color */
  	/* get header field name */
  	help = NO_HELP;
  	while(1){
  	    i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, sizeof(sval),
! 		(cmd == MC_ADD ? _("Enter the name of the header field to be added: ")
! 			       : _("Enter the name of the index token to be added: ")),
  				 NULL, help, NULL);
! 	    if(i == 0){
! 	      if(cmd == MC_ADDHEADER && itoktype(sval, FOR_INDEX) == NULL){
! 		q_status_message1(SM_ORDER, 1, 3,
! 			 _("token \"%s\" not recognized"), sval);
! 		continue;
! 	      }
  	      break;
+ 	    }
  	    else if(i == 1){
  		cmd_cancelled("Add");
  		cancel = 1;
***************
*** 1937,1943 ****
  	confline = var_from_spec_color(new_hcolor);
  
  	/* add it to end of list */
! 	alval = ALVAL(&ps->vars[V_VIEW_HDR_COLORS], ew);
  	if(alval){
  	    /* get rid of possible empty value first */
  	    if((t = *alval) && t[0] && !t[0][0] && !(t+1)[0])
--- 2014,2020 ----
  	confline = var_from_spec_color(new_hcolor);
  
  	/* add it to end of list */
! 	alval = ALVAL(&ps->vars[(cmd == MC_ADD ? V_VIEW_HDR_COLORS : V_INDEX_TOKEN_COLORS)], ew);
  	if(alval){
  	    /* get rid of possible empty value first */
  	    if((t = *alval) && t[0] && !t[0][0] && !(t+1)[0])
***************
*** 1962,1968 ****
  	  ;
  
  	/* back up to the KEYWORD COLORS title line */
! 	for(; ctmp && (!ctmp->value || strcmp(ctmp->value, KW_COLORS_HDR))
  	      && ctmp->prev;
  	    ctmp = prev_confline(ctmp))
  	  ;
--- 2039,2045 ----
  	  ;
  
  	/* back up to the KEYWORD COLORS title line */
! 	for(; ctmp && (!ctmp->value || strcmp(ctmp->value, (cmd == MC_ADD ? KW_COLORS_HDR : HDR_COLORS)))
  	      && ctmp->prev;
  	    ctmp = prev_confline(ctmp))
  	  ;
***************
*** 2000,2006 ****
  	    free_conflines(&beg);
  	}
  
! 	add_header_color_line(ps, cl, confline, i);
  
  	/* be sure current is on selectable line */
  	for(; *cl && ((*cl)->flags & CF_NOSELECT); *cl = next_confline(*cl))
--- 2077,2084 ----
  	    free_conflines(&beg);
  	}
  
! 	add_header_color_line(ps, cl, confline, i, cmd == MC_ADD 
! 					? V_VIEW_HDR_COLORS : V_INDEX_TOKEN_COLORS);
  
  	/* be sure current is on selectable line */
  	for(; *cl && ((*cl)->flags & CF_NOSELECT); *cl = next_confline(*cl))
***************
*** 2012,2024 ****
  	break;
  
        case MC_DELETE :				/* delete custom header color */
! 	if((*cl)->var != &ps->vars[V_VIEW_HDR_COLORS]){
  	    q_status_message(SM_ORDER, 0, 2,
  			     _("Can't delete this color setting"));
  	    break;
  	}
  
! 	if(want_to(_("Really delete header color from config"),
  		   'y', 'n', NO_HELP, WT_NORM) != 'y'){
  	    cmd_cancelled("Delete");
  	    return(rv);
--- 2090,2105 ----
  	break;
  
        case MC_DELETE :				/* delete custom header color */
! 	if((*cl)->var != &ps->vars[V_VIEW_HDR_COLORS]
! 		&& (*cl)->var != &ps->vars[V_INDEX_TOKEN_COLORS]){
  	    q_status_message(SM_ORDER, 0, 2,
  			     _("Can't delete this color setting"));
  	    break;
  	}
  
! 	if(want_to(((*cl)->var == &ps->vars[V_VIEW_HDR_COLORS]
! 		? _("Really delete header color from config")
! 		: _("Really delete index token color from config")),
  		   'y', 'n', NO_HELP, WT_NORM) != 'y'){
  	    cmd_cancelled("Delete");
  	    return(rv);
***************
*** 2054,2072 ****
  	another = 0;
  	/* reset current line */
  	if(end && end->next && end->next->next && 
! 	   end->next->next->var == &ps->vars[V_VIEW_HDR_COLORS]){
  	    *cl = end->next->next;		/* next Header Color */
  	    another++;
  	}
  	else if(beg && beg->prev &&
! 	   beg->prev->var == &ps->vars[V_VIEW_HDR_COLORS]){
  	    *cl = beg->prev;			/* prev Header Color */
  	    another++;
  	}
  
  	/* adjust SPEC_COLOR_S index (varmem) values */
  	for(ctmp = end; ctmp; ctmp = next_confline(ctmp))
! 	  if(ctmp->var == &ps->vars[V_VIEW_HDR_COLORS])
  	    ctmp->varmem = CFC_ICUST_DEC(ctmp);
  	
  	/*
--- 2135,2156 ----
  	another = 0;
  	/* reset current line */
  	if(end && end->next && end->next->next && 
! 	   end->next->next->var == &ps->vars[(*cl)->var == &ps->vars[V_VIEW_HDR_COLORS] 
! 					? V_VIEW_HDR_COLORS : V_INDEX_TOKEN_COLORS]){
  	    *cl = end->next->next;		/* next Header Color */
  	    another++;
  	}
  	else if(beg && beg->prev &&
! 	   beg->prev->var == &ps->vars[(*cl)->var == &ps->vars[V_VIEW_HDR_COLORS]
! 					? V_VIEW_HDR_COLORS : V_INDEX_TOKEN_COLORS]){
  	    *cl = beg->prev;			/* prev Header Color */
  	    another++;
  	}
  
  	/* adjust SPEC_COLOR_S index (varmem) values */
  	for(ctmp = end; ctmp; ctmp = next_confline(ctmp))
! 	  if(ctmp->var == &ps->vars[(*cl)->var == &ps->vars[V_VIEW_HDR_COLORS] 
! 				? V_VIEW_HDR_COLORS : V_INDEX_TOKEN_COLORS])
  	    ctmp->varmem = CFC_ICUST_DEC(ctmp);
  	
  	/*
***************
*** 2098,2104 ****
  
  	    end->flags     = CF_NOSELECT;
  	    end->help      = NO_HELP;
! 	    end->value     = cpystr(_(ADDHEADER_COMMENT));
  	    end->valoffset = COLOR_INDENT;
  	    end->varnamep  = NULL;
  	    end->varmem    = 0;
--- 2182,2189 ----
  
  	    end->flags     = CF_NOSELECT;
  	    end->help      = NO_HELP;
! 	    end->value     = cpystr((*cl)->var == &ps->vars[V_VIEW_HDR_COLORS] 
! 				? _(ADDHEADER_COMMENT) : _(ADDINDEXTOKEN_COMMENT));
  	    end->valoffset = COLOR_INDENT;
  	    end->varnamep  = NULL;
  	    end->varmem    = 0;
***************
*** 2556,2562 ****
      OPT_SCREEN_S     screen, *saved_screen;
      CONF_S          *ctmp = NULL, *first_line = NULL, *ctmpb;
      int              rv, is_index = 0, is_hdrcolor = 0, indent = 12;
!     int              is_general = 0, is_keywordcol = 0;
      char             tmp[1200+1], name[1200], *p;
      struct variable *vtmp, v;
      int              i, def;
--- 2641,2647 ----
      OPT_SCREEN_S     screen, *saved_screen;
      CONF_S          *ctmp = NULL, *first_line = NULL, *ctmpb;
      int              rv, is_index = 0, is_hdrcolor = 0, indent = 12;
!     int              is_general = 0, is_keywordcol = 0, is_idxtokcol = 0;
      char             tmp[1200+1], name[1200], *p;
      struct variable *vtmp, v;
      int              i, def;
***************
*** 2567,2572 ****
--- 2652,2659 ----
      vtmp = (*cl)->var;
      if(vtmp == &ps->vars[V_VIEW_HDR_COLORS])
        is_hdrcolor++;
+     else if(vtmp == &ps->vars[V_INDEX_TOKEN_COLORS])
+       is_idxtokcol++;
      else if(vtmp == &ps->vars[V_KW_COLORS])
        is_keywordcol++;
      else if(color_holding_var(ps, vtmp)){
***************
*** 2618,2623 ****
--- 2705,2728 ----
  	      name[i] = toupper((unsigned char) name[i]);
  	}
      }
+     else if(is_idxtokcol){
+ 	char **lval;
+ 	
+ 	lval = LVAL(vtmp, ew);
+ 	hcolors = spec_colors_from_varlist(lval, 0);
+ 
+ 	for(hc = hcolors, i = 0; hc; hc = hc->next, i++)
+ 	  if(CFC_ICUST(*cl) == i)
+ 	    break;
+ 	
+ 	if(hc){
+ 	    snprintf(name, sizeof(name), "%s%s", TOKEN_WORD, hc->spec);
+ 	    name[sizeof(name)-1] = '\0';
+ 	    i = sizeof(TOKEN_WORD) - 1;
+ 	    if(islower((unsigned char) name[i]))
+ 	      name[i] = toupper((unsigned char) name[i]);
+ 	}
+     }
      else if(is_keywordcol){
  	char **lval;
  
***************
*** 2663,2669 ****
      ctmp->flags			|= (CF_STARTITEM | CF_NOSELECT);
      ctmp->keymenu		 = &color_changing_keymenu;
  
!     if(is_hdrcolor){
  	char **apval;
  
  	def = !(hc && hc->fg && hc->fg[0] && hc->bg && hc->bg[0]);
--- 2768,2774 ----
      ctmp->flags			|= (CF_STARTITEM | CF_NOSELECT);
      ctmp->keymenu		 = &color_changing_keymenu;
  
!     if(is_hdrcolor || is_idxtokcol){
  	char **apval;
  
  	def = !(hc && hc->fg && hc->fg[0] && hc->bg && hc->bg[0]);
diff -rc alpine-2.00/alpine/colorconf.h alpine-2.00.I.USE/alpine/colorconf.h
*** alpine-2.00/alpine/colorconf.h	2007-08-16 15:25:10.000000000 -0700
--- alpine-2.00.I.USE/alpine/colorconf.h	2011-02-07 20:33:45.000000000 -0800
***************
*** 23,30 ****
--- 23,33 ----
  
  
  #define HEADER_WORD "Header "
+ #define TOKEN_WORD "Index Token "
  #define KW_COLORS_HDR "KEYWORD COLORS"
+ #define HDR_COLORS "HEADER COLORS"
  #define ADDHEADER_COMMENT N_("[ Use the AddHeader command to add colored headers in MESSAGE TEXT screen ]")
+ #define ADDINDEXTOKEN_COMMENT N_("[ Use the IndxHdr command to add colored tokens in MESSAGE INDEX screen ]")
  #define EQ_COL 37
  
  #define SPACE_BETWEEN_DOUBLEVARS 3
diff -rc alpine-2.00/alpine/confscroll.c alpine-2.00.I.USE/alpine/confscroll.c
*** alpine-2.00/alpine/confscroll.c	2008-08-21 15:14:45.000000000 -0700
--- alpine-2.00.I.USE/alpine/confscroll.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 50,55 ****
--- 50,56 ----
  #include "../pith/tempfile.h"
  #include "../pith/pattern.h"
  #include "../pith/charconv/utf8.h"
+ #include "../pith/rules.h"
  
  
  #define	CONFIG_SCREEN_HELP_TITLE	_("HELP FOR SETUP CONFIGURATION")
***************
*** 138,144 ****
  char    *radio_pretty_value(struct pine *, CONF_S *);
  char    *sigfile_pretty_value(struct pine *, CONF_S *);
  char    *color_pretty_value(struct pine *, CONF_S *);
! char    *sort_pretty_value(struct pine *, CONF_S *);
  int      longest_feature_name(void);
  COLOR_PAIR *sample_color(struct pine *, struct variable *);
  COLOR_PAIR *sampleexc_color(struct pine *, struct variable *);
--- 139,145 ----
  char    *radio_pretty_value(struct pine *, CONF_S *);
  char    *sigfile_pretty_value(struct pine *, CONF_S *);
  char    *color_pretty_value(struct pine *, CONF_S *);
! char    *sort_pretty_value(struct pine *, CONF_S *, int);
  int      longest_feature_name(void);
  COLOR_PAIR *sample_color(struct pine *, struct variable *);
  COLOR_PAIR *sampleexc_color(struct pine *, struct variable *);
***************
*** 286,292 ****
      CONF_S *ctmp;
  
      if(!(cl && *cl &&
!        ((*cl)->var == &ps->vars[V_SORT_KEY] ||
          standard_radio_var(ps, (*cl)->var) ||
  	(*cl)->var == startup_ptr)))
        return;
--- 287,294 ----
      CONF_S *ctmp;
  
      if(!(cl && *cl &&
!         (((*cl)->var == &ps->vars[V_SORT_KEY]) || 
!         ((*cl)->var == &ps->vars[V_THREAD_SORT_KEY]) ||
          standard_radio_var(ps, (*cl)->var) ||
  	(*cl)->var == startup_ptr)))
        return;
***************
*** 462,468 ****
      char	  tmp[MAXPATH+1];
      char         *utf8str;
      UCS           ch = 'x';
!     int		  cmd, i, j, done = 0, changes = 0;
      int		  retval = 0;
      int		  km_popped = 0, stay_in_col = 0;
      struct	  key_menu  *km = NULL;
--- 464,470 ----
      char	  tmp[MAXPATH+1];
      char         *utf8str;
      UCS           ch = 'x';
!     int		  cmd, i, j, k = 1, done = 0, changes = 0;
      int		  retval = 0;
      int		  km_popped = 0, stay_in_col = 0;
      struct	  key_menu  *km = NULL;
***************
*** 491,499 ****
--- 493,504 ----
  
      opt_screen	       = screen;
      ps->mangled_screen = 1;
+     ps->resize_for_pico= 0;
      ps->redrawer       = option_screen_redrawer;
  
      while(!done){
+ 	if(ps->resize_for_pico)
+ 	  ps->mangled_screen = ps->resize_for_pico;
  	ps->user_says_cancel = 0;
  	if(km_popped){
  	    km_popped--;
***************
*** 507,516 ****
  	    ps->mangled_header = 1;
  	    ps->mangled_footer = 1;
  	    ps->mangled_body   = 1;
! 	    ps->mangled_screen = 0;
  	}
  
  	/*----------- Check for new mail -----------*/
          if(new_mail(0, NM_TIMING(ch), NM_STATUS_MSG | NM_DEFER_SORT) >= 0)
            ps->mangled_header = 1;
  
--- 512,522 ----
  	    ps->mangled_header = 1;
  	    ps->mangled_footer = 1;
  	    ps->mangled_body   = 1;
! 	    ps->mangled_screen = ps->resize_for_pico = 0;
  	}
  
  	/*----------- Check for new mail -----------*/
+         if (!ps->send_immediately){
          if(new_mail(0, NM_TIMING(ch), NM_STATUS_MSG | NM_DEFER_SORT) >= 0)
            ps->mangled_header = 1;
  
***************
*** 540,545 ****
--- 546,552 ----
  	    mark_status_unknown();
  	}
  
+ 	} /* send_immediately */
  	if(ps->mangled_footer || km != screen->current->keymenu){
  	    bitmap_t	 bitmap;
  
***************
*** 611,616 ****
--- 618,624 ----
  	    }
  	}
  
+ 	if(!ps_global->send_immediately){
  	MoveCursor(cursor_pos.row, cursor_pos.col);
  #ifdef	MOUSE
  	mouse_in_content(KEY_MOUSE, -1, -1, 0, 0);	/* prime the handler */
***************
*** 629,634 ****
--- 637,650 ----
  #ifdef	_WINDOWS
  	mswin_setscrollcallback(NULL);
  #endif
+         } /* send_immediately */
+                        
+         if (ps->send_immediately){
+ 	      ps_global->dont_use_init_cmds = 0;
+               process_config_input(&ch);
+               if (ch == '\030')   /* ^X, bye */
+                 goto end;
+         }           
  
  	cmd = menu_command(ch, km);
  
***************
*** 1382,1388 ****
  	    break;
  	}
      }
! 
      screen->current = first_confline(screen->current);
      free_conflines(&screen->current);
      return(retval);
--- 1398,1404 ----
  	    break;
  	}
      }
! end:
      screen->current = first_confline(screen->current);
      free_conflines(&screen->current);
      return(retval);
***************
*** 2426,2431 ****
--- 2442,2450 ----
  	 * Now go and set the current_val based on user_val changes
  	 * above.  Turn off command line settings...
  	 */
+ 	set_current_val((*cl)->var,
+ 	    (strcmp((*cl)->var->name,"key-definition-rules") ? TRUE : FALSE),
+ 	    FALSE);
  	set_current_val((*cl)->var, TRUE, FALSE);
  	fix_side_effects(ps, (*cl)->var, 0);
  
***************
*** 2922,2928 ****
  	    }
  
  	    set_current_val((*cl)->var, TRUE, TRUE);
! 	    if(decode_sort(ps->VAR_SORT_KEY, &def_sort, &def_sort_rev) != -1){
  		ps->def_sort     = def_sort;
  		ps->def_sort_rev = def_sort_rev;
  	    }
--- 2941,2947 ----
  	    }
  
  	    set_current_val((*cl)->var, TRUE, TRUE);
! 	    if(decode_sort(ps->VAR_SORT_KEY, &def_sort, &def_sort_rev,0) != -1){
  		ps->def_sort     = def_sort;
  		ps->def_sort_rev = def_sort_rev;
  	    }
***************
*** 2931,2936 ****
--- 2950,2986 ----
  	    ps->mangled_body = 1;	/* BUG: redraw it all for now? */
  	    rv = 1;
  	}
+         else if((*cl)->var == &ps->vars[V_THREAD_SORT_KEY]){
+             SortOrder thread_def_sort;
+             int       thread_def_sort_rev;
+ 
+             thread_def_sort_rev  = (*cl)->varmem >= (short) EndofList;
+             thread_def_sort      = (SortOrder) ((*cl)->varmem - (thread_def_sort_rev
+                                                                  * EndofList));
+             sprintf(tmp_20k_buf, "%s%s", sort_name(thread_def_sort),
+                    (thread_def_sort_rev) ? "/Reverse" : "");
+ 
+             if((*cl)->var->cmdline_val.p)
+               fs_give((void **)&(*cl)->var->cmdline_val.p);
+ 
+             if(apval){
+                 if(*apval)
+                   fs_give((void **)apval);
+ 
+                 *apval = cpystr(tmp_20k_buf);
+             }
+ 
+             set_current_val((*cl)->var, TRUE, TRUE);
+             if(decode_sort(ps->VAR_THREAD_SORT_KEY, &thread_def_sort, 
+                                         &thread_def_sort_rev, 1) != -1){
+                 ps->thread_def_sort     = thread_def_sort;
+                 ps->thread_def_sort_rev = thread_def_sort_rev;
+             }
+ 
+             set_radio_pretty_vals(ps, cl);
+             ps->mangled_body = 1;       /* BUG: redraw it all for now? */
+             rv = 1;
+         }
  	else
  	  q_status_message(SM_ORDER | SM_DING, 3, 6,
  			   "Programmer botch!  Unknown radiobutton type.");
***************
*** 3369,3375 ****
  			    ptr = sample;
  
  			    /* then the color sample */
! 			    if(ctmp->var == &ps->vars[V_VIEW_HDR_COLORS]){
  				SPEC_COLOR_S *hc, *hcolors;
  
  				lastc = newc = NULL;
--- 3419,3426 ----
  			    ptr = sample;
  
  			    /* then the color sample */
! 			    if(ctmp->var == &ps->vars[V_VIEW_HDR_COLORS]
! 				|| ctmp->var == &ps->vars[V_INDEX_TOKEN_COLORS]){
  				SPEC_COLOR_S *hc, *hcolors;
  
  				lastc = newc = NULL;
***************
*** 3787,3793 ****
      else if(standard_radio_var(ps, v) || v == startup_ptr)
        return(radio_pretty_value(ps, cl));
      else if(v == &ps->vars[V_SORT_KEY])
!       return(sort_pretty_value(ps, cl));
      else if(v == &ps->vars[V_SIGNATURE_FILE])
        return(sigfile_pretty_value(ps, cl));
      else if(v == &ps->vars[V_USE_ONLY_DOMAIN_NAME])
--- 3838,3846 ----
      else if(standard_radio_var(ps, v) || v == startup_ptr)
        return(radio_pretty_value(ps, cl));
      else if(v == &ps->vars[V_SORT_KEY])
!        return(sort_pretty_value(ps, cl, 0));
!      else if(v == &ps->vars[V_THREAD_SORT_KEY])
!        return(sort_pretty_value(ps, cl, 1));
      else if(v == &ps->vars[V_SIGNATURE_FILE])
        return(sigfile_pretty_value(ps, cl));
      else if(v == &ps->vars[V_USE_ONLY_DOMAIN_NAME])
***************
*** 4318,4331 ****
  
  
  char *
! sort_pretty_value(struct pine *ps, CONF_S *cl)
  {
!     return(generalized_sort_pretty_value(ps, cl, 1));
  }
  
  
  char *
! generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok)
  {
      char  tmp[6*MAXPATH];
      char *pvalnorm, *pvalexc, *pval;
--- 4371,4384 ----
  
  
  char *
! sort_pretty_value(struct pine *ps, CONF_S *cl, int thread)
  {
!     return(generalized_sort_pretty_value(ps, cl, 1, thread));
  }
  
  
  char *
! generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok, int thread)
  {
      char  tmp[6*MAXPATH];
      char *pvalnorm, *pvalexc, *pval;
***************
*** 4375,4381 ****
      }
      else if(fixed){
  	pval = v->fixed_val.p;
! 	decode_sort(pval, &var_sort, &var_sort_rev);
  	is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
  
  	utf8_snprintf(tmp, sizeof(tmp), "(%c)  %s%-*w%*s%s",
--- 4428,4434 ----
      }
      else if(fixed){
  	pval = v->fixed_val.p;
! 	decode_sort(pval, &var_sort, &var_sort_rev, thread);
  	is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
  
  	utf8_snprintf(tmp, sizeof(tmp), "(%c)  %s%-*w%*s%s",
***************
*** 4386,4394 ****
  		is_the_one ? "   (value is fixed)" : "");
      }
      else if(is_set_for_this_level){
! 	decode_sort(pval, &var_sort, &var_sort_rev);
  	is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
! 	decode_sort(pvalexc, &exc_sort, &exc_sort_rev);
  	the_exc_one = (editing_normal_which_isnt_except && pvalexc &&
  		       exc_sort_rev == line_sort_rev && exc_sort == line_sort);
  	utf8_snprintf(tmp, sizeof(tmp), "(%c)  %s%-*w%*s%s",
--- 4439,4447 ----
  		is_the_one ? "   (value is fixed)" : "");
      }
      else if(is_set_for_this_level){
! 	decode_sort(pval, &var_sort, &var_sort_rev, thread);
  	is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
! 	decode_sort(pvalexc, &exc_sort, &exc_sort_rev, thread);
  	the_exc_one = (editing_normal_which_isnt_except && pvalexc &&
  		       exc_sort_rev == line_sort_rev && exc_sort == line_sort);
  	utf8_snprintf(tmp, sizeof(tmp), "(%c)  %s%-*w%*s%s",
***************
*** 4406,4412 ****
      }
      else{
  	if(pvalexc){
! 	    decode_sort(pvalexc, &exc_sort, &exc_sort_rev);
  	    is_the_one = (exc_sort_rev == line_sort_rev &&
  			  exc_sort == line_sort);
  	    utf8_snprintf(tmp, sizeof(tmp), "( )  %s%-*w%*s%s",
--- 4459,4465 ----
      }
      else{
  	if(pvalexc){
! 	    decode_sort(pvalexc, &exc_sort, &exc_sort_rev, thread);
  	    is_the_one = (exc_sort_rev == line_sort_rev &&
  			  exc_sort == line_sort);
  	    utf8_snprintf(tmp, sizeof(tmp), "( )  %s%-*w%*s%s",
***************
*** 4417,4423 ****
  	}
  	else{
  	    pval = v->current_val.p;
! 	    decode_sort(pval, &var_sort, &var_sort_rev);
  	    is_the_one = ((pval || default_ok) &&
  			  var_sort_rev == line_sort_rev &&
  			  var_sort == line_sort);
--- 4470,4476 ----
  	}
  	else{
  	    pval = v->current_val.p;
! 	    decode_sort(pval, &var_sort, &var_sort_rev, thread);
  	    is_the_one = ((pval || default_ok) &&
  			  var_sort_rev == line_sort_rev &&
  			  var_sort == line_sort);
***************
*** 5154,5159 ****
--- 5207,5236 ----
  	    var == &ps->vars[V_ABOOK_FORMATS]){
  	addrbook_reset();
      }
+     else if(var == &ps->vars[V_INDEX_RULES]){
+ 	   if(ps_global->rule_list)
+ 	      free_parsed_rule_list(&ps_global->rule_list);
+ 	   create_rule_list(ps->vars);
+ 	   reset_index_format();
+ 	   clear_index_cache(ps->mail_stream, 0);
+     }
+     else if(var == &ps->vars[V_COMPOSE_RULES] ||
+ 	    var == &ps->vars[V_FORWARD_RULES] ||
+ 	    var == &ps->vars[V_KEY_RULES] ||
+ 	    var == &ps->vars[V_REPLACE_RULES] ||
+ 	    var == &ps->vars[V_REPLY_INDENT_RULES] ||
+ 	    var == &ps->vars[V_REPLY_LEADIN_RULES] ||
+ 	    var == &ps->vars[V_RESUB_RULES] ||
+ 	    var == &ps->vars[V_SAVE_RULES] ||
+ 	    var == &ps->vars[V_SMTP_RULES] ||
+ 	    var == &ps->vars[V_SORT_RULES] ||
+ 	    var == &ps->vars[V_STARTUP_RULES] ||
+ 	    var == &ps->vars[V_THREAD_DISP_STYLE_RULES] ||
+ 	    var == &ps->vars[V_THREAD_INDEX_STYLE_RULES]){
+ 	if(ps_global->rule_list)
+ 	   free_parsed_rule_list(&ps_global->rule_list);
+ 	create_rule_list(ps->vars);
+     }
      else if(var == &ps->vars[V_INDEX_FORMAT]){
  	reset_index_format();
  	clear_index_cache(ps->mail_stream, 0);
***************
*** 5176,5181 ****
--- 5253,5261 ----
  
  	clear_index_cache(ps->mail_stream, 0);
      }
+     else if(var == &ps->vars[V_SPECIAL_TEXT]){
+ 	regex_pattern(ps->VAR_SPECIAL_TEXT);
+     }
      else if(var == &ps->vars[V_INIT_CMD_LIST]){
  	if(!revert)
  	  q_status_message(SM_ASYNC, 0, 3,
***************
*** 5489,5494 ****
--- 5569,5580 ----
  			  (void *)var->current_val.p);
      }
  #endif
+ #ifndef _WINDOWS
+     else if(var == &ps->vars[V_MAILDIR_LOCATION]){
+       if(var->current_val.p && var->current_val.p[0])
+ 	mail_parameters(NULL, SET_MDINBOXPATH, (void *)var->current_val.p);
+     }
+ #endif
      else if(revert && standard_radio_var(ps, var)){
  
  	cur_rule_value(var, TRUE, FALSE);
***************
*** 5538,5546 ****
      else if(revert && var == &ps->vars[V_SORT_KEY]){
  	int def_sort_rev;
  
! 	decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev);
  	ps->def_sort_rev = def_sort_rev;
      }
      else if(var == &ps->vars[V_THREAD_MORE_CHAR] ||
              var == &ps->vars[V_THREAD_EXP_CHAR] ||
              var == &ps->vars[V_THREAD_LASTREPLY_CHAR]){
--- 5624,5638 ----
      else if(revert && var == &ps->vars[V_SORT_KEY]){
  	int def_sort_rev;
  
! 	decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev, 0);
  	ps->def_sort_rev = def_sort_rev;
      }
+     else if(revert && var == &ps->vars[V_THREAD_SORT_KEY]){
+       int thread_def_sort_rev;
+ 
+       decode_sort(VAR_THREAD_SORT_KEY, &ps->thread_def_sort, &thread_def_sort_rev, 1);
+       ps->thread_def_sort_rev = thread_def_sort_rev;
+     }
      else if(var == &ps->vars[V_THREAD_MORE_CHAR] ||
              var == &ps->vars[V_THREAD_EXP_CHAR] ||
              var == &ps->vars[V_THREAD_LASTREPLY_CHAR]){
***************
*** 5607,5612 ****
--- 5699,5705 ----
  	}
      }
      else if(var == &ps->vars[V_KW_COLORS] ||
+ 	    var == &ps->vars[V_INDEX_TOKEN_COLORS] ||
  	    var == &ps->vars[V_IND_PLUS_FORE_COLOR] ||
  	    var == &ps->vars[V_IND_IMP_FORE_COLOR]  ||
              var == &ps->vars[V_IND_DEL_FORE_COLOR]  ||
diff -rc alpine-2.00/alpine/confscroll.h alpine-2.00.I.USE/alpine/confscroll.h
*** alpine-2.00/alpine/confscroll.h	2007-11-09 13:13:47.000000000 -0800
--- alpine-2.00.I.USE/alpine/confscroll.h	2011-02-07 20:33:41.000000000 -0800
***************
*** 94,100 ****
  int	 radiobutton_tool(struct pine *, int, CONF_S **, unsigned);
  int	 yesno_tool(struct pine *, int, CONF_S **, unsigned);
  int      text_toolit(struct pine *, int, CONF_S **, unsigned, int);
! char    *generalized_sort_pretty_value(struct pine *, CONF_S *, int);
  int	 exclude_config_var(struct pine *, struct variable *, int);
  int      config_exit_cmd(unsigned);
  int	 simple_exit_cmd(unsigned);
--- 94,100 ----
  int	 radiobutton_tool(struct pine *, int, CONF_S **, unsigned);
  int	 yesno_tool(struct pine *, int, CONF_S **, unsigned);
  int      text_toolit(struct pine *, int, CONF_S **, unsigned, int);
! char    *generalized_sort_pretty_value(struct pine *, CONF_S *, int, int);
  int	 exclude_config_var(struct pine *, struct variable *, int);
  int      config_exit_cmd(unsigned);
  int	 simple_exit_cmd(unsigned);
diff -rc alpine-2.00/alpine/dispfilt.c alpine-2.00.I.USE/alpine/dispfilt.c
*** alpine-2.00/alpine/dispfilt.c	2008-03-18 10:24:31.000000000 -0700
--- alpine-2.00.I.USE/alpine/dispfilt.c	2011-02-07 20:33:47.000000000 -0800
***************
*** 56,68 ****
  dfilter(char *rawcmd, STORE_S *input_so, gf_io_t output_pc, FILTLIST_S *aux_filters)
  {
      char *status = NULL, *cmd, *resultf = NULL, *tmpfile = NULL;
!     int   key = 0;
  
!     if((cmd = expand_filter_tokens(rawcmd,NULL,&tmpfile,&resultf,NULL,&key,NULL)) != NULL){
  	suspend_busy_cue();
  #ifndef	_WINDOWS
! 	ps_global->mangled_screen = 1;
! 	ClearScreen();
  	fflush(stdout);
  #endif
  
--- 56,70 ----
  dfilter(char *rawcmd, STORE_S *input_so, gf_io_t output_pc, FILTLIST_S *aux_filters)
  {
      char *status = NULL, *cmd, *resultf = NULL, *tmpfile = NULL;
!     int   key = 0, silent = 0;
  
!     if((cmd = expand_filter_tokens(rawcmd,NULL,&tmpfile,&resultf,NULL,&key,NULL, &silent)) != NULL){
  	suspend_busy_cue();
  #ifndef	_WINDOWS
! 	if(!silent){
! 	  ps_global->mangled_screen = 1;
! 	  ClearScreen();
! 	}
  	fflush(stdout);
  #endif
  
***************
*** 99,105 ****
  		/* prepare the terminal in case the filter uses it */
  		if(status == NULL){
  		    if((filter_pipe = open_system_pipe(cmd, NULL, NULL,
! 						      PIPE_USER | PIPE_RESET,
  						      0, pipe_callback, NULL)) != NULL){
  			if(close_system_pipe(&filter_pipe, NULL, pipe_callback) == 0){
  			    /* pull result out of tmp file */
--- 101,108 ----
  		/* prepare the terminal in case the filter uses it */
  		if(status == NULL){
  		    if((filter_pipe = open_system_pipe(cmd, NULL, NULL,
! 						PIPE_USER | (silent ? PIPE_SILENT : 
! 						(F_ON(F_DISABLE_TERM_RESET_DISP, ps_global) ? 0 : PIPE_RESET)),
  						      0, pipe_callback, NULL)) != NULL){
  			if(close_system_pipe(&filter_pipe, NULL, pipe_callback) == 0){
  			    /* pull result out of tmp file */
***************
*** 130,136 ****
  	      status = "Can't open display filter tmp file";
  	}
  	else if((status = gf_filter(cmd, key ? filter_session_key() : NULL,
! 				   input_so, output_pc, aux_filters,
  				   F_ON(F_DISABLE_TERM_RESET_DISP, ps_global),
  				   pipe_callback)) != NULL){
  	    unsigned long ch;
--- 133,139 ----
  	      status = "Can't open display filter tmp file";
  	}
  	else if((status = gf_filter(cmd, key ? filter_session_key() : NULL,
! 				   input_so, output_pc, aux_filters, silent,
  				   F_ON(F_DISABLE_TERM_RESET_DISP, ps_global),
  				   pipe_callback)) != NULL){
  	    unsigned long ch;
***************
*** 150,156 ****
  
  	resume_busy_cue(0);
  #ifndef	_WINDOWS
! 	ClearScreen();
  #endif
  	fs_give((void **)&cmd);
      }
--- 153,160 ----
  
  	resume_busy_cue(0);
  #ifndef	_WINDOWS
! 	if(!silent)
! 	  ClearScreen();
  #endif
  	fs_give((void **)&cmd);
      }
***************
*** 165,171 ****
   */
  char *
  expand_filter_tokens(char *filter, ENVELOPE *env, char **tmpf, char **resultf,
! 		     char **mtypef, int *key, int *hdrs)
  {
      char   **array, **q;
      char    *bp, *cmd = NULL, *p = NULL,
--- 169,175 ----
   */
  char *
  expand_filter_tokens(char *filter, ENVELOPE *env, char **tmpf, char **resultf,
! 		     char **mtypef, int *key, int *hdrs, int *silent)
  {
      char   **array, **q;
      char    *bp, *cmd = NULL, *p = NULL,
***************
*** 238,243 ****
--- 242,260 ----
  	    fs_give((void **)q);
  	    *q = rl ? rl : cpystr("");
  	}
+ 	else if(!strcmp(*q, "_ADDRESS_")){
+ 	    char *r = NULL;
+ 
+ 	    if(env && env->from && env->from->mailbox && env->from->host){
+ 		size_t l;
+ 		l = strlen(env->from->mailbox) + strlen(env->from->host) + 1;
+ 		r = (char *) fs_get((l+1) * sizeof(char));
+ 		snprintf(r, l+1, "%s@%s", env->from->mailbox, env->from->host);
+ 	    }
+ 
+ 	    fs_give((void **)q);
+ 	    *q = r ? r : cpystr("");
+ 	}
  	else if(!strcmp(*q, "_TMPFILE_")){
  	    if(!tfn){
  		tfn = temp_nam(NULL, "sf"); 	/* send filter file */
***************
*** 312,317 ****
--- 329,339 ----
  	    if(hdrs)
  	      *hdrs = 1;
  	}
+ 	else if(!strcmp(*q, "_SILENT_")){
+ 	    (*q)[0] = '\0';
+ 	    if(silent)
+ 	      *silent = 1;
+ 	}
      }
  
      /* count up required length */
***************
*** 451,453 ****
--- 473,535 ----
  
      return(passed);
  }
+ 
+ char *
+ exec_function_rule(char *rawcmd, gf_io_t input_gc, gf_io_t output_pc)
+ {
+     char *status = NULL, *cmd,  *tmpfile = NULL;
+ 
+     if((cmd = expand_filter_tokens(rawcmd,NULL,&tmpfile,NULL,NULL,NULL,NULL, NULL)) != NULL){
+ 	suspend_busy_cue();
+ 	ps_global->mangled_screen = 1;
+ 	if(tmpfile){
+ 	    PIPE_S	  *filter_pipe;
+ 	    FILE          *fp;
+ 	    gf_io_t	   gc, pc;
+ 	    STORE_S       *tmpf_so;
+ 
+ 	    /* write the tmp file */
+ 	    if((tmpf_so = so_get(FileStar, tmpfile, WRITE_ACCESS|OWNER_ONLY|WRITE_TO_LOCALE)) != NULL){
+ 	        /* copy input to tmp file */
+ 		gf_set_so_writec(&pc, tmpf_so);
+ 		gf_filter_init();
+ 		status = gf_pipe(input_gc, pc);
+ 		gf_clear_so_writec(tmpf_so);
+ 		if(so_give(&tmpf_so) != 0 && status == NULL)
+ 		  status = error_description(errno);
+ 
+ 		/* prepare the terminal in case the filter uses it */
+ 		if(status == NULL){
+ 		    if((filter_pipe = open_system_pipe(cmd, NULL, NULL,
+ 						      PIPE_USER|PIPE_PROT|PIPE_NOSHELL|PIPE_SILENT,
+ 						      0, pipe_callback, NULL)) != NULL){
+ 			if(close_system_pipe(&filter_pipe, NULL, pipe_callback) == 0){
+ 			    /* pull result out of tmp file */
+ 			    if((fp = our_fopen(tmpfile, "rb")) != NULL){
+ 				gf_set_readc(&gc, fp, 0L, FileStar, READ_FROM_LOCALE);
+ 				gf_filter_init();
+ 				status = gf_pipe(gc, output_pc);
+ 				fclose(fp);
+ 			    }
+ 			    else
+ 			      status = "Can't read result of EXEC command";
+ 			}
+ 			else
+ 			  status = "EXEC command command returned error.";
+ 		    }
+ 		    else
+ 		      status = "Can't open pipe for EXEC command";
+ 		}
+ 
+ 		our_unlink(tmpfile);
+ 	    }
+ 	    else
+ 	      status = "Can't open EXEC command tmp file";
+ 	}
+ 
+ 	resume_busy_cue(0);
+ 	fs_give((void **)&cmd);
+     }
+ 
+     return(status);
+ }
diff -rc alpine-2.00/alpine/dispfilt.h alpine-2.00.I.USE/alpine/dispfilt.h
*** alpine-2.00/alpine/dispfilt.h	2006-09-26 12:30:49.000000000 -0700
--- alpine-2.00.I.USE/alpine/dispfilt.h	2011-02-07 20:33:45.000000000 -0800
***************
*** 21,30 ****
  /* exported protoypes */
  char	*dfilter(char *, STORE_S *, gf_io_t, FILTLIST_S *);
  char	*dfilter_trigger(BODY *, char *, size_t);
! char	*expand_filter_tokens(char *, ENVELOPE *, char **, char **, char **, int *, int *);
  char	*filter_session_key(void);
  char	*filter_data_file(int);
! 
  
  
  #endif /* PINE_DISPFILT_INCLUDED */
--- 21,30 ----
  /* exported protoypes */
  char	*dfilter(char *, STORE_S *, gf_io_t, FILTLIST_S *);
  char	*dfilter_trigger(BODY *, char *, size_t);
! char	*expand_filter_tokens(char *, ENVELOPE *, char **, char **, char **, int *, int *, int *);
  char	*filter_session_key(void);
  char	*filter_data_file(int);
! char	*exec_function_rule(char *, gf_io_t, gf_io_t);
  
  
  #endif /* PINE_DISPFILT_INCLUDED */
diff -rc alpine-2.00/alpine/folder.c alpine-2.00.I.USE/alpine/folder.c
*** alpine-2.00/alpine/folder.c	2008-08-13 17:51:47.000000000 -0700
--- alpine-2.00.I.USE/alpine/folder.c	2011-02-07 20:33:45.000000000 -0800
***************
*** 77,83 ****
  #define	FLW_LIST	0x04	/* Allow for ListMode for subscribing */
  #define	FLW_UNSEEN	0x08	/* Add (unseen) */
  
! 
  
  /*----------------------------------------------------------------------
     The data needed to redraw the folders screen, including the case where the 
--- 77,88 ----
  #define	FLW_LIST	0x04	/* Allow for ListMode for subscribing */
  #define	FLW_UNSEEN	0x08	/* Add (unseen) */
  
! /* folder colors */
! #define CLR_UNSEEN	0x01	/* color folder with unseen/new messages */
! #define CLR_FOLDER	0x02	/* color a name of folder or directory   */
! #define CLR_DIRECT	0x04	/* color a separator of a directory	 */
! #define CLR_FLDRLT	0x08	/* color of explanatory text in list scrn*/
! #define CLR_NORMAL	0x10	/* use normal color			 */
  
  /*----------------------------------------------------------------------
     The data needed to redraw the folders screen, including the case where the 
***************
*** 173,179 ****
  int	    folder_list_write_prefix(FOLDER_S *, int, gf_io_t);
  int         folder_list_write_middle(FOLDER_S *fp, CONTEXT_S *ctxt, gf_io_t pc, HANDLE_S *);
  int	    folder_list_write_suffix(FOLDER_S *, int, gf_io_t);
! int         color_monitored_unseen(FOLDER_S *, int);
  int	    folder_list_ith(int, CONTEXT_S *);
  char	   *folder_list_center_space(char *, int);
  HANDLE_S   *folder_list_handle(FSTATE_S *, HANDLE_S *);
--- 178,187 ----
  int	    folder_list_write_prefix(FOLDER_S *, int, gf_io_t);
  int         folder_list_write_middle(FOLDER_S *fp, CONTEXT_S *ctxt, gf_io_t pc, HANDLE_S *);
  int	    folder_list_write_suffix(FOLDER_S *, int, gf_io_t);
! int         color_monitored(FOLDER_S *, int, int);
! int         color_test_for_folder(char *, char *);
! int         color_write_for_folder(gf_io_t pc, int testtype);
! int         use_color_for_folder(FOLDER_S *fp);
  int	    folder_list_ith(int, CONTEXT_S *);
  char	   *folder_list_center_space(char *, int);
  HANDLE_S   *folder_list_handle(FSTATE_S *, HANDLE_S *);
***************
*** 238,244 ****
      dprint((1, "=== folder_screen called ====\n"));
      mailcap_free(); /* free resources we won't be using for a while */
      ps->next_screen = SCREEN_FUN_NULL;
! 
      /* Initialize folder state and dispatches */
      memset(&fs, 0, sizeof(FSTATE_S));
      fs.context		= cntxt;
--- 246,252 ----
      dprint((1, "=== folder_screen called ====\n"));
      mailcap_free(); /* free resources we won't be using for a while */
      ps->next_screen = SCREEN_FUN_NULL;
!     strcpy(ps->screen_name, "folder");
      /* Initialize folder state and dispatches */
      memset(&fs, 0, sizeof(FSTATE_S));
      fs.context		= cntxt;
***************
*** 335,340 ****
--- 343,349 ----
        pine_mail_close(*fs.cache_streamp);
  
      ps->prev_screen = folder_screen;
+     strcpy(ps->screen_name, "unknown");
  }
  
  
***************
*** 1615,1622 ****
--- 1624,1633 ----
  		if(c_list->prev)
  		  gf_puts("\n", pc);		/* blank line */
  
+ 		color_write_for_folder(pc, CLR_FLDRLT);
  		gf_puts(repeat_char(cols, '-'), pc);
  		gf_puts("\n", pc);
+ 		color_write_for_folder(pc, CLR_NORMAL);
  	    }
  
  	    /* nickname or description */
***************
*** 1625,1630 ****
--- 1636,1642 ----
  		   || F_ON(F_CMBND_SUBDIR_DISP, ps_global))){
  		char buf[6*MAX_SCREEN_COLS + 1];
  
+ 		color_write_for_folder(pc, CLR_FLDRLT);
  		if(cols < 40){
  		  snprintf(buf, sizeof(buf), "%.*s", cols,
  			strsquish(tmp_20k_buf, SIZEOF_20KBUF,
***************
*** 1651,1656 ****
--- 1663,1669 ----
  
  		gf_puts(buf, pc);
  		gf_puts("\n", pc);
+ 		color_write_for_folder(pc, CLR_NORMAL);
  	    }
  	    else if(c_list->label){
  		if(utf8_width(c_list->label) > ps_global->ttyo->screen_cols)
***************
*** 1660,1668 ****
--- 1673,1683 ----
  
  		lbuf[sizeof(lbuf)-1] = '\0';
  
+ 		color_write_for_folder(pc, CLR_FLDRLT);
  		gf_puts(folder_list_center_space(lbuf, cols), pc);
  		gf_puts(lbuf, pc);
  		gf_puts("\n", pc);
+ 		color_write_for_folder(pc, CLR_NORMAL);
  	    }
  
  	    if(c_list->comment){
***************
*** 1673,1681 ****
--- 1688,1698 ----
  
  		lbuf[sizeof(lbuf)-1] = '\0';
  
+ 		color_write_for_folder(pc, CLR_FLDRLT);
  		gf_puts(folder_list_center_space(lbuf, cols), pc);
  		gf_puts(lbuf, pc);
  		gf_puts("\n", pc);
+ 		color_write_for_folder(pc, CLR_NORMAL);
  	    }
  
  	    if(c_list->dir->desc){
***************
*** 1684,1692 ****
--- 1701,1711 ----
  		strncpy(buf, strsquish(tmp_20k_buf,SIZEOF_20KBUF,c_list->dir->desc,cols),
  			sizeof(buf)-1);
  		buf[sizeof(buf)-1] = '\0';
+ 		color_write_for_folder(pc, CLR_FLDRLT);
  		gf_puts(folder_list_center_space(buf, cols), pc);
  		gf_puts(buf, pc);
  		gf_puts("\n", pc);
+ 		color_write_for_folder(pc, CLR_NORMAL);
  	    }
  
  	    if(c_list->use & CNTXT_ZOOM){
***************
*** 1703,1720 ****
--- 1722,1744 ----
  
  		lbuf[sizeof(lbuf)-1] = '\0';
  
+ 		color_write_for_folder(pc, CLR_FLDRLT);
  		gf_puts(folder_list_center_space(lbuf, cols), pc);
  		gf_puts(lbuf, pc);
  		gf_puts("\n", pc);
+ 		color_write_for_folder(pc, CLR_NORMAL);
  	    }
  
+ 	    color_write_for_folder(pc, CLR_FLDRLT);
  	    gf_puts(repeat_char(cols, '-'), pc);
  	    gf_puts("\n\n", pc);
+ 	    color_write_for_folder(pc, CLR_NORMAL);
  	}
  
  	if(shown){
  	    /* Run thru list formatting as necessary */
  	    if((ftotal = folder_total(FOLDERS(c_list))) != 0){
+ 		int use_color;
  		/* If previously selected, mark members of new list */
  		selected = selected_folders(c_list);
  
***************
*** 1729,1738 ****
  		      continue;
  
  		    fcount++;
! 
  		    width = utf8_width(FLDR_NAME(f));
  		    if(f->isdir)
! 		      width += (f->isfolder) ? 3 : 1;
  
  		    if(NEWS_TEST(c_list) && (c_list->use & CNTXT_FINDALL))
  		      /* assume listmode so we don't have to reformat */
--- 1753,1762 ----
  		      continue;
  
  		    fcount++;
! 		    use_color = use_color_for_folder(f);
  		    width = utf8_width(FLDR_NAME(f));
  		    if(f->isdir)
! 		      width += (f->isfolder) ? (use_color ? 1 : 3) : (use_color ? 0 : 1);
  
  		    if(NEWS_TEST(c_list) && (c_list->use & CNTXT_FINDALL))
  		      /* assume listmode so we don't have to reformat */
***************
*** 1866,1874 ****
--- 1890,1900 ----
  
  		lbuf[sizeof(lbuf)-1] = '\0';
  
+ 		color_write_for_folder(pc, CLR_FLDRLT);
  		gf_puts(folder_list_center_space(lbuf, cols), pc);
  		(void) folder_list_write(pc, handlesp, c_list, -1, lbuf,
  					(handlesp) ? FLW_LUNK : FLW_NONE);
+ 		color_write_for_folder(pc, CLR_NORMAL);
  	    }
  	}
  	else if(fp->fs->combined_view
***************
*** 1883,1891 ****
--- 1909,1919 ----
  
  	    lbuf[sizeof(lbuf)-1] = '\0';
  
+ 	    color_write_for_folder(pc, CLR_FLDRLT);
  	    gf_puts(folder_list_center_space(lbuf, cols), pc);
  	    (void) folder_list_write(pc, handlesp, c_list, -1, lbuf,
  				    (handlesp) ? FLW_LUNK : FLW_NONE);
+ 	    color_write_for_folder(pc, CLR_NORMAL);
  	}
  
  	gf_puts("\n", pc);			/* blank line */
***************
*** 1932,1948 ****
  
      if(h1){
  	/* color unseen? */
! 	if(color_monitored_unseen(fp, flags)){
  	    h1->color_unseen = 1;
  	    if(h2)
  	      h2->color_unseen = 1;
  	}
      }
  
      /* embed handle pointer */
!     if(((h1 && h1->color_unseen) ?
! 		gf_puts(color_embed(ps_global->VAR_INCUNSEEN_FORE_COLOR,
! 				    ps_global->VAR_INCUNSEEN_BACK_COLOR), pc) : 1)
         && (h1 ? ((*pc)(TAG_EMBED) && (*pc)(TAG_HANDLE)
  	     && (*pc)(strlen(buf)) && gf_puts(buf, pc)) : 1)
         && (fp ? ((lprefix = folder_list_write_prefix(fp, flags, pc)) >= 0
--- 1960,1983 ----
  
      if(h1){
  	/* color unseen? */
! 	if(color_monitored(fp, flags, CLR_UNSEEN)){
  	    h1->color_unseen = 1;
  	    if(h2)
  	      h2->color_unseen = 1;
  	}
+ 	/* color folder? */
+ 	if(color_monitored(fp, flags, CLR_FOLDER)){
+ 	    h1->color_folder = 1;
+ 	    if(h2)
+ 	      h2->color_folder = 1;
+ 	}
      }
  
      /* embed handle pointer */
!     if(((h1 && h1->color_unseen) ? color_write_for_folder(pc, CLR_UNSEEN)
! 		: ((h1 && h1->color_folder) 
! 		  ? color_write_for_folder(pc, fp->isfolder ? CLR_FOLDER : CLR_DIRECT)
! 							    : 1))
         && (h1 ? ((*pc)(TAG_EMBED) && (*pc)(TAG_HANDLE)
  	     && (*pc)(strlen(buf)) && gf_puts(buf, pc)) : 1)
         && (fp ? ((lprefix = folder_list_write_prefix(fp, flags, pc)) >= 0
***************
*** 1951,1959 ****
  	      : (alt_name ? gf_puts(alt_name, pc) : 0))
         && (h1 ? ((*pc)(TAG_EMBED) && (*pc)(TAG_BOLDOFF)
  		&& (*pc)(TAG_EMBED) && (*pc)(TAG_INVOFF)) : 1)
!        && ((h1 && h1->color_unseen) ?
! 	       gf_puts(color_embed(ps_global->VAR_NORM_FORE_COLOR,
! 				   ps_global->VAR_NORM_BACK_COLOR), pc) : 1)){
  	if(fp)
  	  width = lprefix + lmiddle + lsuffix;
  	else if(alt_name)
--- 1986,1993 ----
  	      : (alt_name ? gf_puts(alt_name, pc) : 0))
         && (h1 ? ((*pc)(TAG_EMBED) && (*pc)(TAG_BOLDOFF)
  		&& (*pc)(TAG_EMBED) && (*pc)(TAG_INVOFF)) : 1)
!        && ((h1 && (h1->color_unseen || h1->color_folder)) ?
! 		color_write_for_folder(pc, CLR_NORMAL): 1)){
  	if(fp)
  	  width = lprefix + lmiddle + lsuffix;
  	else if(alt_name)
***************
*** 1992,2002 ****
      return(rv);
  }
  
- 
  int
  folder_list_write_middle(FOLDER_S *fp, CONTEXT_S *ctxt, gf_io_t pc, HANDLE_S *h2)
  {
!     int rv = -1;
      char buf[256];
  
      if(h2){
--- 2026,2035 ----
      return(rv);
  }
  
  int
  folder_list_write_middle(FOLDER_S *fp, CONTEXT_S *ctxt, gf_io_t pc, HANDLE_S *h2)
  {
!     int rv = -1, use_color;
      char buf[256];
  
      if(h2){
***************
*** 2007,2023 ****
      if(!fp)
        return(rv);
  
      if(gf_puts(FLDR_NAME(fp), pc)
         && (h2 ? ((*pc)(TAG_EMBED) && (*pc)(TAG_BOLDOFF)		/* tie off handle 1 */
  		&& (*pc)(TAG_EMBED) && (*pc)(TAG_INVOFF)) : 1)
         && (h2 ? ((*pc)(TAG_EMBED) && (*pc)(TAG_HANDLE)		/* start handle 2 */
  	     && (*pc)(strlen(buf)) && gf_puts(buf, pc)) : 1)
!        && ((fp->isdir && fp->isfolder) ? (*pc)('[') : 1)
!        && ((fp->isdir) ? (*pc)(ctxt->dir->delim) : 1)
!        && ((fp->isdir && fp->isfolder) ? (*pc)(']') : 1)){
  	rv = utf8_width(FLDR_NAME(fp));
  	if(fp->isdir)
! 	  rv += (fp->isfolder) ? 3 : 1;
      }
  	
      return(rv);
--- 2040,2062 ----
      if(!fp)
        return(rv);
  
+     use_color = use_color_for_folder(fp);
+ 
      if(gf_puts(FLDR_NAME(fp), pc)
         && (h2 ? ((*pc)(TAG_EMBED) && (*pc)(TAG_BOLDOFF)		/* tie off handle 1 */
  		&& (*pc)(TAG_EMBED) && (*pc)(TAG_INVOFF)) : 1)
+        && ((use_color && fp->isdir && fp->isfolder)
+ 		? color_write_for_folder(pc, CLR_DIRECT) : 1)
         && (h2 ? ((*pc)(TAG_EMBED) && (*pc)(TAG_HANDLE)		/* start handle 2 */
  	     && (*pc)(strlen(buf)) && gf_puts(buf, pc)) : 1)
!        && use_color 
! 	 ? (fp->isdir && fp->isfolder ? (*pc)(ctxt->dir->delim) : 1)
! 	 : (((fp->isdir && fp->isfolder) ? (*pc)('[') : 1)
! 	       && ((fp->isdir) ? (*pc)(ctxt->dir->delim) : 1)
! 	       && ((fp->isdir && fp->isfolder) ? (*pc)(']') : 1))){
  	rv = utf8_width(FLDR_NAME(fp));
  	if(fp->isdir)
! 	  rv += (fp->isfolder) ? (use_color ? 1 : 3) : (use_color ? 0 : 1);
      }
  	
      return(rv);
***************
*** 2065,2084 ****
      return(rv);
  }
  
  
  int
! color_monitored_unseen(FOLDER_S *f, int flags)
  {
!     return((flags & FLW_UNSEEN) && f && f->unseen_valid
  	   && ((F_ON(F_INCOMING_CHECKING_RECENT, ps_global) && f->new > 0L)
  	       || (F_OFF(F_INCOMING_CHECKING_RECENT, ps_global) && f->unseen > 0L))
!            && pico_usingcolor()
! 	   && pico_is_good_color(ps_global->VAR_INCUNSEEN_FORE_COLOR)
! 	   && pico_is_good_color(ps_global->VAR_INCUNSEEN_BACK_COLOR)
! 	   && (colorcmp(ps_global->VAR_INCUNSEEN_FORE_COLOR,
! 		        ps_global->VAR_NORM_FORE_COLOR)
! 	       || colorcmp(ps_global->VAR_INCUNSEEN_BACK_COLOR,
! 			   ps_global->VAR_NORM_BACK_COLOR)));
  }
  
  
--- 2104,2188 ----
      return(rv);
  }
  
+ int
+ color_write_for_folder(gf_io_t pc, int testtype)
+ {
+   int rv;
+   if(!pico_usingcolor())
+     return 1;
+   switch (testtype){
+     case CLR_UNSEEN: 
+ 	rv = gf_puts(color_embed(ps_global->VAR_INCUNSEEN_FORE_COLOR,
+ 		ps_global->VAR_INCUNSEEN_BACK_COLOR), pc);
+ 	break;
+     case CLR_FOLDER:
+ 	rv = gf_puts(color_embed(ps_global->VAR_FOLDER_FORE_COLOR,
+ 		ps_global->VAR_FOLDER_BACK_COLOR ), pc);
+ 	break;
+     case CLR_FLDRLT:
+ 	rv = gf_puts(color_embed(ps_global->VAR_FOLDER_LIST_FORE_COLOR,
+ 		ps_global->VAR_FOLDER_LIST_BACK_COLOR ), pc);
+ 	break;
+     case CLR_DIRECT:
+ 	rv = gf_puts(color_embed(ps_global->VAR_DIRECTORY_FORE_COLOR,
+ 		ps_global->VAR_DIRECTORY_BACK_COLOR), pc);
+ 	break;
+     case CLR_NORMAL:
+ 	rv = gf_puts(color_embed(ps_global->VAR_NORM_FORE_COLOR,
+ 		ps_global->VAR_NORM_BACK_COLOR), pc);
+ 	break;
+     default: 
+ 	rv = 0;	/* fail */
+ 	break;
+   }
+   return rv;
+ }
+ 
  
  int
! color_test_for_folder(char *color_fore, char *color_back)
  {
!    return pico_usingcolor()
! 	   && pico_is_good_color(color_fore)
! 	   && pico_is_good_color(color_back)
! 	   && (colorcmp(color_fore, ps_global->VAR_NORM_FORE_COLOR)
! 	       || colorcmp(color_back, 
! 			   ps_global->VAR_NORM_BACK_COLOR)) ? 1 : 0;
! 
! }
! 
! 
! int
! use_color_for_folder(FOLDER_S *fp)
! {
!    int test1, test2;
!    if(fp->isdir)
! 	test1 = color_test_for_folder(ps_global->VAR_DIRECTORY_FORE_COLOR,
! 				ps_global->VAR_DIRECTORY_BACK_COLOR);
!     if(fp->isfolder)
! 	test2 = color_test_for_folder(ps_global->VAR_FOLDER_FORE_COLOR,
! 				ps_global->VAR_FOLDER_BACK_COLOR);
!     return (fp->isdir && fp->isfolder) ? test1 + test2
! 			: (fp->isdir ? test1 : (fp->isfolder? test2 : 0));
! }
! 
! 
! int
! color_monitored(FOLDER_S *f, int flags, int testtype)
! {
!    int rv;
!    switch(testtype){
! 	case CLR_UNSEEN: rv = (flags & FLW_UNSEEN) && f && f->unseen_valid
  	   && ((F_ON(F_INCOMING_CHECKING_RECENT, ps_global) && f->new > 0L)
  	       || (F_OFF(F_INCOMING_CHECKING_RECENT, ps_global) && f->unseen > 0L))
! 	   && color_test_for_folder(ps_global->VAR_INCUNSEEN_FORE_COLOR,
! 				ps_global->VAR_INCUNSEEN_BACK_COLOR) ? 1 : 0;
! 		break;
! 	case CLR_FOLDER: rv = f ? use_color_for_folder(f) : 0;
! 		break;
! 	default: rv = 0;
!      }
!      return rv;
  }
  
  
***************
*** 6223,6233 ****
  char *
  next_folder(MAILSTREAM **streamp, char *next, size_t nextlen, char *current, CONTEXT_S *cntxt, long int *find_recent, int *did_cancel)
  {
!     int       index, recent = 0, failed_status = 0, try_fast;
      char      prompt[128];
      FOLDER_S *f = NULL;
      char      tmp[MAILTMPLEN];
! 
  
      /* note: find_folders may assign "stream" */
      build_folder_list(streamp, cntxt, NULL, NULL,
--- 6327,6343 ----
  char *
  next_folder(MAILSTREAM **streamp, char *next, size_t nextlen, char *current, CONTEXT_S *cntxt, long int *find_recent, int *did_cancel)
  {
!     int       index, recent = 0, failed_status = 0, try_fast, done = 0;
      char      prompt[128];
      FOLDER_S *f = NULL;
      char      tmp[MAILTMPLEN];
!     char *test_current = cpystr(current);
!     int  cur_indx  = folder_index(ps_global->cur_folder, cntxt, FI_FOLDER);
!     int  loop = !strcmp(next, ps_global->cur_folder) ? 0 :
!               (folder_index(test_current, cntxt, FI_FOLDER) <= cur_indx
!                       ? 1 : 0);
!     int  last = !strcmp(ps_global->cur_folder, ps_global->inbox_name)
!                ? 1 : cur_indx;
  
      /* note: find_folders may assign "stream" */
      build_folder_list(streamp, cntxt, NULL, NULL,
***************
*** 6238,6244 ****
      if(find_recent)
        *find_recent = 0L;
  
!     for(index = folder_index(current, cntxt, FI_FOLDER) + 1;
  	index > 0
  	&& index < folder_total(FOLDERS(cntxt))
  	&& (f = folder_entry(index, FOLDERS(cntxt)))
--- 6348,6356 ----
      if(find_recent)
        *find_recent = 0L;
  
! 
! find_new_message:
!     for(index = folder_index(test_current, cntxt, FI_FOLDER) + 1;
  	index > 0
  	&& index < folder_total(FOLDERS(cntxt))
  	&& (f = folder_entry(index, FOLDERS(cntxt)))
***************
*** 6249,6254 ****
--- 6361,6371 ----
  	  int         rv, we_cancel = 0, match;
  	  char        msg_buf[MAX_BM+1];
  
+ 	  if (loop && (index == last)){
+ 	    done++;
+ 	    break;
+ 	  }
+ 
  	  /* must be a folder and it can't be the current one */
  	  if(ps_global->context_current == ps_global->context_list
  	     && !strcmp(ps_global->cur_folder, FLDR_NAME(f)))
***************
*** 6416,6427 ****
--- 6533,6556 ----
      if(f && (!find_recent || recent)){
  	strncpy(next, FLDR_NAME(f), nextlen);
  	next[nextlen-1] = '\0';
+ 	done++;
      }
      else if(nextlen > 0)
        *next = '\0';
  
+     if (!done && F_ON(F_AUTO_CIRCULAR_TAB,ps_global)
+        && strcmp(test_current,ps_global->inbox_name)){
+        done++; loop++;
+ 	if (test_current)
+ 	   fs_give((void **)&test_current);
+ 	test_current = cpystr(ps_global->inbox_name);
+ 	goto find_new_message;
+    }
+ 
      /* BUG: how can this be made smarter so we cache the list? */
      free_folder_list(cntxt);
+     if (test_current)
+       fs_give((void **)&test_current);
      return((*next) ? next : NULL);
  }
  
diff -rc alpine-2.00/alpine/help.c alpine-2.00.I.USE/alpine/help.c
*** alpine-2.00/alpine/help.c	2008-04-10 09:50:54.000000000 -0700
--- alpine-2.00.I.USE/alpine/help.c	2011-02-07 20:33:44.000000000 -0800
***************
*** 390,395 ****
--- 390,396 ----
  {
      int rv = 0;
      char message[64];
+     struct help_texts *t;
  
      switch(cmd){
  	/*----------- Print all the help ------------*/
***************
*** 407,412 ****
--- 408,430 ----
  
  	break;
  
+       case MC_EXPORT: /* reuse old definition, so as not to patch pine.h */
+ 	{char help_name[40];
+ 	 help_name[0] = '\0';
+ 	 for(t = h_texts; t->help_text != NO_HELP; t++)
+ 	   if(t->help_text == ((HELP_SCROLL_S *)sparms->proc.data.p)->help_source){
+ 	     strcpy(help_name,t->tag);
+ 	     break;
+ 	   }
+ 	 if(help_name[0])
+ 	   q_status_message1(SM_ORDER, 0, 2, 
+ 		"Internal Name: x-alpine-help:%s", help_name);
+ 	 else
+ 	   q_status_message(SM_ORDER|SM_DING, 1, 2, 
+ 		"Can not find link for text help");
+ 	}
+ 	break;
+ 
        case MC_FINISH :
  	rv = 1;
  	break;
***************
*** 572,578 ****
  int
  url_local_helper(char *url)
  {
!     if(!struncmp(url, "x-alpine-help:", 14) && *(url += 14)){
  	char		   *frag;
  	HelpType	    newhelp;
  
--- 590,597 ----
  int
  url_local_helper(char *url)
  {
!     if((!struncmp(url, "x-alpine-help:", 14) && *(url += 14))
! 	|| (!struncmp(url, "x-pine-help:", 12) && *(url += 12))){
  	char		   *frag;
  	HelpType	    newhelp;
  
diff -rc alpine-2.00/alpine/imap.c alpine-2.00.I.USE/alpine/imap.c
*** alpine-2.00/alpine/imap.c	2008-04-10 14:26:20.000000000 -0700
--- alpine-2.00.I.USE/alpine/imap.c	2011-02-07 20:33:47.000000000 -0800
***************
*** 94,100 ****
   * Internal prototypes
   */
  void  mm_login_alt_cue(NETMBX *);
! long  pine_tcptimeout_noscreen(long, long);
  int   answer_cert_failure(int, MSGNO_S *, SCROLL_S *);
  
  #ifdef	LOCAL_PASSWD_CACHE
--- 94,100 ----
   * Internal prototypes
   */
  void  mm_login_alt_cue(NETMBX *);
! long  pine_tcptimeout_noscreen(long, long, char *);
  int   answer_cert_failure(int, MSGNO_S *, SCROLL_S *);
  
  #ifdef	LOCAL_PASSWD_CACHE
***************
*** 350,355 ****
--- 350,356 ----
      HelpType  help ;
      int       len, rc, q_line, flags;
      int       oespace, avail, need, save_dont_use;
+     int       save_in_init;
      struct servent *sv;
  #if defined(_WINDOWS) || defined(LOCAL_PASSWD_CACHE)
      int       preserve_password = -1;
***************
*** 364,369 ****
--- 365,372 ----
  	       altuserforcache ? altuserforcache : ""));
      q_line = -(ps_global->ttyo ? ps_global->ttyo->footer_rows : 3);
  
+     save_in_init = ps_global->in_init_seq;
+     ps_global->in_init_seq = 0;
      ps_global->no_newmail_check_from_optionally_enter = 1;
  
      /* make sure errors are seen */
***************
*** 440,448 ****
  
  	/* try last working password associated with this host. */
  	if(imap_get_passwd(mm_login_list, pwd, user, hostlist,
! 	   (mb->sslflag||mb->tlsflag))){
  	    dprint((9, "mm_login: found a password to try\n"));
  	    ps_global->no_newmail_check_from_optionally_enter = 0;
  	    return;
  	}
  
--- 443,452 ----
  
  	/* try last working password associated with this host. */
  	if(imap_get_passwd(mm_login_list, pwd, user, hostlist,
! 	   (mb->sslflag||mb->tlsflag)) && pwd[0] != '\0'){
  	    dprint((9, "mm_login: found a password to try\n"));
  	    ps_global->no_newmail_check_from_optionally_enter = 0;
+ 	    ps_global->in_init_seq = save_in_init;
  	    return;
  	}
  
***************
*** 456,461 ****
--- 460,466 ----
  				     (mb->sslflag||mb->tlsflag));
  	    dprint((9, "mm_login: found a password in passfile to try\n"));
  	    ps_global->no_newmail_check_from_optionally_enter = 0;
+ 	    ps_global->in_init_seq = save_in_init;
  	    return;
  	}
  #endif	/* LOCAL_PASSWD_CACHE */
***************
*** 484,489 ****
--- 489,495 ----
  		       "mm_login: found a password for user=%s to try\n",
  		       user ? user : "?"));
  		ps_global->no_newmail_check_from_optionally_enter = 0;
+ 		ps_global->in_init_seq = save_in_init;
  		return;
  	    }
  
***************
*** 499,504 ****
--- 505,511 ----
  		  "mm_login: found a password for user=%s in passfile to try\n",
  		  user ? user : "?"));
  		ps_global->no_newmail_check_from_optionally_enter = 0;
+ 		ps_global->in_init_seq = save_in_init;
  		return;
  	    }
  #endif	/* LOCAL_PASSWD_CACHE */
***************
*** 519,524 ****
--- 526,532 ----
  	       (mb->sslflag||mb->tlsflag))){
  		dprint((9, "mm_login:ui: found a password to try\n"));
  		ps_global->no_newmail_check_from_optionally_enter = 0;
+ 		ps_global->in_init_seq = save_in_init;
  		return;
  	    }
  
***************
*** 532,537 ****
--- 540,546 ----
  					 (mb->sslflag||mb->tlsflag));
  		dprint((9, "mm_login:ui: found a password in passfile to try\n"));
  		ps_global->no_newmail_check_from_optionally_enter = 0;
+ 		ps_global->in_init_seq = save_in_init;
  		return;
  	    }
  #endif	/* LOCAL_PASSWD_CACHE */
***************
*** 750,755 ****
--- 759,765 ----
  
      if(!(user[0] || altuserforcache)){
  	ps_global->no_newmail_check_from_optionally_enter = 0;
+ 	ps_global->in_init_seq = save_in_init;
  	return;
      }
  
***************
*** 762,767 ****
--- 772,778 ----
  	if(imap_get_passwd(mm_login_list, pwd, user, hostlist,
  	   (mb->sslflag||mb->tlsflag))){
  	    ps_global->no_newmail_check_from_optionally_enter = 0;
+ 	    ps_global->in_init_seq = save_in_init;
  	    return;
  	}
  
***************
*** 771,776 ****
--- 782,788 ----
  	    imap_set_passwd(&mm_login_list, pwd, user,
  			    hostlist, (mb->sslflag||mb->tlsflag), 0, 0);
  	    ps_global->no_newmail_check_from_optionally_enter = 0;
+ 	    ps_global->in_init_seq = save_in_init;
  	    return;
  	}
  #endif	/* LOCAL_PASSWD_CACHE */
***************
*** 779,784 ****
--- 791,797 ----
  	if(imap_get_passwd(mm_login_list, pwd, altuserforcache, hostlist,
  	   (mb->sslflag||mb->tlsflag))){
  	    ps_global->no_newmail_check_from_optionally_enter = 0;
+ 	    ps_global->in_init_seq = save_in_init;
  	    return;
  	}
  
***************
*** 788,793 ****
--- 801,807 ----
  	    imap_set_passwd(&mm_login_list, pwd, altuserforcache,
  			    hostlist, (mb->sslflag||mb->tlsflag), 0, 0);
  	    ps_global->no_newmail_check_from_optionally_enter = 0;
+ 	    ps_global->in_init_seq = save_in_init;
  	    return;
  	}
  #endif	/* LOCAL_PASSWD_CACHE */
***************
*** 976,981 ****
--- 990,996 ----
  	ps_global->user_says_cancel = (rc == 1);
          user[0] = pwd[0] = '\0';
  	ps_global->no_newmail_check_from_optionally_enter = 0;
+ 	ps_global->in_init_seq = save_in_init;
          return;
      }
  
***************
*** 1181,1187 ****
  
  
  long
! pine_tcptimeout_noscreen(long int elapsed, long int sincelast)
  {
      long rv = 1L;
      char pmt[128];
--- 1196,1202 ----
  
  
  long
! pine_tcptimeout_noscreen(long int elapsed, long int sincelast, char *host)
  {
      long rv = 1L;
      char pmt[128];
***************
*** 1192,1199 ****
  
      if(elapsed >= (long)ps_global->tcp_query_timeout){
  	snprintf(pmt, sizeof(pmt),
! 	 _("Waited %s seconds for server reply.  Break connection to server"),
! 		long2string(elapsed));
  	pmt[sizeof(pmt)-1] = '\0';
  	if(want_to(pmt, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
  	  ps_global->user_says_cancel = 1;
--- 1207,1214 ----
  
      if(elapsed >= (long)ps_global->tcp_query_timeout){
  	snprintf(pmt, sizeof(pmt),
! 	 _("No reply in %s seconds from server %s. Break connection"),
! 		long2string(elapsed), host);
  	pmt[sizeof(pmt)-1] = '\0';
  	if(want_to(pmt, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
  	  ps_global->user_says_cancel = 1;
***************
*** 1216,1222 ****
   * pine_tcptimeout - C-client callback to handle tcp-related timeouts.
   */
  long
! pine_tcptimeout(long int elapsed, long int sincelast)
  {
      long rv = 1L;			/* keep trying by default */
      unsigned long ch;
--- 1231,1237 ----
   * pine_tcptimeout - C-client callback to handle tcp-related timeouts.
   */
  long
! pine_tcptimeout(long int elapsed, long int sincelast, char *host)
  {
      long rv = 1L;			/* keep trying by default */
      unsigned long ch;
***************
*** 1236,1242 ****
        return(rv);
  
      if(!ps_global->ttyo)
!       return(pine_tcptimeout_noscreen(elapsed, sincelast));
  
      suspend_busy_cue();
      
--- 1251,1257 ----
        return(rv);
  
      if(!ps_global->ttyo)
!       return(pine_tcptimeout_noscreen(elapsed, sincelast, host));
  
      suspend_busy_cue();
      
***************
*** 1253,1261 ****
  
  	Writechar(BELL, 0);
  
! 	PutLine1(ps_global->ttyo->screen_rows - FOOTER_ROWS(ps_global), 0,
!        _("Waited %s seconds for server reply.  Break connection to server? "),
! 	   long2string(elapsed));
  	CleartoEOLN();
  	fflush(stdout);
  	flush_input();
--- 1268,1276 ----
  
  	Writechar(BELL, 0);
  
! 	PutLine2(ps_global->ttyo->screen_rows - FOOTER_ROWS(ps_global), 0,
! 	 _("No reply in %s seconds from server %s. Break connection?"),
! 	   long2string(elapsed), host);
  	CleartoEOLN();
  	fflush(stdout);
  	flush_input();
***************
*** 1272,1280 ****
      }
  
      if(rv == 1L){			/* just warn 'em something's up */
! 	q_status_message1(SM_ORDER, 0, 0,
! 		  _("Waited %s seconds for server reply.  Still Waiting..."),
! 		  long2string(elapsed));
  	flush_status_messages(0);	/* make sure it's seen */
      }
  
--- 1287,1295 ----
      }
  
      if(rv == 1L){			/* just warn 'em something's up */
! 	q_status_message2(SM_ORDER, 0, 0,
! 	 _("No reply in %s seconds from server %s. Still Waiting..."),
! 		  long2string(elapsed), host);
  	flush_status_messages(0);	/* make sure it's seen */
      }
  
***************
*** 1285,1290 ****
--- 1300,1335 ----
      return(rv);
  }
  
+ QUOTALIST *pine_quotalist_copy (pquota)
+    QUOTALIST  *pquota;
+ {
+   QUOTALIST *cquota = NULL;
+ 
+   if(pquota){
+      cquota = mail_newquotalist();
+      if (pquota->name && *pquota->name){
+ 	cquota->name = (char *) fs_get((strlen(pquota->name) + 1)*sizeof(char));
+ 	cquota->name = cpystr(pquota->name);
+      }
+      cquota->usage = pquota->usage;
+      cquota->limit = pquota->limit;
+      if (pquota->next)
+         cquota->next = pine_quotalist_copy(pquota->next);
+   }
+   return cquota;
+ }
+ 
+ 
+ /* C-client callback to handle quota */
+ 
+ void
+ pine_parse_quota (stream, msg, pquota)
+    MAILSTREAM *stream;
+    unsigned char *msg;
+    QUOTALIST *pquota;
+ {
+    ps_global->quota = pine_quotalist_copy (pquota);
+ } 
  
  /*
   * C-client callback to handle SSL/TLS certificate validation failures
diff -rc alpine-2.00/alpine/imap.h alpine-2.00.I.USE/alpine/imap.h
*** alpine-2.00/alpine/imap.h	2008-04-23 19:00:26.000000000 -0700
--- alpine-2.00.I.USE/alpine/imap.h	2011-02-07 20:33:45.000000000 -0800
***************
*** 21,28 ****
  
  
  /* exported protoypes */
  void   *pine_block_notify(int, void *);
! long    pine_tcptimeout(long, long);
  long    pine_sslcertquery(char *, char *, char *);
  char   *pine_newsrcquery(MAILSTREAM *, char *, char *);
  int     url_local_certdetails(char *);
--- 21,30 ----
  
  
  /* exported protoypes */
+ void pine_parse_quota (MAILSTREAM *, unsigned char *, QUOTALIST *);
+ QUOTALIST *pine_quotalist_copy (QUOTALIST  *);
  void   *pine_block_notify(int, void *);
! long    pine_tcptimeout(long, long, char *);
  long    pine_sslcertquery(char *, char *, char *);
  char   *pine_newsrcquery(MAILSTREAM *, char *, char *);
  int     url_local_certdetails(char *);
diff -rc alpine-2.00/alpine/keymenu.c alpine-2.00.I.USE/alpine/keymenu.c
*** alpine-2.00/alpine/keymenu.c	2008-06-03 08:54:15.000000000 -0700
--- alpine-2.00.I.USE/alpine/keymenu.c	2011-02-07 20:33:47.000000000 -0800
***************
*** 314,319 ****
--- 314,333 ----
  	WHEREIS_MENU};
  INST_KEY_MENU(c_fcc_km, context_fcc_keys);
  
+ static struct key quota_keys[] =
+ 	{HELP_MENU,
+ 	NULL_MENU,
+ 	{"E","Exit",{MC_EXIT,3,{'e','i',ctrl('C')}},KS_EXITMODE},
+ 	NULL_MENU,
+ 	NULL_MENU,
+ 	NULL_MENU,
+ 	NULL_MENU,
+ 	NULL_MENU,
+ 	NULL_MENU,
+ 	NULL_MENU,
+ 	NULL_MENU,
+ 	NULL_MENU};
+ INST_KEY_MENU(pine_quota_keymenu, quota_keys);
  
  struct key folder_keys[] =
         {HELP_MENU,
***************
*** 482,488 ****
  	NEXTPAGE_MENU,
  	PRYNTMSG_MENU,
  	{"Z",N_("Print All"),{MC_PRINTALL,1,{'z'}},KS_NONE},
! 	NULL_MENU,
  	WHEREIS_MENU,
  
  	HELP_MENU,
--- 496,502 ----
  	NEXTPAGE_MENU,
  	PRYNTMSG_MENU,
  	{"Z",N_("Print All"),{MC_PRINTALL,1,{'z'}},KS_NONE},
! 	{"N",N_("Name"),{MC_EXPORT,1,{'n'}},KS_NONE},
  	WHEREIS_MENU,
  
  	HELP_MENU,
***************
*** 650,661 ****
  	RCOMPOSE_MENU,
  	HOMEKEY_MENU,
  	ENDKEY_MENU,
! 	NULL_MENU,
  	/* TRANSLATORS: toggles a collapsed view or an expanded view
  	   of a message thread on and off */
  	{"/",N_("Collapse/Expand"),{MC_COLLAPSE,1,{'/'}},KS_NONE},
! 	NULL_MENU,
  	NULL_MENU};
  INST_KEY_MENU(index_keymenu, index_keys);
  
  
--- 664,691 ----
  	RCOMPOSE_MENU,
  	HOMEKEY_MENU,
  	ENDKEY_MENU,
! 	{"K","Sort Thread",{MC_SORTHREAD,1,{'k'}},KS_NONE},
  	/* TRANSLATORS: toggles a collapsed view or an expanded view
  	   of a message thread on and off */
  	{"/",N_("Collapse/Expand"),{MC_COLLAPSE,1,{'/'}},KS_NONE},
! 	/* TRANSLATORS: Collapse all threads */
! 	{"{",N_("Collapse All"),{MC_KOLAPSE,1,{'{'}},KS_NONE},
! 	/* TRANSLATORS: Expand all threads */
! 	{"}",N_("Expand All"), {MC_EXPTHREAD,1,{'}'}},KS_NONE},
! 
! 	HELP_MENU,
! 	OTHER_MENU,
! 	{")","Next Threa",{MC_NEXTHREAD,1,{')'}},KS_NONE},
! 	{"(","Prev Threa",{MC_PRETHREAD,1,{'('}},KS_NONE},
! 	{"^D","Delete Thr",{MC_DELTHREAD,1,{ctrl('D')}},KS_NONE},
! 	{"^U","Undel Thre",{MC_UNDTHREAD,1,{ctrl('U')}},KS_NONE},
! 	{"^T","Select Thr",{MC_SELTHREAD,1,{ctrl('T')}},KS_NONE},
! 	NULL_MENU,
! 	{"[","Close Thre",{MC_CTHREAD,1,{'['}},KS_NONE},
! 	{"]","Open Threa",{MC_OTHREAD,1,{']'}},KS_NONE},
! 	{"@", N_("Quota"), {MC_QUOTA,1,{'@'}}, KS_NONE},
  	NULL_MENU};
+ 
  INST_KEY_MENU(index_keymenu, index_keys);
  
  
***************
*** 728,736 ****
  	RCOMPOSE_MENU,
  	HOMEKEY_MENU,
  	ENDKEY_MENU,
! 	NULL_MENU,
  	{"/",N_("Collapse/Expand"),{MC_COLLAPSE,1,{'/'}},KS_NONE},
  	NULL_MENU,
  	NULL_MENU};
  INST_KEY_MENU(thread_keymenu, thread_keys);
  
--- 758,779 ----
  	RCOMPOSE_MENU,
  	HOMEKEY_MENU,
  	ENDKEY_MENU,
! 	{"]",N_("Open Thread"),{MC_OTHREAD,1,{']'}},KS_NONE},
  	{"/",N_("Collapse/Expand"),{MC_COLLAPSE,1,{'/'}},KS_NONE},
+ 	{")",N_("Next Thread"),{MC_NEXTHREAD,1,{')'}},KS_NONE},
+ 	{"(",N_("Prev Thread"),{MC_PRETHREAD,1,{'('}},KS_NONE},
+ 
+ 	HELP_MENU,
+ 	OTHER_MENU,
+ 	{"@", N_("Quota"), {MC_QUOTA,1,{'@'}}, KS_NONE},
+ 	NULL_MENU,
+ 	{"^D",N_("Delete Thread"),{MC_DELTHREAD,1,{ctrl('D')}},KS_NONE},
+ 	{"^U",N_("Undelete Thread"),{MC_UNDTHREAD,1,{ctrl('U')}},KS_NONE},
+ 	{"^T",N_("SelecT Thread"),{MC_SELTHREAD,1,{ctrl('T')}},KS_NONE},
+ 	NULL_MENU,
+ 	NULL_MENU,
  	NULL_MENU,
+ 	{"K","Sort Thread",{MC_SORTHREAD,1,{'k'}},KS_NONE},
  	NULL_MENU};
  INST_KEY_MENU(thread_keymenu, thread_keys);
  
***************
*** 880,886 ****
  	NULL_MENU,
  	NULL_MENU,
  	NULL_MENU,
! 	NULL_MENU};
  INST_KEY_MENU(view_keymenu, view_keys);
  
  
--- 923,942 ----
  	NULL_MENU,
  	NULL_MENU,
  	NULL_MENU,
! 	NULL_MENU,
! 
! 	HELP_MENU,
! 	OTHER_MENU,
! 	NULL_MENU,
! 	NULL_MENU,
! 	NULL_MENU,
! 	NULL_MENU,
! 	NULL_MENU,
! 	{"(",N_("Prev Thread"),{MC_PRETHREAD,1,{'('}},KS_NONE},
! 	{")",N_("Next Thread"),{MC_NEXTHREAD,1,{')'}},KS_NONE},
! 	{"^D",N_("Delete Thread"),{MC_DELTHREAD,1,{ctrl('D')}},KS_NONE},
! 	{"^U",N_("Undelete Thread"),{MC_UNDTHREAD,1,{ctrl('U')}},KS_NONE},
! 	{"^T",N_("selecT Thread"),{MC_SELTHREAD,1,{ctrl('T')}},KS_NONE}};
  INST_KEY_MENU(view_keymenu, view_keys);
  
  
***************
*** 2452,2458 ****
  
  	HELP_MENU,
  	OTHER_MENU,
! 	NULL_MENU,
  	NULL_MENU,
  	NULL_MENU,
  	NULL_MENU,
--- 2508,2514 ----
  
  	HELP_MENU,
  	OTHER_MENU,
! 	{"I", N_("IndxHdr"), {MC_ADDHEADER,1,{'i'}}, KS_NONE},
  	NULL_MENU,
  	NULL_MENU,
  	NULL_MENU,
***************
*** 2481,2487 ****
  
          HELP_MENU,
  	OTHER_MENU,
! 	NULL_MENU,
  	NULL_MENU,
  	{"D", N_("DeleteHdr"), {MC_DELETE,1,{'d'}}, KS_NONE},
  	/* TRANSLATORS: shuffle headers (change the order of headers) */
--- 2537,2543 ----
  
          HELP_MENU,
  	OTHER_MENU,
! 	{"I", N_("IndxHdr"), {MC_ADDHEADER,1,{'i'}}, KS_NONE},
  	NULL_MENU,
  	{"D", N_("DeleteHdr"), {MC_DELETE,1,{'d'}}, KS_NONE},
  	/* TRANSLATORS: shuffle headers (change the order of headers) */
***************
*** 2527,2533 ****
  
  	HELP_MENU,
  	OTHER_MENU,
! 	NULL_MENU,
  	NULL_MENU,
  	NULL_MENU,
  	NULL_MENU,
--- 2583,2589 ----
  
  	HELP_MENU,
  	OTHER_MENU,
! 	{"I", N_("IndxHdr"), {MC_ADDHEADER,1,{'i'}}, KS_NONE},
  	NULL_MENU,
  	NULL_MENU,
  	NULL_MENU,
diff -rc alpine-2.00/alpine/keymenu.h alpine-2.00.I.USE/alpine/keymenu.h
*** alpine-2.00/alpine/keymenu.h	2008-06-03 08:54:15.000000000 -0700
--- alpine-2.00.I.USE/alpine/keymenu.h	2011-02-07 20:33:47.000000000 -0800
***************
*** 212,218 ****
  #define	MC_COLLAPSE	800
  #define	MC_CHK_RECENT	801
  #define	MC_DECRYPT	802
! 
  
  /*
   * Some standard Key/Command Bindings 
--- 212,232 ----
  #define	MC_COLLAPSE	800
  #define	MC_CHK_RECENT	801
  #define	MC_DECRYPT	802
! #define MC_CTHREAD	803
! #define MC_OTHREAD	804
! #define MC_DELTHREAD	805
! #define MC_UNDTHREAD	806
! #define MC_SELTHREAD	807
! #define MC_SSUTHREAD	808
! #define MC_DSUTHREAD	809
! #define MC_USUTHREAD	810
! #define MC_SORTHREAD	811
! #define MC_NEXTHREAD	812
! #define MC_KOLAPSE	813
! #define MC_EXPTHREAD	814
! #define MC_PRETHREAD	815
! #define MC_QUOTA	816
! #define MC_ADDHEADER	817
  
  /*
   * Some standard Key/Command Bindings 
***************
*** 559,564 ****
--- 573,579 ----
  			c_cfg_km,
  			c_sel_km,
  			c_fcc_km,
+ 			pine_quota_keymenu,
  			folder_km,
  			folder_sel_km,
  			folder_sela_km,
diff -rc alpine-2.00/alpine/mailcmd.c alpine-2.00.I.USE/alpine/mailcmd.c
*** alpine-2.00/alpine/mailcmd.c	2008-08-21 15:14:45.000000000 -0700
--- alpine-2.00.I.USE/alpine/mailcmd.c	2011-02-07 20:33:44.000000000 -0800
***************
*** 72,77 ****
--- 72,78 ----
  #include "../pith/tempfile.h"
  #include "../pith/search.h"
  #include "../pith/margin.h"
+ #include "../pith/rules.h"
  #ifdef _WINDOWS
  #include "../pico/osdep/mswin.h"
  #endif
***************
*** 112,118 ****
  char     *choose_a_rule(int);
  int	  select_by_keyword(MAILSTREAM *, SEARCHSET **);
  char     *choose_a_keyword(void);
! int	  select_sort(struct pine *, int, SortOrder *, int *);
  int       print_index(struct pine *, MSGNO_S *, int);
  
  
--- 113,119 ----
  char     *choose_a_rule(int);
  int	  select_by_keyword(MAILSTREAM *, SEARCHSET **);
  char     *choose_a_keyword(void);
! int	  select_sort(struct pine *, int, SortOrder *, int *, int);
  int       print_index(struct pine *, MSGNO_S *, int);
  
  
***************
*** 253,258 ****
--- 254,260 ----
      {'r', 'r', "R", N_("Recipient")},
      {'p', 'p', "P", N_("Participant")},
      {'b', 'b', "B", N_("Body")},
+     {'h', 'h', "H", N_("Header")},
      {-1, 0, NULL, NULL}
  };
  
***************
*** 972,978 ****
  				     state->context_current, &recent_cnt,
  				     F_ON(F_TAB_NO_CONFIRM,state)
  				       ? NULL : &did_cancel))){
! 			if(!in_inbox){
  			    static ESCKEY_S inbox_opt[] = {
  				{'y', 'y', "Y", N_("Yes")},
  				{'n', 'n', "N", N_("No")},
--- 974,980 ----
  				     state->context_current, &recent_cnt,
  				     F_ON(F_TAB_NO_CONFIRM,state)
  				       ? NULL : &did_cancel))){
! 			if(!in_inbox && F_OFF(F_AUTO_CIRCULAR_TAB,state)){
  			    static ESCKEY_S inbox_opt[] = {
  				{'y', 'y', "Y", N_("Yes")},
  				{'n', 'n', "N", N_("No")},
***************
*** 1333,1339 ****
  	if(any_messages(msgmap, NULL, NULL)){
  	    if(any_lflagged(msgmap, MN_SLCT) > 0L){
  		if(apply_command(state, stream, msgmap, 0,
! 				 AC_NONE, question_line)){
  		    if(F_ON(F_AUTO_UNSELECT, state)){
  			agg_select_all(stream, msgmap, NULL, 0);
  			unzoom_index(state, stream, msgmap);
--- 1335,1341 ----
  	if(any_messages(msgmap, NULL, NULL)){
  	    if(any_lflagged(msgmap, MN_SLCT) > 0L){
  		if(apply_command(state, stream, msgmap, 0,
! 				 AC_NONE, question_line, 1)){
  		    if(F_ON(F_AUTO_UNSELECT, state)){
  			agg_select_all(stream, msgmap, NULL, 0);
  			unzoom_index(state, stream, msgmap);
***************
*** 1351,1373 ****
  
            /*-------- Sort command -------*/
        case MC_SORT :
  	{
  	    int were_threading = THREADING();
  	    SortOrder sort = mn_get_sort(msgmap);
  	    int	      rev  = mn_get_revsort(msgmap);
  
  	    dprint((1,"MAIL_CMD: sort\n"));		    
! 	    if(select_sort(state, question_line, &sort, &rev)){
  		/* $ command reinitializes threading collapsed/expanded info */
  		if(SORT_IS_THREADED(msgmap) && !SEP_THRDINDX())
  		  erase_threading_info(stream, msgmap);
  
  		if(ps_global && ps_global->ttyo){
  		    blank_keymenu(ps_global->ttyo->screen_rows - 2, 0);
  		    ps_global->mangled_footer = 1;
  		}
  
! 		sort_folder(stream, msgmap, sort, rev, SRT_VRB|SRT_MAN);
  	    }
  
  	    state->mangled_footer = 1;
--- 1353,1387 ----
  
            /*-------- Sort command -------*/
        case MC_SORT :
+       case MC_SORTHREAD:
  	{
  	    int were_threading = THREADING();
  	    SortOrder sort = mn_get_sort(msgmap);
  	    int	      rev  = mn_get_revsort(msgmap);
+ 	    int	      thread = (command == MC_SORT) ? 0 : 1;
  
  	    dprint((1,"MAIL_CMD: sort\n"));		    
! 	    if(sort == SortThread)
! 		sort = ps_global->thread_cur_sort;
! 	    if(select_sort(state, question_line, &sort, &rev, thread)){
  		/* $ command reinitializes threading collapsed/expanded info */
  		if(SORT_IS_THREADED(msgmap) && !SEP_THRDINDX())
  		  erase_threading_info(stream, msgmap);
  
+ 		if(command == MC_SORTHREAD){
+ 		  ps_global->thread_cur_sort = sort;
+ 		  sort = SortThread;
+ 		}
+ 		else if(sort == SortThread)	/* command = MC_SORT */
+ 		  ps_global->thread_cur_sort = F_ON(F_THREAD_SORTS_BY_ARRIVAL, ps_global)
+ 						? SortArrival : ps_global->thread_def_sort;
+ 
  		if(ps_global && ps_global->ttyo){
  		    blank_keymenu(ps_global->ttyo->screen_rows - 2, 0);
  		    ps_global->mangled_footer = 1;
  		}
  
! 		sort_folder(stream, msgmap, sort, rev, SRT_VRB|SRT_MAN, 1);
  	    }
  
  	    state->mangled_footer = 1;
***************
*** 2368,2373 ****
--- 2382,2388 ----
  
      dprint((4, "\n - saving message -\n"));
  
+     saved_stream = stream;		/* ugly hack! */
      state->ugly_consider_advancing_bit = 0;
      if(F_OFF(F_SAVE_PARTIAL_WO_CONFIRM, state)
         && msgno_any_deletedparts(stream, msgmap)
***************
*** 2592,2597 ****
--- 2607,2615 ----
  		role->nick = cpystr("Default Role");
  	    }
  
+ 	    if(state->role)
+ 	      fs_give((void **)&state->role);
+ 	    state->role = cpystr(role->nick); /* remember the role */
  	    state->redrawer = NULL;
  	    switch(action){
  	      case 'c':
***************
*** 2642,2653 ****
  	    char *nmsgs, ENVELOPE *env, long int rawmsgno, char *section,
  	    SaveDel *dela, SavePreserveOrder *prea)
  {
!     int		      rc, ku = -1, n, flags, last_rc = 0, saveable_count = 0, done = 0;
      int		      delindex, preindex, r;
      char	      prompt[6*MAX_SCREEN_COLS+1], *p, expanded[MAILTMPLEN];
      char              *buf = tmp_20k_buf;
      char              shortbuf[200];
!     char              *folder;
      HelpType	      help;
      SaveDel           del = DontAsk;
      SavePreserveOrder pre = DontAskPreserve;
--- 2660,2671 ----
  	    char *nmsgs, ENVELOPE *env, long int rawmsgno, char *section,
  	    SaveDel *dela, SavePreserveOrder *prea)
  {
!     int		      rc, ku = -1, n = 0, flags, last_rc = 0, saveable_count = 0, done = 0;
      int		      delindex, preindex, r;
      char	      prompt[6*MAX_SCREEN_COLS+1], *p, expanded[MAILTMPLEN];
      char              *buf = tmp_20k_buf;
      char              shortbuf[200];
!     char              *folder, folder2[MAXPATH];
      HelpType	      help;
      SaveDel           del = DontAsk;
      SavePreserveOrder pre = DontAskPreserve;
***************
*** 2655,2660 ****
--- 2673,2681 ----
      static HISTORY_S *history = NULL;
      CONTEXT_S	     *tc;
      ESCKEY_S	      ekey[10];
+     RULE_RESULT	     *rule;
+ 
+     saved_stream = state->mail_stream;
  
      if(!cntxt)
        panic("no context ptr in save_prompt");
***************
*** 2664,2669 ****
--- 2685,2699 ----
      if(!(folder = save_get_default(state, env, rawmsgno, section, cntxt)))
        return(0);		/* message expunged! */
  
+     if (rule = get_result_rule(V_SAVE_RULES, FOR_SAVE, env)){
+        strncpy(folder2,rule->result,sizeof(folder2)-1);
+        folder2[sizeof(folder2)-1] = '\0';
+        folder = folder2;
+        if (rule->result)
+ 	   fs_give((void **)&rule->result);
+        fs_give((void **)&rule);
+     }
+ 
      /* how many context's can be saved to... */
      for(tc = state->context_list; tc; tc = tc->next)
        if(!NEWS_TEST(tc))
***************
*** 3172,3177 ****
--- 3202,3211 ----
  		if(SORT_IS_THREADED(msgmap))
  		  refresh_sort(stream, msgmap, SRT_NON);
  
+ 		if (msgmap->nmsgs
+ 			&& F_ON(F_ENHANCED_THREAD, state) && COLL_THRDS())
+ 			kolapse_thread(state, stream, msgmap, '[', 0);
+ 
  		state->mangled_body = 1;
  		state->mangled_header = 1;
  		q_status_message2(SM_ORDER, 0, 4,
***************
*** 3266,3271 ****
--- 3300,3308 ----
  	 */
  	if(SORT_IS_THREADED(msgmap))
  	  refresh_sort(stream, msgmap, SRT_NON);
+ 	if (msgmap->nmsgs
+ 		&& F_ON(F_ENHANCED_THREAD, state) && COLL_THRDS())
+ 		kolapse_thread(state, stream, msgmap, '[', 0);
      }
      else{
  	if(del_count)
***************
*** 3347,3352 ****
--- 3384,3392 ----
  	{-1, 0, NULL, NULL}
      };
  
+     if(F_ON(F_IGNORE_SIZE, ps_global))
+       return 'y';
+ 
      if(flags & SSCP_INIT || flags & SSCP_END){
  	if(flags & SSCP_END && possible_corruption)
  	  q_status_message(SM_ORDER, 3, 3, "There is possible data corruption, check the results");
***************
*** 6933,6939 ****
  	 * Maybe it makes sense to zoom after a select but not after a colon
  	 * command even though they are very similar.
  	 */
! 	thread_command(state, state->mail_stream, msgmap, ':', -FOOTER_ROWS(state));
      }
      else{
  	if((all_selected =
--- 6973,6979 ----
  	 * Maybe it makes sense to zoom after a select but not after a colon
  	 * command even though they are very similar.
  	 */
! 	thread_command(state, state->mail_stream, msgmap, ':', -FOOTER_ROWS(state), 1);
      }
      else{
  	if((all_selected =
***************
*** 6989,6995 ****
    ----*/
  int
  apply_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap,
! 	      UCS preloadkeystroke, int flags, int q_line)
  {
      int i = 8,			/* number of static entries in sel_opts3 */
          rv = 0,
--- 7029,7035 ----
    ----*/
  int
  apply_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap,
! 	      UCS preloadkeystroke, int flags, int q_line, int display)
  {
      int i = 8,			/* number of static entries in sel_opts3 */
          rv = 0,
***************
*** 7141,7149 ****
  	collapse_or_expand(state, stream, msgmap,
  			   F_ON(F_SLASH_COLL_ENTIRE, ps_global)
  			     ? 0L
! 			     : mn_get_cur(msgmap));
  	break;
  
        case ':' :
  	select_thread_stmp(state, stream, msgmap);
  	break;
--- 7181,7199 ----
  	collapse_or_expand(state, stream, msgmap,
  			   F_ON(F_SLASH_COLL_ENTIRE, ps_global)
  			     ? 0L
! 			     : mn_get_cur(msgmap),
! 			   display);
  	break;
  
+       case '[' :
+ 	collapse_this_thread(state, stream, msgmap, display, 0);
+       break;
+ 
+       case ']' :
+ 	expand_this_thread(state, stream, msgmap, display, 0);
+       break;
+ 
+ 
        case ':' :
  	select_thread_stmp(state, stream, msgmap);
  	break;
***************
*** 7670,7676 ****
      int          not = 0, me = 0;
      char         sstring[80], savedsstring[80], tmp[128];
      char        *p, *sval = NULL;
!     char         buftmp[MAILTMPLEN];
      ESCKEY_S     ekey[8];
      ENVELOPE    *env = NULL;
      HelpType     help;
--- 7720,7726 ----
      int          not = 0, me = 0;
      char         sstring[80], savedsstring[80], tmp[128];
      char        *p, *sval = NULL;
!     char         buftmp[MAILTMPLEN], namehdr[80];
      ESCKEY_S     ekey[8];
      ENVELOPE    *env = NULL;
      HelpType     help;
***************
*** 7757,7762 ****
--- 7807,7846 ----
  	sval = "BODYTEXT";
  	break;
  
+       case 'h' :
+ 	strcpy(tmp, "Name of HEADER to match : ");
+ 	flags = OE_APPEND_CURRENT;
+ 	namehdr[0] = '\0';
+ 	r = 'x';
+ 	while (r == 'x'){
+ 	       int done = 0;
+ 
+ 	       r = optionally_enter(namehdr, -FOOTER_ROWS(ps_global), 0,
+ 				 sizeof(namehdr), tmp, ekey, NO_HELP, &flags);
+ 	       if (r == 1){
+ 		  cmd_cancelled("Selection by text");
+ 		  return(1);
+ 	       }
+ 	       removing_leading_white_space(namehdr);
+ 	       while(!done){
+ 	          while ((namehdr[0] != '\0') && /* remove trailing ":" */
+ 			(namehdr[strlen(namehdr) - 1] == ':'))
+ 		     namehdr[strlen(namehdr) - 1] = '\0';
+ 		  if ((namehdr[0] != '\0') 
+ 		     && isspace((unsigned char) namehdr[strlen(namehdr) - 1]))
+ 		       removing_trailing_white_space(namehdr);
+ 		  else
+ 		    done++;
+ 	       }
+ 	       if (strchr(namehdr,' ') || strchr(namehdr,'\t') ||
+ 		   strchr(namehdr,':'))
+ 		  namehdr[0] = '\0';
+ 	       if (namehdr[0] == '\0')
+ 	         r = 'x';
+ 	}
+ 	sval = namehdr;
+ 	break;
+ 
        case 'x':
  	break;
  
***************
*** 7953,7959 ****
      flagsforhist = (not ? 0x1 : 0) + (me ? 0x2 : 0);
      save_hist(history, sstring, flagsforhist, NULL);
  
!     rv = agg_text_select(stream, msgmap, type, not, me, sstring, "utf-8", limitsrch);
      if(we_cancel)
        cancel_busy_cue(0);
  
--- 8037,8043 ----
      flagsforhist = (not ? 0x1 : 0) + (me ? 0x2 : 0);
      save_hist(history, sstring, flagsforhist, NULL);
  
!     rv = agg_text_select(stream, msgmap, type, namehdr, not, me, sstring, "utf-8", limitsrch);
      if(we_cancel)
        cancel_busy_cue(0);
  
***************
*** 8874,8879 ****
--- 8958,9102 ----
      return(ret);
  }
  
+ int process_quota_cmd(int cmd, MSGNO_S *msgmap, SCROLL_S *sparms)
+ {
+ return cmd;
+ }
+ 
+ void cmd_quota (struct pine *state)
+ {
+    QUOTALIST *imapquota;
+    NETMBX mb;
+    unsigned long len, storageuse, storagelim, messageuse, messagelim;
+    STORE_S *store;
+    SCROLL_S  sargs;
+    char *linedata, *storageq = NULL, *messageq = NULL;
+    int storage=0, message=0, other=0, storagelen = 0, messagelen = 0;
+ 
+    if(!state->mail_stream || !is_imap_stream(state->mail_stream)){
+       q_status_message(SM_ORDER, 1, 5, "Quota only available for IMAP folders");
+       return;
+    }
+ 
+    if (state->mail_stream
+       && !sp_dead_stream(state->mail_stream)
+       && state->mail_stream->mailbox
+       && *state->mail_stream->mailbox
+       && mail_valid_net_parse(state->mail_stream->mailbox, &mb))
+       imap_getquotaroot(state->mail_stream, mb.mailbox);
+ 
+    if(!state->quota)  /* failed ? */
+       return;         /* go back... */
+ 
+    if(!(store = so_get(CharStar, NULL, EDIT_ACCESS))){
+        q_status_message(SM_ORDER | SM_DING, 3, 3, "Error allocating space.");
+        return;
+    }
+ 
+    if (state->mail_stream && state->mail_stream->original_mailbox){
+       len = strlen(state->mail_stream->original_mailbox) + 19;
+       linedata = (char *) fs_get(len*sizeof(char));
+       sprintf(linedata,"Quota Report for %s\n",
+                         state->mail_stream->original_mailbox);
+       so_puts(store,linedata);
+       if (linedata)
+          fs_give((void **)&linedata);
+    }
+    else
+      so_puts(store,"Quota Report:\n");
+    so_puts(store,"\n");
+ 
+    for (imapquota = state->quota; imapquota; imapquota = imapquota->next){
+       if(!strucmp(imapquota->name,"STORAGE")){
+         storage++;
+         storagelen = strlen(long2string(imapquota->limit)) + 1+3;
+         storageuse = imapquota->usage;
+         storagelim = imapquota->limit;
+       }
+       if(!strucmp(imapquota->name,"MESSAGE")){
+         message++;
+         messagelen = strlen(long2string(imapquota->limit)) + 1+9;
+         messageuse = imapquota->usage;
+         messagelim = imapquota->limit;
+       }
+       other   += strucmp(imapquota->name,"STORAGE") &&
+                         strucmp(imapquota->name,"MESSAGE")  ? 0 : 1;
+    }
+ 
+    storageq = (char *) fs_get(storagelen*sizeof(char));
+    if (storage)
+       sprintf(storageq, "%lu KB", storageuse);
+    messageq = (char *) fs_get(messagelen*sizeof(char));
+    if (message)
+       sprintf(messageq, "%lu message%s", messageuse, plural(messageuse));
+    len = strlen("Usage: ") + storagelen + messagelen + 9;
+    linedata = (char *) fs_get(len*sizeof(char));
+    sprintf(linedata,"Usage: %s%s%s%s\n", (storage ? storageq : ""),
+ 		(message ? (storage ? " (" : "") : ""),
+ 		(message ? messageq : ""),
+ 		(message ? (storage ? ")" : "") : ""));
+    so_puts(store, linedata);
+    if (storageq)
+       fs_give((void **)&storageq);
+    if (messageq)
+       fs_give((void **)&messageq);
+    if (linedata)
+       fs_give((void **)&linedata);
+ 
+    storageq = (char *) fs_get(storagelen*sizeof(char));
+    if (storage)
+       sprintf(storageq, "%lu KB", storagelim);
+    messageq = (char *) fs_get(messagelen*sizeof(char));
+    if (message)
+       sprintf(messageq, "%lu message%s", messagelim, plural(messagelim));
+    len = strlen("Limit: ") + storagelen + messagelen + 9;
+    linedata = (char *) fs_get(len*sizeof(char));
+    sprintf(linedata,"Limit: %s%s%s%s", (storage ? storageq : ""),
+ 		(message ? (storage ? " (" : "") : ""),
+ 		(message ? messageq : ""),
+ 		(message ? (storage ? ")" : "") : ""));
+    so_puts(store, linedata);
+    if (storageq)
+       fs_give((void **)&storageq);
+    if (messageq)
+       fs_give((void **)&messageq);
+    if (linedata)
+       fs_give((void **)&linedata);
+ 
+    for (imapquota = state->quota; other && imapquota;
+       imapquota = imapquota->next){
+       if (strucmp(imapquota->name,"STORAGE") &&
+                   strucmp(imapquota->name,"MESSAGE")){
+          len = (imapquota->name ? strlen(imapquota->name) : strlen("No Name"));
+          linedata = (char *) fs_get(len*sizeof(char));
+          sprintf(linedata,
+ 		"Resource : %s\nUsage    : %lu (%lu%%)\nLimit    : %lu\n\n",
+ 		(imapquota->name ? imapquota->name : "No Name"),
+ 		 imapquota->usage, 100*imapquota->usage/imapquota->limit,
+ 		 imapquota->limit);
+          so_puts(store,linedata);
+          if (linedata)
+             fs_give((void **)&linedata);
+       }
+    }
+ 
+    memset(&sargs, 0, sizeof(SCROLL_S));
+    sargs.text.text   = so_text(store);
+    sargs.text.src    = CharStar;
+    sargs.text.desc   = _("Quota Resources Summary");
+    sargs.bar.title   = _("QUOTA SUMMARY");
+    sargs.proc.tool   = process_quota_cmd;
+    sargs.help.text   = NO_HELP;
+    sargs.help.title  = NULL;
+    sargs.keys.menu   = &pine_quota_keymenu;
+    setbitmap(sargs.keys.bitmap);
+ 
+    scrolltool(&sargs);
+    so_give(&store);
+ 
+    if (state->quota)
+      mail_free_quotalist(&(state->quota));
+ }
  
  /*----------------------------------------------------------------------
     Prompt the user for the type of sort he desires
***************
*** 8884,8893 ****
        Returns 0 if it was cancelled, 1 otherwise.
    ----*/
  int
! select_sort(struct pine *state, int ql, SortOrder *sort, int *rev)
  {
      char      prompt[200], tmp[3], *p;
!     int       s, i;
      int       deefault = 'a', retval = 1;
      HelpType  help;
      ESCKEY_S  sorts[14];
--- 9107,9116 ----
        Returns 0 if it was cancelled, 1 otherwise.
    ----*/
  int
! select_sort(struct pine *state, int ql, SortOrder *sort, int *rev, int thread)
  {
      char      prompt[200], tmp[3], *p;
!     int       s, i, j;
      int       deefault = 'a', retval = 1;
      HelpType  help;
      ESCKEY_S  sorts[14];
***************
*** 8920,8936 ****
        strncpy(prompt, _("Choose type of sort, or 'R' to reverse current sort : "),
  	      sizeof(prompt));
  
!     for(i = 0; state->sort_types[i] != EndofList; i++) {
! 	sorts[i].rval	   = i;
! 	p = sorts[i].label = sort_name(state->sort_types[i]);
! 	while(*(p+1) && islower((unsigned char)*p))
! 	  p++;
! 
! 	sorts[i].ch   = tolower((unsigned char)(tmp[0] = *p));
! 	sorts[i].name = cpystr(tmp);
! 
!         if(mn_get_sort(state->msgmap) == state->sort_types[i])
! 	  deefault = sorts[i].rval;
      }
  
      sorts[i].ch     = 'r';
--- 9143,9168 ----
        strncpy(prompt, _("Choose type of sort, or 'R' to reverse current sort : "),
  	      sizeof(prompt));
  
!     for(i = 0, j = 0; state->sort_types[i] != EndofList; i++) {
!        sorts[i].rval = i;
!        sorts[i].name = cpystr("");
!        sorts[i].label = "";
!        sorts[i].ch    = -2;
!        if (!thread || allowed_thread_key(state->sort_types[i])){
!           p = sorts[j].label = sort_name(state->sort_types[i]);
!           while(*(p+1) && islower((unsigned char)*p))
!             p++;
!           sorts[j].ch   = tolower((unsigned char)(tmp[0] = *p));
!           sorts[j++].name = cpystr(tmp);
!        }
! 
!        if (thread){
!           if (state->thread_def_sort == state->sort_types[i])
!               deefault = sorts[j-1].rval;
!        }
!        else
!            if(mn_get_sort(state->msgmap) == state->sort_types[i])
!              deefault = sorts[i].rval;
      }
  
      sorts[i].ch     = 'r';
***************
*** 8954,8961 ****
  	state->mangled_body = 1;		/* signal screen's changed */
  	if(s == 'r')
  	  *rev = !mn_get_revsort(state->msgmap);
! 	else
  	  *sort = state->sort_types[s];
  
  	if(F_ON(F_SHOW_SORT, ps_global))
  	  ps_global->mangled_header = 1;
--- 9186,9202 ----
  	state->mangled_body = 1;		/* signal screen's changed */
  	if(s == 'r')
  	  *rev = !mn_get_revsort(state->msgmap);
! 	else{
! 	  if(thread){
! 	    for(i = 0; state->sort_types[i] != EndofList; i++){
! 	      if(struncmp(sort_name(state->sort_types[i]),
!                   sorts[s].label, strlen(sorts[s].label)) == 0)
!         	break;
! 	    }
! 	    s = i;
! 	  }
  	  *sort = state->sort_types[s];
+ 	}
  
  	if(F_ON(F_SHOW_SORT, ps_global))
  	  ps_global->mangled_header = 1;
***************
*** 9340,9342 ****
--- 9581,9958 ----
  }
  
  #endif	/* _WINDOWS */
+ 
+ void
+ cmd_delete_this_thread(state, stream, msgmap)
+     struct pine *state;
+     MAILSTREAM  *stream;
+     MSGNO_S     *msgmap;
+ {
+     unsigned long rawno, top, save_kolapsed;
+     PINETHRD_S   *thrd = NULL, *nxthrd;
+ 
+     if(!stream)
+       return;
+ 
+     rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
+     move_top_this_thread(stream, msgmap, rawno);
+     top =  mn_m2raw(msgmap, mn_get_cur(msgmap));
+     if(top)
+       thrd = fetch_thread(stream, top);
+ 
+     if(!thrd)
+       return;
+ 
+     save_kolapsed = this_thread_is_kolapsed(state, stream, msgmap, top);
+     collapse_this_thread(state, stream, msgmap, 0, 0);
+     thread_command(state, stream, msgmap, 'd', -FOOTER_ROWS(state), 1);
+     if (!save_kolapsed)
+        expand_this_thread(state, stream, msgmap, 0, 0);
+ }
+ 
+ void
+ cmd_delete_thread(state, stream, msgmap)
+     struct pine *state;
+     MAILSTREAM  *stream;
+     MSGNO_S     *msgmap;
+ {
+     unsigned long rawno, top, orig_top, topnxt, save_kolapsed;
+     PINETHRD_S   *thrd = NULL, *nxthrd;
+     int done = 0, count;
+ 
+     if(!stream)
+       return;
+ 
+     rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
+     move_top_thread(stream, msgmap, rawno);
+     top =  orig_top = mn_m2raw(msgmap, mn_get_cur(msgmap));
+     if(top)
+       thrd = fetch_thread(stream, top);
+ 
+     if(!thrd)
+       return;
+ 
+     while (!done){
+       cmd_delete_this_thread(state, stream, msgmap);
+       if (F_OFF(F_ENHANCED_THREAD, state)
+          || (move_next_this_thread(state, stream, msgmap, 0) <= 0)
+          || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap)))
+          || (orig_top != top_thread(stream, top)))
+          done++;
+     }
+     mn_set_cur(msgmap,mn_raw2m(msgmap, rawno));
+     cmd_delete(state, msgmap, MCMD_NONE, cmd_delete_index);
+     count = count_thread(state, stream, msgmap, rawno);
+     q_status_message2(SM_ORDER, 0, 1, "%s message%s marked deleted",
+                 int2string(count), plural(count));
+ }
+ 
+ int
+ collapse_this_thread(state, stream, msgmap, display, special)
+     struct pine *state;
+     MAILSTREAM  *stream;
+     MSGNO_S     *msgmap;
+     int          display;
+     int		 special;
+ {
+     int collapsed, rv = 1, done = 0;
+     PINETHRD_S   *thrd = NULL, *nthrd;
+     unsigned long rawno, orig, msgno;
+ 
+     if(!stream)
+       return 0;
+ 
+     rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
+ 
+     if(rawno)
+        thrd = fetch_thread(stream, rawno);
+ 
+     if(!thrd)
+        return rv;
+ 
+     collapsed = this_thread_is_kolapsed(state, stream, msgmap, rawno);
+ 
+     if (special && collapsed){
+ 	expand_this_thread(state, stream, msgmap, 0, 0);
+ 	collapsed = 0;
+     }
+ 
+     clear_index_cache_ent(stream, rawno, 0);
+ 
+     if (!collapsed && thrd->next){
+        if (thrd->rawno == top_thread(stream, thrd->rawno))
+          collapse_or_expand(state, stream, msgmap, mn_get_cur(msgmap), display);
+        else{
+ 	 set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno), MN_COLL, 1);
+ 	 set_thread_subtree(stream, thrd, msgmap, 1, MN_CHID);
+        }
+     }
+     else{
+        if (!collapsed && special 
+ 	   && ((F_OFF(F_ENHANCED_THREAD, state) && !thrd->next) 
+ 	        || F_ON(F_ENHANCED_THREAD, state))){
+ 	  if (thrd->toploose){
+ 	    if (thrd->rawno != thrd->toploose)
+ 	       set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno),MN_CHID, 
+ 									     1);
+ 	    else
+ 	       set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno),MN_COLL,
+ 									     1);
+ 	  }
+        }
+        else{
+          rv = 0; 
+          if (display)
+             q_status_message(SM_ORDER, 0, 1, "Thread already collapsed");
+        }
+     }
+     return rv;
+ }
+ 
+ void
+ collapse_thread(state, stream, msgmap, display)
+     struct pine *state;
+     MAILSTREAM  *stream;
+     MSGNO_S     *msgmap;
+     int          display;
+ {
+     int collapsed, rv = 1, done = 0;
+     PINETHRD_S   *thrd = NULL;
+     unsigned long orig, orig_top, top;
+ 
+     if(!stream)
+       return;
+ 
+     expand_this_thread(state, stream, msgmap, display, 1);
+     orig = mn_m2raw(msgmap, mn_get_cur(msgmap));
+     move_top_thread(stream, msgmap,orig);
+     top = orig_top = mn_m2raw(msgmap, mn_get_cur(msgmap));
+ 
+     if(top)
+       thrd = fetch_thread(stream, top);
+ 
+     if(!thrd)
+       return;
+ 
+     while (!done){
+       collapse_this_thread(state, stream, msgmap, display, 1);
+       if (F_OFF(F_ENHANCED_THREAD, state)
+          || (move_next_this_thread(state, stream, msgmap, 0) <= 0)
+ 	 || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap)))
+ 	 || (orig_top != top_thread(stream, top)))
+ 	 done++;
+     }
+     mn_set_cur(msgmap,mn_raw2m(msgmap, orig_top));
+ }
+ 
+ int
+ expand_this_thread(state, stream, msgmap, display, special)
+     struct pine *state;
+     MAILSTREAM  *stream;
+     MSGNO_S     *msgmap;
+     int          display;
+     int		 special;
+ {
+     int collapsed, rv = 1, done = 0;
+     PINETHRD_S   *thrd = NULL, *nthrd;
+     unsigned long rawno, orig, msgno;
+ 
+     if(!stream)
+       return 0;
+ 
+     orig = mn_m2raw(msgmap, mn_get_cur(msgmap));
+     move_top_this_thread(stream, msgmap,orig);
+     rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
+ 
+     if(rawno)
+        thrd = fetch_thread(stream, rawno);
+ 
+     if(!thrd)
+        return rv;
+ 
+     collapsed = this_thread_is_kolapsed(state, stream, msgmap, rawno);
+ 
+     if (special && !collapsed){
+ 	collapse_this_thread(state, stream, msgmap, 0, 0);
+ 	collapsed = 1;
+     }
+ 
+     clear_index_cache_ent(stream, rawno, 0);
+ 
+      if (collapsed && thrd->next){
+        if (thrd->rawno == top_thread(stream, thrd->rawno))
+          collapse_or_expand(state, stream, msgmap, mn_get_cur(msgmap), display);
+        else{
+         set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno), MN_COLL, 0);
+ 	 set_thread_subtree(stream, thrd, msgmap, 0, MN_CHID);
+        }
+      }
+      else{
+        if (collapsed && special 
+ 	&& ((F_OFF(F_ENHANCED_THREAD, state) && !thrd->next) 
+ 	   || F_ON(F_ENHANCED_THREAD, state))){ 
+ 	  if (thrd->toploose)
+ 	    if (thrd->rawno != thrd->toploose)
+ 	       set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno),MN_CHID, 0);
+ 	    else
+ 	       set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno),MN_COLL, 0);
+        }
+        else{
+          rv = 0; 
+          if (display)
+             q_status_message(SM_ORDER, 0, 1, "Thread already expanded");
+        }
+      }
+     return rv;
+ }
+ 
+ void
+ expand_thread(state, stream, msgmap, display)
+     struct pine *state;
+     MAILSTREAM  *stream;
+     MSGNO_S     *msgmap;
+     int          display;
+ {
+     int collapsed, rv = 1, done = 0;
+     PINETHRD_S   *thrd = NULL;
+     unsigned long orig, orig_top, top;
+ 
+     if(!stream)
+       return;
+ 
+     orig = mn_m2raw(msgmap, mn_get_cur(msgmap));
+     top = orig_top = mn_m2raw(msgmap, mn_get_cur(msgmap));
+ 
+     if(top)
+       thrd = fetch_thread(stream, top);
+ 
+     if(!thrd)
+       return;
+ 
+     while (!done){
+       expand_this_thread(state, stream, msgmap, display, 1);
+       if (F_OFF(F_ENHANCED_THREAD, state)
+          || (move_next_this_thread(state, stream, msgmap, 0) <= 0)
+ 	 || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap)))
+ 	 || (orig_top != top_thread(stream, top)))
+ 	 done++;
+     }
+     mn_set_cur(msgmap,mn_raw2m(msgmap, orig_top));
+ }
+ 
+ 
+ void
+ cmd_undelete_this_thread(state, stream, msgmap)
+     struct pine *state;
+     MAILSTREAM  *stream;
+     MSGNO_S     *msgmap;
+ {
+     unsigned long rawno;
+     int save_kolapsed;
+ 
+     rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
+     save_kolapsed = this_thread_is_kolapsed(state, stream, msgmap, rawno);
+     collapse_this_thread(state, stream, msgmap, 0, 0);
+     thread_command(state, stream, msgmap, 'u', -FOOTER_ROWS(state), 1);
+     if (!save_kolapsed)
+        expand_this_thread(state, stream, msgmap, 0, 0);
+ }
+ 
+ void
+ cmd_undelete_thread(state, stream, msgmap)
+     struct pine *state;
+     MAILSTREAM  *stream;
+     MSGNO_S     *msgmap;
+ {
+     PINETHRD_S   *thrd = NULL;
+     unsigned long rawno, top, orig_top;
+     int done = 0, count;
+ 
+     rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
+     move_top_thread(stream, msgmap, rawno);
+     top =  orig_top = mn_m2raw(msgmap, mn_get_cur(msgmap));
+     if(top)
+       thrd = fetch_thread(stream, top);
+ 
+     if(!thrd)
+       return;
+ 
+     while (!done){
+       cmd_undelete_this_thread(state, stream, msgmap);
+       if (F_OFF(F_ENHANCED_THREAD, state)
+          || (move_next_this_thread(state, stream, msgmap, 0) <= 0)
+ 	 || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap)))
+ 	 || (orig_top != top_thread(stream, top)))
+ 	 done++;
+     }
+     mn_set_cur(msgmap,mn_raw2m(msgmap, rawno));
+     count = count_thread(state, stream, msgmap, rawno);
+     q_status_message2(SM_ORDER, 0, 1, "Deletion mark removed from %s message%s",
+ 		int2string(count), plural(count));
+ }
+ 
+ void
+ kolapse_thread(state, stream, msgmap, ch, display)
+     struct pine *state;
+     MAILSTREAM  *stream;
+     MSGNO_S     *msgmap;
+     char      ch;
+     int		display;
+ {
+     PINETHRD_S   *thrd = NULL;
+     unsigned long rawno;
+     int       rv = 1, done = 0;
+ 
+     if(!stream)
+       return;
+ 
+     rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
+     if(rawno)
+       thrd = fetch_thread(stream, rawno);
+ 
+     if(!thrd)
+       return;
+ 
+     clear_index_cache(stream, 0);
+     mn_set_cur(msgmap,1); /* go to the first message */
+     while (!done){
+       if (ch == '[')
+ 	collapse_thread(state, stream, msgmap, display);
+       else
+ 	expand_thread(state, stream, msgmap, display);
+       if ((rv = move_next_thread(state, stream, msgmap, 0)) <= 0)
+          done++;
+     }
+ 
+     if (rv < 0){
+       if (display)
+       q_status_message(SM_ORDER, 0, 1, (ch == '[')
+                ? "Error while collapsing thread"
+                : "Error while expanding thread");
+     }
+     else
+       if(display)
+       q_status_message(SM_ORDER, 0, 1, (ch == '[')
+                ? "All threads collapsed. Use \"}\" to expand them"
+                : "All threads expanded. Use \"{\" to collapse them");
+ 
+     mn_set_cur(msgmap,mn_raw2m(msgmap, top_thread(stream,rawno)));
+ }
+ 
+ void
+ cmd_select_thread(state, stream, msgmap)
+     struct pine *state;
+     MAILSTREAM  *stream;
+     MSGNO_S     *msgmap;
+ {
+     unsigned long rawno;
+     int save_kolapsed;
+ 
+     rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
+     save_kolapsed = thread_is_kolapsed(state, stream, msgmap, rawno);
+     collapse_thread(state, stream, msgmap, 0);
+     thread_command(state, stream, msgmap, ':', -FOOTER_ROWS(state), 1);
+     if (!save_kolapsed)
+        expand_thread(state, stream, msgmap, 0);
+ }
+ 
diff -rc alpine-2.00/alpine/mailcmd.h alpine-2.00.I.USE/alpine/mailcmd.h
*** alpine-2.00/alpine/mailcmd.h	2008-03-19 12:43:03.000000000 -0700
--- alpine-2.00.I.USE/alpine/mailcmd.h	2011-02-07 20:33:41.000000000 -0800
***************
*** 83,89 ****
  int	    ask_mailbox_reopen(struct pine *, int *);
  void	    visit_folder(struct pine *, char *, CONTEXT_S *, MAILSTREAM *, unsigned long);
  int	    select_by_current(struct pine *, MSGNO_S *, CmdWhere);
! int	    apply_command(struct pine *, MAILSTREAM *, MSGNO_S *, UCS, int, int);
  char      **choose_list_of_keywords(void);
  char       *choose_a_charset(int);
  char      **choose_list_of_charsets(void);
--- 83,89 ----
  int	    ask_mailbox_reopen(struct pine *, int *);
  void	    visit_folder(struct pine *, char *, CONTEXT_S *, MAILSTREAM *, unsigned long);
  int	    select_by_current(struct pine *, MSGNO_S *, CmdWhere);
! int	    apply_command(struct pine *, MAILSTREAM *, MSGNO_S *, UCS, int, int, int);
  char      **choose_list_of_keywords(void);
  char       *choose_a_charset(int);
  char      **choose_list_of_charsets(void);
***************
*** 101,106 ****
  int	    flag_callback(int, long);
  MPopup	   *flag_submenu(MESSAGECACHE *);
  #endif
! 
  
  #endif /* PINE_MAILCMD_INCLUDED */
--- 101,115 ----
  int	    flag_callback(int, long);
  MPopup	   *flag_submenu(MESSAGECACHE *);
  #endif
! void          cmd_delete_thread(struct pine *, MAILSTREAM *, MSGNO_S *);
! void          cmd_delete_this_thread(struct pine *, MAILSTREAM *, MSGNO_S *);
! void          cmd_undelete_this_thread(struct pine *, MAILSTREAM *, MSGNO_S *);
! void          cmd_undelete_thread(struct pine *, MAILSTREAM *, MSGNO_S *);
! void          cmd_select_thread(struct pine *, MAILSTREAM *, MSGNO_S *);
! void          kolapse_thread(struct pine *, MAILSTREAM *, MSGNO_S *, char, int);
! void          collapse_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int);
! void          expand_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int);
! int           collapse_this_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int, int);
! int           expand_this_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int, int);
  
  #endif /* PINE_MAILCMD_INCLUDED */
diff -rc alpine-2.00/alpine/mailindx.c alpine-2.00.I.USE/alpine/mailindx.c
*** alpine-2.00/alpine/mailindx.c	2008-07-09 22:01:13.000000000 -0700
--- alpine-2.00.I.USE/alpine/mailindx.c	2011-02-07 20:33:44.000000000 -0800
***************
*** 228,233 ****
--- 228,235 ----
      state->prev_screen = mail_index_screen;
      state->next_screen = SCREEN_FUN_NULL;
  
+     setup_threading_display_style();
+ 
      if(THRD_AUTO_VIEW()
         && sp_viewing_a_thread(state->mail_stream)
         && state->view_skipped_index
***************
*** 239,248 ****
--- 241,254 ----
  
      adjust_cur_to_visible(state->mail_stream, state->msgmap);
  
+     strcpy(state->screen_name,"index");
+ 
      if(THRD_INDX())
        thread_index_screen(state);
      else
        index_index_screen(state);
+ 
+     strcpy(state->screen_name,"unknown");
  }
  
  
***************
*** 560,565 ****
--- 566,572 ----
  
              /*---------- Scroll line up ----------*/
  	  case MC_CHARUP :
+ previtem:
  	    (void) process_cmd(state, stream, msgmap, MC_PREVITEM,
  			       (style == MsgIndex
  				|| style == MultiMsgIndex
***************
*** 577,582 ****
--- 584,590 ----
  
              /*---------- Scroll line down ----------*/
  	  case MC_CHARDOWN :
+ nextitem:
  	    /*
  	     * Special Page framing handling here.  If we
  	     * did something that should scroll-by-a-line, frame
***************
*** 794,799 ****
--- 802,808 ----
  
  
  	  case MC_THRDINDX :
+ mc_thrdindx:
  	    msgmap->top = msgmap->top_after_thrd;
  	    if(unview_thread(state, stream, msgmap)){
  		state->next_screen = mail_index_screen;
***************
*** 844,850 ****
  			      && mp.col == id.plus_col
  			      && style != ThreadIndex){
  			      collapse_or_expand(state, stream, msgmap,
! 						 mn_get_cur(msgmap));
  			  }
  			  else if (mp.doubleclick){
  			      if(mp.button == M_BUTTON_LEFT){
--- 853,859 ----
  			      && mp.col == id.plus_col
  			      && style != ThreadIndex){
  			      collapse_or_expand(state, stream, msgmap,
! 						 mn_get_cur(msgmap), 1);
  			  }
  			  else if (mp.doubleclick){
  			      if(mp.button == M_BUTTON_LEFT){
***************
*** 923,928 ****
--- 932,939 ----
  	    reset_index_border();
  	    break;
  
+ 	  case MC_QUOTA:
+ 	    cmd_quota(state);
  
              /*---------- Redraw ----------*/
  	  case MC_REPAINT :
***************
*** 951,959 ****
  
  
  	  case MC_COLLAPSE :
! 	    thread_command(state, stream, msgmap, ch, -FOOTER_ROWS(state));
  	    break;
  
            case MC_DELETE :
            case MC_UNDELETE :
            case MC_REPLY :
--- 962,1066 ----
  
  
  	  case MC_COLLAPSE :
! 	    thread_command(state, stream, msgmap, ch, -FOOTER_ROWS(state), 1);
  	    break;
  
+ 	  case MC_CTHREAD  :
+ 	     if (SEP_THRDINDX())
+ 	        goto mc_thrdindx;
+ 	   else
+ 	     if (THREADING()){
+ 	        if (any_messages(ps_global->msgmap, NULL,
+ 							"to collapse a thread"))
+ 		   collapse_thread(state, stream,msgmap, 1);
+ 	     }
+ 	     else
+ 		q_status_message(SM_ORDER, 0, 1,
+ 		  "Command available in threaded mode only");
+ 	  break;
+ 
+ 	  case MC_OTHREAD  :
+ 	     if (SEP_THRDINDX())
+ 		goto view_a_thread;
+ 	  else
+ 	     if (THREADING()){
+ 		if (any_messages(ps_global->msgmap, NULL, "to expand a thread"))
+ 		   expand_thread(state, stream,msgmap, 1);
+ 	     }
+ 	     else
+ 		q_status_message(SM_ORDER, 0, 1,
+ 				"Command available in threaded mode only");
+ 	     break;
+ 
+ 	    case MC_NEXTHREAD:
+ 	    case MC_PRETHREAD:
+ 	     if (THRD_INDX()){
+ 		if (cmd == MC_NEXTHREAD)
+ 		   goto nextitem;
+ 		else
+ 		   goto previtem;
+ 	     }
+ 	     else
+ 		if (THREADING()){
+ 		   if (any_messages(ps_global->msgmap, NULL,
+ 						"to move to other thread"))
+ 		      move_thread(state, stream, msgmap,
+ 						cmd == MC_NEXTHREAD ? 1 : -1);
+ 		}
+ 		else
+ 		   q_status_message(SM_ORDER, 0, 1,
+ 			"Command available in threaded mode only");
+ 	     break;
+ 
+           case MC_KOLAPSE:
+           case MC_EXPTHREAD:
+               if (SEP_THRDINDX()){
+                       q_status_message(SM_ORDER, 0, 1,
+                               "Command not available in this screen");
+               }
+               else{
+               if (THREADING()){
+                  if (any_messages(ps_global->msgmap, NULL,
+                            cmd == MC_KOLAPSE ? "to collapse" : "to expand"))
+                     kolapse_thread(state, stream, msgmap,
+                               (cmd == MC_KOLAPSE) ? '[' : ']', 1);
+               }
+               else
+                   q_status_message(SM_ORDER, 0, 1,
+                        "Command available in threaded mode only");
+             }
+           break;
+ 
+         case MC_DELTHREAD:
+            if (THREADING()){
+               if (any_messages(ps_global->msgmap, NULL, "to delete"))
+                     cmd_delete_thread(state, stream, msgmap);
+            }
+            else
+               q_status_message(SM_ORDER, 0, 1,
+                        "Command available in threaded mode only");
+           break;
+ 
+         case MC_UNDTHREAD:
+            if (THREADING()){
+               if (any_messages(ps_global->msgmap, NULL, "to undelete"))
+                   cmd_undelete_thread(state, stream, msgmap);
+            }
+            else
+               q_status_message(SM_ORDER, 0, 1,
+                        "Command available in threaded mode only");
+         break;
+ 
+         case MC_SELTHREAD:
+            if (THREADING()){
+               if (any_messages(ps_global->msgmap, NULL, "to undelete"))
+                   cmd_select_thread(state, stream, msgmap);
+            }
+            else
+               q_status_message(SM_ORDER, 0, 1,
+                        "Command available in threaded mode only");
+         break;
+ 
            case MC_DELETE :
            case MC_UNDELETE :
            case MC_REPLY :
***************
*** 974,986 ****
  		  if(rawno)
  		    thrd = fetch_thread(stream, rawno);
  
! 		  collapsed = thrd && thrd->next
! 			      && get_lflag(stream, NULL, rawno, MN_COLL);
  	      }
  
  	      if(collapsed){
  		  thread_command(state, stream, msgmap,
! 				 ch, -FOOTER_ROWS(state));
  		  /* increment current */
  		  if(cmd == MC_DELETE){
  		      advance_cur_after_delete(state, stream, msgmap,
--- 1081,1092 ----
  		  if(rawno)
  		    thrd = fetch_thread(stream, rawno);
  
! 		collapsed = thread_is_kolapsed(ps_global, stream, msgmap, rawno);
  	      }
  
  	      if(collapsed){
  		  thread_command(state, stream, msgmap,
! 				 ch, -FOOTER_ROWS(state),1);
  		  /* increment current */
  		  if(cmd == MC_DELETE){
  		      advance_cur_after_delete(state, stream, msgmap,
***************
*** 2672,2677 ****
--- 2778,2784 ----
  		      n = mn_raw2m(msgs, thrd->rawno);
  
  		    while(thrd){
+ 			unsigned long branch;
  			if(!msgline_hidden(stream, msgs, n, 0)
  			   && (++m % lines_per_page) == 1L)
  			  t = n;
***************
*** 2740,2750 ****
  
  	    /* n is the end of this thread */
  	    while(thrd){
  		n = mn_raw2m(msgs, thrd->rawno);
! 		if(thrd->branch)
! 		  thrd = fetch_thread(stream, thrd->branch);
! 		else if(thrd->next)
! 		  thrd = fetch_thread(stream, thrd->next);
  		else
  		  thrd = NULL;
  	    }
--- 2847,2858 ----
  
  	    /* n is the end of this thread */
  	    while(thrd){
+ 		unsigned long next = 0L, branch = 0L;
  		n = mn_raw2m(msgs, thrd->rawno);
! 		if(branch = get_branch(stream,thrd))
! 		  thrd = fetch_thread(stream, branch);
! 		else if(next = get_next(stream,thrd))
! 		  thrd = fetch_thread(stream, next);
  		else
  		  thrd = NULL;
  	    }
***************
*** 2852,2858 ****
  
  void
  thread_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap,
! 	       UCS preloadkeystroke, int q_line)
  {
      PINETHRD_S   *thrd = NULL;
      unsigned long rawno, save_branch;
--- 2960,2966 ----
  
  void
  thread_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap,
! 	       UCS preloadkeystroke, int q_line, int display)
  {
      PINETHRD_S   *thrd = NULL;
      unsigned long rawno, save_branch;
***************
*** 2901,2907 ****
        cancel_busy_cue(0);
  
      (void ) apply_command(state, stream, msgmap, preloadkeystroke, flags,
! 			  q_line);
  
      /* restore the original flags */
      copy_lflags(stream, msgmap, MN_STMP, MN_SLCT);
--- 3009,3015 ----
        cancel_busy_cue(0);
  
      (void ) apply_command(state, stream, msgmap, preloadkeystroke, flags,
! 			  q_line, display);
  
      /* restore the original flags */
      copy_lflags(stream, msgmap, MN_STMP, MN_SLCT);
***************
*** 3395,3401 ****
      if(set){
  	sort_folder(ps_global->mail_stream, ps_global->msgmap,
  		    order & 0x000000ff,
! 		    (order & 0x00000100) != 0, SRT_VRB);
  	mswin_beginupdate();
  	update_titlebar_message();
  	update_titlebar_status();
--- 3503,3509 ----
      if(set){
  	sort_folder(ps_global->mail_stream, ps_global->msgmap,
  		    order & 0x000000ff,
! 		    (order & 0x00000100) != 0, SRT_VRB, 1);
  	mswin_beginupdate();
  	update_titlebar_message();
  	update_titlebar_status();
diff -rc alpine-2.00/alpine/mailindx.h alpine-2.00.I.USE/alpine/mailindx.h
*** alpine-2.00/alpine/mailindx.h	2007-10-15 14:02:56.000000000 -0700
--- alpine-2.00.I.USE/alpine/mailindx.h	2011-02-07 20:33:41.000000000 -0800
***************
*** 102,108 ****
  void		 paint_index_hline(MAILSTREAM *, long, ICE_S *);
  void		 setup_index_state(int);
  void		 warn_other_cmds(void);
! void		 thread_command(struct pine *, MAILSTREAM *, MSGNO_S *, UCS, int);
  COLOR_PAIR      *apply_rev_color(COLOR_PAIR *, int);
  #ifdef	_WINDOWS
  int		 index_sort_callback(int, long);
--- 102,108 ----
  void		 paint_index_hline(MAILSTREAM *, long, ICE_S *);
  void		 setup_index_state(int);
  void		 warn_other_cmds(void);
! void		 thread_command(struct pine *, MAILSTREAM *, MSGNO_S *, UCS, int, int);
  COLOR_PAIR      *apply_rev_color(COLOR_PAIR *, int);
  #ifdef	_WINDOWS
  int		 index_sort_callback(int, long);
diff -rc alpine-2.00/alpine/mailpart.c alpine-2.00.I.USE/alpine/mailpart.c
*** alpine-2.00/alpine/mailpart.c	2008-06-03 08:54:15.000000000 -0700
--- alpine-2.00.I.USE/alpine/mailpart.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 2145,2150 ****
--- 2145,2155 ----
          return(1);
      }
  
+     /* ok, we have a filename. Now check if there is a template, and if
+      * so, rename the file accordingly
+      */
+     filename = mc_template(filename, a->body, a->can_display & MCD_EXT_PROMPT);
+ 
      if((store = so_get(FileStar, filename, WRITE_ACCESS|OWNER_ONLY)) == NULL){
          q_status_message2(SM_ORDER | SM_DING, 3, 5,
                            _("Error \"%s\", Can't write file %s"),
***************
*** 3307,3313 ****
      /*
       * For consistency, the first question is always "include text?"
       */
!     if((include_text = reply_text_query(ps_global, 1, &prefix)) >= 0
         && reply_news_test(a->body->nested.msg->env, outgoing) > 0
         && reply_harvest(ps_global, msgno, a->number,
  			a->body->nested.msg->env, &saved_from,
--- 3312,3318 ----
      /*
       * For consistency, the first question is always "include text?"
       */
!     if((include_text = reply_text_query(ps_global, 1, NULL, &prefix)) >= 0
         && reply_news_test(a->body->nested.msg->env, outgoing) > 0
         && reply_harvest(ps_global, msgno, a->number,
  			a->body->nested.msg->env, &saved_from,
diff -rc alpine-2.00/alpine/mailview.c alpine-2.00.I.USE/alpine/mailview.c
*** alpine-2.00/alpine/mailview.c	2008-08-01 17:32:26.000000000 -0700
--- alpine-2.00.I.USE/alpine/mailview.c	2011-02-07 20:33:47.000000000 -0800
***************
*** 44,49 ****
--- 44,50 ----
  #include "dispfilt.h"
  #include "busy.h"
  #include "smime.h"
+ #include "roleconf.h"
  #include "../pith/conf.h"
  #include "../pith/filter.h"
  #include "../pith/msgno.h"
***************
*** 129,134 ****
--- 130,136 ----
  #define	SS_CUR	2
  #define	SS_FREE	3
  
+ static ACTION_S *role_chosen = NULL;
  
  /*
   * Handle hints.
***************
*** 203,209 ****
--- 205,219 ----
  int	    pcpine_view_cursor(int, long);
  #endif
  
+ static char *prefix;
+ #define NO_FLOWED  0x0000
+ #define IS_FLOWED  0x0001
+ #define DELETEQUO  0x0010
+ #define COLORAQUO  0x0100
+ #define RAWSTRING  0x1000
  
+ int         is_word (char *, int, int);
+ int         is_mailbox(char *, int, int);
  
  /*----------------------------------------------------------------------
       Format a buffer with the text of the current message for browser
***************
*** 242,247 ****
--- 252,259 ----
      ps->prev_screen = mail_view_screen;
      ps->force_prefer_plain = ps->force_no_prefer_plain = 0;
  
+     strcpy(ps->screen_name, "text");
+ 
      if(ps->ttyo->screen_rows - HEADER_ROWS(ps) - FOOTER_ROWS(ps) < 1){
  	q_status_message(SM_ORDER | SM_DING, 0, 3,
  			 _("Screen too small to view message"));
***************
*** 294,299 ****
--- 306,322 ----
  	else
  	  ps->unseen_in_view = !mc->seen;
  
+ 	prefix = reply_quote_str(env);
+ 	/* Make sure the prefix is not only made of spaces, so that we do not
+ 	 * paint the screen incorrectly
+ 	 */
+ 	if (prefix && *prefix){
+ 	   int i;
+ 	   for (i = 0; isspace((unsigned char) prefix[i]); i++);
+ 	   if (i == strlen(prefix))
+ 	     fs_give((void **)&prefix);
+ 	}
+ 
  	init_handles(&handles);
  
  	store = so_get(src, NULL, EDIT_ACCESS);
***************
*** 478,483 ****
--- 501,510 ----
      }
      while(ps->next_screen == SCREEN_FUN_NULL);
  
+     strcpy(ps->screen_name, "unknown");
+ 
+     if (prefix && *prefix)
+        fs_give((void **)&prefix);
      if(we_cancel)
        cancel_busy_cue(-1);
  
***************
*** 732,741 ****
  	{0, 'a', "A", N_("editApp")},
  	{-1, 0, NULL, NULL}};
  
      if(handle->type == URL){
  	launch_opts[4].ch = 'u';
  
! 	if(!(local_h = !struncmp(handle->h.url.path, "x-alpine-", 9))
  	   && (handle->h.url.tool
  	       || ((local_h = url_local_handler(handle->h.url.path) != NULL)
  		   && (handle->h.url.tool = url_external_handler(handle,1)))
--- 759,771 ----
  	{0, 'a', "A", N_("editApp")},
  	{-1, 0, NULL, NULL}};
  
+     if (role_chosen)
+ 	free_action(&role_chosen);
      if(handle->type == URL){
  	launch_opts[4].ch = 'u';
  
! 	if((!(local_h = !struncmp(handle->h.url.path, "x-alpine-", 9))
! 	   || !(local_h = !struncmp(handle->h.url.path, "x-pine-help", 11)))
  	   && (handle->h.url.tool
  	       || ((local_h = url_local_handler(handle->h.url.path) != NULL)
  		   && (handle->h.url.tool = url_external_handler(handle,1)))
***************
*** 833,839 ****
  
      if(force
         || (handle->type == URL
! 	   && !struncmp(handle->h.url.path, "x-alpine-", 9)))
        return(1);
  
      while(1){
--- 863,870 ----
  
      if(force
         || (handle->type == URL
! 	   && !struncmp(handle->h.url.path, "x-alpine-", 9)
! 		|| !struncmp(handle->h.url.path, "x-pine-help", 11)))
        return(1);
  
      while(1){
***************
*** 844,855 ****
  	 * sense if you just say View selected URL ...
  	 */
  	if(handle->type == URL &&
! 	   !struncmp(handle->h.url.path, "mailto:", 7))
! 	  snprintf(prompt, sizeof(prompt), "Compose mail to \"%.*s%s\" ? ",
! 		  MIN(MAX(0,sc - 25), sizeof(prompt)-50), handle->h.url.path+7,
! 		  (strlen(handle->h.url.path+7) > MAX(0,sc-25)) ? "..." : "");
! 	else
! 	  snprintf(prompt, sizeof(prompt), "View selected %s %s%.*s%s ? ",
  		  (handle->type == URL) ? "URL" : "Attachment",
  		  (handle->type == URL) ? "\"" : "",
  		  MIN(MAX(0,sc-27), sizeof(prompt)-50),
--- 875,916 ----
  	 * sense if you just say View selected URL ...
  	 */
  	if(handle->type == URL &&
! 	  !struncmp(handle->h.url.path, "mailto:", 7)){
! 	  int rolenick = role_chosen ? strlen(role_chosen->nick) : 0;
! 	  int offset   = 25 + (role_chosen ? 20 : 0);
! 	  int offset2  = max(0, sc - offset) - strlen(handle->h.url.path+7);
! 	  int offset3  = sc - strlen(handle->h.url.path+7) - rolenick - offset;
! 	  int laddress = min(max(0,sc - offset), sizeof(prompt)-50);
! 	  int lrole    = rolenick;
! 
! 	  if (offset3 < 0){
! 		lrole    = rolenick;
! 		laddress = sc - offset - lrole;
! 		offset3 = laddress - 20; /* redefine offset3 */
! 		if (offset3 < 0){
! 		   laddress = 20;
! 		   lrole    = sc - offset - laddress;
! 		}
! 	  }
! 	  launch_opts[2].ch = 'r';
! 	  launch_opts[2].rval = 'r';
! 	  launch_opts[2].name = "R";
! 	  launch_opts[2].label = N_("Set Role");
! 	  snprintf(prompt, sizeof(prompt), "Compose mail to \"%.*s%s\" %s%.*s%s%s? ",
! 		laddress, handle->h.url.path+7,
! 		(offset2 < 0 ? "..." : ""),
! 		(role_chosen ? "using role \"" : ""),
! 		(role_chosen ? lrole : 0),
! 		(role_chosen ? role_chosen->nick  : ""),
! 		(role_chosen ? (rolenick > lrole ? "..." : "") : ""),
! 		(role_chosen ? "\" " : ""));
! 	}
! 	else{
! 	    launch_opts[2].ch = -2;
! 	    launch_opts[2].rval = 0;
! 	    launch_opts[2].name = NULL;
! 	    launch_opts[2].label = NULL;
! 	    snprintf(prompt, sizeof(prompt), "View selected %s %s%.*s%s ? ",
  		  (handle->type == URL) ? "URL" : "Attachment",
  		  (handle->type == URL) ? "\"" : "",
  		  MIN(MAX(0,sc-27), sizeof(prompt)-50),
***************
*** 857,862 ****
--- 918,924 ----
  		  (handle->type == URL)
  		    ? ((strlen(handle->h.url.path) > MAX(0,sc-27))
  			    ? "...\"" : "\"") : "");
+ 	}
  
  	prompt[sizeof(prompt)-1] = '\0';
  
***************
*** 865,870 ****
--- 927,955 ----
  	  case 'y' :
  	    return(1);
  
+           case 'r':
+ 	  {
+ 	  void (*prev_screen)(struct pine *) = ps_global->prev_screen,
+ 		    (*redraw)(void) = ps_global->redrawer;
+ 	  ps_global->redrawer = NULL;
+ 	  ps_global->next_screen = SCREEN_FUN_NULL;
+ 	  if(role_select_screen(ps_global, &role_chosen, 1) < 0){
+ 	     cmd_cancelled("Compose");
+ 	   ps_global->next_screen = prev_screen;
+ 	   ps_global->redrawer = redraw;
+ 	     if(ps_global->redrawer)
+ 	       (*ps_global->redrawer)();
+ 	     return 0;
+ 	  }
+ 	  ps_global->next_screen = prev_screen;
+ 	  ps_global->redrawer = redraw;
+ 	  if(role_chosen)
+ 	  role_chosen = combine_inherited_role(role_chosen);
+ 	  if(ps_global->redrawer)
+ 	    (*ps_global->redrawer)();
+ 	  break;
+ 	}
+ 
  	  case 'u' :
  	    strncpy(tmp, handle->h.url.path, sizeof(tmp)-1);
  	    tmp[sizeof(tmp)-1] = '\0';
***************
*** 1697,1702 ****
--- 1782,1788 ----
  	{"news:", 5, url_local_news},
  	{"x-alpine-gripe:", 15, gripe_gripe_to},
  	{"x-alpine-help:", 14, url_local_helper},
+ 	{"x-pine-help:", 12, url_local_helper},
  	{"x-alpine-phone-home:", 20, url_local_phone_home},
  	{"x-alpine-config:", 16, url_local_config},
  	{"x-alpine-cert:", 14, url_local_certdetails},
***************
*** 1812,1818 ****
  	fs_give((void **) &urlp);
  
  	rflags = ROLE_COMPOSE;
! 	if(nonempty_patterns(rflags, &dummy)){
  	    role = set_role_from_msg(ps_global, rflags, -1L, NULL);
  	    if(confirm_role(rflags, &role))
  	      role = combine_inherited_role(role);
--- 1898,1904 ----
  	fs_give((void **) &urlp);
  
  	rflags = ROLE_COMPOSE;
! 	if(!(role = copy_action(role_chosen)) && nonempty_patterns(rflags, &dummy)){
  	    role = set_role_from_msg(ps_global, rflags, -1L, NULL);
  	    if(confirm_role(rflags, &role))
  	      role = combine_inherited_role(role);
***************
*** 1888,1893 ****
--- 1974,1980 ----
      
      free_redraft_pos(&redraft_pos);
      free_action(&role);
+     free_action(&role_chosen);
  
      return(rv);
  }
***************
*** 2603,2608 ****
--- 2690,2696 ----
  	}
  
  	if(ps_global->noticed_change_in_unseen){
+ 	    ps_global->noticed_change_in_unseen = 0;  /* redraw only once */
  	    cmd = MC_RESIZE;	/* causes cursor to be saved in folder_lister */
  	    done = 1;
  	    continue;
***************
*** 3449,3454 ****
--- 3537,3588 ----
  	    print_to_printer(sparms);
  	    break;
  
+           case MC_NEXTHREAD:
+           case MC_PRETHREAD:
+              if (THREADING()){
+                 if (any_messages(ps_global->msgmap, NULL,
+                                         "to move to other thread"))
+                   move_thread(ps_global, ps_global->mail_stream, ps_global->msgmap,
+                                                 cmd == MC_NEXTHREAD ? 1 : -1);
+ 		  done = 1;
+              }
+              else
+                 q_status_message(SM_ORDER, 0, 1,
+                          "Command available in threaded mode only");
+           break;
+ 
+           case MC_DELTHREAD:
+              if (THREADING()){
+                 if (any_messages(ps_global->msgmap, NULL, "to delete"))
+                     cmd_delete_thread(ps_global, ps_global->mail_stream, ps_global->msgmap);
+ 		done = 1;
+              }
+              else
+                 q_status_message(SM_ORDER, 0, 1,
+                          "Command available in threaded mode only");
+           break;  
+                 
+           case MC_UNDTHREAD:
+              if (THREADING()){
+                 if (any_messages(ps_global->msgmap, NULL, "to undelete"))
+                     cmd_undelete_thread(ps_global, ps_global->mail_stream, ps_global->msgmap);
+ 		done = 1;
+              }
+              else
+                 q_status_message(SM_ORDER, 0, 1,
+                          "Command available in threaded mode only");   
+           break;
+              
+           case MC_SELTHREAD:
+              if (THREADING()){
+                 if (any_messages(ps_global->msgmap, NULL, "to undelete"))
+                     cmd_select_thread(ps_global, ps_global->mail_stream, ps_global->msgmap);
+ 		done = 1;
+              }
+              else
+                 q_status_message(SM_ORDER, 0, 1,
+                          "Command available in threaded mode only");
+           break;
  
  	    /* ------- First handle on Line ------ */
  	  case MC_GOTOBOL :
diff -rc alpine-2.00/alpine/Makefile.am alpine-2.00.I.USE/alpine/Makefile.am
*** alpine-2.00/alpine/Makefile.am	2008-06-03 08:54:15.000000000 -0700
--- alpine-2.00.I.USE/alpine/Makefile.am	2011-02-07 20:33:46.000000000 -0800
***************
*** 46,48 ****
--- 46,49 ----
  date.c:
  	echo "char datestamp[]="\"`date`\"";" > date.c
  	echo "char hoststamp[]="\"`hostname`\"";" >> date.c
+ 	cat ../patchlevel >> date.c
diff -rc alpine-2.00/alpine/Makefile.in alpine-2.00.I.USE/alpine/Makefile.in
*** alpine-2.00/alpine/Makefile.in	2008-06-03 08:54:15.000000000 -0700
--- alpine-2.00.I.USE/alpine/Makefile.in	2011-02-07 20:33:46.000000000 -0800
***************
*** 724,729 ****
--- 724,730 ----
  date.c:
  	echo "char datestamp[]="\"`date`\"";" > date.c
  	echo "char hoststamp[]="\"`hostname`\"";" >> date.c
+ 	cat ../patchlevel >> date.c
  # Tell versions [3.59,3.63) of GNU make to not export all variables.
  # Otherwise a system limit (for SysV at least) may be exceeded.
  .NOEXPORT:
diff -rc alpine-2.00/alpine/osdep/debuging.c alpine-2.00.I.USE/alpine/osdep/debuging.c
*** alpine-2.00/alpine/osdep/debuging.c	2008-01-04 14:49:15.000000000 -0800
--- alpine-2.00.I.USE/alpine/osdep/debuging.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 104,109 ****
--- 104,110 ----
  
      if(debugfile != NULL){
  	char rev[128];
+ 	extern char plevstamp[];
  	time_t now = time((time_t *)0);
  	if(ps_global->debug_flush)
  	  setvbuf(debugfile, (char *)NULL, _IOLBF, BUFSIZ);
***************
*** 126,131 ****
--- 127,134 ----
  	       get_alpine_revision_string(rev, sizeof(rev)),
  	       ctime(&now)));
  
+ 	dprint((0, "This version uses all.patch:\n%s\n\n", plevstamp));
+ 
  	dprint((0, "Starting after the reading_pinerc calls, the data in this file should\nbe encoded as UTF-8. Before that it will be in the user's native charset.\n"));
  	if(dfile && (debug > DEFAULT_DEBUG ||
  		     ps_global->debug_imap > 0 ||
diff -rc alpine-2.00/alpine/osdep/termin.gen.c alpine-2.00.I.USE/alpine/osdep/termin.gen.c
*** alpine-2.00/alpine/osdep/termin.gen.c	2008-03-26 10:27:45.000000000 -0700
--- alpine-2.00.I.USE/alpine/osdep/termin.gen.c	2011-02-07 20:33:42.000000000 -0800
***************
*** 32,37 ****
--- 32,39 ----
  #include "../../pith/newmail.h"
  #include "../../pith/conf.h"
  #include "../../pith/busy.h"
+ #include "../../pith/list.h"
+ #include "../../pith/rules.h"
  
  #include "../../pico/estruct.h"
  #include "../../pico/pico.h"
***************
*** 66,77 ****
  int	pcpine_oe_cursor(int, long);
  #endif
  
  
  /*
   *     Generic tty input routines
   */
  
! 
  /*----------------------------------------------------------------------
          Read a character from keyboard with timeout
   Input:  none
--- 68,97 ----
  int	pcpine_oe_cursor(int, long);
  #endif
  
+ void
+ fake_config_screen(tt)
+      struct ttyo **tt;
+ {
+     struct ttyo *ttyo;
+ 
+     ttyo = (struct ttyo *)fs_get(sizeof (struct ttyo));
+ 
+     ttyo->header_rows = 2;
+     ttyo->footer_rows = 3;
+     ttyo->screen_rows = 24;
+     ttyo->screen_cols = 80;
+ 
+     *tt = ttyo;
+ 
+ }
+ 
  
  /*
   *     Generic tty input routines
   */
  
! void    process_init_cmds(struct pine *, char **);
! void    queue_init_errors(struct pine *);
  /*----------------------------------------------------------------------
          Read a character from keyboard with timeout
   Input:  none
***************
*** 113,118 ****
--- 133,173 ----
        *utf8str = NULL;
  
      ucs = read_char(tm);
+     if(!ps_global->initial_cmds){
+       RULE_RESULT *rule;
+       char **list = NULL, *error = NULL;
+       int    commas = 0, k;   /* From args.c */
+ 
+       ps_global->pressed_key = cpystr(pretty_command(ucs));
+       rule = (RULE_RESULT *)get_result_rule(V_KEY_RULES, FOR_KEY, NULL);
+       if(ps_global->pressed_key)
+         fs_give((void **)&ps_global->pressed_key);
+       if (rule){
+          for(k = 0; rule->result[k]; k++)
+             if(rule->result[k] == ',') commas++;
+          list = parse_list(rule->result, commas+1, 0, &error);
+          if(error)
+             sprintf(tmp_20k_buf, "Error in parsing command list: %s, %s",
+                       rule->result, error);
+          if (rule->result)
+            fs_give((void **)&rule->result);
+          fs_give((void **)&rule);
+          if(error){
+             q_status_message(SM_ORDER | SM_DING, 0, 2, tmp_20k_buf);
+             return (NO_OP_COMMAND);
+          }
+ 	 process_init_cmds(ps_global, list);
+ 	 if(ps_global->init_errs){
+ 	    queue_init_errors(ps_global);
+             return (NO_OP_COMMAND);
+ 	 }
+ 	 ucs = read_char(tm);
+ 	 ps_global->in_init_seq = 1;  /* no output please */
+ 	 for(k = 0; k < commas; k++)
+             if(list[k]) fs_give((void **)&list[k]);
+          if (list) fs_give((void **)list);
+       }
+     }
      if(ucs != NO_OP_COMMAND && ucs != NO_OP_IDLE && ucs != KEY_RESIZE)
        zero_new_mail_count();
  
***************
*** 306,312 ****
  	       (escape_list && escape_list[0].ch != -1 && escape_list[0].label)
  		 ? escape_list[0].label: ""));
  
!     if(!ps_global->ttyo)
        return(pre_screen_config_opt_enter(utf8string, utf8string_size, utf8prompt,
  					 escape_list, help, flags));
  
--- 361,367 ----
  	       (escape_list && escape_list[0].ch != -1 && escape_list[0].label)
  		 ? escape_list[0].label: ""));
  
!     if(!ps_global->ttyo || ps_global->send_immediately)
        return(pre_screen_config_opt_enter(utf8string, utf8string_size, utf8prompt,
  					 escape_list, help, flags));
  
***************
*** 1153,1162 ****
  		}
  	    }
  	}
! 
  	if(!*ps_global->initial_cmds && ps_global->free_initial_cmds){
  	    fs_give((void **) &ps_global->free_initial_cmds);
  	    ps_global->initial_cmds = NULL;
  	}
  
  	return(ret);
--- 1208,1218 ----
  		}
  	    }
  	}
! 	ps_global->initial_cmds_offset++;
  	if(!*ps_global->initial_cmds && ps_global->free_initial_cmds){
  	    fs_give((void **) &ps_global->free_initial_cmds);
  	    ps_global->initial_cmds = NULL;
+ 	    firsttime = (char) 1;
  	}
  
  	return(ret);
diff -rc alpine-2.00/alpine/osdep/termin.gen.h alpine-2.00.I.USE/alpine/osdep/termin.gen.h
*** alpine-2.00/alpine/osdep/termin.gen.h	2007-12-18 10:29:24.000000000 -0800
--- alpine-2.00.I.USE/alpine/osdep/termin.gen.h	2011-02-07 20:33:42.000000000 -0800
***************
*** 32,37 ****
--- 32,38 ----
  int	key_recorder(int);
  int	key_playback(int);
  int	recent_keystroke(int *, char *, size_t);
+ void	fake_config_screen(struct ttyo **);
  int	init_tty_driver(struct pine *);
  void	end_tty_driver(struct pine *);
  int	PineRaw(int);
diff -rc alpine-2.00/alpine/osdep/termin.unx.c alpine-2.00.I.USE/alpine/osdep/termin.unx.c
*** alpine-2.00/alpine/osdep/termin.unx.c	2008-03-26 10:27:45.000000000 -0700
--- alpine-2.00.I.USE/alpine/osdep/termin.unx.c	2011-02-07 20:33:42.000000000 -0800
***************
*** 110,115 ****
--- 110,117 ----
  int
  init_tty_driver(struct pine *ps)
  {
+    if(ps->send_immediately)
+      return 0;
  #ifdef	MOUSE
      if(F_ON(F_ENABLE_MOUSE, ps_global))
        init_mouse();
***************
*** 676,681 ****
--- 678,686 ----
  void
  init_keyboard(int use_fkeys)
  {
+     if (ps_global->send_immediately)
+ 	return;
+ 
      if(use_fkeys && (!strucmp(term_name,"vt102")
  		     || !strucmp(term_name,"vt100")))
        printf("\033\133\071\071\150");
***************
*** 693,698 ****
--- 698,706 ----
  void
  end_keyboard(int use_fkeys)
  {
+     if(ps_global->send_immediately)
+ 	return;
+ 
      if(use_fkeys && (!strcmp(term_name, "vt102")
  		     || !strcmp(term_name, "vt100"))){
  	printf("\033\133\071\071\154");
diff -rc alpine-2.00/alpine/osdep/termout.unx.c alpine-2.00.I.USE/alpine/osdep/termout.unx.c
*** alpine-2.00/alpine/osdep/termout.unx.c	2008-03-04 12:41:47.000000000 -0800
--- alpine-2.00.I.USE/alpine/osdep/termout.unx.c	2011-02-07 20:33:42.000000000 -0800
***************
*** 205,210 ****
--- 205,213 ----
  void
  init_screen(void)
  {
+     if(ps_global->send_immediately)
+ 	return;
+ 
      if(_termcap_init)			/* init using termcap's rule */
        tputs(_termcap_init, 1, outchar);
  
***************
*** 312,317 ****
--- 315,323 ----
  {
      int footer_rows_was_one = 0;
  
+     if(ps_global->send_immediately)
+       return;
+ 
      if(!panicking()){
  
  	dprint((9, "end_screen called\n"));
***************
*** 366,372 ****
      _line = 0;	/* clear leaves us at top... */
      _col  = 0;
  
!     if(ps_global->in_init_seq)
        return;
  
      mark_status_unknown();
--- 372,378 ----
      _line = 0;	/* clear leaves us at top... */
      _col  = 0;
  
!     if(ps_global->in_init_seq || ps_global->send_immediately)
        return;
  
      mark_status_unknown();
diff -rc alpine-2.00/alpine/radio.c alpine-2.00.I.USE/alpine/radio.c
*** alpine-2.00/alpine/radio.c	2007-08-16 15:25:10.000000000 -0700
--- alpine-2.00.I.USE/alpine/radio.c	2011-02-07 20:33:42.000000000 -0800
***************
*** 121,127 ****
      int	  rv, width;
      size_t len;
  
!     if(!ps_global->ttyo)
        return(pre_screen_config_want_to(question, dflt, on_ctrl_C));
  #ifdef _WINDOWS
      if (mswin_usedialog ()) {
--- 121,127 ----
      int	  rv, width;
      size_t len;
  
!     if(!ps_global->ttyo || ps_global->send_immediately)
        return(pre_screen_config_want_to(question, dflt, on_ctrl_C));
  #ifdef _WINDOWS
      if (mswin_usedialog ()) {
diff -rc alpine-2.00/alpine/reply.c alpine-2.00.I.USE/alpine/reply.c
*** alpine-2.00/alpine/reply.c	2008-06-03 08:54:15.000000000 -0700
--- alpine-2.00.I.USE/alpine/reply.c	2011-02-07 20:33:47.000000000 -0800
***************
*** 61,67 ****
  #include "../pith/tempfile.h"
  #include "../pith/busy.h"
  #include "../pith/ablookup.h"
! 
  
  /*
   * Internal Prototypes
--- 61,68 ----
  #include "../pith/tempfile.h"
  #include "../pith/busy.h"
  #include "../pith/ablookup.h"
! #include "../pith/copyaddr.h"
! #include "../pith/rules.h"
  
  /*
   * Internal Prototypes
***************
*** 108,118 ****
      long        msgno, j, totalm, rflags, *seq = NULL;
      int         i, include_text = 0, times = -1, warned = 0, rv = 0,
  		flags = RSF_QUERY_REPLY_ALL, reply_raw_body = 0;
!     int         rolemsg = 0, copytomsg = 0;
      gf_io_t     pc;
      PAT_STATE   dummy;
      REDRAFT_POS_S *redraft_pos = NULL;
      ACTION_S   *role = NULL, *nrole;
  #if	defined(DOS) && !defined(_WINDOWS)
      char *reserve;
  #endif
--- 109,120 ----
      long        msgno, j, totalm, rflags, *seq = NULL;
      int         i, include_text = 0, times = -1, warned = 0, rv = 0,
  		flags = RSF_QUERY_REPLY_ALL, reply_raw_body = 0;
!     int         rolemsg = 0, copytomsg = 0, do_role_early = 0;
      gf_io_t     pc;
      PAT_STATE   dummy;
      REDRAFT_POS_S *redraft_pos = NULL;
      ACTION_S   *role = NULL, *nrole;
+     RULE_RESULT *rule;
  #if	defined(DOS) && !defined(_WINDOWS)
      char *reserve;
  #endif
***************
*** 138,143 ****
--- 140,208 ----
         && F_ON(F_ENABLE_FULL_HDR_AND_TEXT, ps_global))
        reply_raw_body = 1;
  
+     /* Setup possible role */
+     if(role_arg)
+       role = copy_action(role_arg);
+ 
+     if(!role && F_ON(F_ENABLE_EDIT_REPLY_INDENT, pine_state)){
+ 	for(msgno = mn_first_cur(pine_state->msgmap);
+ 	    msgno > 0L;  msgno = mn_next_cur(pine_state->msgmap)){
+ 
+ 	    env = pine_mail_fetchstructure(pine_state->mail_stream,
+ 					   mn_m2raw(pine_state->msgmap, msgno),
+ 					   NULL);
+ 	    if(!env) {
+ 		q_status_message1(SM_ORDER,3,4,
+ 			    _("Error fetching message %s. Can't reply to it."),
+ 				long2string(msgno));
+ 		goto done_early;
+ 	    }
+ 
+ 	    if(rule = get_result_rule(V_REPLY_INDENT_RULES, FOR_COMPOSE , env)){
+ 	        RULELIST *list = get_rulelist_from_code(V_REPLY_INDENT_RULES,
+                                                 ps_global->rule_list);
+ 	        RULE_S *prule = get_rule(list, rule->number);
+ 		if(condition_contains_token(prule->condition, ROLE_TOKEN))
+ 		  do_role_early++;
+ 		if(rule->result)
+ 		  fs_give((void **)&rule->result);
+ 		fs_give((void **)&rule);
+ 	    }
+ 	}
+     }
+ 
+     if(do_role_early){
+ 	rflags = ROLE_REPLY;
+ 	if(!role && nonempty_patterns(rflags, &dummy)){
+ 	    /* setup default role */
+ 	    nrole = NULL;
+ 	    j = mn_first_cur(pine_state->msgmap);
+ 	    do {
+ 		role = nrole;
+ 		nrole = set_role_from_msg(pine_state, rflags,
+ 					  mn_m2raw(pine_state->msgmap, j),
+ 					  NULL);
+ 	    } while(nrole && (!role || nrole == role)
+ 		    && (j=mn_next_cur(pine_state->msgmap)) > 0L);
+ 
+ 	    if(!role || nrole == role)
+ 	      role = nrole;
+ 	    else
+ 	      role = NULL;
+ 
+ 	    if(confirm_role(rflags, &role))
+ 	      role = combine_inherited_role(role);
+ 	    else{				/* cancel reply */
+ 		role = NULL;
+ 		cmd_cancelled("Reply");
+ 		goto done_early;
+ 	    }
+ 	}
+     }
+ 
+     if (role)
+ 	ps_global->role = cpystr(role->nick); /* remember the role */
+ 
      /*
       * We may have to loop through first to figure out what default
       * reply-indent-string to offer...
***************
*** 229,235 ****
  	if(!times){		/* only first time */
  	    char *p = cpystr(prefix);
  
! 	    if((include_text=reply_text_query(pine_state,totalm,&prefix)) < 0)
  	      goto done_early;
  	    
  	    /* edited prefix? */
--- 294,300 ----
  	if(!times){		/* only first time */
  	    char *p = cpystr(prefix);
  
! 	    if((include_text=reply_text_query(pine_state,totalm,env,&prefix)) < 0)
  	      goto done_early;
  	    
  	    /* edited prefix? */
***************
*** 285,292 ****
  		outgoing->subject = cpystr("Re: several messages");
  	    }
  	}
! 	else
! 	  outgoing->subject = reply_subject(env->subject, NULL, 0);
      }
  
      /* fill reply header */
--- 350,367 ----
  		outgoing->subject = cpystr("Re: several messages");
  	    }
  	}
! 	else{
! 	   RULE_RESULT *rule;
! 	   rule = get_result_rule(V_RESUB_RULES,FOR_RESUB|FOR_TRIM , env);
! 	   if (rule){
! 	     outgoing->subject = reply_subject(rule->result, NULL, 0);
! 	     if (rule->result)
! 	        fs_give((void **)&rule->result);
! 	     fs_give((void **)&rule);
! 	   }
! 	   else
! 	       outgoing->subject = reply_subject(env->subject, NULL, 0);
! 	}
      }
  
      /* fill reply header */
***************
*** 305,315 ****
      if(sp_expunge_count(pine_state->mail_stream))	/* cur msg expunged */
        goto done_early;
  
!     /* Setup possible role */
!     if(role_arg)
!       role = copy_action(role_arg);
  
!     if(!role){
  	rflags = ROLE_REPLY;
  	if(nonempty_patterns(rflags, &dummy)){
  	    /* setup default role */
--- 380,392 ----
      if(sp_expunge_count(pine_state->mail_stream))	/* cur msg expunged */
        goto done_early;
  
!     if (ps_global->reply.role_chosen){
!       if(role_arg)
!         free_action(&role);
!       role = ps_global->reply.role_chosen;
!     }
  
!     if(!role && !do_role_early){
  	rflags = ROLE_REPLY;
  	if(nonempty_patterns(rflags, &dummy)){
  	    /* setup default role */
***************
*** 545,553 ****
  		goto done_early;
  	    }
  
! 	    if(orig_body == NULL || orig_body->type == TYPETEXT || reply_raw_body) {
  		reply_delimiter(env, role, pc);
! 		if(F_ON(F_INCLUDE_HEADER, pine_state))
  		  reply_forward_header(pine_state->mail_stream,
  				       mn_m2raw(pine_state->msgmap,msgno),
  				       NULL, env, pc, prefix);
--- 622,631 ----
  		goto done_early;
  	    }
  
! 	    if(orig_body == NULL || orig_body->type == TYPETEXT || reply_raw_body
! 		|| !ps_global->reply.attach) {
  		reply_delimiter(env, role, pc);
! 		if(ps_global->reply.inchdr)
  		  reply_forward_header(pine_state->mail_stream,
  				       mn_m2raw(pine_state->msgmap,msgno),
  				       NULL, env, pc, prefix);
***************
*** 566,572 ****
  		   && orig_body->nested.part->body.type == TYPETEXT) {
  		    /*---- First part of the message is text -----*/
  		    reply_delimiter(env, role, pc);
! 		    if(F_ON(F_INCLUDE_HEADER, pine_state))
  		      reply_forward_header(pine_state->mail_stream,
  					   mn_m2raw(pine_state->msgmap,
  						    msgno),
--- 644,650 ----
  		   && orig_body->nested.part->body.type == TYPETEXT) {
  		    /*---- First part of the message is text -----*/
  		    reply_delimiter(env, role, pc);
! 		    if(ps_global->reply.inchdr)
  		      reply_forward_header(pine_state->mail_stream,
  					   mn_m2raw(pine_state->msgmap,
  						    msgno),
***************
*** 720,725 ****
--- 798,806 ----
      if(prefix)
        fs_give((void **)&prefix);
  
+     if (ps_global->role)
+ 	fs_give((void **)&ps_global->role);
+ 
      if(fcc)
        fs_give((void **) &fcc);
  
***************
*** 875,881 ****
  
  	prompt[sizeof(prompt)-1] = '\0';
  
! 	cmd = radio_buttons(prompt, -FOOTER_ROWS(ps_global), ekey,
  			    'y', 'x', help, RB_NORM);
  
  	switch(cmd){
--- 956,963 ----
  
  	prompt[sizeof(prompt)-1] = '\0';
  
! 	cmd = ps_global->send_immediately ? 'n' :
! 		radio_buttons(prompt, -FOOTER_ROWS(ps_global), ekey,
  			    'y', 'x', help, RB_NORM);
  
  	switch(cmd){
***************
*** 930,937 ****
  int
  reply_to_all_query(int *flagp)
  {
!     switch(want_to("Reply to all recipients",
! 		   'n', 'x', NO_HELP, WT_SEQ_SENSITIVE)){
        case 'x' :
  	return(-1);
  
--- 1012,1047 ----
  int
  reply_to_all_query(int *flagp)
  {
!     char prompt[80];
!     ESCKEY_S  ekey[4];
!     char cmd;
! 
!     ekey[0].name  = "Y";
!     ekey[0].ch = 'y';
!     ekey[0].rval = 'y';
!     ekey[0].label = N_("Yes");
!     ekey[1].name  = "N";
!     ekey[1].ch = 'n';
!     ekey[1].rval = 'n';
!     ekey[1].label = N_("No");
!     ekey[2].name = "P";
!     ekey[2].ch = 'p';
!     ekey[2].rval = 'p';
!     ekey[3].ch = -1;
! 
!     ps_global->preserve = F_ON(F_PRESERVE_ORIGINAL_FIELD, ps_global);
! 
! 
! loop:
!     ekey[2].label = ps_global->preserve ? N_("Not Preserve") : N_("Preserve");
!     snprintf(prompt, sizeof(prompt), _("Reply to all recipients%s"),
! 		ps_global->preserve ? _(" (preserving fields)? ") : "? ");
! 
!     prompt[sizeof(prompt)-1] = '\0';
! 
!     switch(cmd = radio_buttons(prompt, -FOOTER_ROWS(ps_global), ekey,
! 				'n', 'x', h_preserve_field, RB_NORM)){
! 
        case 'x' :
  	return(-1);
  
***************
*** 942,947 ****
--- 1052,1062 ----
        case 'n' :		/* clear reply-all bit */
  	(*flagp) &= ~RSF_FORCE_REPLY_ALL;
  	break;
+ 
+       case 'p' :
+         ps_global->preserve = !ps_global->preserve;
+ 	goto loop;		/* ugly, but saves me a variable */
+ 	break;
      }
  
      return(0);
***************
*** 969,1016 ****
   *	     0 if we're NOT to include the text
   *	    -1 on cancel or error
   */
  int
! reply_text_query(struct pine *ps, long int many, char **prefix)
  {
      int ret, edited = 0;
!     static ESCKEY_S rtq_opts[] = {
! 	{'y', 'y', "Y", N_("Yes")},
! 	{'n', 'n', "N", N_("No")},
! 	{-1, 0, NULL, NULL},	                  /* may be overridden below */
! 	{-1, 0, NULL, NULL}
!     };
  
      if(F_ON(F_AUTO_INCLUDE_IN_REPLY, ps)
!        && F_OFF(F_ENABLE_EDIT_REPLY_INDENT, ps))
        return(1);
  
!     while(1){
! 	if(many > 1L)
! 	  /* TRANSLATORS: The final three %s's can probably be safely ignored */
! 	  snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Include %s original messages in Reply%s%s%s? "),
! 		comatose(many),
! 		F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? " (using \"" : "",
! 		F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? *prefix : "",
! 		F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? "\")" : "");
! 	else
! 	  snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Include original message in Reply%s%s%s? "),
  		F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? " (using \"" : "",
  		F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? *prefix : "",
  		F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? "\")" : "");
  
! 	if(F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps)){
! 	    rtq_opts[2].ch    = ctrl('R');
! 	    rtq_opts[2].rval  = 'r';
! 	    rtq_opts[2].name  = "^R";
! 	    rtq_opts[2].label = N_("Edit Indent String");
! 	}
! 	else
! 	  rtq_opts[2].ch    = -1;
  
  	switch(ret = radio_buttons(tmp_20k_buf, 
  				   ps->ttyo->screen_rows > 4
  				     ? -FOOTER_ROWS(ps_global) : -1,
! 				   rtq_opts,
  				   (edited || F_ON(F_AUTO_INCLUDE_IN_REPLY, ps))
  				       ? 'y' : 'n',
  				   'x', NO_HELP, RB_SEQ_SENSITIVE)){
--- 1084,1195 ----
   *	     0 if we're NOT to include the text
   *	    -1 on cancel or error
   */
+ #define MAX_REPLY_OPTIONS 8
  int
! reply_text_query(struct pine *ps, long int many, ENVELOPE *env, char **prefix)
  {
      int ret, edited = 0;
!     static ESCKEY_S compose_style[MAX_REPLY_OPTIONS];
!     int	ekey_num;
!     int	orig_sf;
! 
!     orig_sf = *prefix && **prefix ? (F_OFF(F_QUELL_FLOWED_TEXT, ps)
! 		&& F_OFF(F_STRIP_WS_BEFORE_SEND, ps)
! 		&& (strcmp(*prefix, "> ") == 0
! 			|| strcmp(*prefix, ">") == 0)) : 0;
! 
!     ps_global->reply.no_send_flowed = !orig_sf;
!     ps_global->reply.role_chosen = NULL;
!     ps_global->reply.strip = ps->full_header == 0
! 		&& (F_ON(F_ENABLE_STRIP_SIGDASHES, ps)
! 			|| F_ON(F_ENABLE_SIGDASHES, ps));
!     ps_global->reply.attach = F_ON(F_ATTACHMENTS_IN_REPLY, ps);
!     ps_global->reply.inchdr = F_ON(F_INCLUDE_HEADER, ps);
  
      if(F_ON(F_AUTO_INCLUDE_IN_REPLY, ps)
!         && F_OFF(F_ENABLE_EDIT_REPLY_INDENT, ps) && F_OFF(F_ALT_REPLY_MENU,ps))
        return(1);
  
!     while(1){ 
! 	  /* TRANSLATORS: The final five %s's can probably be safely ignored */
! 	snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Include %s original messages in Reply%s%s%s%s%s%s%s? "),
! 		(many > 1L) ? comatose(many) : "",
! 		(many > 1L) ? " " : "",
! 		(many > 1L) ? "s" : "",
  		F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? " (using \"" : "",
  		F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? *prefix : "",
+ 		ps_global->reply.role_chosen ? "\" and role \"" : "",
+ 		ps_global->reply.role_chosen ? ps_global->reply.role_chosen->nick : "",
  		F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? "\")" : "");
  
! 	ekey_num = 0;
! 	compose_style[ekey_num].ch    = 'y';
! 	compose_style[ekey_num].rval  = 'y';
! 	compose_style[ekey_num].name  = "Y";
! 	compose_style[ekey_num++].label = N_("Yes");
! 
! 	compose_style[ekey_num].ch    = 'n';
! 	compose_style[ekey_num].rval  = 'n';
! 	compose_style[ekey_num].name  = "N";
! 	compose_style[ekey_num++].label = N_("No");
! 
! 	if (F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps)){
! 	   compose_style[ekey_num].ch      = ctrl('R');
! 	   compose_style[ekey_num].rval    = 'r';
! 	   compose_style[ekey_num].name    = "^R";
! 	   compose_style[ekey_num++].label = N_("Edit Indent String");
! 	}
! 
! 	/***** Alternate Reply Menu ********/
! 
! 	if (F_ON(F_ALT_REPLY_MENU, ps)){
! 	     unsigned which_help;
! 
! 	   if (F_ON(F_ENABLE_STRIP_SIGDASHES, ps) ||
! 		F_ON(F_ENABLE_SIGDASHES, ps)){
! 	      compose_style[ekey_num].ch      = 's';
! 	      compose_style[ekey_num].rval    = 'S';
! 	      compose_style[ekey_num].name    = "S";
! 	      compose_style[ekey_num++].label = ps_global->reply.strip 
! 						? N_("No Strip"): N_("Strip Sig");
! 	   }
! 
! 	   compose_style[ekey_num].ch      = 'r';
! 	   compose_style[ekey_num].rval    = 'R';
! 	   compose_style[ekey_num].name    = "R";
! 	   compose_style[ekey_num++].label = N_("Set Role");
! 
! 	   if(orig_sf){
! 	      compose_style[ekey_num].ch      = 'f';
! 	      compose_style[ekey_num].rval    = 'F';
! 	      compose_style[ekey_num].name    = "F";
! 	      compose_style[ekey_num++].label = ps_global->reply.no_send_flowed 
! 						? N_("Quell Flow") : N_("Send Flowd");
! 	   }
! 
! 	   compose_style[ekey_num].ch      = 'a';
! 	   compose_style[ekey_num].rval    = 'A';
! 	   compose_style[ekey_num].name    = "A";
! 	   compose_style[ekey_num++].label = ps_global->reply.attach 
! 						? N_("No Attach"): N_("Inc Attac");
! 
! 	   compose_style[ekey_num].ch      = 'h';
! 	   compose_style[ekey_num].rval    = 'H';
! 	   compose_style[ekey_num].name    = "H";
! 	   compose_style[ekey_num++].label = ps_global->reply.inchdr 
! 						? N_("No Header") : N_("Inc Head");
! 
! 	}
! 	compose_style[ekey_num].ch    = -1;
! 	compose_style[ekey_num].name  = NULL;
! 	compose_style[ekey_num].label = NULL;
! 
! 	/***** End Alt Reply Menu  *********/
  
  	switch(ret = radio_buttons(tmp_20k_buf, 
  				   ps->ttyo->screen_rows > 4
  				     ? -FOOTER_ROWS(ps_global) : -1,
! 				   compose_style,
  				   (edited || F_ON(F_AUTO_INCLUDE_IN_REPLY, ps))
  				       ? 'y' : 'n',
  				   'x', NO_HELP, RB_SEQ_SENSITIVE)){
***************
*** 1018,1023 ****
--- 1197,1242 ----
  	    cmd_cancelled("Reply");
  	    return(-1);
  
+ 	  case 'F':
+ 		ps_global->reply.no_send_flowed = (ps_global->reply.no_send_flowed + 1) % 2;
+ 		break;
+ 
+ 	  case 'S':
+ 		ps_global->reply.strip = (ps_global->reply.strip + 1) % 2;
+ 	   break;
+ 
+ 	  case 'A':
+ 		ps_global->reply.attach = (ps_global->reply.attach + 1) % 2;
+ 	   break;
+ 
+ 	  case 'H':
+ 		ps_global->reply.inchdr = (ps_global->reply.inchdr + 1) % 2;
+ 	   break;
+ 
+ 
+ 	  case 'R':
+ 	  {
+            void (*prev_screen)(struct pine *) = ps->prev_screen,
+                (*redraw)(void) = ps->redrawer;
+            ps->redrawer = NULL;
+            ps->next_screen = SCREEN_FUN_NULL;
+            if(role_select_screen(ps, &ps_global->reply.role_chosen, 1) < 0){
+              cmd_cancelled("Reply");
+              ps->next_screen = prev_screen;
+              ps->redrawer = redraw;
+ 	     if (ps->redrawer)
+ 		(*ps->redrawer)();
+ 	     continue;
+            }
+            ps->next_screen = prev_screen;
+            ps->redrawer = redraw;
+            if(ps_global->reply.role_chosen)
+               ps_global->reply.role_chosen = combine_inherited_role(ps_global->reply.role_chosen);
+ 	  }
+ 	  if (ps->redrawer)
+ 	     (*ps->redrawer)();
+ 	  break;
+ 
  	  case 'r':
  	    if(prefix && *prefix){
  		int  done = 0;
***************
*** 1041,1046 ****
--- 1260,1271 ----
  			if(flags & OE_USER_MODIFIED){
  			    fs_give((void **)prefix);
  			    *prefix = removing_quotes(cpystr(buf));
+ 			    orig_sf = *prefix && **prefix ?
+ 					   (F_OFF(F_QUELL_FLOWED_TEXT, ps)
+ 					&& F_OFF(F_STRIP_WS_BEFORE_SEND, ps)
+ 					&& (strcmp(*prefix, "> ") == 0
+ 					|| strcmp(*prefix, ">") == 0)) : 0;
+ 			    ps_global->reply.no_send_flowed = !orig_sf;
  			    edited = 1;
  			}
  
***************
*** 1164,1172 ****
  	}
  	else if(!outgoing->newsgroups)
  	  outgoing->newsgroups = cpystr(env->newsgroups);
- 	if(!IS_NEWS(ps_global->mail_stream))
- 	  q_status_message(SM_ORDER, 2, 3,
-  _("Replying to message that MAY or MAY NOT have been posted to newsgroup"));
      }
  
      return(ret);
--- 1389,1394 ----
***************
*** 1440,1448 ****
  	}
      }
  
!     if(role)
        q_status_message1(SM_ORDER, 3, 4,
  			_("Forwarding using role \"%s\""), role->nick);
  
      if(role && role->template){
  	char *filtered;
--- 1662,1675 ----
  	}
      }
  
!     if (ps_global->role)
!       fs_give((void **)&ps_global->role);
! 
!     if(role){
        q_status_message1(SM_ORDER, 3, 4,
  			_("Forwarding using role \"%s\""), role->nick);
+       ps_global->role = cpystr(role->nick);
+     }
  
      if(role && role->template){
  	char *filtered;
***************
*** 1674,1679 ****
--- 1901,1907 ----
  #if	defined(DOS) && !defined(_WINDOWS)
      free((void *)reserve);
  #endif
+     outgoing->sparep = env && env->from ? copyaddr(env->from) : NULL;
      pine_send(outgoing, &body, "FORWARD MESSAGE",
  	      role, NULL, &reply, redraft_pos,
  	      NULL, NULL, 0);
***************
*** 2426,2431 ****
--- 2654,2661 ----
  {
      int rv;
      
+     if(ps_global->send_immediately)
+       return 0;
      clear_cursor_pos();			/* can't know where cursor is */
      mark_status_dirty();		/* don't count on cached text */
      fix_windsize(ps_global);
***************
*** 2485,2490 ****
--- 2715,2721 ----
  resize_for_pico(void)
  {
      fix_windsize(ps_global);
+     ps_global->resize_for_pico = 1;
  }
  
  
diff -rc alpine-2.00/alpine/reply.h alpine-2.00.I.USE/alpine/reply.h
*** alpine-2.00/alpine/reply.h	2006-11-15 20:08:15.000000000 -0800
--- alpine-2.00.I.USE/alpine/reply.h	2011-02-07 20:33:42.000000000 -0800
***************
*** 28,34 ****
  int	    confirm_role(long, ACTION_S **);
  int	    reply_to_all_query(int *);
  int	    reply_using_replyto_query(void);
! int	    reply_text_query(struct pine *, long, char **);
  int	    reply_news_test(ENVELOPE *, ENVELOPE *);
  char       *get_signature_file(char *, int, int, int);
  int	    forward(struct pine *, ACTION_S *);
--- 28,34 ----
  int	    confirm_role(long, ACTION_S **);
  int	    reply_to_all_query(int *);
  int	    reply_using_replyto_query(void);
! int	    reply_text_query(struct pine *, long, ENVELOPE *, char **);
  int	    reply_news_test(ENVELOPE *, ENVELOPE *);
  char       *get_signature_file(char *, int, int, int);
  int	    forward(struct pine *, ACTION_S *);
diff -rc alpine-2.00/alpine/roleconf.c alpine-2.00.I.USE/alpine/roleconf.c
*** alpine-2.00/alpine/roleconf.c	2008-02-27 17:04:46.000000000 -0800
--- alpine-2.00.I.USE/alpine/roleconf.c	2011-02-07 20:33:42.000000000 -0800
***************
*** 139,146 ****
--- 139,151 ----
  
      if(!(nonempty_patterns(rflags, &pstate) &&
           first_pattern(&pstate))){
+        if (!ps->send_immediately)
  	q_status_message(SM_ORDER, 0, 3,
  			 _("No roles available. Use Setup/Rules to add roles."));
+ 	else{
+ 	   printf(_("No roles available. Use Setup/Rules to add roles."));
+ 	   exit(-1);
+ 	}
  	return(ret);
      }
  
***************
*** 4477,4487 ****
  	ctmp->tool		  = role_sort_tool;
  	ctmp->valoffset	    	  = rindent;
  	ctmp->flags              |= CF_NOSELECT;
! 	ctmp->value     = cpystr(set_choose);				\
  
  	pval = PVAL(&sort_act_var, ew);
  	if(pval)
! 	  decode_sort(pval, &def_sort, &def_sort_rev);
  
  	/* allow user to set their default sort order */
  	new_confline(&ctmp)->var = &sort_act_var;
--- 4482,4492 ----
  	ctmp->tool		  = role_sort_tool;
  	ctmp->valoffset	    	  = rindent;
  	ctmp->flags              |= CF_NOSELECT;
! 	ctmp->value     = cpystr(set_choose);
  
  	pval = PVAL(&sort_act_var, ew);
  	if(pval)
! 	  decode_sort(pval, &def_sort, &def_sort_rev, 0);
  
  	/* allow user to set their default sort order */
  	new_confline(&ctmp)->var = &sort_act_var;
***************
*** 4491,4497 ****
  	ctmp->tool	      = role_sort_tool;
  	ctmp->valoffset	      = rindent;
  	ctmp->varmem	      = -1;
! 	ctmp->value	      = generalized_sort_pretty_value(ps, ctmp, 0);
  
  	for(j = 0; j < 2; j++){
  	    for(i = 0; ps->sort_types[i] != EndofList; i++){
--- 4496,4502 ----
  	ctmp->tool	      = role_sort_tool;
  	ctmp->valoffset	      = rindent;
  	ctmp->varmem	      = -1;
! 	ctmp->value	      = generalized_sort_pretty_value(ps, ctmp, 0, 0);
  
  	for(j = 0; j < 2; j++){
  	    for(i = 0; ps->sort_types[i] != EndofList; i++){
***************
*** 4503,4509 ****
  		ctmp->valoffset	      = rindent;
  		ctmp->varmem	      = i + (j * EndofList);
  		ctmp->value	      = generalized_sort_pretty_value(ps, ctmp,
! 								      0);
  	    }
  	}
  
--- 4508,4514 ----
  		ctmp->valoffset	      = rindent;
  		ctmp->varmem	      = i + (j * EndofList);
  		ctmp->value	      = generalized_sort_pretty_value(ps, ctmp,
! 								      0, 0);
  	    }
  	}
  
***************
*** 5436,5442 ****
  	  (*result)->patgrp->stat_boy = PAT_STAT_EITHER;
  
  	if(sort_act){
! 	    decode_sort(sort_act, &def_sort, &def_sort_rev);
  	    (*result)->action->sort_is_set = 1;
  	    (*result)->action->sortorder = def_sort;
  	    (*result)->action->revsort = (def_sort_rev ? 1 : 0);
--- 5441,5447 ----
  	  (*result)->patgrp->stat_boy = PAT_STAT_EITHER;
  
  	if(sort_act){
! 	    decode_sort(sort_act, &def_sort, &def_sort_rev, 0);
  	    (*result)->action->sort_is_set = 1;
  	    (*result)->action->sortorder = def_sort;
  	    (*result)->action->revsort = (def_sort_rev ? 1 : 0);
***************
*** 7705,7710 ****
--- 7710,7720 ----
  	    if(apval)
  	      *apval = (role && role->nick) ? cpystr(role->nick) : NULL;
  
+ 	    if (ps_global->role)
+ 		fs_give((void **)&ps_global->role);
+ 	    if (role && role->nick)
+ 		ps_global->role = cpystr(role->nick);
+ 
  	    if((*cl)->value)
  	      fs_give((void **)&((*cl)->value));
  
diff -rc alpine-2.00/alpine/send.c alpine-2.00.I.USE/alpine/send.c
*** alpine-2.00/alpine/send.c	2008-06-30 15:03:35.000000000 -0700
--- alpine-2.00.I.USE/alpine/send.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 62,68 ****
  #include "../pith/mimetype.h"
  #include "../pith/send.h"
  #include "../pith/smime.h"
! 
  
  typedef struct body_particulars {
      unsigned short     type, encoding, had_csp;
--- 62,68 ----
  #include "../pith/mimetype.h"
  #include "../pith/send.h"
  #include "../pith/smime.h"
! #include "../pith/rules.h"
  
  typedef struct body_particulars {
      unsigned short     type, encoding, had_csp;
***************
*** 98,103 ****
--- 98,104 ----
  void       free_body_particulars(BODY_PARTICULARS_S *);
  long	   message_format_for_pico(long, int (*)(int));
  int	   send_exit_for_pico(struct headerentry *, void (*)(void), int, char **);
+ void	   new_thread_on_blank_subject(void);
  char      *choose_a_priority(char *);
  int        dont_flow_this_time(void);
  int	   mime_type_for_pico(char *);
***************
*** 237,242 ****
--- 238,248 ----
  	role->nick = cpystr("Default Role");
      }
  
+     if (ps_global->role)
+        fs_give((void **)&ps_global->role);  
+ 
+     ps_global->role = cpystr(role->nick);
+ 
      pine_state->redrawer = NULL;
      compose_mail(NULL, NULL, role, NULL, NULL);
      free_action(&role);
***************
*** 446,453 ****
  
  	      ps_global->next_screen = prev_screen;
  	      ps_global->redrawer = redraw;
! 	      if(role)
  		role = combine_inherited_role(role);
  	    }
  	    break;
  	  
--- 452,463 ----
  
  	      ps_global->next_screen = prev_screen;
  	      ps_global->redrawer = redraw;
! 	      if (ps_global->role)
! 		  fs_give((void **)&ps_global->role);  
! 	      if(role){
  		role = combine_inherited_role(role);
+ 		ps_global->role = cpystr(role->nick);
+ 	      }
  	    }
  	    break;
  	  
***************
*** 612,617 ****
--- 622,628 ----
          if(given_to)
  	  rfc822_parse_adrlist(&outgoing->to, given_to, ps_global->maildomain);
  
+         outgoing->subject = cpystr(ps_global->subject);
          outgoing->message_id = generate_message_id();
  
  	/*
***************
*** 642,650 ****
  	    }
  	}
  
! 	if(role)
  	  q_status_message1(SM_ORDER, 3, 4, _("Composing using role \"%s\""),
  			    role->nick);
  
  	/*
  	 * The type of storage object allocated below is vitally
--- 653,666 ----
  	    }
  	}
  
! 	if (ps_global->role)
! 	    fs_give((void **)&ps_global->role);
! 
! 	if(role){
  	  q_status_message1(SM_ORDER, 3, 4, _("Composing using role \"%s\""),
  			    role->nick);
+ 	  ps_global->role = cpystr(role->nick);
+ 	}
  
  	/*
  	 * The type of storage object allocated below is vitally
***************
*** 910,916 ****
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
    {"From    : ",  "From",        h_composer_from,       10, 0, NULL,
     build_address, NULL, NULL, addr_book_compose,    "To AddrBk", NULL, abook_nickname_complete,
!    0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK},
    {"Reply-To: ",  "Reply To",    h_composer_reply_to,   10, 0, NULL,
     build_address, NULL, NULL, addr_book_compose,    "To AddrBk", NULL, abook_nickname_complete,
     0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK},
--- 926,932 ----
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
    {"From    : ",  "From",        h_composer_from,       10, 0, NULL,
     build_address, NULL, NULL, addr_book_compose,    "To AddrBk", NULL, abook_nickname_complete,
!    0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK},
    {"Reply-To: ",  "Reply To",    h_composer_reply_to,   10, 0, NULL,
     build_address, NULL, NULL, addr_book_compose,    "To AddrBk", NULL, abook_nickname_complete,
     0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK},
***************
*** 1780,1785 ****
--- 1796,1804 ----
      pbf = &pbuf1;
      standard_picobuf_setup(pbf);
  
+     pbf->auto_cmds = ps_global->initial_cmds_backup + 
+ 						ps_global->initial_cmds_offset;
+ 
      /*
       * Cancel any pending initial commands since pico uses a different
       * input routine.  If we didn't cancel them, they would happen after
***************
*** 1816,1821 ****
--- 1835,1842 ----
      pbf->mimetype      = mime_type_for_pico;
      pbf->exittest      = send_exit_for_pico;
      pbf->user_says_noflow = dont_flow_this_time;
+     pbf->newthread     = new_thread_on_blank_subject;
+     ps_global->newthread = 0;	/* reset this value */
      if(F_OFF(F_CANCEL_CONFIRM, ps_global))
        pbf->canceltest    = cancel_for_pico;
  
***************
*** 2301,2306 ****
--- 2322,2332 ----
  			he->rich_header = 0;
  		    }
  		}
+ 		if (F_ON(F_ALLOW_CHANGING_FROM, ps_global) &&
+ 		   !ps_global->never_allow_changing_from){
+ 		  he->display_it  = 1;  /* show it */
+ 		  he->rich_header = 0;
+ 		}
  
  		he_from			= he;
  		break;
***************
*** 2410,2415 ****
--- 2436,2461 ----
  		    removing_trailing_white_space(pf->textbuf);
  		    (void)removing_double_quotes(pf->textbuf);
  		    build_address(pf->textbuf, &addr, NULL, NULL, NULL);
+ 		    if (!strncmp(pf->name,"Lcc",3) && addr && *addr){
+ 			RULE_RESULT *rule;
+ 
+   			outgoing->date = (unsigned char *) cpystr(addr);
+ 			ps_global->procid = cpystr("fwd-lcc");
+ 			rule = get_result_rule(V_FORWARD_RULES,
+ 			           FOR_COMPOSE|FOR_TRIM, outgoing);
+ 			if (rule){
+ 			    addr = cpystr(rule->result);
+ 			    removing_trailing_white_space(addr);
+ 			    (void)removing_extra_stuff(addr);
+ 			    if (rule->result)
+ 				fs_give((void **)&rule->result);
+ 				fs_give((void **)&rule);
+ 			}
+ 			fs_give((void **)&ps_global->procid);
+ 			if (outgoing->date)
+ 			    fs_give((void **)&outgoing->date);
+ 		    }   
+ 
  		    rfc822_parse_adrlist(pf->addr, addr,
  					 ps_global->maildomain);
  		    fs_give((void **)&addr);
***************
*** 2979,2985 ****
  #ifdef _WINDOWS
  	mswin_setwindowmenu (MENU_DEFAULT);
  #endif
! 	fix_windsize(ps_global);
  
  	/*
  	 * Only reinitialize signals if we didn't receive an interesting
--- 3025,3036 ----
  #ifdef _WINDOWS
  	mswin_setwindowmenu (MENU_DEFAULT);
  #endif
! 	if (ps_global->send_immediately){  
! 	   if(ps_global->free_initial_cmds_backup)
! 	      fs_give((void **)&ps_global->free_initial_cmds_backup);
! 	} 
! 	else
! 	   fix_windsize(ps_global);
  
  	/*
  	 * Only reinitialize signals if we didn't receive an interesting
***************
*** 3038,3044 ****
  	if(outgoing->return_path)
  	  mail_free_address(&outgoing->return_path);
  
! 	outgoing->return_path = rfc822_cpy_adr(outgoing->from);
  
  	/*
  	 * Don't ever believe the sender that is there.
--- 3089,3097 ----
  	if(outgoing->return_path)
  	  mail_free_address(&outgoing->return_path);
  
!         outgoing->return_path = F_ON(F_USE_DOMAIN_NAME,ps_global) 
! 				? rfc822_cpy_adr(generate_from())
! 				: rfc822_cpy_adr(outgoing->from);
  
  	/*
  	 * Don't ever believe the sender that is there.
***************
*** 3068,3073 ****
--- 3121,3131 ----
  	    outgoing->sender->host    = cpystr(ps_global->hostname);
  	}
  
+ 	if(ps_global->newthread){
+ 	   if(outgoing->in_reply_to) fs_give((void **)&outgoing->in_reply_to);
+ 	   if(outgoing->references) fs_give((void **)&outgoing->references);
+ 	}
+ 
          /*----- Message is edited, now decide what to do with it ----*/
  	if(editor_result & (COMP_SUSPEND | COMP_GOTHUP | COMP_CANCEL)){
              /*=========== Postpone or Interrupted message ============*/
***************
*** 3710,3719 ****
  	    if(sending_filter_requested
  	       && !filter_message_text(sending_filter_requested, outgoing,
  				       *body, &orig_so, &header)){
! 		q_status_message1(SM_ORDER, 3, 3,
  				 _("Problem filtering!  Nothing sent%s."),
  				 fcc ? " or saved to fcc" : "");
! 		continue;
  	    }
  
              /*------ Actually post  -------*/
--- 3768,3783 ----
  	    if(sending_filter_requested
  	       && !filter_message_text(sending_filter_requested, outgoing,
  				       *body, &orig_so, &header)){
! 		if (!ps_global->send_immediately){
! 		     q_status_message1(SM_ORDER, 3, 3,
  				 _("Problem filtering!  Nothing sent%s."),
  				 fcc ? " or saved to fcc" : "");
! 		     continue;
! 		}
! 		else{
! 		   fprintf(stderr, _("Problem filtering! Nothing sent or saved to Fcc\n"));
! 		   exit(-1);
! 		}
  	    }
  
              /*------ Actually post  -------*/
***************
*** 3957,3962 ****
--- 4021,4028 ----
              /*----- Mail Post FAILED, back to composer -----*/
              if(result & (P_MAIL_LOSE | P_FCC_LOSE)){
  		dprint((1, "Send failed, continuing\n"));
+ 		if (ps_global->send_immediately)
+ 		   exit(1);
  
  		if(result & P_FCC_LOSE){
  		    /*
***************
*** 3991,3996 ****
--- 4057,4063 ----
  	    update_answered_flags(reply);
  
              /*----- Signed, sealed, delivered! ------*/
+          if (!ps_global->send_immediately)
  	    q_status_message(SM_ORDER, 0, 3,
  			     pine_send_status(result, fcc, tmp_20k_buf, SIZEOF_20KBUF, NULL));
  
***************
*** 4360,4365 ****
--- 4427,4442 ----
      return(buf);
  }
  
+ /* Callback from Pico to set the conditions for Alpine to start a new thread
+  */
+ 
+ void
+ new_thread_on_blank_subject(void)
+ {
+   ps_global->newthread = F_ON(F_NEW_THREAD_ON_BLANK_SUBJECT, ps_global);
+ }
+ 
+ 
  
  /*----------------------------------------------------------------------
      Call back for pico to insert the specified message's text
***************
*** 4447,4453 ****
  	return(1);
      }
  
!     if(F_ON(F_SEND_WO_CONFIRM, ps_global)){
  	if(result)
  	  *result = NULL;
  
--- 4524,4530 ----
  	return(1);
      }
  
!     if(!ps_global->send_immediately && F_ON(F_SEND_WO_CONFIRM, ps_global)){
  	if(result)
  	  *result = NULL;
  
***************
*** 4627,4633 ****
  
      opts[i].ch = -1;
  
!     fix_windsize(ps_global);
  
      while(1){
  	if(filters && filters->filter && (p = strindex(filters->filter, ' ')))
--- 4704,4711 ----
  
      opts[i].ch = -1;
  
!     if (!ps_global->send_immediately)
!        fix_windsize(ps_global);
  
      while(1){
  	if(filters && filters->filter && (p = strindex(filters->filter, ' ')))
***************
*** 4809,4815 ****
  	if(double_rad +
  	   ((call_mailer_flags & CM_DSN_SHOW)
  	       ? 4 : F_ON(F_DSN, ps_global) ? 1 : 0) > 11)
! 	  rv = double_radio_buttons(tmp_20k_buf, -FOOTER_ROWS(ps_global), opts,
  			   'y', 'z',
  			   (F_ON(F_DSN, ps_global) && allow_flowed)
  					          ? h_send_prompt_dsn_flowed :
--- 4887,4894 ----
  	if(double_rad +
  	   ((call_mailer_flags & CM_DSN_SHOW)
  	       ? 4 : F_ON(F_DSN, ps_global) ? 1 : 0) > 11)
! 	  rv = ps_global->send_immediately ? 'y' :
! 		double_radio_buttons(tmp_20k_buf, -FOOTER_ROWS(ps_global), opts,
  			   'y', 'z',
  			   (F_ON(F_DSN, ps_global) && allow_flowed)
  					          ? h_send_prompt_dsn_flowed :
***************
*** 4818,4824 ****
  						       h_send_prompt,
  			   RB_NORM);
  	else
! 	  rv = radio_buttons(tmp_20k_buf, -FOOTER_ROWS(ps_global), opts,
  			   'y', 'z',
  			   (double_rad +
  			    ((call_mailer_flags & CM_DSN_SHOW)
--- 4897,4904 ----
  						       h_send_prompt,
  			   RB_NORM);
  	else
! 	  rv = ps_global->send_immediately ? 'y' :
! 		radio_buttons(tmp_20k_buf, -FOOTER_ROWS(ps_global), opts,
  			   'y', 'z',
  			   (double_rad +
  			    ((call_mailer_flags & CM_DSN_SHOW)
***************
*** 5155,5165 ****
--- 5235,5247 ----
  	{'c', 'c', "C", N_("Confirm")},
  	{'n', 'n', "N", N_("No")},
  	{'y', 'y', "", ""},
+ 	{'t', 't', "T", N_("CounT")},
  	{-1, 0, NULL, NULL}
      };
  
      ps_global->redrawer = redraw_pico;
      fix_windsize(ps_global);
+     pbf->curpos[0] = '\0';
      
      while(1){
  	rv = radio_buttons(prompt, -FOOTER_ROWS(ps_global), opts,
***************
*** 5172,5183 ****
  	    q_status_message(SM_INFO, 1, 3, _(" Type \"C\" to cancel message "));
  	    display_message('x');
  	}
  	else
  	  break;
      }
  
      ps_global->redrawer = redraw;
!     return(rstr);
  }
  
  
--- 5254,5269 ----
  	    q_status_message(SM_INFO, 1, 3, _(" Type \"C\" to cancel message "));
  	    display_message('x');
  	}
+ 	else if(rv == 't'){
+ 	    showcpos(1,0);
+ 	    break;
+ 	}
  	else
  	  break;
      }
  
      ps_global->redrawer = redraw;
!     return(pbf->curpos[0] ? pbf->curpos : rstr);
  }
  
  
***************
*** 5204,5210 ****
  
      if(fcmd
         && (cmd=expand_filter_tokens(fcmd, outgoing, &tmpf, &resultf, &mtf,
! 				    &key, &include_hdrs))){
  	if(tmpf){
  	    /*
  	     * We need WRITE_TO_LOCALE here because the user is going to
--- 5290,5296 ----
  
      if(fcmd
         && (cmd=expand_filter_tokens(fcmd, outgoing, &tmpf, &resultf, &mtf,
! 				    &key, &include_hdrs, NULL))){
  	if(tmpf){
  	    /*
  	     * We need WRITE_TO_LOCALE here because the user is going to
***************
*** 5281,5289 ****
  	    if((tmp_so = so_get(PicoText, NULL, EDIT_ACCESS)) != NULL){
  		gf_set_so_writec(&pc, tmp_so);
  		ps_global->mangled_screen = 1;
! 		suspend_busy_cue();
! 		ClearScreen();
! 		fflush(stdout);
  		if(tmpf){
  		    PIPE_S *fpipe;
  
--- 5367,5377 ----
  	    if((tmp_so = so_get(PicoText, NULL, EDIT_ACCESS)) != NULL){
  		gf_set_so_writec(&pc, tmp_so);
  		ps_global->mangled_screen = 1;
! 		if (!ps_global->send_immediately){
! 		   suspend_busy_cue();
! 		   ClearScreen();
! 		   fflush(stdout);
! 		}
  		if(tmpf){
  		    PIPE_S *fpipe;
  
***************
*** 5311,5317 ****
  		}
  		else
  		  errstr = gf_filter(cmd, key ? filter_session_key() : NULL,
! 				     readthis_so, pc, NULL, 0,
  				     pipe_callback);
  
  		if(our_tmpf_so)
--- 5399,5405 ----
  		}
  		else
  		  errstr = gf_filter(cmd, key ? filter_session_key() : NULL,
! 				     readthis_so, pc, NULL, 0, 0,
  				     pipe_callback);
  
  		if(our_tmpf_so)
***************
*** 5395,5402 ****
  		    set_mime_type_by_grope(b);
  		}
  
! 		ClearScreen();
! 		resume_busy_cue(0);
  	    }
  	    else
  	      errstr = "Can't create space for filtered text.";
--- 5483,5492 ----
  		    set_mime_type_by_grope(b);
  		}
  
! 		if (!ps_global->send_immediately){
! 		   ClearScreen();
! 		   resume_busy_cue(0);
! 		}
  	    }
  	    else
  	      errstr = "Can't create space for filtered text.";
***************
*** 5427,5436 ****
  	if(tmp_so)
  	  so_give(&tmp_so);
  
! 	q_status_message1(SM_ORDER | SM_DING, 3, 6, _("Problem filtering: %s"),
  			  errstr);
! 	dprint((1, "Filter FAILED: %s\n",
  	       errstr ? errstr : "?"));
      }
  
      return(errstr == NULL);
--- 5517,5532 ----
  	if(tmp_so)
  	  so_give(&tmp_so);
  
! 	if (!ps_global->send_immediately){
! 	     q_status_message1(SM_ORDER | SM_DING, 3, 6, _("Problem filtering: %s"),
  			  errstr);
! 	     dprint((1, "Filter FAILED: %s\n",
  	       errstr ? errstr : "?"));
+ 	}
+ 	else{
+ 	   fprintf(stderr, _("Filter FAILED: %s\n"), errstr ? errstr : "?");
+ 	   exit(-1);
+ 	}
      }
  
      return(errstr == NULL);
diff -rc alpine-2.00/alpine/setup.c alpine-2.00.I.USE/alpine/setup.c
*** alpine-2.00/alpine/setup.c	2008-01-23 11:15:36.000000000 -0800
--- alpine-2.00.I.USE/alpine/setup.c	2011-02-07 20:33:41.000000000 -0800
***************
*** 257,263 ****
  	    ctmpa->flags             |= CF_NOSELECT;
  	    ctmpa->value = cpystr("---  ----------------------");
  
! 	    decode_sort(pval, &def_sort, &def_sort_rev);
  
  	    for(j = 0; j < 2; j++){
  		for(i = 0; ps->sort_types[i] != EndofList; i++){
--- 257,263 ----
  	    ctmpa->flags             |= CF_NOSELECT;
  	    ctmpa->value = cpystr("---  ----------------------");
  
! 	    decode_sort(pval, &def_sort, &def_sort_rev, 0);
  
  	    for(j = 0; j < 2; j++){
  		for(i = 0; ps->sort_types[i] != EndofList; i++){
***************
*** 272,277 ****
--- 272,326 ----
  		}
  	    }
  	}
+         else if(vtmp == &ps->vars[V_THREAD_SORT_KEY]){ /* radio case */
+             SortOrder thread_def_sort;
+             int       thread_def_sort_rev, lv;
+ 
+             ctmpa->flags       |= CF_NOSELECT;
+             ctmpa->keymenu      = &config_radiobutton_keymenu;
+             ctmpa->tool         = NULL;
+ 
+             /* put a nice delimiter before list */
+             new_confline(&ctmpa)->var = NULL;
+             ctmpa->varnamep               = ctmpb;
+             ctmpa->keymenu                = &config_radiobutton_keymenu;
+             ctmpa->help                   = NO_HELP;
+             ctmpa->tool                   = radiobutton_tool;
+             ctmpa->valoffset              = 12;
+             ctmpa->flags                 |= CF_NOSELECT;
+             ctmpa->value = cpystr("Set    Thread Sort Options");
+ 
+             new_confline(&ctmpa)->var = NULL;
+             ctmpa->varnamep           = ctmpb;
+             ctmpa->keymenu            = &config_radiobutton_keymenu;
+             ctmpa->help               = NO_HELP;
+             ctmpa->tool               = radiobutton_tool;
+             ctmpa->valoffset          = 12;
+             ctmpa->flags             |= CF_NOSELECT;
+             ctmpa->value = cpystr("---  ----------------------");
+   
+             /* find longest value's name */
+             for(lv = 0, i = 0; ps->sort_types[i] != EndofList; i++)
+               if(lv < (j = strlen(sort_name(ps->sort_types[i]))))
+                 lv = j;
+ 
+             decode_sort(pval, &thread_def_sort, &thread_def_sort_rev, 1);
+ 
+             for(j = 0; j < 2; j++){
+                 for(i = 0; ps->sort_types[i] != EndofList; i++){
+ 		  if (allowed_thread_key(ps->sort_types[i])){
+                     new_confline(&ctmpa)->var = vtmp;
+                     ctmpa->varnamep           = ctmpb;
+                     ctmpa->keymenu            = &config_radiobutton_keymenu;
+                     ctmpa->help               = config_help(vtmp - ps->vars, 0);
+                     ctmpa->tool               = radiobutton_tool;
+                     ctmpa->valoffset          = 12;
+                     ctmpa->varmem             = i + (j * EndofList);
+                     ctmpa->value              = pretty_value(ps, ctmpa);
+ 		  }
+                 }
+             }
+         }
  	else if(vtmp == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){ /* yesno case */
  	    ctmpa->keymenu = &config_yesno_keymenu;
  	    ctmpa->tool	   = yesno_tool;
***************
*** 463,468 ****
--- 512,526 ----
  	}
      }
  
+     pval = PVAL(&ps->vars[V_THREAD_SORT_KEY], ew);
+     if(vsave[V_THREAD_SORT_KEY].saved_user_val.p && pval
+        && strcmp(vsave[V_THREAD_SORT_KEY].saved_user_val.p, pval)){
+       if(!mn_get_mansort(ps_global->msgmap)){
+ 	  clear_index_cache(ps_global->mail_stream, 0);
+           reset_sort_order(SRT_VRB);
+       }
+     }
+ 
      treat_color_vars_as_text = 0;
      free_saved_config(ps, &vsave, expose_hidden_config);
  #ifdef _WINDOWS
diff -rc alpine-2.00/alpine/signal.c alpine-2.00.I.USE/alpine/signal.c
*** alpine-2.00/alpine/signal.c	2008-04-07 15:58:40.000000000 -0700
--- alpine-2.00.I.USE/alpine/signal.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 819,826 ****
  #else
      if(F_ON(F_SUSPEND_SPAWNS, ps_global)){
  	PIPE_S *syspipe;
  
! 	if((syspipe = open_system_pipe(NULL, NULL, NULL, PIPE_USER|PIPE_RESET,
  				      0, pipe_callback, pipe_report_error)) != NULL){
  	    suspend_notice("exit");
  #ifndef	SIGCHLD
--- 819,828 ----
  #else
      if(F_ON(F_SUSPEND_SPAWNS, ps_global)){
  	PIPE_S *syspipe;
+ 	int flag = some_stream_is_locked() ? PIPE_NONEWMAIL : 0;
  
! 	flag |= PIPE_USER|PIPE_RESET;
! 	if((syspipe = open_system_pipe(NULL, NULL, NULL, flag,
  				      0, pipe_callback, pipe_report_error)) != NULL){
  	    suspend_notice("exit");
  #ifndef	SIGCHLD
***************
*** 867,873 ****
  			_("Error loading \"%s\""), shell);
  #endif
  
!     if(isremote && !pine_mail_ping(ps_global->mail_stream))
        q_status_message(SM_ORDER | SM_DING, 4, 9,
  		       _("Suspended for too long, IMAP connection broken"));
  
--- 869,876 ----
  			_("Error loading \"%s\""), shell);
  #endif
  
!     if(isremote && !ps_global->mail_stream->lock 
! 		&& !pine_mail_ping(ps_global->mail_stream))
        q_status_message(SM_ORDER | SM_DING, 4, 9,
  		       _("Suspended for too long, IMAP connection broken"));
  
diff -rc alpine-2.00/alpine/status.c alpine-2.00.I.USE/alpine/status.c
*** alpine-2.00/alpine/status.c	2007-11-28 09:57:15.000000000 -0800
--- alpine-2.00.I.USE/alpine/status.c	2011-02-07 20:33:42.000000000 -0800
***************
*** 110,115 ****
--- 110,118 ----
      char  *clean_msg;
      size_t mlen;
  
+     if (ps_global->send_immediately)
+ 	return;
+ 
      status_message_lock();
  
      /*
***************
*** 604,609 ****
--- 607,615 ----
      SMQ_T *q, *copy_of_q;
      int ding;
  
+     if(ps_global->send_immediately)
+       return;
+ 
  start_over:
      status_message_lock();
  
diff -rc alpine-2.00/doc/alpine.1 alpine-2.00.I.USE/doc/alpine.1
*** alpine-2.00/doc/alpine.1	2008-08-22 13:40:16.000000000 -0700
--- alpine-2.00.I.USE/doc/alpine.1	2011-02-07 20:33:45.000000000 -0800
***************
*** 164,169 ****
--- 164,171 ----
  .IP \fB-n\ \fInumber\fR 20
  Start up with current message-number set to 
  .I number.
+ .IP \fB-noutf8\fR 20
+ Warns Alpine that piped input is not encoded in UTF-8.
  .IP \fB-o\fR 20
  Open first folder read-only.
  .IP \fB-p\ \fIconfig-file\fR 20
diff -rc alpine-2.00/imap/src/c-client/imap4r1.c alpine-2.00.I.USE/imap/src/c-client/imap4r1.c
*** alpine-2.00/imap/src/c-client/imap4r1.c	2008-06-04 11:39:54.000000000 -0700
--- alpine-2.00.I.USE/imap/src/c-client/imap4r1.c	2011-02-07 20:33:43.000000000 -0800
***************
*** 1121,1126 ****
--- 1121,1127 ----
        sprintf (tmp,"Retrying using %s authentication after %.80s",
  	       at->name,lsterr);
        mm_log (tmp,NIL);
+       delete_password(mb, usr);
        fs_give ((void **) &lsterr);
      }
      trial = 0;			/* initial trial count */
***************
*** 1129,1134 ****
--- 1130,1136 ----
        if (lsterr) {		/* previous attempt with this one failed? */
  	sprintf (tmp,"Retrying %s authentication after %.80s",at->name,lsterr);
  	mm_log (tmp,WARN);
+ 	delete_password(mb, usr);
  	fs_give ((void **) &lsterr);
        }
        LOCAL->saslcancel = NIL;
***************
*** 1166,1171 ****
--- 1168,1174 ----
        sprintf (tmp,"Can not authenticate to IMAP server: %.80s",lsterr);
        mm_log (tmp,ERROR);
      }
+     delete_password(mb, usr);
      fs_give ((void **) &lsterr);
    }
    return NIL;			/* ran out of authenticators */
***************
*** 1207,1212 ****
--- 1210,1216 ----
  	if (imap_OK (stream,reply = imap_send (stream,"LOGIN",args)))
  	  ret = LONGT;		/* success */
  	else {
+ 	  delete_password(mb, usr);
  	  mm_log (reply->text,WARN);
  	  if (!LOCAL->referral && (trial == imap_maxlogintrials))
  	    mm_log ("Too many login failures",ERROR);
***************
*** 4527,4532 ****
--- 4531,4537 ----
    if (*env) {			/* need to merge this header into envelope? */
      if (!(*env)->newsgroups) {	/* need Newsgroups? */
        (*env)->newsgroups = nenv->newsgroups;
+       (*env)->ngpathexists = nenv->ngpathexists;
        nenv->newsgroups = NIL;
      }
      if (!(*env)->followup_to) {	/* need Followup-To? */
***************
*** 4581,4586 ****
--- 4586,4592 ----
      if (oenv) {			/* need to merge old envelope? */
        (*env)->newsgroups = oenv->newsgroups;
        oenv->newsgroups = NIL;
+       (*env)->ngpathexists = oenv->ngpathexists;
        (*env)->followup_to = oenv->followup_to;
        oenv->followup_to = NIL;
        (*env)->references = oenv->references;
diff -rc alpine-2.00/imap/src/c-client/mail.c alpine-2.00.I.USE/imap/src/c-client/mail.c
*** alpine-2.00/imap/src/c-client/mail.c	2008-06-04 11:39:54.000000000 -0700
--- alpine-2.00.I.USE/imap/src/c-client/mail.c	2011-02-07 20:33:47.000000000 -0800
***************
*** 34,39 ****
--- 34,41 ----
  
  /* c-client global data */
  
+ static char *pwdfile = NIL;	/*password file */
+ static int  xlate_key;		/* for password file support */
  				/* version of this library */
  static char *mailcclientversion = CCLIENTVERSION;
  				/* list of mail drivers */
***************
*** 52,57 ****
--- 54,61 ----
  static rfc822out_t mail822out = NIL;
  				/* RFC-822 output generator (new style) */
  static rfc822outfull_t mail822outfull = NIL;
+ 				/* Erase password (client side) */
+ static deletepwd_t erase_password = NIL;
  				/* SMTP verbose callback */
  static smtpverbose_t mailsmtpverbose = mm_dlog;
  				/* proxy copy routine */
***************
*** 544,549 ****
--- 548,558 ----
    case GET_SENDCOMMAND:
      ret = (void *) mailsendcommand;
      break;
+   case SET_ERASEPASSWORD:
+     erase_password = (deletepwd_t) value;
+   case GET_ERASEPASSWORD:
+     ret = (void *) erase_password;
+     break;
  
    case SET_SERVICENAME:
      servicename = (char *) value;
***************
*** 640,645 ****
--- 649,661 ----
    case GET_SNARFMAILBOXNAME:
      if (stream) ret = (void *) stream->snarf.name;
      break;
+   case SET_PASSWORDFILE:
+     if (pwdfile) fs_give ((void **) &pwdfile);
+     pwdfile = cpystr ((char *) value);
+     break;
+   case GET_PASSWORDFILE:
+     ret = (void *) pwdfile;
+     break;
    default:
      if (r = smtp_parameters (function,value)) ret = r;
      if (r = env_parameters (function,value)) ret = r;
***************
*** 991,997 ****
    MAILSTREAM *ts;
    char *s,*t,tmp[MAILTMPLEN];
    size_t i;
!   DRIVER *d;
  				/* never allow names with newlines */
    if (s = strpbrk (mailbox,"\015\012")) {
      MM_LOG ("Can't create mailbox with such a name",ERROR);
--- 1007,1013 ----
    MAILSTREAM *ts;
    char *s,*t,tmp[MAILTMPLEN];
    size_t i;
!   DRIVER *d, *md;
  				/* never allow names with newlines */
    if (s = strpbrk (mailbox,"\015\012")) {
      MM_LOG ("Can't create mailbox with such a name",ERROR);
***************
*** 1015,1020 ****
--- 1031,1038 ----
      return NIL;
    }
  
+   /* Hack, we should do this better, but it works */
+     for (md = maildrivers; md && strcmp (md->name, "md"); md = md->next);
  				/* see if special driver hack */
    if ((mailbox[0] == '#') && ((mailbox[1] == 'd') || (mailbox[1] == 'D')) &&
        ((mailbox[2] == 'r') || (mailbox[2] == 'R')) &&
***************
*** 1045,1050 ****
--- 1063,1075 ----
  	   (((*mailbox == '{') || (*mailbox == '#')) &&
  	    (stream = mail_open (NIL,mailbox,OP_PROTOTYPE | OP_SILENT))))
      d = stream->dtb;
+   else if(mailbox[0] == '#'
+ 	&& (mailbox[1] == 'm' || mailbox[1] == 'M')
+ 	&& (mailbox[2] == 'd' || mailbox[2] == 'D'
+ 	    || mailbox[2] == 'c' || mailbox[2] == 'C')
+ 	&& mailbox[3] == '/'
+ 	&& mailbox[4] != '\0')
+      return (*md->create)(stream, mailbox);
    else if ((*mailbox != '{') && (ts = default_proto (NIL))) d = ts->dtb;
    else {			/* failed utterly */
      sprintf (tmp,"Can't create mailbox %.80s: indeterminate format",mailbox);
***************
*** 3352,3364 ****
  			   long flags)
  {
    STRINGLIST *hdrs;
!   int notfound;
    unsigned long i;
    char c,*s,*e,*t,tmp[MAILTMPLEN];
    char *src = text;
    char *dst = src;
    char *end = text + len;
!   text[len] = '\012';		/* guard against running off buffer */
    while (src < end) {		/* process header */
  				/* slurp header line name */
      for (s = src,e = s + MAILTMPLEN - 1,e = (e < end ? e : end),t = tmp;
--- 3377,3389 ----
  			   long flags)
  {
    STRINGLIST *hdrs;
!   int notfound, fix = text[len - 1] == '\0';
    unsigned long i;
    char c,*s,*e,*t,tmp[MAILTMPLEN];
    char *src = text;
    char *dst = src;
    char *end = text + len;
!   text[fix ? len - 1 : len] = '\012';	/* guard against running off buffer */
    while (src < end) {		/* process header */
  				/* slurp header line name */
      for (s = src,e = s + MAILTMPLEN - 1,e = (e < end ? e : end),t = tmp;
***************
*** 3397,3402 ****
--- 3422,3431 ----
      }
    }
    *dst = '\0';			/* tie off destination */
+   if(fix){
+ 	text[len] = '\012';
+ 	text[len-1] = '\0';
+   }
    return dst - text;
  }
  
***************
*** 5108,5114 ****
  			    unsigned long msgno)
  {
    if (msgno && ov) {		/* just in case */
!     MESSAGECACHE telt;
      SORTCACHE *s = (SORTCACHE *) (*mailcache) (stream,msgno,CH_SORTCACHE);
      if (!s->subject && ov->subject) {
        s->refwd = mail_strip_subject (ov->subject,&s->subject);
--- 5137,5144 ----
  			    unsigned long msgno)
  {
    if (msgno && ov) {		/* just in case */
!     MESSAGECACHE telt, *elt;
!     ENVELOPE *env;
      SORTCACHE *s = (SORTCACHE *) (*mailcache) (stream,msgno,CH_SORTCACHE);
      if (!s->subject && ov->subject) {
        s->refwd = mail_strip_subject (ov->subject,&s->subject);
***************
*** 5127,5133 ****
        s->dirty = T;
      }
      if (!s->references &&
! 	!(s->references = mail_thread_parse_references (ov->references,T))) {
  				/* don't do In-Reply-To with NNTP mailboxes */
        s->references = mail_newstringlist ();
        s->dirty = T;
--- 5157,5168 ----
        s->dirty = T;
      }
      if (!s->references &&
! 	!(s->references = mail_thread_parse_references (ov->references,T))
! 	&& stream->dtb && !strcmp(stream->dtb->name, "imap")
! 	&& (elt = mail_elt (stream, msgno)) != NULL
! 	&& (env = elt->private.msg.env) != NULL 
! 	&& env->in_reply_to
! 	&& !(s->references = mail_thread_parse_references(env->in_reply_to, NIL))) {
  				/* don't do In-Reply-To with NNTP mailboxes */
        s->references = mail_newstringlist ();
        s->dirty = T;
***************
*** 6115,6120 ****
--- 6150,6164 ----
        return i;
    return 0;
  }
+ /* Client side callback warning to delete wrong password
+  * 
+  */
+ void delete_password(NETMBX *mb, char *user)
+ {
+   deletepwd_t ep = mail_parameters(NULL, GET_ERASEPASSWORD, NULL);
+   if (ep) (ep)(mb, user);
+ }
+ 
  
  /* Standard TCP/IP network driver */
  
***************
*** 6329,6331 ****
--- 6373,6450 ----
  {
    return (*stream->dtb->localhost) (stream->stream);
  }
+ 
+ /*
+  *
+  * Module to add support for password file to a c-client application
+  *
+  * Written by Eduardo Chappa, based on password file support for Pine
+  *
+  */
+ #ifndef PWDFILE
+ #define PWDFILE 1
+ #endif
+ 
+ #define FIRSTCH         0x20
+ #define LASTCH          0x7e
+ #define TABSZ           (LASTCH - FIRSTCH + 1)
+ 
+ char  mm_xlate_out (char c);
+ void  mm_userpwd (NETMBX *mb, char **username, char **password);
+ 
+ /* function that decodes passwords */
+ 
+ char  mm_xlate_out (char c)
+ {
+     register int  dti;
+     register int  xch;
+ 
+     if((c >= FIRSTCH) && (c <= LASTCH)){
+ 	xch  = c - (dti = xlate_key);
+ 	xch += (xch < FIRSTCH-TABSZ) ? 2*TABSZ : (xch < FIRSTCH) ? TABSZ : 0;
+ 	dti  = (xch - FIRSTCH) + dti;
+ 	dti -= (dti >= 2*TABSZ) ? 2*TABSZ : (dti >= TABSZ) ? TABSZ : 0;
+ 	xlate_key = dti;
+ 	return(xch);
+     }
+     else
+       return(c);
+ }
+ 
+ void mm_userpwd (NETMBX *mb, char **username,  char **password)
+ {
+     char *s;
+     char  tmp[MAILTMPLEN], *ui[5];
+     FILE *fp;
+     int i, j, n;
+ 
+    if (!(pwdfile = env_parameters(GET_PASSWORDFILE, NULL)))
+       return;
+ 
+    if (fp = fopen(pwdfile, "r")){
+       for(n = 0; fgets(tmp, sizeof(tmp), fp); n++){
+ 	 xlate_key = n;
+ 	 for(i = 0; tmp[i]; i++)
+ 	   tmp[i] = mm_xlate_out(tmp[i]);
+ 
+ 	 if(i && tmp[i-1] == '\n')
+ 	   tmp[i-1] = '\0';
+ 
+ 	 ui[0] = ui[1] = ui[2] = ui[3] = ui[4] = NULL;
+ 	 for(i = 0, j = 0; tmp[i] && j < 5; j++){
+ 	     for(ui[j] = &tmp[i]; tmp[i] && tmp[i] != '\t'; i++);
+ 
+ 	     if(tmp[i])
+ 	       tmp[i++] = '\0';
+          }
+ 	 if (*username && ui[1] && !strcmp(*username, ui[1]) && mb->host
+ 	      && ((ui[2] && !strcmp(mb->host, ui[2]))
+ 		|| (ui[4] && !strcmp(mb->host,ui[4]))
+ 		|| (ui[2] && !strcmp(mb->orighost, ui[2]))
+ 		|| (ui[4] && !strcmp(mb->orighost,ui[4]))))
+ 	    strcpy (*password,ui[0]);
+       }
+       fclose(fp);
+    }
+ }
+ 
diff -rc alpine-2.00/imap/src/c-client/mail.h alpine-2.00.I.USE/imap/src/c-client/mail.h
*** alpine-2.00/imap/src/c-client/mail.h	2008-08-08 10:34:22.000000000 -0700
--- alpine-2.00.I.USE/imap/src/c-client/mail.h	2011-02-07 20:33:47.000000000 -0800
***************
*** 177,182 ****
--- 177,186 ----
  #define SET_EXTERNALAUTHID (long) 230
  #define GET_SSLCAPATH (long) 231
  #define SET_SSLCAPATH (long) 232
+ #define GET_ERASEPASSWORD (long) 233
+ #define SET_ERASEPASSWORD (long) 234
+ #define SET_PASSWORDFILE (long) 235
+ #define GET_PASSWORDFILE (long) 236
  
  	/* 3xx: TCP/IP */
  #define GET_OPENTIMEOUT (long) 300
***************
*** 353,358 ****
--- 357,366 ----
  #define SET_SCANCONTENTS (long) 573
  #define GET_MHALLOWINBOX (long) 574
  #define SET_MHALLOWINBOX (long) 575
+ #define GET_COURIERSTYLE (long) 576
+ #define SET_COURIERSTYLE (long) 577
+ #define SET_MDINBOXPATH  (long) 578
+ #define GET_MDINBOXPATH  (long) 579
  
  /* Driver flags */
  
***************
*** 685,690 ****
--- 693,699 ----
  /* Message envelope */
  
  typedef struct mail_envelope {
+   unsigned int ngpathexists : 1;	/* newsgroups may be bogus */
    unsigned int incomplete : 1;	/* envelope may be incomplete */
    unsigned int imapenvonly : 1;	/* envelope only has IMAP envelope */
    char *remail;			/* remail header if any */
***************
*** 1302,1308 ****
  typedef void *(*mailcache_t) (MAILSTREAM *stream,unsigned long msgno,long op);
  typedef long (*mailproxycopy_t) (MAILSTREAM *stream,char *sequence,
  				 char *mailbox,long options);
! typedef long (*tcptimeout_t) (long overall,long last);
  typedef void *(*authchallenge_t) (void *stream,unsigned long *len);
  typedef long (*authrespond_t) (void *stream,char *s,unsigned long size);
  typedef long (*authcheck_t) (void);
--- 1311,1317 ----
  typedef void *(*mailcache_t) (MAILSTREAM *stream,unsigned long msgno,long op);
  typedef long (*mailproxycopy_t) (MAILSTREAM *stream,char *sequence,
  				 char *mailbox,long options);
! typedef long (*tcptimeout_t) (long overall,long last, char *host);
  typedef void *(*authchallenge_t) (void *stream,unsigned long *len);
  typedef long (*authrespond_t) (void *stream,char *s,unsigned long size);
  typedef long (*authcheck_t) (void);
***************
*** 1325,1330 ****
--- 1334,1340 ----
  typedef void *(*blocknotify_t) (int reason,void *data);
  typedef long (*kinit_t) (char *host,char *reason);
  typedef void (*sendcommand_t) (MAILSTREAM *stream,char *cmd,long flags);
+ typedef void (*deletepwd_t) (NETMBX *mb,char *user);
  typedef char *(*newsrcquery_t) (MAILSTREAM *stream,char *mulname,char *name);
  typedef void (*getacl_t) (MAILSTREAM *stream,char *mailbox,ACLLIST *acl);
  typedef void (*listrights_t) (MAILSTREAM *stream,char *mailbox,char *id,
***************
*** 1604,1609 ****
--- 1614,1621 ----
  void mm_fatal (char *string);
  void *mm_cache (MAILSTREAM *stream,unsigned long msgno,long op);
  
+ void delete_password (NETMBX *mb, char *user);
+ 
  extern STRINGDRIVER mail_string;
  void mail_versioncheck (char *version);
  void mail_link (DRIVER *driver);
diff -rc alpine-2.00/imap/src/c-client/nntp.c alpine-2.00.I.USE/imap/src/c-client/nntp.c
*** alpine-2.00/imap/src/c-client/nntp.c	2008-06-04 11:18:34.000000000 -0700
--- alpine-2.00.I.USE/imap/src/c-client/nntp.c	2011-02-07 20:33:43.000000000 -0800
***************
*** 2031,2036 ****
--- 2031,2037 ----
        sprintf (tmp,"Retrying using %s authentication after %.80s",
  	       at->name,lsterr);
        mm_log (tmp,NIL);
+       delete_password(mb, mb ? mb->user : NULL);
        fs_give ((void **) &lsterr);
      }
      trial = 0;			/* initial trial count */
***************
*** 2039,2044 ****
--- 2040,2046 ----
        if (lsterr) {
  	sprintf (tmp,"Retrying %s authentication after %.80s",at->name,lsterr);
  	mm_log (tmp,WARN);
+ 	delete_password(mb, mb ? mb->user : NULL);
  	fs_give ((void **) &lsterr);
        }
        stream->saslcancel = NIL;
***************
*** 2064,2069 ****
--- 2066,2072 ----
        sprintf (tmp,"Can not authenticate to NNTP server: %.80s",lsterr);
        mm_log (tmp,ERROR);
      }
+     delete_password(mb, mb ? mb->user : NULL);
      fs_give ((void **) &lsterr);
    }
    else if (mb->secflag)		/* no SASL, can't do /secure */
***************
*** 2092,2097 ****
--- 2095,2102 ----
        stream->sensitive = T;	/* hide this command */
        if (nntp_send_work (stream,"AUTHINFO PASS",pwd) == NNTPAUTHED)
  	ret = LONGT;		/* password OK */
+       else
+         delete_password(mb, mb ? mb->user : NULL);
        stream->sensitive = NIL;	/* unhide */
        if (ret) break;		/* OK if successful */
      default:			/* authentication failed */
diff -rc alpine-2.00/imap/src/c-client/pop3.c alpine-2.00.I.USE/imap/src/c-client/pop3.c
*** alpine-2.00/imap/src/c-client/pop3.c	2008-06-04 11:18:34.000000000 -0700
--- alpine-2.00.I.USE/imap/src/c-client/pop3.c	2011-02-07 20:33:43.000000000 -0800
***************
*** 615,620 ****
--- 615,621 ----
  	sprintf (pwd,"Retrying using %.80s authentication after %.80s",
  		 at->name,t);
  	mm_log (pwd,NIL);
+ 	delete_password(mb, usr);
  	fs_give ((void **) &t);
        }
        trial = 0;		/* initial trial count */
***************
*** 622,627 ****
--- 623,629 ----
  	if (t) {
  	  sprintf (pwd,"Retrying %s authentication after %.80s",at->name,t);
  	  mm_log (pwd,WARN);
+ 	  delete_password(mb, usr);
  	  fs_give ((void **) &t);
  	}
  	LOCAL->saslcancel = NIL;
***************
*** 667,672 ****
--- 669,675 ----
  	  LOCAL->sensitive=NIL;	/* unhide */
  	}
  	if (!ret) {		/* failure */
+ 	  delete_password(mb, usr);
  	  mm_log (LOCAL->reply,WARN);
  	  if (trial == pop3_maxlogintrials)
  	    mm_log ("Too many login failures",ERROR);
diff -rc alpine-2.00/imap/src/c-client/rfc822.c alpine-2.00.I.USE/imap/src/c-client/rfc822.c
*** alpine-2.00/imap/src/c-client/rfc822.c	2008-06-04 11:46:10.000000000 -0700
--- alpine-2.00.I.USE/imap/src/c-client/rfc822.c	2011-02-07 20:33:43.000000000 -0800
***************
*** 128,133 ****
--- 128,134 ----
    ENVELOPE *env = (*en = mail_newenvelope ());
    BODY *body = bdy ? (*bdy = mail_newbody ()) : NIL;
    long MIMEp = -1;		/* flag that MIME semantics are in effect */
+   long PathP = NIL;             /* flag that a Path: was seen */
    parseline_t pl = (parseline_t) mail_parameters (NIL,GET_PARSELINE,NIL);
    if (!host) host = BADHOST;	/* make sure that host is non-null */
    while (i && *s != '\n') {	/* until end of header */
***************
*** 230,235 ****
--- 231,239 ----
  	  *t++ = '\0';
  	}
  	break;
+       case 'P':                 /* possible Path: */
+ 	if (!strcmp (tmp+1,"ATH")) env->ngpathexists = T;
+ 	break;
        case 'R':			/* possible Reply-To: */
  	if (!strcmp (tmp+1,"EPLY-TO"))
  	  rfc822_parse_adrlist (&env->reply_to,d,host);
diff -rc alpine-2.00/imap/src/osdep/mac/tcp_mac.c alpine-2.00.I.USE/imap/src/osdep/mac/tcp_mac.c
*** alpine-2.00/imap/src/osdep/mac/tcp_mac.c	2008-06-04 11:18:34.000000000 -0700
--- alpine-2.00.I.USE/imap/src/osdep/mac/tcp_mac.c	2011-02-07 20:33:45.000000000 -0800
***************
*** 383,389 ****
      if (stream->pb.ioResult) {	/* punt if got an error */
        time_t tc = time (0);
        if ((stream->pb.ioResult == commandTimeout) && tmoh &&
! 	  ((*tmoh) (tc - t,tc - tl))) continue;
      				/* nuke connection */
        stream->pb.csCode = TCPAbort;
        abortpb->userDataPtr = NIL;
--- 383,389 ----
      if (stream->pb.ioResult) {	/* punt if got an error */
        time_t tc = time (0);
        if ((stream->pb.ioResult == commandTimeout) && tmoh &&
! 	  ((*tmoh) (tc - t,tc - tl, stream->host))) continue;
      				/* nuke connection */
        stream->pb.csCode = TCPAbort;
        abortpb->userDataPtr = NIL;
diff -rc alpine-2.00/imap/src/osdep/nt/tcp_nt.c alpine-2.00.I.USE/imap/src/osdep/nt/tcp_nt.c
*** alpine-2.00/imap/src/osdep/nt/tcp_nt.c	2008-06-04 11:18:34.000000000 -0700
--- alpine-2.00.I.USE/imap/src/osdep/nt/tcp_nt.c	2011-02-07 20:33:45.000000000 -0800
***************
*** 430,436 ****
  			   SOCKET_ERROR) &&
  			  ((errno = WSAGetLastError ()) == WSAEINTR));
  	else if (!i) {		/* timeout, ignore if told to resume */
! 	  if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl))) continue;
  				/* otherwise punt */
  	  if (tcpdebug) mm_log ("TCP buffer read timeout",TCPDEBUG);
  	  return tcp_abort (stream);
--- 430,438 ----
  			   SOCKET_ERROR) &&
  			  ((errno = WSAGetLastError ()) == WSAEINTR));
  	else if (!i) {		/* timeout, ignore if told to resume */
! 	  if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl), 
! 								stream->host))
! 		continue;
  				/* otherwise punt */
  	  if (tcpdebug) mm_log ("TCP buffer read timeout",TCPDEBUG);
  	  return tcp_abort (stream);
***************
*** 498,504 ****
  			 SOCKET_ERROR) &&
  			((errno = WSAGetLastError ()) == WSAEINTR));
        else if (!i) {		/* timeout, ignore if told to resume */
! 	if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl))) continue;
  				/* otherwise punt */
  	if (tcpdebug) mm_log ("TCP data read timeout",TCPDEBUG);
  	return tcp_abort (stream);
--- 500,507 ----
  			 SOCKET_ERROR) &&
  			((errno = WSAGetLastError ()) == WSAEINTR));
        else if (!i) {		/* timeout, ignore if told to resume */
! 	if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl), stream->host))
! 		continue;
  				/* otherwise punt */
  	if (tcpdebug) mm_log ("TCP data read timeout",TCPDEBUG);
  	return tcp_abort (stream);
***************
*** 582,588 ****
  			 SOCKET_ERROR) &&
  			((errno = WSAGetLastError ()) == WSAEINTR));
        else if (!i) {		/* timeout, ignore if told to resume */
! 	if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl))) continue;
  				/* otherwise punt */
  	if (tcpdebug) mm_log ("TCP write timeout",TCPDEBUG);
  	return tcp_abort (stream);
--- 585,592 ----
  			 SOCKET_ERROR) &&
  			((errno = WSAGetLastError ()) == WSAEINTR));
        else if (!i) {		/* timeout, ignore if told to resume */
! 	if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl), stream->host))
! 		continue;
  				/* otherwise punt */
  	if (tcpdebug) mm_log ("TCP write timeout",TCPDEBUG);
  	return tcp_abort (stream);
diff -rc alpine-2.00/imap/src/osdep/unix/dummy.c alpine-2.00.I.USE/imap/src/osdep/unix/dummy.c
*** alpine-2.00/imap/src/osdep/unix/dummy.c	2008-06-04 11:18:34.000000000 -0700
--- alpine-2.00.I.USE/imap/src/osdep/unix/dummy.c	2011-02-07 20:33:41.000000000 -0800
***************
*** 106,118 ****
   * Accepts: mailbox name
   * Returns: our driver if name is valid, NIL otherwise
   */
! 
  DRIVER *dummy_valid (char *name)
  {
!   char *s,tmp[MAILTMPLEN];
    struct stat sbuf;
  				/* must be valid local mailbox */
!   if (name && *name && (*name != '{') && (s = mailboxfile (tmp,name))) {
  				/* indeterminate clearbox INBOX */
      if (!*s) return &dummydriver;
      else if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) {
--- 106,124 ----
   * Accepts: mailbox name
   * Returns: our driver if name is valid, NIL otherwise
   */
! char * maildir_remove_root(char *);
  DRIVER *dummy_valid (char *name)
  {
!   char *s,tmp[MAILTMPLEN], *rname;
    struct stat sbuf;
+ 
+   if(strlen(name) > MAILTMPLEN)
+    name[MAILTMPLEN] = '\0';
+ 
+   strcpy(tmp, name);
+   rname = maildir_remove_root(tmp);
  				/* must be valid local mailbox */
!   if (rname && *rname && (*rname != '{') && (s = mailboxfile (tmp,rname))) {
  				/* indeterminate clearbox INBOX */
      if (!*s) return &dummydriver;
      else if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) {
***************
*** 121,128 ****
        return &dummydriver;
      }
  				/* blackbox INBOX does not exist yet */
!     else if (!compare_cstring (name,"INBOX")) return &dummydriver;
    }
    return NIL;
  }
  
--- 127,135 ----
        return &dummydriver;
      }
  				/* blackbox INBOX does not exist yet */
!     else if (!compare_cstring (rname,"INBOX")) return &dummydriver;
    }
+   if(rname) fs_give((void **)&rname);
    return NIL;
  }
  
***************
*** 454,459 ****
--- 461,468 ----
  {
    char *s,tmp[MAILTMPLEN];
    long ret = NIL;
+   if(!strncmp(mailbox,"#md/",4) || !strncmp(mailbox,"#mc/", 4))
+     return maildir_create(stream, mailbox);
  				/* validate name */
    if (!(compare_cstring (mailbox,"INBOX") && (s = dummy_file (tmp,mailbox)))) {
      sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
***************
*** 519,524 ****
--- 528,541 ----
  {
    struct stat sbuf;
    char *s,tmp[MAILTMPLEN];
+   if (!strncmp(mailbox,"#md/",4) || !strncmp(mailbox,"#mc/", 4) 
+ 	|| is_valid_maildir(&mailbox)){
+     char tmp[MAILTMPLEN] = {'\0'};
+     strcpy(tmp, mailbox);
+     if(tmp[strlen(tmp) - 1] != '/')
+        tmp[strlen(tmp)] = '/';
+      return maildir_delete(stream, tmp);
+   }
    if (!(s = dummy_file (tmp,mailbox))) {
      sprintf (tmp,"Can't delete - invalid name: %.80s",s);
      MM_LOG (tmp,ERROR);
***************
*** 544,555 ****
  long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
  {
    struct stat sbuf;
!   char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN];
  				/* no trailing / allowed */
!   if (!dummy_file (oldname,old) || !(s = dummy_file (mbx,newname)) ||
        stat (oldname,&sbuf) || ((s = strrchr (s,'/')) && !s[1] &&
  			       ((sbuf.st_mode & S_IFMT) != S_IFDIR))) {
!     sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",old,newname);
      MM_LOG (mbx,ERROR);
      return NIL;
    }
--- 561,583 ----
  long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
  {
    struct stat sbuf;
!   char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN], *rold, *rnewname;
! 
!   if(strlen(old) > MAILTMPLEN)
!     old[MAILTMPLEN] = '\0';
! 
!   if(strlen(newname) > MAILTMPLEN)
!     newname[MAILTMPLEN] = '\0';
! 
!   strcpy(tmp, old);
!   rold = maildir_remove_root(tmp);
!   strcpy(tmp, newname);
!   rnewname = maildir_remove_root(tmp);
  				/* no trailing / allowed */
!   if (!dummy_file (oldname,rold) || !(s = dummy_file (mbx,rnewname)) ||
        stat (oldname,&sbuf) || ((s = strrchr (s,'/')) && !s[1] &&
  			       ((sbuf.st_mode & S_IFMT) != S_IFDIR))) {
!     sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",rold,rnewname);
      MM_LOG (mbx,ERROR);
      return NIL;
    }
***************
*** 565,578 ****
      }
    }
  				/* rename of non-ex INBOX creates dest */
!   if (!compare_cstring (old,"INBOX") && stat (oldname,&sbuf))
      return dummy_create (NIL,mbx);
    if (rename (oldname,mbx)) {
!     sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",old,newname,
  	     strerror (errno));
      MM_LOG (tmp,ERROR);
      return NIL;
    }
    return T;			/* return success */
  }
  
--- 593,608 ----
      }
    }
  				/* rename of non-ex INBOX creates dest */
!   if (!compare_cstring (rold,"INBOX") && stat (oldname,&sbuf))
      return dummy_create (NIL,mbx);
    if (rename (oldname,mbx)) {
!     sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",rold,rnewname,
  	     strerror (errno));
      MM_LOG (tmp,ERROR);
      return NIL;
    }
+   if(rold) fs_give((void **)&rold);
+   if(rnewname) fs_give((void **)&rnewname);
    return T;			/* return success */
  }
  
diff -rc alpine-2.00/imap/src/osdep/unix/maildir.c alpine-2.00.I.USE/imap/src/osdep/unix/maildir.c
*** alpine-2.00/imap/src/osdep/unix/maildir.c	2011-02-07 20:34:02.000000000 -0800
--- alpine-2.00.I.USE/imap/src/osdep/unix/maildir.c	2011-02-07 20:33:41.000000000 -0800
***************
*** 0 ****
--- 1,2584 ----
+ /*
+  * Maildir driver for Alpine 2.00
+  * 
+  * Written by Eduardo Chappa <chappa@washington.edu>
+  * Last Update: November 6, 2010.
+  *
+  */
+ 
+ #include <stdio.h>
+ #include <ctype.h>
+ #include <errno.h>
+ extern int errno;		/* just in case */
+ #include "mail.h"
+ #include <pwd.h>
+ #include <sys/stat.h>
+ #include <sys/time.h>
+ #include "osdep.h"
+ #include "rfc822.h"
+ #include "fdstring.h"
+ #include "misc.h"
+ #include "dummy.h"
+ #include "maildir.h"
+ 
+ /* Driver dispatch used by MAIL */
+ DRIVER maildirdriver = {
+   "md",			/* driver name, yes it's md, not maildir */
+ 				/* driver flags */
+   DR_MAIL|DR_LOCAL|DR_NAMESPACE|DR_DIRFMT,
+   (DRIVER *) NIL,		/* next driver 				*/
+   maildir_valid,		/* mailbox is valid for us 		*/
+   maildir_parameters,		/* manipulate parameters		*/
+   NIL,				/* scan mailboxes 			*/
+   maildir_list,			/* find mailboxes 			*/
+   maildir_lsub,			/* find subscribed mailboxes 		*/
+   maildir_sub,			/* subscribe to mailbox 		*/
+   maildir_unsub,		/* unsubscribe from mailbox 		*/
+   maildir_create,		/* create mailbox 			*/
+   maildir_delete,		/* delete mailbox 			*/
+   maildir_rename,		/* rename mailbox 			*/
+   mail_status_default,		/* status of mailbox 			*/
+   maildir_open,			/* open mailbox				*/
+   maildir_close,		/* close mailbox 			*/
+   maildir_fast,			/* fetch message "fast" attributes	*/
+   NIL,				/* fetch message flags 			*/
+   NIL,				/* fetch overview 			*/
+   NIL,				/* fetch message structure 		*/
+   maildir_header,		/* fetch message header 		*/
+   maildir_text,			/* fetch message body 			*/
+   NIL,				/* fetch partial message text 		*/
+   NIL,				/* unique identifier 			*/
+   NIL,				/* message number 			*/
+   NIL,				/* modify flags 			*/
+   maildir_flagmsg,		/* per-message modify flags 		*/
+   NIL,				/* search for message based on criteria */
+   NIL,				/* sort messages 			*/
+   NIL,				/* thread messages 			*/
+   maildir_ping,			/* ping mailbox to see if still alive 	*/
+   maildir_check,		/* check for new messages		*/
+   maildir_expunge,		/* expunge deleted messages 		*/
+   maildir_copy,			/* copy messages to another mailbox 	*/
+   maildir_append,		/* append string message to mailbox 	*/
+   NIL				/* garbage collect stream 		*/
+ };
+ 
+ 
+ DRIVER courierdriver = {
+   "mc",				/* Why a separate driver? So that
+ 				   createproto will work		*/
+ 				/* driver flags */
+   DR_MAIL|DR_LOCAL|DR_NAMESPACE|DR_DIRFMT,
+   (DRIVER *) NIL,		/* next driver 				*/
+   maildir_valid,		/* mailbox is valid for us 		*/
+   maildir_parameters,		/* manipulate parameters		*/
+   NIL,				/* scan mailboxes 			*/
+   courier_list,			/* find mailboxes 			*/
+   maildir_lsub,			/* find subscribed mailboxes 		*/
+   maildir_sub,			/* subscribe to mailbox 		*/
+   maildir_unsub,		/* unsubscribe from mailbox 		*/
+   maildir_create,		/* create mailbox 			*/
+   maildir_delete,		/* delete mailbox 			*/
+   maildir_rename,		/* rename mailbox 			*/
+   mail_status_default,		/* status of mailbox 			*/
+   maildir_open,			/* open mailbox				*/
+   maildir_close,		/* close mailbox 			*/
+   maildir_fast,			/* fetch message "fast" attributes	*/
+   NIL,				/* fetch message flags 			*/
+   NIL,				/* fetch overview 			*/
+   NIL,				/* fetch message structure 		*/
+   maildir_header,		/* fetch message header 		*/
+   maildir_text,			/* fetch message body 			*/
+   NIL,				/* fetch partial message text 		*/
+   NIL,				/* unique identifier 			*/
+   NIL,				/* message number 			*/
+   NIL,				/* modify flags 			*/
+   maildir_flagmsg,		/* per-message modify flags 		*/
+   NIL,				/* search for message based on criteria */
+   NIL,				/* sort messages 			*/
+   NIL,				/* thread messages 			*/
+   maildir_ping,			/* ping mailbox to see if still alive 	*/
+   maildir_check,		/* check for new messages		*/
+   maildir_expunge,		/* expunge deleted messages 		*/
+   maildir_copy,			/* copy messages to another mailbox 	*/
+   maildir_append,		/* append string message to mailbox 	*/
+   NIL				/* garbage collect stream 		*/
+ };
+ 
+ MAILSTREAM maildirproto = {&maildirdriver};	/* prototype stream */
+ MAILSTREAM courierproto = {&courierdriver};	/* prototype stream */
+ 
+ long maildir_dirfmttest (char *name)
+ {
+   int i;
+   for (i = 0; mdstruct[i] && strcmp(name, mdstruct[i]); i++);
+   return (i < EndDir) || !strcmp(name, MDDIR) 
+ 	|| !strncmp(name, MDUIDLAST, strlen(MDUIDLAST))
+ 	|| !strncmp(name, MDUIDTEMP, strlen(MDUIDTEMP)) ? LONGT : NIL;
+ }
+ 
+ void 
+ md_domain_name(void)
+ {
+    int i;
+ 
+    strcpy(mdlocaldomain,mylocalhost ());
+    for (i = 0; mdlocaldomain[i] ; i++)
+       if(mdlocaldomain[i] == '/')
+ 	 mdlocaldomain[i] = '\057';
+       else if (mdlocaldomain[i] == ':')
+ 	 mdlocaldomain[i] =  '\072';
+ }
+ 
+ char *
+ myrootdir(char *name)
+ {
+ return myhomedir();
+ }
+ 
+ char *
+ mdirpath(void)
+ {
+   char *path = maildir_parameters(GET_MDINBOXPATH,NIL);
+   return path ? (path[0] ? path : ".") : "Maildir";
+ }
+ 
+ /* remove the "#md/" or "#mc/" part from a folder name */
+ char *
+ maildir_remove_root (char *name)
+ {
+   int courier = IS_COURIER(name), offset;
+   char realname[MAILTMPLEN];
+ 
+   offset = maildir_valid_name(name) ? (name[3] == '/' ? 4 : 3) : 0;
+   if(courier)
+      courier_realname(name+offset, realname);
+   else
+      strcpy(realname, name+offset);
+   return cpystr(realname);
+ }
+ 
+ 
+ /* Check validity of the name, we accept:
+  *	a) #md/directory/folder
+  *	b) #md/inbox
+  * A few considerations: We can only accept as valid
+  *  a) names that start with #md/ and the directory exists or
+  *  b) names that do not start with #md/ but are maildir directories (have
+  *     the /cur, /tmp and /new structure)
+  */
+ int maildir_valid_name (char *name)
+ {
+   char tmpname[MAILTMPLEN] = {'\0'};
+ 
+    if (mdfpath)
+       fs_give((void **)&mdfpath);
+    if (name && (name[0] != '#'))
+ 	sprintf(tmpname,"%s%s",MDPREFIX(CCLIENT), name);
+    mdfpath = cpystr(tmpname[0] ? tmpname : name);
+ 
+   return IS_CCLIENT(name) || IS_COURIER(name);
+ }
+ 
+ /* Check if the directory whose path is given by name is a valid maildir
+  *  directory (contains /cur, /tmp and /new)
+  */
+ int maildir_valid_dir (char *name)
+ {
+  int len;
+  DirNamesType i;
+  struct stat sbuf;
+  char tmp[MAILTMPLEN];
+ 
+    if(name[strlen(name) - 1] == '/')
+       name[strlen(name) - 1] = '\0';
+    len = strlen(name);
+    for (i = Cur; i != EndDir; i++){
+       MDFLD(tmp, name, i);
+       if (stat(tmp, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode))
+ 	  break;
+    }
+    name[len] = '\0';
+    return (i == EndDir) ? T : NIL;
+ }
+ 
+ void courier_realname(char *name, char *realname)
+ {
+   int i,j;
+ 
+   if(!name)
+     return;
+ 
+   for (i = 0, j = 0; i < MAILTMPLEN && j < strlen(name); j++, i++){
+       realname[i] = name[j];
+       if(name[j] == '/' && name[j+1] != '.' && name[j+1] != '%' 
+ 		&& name[j+1] != '*') 
+ 	realname[++i] = '.';
+   }
+   if(realname[i-1] == '.')
+     i--; 
+   realname[i] = '\0';
+ }
+ 
+ 
+ /* given a maildir folder, return its path. Memory freed by caller. Directory
+  * does not contain the trailing slash "/". On error NULL is returned.
+  */
+ int maildir_file_path (char *name, char *tmp)
+ {
+    char *maildirpath = mdirpath(), *rname;
+    int courier = IS_COURIER(name);
+ 
+    /* There are several ways in which the path can come, so we will handle 
+       them here. First we deal with #mc/ or #md/ prefix by removing the 
+       prefix, if any */
+ 
+     if(strlen(name) >= MAILTMPLEN)
+       name[MAILTMPLEN] = '\0';
+     strcpy(tmp, name);
+     rname = maildir_remove_root(tmp);
+     tmp[0] = '\0';	/* just in case something fails */
+ 
+     if (strlen(myrootdir(rname)) + 
+ 		max(strlen(rname), strlen(maildirpath)) > MAILTMPLEN){
+ 	errno = ENAMETOOLONG;
+ 	sprintf(tmp,"Error opening \"%s\": %s", rname, strerror (errno));
+ 	mm_log(tmp,ERROR);
+ 	return NIL;
+     }
+ 
+     /* There are two ways in which the name can come here, either as a 
+        full path or not. If it is not a full path it can come in two ways, 
+        either as a file system path (Maildir/.Drafts) or as a maildir path 
+        (INBOX.Drafts)
+      */
+ 
+      if(*rname == '/')	/* full path */
+ 	strcpy(tmp, rname); /* do nothing */
+      else{
+ 	sprintf (tmp,"%s/%s%s%s", myrootdir (rname),
+ 	    strncmp (ucase (strcpy (tmp, rname)), "INBOX", 5) 
+ 		? rname : maildirpath,
+ 	    strncmp (ucase (strcpy (tmp, rname)), "INBOX", 5) 
+ 		? "" : (courier ? "/" : ""),
+ 	    strncmp (ucase (strcpy (tmp, rname)), "INBOX", 5) 
+ 		? "" : (*(rname+5) == MDSEPARATOR(courier) ? rname+5 : ""));
+      }
+     if(rname) fs_give((void **)&rname);
+     return tmp[0] ? T : NIL;
+ }
+ 
+ /* This function is given a full path for a mailbox and returns
+  * if it is a valid maildir transformed to canonical notation
+  */
+ int
+ is_valid_maildir (char **name)
+ {
+   if (!strncmp(*name, myrootdir (*name), strlen(myrootdir(*name)))){
+      (*name) += strlen(myrootdir(*name));
+      if (**name == '/') (*name)++;
+   }
+   return maildir_valid(*name) ? T :  NIL;
+ }
+ 
+ /* Check validity of mailbox. This routine does not send errors to log, other
+  *  routines calling this one may do so, though
+  */ 
+ 
+ DRIVER *maildir_valid (char *name)
+ {
+    char tmpname[MAILTMPLEN];
+ 
+    maildir_file_path(name, tmpname);
+    
+    return maildir_valid_dir(tmpname) 
+ 		? (IS_COURIER(name) ? &courierdriver : &maildirdriver) : NIL;
+ }
+ 
+ void maildir_fast (MAILSTREAM *stream,char *sequence,long flags)
+ {
+   unsigned long i;
+   MESSAGECACHE *elt;
+                                 /* get sequence */
+   if (stream && LOCAL && ((flags & FT_UID) ?
+                           mail_uid_sequence (stream,sequence) :
+                           mail_sequence (stream,sequence)))
+     for (i = 1L; i <= stream->nmsgs; i++) {
+       if ((elt = mail_elt (stream,i))->sequence && (elt->valid = T) &&
+           !(elt->day && elt->rfc822_size)) {
+         ENVELOPE **env = NIL;
+         ENVELOPE *e = NIL;
+         if (!stream->scache) env = &elt->private.msg.env;
+         else if (stream->msgno == i) env = &stream->env;
+         else env = &e;
+         if (!*env || !elt->rfc822_size) {
+           STRING bs;
+           unsigned long hs;
+           char *ht = (*stream->dtb->header) (stream,i,&hs,NIL);
+ 
+           if (!*env) rfc822_parse_msg (env,NIL,ht,hs,NIL,BADHOST,
+                                        stream->dtb->flags);
+           if (!elt->rfc822_size) {
+             (*stream->dtb->text) (stream,i,&bs,FT_PEEK);
+             elt->rfc822_size = hs + SIZE (&bs) - GETPOS (&bs);
+           }
+         }
+ 
+         if (!elt->day && *env && (*env)->date)
+           mail_parse_date (elt,(*env)->date);
+ 
+         if (!elt->day) elt->day = elt->month = 1;
+         mail_free_envelope (&e);
+       }
+     }
+ }
+ 
+ int
+ maildir_eliminate_duplicate (char *name, struct direct ***flist, unsigned long *nfiles)
+ {
+    int i, j, k, error = 0, scanr;
+    char new[MAILTMPLEN], old[MAILTMPLEN], tmp[MAILTMPLEN], *str;
+    struct direct **names = NIL;
+ 
+    if((scanr = maildir_doscandir(name, &names, CCLIENT)) < 0)
+      return -1;
+ 
+    if(nfiles) *nfiles = scanr;
+    for(i = 0, j = 1, k = 0;  j < scanr; i++, j++){
+       if(k)
+ 	names[i] = names[i+k];
+       if(same_maildir_file(names[i]->d_name, names[j]->d_name)){
+ 	int d, f, r, s;
+ 	maildir_getflag(names[i]->d_name, &d, &f, &r, &s, NIL);
+ 	sprintf(old,"%s/%s", name, names[i]->d_name);
+ 	sprintf(new,"%s/.%s", name, names[i]->d_name);
+ 	if(rename(old, new) < 0 && errno != EEXIST)
+ 	  error++;
+ 	if(!error){
+ 	  for(; j < scanr
+ 		&& same_maildir_file(names[i]->d_name, names[j]->d_name)
+ 	      ; j++, k++){
+ 	      maildir_getflag(names[j]->d_name, (d ? NIL : &d), 
+ 			(f ? NIL : &f), (r ? NIL : &r), (s ? NIL : &s), NIL);
+ 	      sprintf(tmp,"%s/%s", name, names[j]->d_name);
+ 	      if(unlink(tmp) < 0){	/* Hmmm... a problem, let's see */
+ 		struct stat sbuf;
+ 		if (stat(tmp, &sbuf) == 0 && (sbuf.st_mode & S_IFMT) == S_IFREG)
+ 		   error++;
+ 	      }
+ 	  }
+ 	  if((str = strrchr(names[i]->d_name,FLAGSEP)) != NULL) *str = '\0';
+ 	  sprintf (old,"%s/%s%s%s%s%s%s", name, names[i]->d_name, MDSEP(2),
+ 		MDFLAG(Draft, d), MDFLAG(Flagged, f), MDFLAG(Replied, r), 
+ 		MDFLAG(Seen, s));
+ 	  if(rename(new, old) < 0)
+ 	     error++;
+ 	}
+       }
+ 
+    }
+    if(k > 0)
+      fs_give((void **)&names);
+    else
+      *flist = names;
+    return error ? -1 : k;
+ }
+ 
+ int
+ maildir_doscandir(char *name, struct direct ***flist, int flag)
+ {
+ return scandir(name, flist, 
+ 		flag == CCLIENT ? maildir_select : courier_dir_select, 
+ 		flag == CCLIENT ? maildir_namesort : courier_dir_sort);
+ }
+ 
+ /* 
+  * return all files in a given directory. This is a separate call
+  * so that if there are warnings during compilation this only appears once.
+  */
+ unsigned long
+ maildir_scandir (char *name, struct direct ***flist, 
+ 			unsigned long *nfiles, int *scand, int flag)
+ {
+   struct stat sbuf;
+   int rv = -2;	/* impossible value */
+ 
+   if (scand)
+      *scand = -1;	/* assume error for safety */
+   *nfiles = 0;
+   if((stat(name,&sbuf) < 0) 
+ 	|| (flag == CCLIENT
+ 	 && ((rv = maildir_eliminate_duplicate(name, flist, nfiles)) < 0)))
+      return 0L;
+ 
+   if (scand && (rv > 0 || rv == -2))
+      *nfiles = maildir_doscandir(name, flist, flag);
+ 
+   if(scand) *scand = *nfiles;
+ 
+   return (unsigned long) sbuf.st_ctime;
+ }
+ 
+ /* Does a message with given name exists (or was it removed)?
+  * Returns: 1 - yes, such message exist,
+  *	    0 - No, that message does not exist anymore
+  *
+  * Parameters: stream, name of mailbox, new name if his message does not
+  *		exist.
+  */
+ 
+ int maildir_message_exists(MAILSTREAM *stream, char *name, char *newfile)
+ {
+   char tmp[MAILTMPLEN];
+   int gotit = NIL;
+   DIR *dir;
+   struct direct *d;
+   struct stat sbuf;
+ 
+   /* First check directly if it exists, if not there, look for it */
+   sprintf(tmp,"%s/%s", LOCAL->curdir, name);
+   if ((stat(tmp, &sbuf) == 0) && ((sbuf.st_mode & S_IFMT) == S_IFREG))
+     return T;
+ 
+   if (!(dir = opendir (LOCAL->curdir)))
+      return NIL;
+ 
+   while ((d = readdir(dir)) && gotit == NIL){
+     if (d->d_name[0] == '.')
+       continue;
+     if (same_maildir_file(d->d_name, name)){
+ 	  gotit = T;
+ 	  strcpy(newfile, d->d_name);
+     }
+   }
+   closedir(dir);
+   return gotit;
+ }
+ 
+ /* Maildir open */
+  
+ MAILSTREAM *maildir_open (MAILSTREAM *stream)
+ {
+   char tmp[MAILTMPLEN];
+   struct stat sbuf;
+ 
+   if (!stream) return &maildirproto;
+   if (stream->local) fatal ("maildir recycle stream");
+   md_domain_name();    /* get domain name for maildir files in mdlocaldomain */
+   if(mypid == (pid_t) 0)
+     mypid = getpid();
+   if (!stream->rdonly){
+      stream->perm_seen = stream->perm_deleted = stream->perm_flagged = 
+ 	stream->perm_answered = stream->perm_draft = T;
+   }
+   stream->local = (MAILDIRLOCAL *) fs_get (sizeof (MAILDIRLOCAL));
+   memset(LOCAL, 0, sizeof(MAILDIRLOCAL));
+   LOCAL->fd = -1;
+ 
+   LOCAL->courier = IS_COURIER(stream->mailbox);
+   strcpy(tmp, stream->mailbox);
+   if (maildir_file_path (stream->mailbox, tmp))
+      LOCAL->dir = cpystr (tmp);
+   LOCAL->candouid = maildir_can_assign_uid(stream);
+   maildir_read_uid(stream, &stream->uid_last, &stream->uid_validity);
+   if (LOCAL->dir){
+      MDFLD(tmp, LOCAL->dir, Cur);
+      LOCAL->curdir = cpystr (tmp);
+      if (stat (LOCAL->curdir,&sbuf) < 0) {
+          sprintf (tmp,"Can't open folder %s: %s",
+ 				stream->mailbox,strerror (errno));
+          mm_log (tmp,ERROR);
+ 	 maildir_close(stream, 0);
+         return NIL;
+      }
+   }
+ 
+   if(maildir_file_path (stream->mailbox, tmp)){
+     fs_give ((void **) &stream->mailbox);
+     stream->mailbox = cpystr(tmp);
+   }
+ 
+   LOCAL->buf = (char *) fs_get ((LOCAL->buflen = SENDBUFLEN) + 1);
+   stream->sequence++;
+   stream->nmsgs = stream->recent = 0L;
+ 
+   maildir_parse_folder(stream, 1);
+ 
+   return stream;
+ }
+ 
+ /* Maildir initial parsing of the folder */
+ void
+ maildir_parse_folder (MAILSTREAM *stream, int full)
+ {
+    char tmp[MAILTMPLEN], tmp2[MAILTMPLEN];
+    struct direct **namescur = NIL, **namesnew = NIL;
+    unsigned long i, nfilescur = 0L, nfilesnew = 0L, oldpos, newpos, total;
+    int scan_err, rescan, loop = 0;
+ 
+    if (!stream)		/* what??? */
+       return;
+ 
+    MM_CRITICAL(stream);
+ 
+    MDFLD(tmp, LOCAL->dir, New);
+    maildir_scandir (tmp, &namesnew, &nfilesnew, &scan_err, CCLIENT);
+    if (scan_err < 0)
+       maildir_abort(stream);
+ 
+    /* Scan old messages first, escoba! */
+    if(stream->rdonly ||
+       (LOCAL && ((maildir_initial_check(stream, Cur) == 0)
+ 							|| nfilesnew > 0L))){
+       MDFLD(tmp, LOCAL->dir, Cur);
+       LOCAL->scantime =  maildir_scandir (tmp, &namescur, &nfilescur, 
+ 					&scan_err, CCLIENT);
+       if (scan_err < 0){
+ 	if(namesnew){
+ 	  for(i = 0L; i < nfilesnew; i++)
+ 	    fs_give((void **)&namesnew[i]);
+ 	  fs_give((void **) &namesnew);
+ 	}
+ 	 maildir_abort(stream);
+       }
+    }
+    if(LOCAL && (maildir_initial_check(stream, New) == 0)
+ 	&& (nfilescur > 0L)){
+       MDFLD(tmp, LOCAL->dir, New);
+       while(LOCAL && loop < 10){
+ 	 if(nfilesnew == 0L)
+ 	   maildir_scandir (tmp, &namesnew, &nfilesnew, &scan_err, CCLIENT);
+          if (scan_err < 0){
+ 	    if(namesnew){
+ 	      for(i = 0L; i < nfilesnew; i++)
+ 		fs_give((void **)&namesnew[i]);
+ 	      fs_give((void **) &namesnew);
+ 	    }
+ 	    maildir_abort(stream);
+ 	    break;
+ 	 }
+ 	 for(i = 0L, rescan = 0, newpos = oldpos = 0L; 
+ 		newpos < nfilescur && i < nfilesnew; i++){
+ 	    if(maildir_message_in_list(namesnew[i]->d_name, namescur, oldpos, 
+ 						nfilescur - 1L, &newpos)){
+ 	       oldpos = newpos;
+ 	       sprintf(tmp2,"%s/%s",tmp,namesnew[i]->d_name);
+ 	       if(unlink(tmp2) < 0)
+ 		 scan_err = -1;
+ 	       rescan++;
+ 	    }
+ 	    else
+ 	      newpos = oldpos;
+ 	 }
+ 	 if(scan_err < 0)
+ 	    maildir_abort(stream);
+ 	 if(rescan == 0)
+ 	   break;
+ 	 else{ /* restart */
+ 	   if(namesnew){
+ 	     for(i = 0L; i < nfilesnew; i++)
+ 		fs_give((void **)&namesnew[i]);
+ 	     fs_give((void **) &namesnew);
+ 	   }
+ 	   nfilesnew = 0L;
+ 	   loop++;
+ 	 }
+       }
+    }
+    if(loop == 10)
+      maildir_abort(stream);
+    if(LOCAL){
+      if(stream->rdonly)
+ 	stream->recent = 0L;
+      total = namescur || stream->rdonly 
+ 		? maildir_parse_dir(stream, 0L, Cur, namescur, 
+ 					      nfilescur, full) : stream->nmsgs;
+      stream->nmsgs = maildir_parse_dir(stream, total, New, namesnew, 
+ 						nfilesnew, full);
+    }
+    if(namesnew){
+      for(i = 0L; i < nfilesnew; i++)
+ 	fs_give((void **)&namesnew[i]);
+      fs_give((void **) &namesnew);
+    }
+    if(namescur){
+      for(i = 0L; i < nfilescur; i++)
+ 	fs_give((void **)&namescur[i]);
+      fs_give((void **) &namescur);
+    }
+    MM_NOCRITICAL(stream);
+ }
+ 
+ int
+ maildir_initial_check (MAILSTREAM *stream, DirNamesType dirtype)
+ {
+    char tmp[MAILTMPLEN];
+    struct stat sbuf;
+ 
+    MDFLD(tmp, LOCAL->dir, dirtype);
+    if (access (tmp, R_OK|W_OK|X_OK) != 0){
+       maildir_abort(stream);
+       return -1;
+    }
+ 
+    MDFLD(tmp, LOCAL->dir, Cur);
+    if (dirtype != New && 
+ 	(stat(tmp, &sbuf) < 0 || sbuf.st_ctime == LOCAL->scantime))
+       return -1;
+    return 0;
+ }
+ 
+ 
+ /* Return the number of messages in the directory, while filling the
+  * elt structure.
+  */
+ 
+ unsigned long
+ maildir_parse_dir(MAILSTREAM *stream, unsigned long nmsgs,
+ 		  DirNamesType dirtype, struct direct **names, 
+ 		  unsigned long nfiles, int full)
+ {
+    char tmp[MAILTMPLEN], tmp2[MAILTMPLEN], file[MAILTMPLEN], 
+ 	newfile[MAILTMPLEN], *mdstr;
+    struct stat sbuf;
+    unsigned long i, new = 0L, l, uid_last;
+    unsigned long recent = stream ? stream->recent : 0L;
+    int d = 0, f = 0, r = 0, s = 0, t = 0;
+    int we_compute, in_list;
+    int silent = stream ? stream->silent : NIL;
+    MESSAGECACHE *elt;
+ 
+    MDFLD(tmp, LOCAL->dir, dirtype);
+    if (dirtype == Cur && !stream->rdonly)
+       for (i = 1L; i <= stream->nmsgs;){
+ 	elt = mail_elt(stream,  i);
+ 	in_list = elt && elt->private.spare.ptr && nfiles > 0L
+ 		  ? (MDPOS(elt) < nfiles 
+ 		    ? same_maildir_file(MDFILE(elt), names[MDPOS(elt)]->d_name)
+ 		    : NIL)
+ 		    || maildir_message_in_list(MDFILE(elt), names, 0L, 
+ 						nfiles - 1L, &MDPOS(elt))
+ 		  : NIL;
+ 	if (!in_list){
+ 	   if (elt->private.spare.ptr)
+ 	      maildir_free_file ((void **) &elt->private.spare.ptr);
+ 
+ 	   if (elt->recent) --recent;
+ 	   mail_expunged(stream,i);
+ 	}
+ 	else i++;
+       }
+ 
+    stream->silent = T;
+    uid_last = 0L;
+    for (we_compute = 0, i = l = 1L; l <= nfiles; l++){
+       unsigned long pos, uid;
+       if (dirtype == New && !stream->rdonly){ /* move new messages to cur */
+ 	pos = l - 1L;
+ 	sprintf (file,"%s/%s", tmp, names[pos]->d_name);
+ 	if(lstat(file,&sbuf) == 0)
+ 	   switch(sbuf.st_mode & S_IFMT){
+ 	    case S_IFREG:
+ 		strcpy(tmp2, names[pos]->d_name);
+ 		if((mdstr = strstr(tmp2,MDSEP(3))) 
+ 		   || (mdstr = strstr(tmp2,MDSEP(2))))
+ 		   *(mdstr+1) = '2';
+ 		else
+ 		   strcat(tmp2, MDSEP(2));
+ 		sprintf(newfile, "%s/%s",LOCAL->curdir, tmp2);
+ 		if(rename (file, newfile) != 0){
+ 		   mm_log("Unable to read new mail!", WARN);
+ 		   continue;
+ 		}
+ 		unlink (file);
+ 		new++;
+ 	        break;
+ 	    case S_IFLNK:  /* clean up, clean up, everybody, everywhere */
+ 		if(unlink(file) < 0){
+ 		   if(LOCAL->link == NIL){ 
+ 		      mm_log("Unable to remove symbolic link", WARN);
+ 		      LOCAL->link = T;
+ 		   }
+ 		}
+ 		continue;
+ 		break;
+ 	    default: 
+ 		if(LOCAL && LOCAL->link == NIL){
+ 		  mm_log("Unrecognized file or link in folder", WARN);
+ 		  LOCAL->link = T;
+ 		}
+ 		continue;
+ 		break;
+ 	   }
+       }
+       mail_exists(stream, i + nmsgs);
+       elt = mail_elt(stream, i + nmsgs);
+       pos = (elt && elt->private.spare.ptr) ? MDPOS(elt) : l - 1L;
+       if (dirtype == New) elt->recent = T;
+       maildir_getflag(names[pos]->d_name, &d, &f, &r ,&s, &t);
+       if (elt->private.spare.ptr)
+ 	 maildir_free_file_only ((void **)&elt->private.spare.ptr);
+       else{
+ 	 maildir_get_file((MAILDIRFILE **)&elt->private.spare.ptr);
+ 	 we_compute++;
+       }
+       MDFILE(elt) = cpystr(names[pos]->d_name);
+       MDPOS(elt)  = pos;
+       MDLOC(elt)  = dirtype;
+       if (dirtype == Cur){	/* deal with UIDs */
+ 	if(elt->private.uid == 0L)
+ 	  elt->private.uid = maildir_get_uid(MDFILE(elt));
+ 	if(elt->private.uid <= uid_last){
+ 	  uid = (we_compute ? uid_last : stream->uid_last) + 1L;
+ 	  if(LOCAL->candouid)
+ 	    maildir_assign_uid(stream, i + nmsgs, uid);
+ 	  else
+ 	    elt->private.uid = uid;
+ 	}
+ 	else
+ 	  uid = elt->private.uid;
+ 	uid_last = uid;
+ 	if(uid_last > stream->uid_last)
+ 	  stream->uid_last = uid_last;
+       }
+       if(dirtype == New && !stream->rdonly){
+ 	maildir_free_file_only((void **)&elt->private.spare.ptr);
+ 	MDFILE(elt)  = cpystr(tmp2);
+ 	MDSIZE(elt)  = sbuf.st_size;
+ 	MDMTIME(elt) = sbuf.st_mtime;
+ 	MDLOC(elt)   = Cur;
+       }
+       if (elt->draft != d || elt->flagged != f || 
+ 	elt->answered != r || elt->seen != s || elt->deleted != t){
+ 	   elt->draft = d; elt->flagged = f; elt->answered = r;
+ 	   elt->seen  = s; elt->deleted = t;
+ 	   if (!we_compute && !stream->rdonly)
+ 	      MM_FLAGS(stream, i+nmsgs);
+       }
+       maildir_get_date(stream, i+nmsgs);
+       elt->valid = T;
+       i++;
+    }
+    stream->silent = silent;
+    if(LOCAL->candouid && dirtype == Cur)
+       maildir_read_uid(stream, NULL, &stream->uid_validity);
+    if (dirtype == New && stream->rdonly)
+       new = nfiles;
+    mail_exists(stream, nmsgs  + ((dirtype == New) ? new : nfiles));
+    mail_recent(stream, recent + ((dirtype == New) ? new : 0L));
+ 
+    return (nmsgs  + (dirtype == New ? new : nfiles));
+ }
+ 
+ long maildir_ping (MAILSTREAM *stream)
+ {
+   maildir_parse_folder(stream, 0);
+   if(stream && LOCAL){
+      if(LOCAL->candouid)
+         maildir_uid_renew_tempfile(stream);
+      else	 /* try again to get uids */
+ 	LOCAL->candouid = maildir_can_assign_uid(stream);
+   }
+   return stream && LOCAL ? LONGT : NIL;
+ }
+ 
+ int maildir_select (const struct direct *name)
+ {
+  return (name->d_name[0] != '.');
+ }
+ 
+ /*
+  * Unfortunately, there is no way to sort by arrival in this driver, this
+  * means that opening a folder in this driver using the scandir function
+  * will always make this driver slower than any driver that has a natural
+  * way of sorting by arrival (like a flat file format, "mbox", "mbx", etc).
+  */
+ int maildir_namesort (const void *d1, const void *d2)
+ {
+   const struct direct *e1 = *(const struct direct **) d1;
+   const struct direct *e2 = *(const struct direct **) d2;
+ 
+   return comp_maildir_file((char *) e1->d_name, (char *) e2->d_name);
+ }
+ 
+ /* Maildir close */
+ 
+ void maildir_close (MAILSTREAM *stream, long options)
+ {
+   MESSAGECACHE *elt;
+   unsigned long i;
+   int silent = stream ? stream->silent : 0;
+   mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
+ 
+   if (!stream) return;
+ 
+   for (i = 1L; i <= stream->nmsgs; i++)
+     if((elt = (MESSAGECACHE *) (*mc)(stream,i,CH_ELT)) && elt->private.spare.ptr)
+       maildir_free_file ((void **) &elt->private.spare.ptr);
+   stream->silent = T;
+   if (options & CL_EXPUNGE) maildir_expunge (stream, NIL, NIL);
+   maildir_abort(stream);
+   if (mdfpath) fs_give((void **)&mdfpath);
+   if (mypid) mypid = (pid_t) 0;
+   stream->silent = silent;
+ }
+ 
+ void maildir_check (MAILSTREAM *stream)
+ {
+   if (maildir_ping (stream)) mm_log ("Check completed",(long) NIL);   
+ }
+ 
+ long maildir_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs, long flags)
+ {
+   char tmp[MAILTMPLEN];
+   unsigned long i;
+   MESSAGECACHE *elt;
+   char *s;
+                                 /* UID call "impossible" */
+   if (flags & FT_UID || !LOCAL) return NIL;
+   elt = mail_elt (stream, msgno);
+ 
+   if (!(flags & FT_PEEK) && !elt->seen){
+     elt->seen = T;
+     maildir_flagmsg (stream, elt);
+     MM_FLAGS(stream, elt->msgno);
+   }
+ 
+   MSGPATH(tmp, LOCAL->dir, MDFILE(elt), MDLOC(elt));
+   if (LOCAL->fd < 0)	/* if file closed ? */
+      LOCAL->fd = open(tmp,O_RDONLY,NIL);
+ 
+   if (LOCAL->fd < 0 && (errno == EACCES || errno == ENOENT)){
+      INIT (bs, mail_string, "", 0);
+      elt->rfc822_size = 0L;
+      return NIL;
+   }
+ 
+   s = maildir_text_work(stream, elt, &i, flags);
+   INIT (bs, mail_string, s, i);
+   return LONGT;
+ }
+ 
+ char *maildir_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
+                       unsigned long *length,long flags)
+ {
+   FDDATA d;
+   STRING bs;
+   char *s,tmp[CHUNK];
+   unsigned long msgno = elt->msgno;
+   static int try = 0;
+ 
+   if (length)
+      *length = 0L;
+   LOCAL->buf[0] = '\0';
+ 
+   MSGPATH(tmp, LOCAL->dir, MDFILE(elt), MDLOC(elt));
+   if (LOCAL->fd < 0)	/* if file closed ? */
+      LOCAL->fd = open(tmp,O_RDONLY,NIL);
+ 
+   if (LOCAL->fd < 0){		/* flag change? */
+       if (try < 5){
+ 	try++;
+ 	if (maildir_update_elt_maildirp(stream, msgno) > 0)
+ 	  try = 0;
+ 	return maildir_text_work(stream, mail_elt(stream, msgno),length, flags);
+       }
+       try = 0;
+       return NULL;
+   }
+ 
+   lseek (LOCAL->fd, elt->private.msg.text.offset,L_SET);
+ 
+   if (flags & FT_INTERNAL) {    /* initial data OK? */
+     if (elt->private.msg.text.text.size > LOCAL->buflen) {
+       fs_give ((void **) &LOCAL->buf);
+       LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
+                                      elt->private.msg.text.text.size) + 1);
+     }
+     read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size);
+     LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0';
+   }
+   else {
+     if (elt->rfc822_size > LOCAL->buflen) {
+       fs_give ((void **) &LOCAL->buf);
+       LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->rfc822_size) + 1);
+     }
+     d.fd = LOCAL->fd;           /* yes, set up file descriptor */
+     d.pos = elt->private.msg.text.offset;
+     d.chunk = tmp;              /* initial buffer chunk */
+     d.chunksize = CHUNK;
+     INIT (&bs,fd_string,&d,elt->private.msg.text.text.size);
+     for (s = LOCAL->buf; SIZE (&bs);) switch (CHR (&bs)) {
+     case '\r':                  /* carriage return seen */
+       *s++ = SNX (&bs);         /* copy it and any succeeding LF */
+       if (SIZE (&bs) && (CHR (&bs) == '\n')) *s++ = SNX (&bs);
+       break;
+     case '\n':
+       *s++ = '\r';              /* insert a CR */
+     default:
+       *s++ = SNX (&bs);         /* copy characters */
+     }
+     *s = '\0';                  /* tie off buffer */
+     *length = s - (char *) LOCAL->buf;   /* calculate length */
+   }
+   close(LOCAL->fd); LOCAL->fd = -1;
+   return LOCAL->buf;
+ }
+ 
+ /* maildir parse, fill the elt structure... well not all of it... */
+ unsigned long maildir_parse_message(MAILSTREAM *stream, unsigned long msgno,
+ 				    DirNamesType dirtype)
+ {
+   char *b, *s, *t, c;
+   char tmp[MAILTMPLEN];
+   struct stat sbuf;
+   unsigned long i, len;
+   int d, f, r, se, dt;
+   MESSAGECACHE *elt;
+ 
+   elt = mail_elt (stream,msgno);
+   MSGPATH(tmp, LOCAL->dir, MDFILE(elt), dirtype);
+   if(stat(tmp, &sbuf) == 0)
+      MDSIZE(elt) = sbuf.st_size;
+ 
+   maildir_get_date(stream, msgno);
+   maildir_getflag(MDFILE(elt), &d, &f, &r ,&se, &dt);
+   elt->draft = d; elt->flagged = f; elt->answered = r; elt->seen = se;
+   elt->deleted = dt; elt->valid  = T;
+   if (LOCAL->fd < 0)	/* if file closed ? */
+      LOCAL->fd = open(tmp,O_RDONLY,NIL);
+ 
+   if (LOCAL->fd >= 0){
+ 	s = (char *) fs_get (MDSIZE(elt) + 1);
+ 	read (LOCAL->fd,s,MDSIZE(elt));
+ 	s[MDSIZE(elt)] = '\0';
+ 	t = s + strlen(s);	/* make t point to the end of s */
+ 	for (i = 0L, b = s; b < t && !(i && (*b == '\n')); i = (*b++ == '\n'));
+ 	len = (*b ? ++b : b) - s;
+ 	elt->private.msg.header.text.size = 
+ 		elt->private.msg.text.offset = len;
+ 	elt->private.msg.text.text.size = MDSIZE(elt) - len;
+ 	for (i = 0L, b = s, c = *b; b &&
+ 	    ((c < '\016' && ((c == '\012' && ++i) 
+ 			 ||(c == '\015' && *(b+1) == '\012' && ++b && (i +=2))))
+ 	    || b < t); i++, c= *++b);
+ 	elt->rfc822_size = i;
+ 	fs_give ((void **) &s);
+ 	close(LOCAL->fd); LOCAL->fd = -1;
+   }
+   return elt->rfc822_size;
+ }
+ 
+ int
+ maildir_update_elt_maildirp(MAILSTREAM *stream, unsigned long msgno)
+ {
+      char tmp[MAILTMPLEN];
+      struct direct **names = NIL;
+      unsigned long i, nfiles, pos;
+      int d = 0, f = 0 , r = 0, s = 0, t = 0, in_list, scan_err;
+      MESSAGECACHE *elt;
+ 
+      MDFLD(tmp, LOCAL->dir, Cur);
+ 
+      maildir_scandir (tmp, &names, &nfiles, &scan_err, CCLIENT);
+ 
+      elt = mail_elt (stream,msgno);
+ 
+      in_list = nfiles > 0L
+ 	    ? maildir_message_in_list(MDFILE(elt), names, 0L, nfiles - 1L, &pos)
+ 	    : NIL;
+ 
+      if (in_list && pos >= 0L && pos < nfiles
+ 	 && !strcmp(MDFILE(elt), names[pos]->d_name)){
+ 	in_list = NIL;
+ 	maildir_abort(stream);
+      }
+ 
+      if (in_list && pos >= 0L && pos < nfiles){
+ 	maildir_free_file_only((void **)&elt->private.spare.ptr);
+ 	MDFILE(elt) = cpystr(names[pos]->d_name);
+ 	maildir_getflag(MDFILE(elt), &d, &f, &r ,&s, &t);
+ 	if (elt->draft != d || elt->flagged != f || 
+ 	   elt->answered != r || elt->seen != s || elt->deleted != t){
+ 	   elt->draft = d; elt->flagged = f; elt->answered = r;
+ 	   elt->seen  = s; elt->deleted = t;
+ 	   MM_FLAGS(stream, msgno);
+         }
+      }
+      for (i = 0L; i < nfiles; i++)
+ 	fs_give((void **) &names[i]);
+      if (names)
+ 	fs_give((void **) &names);
+      return in_list ? 1 : -1;
+ }
+ 
+ /* Maildir fetch message header */
+ 
+ char *maildir_header (MAILSTREAM *stream,unsigned long msgno,
+ 		unsigned long *length, long flags)
+ {
+   char tmp[MAILTMPLEN], *s;
+   MESSAGECACHE *elt;
+   static int try = 0;
+ 
+   if (length) *length = 0;
+   if (flags & FT_UID || !LOCAL) return "";	/* UID call "impossible" */
+   elt = mail_elt (stream,msgno);
+   if(elt->private.msg.header.text.size == 0)
+      maildir_parse_message(stream, msgno, MDLOC(elt));
+ 
+   MSGPATH(tmp, LOCAL->dir, MDFILE(elt), MDLOC(elt));
+   if (LOCAL->fd < 0)
+      LOCAL->fd = open (tmp,O_RDONLY,NIL);
+ 
+   if (LOCAL->fd < 0 && errno == EACCES){
+      mm_log ("Message exists but can not be read. Envelope and body lost!",ERROR);
+      return NULL;
+   }
+ 
+   if (LOCAL->fd < 0){			/* flag change? */
+       if (try < 5){
+ 	try++;
+ 	if (maildir_update_elt_maildirp(stream, msgno) > 0)
+ 	  try = 0;
+ 	return maildir_header(stream, msgno, length, flags);
+       }
+       try = 0;
+       return NULL;
+   }
+ 
+   if (flags & FT_INTERNAL){
+      if(elt->private.msg.header.text.size > LOCAL->buflen){
+          fs_give ((void **) &LOCAL->buf);
+          LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
+                                  elt->private.msg.header.text.size) + 1);
+      }
+      read (LOCAL->fd, (void *)LOCAL->buf, elt->private.msg.header.text.size);
+      LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0';
+   }
+   else{
+       s = (char *) fs_get(elt->private.msg.header.text.size+1);
+       read (LOCAL->fd, (void *)s, elt->private.msg.header.text.size);
+       s[elt->private.msg.header.text.size] = '\0';
+       *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,
+                        elt->private.msg.header.text.size);
+       fs_give ((void **) &s);
+   }
+   elt->private.msg.text.offset = elt->private.msg.header.text.size;
+   elt->private.msg.text.text.size = MDSIZE(elt) - elt->private.msg.text.offset;
+   close(LOCAL->fd); LOCAL->fd = -1;
+   return LOCAL->buf;
+ }
+ 
+ /* Maildir find list of subscribed mailboxes
+  * Accepts: mail stream
+  *	    pattern to search
+  */
+ 
+ void maildir_list (MAILSTREAM *stream,char *ref, char *pat)
+ {
+   char *s,test[MAILTMPLEN],file[MAILTMPLEN];
+   long i = 0L;
+ 
+   if((!pat || !*pat) && maildir_canonicalize (test,ref,"*")
+ 	&& maildir_valid_name(test)){	/* there is a #md/ leading here */
+     for (i = 3L; test[i] && test[i] != '/'; i++);
+     if ((s = strchr (test+i+1,'/')) != NULL) *++s = '\0';
+     else test[0] = '\0';
+     mm_list (stream,'/',test, LATT_NOSELECT);
+   }
+   else if (maildir_canonicalize (test,ref,pat)) {
+     if (test[3] == '/') {       /* looking down levels? */
+                                 /* yes, found any wildcards? */
+       if ((s = strpbrk (test,"%*")) != NULL){
+                                 /* yes, copy name up to that point */
+         strncpy (file,test+4,i = s - (test+4));
+         file[i] = '\0';         /* tie off */
+       }
+       else strcpy (file,test+4);/* use just that name then */
+                                 /* find directory name */
+       if ((s = strrchr (file, '/')) != NULL){
+         *s = '\0';              /* found, tie off at that point */
+         s = file;
+       }
+                                 /* do the work */
+       if(IS_COURIER(test))
+ 	courier_list_work (stream,s,test,0);
+       else
+ 	maildir_list_work (stream,s,test,0);
+     }
+                                 /* always an INBOX */
+     if (!compare_cstring (test,"#MD/INBOX"))
+       mm_list (stream,NIL,"#MD/INBOX",LATT_NOINFERIORS);
+     if (!compare_cstring (test,"#MC/INBOX"))
+       mm_list (stream,NIL,"#MC/INBOX",LATT_NOINFERIORS);
+   }
+ }
+ 
+ void courier_list (MAILSTREAM *stream,char *ref, char *pat)
+ {
+ /* I am too lazy to do anything. Do you care to ask maildir list, please?
+    The real reason why this is a dummy function is because we do not want to
+    see the same folder listed twice. 
+ */
+ }
+ 
+ /* For those that want to hide things, we give them a chance to do so */
+ void *maildir_parameters (long function, void *value)
+ {
+   void *ret = NIL;
+   switch ((int) function) {
+   case SET_MDINBOXPATH:
+     if(strlen((char *) value ) > 49)
+        strcpy(myMdInboxDir, "Maildir");
+     else
+        strcpy(myMdInboxDir, (char *) value);
+   case GET_MDINBOXPATH:
+     if (myMdInboxDir[0] == '\0') strcpy(myMdInboxDir,"Maildir");
+     ret = (void *) myMdInboxDir;
+     break;
+   case SET_COURIERSTYLE:
+     CourierStyle = (long) value;
+   case GET_COURIERSTYLE:
+     ret = (void *) CourierStyle;
+     break;
+   case GET_DIRFMTTEST:
+     ret = (void *) maildir_dirfmttest;
+     break;
+   default:
+     break;
+   }
+   return ret;
+ }
+ 
+ int maildir_create_folder(char *mailbox)
+ {
+   char tmp[MAILTMPLEN], err[MAILTMPLEN];
+   int i;
+ 
+   for (i = Cur; i != EndDir; i++){
+ 	MDFLD(tmp, mailbox, i);
+ 	if (mkdir(tmp, 0700) && errno != EEXIST){ /* try to make new dir */
+ 	    sprintf (err, "Can't create %s: %s", tmp, strerror(errno));
+ 	    mm_log (err,ERROR);
+ 	    return NIL;
+ 	}
+   }
+   return T;
+ }
+ 
+ int maildir_create_work(char *mailbox, int loop)
+ {
+   char *s, c, err[MAILTMPLEN], tmp[MAILTMPLEN], tmp2[MAILTMPLEN], mbx[MAILTMPLEN];
+   int fnlen, create_dir = 0, courier, mv;
+   struct stat sbuf;
+   long style = (long) maildir_parameters(GET_COURIERSTYLE, NIL);
+ 
+   courier = IS_COURIER(mailbox);
+   strcpy(mbx, mailbox);
+   mv = maildir_valid(mbx) ? 1 : 0;
+   maildir_file_path(mailbox, tmp);
+   if (mailbox[strlen(mailbox) - 1] == MDSEPARATOR(courier)){
+       create_dir++;
+       mailbox[strlen(mailbox) - 1] = '\0';
+   }
+ 
+   if(!loop && courier){
+     if(mv){
+        if(create_dir){
+ 	  if(style == CCLIENT)
+ 	   strcpy (err,"Can not create directory: folder exists. Create subfolder");
+ 	  else
+ 	   strcpy(err,"Folder and Directory already exist");
+        }
+        else
+           strcpy (err, "Can't create mailbox: mailbox already exists");
+     }
+     else{
+ 	if(create_dir)
+ 	   strcpy(err, "Can not create directory. Cread folder instead");
+ 	else
+ 	  err[0] = '\0';
+     }
+     if(err[0]){
+        mm_log (err,ERROR);
+        return NIL;
+     }
+   }
+ 
+   fnlen = strlen(tmp);
+   if ((s = strrchr(mailbox,MDSEPARATOR(courier))) != NULL){
+      c = *++s;
+     *s = '\0';
+     if ((stat(tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+         !maildir_create_work (mailbox, ++loop))
+       return NIL;
+     *s = c;
+   }
+   tmp[fnlen] = '\0';
+ 
+   if (mkdir(tmp,0700) && errno != EEXIST)
+      return NIL;
+ 
+   if (create_dir)
+      mailbox[fnlen] = '/';
+ 
+   if (create_dir){
+      if(style == CCLIENT){
+ 	if(!courier){
+ 	   FILE *fp = NULL;
+ 	   sprintf(tmp2,"%s%s", tmp, MDDIR);
+ 	   if ((fp = fopen(tmp2,"w")) == NULL){
+ 	      sprintf (err,"Problem creating %s: %s", tmp2, strerror(errno));
+               mm_log (err,ERROR);
+               return NIL;
+ 	   }
+ 	   fclose(fp);
+ 	}
+      }
+      return T;
+   }
+   else
+      return maildir_create_folder(tmp);
+ }
+ 
+ long maildir_create (MAILSTREAM *stream,char *mailbox)
+ {
+   char tmp[MAILTMPLEN], err[MAILTMPLEN];
+   int rv, create_dir;
+ 
+   create_dir = mailbox ? 
+ 		(mailbox[strlen(mailbox) - 1] == 
+ 					MDSEPARATOR(IS_COURIER(mailbox))) : 0;
+   maildir_file_path(mailbox, tmp);
+   strcpy(tmp, mailbox);
+   rv = maildir_create_work(mailbox, 0);
+   strcpy(mailbox, tmp);
+   if (rv == 0){
+      sprintf (err,"Can't create %s %s",
+ 		   (create_dir ? "directory" : "mailbox"), mailbox);
+      mm_log (err,ERROR);
+   }
+   return rv ? LONGT : NIL;
+ }
+ 
+ #define MAXTRY 10000
+ void maildir_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+ {
+   char oldfile[MAILTMPLEN],newfile[MAILTMPLEN],fn[MAILTMPLEN];
+   char *s;
+   int ren, try = 0;
+ 
+   if (elt->valid){
+      for (try = 1; try > 0 && try < MAXTRY; try++){
+                                 /* build the new filename */
+ 	sprintf (oldfile,"%s/%s",LOCAL->curdir, MDFILE(elt));
+ 	fn[0] = '\0';
+ 	if ((ren = maildir_message_exists(stream, MDFILE(elt), fn)) == 0){
+ 	    errno = ENOENT;
+ 	    try = MAXTRY;
+ 	}
+ 	if (*fn)	/* new oldfile! */
+ 	   sprintf (oldfile,"%s/%s",LOCAL->curdir,fn);
+         if ((s = strrchr (MDFILE(elt), FLAGSEP))) *s = '\0';
+ 	sprintf (fn,"%s%s%s%s%s%s%s", MDFILE(elt), MDSEP(2),
+ 		MDFLAG(Draft, elt->draft), MDFLAG(Flagged, elt->flagged),
+ 		MDFLAG(Replied, elt->answered), MDFLAG(Seen, elt->seen),
+ 		MDFLAG(Trashed, elt->deleted));
+ 	sprintf (newfile,"%s/%s",LOCAL->curdir,fn);
+         if (ren != 0 && rename (oldfile,newfile) >= 0)
+ 	    try = -1;
+      }
+ 
+      if (try > 0){
+        sprintf(oldfile,"Unable to write flags to disk: %s",
+ 		(errno == ENOENT) ? "message is gone!" : strerror (errno));
+        mm_log(oldfile,ERROR);
+        return;
+      }
+ #ifdef __CYGWIN__
+      utime(LOCAL->curdir, NIL);	/* make sure next scan will catch the change */
+ #endif
+      maildir_free_file_only ((void **) &elt->private.spare.ptr);
+      MDFILE(elt) = cpystr (fn);
+   }
+ }
+ 
+ long maildir_expunge (MAILSTREAM *stream, char *sequence, long options)
+ {
+   long ret;
+   MESSAGECACHE *elt;
+   unsigned long i, n = 0L;
+   unsigned long recent = stream->recent;
+   char tmp[MAILTMPLEN];
+ 
+   mm_critical (stream);               /* go critical */
+   ret = sequence ? ((options & EX_UID) ?
+                          mail_uid_sequence (stream,sequence) :
+                          mail_sequence (stream,sequence)) : LONGT;
+   if(ret == 0L)
+      return 0L;
+   for (i = 1L; i <= stream->nmsgs;){
+     elt = mail_elt (stream,i);
+     if (elt->deleted && (sequence ? elt->sequence : T)){
+       sprintf (tmp,"%s/%s",LOCAL->curdir, MDFILE(elt));
+       if (unlink (tmp) < 0) {/* try to delete the message */
+       sprintf (tmp,"Expunge of message %ld failed, aborted: %s",i,
+               strerror (errno));
+       if (!stream->silent)
+          mm_log (tmp,WARN);
+       break;
+       }
+       if (elt->private.spare.ptr)
+        maildir_free_file ((void **) &elt->private.spare.ptr);
+       if (elt->recent) --recent;/* if recent, note one less recent message */
+       mail_expunged (stream,i);       /* notify upper levels */
+        n++;                    /* count up one more expunged message */
+     }
+     else i++;
+   }
+   if(n){                      /* output the news if any expunged */
+     sprintf (tmp,"Expunged %ld messages",n);
+     if (!stream->silent)
+        mm_log (tmp,(long) NIL);
+   }
+   else
+     if (!stream->silent)
+       mm_log ("No messages deleted, so no update needed",(long) NIL);
+   mm_nocritical (stream);     /* release critical */
+                             /* notify upper level of new mailbox size */
+   mail_exists (stream,stream->nmsgs);
+   mail_recent (stream,recent);
+   return ret;
+ }
+ 
+ long maildir_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+ {
+   STRING st;
+   MESSAGECACHE *elt;
+   unsigned long len;
+   int fd;
+   unsigned long i;
+   struct stat sbuf;
+   char tmp[MAILTMPLEN], flags[MAILTMPLEN], path[MAILTMPLEN], *s;
+ 				/* copy the messages */
+   if ((options & CP_UID) ? mail_uid_sequence (stream, sequence) : 
+   	mail_sequence (stream,sequence)) 
+   for (i = 1L; i <= stream->nmsgs; i++)
+     if ((elt = mail_elt (stream,i))->sequence){
+       MSGPATH(path, LOCAL->dir, MDFILE(elt), MDLOC(elt));
+       if (((fd = open (path,O_RDONLY,NIL)) < 0)	 
+ 	  ||((!elt->rfc822_size && 
+ 		((stat(path, &sbuf) < 0) || !S_ISREG (sbuf.st_mode)))))
+ 	return NIL;
+ 	if(!elt->rfc822_size)
+ 	  MDSIZE(elt) = sbuf.st_size;
+         s = (char *) fs_get(MDSIZE(elt) + 1);
+         read (fd,s,MDSIZE(elt));
+         s[MDSIZE(elt)] = '\0';
+         close (fd);
+ 	len = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen, s, MDSIZE(elt));
+         INIT (&st,mail_string, LOCAL->buf, len);
+ 	elt->rfc822_size = len;
+ 	fs_give ((void **)&s);
+ 
+       flags[0] = flags[1] = '\0';
+       if (elt->seen) strcat (flags," \\Seen");
+       if (elt->draft) strcat (flags," \\Draft");
+       if (elt->deleted) strcat (flags," \\Deleted");
+       if (elt->flagged) strcat (flags," \\Flagged");
+       if (elt->answered) strcat (flags," \\Answered");
+       flags[0] = '(';         /* open list */
+       strcat (flags,")");     /* close list */
+       mail_date (tmp,elt);	/* generate internal date */
+       if (!mail_append_full (NIL,mailbox,flags,tmp,&st))
+         return NIL;
+       if (options & CP_MOVE) elt->deleted = T;
+     }
+   return LONGT;			/* return success */
+ }
+ 
+ long maildir_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+ {
+   int fd, k;
+   STRING *message;
+   char c,*s, *flags, *date;
+   char tmp[MAILTMPLEN],file[MAILTMPLEN],path1[MAILTMPLEN],path2[MAILTMPLEN];
+   MESSAGECACHE elt;
+   long i, size = 0L, ret = LONGT, f;
+   unsigned long uf, ti;
+   static unsigned int transact = 0;
+ 
+   if (!maildir_valid(mailbox)) {
+     sprintf (tmp,"Not a valid Maildir mailbox: %s",mailbox);
+     mm_log (tmp,ERROR);
+     return NIL;
+   }
+ 
+  if (!*mdlocaldomain)
+      md_domain_name();    /* get domain name for maildir files in mdlocaldomain now! */
+ 
+  if (mypid == (pid_t) 0)
+     mypid = getpid();
+ 
+  if (!stream){
+     stream = &maildirproto;
+   
+     for (k = 0; k < NUSERFLAGS && stream->user_flags[k]; ++k)
+        fs_give ((void **) &stream->user_flags[k]);
+  }
+ 
+   if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
+ 
+   mm_critical (stream);		/* go critical */
+   /* call time(0) only once, use transact to distinguish instead */
+   ti = time(0);
+   do {
+     if (!SIZE (message)) {      /* guard against zero-length */
+       mm_log ("Append of zero-length message",ERROR);
+       ret = NIL;
+       break;
+     }
+     if (date && !mail_parse_date(&elt,date)){
+         sprintf (tmp,"Bad date in append: %.80s",date);
+         mm_log (tmp,ERROR);
+         ret = NIL;
+         break;
+     }
+     f = mail_parse_flags (stream,flags,&uf);
+ 				/* build file name we will use */
+     sprintf (file,"%lu.%d_%09u.%s%s%s%s%s%s",
+ 		ti, mypid, transact++, mdlocaldomain, (f ? MDSEP(2) : ""),
+ 		MDFLAG(Draft, f&fDRAFT), MDFLAG(Flagged, f&fFLAGGED),
+ 		MDFLAG(Replied, f&fANSWERED), MDFLAG(Seen, f&fSEEN));
+ 				/* build tmp file name */
+     if (maildir_file_path(mailbox, tmp))
+        MSGPATH(path1, tmp, file, Tmp);
+ 
+     if ((fd = open (path1,O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE)) < 0) {
+        sprintf (tmp, "Can't open append mailbox: %s", strerror (errno));
+        mm_log (tmp, ERROR);
+        return NIL;
+     }
+     for (size = 0,i = SIZE (message),s = (char *) fs_get (i + 1); i; --i)
+       if ((c = SNX (message)) != '\015') s[size++] = c;
+     if ((write (fd, s, size) < 0) || fsync (fd)) {
+ 	unlink (path1);		/* delete message */
+ 	sprintf (tmp, "Message append failed: %s", strerror (errno));
+ 	mm_log (tmp, ERROR);
+ 	ret = NIL;
+     }
+     fs_give ((void **) &s);	/* flush the buffer */
+     close (fd);			/* close the file */
+ 				/* build final filename to use */
+     if (maildir_file_path(mailbox, tmp))
+ 	MSGPATH(path2, tmp, file, New);
+     if (rename (path1,path2) < 0) {
+        sprintf (tmp, "Message append failed: %s", strerror (errno));
+        mm_log (tmp, ERROR);
+        ret = NIL;
+     }
+     unlink (path1);
+ 
+     if (ret)
+      if (!(*af) (stream,data,&flags,&date,&message)) ret = NIL;
+ 
+   } while (ret && message);	/* write the data */
+   mm_nocritical (stream);	/* release critical */
+   return ret;
+ }
+ 
+ long maildir_delete (MAILSTREAM *stream,char *mailbox)
+ {
+   DIR *dirp;
+   struct direct *d;
+   int i, remove_dir = 0, mddir = 0, rv, error = 0;
+   char tmp[MAILTMPLEN],tmp2[MAILTMPLEN], realname[MAILTMPLEN];
+   struct stat sbuf;
+   int courier = IS_COURIER(mailbox);
+ 
+   if (mailbox[strlen(mailbox) - 1] == MDSEPARATOR(courier)){
+       remove_dir++;
+       mailbox[strlen(mailbox) -1] = '\0';
+   }
+ 
+   if (!maildir_valid(mailbox)){
+       maildir_file_path(mailbox, tmp);
+       if (stat(tmp, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode)){
+         sprintf(tmp,"Can not remove %s", mailbox);
+ 	error++;
+       }
+   }
+ 
+   if (!error && remove_dir && !maildir_dir_is_empty(mailbox)){
+      sprintf(tmp,"Can not remove directory %s/: directory not empty", mailbox);
+      error++;
+   }
+ 
+   if(error){
+      mm_log (tmp,ERROR);
+      return NIL;
+   }
+ 
+   maildir_close(stream,0);	/* even if stream was NULL */
+ 
+   maildir_file_path(mailbox, realname);
+ 
+   if (remove_dir){
+      sprintf(tmp,"%s/%s", realname, MDDIR);
+      if ((rv = stat (tmp,&sbuf)) == 0 && S_ISREG(sbuf.st_mode))
+ 	rv = unlink(tmp);
+      else if (errno == ENOENT)
+ 	rv = 0;
+      if (rv != 0){
+ 	sprintf(tmp,"Can not remove %s/%s: %s", tmp2, MDDIR, strerror(errno));
+ 	mm_log (tmp,ERROR);
+ 	return NIL;
+      }
+      if (!maildir_valid(realname) && rmdir(realname) != 0){
+ 	sprintf(tmp,"Can not remove %s/: %s", mailbox, strerror(errno));
+ 	mm_log (tmp,ERROR);
+ 	return NIL;
+      }
+      return LONGT;
+   }
+   /* else remove just the folder. Remove all hidden files, except MDDIR */
+   for (i = Cur; i != EndDir; i++){
+       MDFLD(tmp, realname, i);
+ 
+       if (!(dirp = opendir (tmp))){
+ 	  sprintf(tmp,"Can not read %s/: %s", mailbox, strerror(errno));
+ 	  mm_log (tmp,ERROR);
+ 	  return NIL;
+       }
+ 
+       while ((d = readdir(dirp)) != NULL){
+ 	 if (strcmp(d->d_name, ".") && strcmp(d->d_name,"..")){
+ 	    sprintf(tmp2,"%s/%s", tmp, d->d_name);
+ 	    if (unlink(tmp2) != 0){
+ 	       sprintf(tmp2,"Can not remove %s: %s", mailbox, strerror(errno));
+ 	       mm_log (tmp2,ERROR);
+ 	       return NIL;
+ 	    }
+ 	 }
+       }
+       closedir(dirp);
+       if (rmdir(tmp) != 0){
+ 	 sprintf(tmp,"Can not remove %s: %s", mailbox, strerror(errno));
+ 	 mm_log (tmp,ERROR);
+ 	 return NIL;
+       }
+   }
+   /* 
+    * ok we have removed all subdirectories of the folder mailbox, Remove the
+    * hidden files.
+    */
+ 
+   if(!(dirp = opendir (realname))){
+     sprintf(tmp,"Can not read %s/: %s", realname, strerror(errno));
+     mm_log (tmp,ERROR);
+     return NIL;
+   }
+ 
+   while ((d = readdir(dirp)) != NULL){
+ 	if (strcmp(d->d_name, ".") && strcmp(d->d_name,"..")
+ 		&& (!strcmp(d->d_name, MDDIR)
+ 			|| !strncmp(d->d_name, MDUIDLAST, strlen(MDUIDLAST))
+ 			|| !strncmp(d->d_name, MDUIDTEMP, strlen(MDUIDTEMP)))){
+ 	   if(strcmp(d->d_name, MDDIR) == 0)
+ 	      mddir++;
+ 	   sprintf(tmp,"%s/%s", realname, d->d_name);
+ 	   if (unlink(tmp) != 0)
+ 	      error++;
+ 	}
+   }
+   closedir(dirp);
+   if (error || 
+ 	 (maildir_dir_is_empty(mailbox) && mddir == 0 && rmdir(realname) < 0)){
+         sprintf(tmp,"Can not remove folder %s: %s", mailbox, strerror(errno));
+         mm_log (tmp,ERROR);
+         return NIL;
+   }
+   return LONGT;
+ }
+ 
+ long maildir_rename (MAILSTREAM *stream, char *old, char *new)
+ {
+   char tmp[MAILTMPLEN],tmpnew[MAILTMPLEN], realold[MAILTMPLEN];
+   char realnew[MAILTMPLEN];
+   int courier = IS_COURIER(old) && IS_COURIER(new);
+   int i;
+   long rv = LONGT;
+   COURIER_S *cdir;
+ 
+   if((IS_COURIER(old) || IS_COURIER(new)) && !courier){
+     sprintf (tmp,"Can't rename mailbox %s to %s",old, new);
+     mm_log (tmp,ERROR);
+     return NIL;
+   }
+ 
+   if (!maildir_valid(old)){
+     sprintf (tmp,"Can't rename mailbox %s: folder not in maildir format",old);
+     mm_log (tmp,ERROR);
+     return NIL;
+   }
+   maildir_file_path(old, realold);
+   if (!maildir_valid_name(new) && new[0] == '#'){
+     sprintf (tmp,"Can't rename mailbox %s: folder not in maildir format",new);
+     mm_log (tmp,ERROR);
+     return NIL;
+   }
+   maildir_file_path(new, realnew);
+   if (access(tmpnew,F_OK) == 0){ 	/* new mailbox name must not exist */
+     sprintf (tmp,"Can't rename to mailbox %s: destination already exists",new);
+     mm_log (tmp,ERROR);
+     return NIL;
+   }
+ 
+   if(!courier){
+     if (rename (realold,realnew)){	/* try to rename the directory */
+        sprintf (tmp,"Can't rename mailbox %s to %s: %s",old, new,
+ 							strerror(errno));
+        mm_log (tmp,ERROR);
+        return NIL;
+     }
+     return LONGT;	/* return success */
+   }
+ 
+   cdir = courier_list_dir(old);
+   for (i = 0; cdir && i < cdir->total; i++){
+       if(strstr(cdir->data[i]->name, old)){
+ 	sprintf(tmp,"%s%s", new, cdir->data[i]->name+strlen(old));
+ 	maildir_file_path(cdir->data[i]->name, realold);
+ 	maildir_file_path(tmp, realnew);
+ 	if (rename (realold,realnew)){
+ 	   sprintf (tmp,"Can't rename mailbox %s to %s: %s",old, new,
+ 							strerror(errno));
+ 	   mm_log (tmp,ERROR);
+ 	   rv = NIL;
+ 	}
+     }
+   }
+   courier_free_cdir(&cdir);
+   return rv;
+ }
+ 
+ long maildir_sub (MAILSTREAM *stream,char *mailbox)
+ {
+   return sm_subscribe (mailbox);
+ }
+ 
+ long maildir_unsub (MAILSTREAM *stream,char *mailbox)
+ {
+   return sm_unsubscribe (mailbox);
+ }
+ 
+ void maildir_lsub (MAILSTREAM *stream,char *ref,char *pat)
+ {
+   void *sdb = NIL;
+   char *s, 	test[MAILTMPLEN];
+                                 /* get canonical form of name */
+   if (maildir_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) {
+     do if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,NIL);
+     while ((s = sm_read (&sdb)) != NULL); /* until no more subscriptions */
+   }
+ }
+ 
+ long maildir_canonicalize (char *pattern,char *ref,char *pat)
+ {
+   if (ref && *ref) {            /* have a reference */
+     strcpy (pattern,ref);       /* copy reference to pattern */
+                                 /* # overrides mailbox field in reference */
+     if (*pat == '#') strcpy (pattern,pat);
+                                 /* pattern starts, reference ends, with / */
+     else if ((*pat == '/') && (pattern[strlen (pattern) - 1] == '/'))
+       strcat (pattern,pat + 1); /* append, omitting one of the period */
+                                                                                 
+     else strcat (pattern,pat);  /* anything else is just appended */
+   }
+   else strcpy (pattern,pat);    /* just have basic name */
+   return maildir_valid_name(pattern) ? LONGT : NIL;
+ }
+ 
+ void maildir_list_work (MAILSTREAM *stream,char *dir,char *pat,long level)
+ {
+   DIR *dp;
+   struct direct *d;
+   struct stat sbuf;
+   char curdir[MAILTMPLEN],name[MAILTMPLEN], tmp[MAILTMPLEN];
+   char realpat[MAILTMPLEN];
+   long i;
+   char *maildirpath = mdirpath();
+ 
+   sprintf(curdir,"%s/%s/", myrootdir(pat), dir ? dir : maildirpath);
+   if ((dp = opendir (curdir)) != NULL){ 
+      if (dir) sprintf (name,"%s%s/",MDPREFIX(CCLIENT),dir);
+      else strcpy (name, pat);
+ 
+      if (level == 0 && !strpbrk(pat,"%*")){
+ 	if(maildir_valid(pat)){
+ 	  i =  maildir_contains_folder(pat, NULL)
+ 		? LATT_HASCHILDREN
+ 		: (maildir_is_dir(pat, NULL)
+ 			     ? LATT_HASNOCHILDREN : LATT_NOINFERIORS);
+ 	  maildir_file_path(pat, realpat);
+ 	  i +=  maildir_any_new_msgs(realpat) 
+ 			? LATT_MARKED : LATT_UNMARKED;
+ 	  mm_list (stream,'/', pat, i);
+ 	}
+ 	else
+ 	   if(pat[strlen(pat) - 1] == '/')
+ 	     mm_list (stream,'/', pat, LATT_NOSELECT);
+      }
+ 
+      while ((d = readdir (dp)) != NULL)
+ 	if(strcmp(d->d_name, ".") && strcmp(d->d_name,"..")
+ 		&& strcmp(d->d_name, MDNAME(Cur)) 
+ 		&& strcmp(d->d_name, MDNAME(Tmp)) 
+ 		&& strcmp(d->d_name, MDNAME(New))){
+ 
+ 	  if (dir) sprintf (tmp,"%s%s", name,d->d_name);
+ 	  else strcpy(tmp, d->d_name);
+ 
+ 	  if(pmatch_full (tmp, pat,'/')){
+ 	     sprintf(tmp,"%s/%s/%s", myrootdir(d->d_name), 
+ 				(dir ? dir : maildirpath), d->d_name);
+ 	     if(stat (tmp,&sbuf) == 0 
+ 		   && ((sbuf.st_mode & S_IFMT) == S_IFDIR)){
+ 	       if (dir) sprintf (tmp,"%s%s", name,d->d_name);
+ 	       else strcpy(tmp, d->d_name);
+                i = maildir_valid(tmp)
+ 			? (maildir_contains_folder(dir, d->d_name)
+ 			  ? LATT_HASCHILDREN
+ 			  : (maildir_is_dir(dir, d->d_name)
+ 			     ? LATT_HASNOCHILDREN : LATT_NOINFERIORS))
+ 			: LATT_NOSELECT;
+ 	       i +=  maildir_any_new_msgs(tmp)
+ 			    ? LATT_MARKED : LATT_UNMARKED;
+ 	       mm_list (stream,'/',tmp, i);
+ 	       strcat (tmp, "/");
+ 	       if(dmatch (tmp, pat,'/') &&
+                  (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL))){
+ 		   sprintf(tmp,"%s/%s",dir,d->d_name);
+  		   maildir_list_work (stream,tmp,pat,level+1);
+ 	       }
+ 	     }
+ 	  }
+        }
+      closedir (dp);
+   }
+ }
+ 
+ void courier_list_work (MAILSTREAM *stream, char *dir, char *pat, long level)
+ {
+   char c, curdir[MAILTMPLEN], tmp[MAILTMPLEN];
+   char realname[MAILTMPLEN], realpat[MAILTMPLEN] = {'\0'};
+   int i, found;
+   long style = (long) maildir_parameters(GET_COURIERSTYLE, NIL), j;
+   char *maildirpath = mdirpath();
+   COURIER_S *cdir;
+ 
+   if(!strpbrk(pat,"%*")){	/* a mailbox */
+      maildir_file_path(pat, curdir);
+      i = strlen(curdir) - 1;
+      if(curdir[i] == '/')
+        curdir[i] = '\0';
+      cdir = courier_list_dir(curdir);
+      if(cdir){
+ 	found = 0; j = 0L;
+ 	if(maildir_valid_name(pat)){
+ 	  for(i = 0; !found && i < cdir->total; i++)
+ 	     if(strstr(curdir, cdir->data[i]->name)){
+ 		if(strlen(curdir) < strlen(cdir->data[i]->name))
+ 		  found += 2;
+ 		else if(strlen(curdir) == strlen(cdir->data[i]->name))
+ 		  found -= 1;
+ 	     }
+ 	  if(found > 0)
+             j = LATT_HASCHILDREN;
+           else if(found == 0)
+ 	    j = (style == COURIER) ? LATT_HASNOCHILDREN : LATT_NOINFERIORS;
+ 	}
+ 	else
+ 	   j = LATT_NOSELECT;
+         j += maildir_any_new_msgs(curdir) ? LATT_MARKED : LATT_UNMARKED;
+ 	if (found)
+ 	   mm_list (stream, '.', pat, j);
+         courier_free_cdir(&cdir);
+      }
+      return;
+   }
+ 
+   strcpy(tmp,pat + 4);	/* a directory */
+   j = strlen(pat) - 1;
+   maildir_file_path(pat, realpat);
+   c = pat[j];
+   pat[j] = '\0';
+   realname[0] = '\0';
+   if(dir)
+     maildir_file_path(dir, realname);
+   sprintf(curdir,"%s%s%s/%s", (dir ? "" : myrootdir(pat)), (dir ? "" : "/"),
+ 		(dir ? realname : maildirpath),	(dir ? "" : "."));
+   sprintf(tmp, "%s%s/.", MDPREFIX(COURIER), dir ? dir : maildirpath);
+   if (level == 0 && tmp && pmatch_full (tmp, realpat, '.'))
+      mm_list (stream,'.', tmp, LATT_NOSELECT);
+ 
+   cdir = courier_list_dir(pat);
+   pat[j] = c;
+   for (i = 0; cdir && i < cdir->total; i++)
+    if(pmatch_full (cdir->data[i]->name, pat, '.')){
+       sprintf(tmp, "%s.", cdir->data[i]->name);
+       courier_list_info(&cdir, tmp, i);
+       mm_list (stream,'.',cdir->data[i]->name, cdir->data[i]->attribute);
+    }
+   courier_free_cdir(&cdir);
+ }
+ 
+ int 
+ same_maildir_file(char *name1, char *name2)
+ {
+  char tmp1[MAILTMPLEN], tmp2[MAILTMPLEN];
+  char *s;
+ 
+  strcpy(tmp1, name1 ? name1 : "");
+  strcpy(tmp2, name2 ? name2 : "");
+  if ((s = strrchr(tmp1, FLAGSEP)) != NULL)
+    *s = '\0';
+  if (((s = strrchr(tmp1, SIZESEP)) != NULL) && (strchr(s,'.') == NULL))
+    *s = '\0';
+  if ((s = strrchr(tmp2, FLAGSEP)) != NULL)
+    *s = '\0';
+  if (((s = strrchr(tmp2, SIZESEP)) != NULL) && (strchr(s,'.') == NULL))
+    *s = '\0';
+ 
+  return !strcmp(tmp1, tmp2);
+ }
+ 
+ unsigned long antoul(char *seed)
+ {
+   int i, error = 0;
+   unsigned long val = 0L, rv1 = 0L, t;
+   char c, *p;
+  if(!seed)
+    return 0L;
+  t = strtoul(seed, &p, 10);
+  if(p && (*p == '.' || *p == '_'))
+    return t;
+  /* else */
+  if((p = strchr(seed,'.')) != NULL)
+    *p = '\0';
+  error = (strlen(seed) > 6); /* too long */
+  for(i= strlen(seed)-1; error == 0 && i >= 0; i--){
+     c = seed[i];
+     if (c >= 'A' && c <= 'Z') val = c - 'A';
+     else if (c >= 'a' && c <= 'z') val = c - 'a' + 26;
+     else if (c >= '0' && c <= '9') val = c - '0' + 26 + 26; 
+     else if (c == '-') val = c - '-' + 26 + 26 + 10;
+     else if (c == '_') val = c - '_' + 26 + 26 + 10 + 1;
+     else error++;
+     rv1 = val + (rv1 << 6);
+  }
+  if(p)
+    *p = '.';
+   return error ? 0L : rv1;
+ }
+ 
+ unsigned long mdfntoul (char *name)
+ {
+   unsigned long t;
+   char *r, last;
+ 
+   if((*name == '_') && ((r = strpbrk(name,".,%+")) != NULL)){ /* Grrr!!! */
+     last = *r;
+     *r = '\0';
+      t = antoul(r+1);
+     *r = last;
+   }
+   else
+     t = antoul(name);
+   return t;
+ }
+ 
+ int comp_maildir_file(char *name1, char *name2)
+ {
+   int uset1 = 1, uset2 = 1, i, j, cmp;
+   unsigned long t1, t2;
+   char *s1, *s2;
+ 
+   if (!(name1 && *name1))
+      return (name2 && *name2) ? (*name2 == FLAGSEP ? 0 : -1) : 0;
+ 
+   if (!(name2 && *name2))
+      return (name1 && *name1) ? (*name1 == FLAGSEP ? 0 : 1) : 0;
+ 
+    if((cmp = strcmp(name1,name2)) == 0)
+       return 0;
+ 
+   t1 = strtoul(name1, &s1, 10);
+   t2 = strtoul(name2, &s2, 10);
+ 
+   if(!s1 || *s1 != '.')
+     uset1 = 0;
+ 
+   if(!s2 || *s2 != '.')
+     uset2 = 0;
+ 
+   if(uset1 && uset2)	/* normal sort order */
+     return (t1 < t2) ? -1 : (t1 > t2 ? 1 : (cmp < 0 ? -1 : 1));
+ 
+   /* If we make it here we say Grrrr.... first, then we try to figure out
+    * how to sort this mess.
+    * These are the rules.
+    * If there is a number at the beginning it is bigger than anything else.
+    * If there are digits, then the number of digits decides which one is bigger.
+    */
+ 
+   for(i = 0; isdigit(name1[i]); i++);
+   for(j = 0; isdigit(name2[j]); j++);
+ 
+   return(uset1 ? 1 
+ 	       : (uset2 ? -1 
+ 			: (i < j ? -1 : (i > j ? 1 : (cmp < 0 ? -1 : 1)))));
+ }
+ 
+ void
+ maildir_getflag(char *name, int *d, int *f, int *r ,int *s, int *t)
+ {
+   char tmp[MAILTMPLEN], *b;
+   int offset = 0;
+   int tmpd, tmpf, tmpr, tmps, tmpt;
+ 
+   if(d) *d = 0;
+   if(f) *f = 0;
+   if(r) *r = 0;
+   if(s) *s = 0;
+   if(t) *t = 0;
+ 
+   tmpd = tmpf = tmpr = tmps = tmpt = NIL; /* no flags set by default */
+   strcpy(tmp,name);
+   while ((b = strrchr(tmp+offset, FLAGSEP)) != NULL){
+     char flag,last;
+     int  k;
+     if (!++b) break;
+     switch (*b){
+ 	case '1':
+ 	case '2':
+ 	case '3': flag = *b; b += 2;
+ 		  for (k = 0; b[k] && b[k] != FLAGSEP && b[k] != ','; k++);
+ 		  last = b[k];
+ 		  b[k] = '\0';
+ 		  if (flag == '2' || flag == '3'){
+ 		     tmpd = strchr (b, MDFLAGC(Draft))   ? T : NIL;
+ 		     tmpf = strchr (b, MDFLAGC(Flagged)) ? T : NIL;
+ 		     tmpr = strchr (b, MDFLAGC(Replied)) ? T : NIL;
+ 		     tmps = strchr (b, MDFLAGC(Seen))    ? T : NIL;
+ 		     tmpt = strchr (b, MDFLAGC(Trashed)) ? T : NIL;
+ 		  }
+ 		  b[k] = last;
+ 		  b += k;
+ 		  for (; tmp[offset] && tmp[offset] != FLAGSEP; offset++);
+ 		  offset++;
+ 		break;
+ 	default: break;	/* Should we crash?... Nahhh */
+     }
+   }
+   if(d) *d = tmpd;
+   if(f) *f = tmpf;
+   if(r) *r = tmpr;
+   if(s) *s = tmps;
+   if(t) *t = tmpt;
+ }
+ 
+ int
+ maildir_message_in_list(char *msgname, struct direct **names, 
+ 		unsigned long bottom, unsigned long top, unsigned long *pos)
+ {
+   unsigned long middle = (bottom + top)/2;
+   int test;
+ 
+   if (!msgname)
+      return NIL;
+ 
+   if (pos) *pos = middle;
+ 
+   if (same_maildir_file(msgname, names[middle]->d_name))
+      return T;
+ 
+   if (middle == bottom){	 /* 0 <= 0 < 1 */
+      int rv = NIL;
+      if (same_maildir_file(msgname, names[middle]->d_name)){
+ 	rv = T;
+ 	if (pos) *pos = middle;
+      }
+      else
+        if (same_maildir_file(msgname, names[top]->d_name)){
+ 	rv = T;
+ 	if (pos) *pos = top;
+        }
+      return rv;
+   }
+ 
+   test = comp_maildir_file(msgname, names[middle]->d_name);
+ 
+   if (top <= bottom)
+       return test ? NIL : T;
+ 
+   if (test < 0 ) /* bottom <  msgname < middle */
+      return maildir_message_in_list(msgname, names, bottom, middle, pos);
+   else if (test > 0)  /* middle < msgname < top */
+      return maildir_message_in_list(msgname, names, middle, top, pos);
+   else return T;
+ }
+ 
+ void
+ maildir_abort(MAILSTREAM *stream)
+ {
+   if (LOCAL){
+     if(LOCAL->candouid)
+       maildir_read_uid(stream, NULL, &stream->uid_validity);
+     if (LOCAL->dir) fs_give ((void **) &LOCAL->dir);
+     if (LOCAL->curdir) fs_give ((void **) &LOCAL->curdir);
+     if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+     if(LOCAL->uidtempfile){
+       unlink(LOCAL->uidtempfile);
+       fs_give ((void **) &LOCAL->uidtempfile);
+     }
+     fs_give ((void **) &stream->local);
+   }
+   if (mdfpath) fs_give((void **)&mdfpath);
+   stream->dtb = NIL;
+ }
+ 
+ int
+ maildir_contains_folder(char *dirname, char *name)
+ {
+   char tmp[MAILTMPLEN], tmp2[MAILTMPLEN];
+   int rv = 0;
+   DIR *dir;
+   struct direct *d;
+ 
+   maildir_file_path(dirname, tmp2);
+   if(name){
+     strcat(tmp2,"/");
+     strcat(tmp2, name);
+   }
+ 
+   if (!(dir = opendir (tmp2)))
+      return NIL;
+ 
+   while ((d = readdir(dir)) != NULL){
+     if (strcmp(d->d_name, ".") && strcmp(d->d_name,"..")
+ 	&& strcmp(d->d_name, MDNAME(Cur)) 
+ 	&& strcmp(d->d_name, MDNAME(Tmp)) 
+ 	&& strcmp(d->d_name, MDNAME(New))){
+ 
+        sprintf(tmp,"%s/%s", tmp2, d->d_name);
+        if(maildir_valid(tmp)){
+ 	  rv++;
+ 	  break;
+        }
+     }
+   }
+   closedir(dir);
+   return rv;
+ }
+ 
+ int
+ maildir_is_dir(char *dirname, char *name)
+ {
+   char tmp[MAILTMPLEN];
+   struct stat sbuf;
+ 
+   maildir_file_path(dirname, tmp);
+   if(name){
+     strcat(tmp,"/");
+     strcat(tmp,name);
+   }
+   strcat(tmp,"/");
+   strcat(tmp,MDDIR);
+ 
+   return ((stat(tmp, &sbuf) == 0) && S_ISREG (sbuf.st_mode)) ? 1 : 0;
+ }
+ 
+ int
+ maildir_dir_is_empty(char *mailbox)
+ {
+   char tmp[MAILTMPLEN], tmp2[MAILTMPLEN], tmp3[MAILTMPLEN],*s;
+   int rv = 1, courier = IS_COURIER(mailbox);
+   DIR *dir;
+   struct direct *d;
+   struct stat sbuf;
+ 
+   maildir_file_path(mailbox, tmp2);
+ 
+   if(courier){
+      strcpy(tmp3, tmp2);
+      if(s = strrchr(tmp2, '/'))
+ 	*s = '\0';
+   }
+ 
+   if (!(dir = opendir (tmp2)))
+      return rv;
+ 
+   if(courier){
+      while((d = readdir(dir)) != NULL){
+         sprintf(tmp,"%s/%s", tmp2, d->d_name);
+ 	if(!strncmp(tmp, tmp3, strlen(tmp3)) 
+ 	   && tmp[strlen(tmp3)] == '.'){
+ 	   rv = 0;
+ 	   break;
+ 	}
+      }
+   }
+   else
+     while ((d = readdir(dir)) != NULL){
+       sprintf(tmp,"%s/%s", tmp2, d->d_name);
+       if (strcmp(d->d_name, ".") 
+ 	&& strcmp(d->d_name,"..")
+ 	&& strcmp(d->d_name, MDNAME(Cur)) 
+ 	&& strcmp(d->d_name, MDNAME(Tmp)) 
+ 	&& strcmp(d->d_name, MDNAME(New))
+ 	&& strcmp(d->d_name, MDDIR)
+ 	&& strcmp(d->d_name, MDUIDVALIDITY)
+ 	&& !(d->d_name[0] == '.' 
+ 		&& stat (tmp,&sbuf) == 0 
+ 		&& S_ISREG(sbuf.st_mode))){
+ 	   rv = 0;
+ 	   break;
+        }
+     }
+   closedir(dir);
+   return rv;
+ }
+ 
+ void
+ maildir_get_file (MAILDIRFILE **mdfile)
+ {
+   MAILDIRFILE *md;
+ 
+   md = (MAILDIRFILE *) fs_get(sizeof(MAILDIRFILE));
+   memset(md, 0, sizeof(MAILDIRFILE));
+   *mdfile = md;
+ }
+ 
+ void
+ maildir_free_file (void **mdfile)
+ {
+   MAILDIRFILE *md = (mdfile && *mdfile) ? (MAILDIRFILE *) *mdfile : NULL;
+ 
+   if (md){
+      if (md->name) fs_give((void **)&md->name);
+      fs_give((void **)&md);
+   }
+ }
+ 
+ void
+ maildir_free_file_only (void **mdfile)
+ {
+   MAILDIRFILE *md = (mdfile && *mdfile) ? (MAILDIRFILE *) *mdfile : NULL;
+ 
+   if (md && md->name) 
+      fs_give((void **)&md->name);
+ }
+ 
+ int
+ maildir_any_new_msgs(char *mailbox)
+ {
+   char tmp[MAILTMPLEN];
+   int rv = NIL;
+   DIR *dir;
+   struct direct *d;
+ 
+   MDFLD(tmp, mailbox, New);
+ 
+   if (!(dir = opendir (tmp)))
+      return rv;
+ 
+   while ((d = readdir(dir)) != NULL){
+     if (d->d_name[0] == '.')
+ 	continue;
+     rv = T;
+     break;
+   }
+   closedir(dir);
+   return rv;
+ }
+ 
+ 
+ void
+ maildir_get_date(MAILSTREAM *stream, unsigned long msgno)
+ {
+   MESSAGECACHE *elt;
+   struct tm *t;
+   time_t ti;
+   int i,k;
+ 
+   elt = mail_elt (stream,msgno);
+   if(elt && elt->year != 0)
+     return;
+   if ((ti = mdfntoul(MDFILE(elt))) > 0L && (t = gmtime(&ti))){
+      i = t->tm_hour * 60 + t->tm_min;
+      k = t->tm_yday;
+      t = localtime(&ti);
+      i = t->tm_hour * 60 + t->tm_min - i;
+      if((k = t->tm_yday - k) != 0) 
+ 	i += ((k < 0) == (abs (k) == 1)) ? -24*60 : 24*60;
+      k = abs (i);
+      elt->hours = t->tm_hour; 
+      elt->minutes = t->tm_min; 
+      elt->seconds = t->tm_sec;
+      elt->day = t->tm_mday; elt->month = t->tm_mon + 1;
+      elt->year = t->tm_year - (BASEYEAR - 1900);
+      elt->zoccident = (k == i) ? 0 : 1;
+      elt->zhours = k/60;
+      elt->zminutes = k % 60;
+   }
+ }
+ 
+ /* Support for Courier Style directories 
+    When this code is complete there will be two types of support, which 
+    will be configurable. The problem is the following: In Courier style 
+    folder structure, a "folder" may have a subfolder called 
+    "folder.subfolder", which is not natural in the file system in the 
+    sense that I can not stat for "folder.subfolder" wihtout knowing what 
+    "subfolder" is. It needs to be guessed. Because of this I need to look 
+    in the list of folders if there is a folder with a name 
+    "folder.subfolder", before I can say if the folder is dual or not. One 
+    can avoid this annoyance if one ignores the problem by declaring that 
+    every folder is dual. I will however code as the default the more 
+    complicated idea of scaning the containing directory each time it is 
+    modified and search for subfolders, and list the entries it found.
+  */
+ 
+ int courier_dir_select (const struct direct *name)
+ {
+  return name->d_name[0] == '.' && (strlen(name->d_name) > 2
+ 	|| (strlen(name->d_name) == 2 &&  name->d_name[1] != '.'));
+ }
+ 
+ int courier_dir_sort (const void *d1, const void *d2)
+ {
+   const struct direct *e1 = *(const struct direct **) d1;
+   const struct direct *e2 = *(const struct direct **) d2;
+ 
+   return strcmp((char *) e1->d_name, (char *) e2->d_name);
+ }
+ 
+ void courier_free_cdir (COURIER_S **cdir)
+ {
+   int i;
+ 
+   if (!*cdir)
+      return;
+ 
+   if ((*cdir)->path) fs_give((void **)&((*cdir)->path));
+   for (i = 0; i < (*cdir)->total; i++)
+     if((*cdir)->data[i]->name) fs_give((void **)&((*cdir)->data[i]->name));
+   fs_give((void **)&((*cdir)->data));
+   fs_give((void **)&(*cdir));
+ }
+ 
+ COURIER_S *courier_get_cdir (int total)
+ {
+  COURIER_S *cdir;
+ 
+  cdir = (COURIER_S *)fs_get(sizeof(COURIER_S));
+  memset(cdir, 0, sizeof(COURIER_S));
+  cdir->data = (COURIERLOCAL **) fs_get(total*sizeof(COURIERLOCAL *));
+  memset(cdir->data, 0, sizeof(COURIERLOCAL *));
+  cdir->total = total;
+  return cdir;
+ }
+ 
+ int courier_search_list(COURIERLOCAL **data, char *name, int first, int last)
+ {
+   int try = (first + last)/2;
+ 
+   if(!strstr(data[try]->name, name)){
+      if(first == try) /* first == last || first + 1 == last */
+ 	return strstr(data[last]->name, name) ? 1 : 0;
+      if(strcmp(data[try]->name, name) < 0) /*data[try] < name < data[end] */
+ 	return courier_search_list(data, name, try, last);
+      else	/* data[begin] < name < data[try] */
+ 	return courier_search_list(data, name, first, try);
+   }
+   return 1;
+ }
+ 
+ /* Lists all directories that are subdirectories of a given directory */
+ 
+ COURIER_S *courier_list_dir(char *curdir)
+ {
+   struct direct **names = NIL;
+   struct stat sbuf;
+   unsigned long ndir;
+   COURIER_S *cdir = NULL;
+   char tmp[MAILTMPLEN], tmp2[MAILTMPLEN], pathname[MAILTMPLEN], 
+ 	realname[MAILTMPLEN];
+   int i, j, scand, td;
+ 
+   /* There are two cases, either curdir is 
+  	 #mc/INBOX.	 #mc/INBOX.foo
+ 	or
+ 	 #mc/Maildir/. 	 #mc/Maildir/.foo
+    */
+   strcpy(tmp,curdir + 4);
+   if(!strncmp(ucase(tmp), "INBOX", 5))
+     strcpy(tmp, "#mc/INBOX.");
+   else{
+    strcpy(tmp, curdir);
+    for (i = strlen(tmp) - 1; tmp[i] && tmp[i] != '/'; i--);
+    tmp[i+2] = '\0'; 	/* keep the last "." intact */
+   }
+   maildir_file_path(tmp, realname);
+   maildir_scandir (realname, &names, &ndir, &scand, COURIER);
+ 
+   if (scand > 0){
+      cdir = courier_get_cdir(ndir);
+      cdir->path = cpystr(realname);
+      for(i = 0, j = 0; i < ndir; i++){
+         td = realname[strlen(realname) - 1] == '.'
+ 		&& *names[i]->d_name == '.';
+ 	sprintf(tmp2,"%s%s", tmp, names[i]->d_name+1);
+ 	sprintf(pathname,"%s%s", realname, names[i]->d_name + td);
+ 	if(stat(pathname, &sbuf) == 0 && S_ISDIR(sbuf.st_mode)){
+ 	   cdir->data[j] = (COURIERLOCAL *) fs_get(sizeof(COURIERLOCAL));
+ 	   cdir->data[j++]->name = cpystr(tmp2);
+ 	}
+ 	fs_give((void **)&names[i]);
+      }
+      cdir->total = j;
+      if(cdir->total == 0)
+         courier_free_cdir(&cdir);
+   }
+   if(names)
+     fs_give((void **) &names);
+   return cdir;
+ }
+ 
+ void
+ courier_list_info(COURIER_S **cdirp, char *data, int i)
+ {
+    long style = (long) maildir_parameters(GET_COURIERSTYLE, NIL);
+    COURIER_S *cdir = *cdirp;
+ 
+    if(maildir_valid(cdir->data[i]->name)){
+       if(courier_search_list(cdir->data, data, 0, cdir->total - 1))
+ 	 cdir->data[i]->attribute = LATT_HASCHILDREN;
+       else
+ 	 cdir->data[i]->attribute = (style == COURIER)
+ 				? LATT_HASNOCHILDREN : LATT_NOINFERIORS;
+    }
+    else
+       cdir->data[i]->attribute = LATT_NOSELECT;
+       cdir->data[i]->attribute += maildir_any_new_msgs(cdir->data[i]->name) 
+ 					? LATT_MARKED : LATT_UNMARKED;
+ }
+ 
+ /* UID Support */
+ /* Yes, I know I procastinated a lot about this, but here it is finally */
+ 
+ unsigned int
+ maildir_can_assign_uid (MAILSTREAM *stream)
+ {
+   unsigned int rv = 0;
+   int createtemp;
+   unsigned long t;
+   char tmp[MAILTMPLEN], *s;
+   DIR *dir;
+   struct direct *d;
+ 
+   if(!stream || stream->rdonly 
+ 	|| !LOCAL || !LOCAL->dir || !(dir = opendir(LOCAL->dir)))
+     return rv;
+ 
+   sprintf(tmp, "%s.%d", MDUIDTEMP, mypid);
+   while ((d = readdir(dir)) != NULL){
+     if(!strncmp(d->d_name, tmp, strlen(tmp)) 
+ 	|| !strncmp(d->d_name, MDUIDTEMP, strlen(MDUIDTEMP)))
+        break;
+   }
+   rv = d ? !strncmp(d->d_name, tmp, strlen(tmp)) : 1;
+   createtemp = d ? 0 : 1;
+   if (d && rv == 0){	/* is there a temp file that is not ours? */
+      s = strrchr(d->d_name, '.');
+      t = strtoul(s+1, &s, 10);
+      if(s != NULL && *s != '\0')
+ 	createtemp++;
+      if(time(0) > t + MAXTEMPUID){
+ 	createtemp++;
+ 	sprintf(tmp,"%s/%s", LOCAL->dir, d->d_name);
+ 	unlink(tmp);
+      }
+   }
+   closedir(dir);
+   if(createtemp){
+     FILE *fp;
+     sprintf(tmp,"%s/%s.%d.%lu", LOCAL->dir, MDUIDTEMP, mypid, time(0));
+     if(fp = fopen(tmp, "w")){
+       fclose(fp);
+       if(LOCAL->uidtempfile)
+ 	 fs_give((void **)&LOCAL->uidtempfile);
+       LOCAL->uidtempfile = cpystr(tmp);
+       rv++;
+     }
+   }
+   return rv;
+ }
+ 
+ void
+ maildir_read_uid(MAILSTREAM *stream, unsigned long *uid_last, 
+ 			unsigned long *uid_validity)
+ {
+   int createuid, deleteuid = 0;
+   char tmp[MAILTMPLEN], *s = NULL;
+   DIR *dir;
+   struct direct *d;
+ 
+   if(uid_last) *uid_last = 0L;
+   if(uid_last && uid_validity) *uid_validity = time(0);
+   if(!stream || !LOCAL || !LOCAL->dir || !(dir = opendir(LOCAL->dir)))
+     return;
+ 
+   while ((d = readdir(dir)) != NULL){
+       if(!strncmp(d->d_name, MDUIDLAST, strlen(MDUIDLAST)))
+        break;
+   }
+   createuid = d == NULL ? 1 : 0;
+   if(uid_last == NULL)
+     deleteuid++;
+   if(d){
+      if(uid_last){
+ 	s = d->d_name + strlen(MDUIDLAST) + 1;
+ 	*uid_last = strtoul(s, &s, 10);
+ 	if(!s || *s != '.'){
+ 	  deleteuid++;
+ 	  createuid++;
+ 	  *uid_last = 0L;
+ 	}
+      }
+      if(s && *s == '.'){
+         if(uid_validity){
+ 	  s++;
+ 	  *uid_validity = strtoul(s, &s, 10);
+ 	  if(s && *s != '\0'){
+ 	    *uid_validity = time(0);
+ 	    deleteuid++;
+ 	    createuid++;
+ 	  }
+ 	}
+      }
+      else{
+ 	deleteuid++;
+ 	createuid++;
+      }
+   }
+   if(deleteuid){
+      sprintf(tmp,"%s/%s", LOCAL->dir, d->d_name);
+      unlink(tmp);
+   }
+   if(createuid)
+      maildir_write_uid(stream, (uid_last ? *uid_last : stream->uid_last), 
+ 		uid_validity ? *uid_validity : time(0));
+   closedir(dir);
+ }
+ 
+ void
+ maildir_write_uid(MAILSTREAM *stream, unsigned long uid_last, 
+ 			unsigned long uid_validity)
+ {
+   char tmp[MAILTMPLEN];
+   FILE *fp;
+ 
+   if(!stream || stream->rdonly || !LOCAL || !LOCAL->dir)
+     return;
+ 
+   sprintf(tmp,"%s/%s.%010lu.%010lu", LOCAL->dir, MDUIDLAST, 
+ 			uid_last, uid_validity);
+   if(fp = fopen(tmp, "w"))
+      fclose(fp);
+ }
+ 
+ unsigned long 
+ maildir_get_uid(char *name)
+ {
+   char *s;
+   unsigned long rv = 0L;
+ 
+   if(!name || (s = strstr(name,MDUIDSEP)) == NULL)
+     return rv;
+ 
+   s += strlen(MDUIDSEP);
+   rv = strtoul(s, NULL, 10);
+   return rv;
+ }
+ 
+ 
+ void
+ maildir_delete_uid(MAILSTREAM *stream, unsigned long msgno)
+ {
+   char old[MAILTMPLEN], new[MAILTMPLEN], *s, *t;
+   MESSAGECACHE *elt;
+ 
+   elt = mail_elt(stream, msgno);
+   if(!stream || !elt || !elt->private.spare.ptr || !LOCAL || !LOCAL->dir)
+     return;
+ 
+   sprintf(old, "%s/%s/%s", LOCAL->dir, MDNAME(Cur), MDFILE(elt));
+   t = MDFILE(elt);
+   if(s = strstr(MDFILE(elt), MDUIDSEP)){
+      *s = '\0';
+      s += strlen(MDUIDSEP);
+      strtoul(s, &s, 10);
+      sprintf(new, "%s/%s/%s%s", LOCAL->dir, MDNAME(Cur), t, s);
+      if(rename(old, new) == 0){
+ 	maildir_free_file_only ((void **)&elt->private.spare.ptr);
+ 	s = strrchr(new, '/');
+ 	MDFILE(elt) = cpystr(s+1);
+      }
+      elt->private.uid = 0L;
+   }
+ }
+ 
+ void
+ maildir_assign_uid(MAILSTREAM *stream, unsigned long msgno, unsigned long uid)
+ {
+   int createuid, deleteuid = 0;
+   char old[MAILTMPLEN], new[MAILTMPLEN], *s, *t;
+   MESSAGECACHE *elt;
+ 
+   elt = mail_elt(stream, msgno);
+   if(!stream || !elt || !elt->private.spare.ptr || !LOCAL || !LOCAL->dir)
+     return;
+ 
+   maildir_delete_uid(stream, msgno);
+   sprintf(old, "%s/%s/%s", LOCAL->dir, MDNAME(Cur), MDFILE(elt));
+   t = MDFILE(elt);
+   if((s = strrchr(MDFILE(elt),FLAGSEP)) != NULL){
+      *s++ = '\0';
+      sprintf(new, "%s/%s/%s%s%lu%c%s", 
+ 		LOCAL->dir, MDNAME(Cur), t, MDUIDSEP, uid, FLAGSEP, s);
+      if(rename(old, new) == 0){
+ 	maildir_free_file_only ((void **)&elt->private.spare.ptr);
+ 	s = strrchr(new, '/');
+ 	MDFILE(elt) = cpystr(s+1);
+ 	stream->uid_validity = time(0);
+      }
+      elt->private.uid = uid;
+   }
+ }
+ 
+ void
+ maildir_uid_renew_tempfile(MAILSTREAM *stream)
+ {
+   char tmp[MAILTMPLEN];
+ 
+   if(!stream || stream->rdonly 
+ 	|| !LOCAL || !LOCAL->candouid || !LOCAL->dir || !LOCAL->uidtempfile)
+     return;
+ 
+   sprintf(tmp,"%s/%s.%d.%lu", LOCAL->dir, MDUIDTEMP, mypid, time(0));
+   if(rename(LOCAL->uidtempfile, tmp) == 0){
+       fs_give((void **)&LOCAL->uidtempfile);
+       LOCAL->uidtempfile = cpystr(tmp);
+   }
+ }
diff -rc alpine-2.00/imap/src/osdep/unix/maildir.h alpine-2.00.I.USE/imap/src/osdep/unix/maildir.h
*** alpine-2.00/imap/src/osdep/unix/maildir.h	2011-02-07 20:34:02.000000000 -0800
--- alpine-2.00.I.USE/imap/src/osdep/unix/maildir.h	2011-02-07 20:33:41.000000000 -0800
***************
*** 0 ****
--- 1,226 ----
+ /* 
+  * A few definitions that try to make this module portable to other
+  * platforms (e.g. Cygwin). This module is based on the information from
+  * http://cr.yp.to/proto/maildir.html
+  */
+ 
+ /* First we deal with the separator character */
+ #ifndef FLAGSEP
+ #define FLAGSEP ':'
+ #endif
+ #define SIZESEP ','
+ 
+ const char sep1[] = {FLAGSEP, '1', ',', '\0'}; /* experimental semantics*/
+ const char sep2[] = {FLAGSEP, '2', ',', '\0'}; /* Flags Information	*/
+ const char sep3[] = {FLAGSEP, '3', ',', '\0'}; /* Grrrr....		*/
+ 
+ const char *sep[] = { sep1, sep2, sep3, NULL};
+ 
+ #define MDSEP(i)  sep[((i) - 1)]
+ 
+ /* Now we deal with flags. Woohoo! */
+ typedef enum  {Draft, Flagged, Passed, Replied, Seen, Trashed, 
+ 	       EmptyFlag, EndFlags} MdFlagNamesType;
+ const int mdimapflags[] = {Draft, Flagged, Replied, Seen, Trashed, EmptyFlag, EndFlags};
+ const int mdkwdflags[]  = {Passed, EmptyFlag, EndFlags};
+ 
+ /* this array lists the codes for mdflgnms (maildir flag names) above */
+ const char *mdflags[] = { "D", "F", "P", "R", "S", "T", "", NULL};
+ /* and as characters too */
+ const char cmdflags[] = { 'D', 'F', 'P', 'R', 'S', 'T', '0', '\0'};
+ 
+ /* MDFLAG(Seen, elt->seen) */
+ #define MDFLAG(i,j) mdflags[j ? (i) : EmptyFlag]
+ /* MDFLAGC(Seen) */
+ #define MDFLAGC(i) cmdflags[(i)]
+ 
+ /* Now we deal with the directory structure */
+ typedef enum {Cur, Tmp, New, EndDir} DirNamesType;
+ char *mdstruct[] = {"cur", "tmp", "new", NULL};
+ #define MDNAME(i) mdstruct[(i)]
+ #define MDFLD(tmp, dir, i) sprintf((tmp),"%s/%s", (dir), mdstruct[(i)])
+ #define MSGPATH(tmp, dir, msg,i) sprintf((tmp),"%s/%s/%s", (dir), mdstruct[(i)],(msg))
+ 
+ /* Files associated to a maildir directory */
+ 
+ #define MDUIDVALIDITY	".uidvalidity"	/* support for old maildirs    */
+ #define MDDIR		".mdir"		/* this folder is a directory  */
+ #define MDUIDLAST	".uidlast"	/* last assigned uid	       */
+ #define MDUIDTEMP	".uidtemp"	/* We assign uid's no one else */
+ 
+ 
+ 
+ /* Support of Courier Structure */
+ #define CCLIENT 0
+ #define COURIER 1
+ #define IS_CCLIENT(t) \
+ 		(((t) && (t)[0] == '#' && ((t)[1] == 'm' || (t)[1] == 'M')\
+ 		&& ((t)[2] == 'd' || (t)[2] == 'D')\
+ 		&& (t)[3] == '/'  && (t)[4] != '\0') ? 1 : 0)
+ 
+ #define IS_COURIER(t) \
+ 		(((t) && (t)[0] == '#' && ((t)[1] == 'm' || (t)[1] == 'M')\
+ 		&& ((t)[2] == 'c' || (t)[2] == 'C')\
+ 		&& (t)[3] == '/'  && (t)[4] != '\0') ? 1 : 0)
+ #define MDPREFIX(s) ((s) ? "#mc/" : "#md/")
+ #define MDSEPARATOR(s) ((s) ? '.' : '/')
+ 
+ /* UID Support */
+ 
+ #define MAXTEMPUID (unsigned long) 180L
+ const char mduid[] = {',','u','=','\0'};
+ #define MDUIDSEP mduid
+ 
+ 
+ /* Now we deal with messages filenames */
+ char mdlocaldomain[MAILTMPLEN+1] = {'\0'};
+ pid_t mypid = (pid_t) 0;
+ static char *mdfpath = NULL;
+ static char myMdInboxDir[50] = { '\0' };/* Location of the Maildir INBOX */
+ static long CourierStyle = CCLIENT;
+ 
+ #define CHUNK	16384	/* from unix.h */
+ 
+ typedef struct courier_local {
+   char *name;		/* name of directory/folder */
+   int attribute;	/* attributes (children/marked/etc) */
+ } COURIERLOCAL;
+ 
+ typedef struct courier {
+   char *path;			/* Path to collection */
+   time_t scantime;		/* time at which information was generated */
+   int total;			/* total number of elements in data */
+   COURIERLOCAL **data;
+ } COURIER_S;
+ 
+ /* In gdb this is the  *(struct maildir_local *)stream->local structure */
+ typedef struct maildir_local {
+   unsigned int dirty : 1;	/* diskcopy needs updating 		*/
+   unsigned int courier : 1;	/* It is Courier style file system	*/
+   unsigned int link : 1;	/* There is a symbolic link		*/
+   unsigned int candouid;	/* we can assign uids and no one else	*/
+   char *uidtempfile;		/* path to uid temp file		*/
+   int fd;			/* fd of open message			*/
+   char *dir;			/* mail directory name			*/
+   char *curdir;			/* mail directory name/cur		*/
+   unsigned char *buf;		/* temporary buffer 			*/
+   unsigned long buflen;		/* current size of temporary buffer 	*/
+   time_t scantime;		/* last time directory scanned 		*/
+ } MAILDIRLOCAL;
+ 
+ /* Convenient access to local data */
+ #define LOCAL ((MAILDIRLOCAL *) stream->local)
+ 
+ typedef struct maildir_file_info {
+    char *name;		/* name of the file			   */
+    DirNamesType loc;	/* location of this file		   */
+    unsigned long pos;	/* place in list where this file is listed */
+    off_t size;		/* size in bytes, on disk */
+    time_t atime;	/* last access time */
+    time_t mtime;	/* last modified time */
+    time_t ctime;	/* last changed time */
+ } MAILDIRFILE;
+ 
+ #define MDFILE(F) (((MAILDIRFILE *)((F)->private.spare.ptr))->name)
+ #define MDLOC(F)  (((MAILDIRFILE *)((F)->private.spare.ptr))->loc)
+ #define MDPOS(F)  (((MAILDIRFILE *)((F)->private.spare.ptr))->pos)
+ #define MDSIZE(F)  (((MAILDIRFILE *)((F)->private.spare.ptr))->size)
+ #define MDATIME(F)  (((MAILDIRFILE *)((F)->private.spare.ptr))->atime)
+ #define MDMTIME(F)  (((MAILDIRFILE *)((F)->private.spare.ptr))->mtime)
+ #define MDCTIME(F)  (((MAILDIRFILE *)((F)->private.spare.ptr))->ctime)
+ 
+ /* Function prototypes */
+ 
+ DRIVER *maildir_valid (char *name);
+ MAILSTREAM *maildir_open (MAILSTREAM *stream);
+ void maildir_close (MAILSTREAM *stream, long options);
+ long maildir_ping (MAILSTREAM *stream);
+ void maildir_check (MAILSTREAM *stream);
+ long maildir_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+ char *maildir_header (MAILSTREAM *stream,unsigned long msgno,
+ 		unsigned long *length, long flags);
+ void maildir_list (MAILSTREAM *stream,char *ref,char *pat);
+ void *maildir_parameters (long function,void *value);
+ int maildir_create_folder (char *mailbox);
+ long maildir_create (MAILSTREAM *stream,char *mailbox);
+ void maildir_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); /*check */
+ long maildir_expunge (MAILSTREAM *stream, char *sequence, long options);
+ long maildir_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+ long maildir_append (MAILSTREAM *stream,char *mailbox, append_t af, void *data);
+ long maildir_delete (MAILSTREAM *stream,char *mailbox);
+ long maildir_rename (MAILSTREAM *stream,char *old,char *new);
+ long maildir_sub (MAILSTREAM *stream,char *mailbox);
+ long maildir_unsub (MAILSTREAM *stream,char *mailbox);
+ void maildir_lsub (MAILSTREAM *stream,char *ref,char *pat);
+ void courier_list (MAILSTREAM *stream,char *ref, char *pat);
+ 
+ /* utility functions */
+ void courier_realname (char *name, char *realname);
+ long maildir_dirfmttest (char *name);
+ char *maildir_file (char *dst,char *name);
+ int maildir_select (const struct direct *name);
+ int maildir_namesort (const void *d1, const void *d2);
+ unsigned long antoul (char *seed);
+ unsigned long mdfntoul (char *name);
+ int courier_dir_select (const struct direct *name);
+ int courier_dir_sort (const void *d1, const void *d2);
+ long maildir_canonicalize (char *pattern,char *ref,char *pat);
+ void maildir_list_work (MAILSTREAM *stream,char *subdir,char *pat,long level);
+ void courier_list_work (MAILSTREAM *stream,char *subdir,char *pat,long level);
+ int maildir_file_path(char *name, char *tmp);
+ int maildir_valid_name (char *name);
+ int maildir_valid_dir (char *name);
+ int is_valid_maildir (char **name);
+ int maildir_message_exists(MAILSTREAM *stream,char *name, char *tmp);
+ char *maildir_remove_root(char *name);
+ char *maildir_text_work (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned long *length,long flags);
+ unsigned long  maildir_parse_message(MAILSTREAM *stream, unsigned long msgno, 
+ 						DirNamesType dirtype);
+ int maildir_eliminate_duplicate (char *name, struct direct ***flist, 
+ 					unsigned long *nfiles);
+ int maildir_doscandir (char *name, struct direct ***flist, int flag);
+ unsigned long maildir_scandir (char *name, struct direct ***flist,
+ 			unsigned long *nfiles, int *scand, int flag);
+ void maildir_parse_folder (MAILSTREAM *stream, int full);
+ void  md_domain_name (void);
+ char  *myrootdir (char *name);
+ char  *mdirpath (void);
+ int   maildir_initial_check (MAILSTREAM *stream, DirNamesType dirtype);
+ unsigned long  maildir_parse_dir(MAILSTREAM *stream, unsigned long nmsgs, 
+    DirNamesType dirtype, struct direct **names, unsigned long nfiles, int full);
+ int same_maildir_file(char *name1, char *name2);
+ int comp_maildir_file(char *name1, char *name2);
+ int maildir_message_in_list(char *msgname, struct direct **names,
+ 		unsigned long bottom, unsigned long top, unsigned long *pos);
+ void maildir_getflag(char *name, int *d, int *f, int *r ,int *s, int *t);
+ int maildir_update_elt_maildirp(MAILSTREAM *stream, unsigned long msgno);
+ void maildir_abort (MAILSTREAM *stream);
+ int maildir_contains_folder(char *dirname, char *name);
+ int maildir_is_dir(char *dirname, char *name);
+ int maildir_dir_is_empty(char *mailbox);
+ int maildir_create_work (char *mailbox, int loop);
+ void maildir_get_file (MAILDIRFILE **mdfile);
+ void maildir_free_file (void **mdfile);
+ void maildir_free_file_only (void **mdfile);
+ int maildir_any_new_msgs(char *mailbox);
+ void maildir_get_date(MAILSTREAM *stream, unsigned long msgno);
+ void maildir_fast (MAILSTREAM *stream,char *sequence,long flags);
+ 
+ /* Courier server support */
+ void courier_free_cdir (COURIER_S **cdir);
+ COURIER_S *courier_get_cdir (int total);
+ int courier_search_list(COURIERLOCAL **data, char *name, int first, int last);
+ COURIER_S *courier_list_dir(char *curdir);
+ void courier_list_info(COURIER_S **cdirp, char *data, int i);
+ 
+ /* UID Support */
+ unsigned int maildir_can_assign_uid (MAILSTREAM *stream);
+ void maildir_read_uid(MAILSTREAM *stream, unsigned long *uid_last, 
+      			                   unsigned long *uid_validity);
+ void maildir_write_uid(MAILSTREAM *stream, unsigned long uid_last, 
+      			                   unsigned long uid_validity);
+ unsigned long maildir_get_uid(char *name);
+ void maildir_delete_uid(MAILSTREAM *stream, unsigned long msgno);
+ void maildir_assign_uid(MAILSTREAM *stream, unsigned long msgno, unsigned long uid);
+ void maildir_uid_renew_tempfile(MAILSTREAM *stream);
+ 
diff -rc alpine-2.00/imap/src/osdep/unix/Makefile alpine-2.00.I.USE/imap/src/osdep/unix/Makefile
*** alpine-2.00/imap/src/osdep/unix/Makefile	2008-06-04 11:18:34.000000000 -0700
--- alpine-2.00.I.USE/imap/src/osdep/unix/Makefile	2011-02-07 20:33:41.000000000 -0800
***************
*** 144,150 ****
  # However, mh needs to be before any sysinbox formats (such as mmdf or unix)
  # since otherwise INBOX won't work correctly when mh_allow_inbox is set.
  #
! DEFAULTDRIVERS=imap nntp pop3 mix mx mbx tenex mtx mh mmdf unix news phile
  CHUNKSIZE=65536
  
  # Normally no need to change any of these
--- 144,150 ----
  # However, mh needs to be before any sysinbox formats (such as mmdf or unix)
  # since otherwise INBOX won't work correctly when mh_allow_inbox is set.
  #
! DEFAULTDRIVERS=maildir courier imap nntp pop3 mix mx mbx tenex mtx mh mmdf unix news phile
  CHUNKSIZE=65536
  
  # Normally no need to change any of these
***************
*** 153,159 ****
  BINARIES=osdep.o mail.o misc.o newsrc.o smanager.o utf8.o utf8aux.o siglocal.o \
   dummy.o pseudo.o netmsg.o flstring.o fdstring.o \
   rfc822.o nntp.o smtp.o imap4r1.o pop3.o \
!  unix.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o mix.o
  CFLAGS=-g
  
  CAT=cat
--- 153,159 ----
  BINARIES=osdep.o mail.o misc.o newsrc.o smanager.o utf8.o utf8aux.o siglocal.o \
   dummy.o pseudo.o netmsg.o flstring.o fdstring.o \
   rfc822.o nntp.o smtp.o imap4r1.o pop3.o \
!  unix.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o mix.o maildir.o
  CFLAGS=-g
  
  CAT=cat
***************
*** 282,288 ****
  
  cyg:	# Cygwin - note that most local file drivers don't work!!
  	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
! 	DEFAULTDRIVERS="imap nntp pop3 mbx unix phile" \
  	SIGTYPE=psx CHECKPW=cyg LOGINPW=cyg CRXTYPE=std \
  	SPOOLDIR=/var \
  	ACTIVEFILE=/usr/local/news/lib/active \
--- 282,288 ----
  
  cyg:	# Cygwin - note that most local file drivers don't work!!
  	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
! 	DEFAULTDRIVERS="imap nntp pop3 mbx unix maildir phile" \
  	SIGTYPE=psx CHECKPW=cyg LOGINPW=cyg CRXTYPE=std \
  	SPOOLDIR=/var \
  	ACTIVEFILE=/usr/local/news/lib/active \
***************
*** 892,898 ****
  unix.o: mail.h misc.h osdep.h unix.h pseudo.h dummy.h
  utf8.o: mail.h misc.h osdep.h utf8.h tmap.c widths.c
  utf8aux.o: mail.h misc.h osdep.h utf8.h
! 
  
  # OS-dependent
  
--- 892,898 ----
  unix.o: mail.h misc.h osdep.h unix.h pseudo.h dummy.h
  utf8.o: mail.h misc.h osdep.h utf8.h tmap.c widths.c
  utf8aux.o: mail.h misc.h osdep.h utf8.h
! maildir.o: mail.h misc.h osdep.h maildir.h dummy.h
  
  # OS-dependent
  
diff -rc alpine-2.00/imap/src/osdep/unix/os_cyg.h alpine-2.00.I.USE/imap/src/osdep/unix/os_cyg.h
*** alpine-2.00/imap/src/osdep/unix/os_cyg.h	2008-06-04 11:18:34.000000000 -0700
--- alpine-2.00.I.USE/imap/src/osdep/unix/os_cyg.h	2011-02-07 20:33:41.000000000 -0800
***************
*** 47,52 ****
--- 47,53 ----
  #define setpgrp setpgid
  
  #define SYSTEMUID 18		/* Cygwin returns this for SYSTEM */
+ #define FLAGSEP ';'
  #define geteuid Geteuid
  uid_t Geteuid (void);
  
diff -rc alpine-2.00/imap/src/osdep/unix/ssl_unix.c alpine-2.00.I.USE/imap/src/osdep/unix/ssl_unix.c
*** alpine-2.00/imap/src/osdep/unix/ssl_unix.c	2008-06-04 11:18:34.000000000 -0700
--- alpine-2.00.I.USE/imap/src/osdep/unix/ssl_unix.c	2011-02-07 20:33:45.000000000 -0800
***************
*** 524,530 ****
        if (tcpdebug) mm_log ("Successfully read SSL data",TCPDEBUG);
      }
  				/* timeout, punt unless told not to */
!     else if (!tmoh || !(*tmoh) (now - t,now - tl)) {
        if (tcpdebug) mm_log ("SSL data read timeout",TCPDEBUG);
        return ssl_abort (stream);
      }
--- 524,530 ----
        if (tcpdebug) mm_log ("Successfully read SSL data",TCPDEBUG);
      }
  				/* timeout, punt unless told not to */
!     else if (!tmoh || !(*tmoh) (now - t,now - tl, stream->tcpstream->host)) {
        if (tcpdebug) mm_log ("SSL data read timeout",TCPDEBUG);
        return ssl_abort (stream);
      }
diff -rc alpine-2.00/imap/src/osdep/unix/tcp_unix.c alpine-2.00.I.USE/imap/src/osdep/unix/tcp_unix.c
*** alpine-2.00/imap/src/osdep/unix/tcp_unix.c	2008-06-04 11:18:34.000000000 -0700
--- alpine-2.00.I.USE/imap/src/osdep/unix/tcp_unix.c	2011-02-07 20:33:45.000000000 -0800
***************
*** 585,591 ****
  	if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG);
        }
  				/* timeout, punt unless told not to */
!       else if (!tmoh || !(*tmoh) (now - t,now - tl)) {
  	if (tcpdebug) mm_log ("TCP buffer read timeout",TCPDEBUG);
  	return tcp_abort (stream);
        }
--- 585,591 ----
  	if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG);
        }
  				/* timeout, punt unless told not to */
!       else if (!tmoh || !(*tmoh) (now - t,now - tl, stream->host)) {
  	if (tcpdebug) mm_log ("TCP buffer read timeout",TCPDEBUG);
  	return tcp_abort (stream);
        }
***************
*** 645,651 ****
        if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG);
      }
  				/* timeout, punt unless told not to */
!     else if (!tmoh || !(*tmoh) (now - t,now - tl)) {
        if (tcpdebug) mm_log ("TCP data read timeout",TCPDEBUG);
        return tcp_abort (stream);/* error or timeout no-continue */
      }
--- 645,651 ----
        if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG);
      }
  				/* timeout, punt unless told not to */
!     else if (!tmoh || !(*tmoh) (now - t,now - tl, stream->host)) {
        if (tcpdebug) mm_log ("TCP data read timeout",TCPDEBUG);
        return tcp_abort (stream);/* error or timeout no-continue */
      }
***************
*** 716,722 ****
        if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
      }
  				/* timeout, punt unless told not to */
!     else if (!tmoh || !(*tmoh) (now - t,now - tl)) {
        if (tcpdebug) mm_log ("TCP write timeout",TCPDEBUG);
        return tcp_abort (stream);
      }
--- 716,722 ----
        if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
      }
  				/* timeout, punt unless told not to */
!     else if (!tmoh || !(*tmoh) (now - t,now - tl, stream->host)) {
        if (tcpdebug) mm_log ("TCP write timeout",TCPDEBUG);
        return tcp_abort (stream);
      }
diff -rc alpine-2.00/include/general.h alpine-2.00.I.USE/include/general.h
*** alpine-2.00/include/general.h	2007-01-25 12:29:45.000000000 -0800
--- alpine-2.00.I.USE/include/general.h	2011-02-07 20:33:44.000000000 -0800
***************
*** 32,37 ****
--- 32,38 ----
  #undef	TRUE
  #define TRUE    1                       /* True, yes, good, etc.        */
  #define ABORT   2                       /* Death, ^G, abort, etc.       */
+ #define	COUNT	3			/* For control-c command        */
  
  
  #undef  MIN
diff -rc alpine-2.00/patchlevel alpine-2.00.I.USE/patchlevel
*** alpine-2.00/patchlevel	2011-02-07 20:34:02.000000000 -0800
--- alpine-2.00.I.USE/patchlevel	2011-02-07 20:34:02.000000000 -0800
***************
*** 0 ****
--- 1 ----
+ char plevstamp[]="VERSION=84 created on Mon Feb 07 2011 20:34:02 PST";
diff -rc alpine-2.00/pico/attach.c alpine-2.00.I.USE/pico/attach.c
*** alpine-2.00/pico/attach.c	2008-06-11 10:21:24.000000000 -0700
--- alpine-2.00.I.USE/pico/attach.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 108,115 ****
  	switch(status){
  	  case HELPCH:
  	    if(Pmaster){
- 		VARS_TO_SAVE *saved_state;
- 
  		saved_state = save_pico_state();
  		(*Pmaster->helper)(Pmaster->attach_help, _("Attach Help"), 1);
  		if(saved_state){
--- 108,113 ----
diff -rc alpine-2.00/pico/basic.c alpine-2.00.I.USE/pico/basic.c
*** alpine-2.00/pico/basic.c	2007-11-26 15:45:22.000000000 -0800
--- alpine-2.00.I.USE/pico/basic.c	2011-02-07 20:33:44.000000000 -0800
***************
*** 25,33 ****
   * framing, are hard.
   */
  #include        "headers.h"
! 
  #include "osdep/terminal.h"
  
  
  /*
   * Move the cursor to the
--- 25,34 ----
   * framing, are hard.
   */
  #include        "headers.h"
! #include	"../pith/osdep/color.h"
  #include "osdep/terminal.h"
  
+ int	indent_match(char *, LINE *, char *, int, int);
  
  /*
   * Move the cursor to the
***************
*** 284,290 ****
  gotobop(int f, int n)
  {
      int quoted, qlen;
!     UCS qstr[NLINE], qstr2[NLINE];
  
      if (n < 0)	/* the other way...*/
        return(gotoeop(f, -n));
--- 285,291 ----
  gotobop(int f, int n)
  {
      int quoted, qlen;
!     char qstr[NLINE], qstr2[NLINE], ind_str[NLINE], pqstr[NLINE];;
  
      if (n < 0)	/* the other way...*/
        return(gotoeop(f, -n));
***************
*** 296,301 ****
--- 297,310 ----
  	    curwp->w_dotp = lback(curwp->w_dotp);
  	    curwp->w_doto = 0;
  	}
+ 
+ 	if (indent_match(default_qstr(), curwp->w_dotp,ind_str, NLINE, 0)){
+ 	   if (n){ /* look for another paragraph ? */
+ 	      curwp->w_dotp = lback(curwp->w_dotp);
+ 	      continue;
+ 	   }
+ 	   break;
+ 	}
  	
  	/* scan line by line until we come to a line ending with
  	 * a <NL><NL> or <NL><TAB> or <NL><SPACE>
***************
*** 303,322 ****
  	 * PLUS: if there's a quote string, a quoted-to-non-quoted
  	 *	 line transition.
  	 */
! 	quoted = glo_quote_str ? quote_match(glo_quote_str, curwp->w_dotp, qstr, NLINE) : 0;
! 	qlen   = quoted ? ucs4_strlen(qstr) : 0;
  	while(lback(curwp->w_dotp) != curbp->b_linep
  	      && llength(lback(curwp->w_dotp)) > qlen
! 	      && (glo_quote_str
! 		  ? (quoted == quote_match(glo_quote_str,
! 					   lback(curwp->w_dotp),
! 					   qstr2, NLINE)
! 		     && !ucs4_strcmp(qstr, qstr2))
! 		  : 1)
! 	      && lgetc(curwp->w_dotp, qlen).c != TAB
! 	      && lgetc(curwp->w_dotp, qlen).c != ' ')
  	  curwp->w_dotp = lback(curwp->w_dotp);
  
  	if(n){
  	    /* keep looking */
  	    if(lback(curwp->w_dotp) == curbp->b_linep)
--- 312,369 ----
  	 * PLUS: if there's a quote string, a quoted-to-non-quoted
  	 *	 line transition.
  	 */
! 	quoted = quote_match(default_qstr(), curwp->w_dotp, qstr, NLINE, 0);
! 	qlen   = quoted ? strlen(qstr) : 0;
  	while(lback(curwp->w_dotp) != curbp->b_linep
  	      && llength(lback(curwp->w_dotp)) > qlen
! 	      && (quoted == quote_match(default_qstr(),
! 			lback(curwp->w_dotp), qstr2, NLINE, 0))
! 	      && !strcmp(qstr, qstr2)   /* processed string */
! 	      && (quoted == quote_match(default_qstr(),
! 			lback(curwp->w_dotp), qstr2, NLINE, 1))
! 	      && !strcmp(qstr, qstr2)   /* raw string */
! 	      && !indent_match(default_qstr(),
! 			lback(curwp->w_dotp),ind_str, NLINE, 0)
! 	      && !ISspace(lgetc(curwp->w_dotp, qlen).c))
  	  curwp->w_dotp = lback(curwp->w_dotp);
  
+ 	 /*
+ 	  * Ok, we made it here and we assume that we are at the begining
+ 	  * of the paragraph. Let's double check this now. In order to do
+ 	  * so we shell check if the first line was indented in a special
+ 	  * way.
+ 	  */
+ 	if(lback(curwp->w_dotp) == curbp->b_linep)
+ 	    break;
+ 	else{
+ 	     int i, j;
+ 
+ 	   /*
+ 	    * First we test if the preceding line is indented.
+ 	    * for the following test we need to have the raw values,
+ 	    * not the processed values
+ 	    */
+ 	   quote_match(default_qstr(), curwp->w_dotp, qstr, NLINE, 1);
+ 	   quote_match(default_qstr(), lback(curwp->w_dotp), qstr2, NLINE, 1);
+ 	   for (i = 0, j = 0;
+ 	        qstr[i] && qstr2[i] && (qstr[i] == qstr2[i]); i++, j++);
+ 	   for (; ISspace(qstr2[i]); i++);
+ 	   for (; ISspace(qstr[j]); j++);
+ 	   if ((indent_match(default_qstr(), lback(curwp->w_dotp),
+ 						ind_str, NLINE, 1)
+ 	       && (strlenis(qstr2) 
+ 			+ strlenis(ind_str) >= strlenis(qstr)))
+ 	      || (lback(curwp->w_dotp) != curbp->b_linep
+ 	         && llength(lback(curwp->w_dotp)) > qlen
+ 	         && (quoted == quote_match(default_qstr(),
+ 				lback(curwp->w_dotp), pqstr, NLINE, 0))
+ 		 && !strcmp(qstr, pqstr)
+ 		 && !ISspace(lgetc(curwp->w_dotp, qlen).c)
+ 		 && (strlenis(qstr2) > strlenis(qstr)))
+ 	         && !qstr2[i] && !qstr[j])
+ 		curwp->w_dotp = lback(curwp->w_dotp);
+ 	}
+ 
  	if(n){
  	    /* keep looking */
  	    if(lback(curwp->w_dotp) == curbp->b_linep)
***************
*** 329,335 ****
  	else{
  	  /* leave cursor on first word in para */
  	    curwp->w_doto = 0;
! 	    while(ucs4_isspace(lgetc(curwp->w_dotp, curwp->w_doto).c))
  	      if(++curwp->w_doto >= llength(curwp->w_dotp)){
  		  curwp->w_doto = 0;
  		  curwp->w_dotp = lforw(curwp->w_dotp);
--- 376,382 ----
  	else{
  	  /* leave cursor on first word in para */
  	    curwp->w_doto = 0;
! 	    while(ISspace(lgetc(curwp->w_dotp, curwp->w_doto).c))
  	      if(++curwp->w_doto >= llength(curwp->w_dotp)){
  		  curwp->w_doto = 0;
  		  curwp->w_dotp = lforw(curwp->w_dotp);
***************
*** 343,348 ****
--- 390,578 ----
      return(TRUE);
  }
  
+ unsigned char GetAccent()
+ {
+   UCS c,d;
+     c = GetKey();
+     if ((c == '?') || (c == '!')) {
+         d = c;
+         c = '\\';
+     }
+     else
+       if ((c == 's') || (c == 'S')){
+ 	 c =  d = 's';
+       }
+       else 
+ 	if ((c == 'l') || (c == 'L')){
+ 	   c =  d = 'l';
+ 	}
+ 	else
+           d = GetKey();
+ 	return accent(c,d);
+ }
+ 
+ int pineaccent(f,n)
+   int f,n;
+ { unsigned char e;
+    
+        if (e = GetAccent())
+           execute(e, 0, 1);
+        return 1;
+ }
+ 
+ unsigned char accent(f,n)
+ UCS f,n;
+ {  UCS c,d;
+ 
+        c =  f;
+        d =  n;
+        switch(c){
+         case '~' :  
+                    switch(d){
+                                case 'a' : return '\343';
+                                case 'n' : return '\361';
+                                case 'o' : return '\365';
+                                case 'A' : return '\303';
+                                case 'N' : return '\321';
+                                case 'O' : return '\325';
+                             }
+                        break;
+         case '\047' :
+                        switch(d){
+                                case 'a' : return '\341';
+                                case 'e' : return '\351';
+                                case 'i' : return '\355';
+                                case 'o' : return '\363';
+                                case 'u' : return '\372';
+                                case 'y' : return '\375';
+                                case 'A' : return '\301';
+                                case 'E' : return '\311';
+                                case 'I' : return '\315';
+                                case 'O' : return '\323';
+                                case 'U' : return '\332';
+                                case 'Y' : return '\335';
+                                     }
+                        break;
+         case '"' :
+                        switch(d){
+                                case 'a' : return '\344';
+                                case 'e' : return '\353';
+                                case 'i' : return '\357';
+                                case 'o' : return '\366';
+                                case 'u' : return '\374';
+                                case 'y' : return '\377';
+                                case 'A' : return '\304';
+                                case 'E' : return '\313';
+                                case 'I' : return '\317';
+                                case 'O' : return '\326';
+                                case 'U' : return '\334';
+                                     }
+                        break;
+         case '^' :
+                        switch(d){
+                                case 'a' : return '\342';
+                                case 'e' : return '\352';
+                                case 'i' : return '\356';
+                                case 'o' : return '\364';
+                                case 'u' : return '\373';
+                                case 'A' : return '\302';
+                                case 'E' : return '\312';
+                                case 'I' : return '\316';
+                                case 'O' : return '\324';
+                                case 'U' : return '\333';
+ 			       case '0' : return '\260';
+ 			       case '1' : return '\271';
+ 			       case '2' : return '\262';
+ 			       case '3' : return '\263';
+                                     }
+                        break;
+         case '`' :
+                        switch(d){
+                                case 'a' : return '\340';
+                                case 'e' : return '\350';
+                                case 'i' : return '\354';
+                                case 'o' : return '\362';
+                                case 'u' : return '\371';
+                                case 'A' : return '\300';
+                                case 'E' : return '\310';
+                                case 'I' : return '\314';
+                                case 'O' : return '\322';
+                                case 'U' : return '\331';
+                                     }
+                        break;
+         case 'o' :
+                        switch(d){
+                                case 'a' : return '\345';
+                                case 'A' : return '\305';
+ 			       case '/' : return '\370';
+ 			       case 'r' : return '\256';
+ 			       case 'R' : return '\256';
+ 			       case 'c' : return '\251';
+ 			       case 'C' : return '\251';
+ 				}
+                        break;
+ 	case '-' :
+ 		       switch(d){
+ 			       case 'o' : return '\272';
+ 			       case 'O' : return '\272';
+ 			       case '0' : return '\272';
+ 			       case 'a' : return '\252';
+ 			       case 'A' : return '\252';
+ 			       case 'l' : return '\243';
+ 			       case 'L' : return '\243';
+ 				}
+ 		       break;
+ 	case 'O' :
+ 		       switch(d){
+ 			       case '/' : return '\330';
+ 			       case 'r' : return '\256';
+ 			       case 'R' : return '\256';
+ 			       case 'c' : return '\251';
+ 			       case 'C' : return '\251';
+ 				}
+         case '/' :
+                        switch(d){
+                                case 'o' : return '\370';
+                                case 'O' : return '\330';
+ 				}
+                        break;
+         case 'a' :
+                        switch(d){
+                                case 'e' : return '\346';
+                                case 'E' : return '\346';
+ 				}
+                        break;
+         case 'A' :
+                        switch(d){
+                                 case 'E' : return '\306';
+                                case 'e' : return '\306';
+ 				}
+                        break;
+         case ',' :
+                        switch(d){
+                                case 'c' : return '\347';
+                                case 'C' : return '\307';
+                                     }
+                        break;
+         case '\\' :
+                        switch(d){
+                                case '?' : return '\277';
+                                case '!' : return '\241';
+                                     }
+                        break;
+        case 's' :
+                         switch(d){
+                                 case 's' : return '\337';
+                                      }
+ 			break;
+        case 'l' :
+                         switch(d){
+                                 case 'l' : return '\243';
+                                  }
+ 		break;
+        }
+        return '\0';
+ }
  
  /* 
   * go forword to the end of the current paragraph
***************
*** 352,359 ****
  int
  gotoeop(int f, int n)
  {
!     int quoted, qlen;
!     UCS qstr[NLINE], qstr2[NLINE];
  
      if (n < 0)	/* the other way...*/
        return(gotobop(f, -n));
--- 582,590 ----
  int
  gotoeop(int f, int n)
  {
!     int quoted, qlen, indented, changeqstr = 0;
!     int i,j, fli = 0; /* fli = first line indented a boolean variable */
!     char qstr[NLINE], qstr2[NLINE], ind_str[NLINE];
  
      if (n < 0)	/* the other way...*/
        return(gotobop(f, -n));
***************
*** 366,392 ****
  	      break;
  	}
  
  	/* scan line by line until we come to a line ending with
  	 * a <NL><NL> or <NL><TAB> or <NL><SPACE>
  	 *
  	 * PLUS: if there's a quote string, a quoted-to-non-quoted
  	 *	 line transition.
  	 */
! 	quoted = glo_quote_str
! 	  ? quote_match(glo_quote_str,
! 			curwp->w_dotp, qstr, NLINE) : 0;
! 	qlen   = quoted ? ucs4_strlen(qstr) : 0;
  	
  	while(curwp->w_dotp != curbp->b_linep
  	      && llength(lforw(curwp->w_dotp)) > qlen
! 	      && (glo_quote_str
! 		  ? (quoted == quote_match(glo_quote_str,
! 					   lforw(curwp->w_dotp),
! 					   qstr2, NLINE)
! 		     && !ucs4_strcmp(qstr, qstr2))
! 		  : 1)
! 	      && lgetc(lforw(curwp->w_dotp), qlen).c != TAB
! 	      && lgetc(lforw(curwp->w_dotp), qlen).c != ' ')
  	  curwp->w_dotp = lforw(curwp->w_dotp);
  
  	curwp->w_doto = llength(curwp->w_dotp);
--- 597,666 ----
  	      break;
  	}
  
+ 	/*
+ 	 * We need to figure out if this line is the first line of
+ 	 * a paragraph that has been indented in a special way. If this
+ 	 * is the case, we advance one more line before we use the
+ 	 * algorithm below
+ 	 */
+ 
+ 	if(curwp->w_dotp != curbp->b_linep){
+ 	   quote_match(default_qstr(), curwp->w_dotp, qstr, NLINE, 1);
+ 	   quote_match(default_qstr(), lforw(curwp->w_dotp), qstr2, NLINE, 1);
+ 	   indented = indent_match(default_qstr(), curwp->w_dotp, ind_str,
+ 							NLINE, 1);
+ 	   if (strlenis(qstr) 
+ 		+ strlenis(ind_str) < strlenis(qstr2)){
+ 		curwp->w_doto = llength(curwp->w_dotp);
+ 		if(n){    /* this line is a paragraph by itself */
+ 		   curwp->w_dotp = lforw(curwp->w_dotp);
+ 		   continue;
+ 		}
+ 		break;
+ 	   }
+ 	   for (i=0,j=0; qstr[i] && qstr2[i] && (qstr[i] == qstr2[i]);i++,j++);
+ 	   for (; ISspace(qstr[i]); i++);
+ 	   for (; ISspace(qstr2[j]); j++);
+ 	   if (!qstr[i] && !qstr2[j] && indented){
+ 		fli++;
+ 		if (indent_match(default_qstr(), lforw(curwp->w_dotp),
+ 					ind_str, NLINE, 0)){
+ 		    if (n){ /* look for another paragraph ? */
+ 		      curwp->w_dotp = lforw(curwp->w_dotp);
+ 		      continue;
+ 		    }
+ 		}
+ 		else{
+ 		  if (!lisblank(lforw(curwp->w_dotp)))
+ 		     curwp->w_dotp = lforw(curwp->w_dotp);
+ 		}
+ 	   }
+ 	}
+ 
  	/* scan line by line until we come to a line ending with
  	 * a <NL><NL> or <NL><TAB> or <NL><SPACE>
  	 *
  	 * PLUS: if there's a quote string, a quoted-to-non-quoted
  	 *	 line transition.
  	 */
! 	/* if the first line is indented (fli == 1), then the test below
! 	   is on the second line, and in that case we will need the raw
! 	   string, not the processed string
! 	 */
! 	quoted = quote_match(default_qstr(), curwp->w_dotp, qstr, NLINE, fli);
! 	qlen   = quoted ? strlen(qstr) : 0;
  	
  	while(curwp->w_dotp != curbp->b_linep
  	      && llength(lforw(curwp->w_dotp)) > qlen
! 	      && (quoted == quote_match(default_qstr(),
! 				lforw(curwp->w_dotp), qstr2, NLINE, fli))
! 	      && !strcmp(qstr, qstr2)
! 	      && (quoted == quote_match(default_qstr(),
! 				lforw(curwp->w_dotp), qstr2, NLINE, 1))
! 	      && !strcmp(qstr, qstr2)
! 	      && !indent_match(default_qstr(),
! 				lforw(curwp->w_dotp), ind_str, NLINE, 0)
! 	      && !ISspace(lgetc(lforw(curwp->w_dotp), qlen).c))
  	  curwp->w_dotp = lforw(curwp->w_dotp);
  
  	curwp->w_doto = llength(curwp->w_dotp);
***************
*** 683,689 ****
--- 957,1013 ----
      return (scrollforw (1, FALSE));
  }
  
+ /* deltext deletes from the specified position until the end of the file
+  * or until the signature (when called from Pine), whichever comes first.
+  */
  
+ int
+ deltext (f,n)
+ int f,n;
+ {               
+   LINE *currline = curwp->w_dotp;
+   static int firsttime = 0;
+ 
+   if ((lastflag&CFKILL) == 0)
+      kdelete();
+   
+   curwp->w_markp = curwp->w_dotp;
+   curwp->w_marko = curwp->w_doto;
+   
+   while (curwp->w_dotp != curbp->b_linep){
+      if ((Pmaster) 
+     	&& (llength(curwp->w_dotp) == 3) 
+ 	&& (lgetc(curwp->w_dotp, 0).c == '-') 
+ 	&& (lgetc(curwp->w_dotp, 1).c == '-') 
+ 	&& (lgetc(curwp->w_dotp, 2).c == ' ')){
+ 	  if (curwp->w_dotp == currline){
+ 	     if (curwp->w_doto)
+ 		curwp->w_dotp = lforw(curwp->w_dotp);
+ 	     else
+ 	   	break;
+      	  }
+      	  else{
+ 	     curwp->w_dotp = lback(curwp->w_dotp);
+ 	     curwp->w_doto = llength(curwp->w_dotp);
+ 	     break;
+           }
+      }
+      else{
+ 	if(lforw(curwp->w_dotp) != curbp->b_linep)
+ 	 curwp->w_dotp = lforw(curwp->w_dotp);
+ 	else{
+ 	 curwp->w_doto = llength(curwp->w_dotp);
+ 	 break;
+ 	}
+      }
+   }         
+   killregion(FALSE,1);
+   lastflag |= CFKILL;
+   if(firsttime == 0)
+      emlwrite("Deleted text can be recovered with the ^U command", NULL);
+   firsttime = 1;
+   return TRUE;
+ }
  
  /*
   * Scroll to a position.
diff -rc alpine-2.00/pico/bind.c alpine-2.00.I.USE/pico/bind.c
*** alpine-2.00/pico/bind.c	2007-12-07 15:45:22.000000000 -0800
--- alpine-2.00.I.USE/pico/bind.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 132,139 ****
      }
  
      if(Pmaster){
- 	VARS_TO_SAVE *saved_state;
- 
  	saved_state = save_pico_state();
  	(*Pmaster->helper)(Pmaster->composer_help,
  			   Pmaster->headents
--- 132,137 ----
diff -rc alpine-2.00/pico/blddate.c alpine-2.00.I.USE/pico/blddate.c
*** alpine-2.00/pico/blddate.c	2006-11-22 14:50:13.000000000 -0800
--- alpine-2.00.I.USE/pico/blddate.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 19,25 ****
      char **argv;
  {
      struct tm *t;
!     FILE      *outfile=stdout;
      time_t     ltime;
  
      if(argc > 1 && (outfile = fopen(argv[1], "w")) == NULL){
--- 19,25 ----
      char **argv;
  {
      struct tm *t;
!     FILE      *outfile=stdout, *infile;
      time_t     ltime;
  
      if(argc > 1 && (outfile = fopen(argv[1], "w")) == NULL){
***************
*** 46,51 ****
--- 46,57 ----
  	    1900 + t->tm_year);
  
      fprintf(outfile, "char hoststamp[]=\"random-pc\";\n");
+     if((infile = fopen("../patchlevel", "r")) != NULL){
+ 	int c;
+ 	while ((c = getc(infile)) != EOF) putc(c, outfile);
+ 	fclose(infile);
+     }
+     else fprintf(outfile, "char plevstamp[]=\"No information available\";\n");
  
      fclose(outfile);
  
diff -rc alpine-2.00/pico/browse.c alpine-2.00.I.USE/pico/browse.c
*** alpine-2.00/pico/browse.c	2008-02-26 15:07:15.000000000 -0800
--- alpine-2.00.I.USE/pico/browse.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 931,938 ****
  	    }
  
  	    if(Pmaster){
- 		VARS_TO_SAVE *saved_state;
- 
  		saved_state = save_pico_state();
  		(*Pmaster->helper)(Pmaster->browse_help,
  				   _("Help for Browsing"), 1);
--- 931,936 ----
diff -rc alpine-2.00/pico/composer.c alpine-2.00.I.USE/pico/composer.c
*** alpine-2.00/pico/composer.c	2008-03-21 14:31:58.000000000 -0700
--- alpine-2.00.I.USE/pico/composer.c	2011-02-07 20:33:47.000000000 -0800
***************
*** 93,98 ****
--- 93,103 ----
   */
  struct on_display ods;				/* global on_display struct */
  
+ /* a pointer to the subject line. This is so that we do not have to compute
+  * the header line in every call. It saves a few CPU cycles
+  */
+ 
+ struct hdr_line *subject_line = NULL;
  
  /*
   * useful macros
***************
*** 495,500 ****
--- 500,510 ----
      mswin_setscrollrange (0, 0);
  #endif /* _WINDOWS */
  
+     if(Pmaster)
+       for (subject_line = NULL, i=0; headents[i].name; i++)
+ 	if(strcmp(headents[i].name, "Subject") == 0)
+ 	  subject_line = headents[i].hd_text;
+ 
      /* 
       * Decide where to begin editing.  if f == TRUE begin editing
       * at the bottom.  this case results from the cursor backing
***************
*** 794,802 ****
  		    len += lmp->fname ? strlen(lmp->fname) : 0;
  
  		    if(len+3 > sizeof(buf)){
- 			bfp = malloc(len+3);
  			space = len+3;
! 			if((bfp=malloc(len+3)) == NULL){
  			    emlwrite("\007Can't malloc space for filename",
  				     NULL);
  			    continue;
--- 804,812 ----
  		    len += lmp->fname ? strlen(lmp->fname) : 0;
  
  		    if(len+3 > sizeof(buf)){
  			space = len+3;
! 			bfp = malloc(space*sizeof(char));
! 			if(bfp == NULL){
  			    emlwrite("\007Can't malloc space for filename",
  				     NULL);
  			    continue;
***************
*** 1270,1278 ****
  			len += strlen(lmp->size);
  
  			if(len+3 > sizeof(buf)){
- 			    bfp = malloc(len+3);
  			    space = len+3;
! 			    if((bfp=malloc(len+3)) == NULL){
  				emlwrite("\007Can't malloc space for filename",
  					 NULL);
  				continue;
--- 1280,1288 ----
  			len += strlen(lmp->size);
  
  			if(len+3 > sizeof(buf)){
  			    space = len+3;
! 			    bfp = malloc(space*sizeof(char));
! 			    if(bfp == NULL){
  				emlwrite("\007Can't malloc space for filename",
  					 NULL);
  				continue;
***************
*** 1309,1316 ****
  		    zotlmlist(lm);
  		}				/* else, nothing of interest */
              } else if (headents[ods.cur_e].selector != NULL) {
- 		VARS_TO_SAVE *saved_state;
- 
                  /*---- General selector for non-attachments -----*/
  
  		/*
--- 1319,1324 ----
***************
*** 1485,1491 ****
  		struct hdr_line    *line;
  		int                 sz = 0;
  		char               *filename = NULL;
- 		VARS_TO_SAVE       *saved_state;
  
  		/*
  		 * Since the fileedit will make a new call back to pico()
--- 1493,1498 ----
***************
*** 1852,1857 ****
--- 1859,1866 ----
      }
  
      UpdateHeader(0);
+     if(sendnow)
+ 	return(status !=0);
      PaintHeader(COMPOSER_TOP_LINE, status != 0);
      PaintBody(1);
      return(status != 0);
***************
*** 1899,1904 ****
--- 1908,1918 ----
  
      while(1){					/* edit the line... */
  
+ 	if(Pmaster && subject_line != NULL 
+ 		&& ods.cur_l == subject_line 
+ 		&& ods.cur_l->text[0] == 0)
+ 	  (*Pmaster->newthread)();
+ 
  	if(skipmove)
  	  skipmove = 0;
  	else
***************
*** 1990,1996 ****
  	tbufp = &strng[ods.p_len];
  
  	if(VALID_KEY(ch)){			/* char input */
!             /*
               * if we are allowing editing, insert the new char
               * end up leaving tbufp pointing to newly
               * inserted character in string, and offset to the
--- 2004,2010 ----
  	tbufp = &strng[ods.p_len];
  
  	if(VALID_KEY(ch)){			/* char input */
! insert_char:/*
               * if we are allowing editing, insert the new char
               * end up leaving tbufp pointing to newly
               * inserted character in string, and offset to the
***************
*** 2070,2075 ****
--- 2084,2096 ----
          }
          else {					/* interpret ch as a command */
              switch (ch = normalize_cmd(ch, ckm, 2)) {
+ 	      case (CTRL|'\\') :
+ 		if (ch = GetAccent())
+ 		  goto insert_char;
+ 		else
+ 		  clearcursor();
+ 	      break;
+ 
                case (CTRL|KEY_LEFT):     /* word skip left */
                  if(ods.p_ind > 0)       /* Scoot one char left if possible */
                    ods.p_ind--;
***************
*** 2937,2943 ****
  ComposerHelp(int level)
  {
      char buf[80];
-     VARS_TO_SAVE *saved_state;
  
      curwp->w_flag |= WFMODE;
      sgarbf = TRUE;
--- 2958,2963 ----
***************
*** 3337,3342 ****
--- 3357,3365 ----
  {
      UCS    *bufp, *buf;
  
+     if (sendnow)
+ 	return;
+ 
      if(ComposerTopLine - 1 >= BOTTOM())		/* silently forget it */
        return;
  
***************
*** 3393,3398 ****
--- 3416,3424 ----
      UCS *end;
      int  i;
  
+     if (sendnow)
+       return(TRUE);
+ 
      buf = utf8_to_ucs4_cpystr(headents[entry].prompt);	/* fresh prompt paint */
      if(!buf)
        return(-1);
***************
*** 3606,3612 ****
      char        *tmp;
      struct headerentry *e;
      BUILDER_ARG *nextarg, *arg = NULL, *headarg = NULL;
-     VARS_TO_SAVE *saved_state;
  
      if(!entry->builder)
        return(0);
--- 3632,3637 ----
***************
*** 3826,3832 ****
  call_expander(void)
  {
      char        **s = NULL;
-     VARS_TO_SAVE *saved_state;
      int           expret;
  
      if(!Pmaster->expander)
--- 3851,3856 ----
***************
*** 4348,4353 ****
--- 4372,4380 ----
  void
  ShowPrompt(void)
  {
+     if (sendnow)
+ 	return;
+ 
      if(headents[ods.cur_e].key_label){
  	menu_header[TO_KEY].name  = "^T";
  	menu_header[TO_KEY].label = headents[ods.cur_e].key_label;
***************
*** 4716,4721 ****
--- 4743,4750 ----
        free(state->opertree);
  
      free(state);
+ 
+     state = NULL;
  }
  
  
diff -rc alpine-2.00/pico/display.c alpine-2.00.I.USE/pico/display.c
*** alpine-2.00/pico/display.c	2008-03-26 10:27:45.000000000 -0700
--- alpine-2.00.I.USE/pico/display.c	2011-02-07 20:33:44.000000000 -0800
***************
*** 386,391 ****
--- 386,394 ----
      int     scroll = 0;
      CELL	     c;
  
+     if (sendnow)
+ 	return;
+ 
  #if	TYPEAH
      if (typahead())
  	return;
***************
*** 915,921 ****
      int   nbflag;		/* non-blanks to the right flag? */
      int   cleartoeol = 0;
  
!     if(row < 0 || row > term.t_nrow)
        return;
  
      /* set up pointers to virtual and physical lines */
--- 918,924 ----
      int   nbflag;		/* non-blanks to the right flag? */
      int   cleartoeol = 0;
  
!     if(row < 0 || row > term.t_nrow || sendnow)
        return;
  
      /* set up pointers to virtual and physical lines */
***************
*** 1284,1290 ****
  void
  mlerase(void)
  {
!     if (term.t_nrow < term.t_mrow)
        return;
  
      movecursor(term.t_nrow - term.t_mrow, 0);
--- 1287,1293 ----
  void
  mlerase(void)
  {
!     if (term.t_nrow < term.t_mrow || sendnow)
        return;
  
      movecursor(term.t_nrow - term.t_mrow, 0);
***************
*** 1359,1364 ****
--- 1362,1371 ----
      menu_yesno[6].label = N_("Cancel");
      menu_yesno[7].name  = "N";
      menu_yesno[7].label = (dflt == FALSE) ? "[" N_("No") "]" : N_("No");
+     if(Pmaster && Pmaster->onctrlc){
+       menu_yesno[8].name  = "T";
+       menu_yesno[8].label = N_("counT");
+     }
      wkeyhelp(menu_yesno);		/* paint generic menu */
      sgarbk = TRUE;			/* mark menu dirty */
      if(Pmaster && curwp)
***************
*** 1437,1442 ****
--- 1444,1457 ----
  		km_popped++;
  		break;
  	    }
+ 
+ 	  case 'T':
+ 	  case 't':
+ 	    if(Pmaster && Pmaster->onctrlc){
+ 	      pputs_utf8(_("counT"), 1);
+ 	      rv = COUNT;
+ 	      break;
+ 	    }
  	    /* else fall through */
  
  	  default:
***************
*** 1750,1755 ****
--- 1765,1775 ----
  	    b = &buf[ucs4_strlen(buf)];
  	    continue;
  
+           case (CTRL|'\\'):
+            if (c = GetAccent())
+              goto text;
+           continue;
+ 
  	  case (CTRL|'F') :			/* CTRL-F forward a char*/
  	  case KEY_RIGHT :
  	    if(*b == '\0')
***************
*** 1759,1764 ****
--- 1779,1796 ----
  
  	    continue;
  
+ 	  case (CTRL|'N'):			/* Insert pattern */
+ 	   if (pat[0] != '\0'){
+ 		ucs4_strncpy(buf+ucs4_strlen(buf), pat, NPAT);
+ 		pputs(pat,1);
+ 		b = &buf[ucs4_strlen(buf)];
+ 		dline.vused += ucs4_strlen(pat);
+ 		changed = TRUE;
+ 		}
+ 	   else
+ 		(*term.t_beep)();
+ 	  continue;
+ 
  	  case (CTRL|'G') :			/* CTRL-G help		*/
  	    if(term.t_mrow == 0 && km_popped == 0){
  		movecursor(term.t_nrow-2, 0);
***************
*** 1868,1874 ****
  #endif
  
  	  default : 
! 
  	    /* look for match in extra_v */
  	    for(i = 0; i < 12; i++)
  	      if(c && c == extra_v[i]){
--- 1900,1906 ----
  #endif
  
  	  default : 
! text:
  	    /* look for match in extra_v */
  	    for(i = 0; i < 12; i++)
  	      if(c && c == extra_v[i]){
***************
*** 1962,1968 ****
  
      mlerase();
  
!     if(!(message && *message) || term.t_nrow < 2)	
        return;    /* nothing to write or no space to write, bag it */
  
      bufp = message;
--- 1994,2000 ----
  
      mlerase();
  
!     if(!(message && *message) || term.t_nrow < 2 || sendnow)	
        return;    /* nothing to write or no space to write, bag it */
  
      bufp = message;
***************
*** 2151,2158 ****
      }
  
      ret = ttcol;
!     while(ttcol < term.t_ncol)
!       pputc(' ', 0);
  
      movecursor(term.t_nrow - term.t_mrow, ret);
  
--- 2183,2191 ----
      }
  
      ret = ttcol;
!     if(sendnow == 0)
!       while(ttcol < term.t_ncol)
!         pputc(' ', 0);
  
      movecursor(term.t_nrow - term.t_mrow, ret);
  
***************
*** 2631,2636 ****
--- 2664,2671 ----
  {
      int ind, width, printable_ascii = 0;
  
+     if(sendnow)
+ 	return;
      /*
       * This is necessary but not sufficient to allow us to draw. Note that
       * ttrow runs from 0 to t_nrow (so total number of rows is t_nrow+1)
***************
*** 2685,2690 ****
--- 2720,2727 ----
  pputs(UCS *s,				/* string to write */
        int a)				/* and its attribute */
  {
+     if(sendnow)
+ 	return;
      while (*s != '\0')
        pputc(*s++, a);
  }
***************
*** 2695,2700 ****
--- 2732,2739 ----
  {
      UCS *ucsstr = NULL;
  
+     if(sendnow)
+ 	return;
      if(s && *s){
  	ucsstr = utf8_to_ucs4_cpystr(s);
  	if(ucsstr){
***************
*** 2995,3000 ****
--- 3034,3042 ----
      char  nbuf[NLINE];
  #endif
  
+     if(sendnow)
+ 	return;
+ 
  #ifdef _WINDOWS
      pico_config_menu_items (keymenu);
  #endif
diff -rc alpine-2.00/pico/ebind.h alpine-2.00.I.USE/pico/ebind.h
*** alpine-2.00/pico/ebind.h	2007-11-06 15:51:13.000000000 -0800
--- alpine-2.00.I.USE/pico/ebind.h	2011-02-07 20:33:43.000000000 -0800
***************
*** 61,67 ****
  #ifdef	MOUSE
  	{KEY_MOUSE,		mousepress},
  #ifndef _WINDOWS
! 	{CTRL|'\\',		toggle_xterm_mouse},
  #endif
  #endif
  	{CTRL|'A',		gotobol},
--- 61,67 ----
  #ifdef	MOUSE
  	{KEY_MOUSE,		mousepress},
  #ifndef _WINDOWS
! 	{CTRL|'|',		toggle_xterm_mouse},
  #endif
  #endif
  	{CTRL|'A',		gotobol},
***************
*** 100,106 ****
  	{CTRL|KEY_HOME,	gotobob},
  	{CTRL|KEY_END,	gotoeob},
  	{0x7F,			backdel},
! 	{0,			NULL}
  };
  
  
--- 100,108 ----
  	{CTRL|KEY_HOME,	gotobob},
  	{CTRL|KEY_END,	gotoeob},
  	{0x7F,			backdel},
!         {CTRL|'\\',             pineaccent},
! 	{0,
! NULL}
  };
  
  
***************
*** 123,129 ****
  #ifdef	MOUSE
  	{KEY_MOUSE,		mousepress},
  #ifndef _WINDOWS
! 	{CTRL|'\\',		toggle_xterm_mouse},
  #endif
  #endif
  	{CTRL|'A',		gotobol},
--- 125,131 ----
  #ifdef	MOUSE
  	{KEY_MOUSE,		mousepress},
  #ifndef _WINDOWS
! 	{CTRL|'|',		toggle_xterm_mouse},
  #endif
  #endif
  	{CTRL|'A',		gotobol},
diff -rc alpine-2.00/pico/edef.h alpine-2.00.I.USE/pico/edef.h
*** alpine-2.00/pico/edef.h	2008-01-04 16:41:49.000000000 -0800
--- alpine-2.00.I.USE/pico/edef.h	2011-02-07 20:33:47.000000000 -0800
***************
*** 32,37 ****
--- 32,38 ----
  
  /* initialized global definitions */
  
+ int	sendnow = 0;			/* should we send now		*/
  int     fillcol = 72;                   /* Current fill column          */
  int     userfillcol = -1;               /* Fillcol set from cmd line    */
  UCS     pat[NPAT];                      /* Search pattern		*/
***************
*** 55,60 ****
--- 56,62 ----
  char   *keyboard_character_set = NULL;
  UCS    *glo_wordseps = NULL;            /* points to word separators if set */
  char   *glo_wordseps_orig = NULL;
+ VARS_TO_SAVE *saved_state = NULL;
  
  /* uninitialized global definitions */
  int     currow;                 /* Cursor row                   */
***************
*** 84,89 ****
--- 86,92 ----
  
  /* initialized global external declarations */
  
+ extern	int	sendnow;		/* should we send now		*/
  extern  int     fillcol;                /* Fill column                  */
  extern  int     userfillcol;            /* Fillcol set from cmd line    */
  extern  UCS     pat[];                  /* Search pattern               */
***************
*** 149,154 ****
--- 152,158 ----
  extern	KBESC_T *kbesc;			/* keyboard esc sequence trie   */
  #endif /* HAS_TERMCAP/HAS_TERMINFO/VMS */
  extern void *input_cs;			/* passed to mbtow() via kbseq() */
+ extern VARS_TO_SAVE *saved_state;
  
  #endif /* maindef */
  
diff -rc alpine-2.00/pico/efunc.h alpine-2.00.I.USE/pico/efunc.h
*** alpine-2.00/pico/efunc.h	2007-11-06 15:51:13.000000000 -0800
--- alpine-2.00.I.USE/pico/efunc.h	2011-02-07 20:33:44.000000000 -0800
***************
*** 53,60 ****
--- 53,64 ----
  extern	int backline(int, int);
  extern	int gotobop(int, int);
  extern	int gotoeop(int, int);
+ extern  int pineaccent(int, int);
+ extern  unsigned char accent(UCS, UCS);
+ extern  unsigned char GetAccent(void);
  extern	int forwpage(int, int);
  extern	int backpage(int, int);
+ extern  int deltext (int, int);
  extern  int scrollupline(int, int);
  extern  int scrolldownline(int, int);
  extern  int scrollto(int, int);
***************
*** 248,257 ****
  extern	int fillpara(int, int);
  extern	int fillbuf(int, int);
  extern	int inword(void);
! extern	int quote_match(UCS *, LINE *, UCS *, size_t);
  extern	int ucs4_isalnum(UCS);
  extern	int ucs4_isalpha(UCS);
  extern	int ucs4_isspace(UCS);
  extern	int ucs4_ispunct(UCS);
  
  #endif	/* EFUNC_H */
--- 252,268 ----
  extern	int fillpara(int, int);
  extern	int fillbuf(int, int);
  extern	int inword(void);
! extern	int quote_match(char *, LINE *, char *, size_t, int);
! extern	char *default_qstr(void);
! extern	void flatten_qstring(QSTRING_S *, char *, int);
! extern	void free_qs(QSTRING_S **);
! extern	QSTRING_S *do_quote_match (char *, char *, char *, char *, char *, int, int);
! extern	QSTRING_S *do_raw_quote_match(char *, char *, char *, char *, QSTRING_S **, QSTRING_S **);
! extern  int indent_match(char *, LINE *, char *, int, int);
  extern	int ucs4_isalnum(UCS);
  extern	int ucs4_isalpha(UCS);
  extern	int ucs4_isspace(UCS);
  extern	int ucs4_ispunct(UCS);
  
  #endif	/* EFUNC_H */
+ 
diff -rc alpine-2.00/pico/file.c alpine-2.00.I.USE/pico/file.c
*** alpine-2.00/pico/file.c	2008-06-11 10:21:24.000000000 -0700
--- alpine-2.00.I.USE/pico/file.c	2011-02-07 20:33:47.000000000 -0800
***************
*** 331,338 ****
  #endif	/* !(DOS || MAC) */
  	      case HELPCH:
  		if(Pmaster){
- 		    VARS_TO_SAVE *saved_state;
- 
  		    saved_state = save_pico_state();
  		    (*Pmaster->helper)(msg ? Pmaster->ins_m_help
  					   : Pmaster->ins_help,
--- 331,336 ----
diff -rc alpine-2.00/pico/line.c alpine-2.00.I.USE/pico/line.c
*** alpine-2.00/pico/line.c	2007-08-15 16:07:18.000000000 -0700
--- alpine-2.00.I.USE/pico/line.c	2011-02-07 20:33:42.000000000 -0800
***************
*** 607,620 ****
  lisblank(LINE *line)
  {
      int n = 0;
!     UCS qstr[NLINE];
  
!     n = (glo_quote_str
! 	 && quote_match(glo_quote_str, line, qstr, NLINE))
! 	  ? ucs4_strlen(qstr) : 0;
  
      for(; n < llength(line); n++)
!       if(!ucs4_isspace(lgetc(line, n).c))
  	return(FALSE);
  
      return(TRUE);
--- 607,618 ----
  lisblank(LINE *line)
  {
      int n = 0;
!     char qstr[NLINE];
  
!     n = quote_match(default_qstr(), line, qstr, NLINE, 1);
  
      for(; n < llength(line); n++)
!       if(!ISspace(lgetc(line, n).c))
  	return(FALSE);
  
      return(TRUE);
diff -rc alpine-2.00/pico/main.c alpine-2.00.I.USE/pico/main.c
*** alpine-2.00/pico/main.c	2008-04-02 15:09:20.000000000 -0700
--- alpine-2.00.I.USE/pico/main.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 162,167 ****
--- 162,168 ----
      char    *file_to_edit = NULL;
      char    *display_charmap = NULL;
      char    *keyboard_charmap = NULL;
+     int	     line_information_on = FALSE;
      int      use_system = 0;
      char    *err = NULL;
  
***************
*** 187,193 ****
      if(display_character_set)
        display_charmap = cpstr(display_character_set);
  #if   HAVE_LANGINFO_H && defined(CODESET)
!     else
        display_charmap = cpstr(nl_langinfo_codeset_wrapper());
  #endif
  
--- 188,194 ----
      if(display_character_set)
        display_charmap = cpstr(display_character_set);
  #if   HAVE_LANGINFO_H && defined(CODESET)
!     else if (nl_langinfo_codeset_wrapper() != NULL)
        display_charmap = cpstr(nl_langinfo_codeset_wrapper());
  #endif
  
***************
*** 415,420 ****
--- 416,427 ----
  	      emlwrite(_("You may possibly have new mail."), NULL);
  	}
  
+          if (c == (CTRL|'\\')){
+            c = GetAccent();
+ 	   if (!c)
+ 	     c = NODATA;
+ 	 }
+ 
  	if(km_popped)
  	  switch(c){
  	    case NODATA:
***************
*** 436,449 ****
  	      mlerase();
  	}
  
! 	f = FALSE;
  	n = 1;
  
  #ifdef	MOUSE
  	clear_mfunc(mouse_in_content);
  #endif
  					/* Do it.               */
  	execute(normalize_cmd(c, fkm, 1), f, n);
      }
  }
  
--- 443,471 ----
  	      mlerase();
  	}
  
! 	f = (c == (CTRL|'J'));
  	n = 1;
+ 	if (!line_information_on)
+ 	   line_information_on = (c == (CTRL|'C'));
+ 	else
+ 	   line_information_on = ((c == KEY_DOWN) || (c == KEY_UP) ||
+ 				  (c == KEY_RIGHT) || (c == KEY_LEFT) ||
+ 			          (c == (CTRL|'V')) || (c == (CTRL|'Y')) ||
+ 			          (c == (CTRL|'D')) || (c == (CTRL|'F')) ||
+ 				  (c == (CTRL|'B')) || (c == (CTRL|'N')) ||
+ 				  (c == (CTRL|'P')) || (c == (CTRL|'A')) || 
+ 				  (c == (CTRL|'E')) || (c == (CTRL|'U'))) 
+ 				&& (c != (CTRL|'C'));
  
  #ifdef	MOUSE
  	clear_mfunc(mouse_in_content);
  #endif
  					/* Do it.               */
  	execute(normalize_cmd(c, fkm, 1), f, n);
+ 	if (line_information_on){
+ 	   c = (CTRL|'C');
+ 	   execute(normalize_cmd(c, fkm, 1), f, n);
+ 	}
      }
  }
  
diff -rc alpine-2.00/pico/osdep/getkey.c alpine-2.00.I.USE/pico/osdep/getkey.c
*** alpine-2.00/pico/osdep/getkey.c	2007-08-20 12:46:37.000000000 -0700
--- alpine-2.00.I.USE/pico/osdep/getkey.c	2011-02-07 20:33:42.000000000 -0800
***************
*** 130,135 ****
--- 130,145 ----
  {
      UCS ch, status, cc;
  
+     if(sendnow){
+ 	ch = Pmaster && Pmaster->auto_cmds && *Pmaster->auto_cmds 
+ 		? *Pmaster->auto_cmds++ : NODATA;
+ 
+ 	if (ch >= 0x00 && ch <= 0x1F)
+ 	      ch = CTRL | (ch+'@');
+ 
+         return(ch);
+     }
+ 
      if(!ReadyForKey(FUDGE-5))
        return(NODATA);
  
diff -rc alpine-2.00/pico/osdep/terminal.c alpine-2.00.I.USE/pico/osdep/terminal.c
*** alpine-2.00/pico/osdep/terminal.c	2008-01-29 15:21:10.000000000 -0800
--- alpine-2.00.I.USE/pico/osdep/terminal.c	2011-02-07 20:33:42.000000000 -0800
***************
*** 25,30 ****
--- 25,31 ----
  #include "../keydefs.h"
  #include "../pico.h"
  #include "../mode.h"
+ #include "../edef.h"
  
  #include "raw.h"
  #include "color.h"
***************
*** 477,482 ****
--- 478,489 ----
  {
      int     row, col;
  
+     if (sendnow){
+       term.t_nrow = 23;
+       term.t_ncol = 80;
+       return 0;
+     }
+ 
      /*
       * determine the terminal's communication speed and decide
       * if we need to do optimization ...
***************
*** 1252,1257 ****
--- 1259,1270 ----
  {
      int     row, col;
  
+     if (sendnow){
+       term.t_nrow = 23;
+       term.t_ncol = 80;
+       return 0;
+     }
+ 
      /*
       * determine the terminal's communication speed and decide
       * if we need to do optimization ...
diff -rc alpine-2.00/pico/osdep/tty.c alpine-2.00.I.USE/pico/osdep/tty.c
*** alpine-2.00/pico/osdep/tty.c	2007-08-15 16:07:18.000000000 -0700
--- alpine-2.00.I.USE/pico/osdep/tty.c	2011-02-07 20:33:47.000000000 -0800
***************
*** 223,229 ****
      int row = -1, col = -1;
  
      ttgetwinsz(&row, &col);
!     resize_pico(row, col);
  }
  
  
--- 223,236 ----
      int row = -1, col = -1;
  
      ttgetwinsz(&row, &col);
!     if(saved_state == NULL || wheadp != NULL)
! 	resize_pico(row, col);
!     else{	/* this is awkward */
! 	restore_pico_state(saved_state);
! 	free_pico_state(saved_state);
! 	resize_pico(row,col);
! 	saved_state = save_pico_state();
!     }
  }
  
  
diff -rc alpine-2.00/pico/pico.c alpine-2.00.I.USE/pico/pico.c
*** alpine-2.00/pico/pico.c	2008-01-30 16:44:12.000000000 -0800
--- alpine-2.00.I.USE/pico/pico.c	2011-02-07 20:33:44.000000000 -0800
***************
*** 137,142 ****
--- 137,151 ----
      pico_all_done = 0;
      km_popped     = 0;
  
+     if (pm->auto_cmds){
+        int i;
+ #define CTRL_X 24
+       for (i = 0;  pm->auto_cmds[i]; i++);
+       if ((i > 1) && (pm->auto_cmds[i - 2] == CTRL_X) && 
+ 		((pm->auto_cmds[i - 1] == 'y') || (pm->auto_cmds[i-1] == 'Y')))
+       sendnow++;
+     }
+ 
      if(!vtinit())			/* Init Displays.      */
        return(COMP_CANCEL);
  
***************
*** 637,648 ****
      result = "";
  
      Pmaster->arm_winch_cleanup++;
      if(Pmaster->canceltest){
          if(((Pmaster->pine_flags & MDHDRONLY) && !any_header_changes())
  	  || (result = (*Pmaster->canceltest)(redraw_pico_for_callback))){
- 	    pico_all_done = COMP_CANCEL;
  	    emlwrite(result, NULL);
  	    Pmaster->arm_winch_cleanup--;
  	    return(TRUE);
  	}
  	else{
--- 646,664 ----
      result = "";
  
      Pmaster->arm_winch_cleanup++;
+     Pmaster->onctrlc++;
      if(Pmaster->canceltest){
          if(((Pmaster->pine_flags & MDHDRONLY) && !any_header_changes())
  	  || (result = (*Pmaster->canceltest)(redraw_pico_for_callback))){
  	    emlwrite(result, NULL);
  	    Pmaster->arm_winch_cleanup--;
+ 	    if(Pmaster->curpos[0]){
+ 	       curwp->w_flag |= WFMODE;		/* and modeline so we  */
+ 	       sgarbk = TRUE;			/* redraw the keymenu  */
+ 	       pclear(term.t_nrow - 1, term.t_nrow + 1);
+ 	       return(FALSE);
+ 	    }
+ 	    pico_all_done = COMP_CANCEL;
  	    return(TRUE);
  	}
  	else{
***************
*** 671,676 ****
--- 687,698 ----
  	emlwrite(_("\007Cancel Cancelled"), NULL);
  	break;
  
+       case COUNT:
+ 	showcpos(1,0);
+ 	emlwrite(Pmaster->curpos, NULL);
+ 	Pmaster->onctrlc--;
+ 	break;
+ 
        default:
  	mlerase();
      }
***************
*** 713,718 ****
--- 735,753 ----
  	    return(FALSE);
  	}
  
+  	/* When we send a message using the command line we are going to
+  	   ignore if the user wants to spell check, we assume he already
+  	   did */
+  	if (sendnow){
+  	    ret = (*Pmaster->exittest)(Pmaster->headents,
+ 					redraw_pico_for_callback, 
+ 					Pmaster->allow_flowed_text,
+ 					&result);
+  	    if (!ret)
+  		pico_all_done = COMP_EXIT;
+  	    return(result ? FALSE : TRUE);
+  	}
+ 
  #ifdef	SPELLER
  	if(Pmaster->always_spell_check)
  	  if(spell(0, 0) == -1)
diff -rc alpine-2.00/pico/pico.h alpine-2.00.I.USE/pico/pico.h
*** alpine-2.00/pico/pico.h	2008-08-22 13:40:16.000000000 -0700
--- alpine-2.00.I.USE/pico/pico.h	2011-02-07 20:33:46.000000000 -0800
***************
*** 198,208 ****
--- 198,210 ----
      PCOLORS *colors;                    /* colors for titlebar and keymenu */
      void  *input_cs;			/* passed to mbtow() via kbseq() */
      long   pine_flags;			/* entry mode flags */
+     char  curpos[80];			/* where are we now? */
      /* The next few bits are features that don't fit in pine_flags      */
      /* If we had this to do over, it would probably be one giant bitmap */
      unsigned always_spell_check:1;      /* always spell-checking upon quit */
      unsigned strip_ws_before_send:1;    /* don't default strip bc of flowed */
      unsigned allow_flowed_text:1;    /* clean text when done to keep flowed */
+     unsigned onctrlc;			/* are we on ctrl-c command? */
      int   (*helper)();			/* Pine's help function  */
      int   (*showmsg)();			/* Pine's display_message */
      UCS   (*suspend)();			/* Pine's suspend */
***************
*** 219,225 ****
--- 221,229 ----
      int   (*user_says_noflow)();	/* callback to tell us we're not flowing */
      void  (*resize)();			/* callback handling screen resize */
      void  (*winch_cleanup)();		/* callback handling screen resize */
+     void  (*newthread)();		/* callback to create new thread   */
      int    arm_winch_cleanup;		/* do the winch_cleanup if resized */
+     int   *auto_cmds;			/* Initial keystroke commands */
      HELP_T search_help;
      HELP_T ins_help;
      HELP_T ins_m_help;
diff -rc alpine-2.00/pico/pilot.c alpine-2.00.I.USE/pico/pilot.c
*** alpine-2.00/pico/pilot.c	2008-04-02 15:09:20.000000000 -0700
--- alpine-2.00.I.USE/pico/pilot.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 142,148 ****
      if(display_character_set)
        display_charmap = cpstr(display_character_set);
  #if   HAVE_LANGINFO_H && defined(CODESET)
!     else
        display_charmap = cpstr(nl_langinfo_codeset_wrapper());
  #endif
  
--- 142,148 ----
      if(display_character_set)
        display_charmap = cpstr(display_character_set);
  #if   HAVE_LANGINFO_H && defined(CODESET)
!     else if (nl_langinfo_codeset_wrapper() != NULL)
        display_charmap = cpstr(nl_langinfo_codeset_wrapper());
  #endif
  
diff -rc alpine-2.00/pico/random.c alpine-2.00.I.USE/pico/random.c
*** alpine-2.00/pico/random.c	2007-08-15 16:07:18.000000000 -0700
--- alpine-2.00.I.USE/pico/random.c	2011-02-07 20:33:44.000000000 -0800
***************
*** 73,79 ****
  	    thisline+1, lines+1, (int)((100L*(thisline+1))/(lines+1)),
  	    nbc, nch, (nch) ? (int)((100L*nbc)/nch) : 0);
  
!     emlwrite(buffer, NULL);
      return (TRUE);
  }
  
--- 73,82 ----
  	    thisline+1, lines+1, (int)((100L*(thisline+1))/(lines+1)),
  	    nbc, nch, (nch) ? (int)((100L*nbc)/nch) : 0);
  
!     if(Pmaster)
!       strcpy(Pmaster->curpos, buffer);
!     else
!       emlwrite(buffer, NULL);
      return (TRUE);
  }
  
diff -rc alpine-2.00/pico/search.c alpine-2.00.I.USE/pico/search.c
*** alpine-2.00/pico/search.c	2008-01-04 14:49:15.000000000 -0800
--- alpine-2.00.I.USE/pico/search.c	2011-02-07 20:33:47.000000000 -0800
***************
*** 35,41 ****
  int     readpattern(char *, int);
  int     replace_pat(UCS *, int *);
  int     replace_all(UCS *, UCS *);
! 
  
  #define	FWS_RETURN(RV)	{				\
  			    thisflag |= CFSRCH;		\
--- 35,41 ----
  int     readpattern(char *, int);
  int     replace_pat(UCS *, int *);
  int     replace_all(UCS *, UCS *);
! int	deletepara(int, int);
  
  #define	FWS_RETURN(RV)	{				\
  			    thisflag |= CFSRCH;		\
***************
*** 75,80 ****
--- 75,84 ----
  N_("~        Hitting only ~R~e~t~u~r~n or at the prompt will cause the"),
  N_("        search to be made with the default value."),
  "  ",
+ N_("~        Hitting ~^~N will reinsert the last string you searched for"),
+ N_("        so that you can edit it (in case you made a mistake entering the"),
+ N_("        search pattern the first time)."),
+ "  ",
  N_("        The text search is not case sensitive, and will examine the"),
  N_("        entire message."),
  "  ",
***************
*** 139,146 ****
  
  	  case HELPCH:			/* help requested */
  	    if(Pmaster){
- 		VARS_TO_SAVE *saved_state;
- 
  		saved_state = save_pico_state();
  		(*Pmaster->helper)(Pmaster->search_help,
  				   _("Help for Searching"), 1);
--- 143,148 ----
***************
*** 231,240 ****
--- 233,251 ----
  	    mlerase();
  	    FWS_RETURN(TRUE);
  
+ 	  case (CTRL|'P'):
+ 	    deletepara(0, 1);
+ 	    mlerase();
+ 	    FWS_RETURN(TRUE);
+ 
  	  case  (CTRL|'R'):        /* toggle replacement option */
  	    repl_mode = !repl_mode;
  	    break;
  
+ 	  case (CTRL|'X'):
+ 	    deltext(f,n);
+ 	    FWS_RETURN(TRUE);
+ 
  	  default:
  	    if(status == ABORT)
  	      emlwrite(_("Search Cancelled"), NULL);
***************
*** 273,279 ****
  	}
  
  	if(status + curwp->w_doto >= llength(curwp->w_dotp) ||
! 	   !eq(defpat[status],lgetc(curwp->w_dotp, curwp->w_doto + status).c))
  	  break;		/* do nothing! */
  	status++;
      }
--- 284,290 ----
  	}
  
  	if(status + curwp->w_doto >= llength(curwp->w_dotp) ||
! 	   !eq((unsigned char)defpat[status],lgetc(curwp->w_dotp, curwp->w_doto + status).c))
  	  break;		/* do nothing! */
  	status++;
      }
***************
*** 430,437 ****
  
  	  case HELPCH:                      /* help requested */
  	    if(Pmaster){
- 		VARS_TO_SAVE *saved_state;
- 
  		saved_state = save_pico_state();
  		(*Pmaster->helper)(Pmaster->search_help,
  				   _("Help for Searching"), 1);
--- 441,446 ----
***************
*** 463,470 ****
  	    break;
  
  	  default:
! 	    if(status == ABORT)
  	      emlwrite(_("Replacement Cancelled"), NULL);
  	    else{
  		mlerase();
  		chword(defpat, origpat);
--- 472,481 ----
  	    break;
  
  	  default:
! 	    if(status == ABORT){
  	      emlwrite(_("Replacement Cancelled"), NULL);
+ 	      pico_refresh(FALSE, 1);
+ 	    }
  	    else{
  		mlerase();
  		chword(defpat, origpat);
***************
*** 597,603 ****
  	UCS         *b;
  	UCS	     prompt[NPMT];
  	UCS         *promptp;
! 	EXTRAKEYS    menu_pat[8];
  
  	menu_pat[i = 0].name = "^Y";
  	menu_pat[i].label    = N_("FirstLine");
--- 608,614 ----
  	UCS         *b;
  	UCS	     prompt[NPMT];
  	UCS         *promptp;
! 	EXTRAKEYS    menu_pat[10];
  
  	menu_pat[i = 0].name = "^Y";
  	menu_pat[i].label    = N_("FirstLine");
***************
*** 615,620 ****
--- 626,636 ----
  	KS_OSDATASET(&menu_pat[i], KS_NONE);
  
  	if(!repl_mode){
+ 	    menu_pat[++i].name = "^X";     
+ 	    menu_pat[i].label  = N_("DelEnd");
+ 	    menu_pat[i].key    = (CTRL|'X');    
+ 	    KS_OSDATASET(&menu_pat[i], KS_NONE);
+ 
  	    menu_pat[++i].name = "^T";
  	    menu_pat[i].label  = N_("LineNumber");
  	    menu_pat[i].key    = (CTRL|'T');
***************
*** 631,636 ****
--- 647,657 ----
  	    menu_pat[i].key    = (CTRL|'O');
  	    KS_OSDATASET(&menu_pat[i], KS_NONE);
  
+ 	    menu_pat[++i].name = "^P";
+ 	    menu_pat[i].label  = N_("Delete Para");
+ 	    menu_pat[i].key    = (CTRL|'P');
+ 	    KS_OSDATASET(&menu_pat[i], KS_NONE);
+ 
  	    menu_pat[++i].name = "^U";
  	    /* TRANSLATORS: Instead of justifying (formatting) just a
  	       single paragraph, Full Justify justifies the entire
***************
*** 766,772 ****
  	UCS         *b;
  	UCS	     tpat[NPAT+20];
  	UCS         *tpatp;
! 	EXTRAKEYS    menu_pat[7];
  
  	menu_pat[i = 0].name = "^Y";
  	menu_pat[i].label    = N_("FirstLine");
--- 787,793 ----
  	UCS         *b;
  	UCS	     tpat[NPAT+20];
  	UCS         *tpatp;
! 	EXTRAKEYS    menu_pat[9];
  
  	menu_pat[i = 0].name = "^Y";
  	menu_pat[i].label    = N_("FirstLine");
***************
*** 779,784 ****
--- 800,810 ----
  	KS_OSDATASET(&menu_pat[i], KS_NONE);
  
  	if(text_mode){
+ 	    menu_pat[++i].name = "^X";     
+ 	    menu_pat[i].label  = N_("DelEnd");
+ 	    menu_pat[i].key    = (CTRL|'X');    
+ 	    KS_OSDATASET(&menu_pat[i], KS_NONE);
+ 
  	    menu_pat[++i].name = "^T";
  	    menu_pat[i].label  = N_("LineNumber");
  	    menu_pat[i].key    = (CTRL|'T');
***************
*** 794,799 ****
--- 820,830 ----
  	    menu_pat[i].key    = (CTRL|'O');
  	    KS_OSDATASET(&menu_pat[i], KS_NONE);
  
+ 	    menu_pat[++i].name = "^P";
+ 	    menu_pat[i].label  = N_("Delete Para");
+ 	    menu_pat[i].key    = (CTRL|'P');
+ 	    KS_OSDATASET(&menu_pat[i], KS_NONE);
+ 
  	    menu_pat[++i].name = "^U";
  	    menu_pat[i].label  = N_("FullJustify");
  	    menu_pat[i].key    = (CTRL|'U');
***************
*** 924,930 ****
  	  c = lgetc(curline, curoff++).c;	/* get the char */
  
  	/* test it against first char in pattern */
! 	if (eq(c, patrn[0]) != FALSE) {	/* if we find it..*/
  	    /* setup match pointers */
  	    matchline = curline;
  	    matchoff = curoff;
--- 955,961 ----
  	  c = lgetc(curline, curoff++).c;	/* get the char */
  
  	/* test it against first char in pattern */
! 	if (eq(c, (unsigned char)patrn[0]) != FALSE) {	/* if we find it..*/
  	    /* setup match pointers */
  	    matchline = curline;
  	    matchoff = curoff;
***************
*** 945,951 ****
  		  return(FALSE);
  
  		/* and test it against the pattern */
! 		if (eq(*patptr, c) == FALSE)
  		  goto fail;
  	    }
  
--- 976,982 ----
  		  return(FALSE);
  
  		/* and test it against the pattern */
! 		if (eq((unsigned char) *patptr, c) == FALSE)
  		  goto fail;
  	    }
  
***************
*** 1032,1034 ****
--- 1063,1087 ----
  
      curwp->w_flag |= WFEDIT;
  }
+ 
+ int
+ deletepara(int f, int n) /* Delete the current paragraph */
+ {
+    if(curbp->b_mode&MDVIEW)           /* don't allow this command if  */ 
+      return(rdonly());               /* we are in read only mode     */
+    
+    if(!lisblank(curwp->w_dotp))
+      gotobop(FALSE, 1);
+ 
+    curwp->w_markp = curwp->w_dotp;
+    curwp->w_marko = 0;
+ 
+    gotoeop(FALSE, 1);
+    if (curwp->w_dotp != curbp->b_linep){ /* if we are not at the end of buffer */
+      curwp->w_dotp = lforw(curwp->w_dotp); /* get one more line */
+        curwp->w_doto = 0; /* but only the beginning */
+    }
+    killregion(f,n);
+    return(TRUE);
+ }
+ 
diff -rc alpine-2.00/pico/word.c alpine-2.00.I.USE/pico/word.c
*** alpine-2.00/pico/word.c	2007-08-20 12:46:37.000000000 -0700
--- alpine-2.00.I.USE/pico/word.c	2011-02-07 20:33:42.000000000 -0800
***************
*** 24,33 ****
   */
  
  #include	"headers.h"
! 
  
  int fpnewline(UCS *quote);
! int fillregion(UCS *qstr, REGION *addedregion);
  int setquotelevelinregion(int quotelevel, REGION *addedregion);
  int is_user_separator(UCS c);
  
--- 24,33 ----
   */
  
  #include	"headers.h"
! #include	"../pith/osdep/color.h"
  
  int fpnewline(UCS *quote);
! int fillregion(UCS *qstr, UCS *istr, REGION *addedregion);
  int setquotelevelinregion(int quotelevel, REGION *addedregion);
  int is_user_separator(UCS c);
  
***************
*** 430,471 ****
      return 0;
  }
  
  
  /*
   * Return number of quotes if whatever starts the line matches the quote string
   */
  int
! quote_match(UCS *q, LINE *l, UCS *buf, size_t buflen)
  {
!     register int i, n, j, qb;
  
!     *buf = '\0';
!     if(*q == '\0')
!       return(1);
! 
!     qb = (ucs4_strlen(q) > 1 && q[ucs4_strlen(q)-1] == ' ') ? 1 : 0;
!     for(n = 0, j = 0; ;){
! 	for(i = 0; j <= llength(l) && qb ? q[i+1] : q[i]; i++, j++)
! 	  if(q[i] != lgetc(l, j).c)
! 	    return(n);
! 
! 	n++;
! 	if((!qb && q[i] == '\0') || (qb && q[i+1] == '\0')){
! 	    if(ucs4_strlen(buf) + ucs4_strlen(q) + 1 < buflen){
! 		ucs4_strncat(buf, q, buflen-ucs4_strlen(q)-1);
! 		buf[buflen-1] = '\0';
! 		if(qb && (j > llength(l) || lgetc(l, j).c != ' '))
! 		  buf[ucs4_strlen(buf)-1] = '\0';
! 	    }
! 	}
! 	if(j > llength(l))
! 	  return(n);
! 	else if(qb && lgetc(l, j).c == ' ')
! 	  j++;
      }
!     return(n);  /* never reached */
  }
  
  
  /* Justify the entire buffer instead of just a paragraph */
  int
--- 430,600 ----
      return 0;
  }
  
+ /* 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)
+ 
+ int indent_match(char *, LINE *, char *, int, int);
+ 
+ /* Extended justification support */
+ #define is_cquote(c) ((c) == '>' || (c) == '|' || (c) == ']' || (c) == ':')
+ #define is_cword(c)  ((((c) >= 'a') && ((c) <= 'z')) ||  \
+                      (((c) >= 'A') && ((c) <= 'Z')) || \
+                      (((c) >= '0') && ((c) <= '9')) || \
+                       ((c) == ' ') || ((c) == '?') || \
+                       ((c) == '@') || ((c) == '.') || \
+                       ((c) == '!') || ((c) == '\'') || \
+                       ((c) == ',') || ((c) == '\"') ? 1 : 0)
+ #define isaquote(c)   ((c) == '\"' || (c) == '\'')
+ #define is8bit(c)     ((((int) (c)) & 0x80) ? 1 : 0)
+ #define 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 *qs_quote_match(char *, LINE *, char *, int);
+ int      ucs4_strlenis(UCS *);
+ void     linencpy(char *, LINE *, int);
+ 
+ 
+ char *
+ default_qstr(void)
+ {
+   char *default_qs;
+   static char ucs_def[NSTRING] = {'\0'};
+ 
+   if(ucs_def[0] == '\0'){
+      default_qs = ucs4_to_utf8_cpystr(glo_quote_str);
+      strncpy(ucs_def, (default_qs ? default_qs : ""), NSTRING);
+      fs_give((void **)&default_qs);
+   }
+ 
+   return glo_quote_str ? ucs_def : "";
+ }
+ 
+ void
+ linencpy(word, l, buflen)
+  char word[NSTRING];
+  LINE *l;
+  int buflen;
+ {
+   int i;
+   UCS ucs_word[NSTRING];
+   char *utf_word;
+ 
+   word[0] = '\0';
+   if(l){
+     for (i = 0; i < buflen && i < llength(l)
+                && (ucs_word[i] = lgetc(l,i).c); i++);
+     ucs_word[i == buflen ? i-1 : i] = '\0';
+     utf_word = ucs4_to_utf8_cpystr(ucs_word);
+     strncpy(word, utf_word, (NSTRING < buflen ? NSTRING : buflen));
+     word[NSTRING-1] = '\0';
+     if(utf_word) fs_give((void **)&utf_word);
+   }
+ }
+ 
+  /*
+   * This function returns the quote string as a structure. In this way we
+   * have two ways to get the quote string: as a char * or as a QSTRING_S *
+   * directly.
+   */
+ QSTRING_S *
+ qs_quote_match(char *q, LINE *l, char *rqstr, int rqstrlen)
+ {
+     char GLine[NSTRING], NLine[NSTRING], PLine[NSTRING];
+     LINE *nl = l != curbp->b_linep ? lforw(l) : NULL;
+     LINE *pl = lback(l) != curbp->b_linep ? lback(l) : NULL;
+     int plb = 1;
+ 
+    linencpy(GLine, l, NSTRING);
+    linencpy(NLine, nl, NSTRING);
+ 
+    if (pl){
+       linencpy(PLine, pl, NSTRING);
+       if(lback(pl) != curbp->b_linep){
+ 	char PPLine[NSTRING];
+ 
+ 	linencpy(PPLine, lback(pl), NSTRING);
+ 	plb = line_isblank(q, PLine, GLine, PPLine, NSTRING);
+       }
+     }
+     return do_quote_match(q, GLine, NLine, PLine, rqstr, rqstrlen, plb);
+ }
  
  /*
   * Return number of quotes if whatever starts the line matches the quote string
+  * rqstring is  pointer to raw qstring, buf points to processed qstring
   */
  int
! quote_match(char *q, LINE *l, char *buf, size_t buflen, int raw)
  {
!     QSTRING_S *qs;
!     char rqstr[NSTRING];
  
!     qs = qs_quote_match(q, l, rqstr, NSTRING);
!     flatten_qstring(qs, buf, buflen);
!     if (qs)
!         free_qs(&qs);
! 
!     if(raw){
!       strncpy(buf, rqstr, buflen < NSTRING ? buflen : NSTRING);
!       buf[buflen-1] = '\0';
      }
! 
!     return  buf && buf[0] ? strlen(buf) : 0;
  }
  
+ int ucs4_strlenis(UCS *ucs_qstr)
+ {
+   char *str = ucs4_to_utf8_cpystr(ucs_qstr);
+   int i = (int) strlenis(str);
+ 
+   if(str) fs_give((void **)&str);
+   return i;
+ }
  
  /* Justify the entire buffer instead of just a paragraph */
  int
***************
*** 720,725 ****
--- 849,855 ----
      }
  
      if(action == 'R' && curwp->w_markp){
+ 	char qstrfl[NSTRING];
  	/* let yank() know that it may be restoring a paragraph */
  	thisflag |= CFFILL;
  
***************
*** 732,752 ****
  
  	/* determine if we're justifying quoted text or not */
  	qstr = (glo_quote_str
! 		&& quote_match(glo_quote_str, 
! 			       curwp->w_doto > 0 ? curwp->w_dotp->l_fp : curwp->w_dotp,
! 			       qstr2, NSTRING)
! 		&& *qstr2) ? qstr2 : NULL;
! 
  
  	/*
  	 * Fillregion moves dot to the end of the filled region.
  	 */
! 	if(!fillregion(qstr, &addedregion))
  	  return(FALSE);
  
  	set_last_region_added(&addedregion);
      }
      else if(action == 'P'){
  
  	/*
  	 * Justfiy the current paragraph.
--- 862,886 ----
  
  	/* determine if we're justifying quoted text or not */
  	qstr = (glo_quote_str
! 		&& quote_match(default_qstr(), 
! 			       (curwp->w_doto > 0 ? curwp->w_dotp->l_fp : curwp->w_dotp),
! 			       qstrfl, NSTRING, 0)
! 		&& *qstrfl) ? utf8_to_ucs4_cpystr(qstrfl) : NULL;
  
  	/*
  	 * Fillregion moves dot to the end of the filled region.
  	 */
! 	if(!fillregion(qstr, NULL, &addedregion))
  	  return(FALSE);
  
  	set_last_region_added(&addedregion);
+ 
+ 	if(qstr)
+ 	  fs_give((void **)&qstr);
      }
      else if(action == 'P'){
+ 	char ind_str[NSTRING], qstrfl[NSTRING];
+ 	UCS *istr;
  
  	/*
  	 * Justfiy the current paragraph.
***************
*** 758,774 ****
  	if(gotoeop(FALSE, 1) == FALSE)
  	  return(FALSE);
  
- 	/* determine if we're justifying quoted text or not */
- 	qstr = (glo_quote_str
- 		&& quote_match(glo_quote_str, 
- 			       curwp->w_dotp, qstr2, NSTRING)
- 		&& *qstr2) ? qstr2 : NULL;
- 
  	setmark(0,0);			/* mark last line of para */
  
  	/* jump back to the beginning of the paragraph */
  	gotobop(FALSE, 1);
  
  	/* let yank() know that it may be restoring a paragraph */
  	thisflag |= (CFFILL | CFFLPA);
  
--- 892,907 ----
  	if(gotoeop(FALSE, 1) == FALSE)
  	  return(FALSE);
  
  	setmark(0,0);			/* mark last line of para */
  
  	/* jump back to the beginning of the paragraph */
  	gotobop(FALSE, 1);
  
+ 	istr = indent_match(default_qstr(), curwp->w_dotp, ind_str, NSTRING, 0)
+ 	   && *ind_str  ? utf8_to_ucs4_cpystr(ind_str) : NULL;
+ 	qstr = (quote_match(default_qstr(), curwp->w_dotp, qstrfl, NSTRING, 0)
+             && *qstrfl) ? utf8_to_ucs4_cpystr(qstrfl) : NULL;
+ 
  	/* let yank() know that it may be restoring a paragraph */
  	thisflag |= (CFFILL | CFFLPA);
  
***************
*** 782,790 ****
  	/*
  	 * Fillregion moves dot to the end of the filled region.
  	 */
! 	if(!fillregion(qstr, &addedregion))
  	  return(FALSE);
  
  	set_last_region_added(&addedregion);
  
  	/* Leave cursor on first char of first line after justified region */
--- 915,929 ----
  	/*
  	 * Fillregion moves dot to the end of the filled region.
  	 */
! 	if(!fillregion(qstr, istr, &addedregion))
  	  return(FALSE);
  
+ 	if(qstr)
+ 	  fs_give((void **)&qstr);
+ 
+ 	if(istr)
+ 	  fs_give((void **)&istr);
+ 
  	set_last_region_added(&addedregion);
  
  	/* Leave cursor on first char of first line after justified region */
***************
*** 826,841 ****
   * can delete it and restore the saved part.
   */
  int
! fillregion(UCS *qstr, REGION *addedregion)
  {
      long    c, sz, last_char = 0;
!     int	    i, j, qlen, same_word,
  	    spaces, word_len, word_ind, line_len, ww;
      int     starts_midline = 0;
      int     ends_midline = 0;
      int     offset_into_start;
      LINE   *line_before_start, *lp;
!     UCS     line_last, word[NSTRING];
      REGION  region;
  
      /* if region starts midline insert a newline */
--- 965,980 ----
   * can delete it and restore the saved part.
   */
  int
! fillregion(UCS *qstr, UCS *istr, REGION *addedregion)
  {
      long    c, sz, last_char = 0;
!     int	    i, j, qlen, same_word, qi, pqi, qlenis,
  	    spaces, word_len, word_ind, line_len, ww;
      int     starts_midline = 0;
      int     ends_midline = 0;
      int     offset_into_start;
      LINE   *line_before_start, *lp;
!     UCS     line_last, word[NSTRING], quoid[NSTRING], qstr2[NSTRING];
      REGION  region;
  
      /* if region starts midline insert a newline */
***************
*** 846,851 ****
--- 985,1019 ----
      if(curwp->w_marko > 0 && curwp->w_marko < llength(curwp->w_markp))
        ends_midline++;
  
+     for (i = 0; (i < NSTRING) && qstr && (quoid[i] = qstr[i]); i++);
+     for (j = 0; ((i + j) < NSTRING) && istr && (quoid[i] = istr[j]); i++,j++);
+     quoid[i] = '\0';
+     qi = ucs4_strlen(quoid);
+     if (istr)			/* strip trailing spaces */
+        for (;ISspace(quoid[qi - 1]); qi--);
+     quoid[qi] = '\0';     /* we have closed quoid at "X" in the first line */
+ 
+     if (ucs4_strlenis(quoid) > fillcol)
+ 	return FALSE;		/* Too wide, we can't justify this! */
+ 
+     if (qstr && istr){
+ 	for (i = ucs4_strlen(qstr) - 1; ISspace(qstr[i]); i--);
+ 	qstr[i + 1] = '\0';	/* qstrfl */
+     }
+     qlen   = ucs4_strlen(qstr);	/* qstrfl*/
+     qlenis = ucs4_strlenis(qstr);
+ 
+     for(i = 0, qstr2[0] = '\0'; qstr && qstr[i] && (qstr2[i] = qstr[i]); i++);
+ 
+     if (istr && ((j = ucs4_strlenis(quoid) - ucs4_strlenis(qstr)) > 0)){
+ 	pqi = ucs4_strlen(qstr);
+ 	for (i = 0; (i < j) && (qstr2[pqi + i] = ' '); i++);
+ 	if (ISspace(istr[ucs4_strlen(istr) - 1]))
+ 	   qstr2[pqi + i++] = ' ';
+ 	qstr2[pqi + i] = '\0';
+ 	qstr = qstr2;
+     }
+ 
      /* cut the paragraph into our fill buffer */
      fdelete();
      if(!getregion(&region, curwp->w_markp, curwp->w_marko))
***************
*** 862,889 ****
  
      /* Now insert it back wrapped */
      spaces = word_len = word_ind = line_len = same_word = 0;
-     qlen = qstr ? ucs4_strlen(qstr) : 0;
  
      /* Beginning with leading quoting... */
!     if(qstr){
! 	i = 0;
! 	while(qstr[i]){
! 	  ww = wcellwidth(qstr[i]);
! 	  line_len += (ww >= 0 ? ww : 1);
! 	  linsert(1, qstr[i++]);
! 	}
  
  	line_last = ' ';			/* no word-flush space! */
      }
  
      /* remove first leading quotes if any */
      if(starts_midline)
        i = 0;
!     else
!       for(i = qlen; (c = fremove(i)) == ' ' || c == TAB; i++){
  	  linsert(1, line_last = (UCS) c);
  	  line_len += ((c == TAB) ? (~line_len & 0x07) + 1 : 1);
        }
  
      /* then digest the rest... */
      while((c = fremove(i++)) >= 0){
--- 1030,1065 ----
  
      /* Now insert it back wrapped */
      spaces = word_len = word_ind = line_len = same_word = 0;
  
      /* Beginning with leading quoting... */
!     if(qstr || istr){
! 	for(i = 0; quoid[i] != '\0' ; i++)
! 	  linsert(1, quoid[i]);
  
  	line_last = ' ';			/* no word-flush space! */
+         line_len = ucs4_strlenis(quoid);         /* we demand a recount! */
      }
  
      /* remove first leading quotes if any */
      if(starts_midline)
        i = 0;
!     else{
!       if(qstr || istr){
!         for (i = 0; (c = fremove(i)) != '\0'; i++){
!                 word[i] = c;
!                 word[i+1] = '\0';
!                 if(ucs4_strlenis(word) >= ucs4_strlenis(quoid))
!                 break;
!         }
! 	i++;
!       }
!       else
! 	i = 0;
!       for(; ISspace(c = fremove(i)); i++){
  	  linsert(1, line_last = (UCS) c);
  	  line_len += ((c == TAB) ? (~line_len & 0x07) + 1 : 1);
        }
+     }
  
      /* then digest the rest... */
      while((c = fremove(i++)) >= 0){
***************
*** 905,925 ****
  
  	  case TAB :
  	  case ' ' :
  	    spaces++;
  	    same_word = 0;
  	    break;
  
  	  default :
  	    if(spaces){				/* flush word? */
! 		if((line_len - qlen > 0)
  		   && line_len + word_len + 1 > fillcol
! 		   && ((ucs4_isspace(line_last))
  		       || (linsert(1, ' ')))
  		   && (line_len = fpnewline(qstr)))
  		  line_last = ' ';	/* no word-flush space! */
  
  		if(word_len){			/* word to write? */
! 		    if(line_len && !ucs4_isspace(line_last)){
  			linsert(1, ' ');	/* need padding? */
  			line_len++;
  		    }
--- 1081,1102 ----
  
  	  case TAB :
  	  case ' ' :
+ 	  case NBSP:
  	    spaces++;
  	    same_word = 0;
  	    break;
  
  	  default :
  	    if(spaces){				/* flush word? */
! 		if((line_len - qlenis > 0)
  		   && line_len + word_len + 1 > fillcol
! 		   && ((ISspace(line_last))
  		       || (linsert(1, ' ')))
  		   && (line_len = fpnewline(qstr)))
  		  line_last = ' ';	/* no word-flush space! */
  
  		if(word_len){			/* word to write? */
! 		    if(line_len && !ISspace(line_last)){
  			linsert(1, ' ');	/* need padding? */
  			line_len++;
  		    }
***************
*** 941,948 ****
  
  	    if(word_ind + 1 >= NSTRING){
  		/* Magic!  Fake that we output a wrapped word */
! 		if((line_len - qlen > 0) && !same_word++){
! 		    if(!ucs4_isspace(line_last))
  		      linsert(1, ' ');
  		    line_len = fpnewline(qstr);
  		}
--- 1118,1125 ----
  
  	    if(word_ind + 1 >= NSTRING){
  		/* Magic!  Fake that we output a wrapped word */
! 		if((line_len - qlenis > 0) && !same_word++){
! 		    if(!ISspace(line_last))
  		      linsert(1, ' ');
  		    line_len = fpnewline(qstr);
  		}
***************
*** 964,975 ****
      }
  
      if(word_len){
! 	if((line_len - qlen > 0) && (line_len + word_len + 1 > fillcol)){
! 	    if(!ucs4_isspace(line_last))
  	      linsert(1, ' ');
  	    (void) fpnewline(qstr);
  	}
! 	else if(line_len && !ucs4_isspace(line_last))
  	  linsert(1, ' ');
  
  	for(j = 0; j < word_ind; j++)
--- 1141,1152 ----
      }
  
      if(word_len){
! 	if((line_len - qlenis > 0) && (line_len + word_len + 1 > fillcol)){
! 	    if(!ISspace(line_last))
  	      linsert(1, ' ');
  	    (void) fpnewline(qstr);
  	}
! 	else if(line_len && !ISspace(line_last))
  	  linsert(1, ' ');
  
  	for(j = 0; j < word_ind; j++)
***************
*** 1027,1037 ****
      int len;
  
      lnewline();
!     for(len = 0; quote && *quote; quote++){
  	int ww;
  
! 	ww = wcellwidth(*quote);
! 	len += (ww >= 0 ? ww : 1);
  	linsert(1, *quote);
      }
  
--- 1204,1214 ----
      int len;
  
      lnewline();
!     for(len = ucs4_strlenis(quote); quote && *quote; quote++){
  	int ww;
  
! /*	ww = wcellwidth(*quote);
! 	len += (ww >= 0 ? ww : 1);*/
  	linsert(1, *quote);
      }
  
***************
*** 1175,1179 ****
--- 1352,1396 ----
  	markregion(1);
      }
  
+     /*
+      * This puts us at the end of the quoted region instead
+      * of on the following line. This makes it convenient
+      * for the user to follow a quotelevel adjustment with
+      * a Justify if desired.
+      */
+     if(backuptoprevline){
+ 	curwp->w_doto = 0;
+ 	backchar(0, 1);
+     }
+ 
+     if(ends_midline){	/* doesn't need fixing otherwise */
+ 	unmarkbuffer();
+ 	markregion(1);
+     }
+ 
      return (TRUE);
  }
+ 
+ /*
+  * If there is an indent string this function returns
+  * its length
+  */ 
+ int
+ indent_match(char *q, LINE *l, char *buf, int buflen, int raw)
+ {
+      char GLine[NSTRING];
+      int  i, k, plb;
+        
+      k = quote_match(q,l, buf, buflen, raw);
+      linencpy(GLine, l, NSTRING);
+      plb = (lback(l) != curbp->b_linep) ? lisblank(lback(l)) : 1;
+      if (!plb){
+         i = llength(lback(l)) - 1;
+         for (; i >= 0 && ISspace(lgetc(lback(l), i).c); i--);
+         if (EOLchar(lgetc(lback(l), i).c))
+           plb++;
+      }      
+     
+      return get_indent_raw_line(q, GLine, buf, buflen, k, plb);
+ }
+ 
diff -rc alpine-2.00/pith/adrbklib.c alpine-2.00.I.USE/pith/adrbklib.c
*** alpine-2.00/pith/adrbklib.c	2008-06-03 08:54:15.000000000 -0700
--- alpine-2.00.I.USE/pith/adrbklib.c	2011-02-07 20:33:41.000000000 -0800
***************
*** 5119,5126 ****
  	    if(as.cur >= as.how_many_personals)
  	      pab->type |= GLOBAL;
  
! 	    pab->access = adrbk_access(pab);
! 
  	    /* global address books are forced readonly */
  	    if(pab->type & GLOBAL && pab->access != NoAccess)
  	      pab->access = ReadOnly;
--- 5119,5132 ----
  	    if(as.cur >= as.how_many_personals)
  	      pab->type |= GLOBAL;
  
! 	    if(ps_global->mail_stream && 
! 		ps_global->mail_stream->lock && (pab->type & REMOTE_VIA_IMAP)){
! 	      as.initialized = 0;
! 	      pab->access = NoAccess;
! 	    }
! 	    else{
! 	      pab->access = adrbk_access(pab);
! 	    }
  	    /* global address books are forced readonly */
  	    if(pab->type & GLOBAL && pab->access != NoAccess)
  	      pab->access = ReadOnly;
diff -rc alpine-2.00/pith/charconv/utf8.c alpine-2.00.I.USE/pith/charconv/utf8.c
*** alpine-2.00/pith/charconv/utf8.c	2008-04-02 15:09:20.000000000 -0700
--- alpine-2.00.I.USE/pith/charconv/utf8.c	2011-02-07 20:33:42.000000000 -0800
***************
*** 1048,1053 ****
--- 1048,1103 ----
  
  
  /*
+  * 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 -rc alpine-2.00/pith/charconv/utf8.h alpine-2.00.I.USE/pith/charconv/utf8.h
*** alpine-2.00/pith/charconv/utf8.h	2008-04-02 15:09:20.000000000 -0700
--- alpine-2.00.I.USE/pith/charconv/utf8.h	2011-02-07 20:33:42.000000000 -0800
***************
*** 80,85 ****
--- 80,86 ----
  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 -rc alpine-2.00/pith/color.c alpine-2.00.I.USE/pith/color.c
*** alpine-2.00/pith/color.c	2007-08-15 13:28:09.000000000 -0700
--- alpine-2.00.I.USE/pith/color.c	2011-02-07 20:33:42.000000000 -0800
***************
*** 20,26 ****
  #include "../pith/state.h"
  #include "../pith/conf.h"
  #include "../pith/filter.h"
! 
  
  char *
  color_embed(char *fg, char *bg)
--- 20,27 ----
  #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)
***************
*** 69,91 ****
      struct quote_colors *next;
  };
  
  
  int
  color_a_quote(long int linenum, char *line, LT_INS_S **ins, void *is_flowed_msg)
  {
!     int countem = 0;
      struct variable *vars = ps_global->vars;
!     char *p;
      struct quote_colors *colors = NULL, *cp, *next;
      COLOR_PAIR *col = NULL;
      int is_flowed = is_flowed_msg ? *((int *)is_flowed_msg) : 0;
  
      p = line;
!     if(!is_flowed)
!       while(isspace((unsigned char)*p))
! 	p++;
  
!     if(p[0] == '>'){
  	struct quote_colors *c;
  
  	/*
--- 70,179 ----
      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, i, j = 0;
      struct variable *vars = ps_global->vars;
!     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;
!     for(i = 0; isspace((unsigned char)buf[i]); i++, p++);
  
!     if(buf[i]){
  	struct quote_colors *c;
  
  	/*
***************
*** 134,140 ****
        free_color_pair(&col);
  
      cp = NULL;
!     while(*p == '>'){
  	cp = (cp && cp->next) ? cp->next : colors;
  
  	if(countem > 0)
--- 222,228 ----
        free_color_pair(&col);
  
      cp = NULL;
!     while(buf[i]){
  	cp = (cp && cp->next) ? cp->next : colors;
  
  	if(countem > 0)
***************
*** 144,153 ****
  
  	countem = (countem == 1) ? 0 : countem;
  
! 	p++;
! 	if(!is_flowed)
! 	  for(; isspace((unsigned char)*p); p++)
! 	    ;
      }
  
      if(colors){
--- 232,240 ----
  
  	countem = (countem == 1) ? 0 : countem;
  
!        i = next_level_quote(buf, &p, i, is_flowed);
!        for (; isspace((unsigned char)*p); p++);
!        for (; isspace((unsigned char)buf[i]); i++);
      }
  
      if(colors){
***************
*** 210,216 ****
  	}
      }
  
!     return(0);
  }
  
  
--- 297,303 ----
  	}
      }
  
!     return(1);
  }
  
  
diff -rc alpine-2.00/pith/color.h alpine-2.00.I.USE/pith/color.h
*** alpine-2.00/pith/color.h	2007-05-08 16:38:08.000000000 -0700
--- alpine-2.00.I.USE/pith/color.h	2011-02-07 20:33:42.000000000 -0800
***************
*** 21,26 ****
--- 21,44 ----
  #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,85 ****
--- 98,104 ----
  /* 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 -rc alpine-2.00/pith/conf.c alpine-2.00.I.USE/pith/conf.c
*** alpine-2.00/pith/conf.c	2008-08-22 17:07:05.000000000 -0700
--- alpine-2.00.I.USE/pith/conf.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 28,33 ****
--- 28,34 ----
  #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"
***************
*** 197,208 ****
--- 198,213 ----
  
  CONF_TXT_T cf_text_view_hdr_color[] =	"When viewing messages, these are the header colors";
  
+ CONF_TXT_T cf_text_index_token_color[] =	"Colors in which tokens will be displayed in the index screen";
+ 
  CONF_TXT_T cf_text_save_msg_name_rule[] =	"Determines default folder name for Saves...\n# Choices: default-folder, by-sender, by-from, by-recipient, last-folder-used.\n# Default: \"default-folder\", i.e. \"saved-messages\" (Unix) or \"SAVEMAIL\" (PC).";
  
  CONF_TXT_T cf_text_fcc_name_rule[] =	"Determines default name for Fcc...\n# Choices: default-fcc, by-recipient, last-fcc-used.\n# Default: \"default-fcc\" (see also \"default-fcc=\" variable.)";
  
  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\".";
***************
*** 219,230 ****
--- 224,267 ----
  
  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.";
***************
*** 427,432 ****
--- 464,472 ----
  
  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
***************
*** 517,522 ****
--- 557,564 ----
  	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,
***************
*** 539,544 ****
--- 581,614 ----
  	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},
***************
*** 557,562 ****
--- 627,634 ----
  	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,
***************
*** 627,632 ****
--- 699,708 ----
  	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,
***************
*** 788,793 ****
--- 864,875 ----
  {"title-background-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
  {"title-closed-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
  {"title-closed-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"folder-foreground-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"folder-background-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"directory-foreground-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"directory-background-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"folder-list-text-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"folder-list-text-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
  {"status-foreground-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
  {"status-background-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
  {"keylabel-foreground-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
***************
*** 808,813 ****
--- 890,897 ----
  {"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},
***************
*** 840,845 ****
--- 924,931 ----
  {"index-from-background-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
  {"index-opening-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
  {"index-opening-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
+ {"index-token-colors",			0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
+ 	NULL,			cf_text_index_token_color},
  {"viewer-hdr-colors",			0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
  	"Viewer Header Colors",	cf_text_view_hdr_color},
  {"keyword-colors",			0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
***************
*** 1555,1561 ****
      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;
      long         rvl;
      PINERC_S    *fixedprc = NULL;
      FeatureLevel obs_feature_level;
--- 1641,1647 ----
      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, thread_def_sort_rev;
      long         rvl;
      PINERC_S    *fixedprc = NULL;
      FeatureLevel obs_feature_level;
***************
*** 1580,1585 ****
--- 1666,1672 ----
      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);
***************
*** 1642,1647 ****
--- 1729,1737 ----
      GLO_TITLE_BACK_COLOR	= cpystr(DEFAULT_TITLE_BACK_RGB);
      GLO_TITLECLOSED_FORE_COLOR	= cpystr(DEFAULT_TITLECLOSED_FORE_RGB);
      GLO_TITLECLOSED_BACK_COLOR	= cpystr(DEFAULT_TITLECLOSED_BACK_RGB);
+     GLO_FOLDER_FORE_COLOR	= cpystr(DEFAULT_NORM_FORE_RGB);
+     GLO_DIRECTORY_FORE_COLOR	= cpystr(DEFAULT_NORM_FORE_RGB);
+     GLO_FOLDER_LIST_FORE_COLOR	= cpystr(DEFAULT_NORM_FORE_RGB);
      GLO_METAMSG_FORE_COLOR	= cpystr(DEFAULT_METAMSG_FORE_RGB);
      GLO_METAMSG_BACK_COLOR	= cpystr(DEFAULT_METAMSG_BACK_RGB);
      GLO_QUOTE1_FORE_COLOR	= cpystr(DEFAULT_QUOTE1_FORE_RGB);
***************
*** 1943,1948 ****
--- 2033,2040 ----
      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);
***************
*** 2216,2221 ****
--- 2308,2319 ----
        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])
***************
*** 2446,2452 ****
      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){
  	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;
--- 2544,2550 ----
      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,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;
***************
*** 2455,2460 ****
--- 2553,2569 ----
      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++)
***************
*** 2541,2546 ****
--- 2650,2656 ----
        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 */
***************
*** 2744,2749 ****
--- 2854,2861 ----
  	 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,
***************
*** 2762,2767 ****
--- 2874,2881 ----
  	 F_ENABLE_STRIP_SIGDASHES, h_config_strip_sigdashes, PREF_RPLY, 0},
  	{"forward-as-attachment", "Forward messages as attachments",
  	 F_FORWARD_AS_ATTACHMENT, h_config_forward_as_attachment, PREF_RPLY, 0},
+ 	{"preserve-original-fields", NULL,
+ 	 F_PRESERVE_ORIGINAL_FIELD, h_config_preserve_field, PREF_RPLY, 0},
  
  /* Sending Prefs */
  	{"disable-sender", "Do Not Generate Sender Header",
***************
*** 2786,2791 ****
--- 2900,2907 ----
  	 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",
***************
*** 2832,2837 ****
--- 2948,2957 ----
  	 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",
***************
*** 2848,2853 ****
--- 2968,2975 ----
  /* 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,
***************
*** 2876,2881 ****
--- 2998,3005 ----
  	 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",
***************
*** 2886,2891 ****
--- 3010,3017 ----
  	 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 */
***************
*** 2983,2988 ****
--- 3109,3116 ----
  	 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,
***************
*** 3044,3049 ****
--- 3172,3179 ----
  	 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},
***************
*** 3179,3184 ****
--- 3309,3316 ----
  	 F_DISABLE_SHARED_NAMESPACES, h_config_disable_shared, PREF_HIDDEN, 0},
  	{"disable-signature-edit-cmd", NULL,
  	 F_DISABLE_SIGEDIT_CMD, h_config_disable_signature_edit, PREF_HIDDEN, 0},
+ 	{"new-thread-on-blank-subject", "New Thread on Blank Subject",
+ 	 F_NEW_THREAD_ON_BLANK_SUBJECT, h_config_new_thread_blank_subject, PREF_HIDDEN, 1},
  	{"quell-personal-name-prompt", NULL,
  	 F_QUELL_PERSONAL_NAME_PROMPT, h_config_quell_personal_name_prompt, PREF_HIDDEN, 0},
  	{"quell-user-id-prompt", "Quell User ID Prompt",
***************
*** 4734,4750 ****
     but also after each : in the path.
  	
    ----*/
  
  char *
  expand_variables(char *lineout, size_t lineoutlen, char *linein, int colon_path)
  {
      char *src = linein, *dest = lineout, *p;
      char *limit = lineout + lineoutlen;
!     int   envexpand = 0;
  
      if(!linein)
        return(NULL);
  
      while(*src ){			/* something in input string */
          if(*src == '$' && *(src+1) == '$'){
  	    /*
--- 4866,4887 ----
     but also after each : in the path.
  	
    ----*/
+ #define is_allowed_envchar(C, S) ((S) == 0 ? !isspace((C)) 	\
+ 		: (((C) >= 'a'  && (C) <= 'z')				\
+ 		  || ((C) >= 'A'  && (C) <= 'Z')			\
+ 		  || ((C) >= '0'  && (C) <= '9')))
  
  char *
  expand_variables(char *lineout, size_t lineoutlen, char *linein, int colon_path)
  {
      char *src = linein, *dest = lineout, *p;
      char *limit = lineout + lineoutlen;
!     int   envexpand = 0, sp;
  
      if(!linein)
        return(NULL);
  
+     sp = strncmp(src,"LIT:pattern=\"/NICK=", strlen("LIT:pattern=\"/NICK=")) == 0;
      while(*src ){			/* something in input string */
          if(*src == '$' && *(src+1) == '$'){
  	    /*
***************
*** 4825,4831 ****
  		src = rbrace + 1;
  	    }
  	    else{
! 		while(*src && !isspace((unsigned char) *src)
  		      && (p-word < sizeof(word)-1))
  		  *p++ = *src++;
  	    }
--- 4962,4968 ----
  		src = rbrace + 1;
  	    }
  	    else{
! 		while(*src && is_allowed_envchar((unsigned char) *src, sp)
  		      && (p-word < sizeof(word)-1))
  		  *p++ = *src++;
  	    }
***************
*** 6356,6361 ****
--- 6493,6501 ----
  
      set_color_val(&vars[V_TITLE_FORE_COLOR], 1);
      set_color_val(&vars[V_TITLECLOSED_FORE_COLOR], 0);
+     set_color_val(&vars[V_FOLDER_FORE_COLOR], 0);
+     set_color_val(&vars[V_DIRECTORY_FORE_COLOR], 0);
+     set_color_val(&vars[V_FOLDER_LIST_FORE_COLOR], 0);
      set_color_val(&vars[V_STATUS_FORE_COLOR], 1);
      set_color_val(&vars[V_KEYLABEL_FORE_COLOR], 1);
      set_color_val(&vars[V_KEYNAME_FORE_COLOR], 1);
***************
*** 6379,6385 ****
--- 6519,6527 ----
      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);
      set_current_val(&ps->vars[V_KW_COLORS], TRUE, TRUE);
      set_custom_spec_colors(ps);
***************
*** 6532,6537 ****
--- 6674,6684 ----
  void
  set_custom_spec_colors(struct pine *ps)
  {
+     if(ps->index_token_colors)
+       free_spec_colors(&ps->index_token_colors);
+ 
+     ps->index_token_colors = spec_colors_from_varlist(ps->VAR_INDEX_TOKEN_COLORS, 1);
+ 
      if(ps->hdr_colors)
        free_spec_colors(&ps->hdr_colors);
  
***************
*** 6895,6900 ****
--- 7042,7053 ----
  
  	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);
***************
*** 7500,7509 ****
--- 7653,7692 ----
  	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 :
***************
*** 7554,7559 ****
--- 7737,7744 ----
  	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 :
***************
*** 7676,7681 ****
--- 7861,7870 ----
  	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)
***************
*** 7694,7699 ****
--- 7883,7894 ----
        case V_TITLECLOSED_FORE_COLOR :
        case V_TITLECLOSED_BACK_COLOR :
  	return(h_config_titleclosed_color);
+       case V_FOLDER_FORE_COLOR:
+ 	return(h_config_folder_color);
+       case V_DIRECTORY_FORE_COLOR:
+ 	return(h_config_directory_color);
+       case V_FOLDER_LIST_FORE_COLOR:
+ 	return(h_config_folder_list_color);
        case V_STATUS_FORE_COLOR :
        case V_STATUS_BACK_COLOR :
  	return(h_config_status_color);
***************
*** 7713,7718 ****
--- 7908,7916 ----
        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);
***************
*** 7764,7769 ****
--- 7962,7969 ----
  	return(h_config_metamsg_color);
        case V_VIEW_HDR_COLORS :
  	return(h_config_customhdr_color);
+       case V_INDEX_TOKEN_COLORS :
+ 	return(h_config_indextoken_color);
        case V_PRINTER :
  	return(h_config_printer);
        case V_PERSONAL_PRINT_CATEGORY :
***************
*** 8194,8196 ****
--- 8394,8397 ----
  }
  
  #endif	/* _WINDOWS */
+ 
diff -rc alpine-2.00/pith/conf.h alpine-2.00.I.USE/pith/conf.h
*** alpine-2.00/pith/conf.h	2008-08-19 17:27:11.000000000 -0700
--- alpine-2.00.I.USE/pith/conf.h	2011-02-07 20:33:45.000000000 -0800
***************
*** 143,152 ****
--- 143,195 ----
  #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
***************
*** 160,165 ****
--- 203,210 ----
  #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
***************
*** 249,254 ****
--- 294,303 ----
  #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
***************
*** 373,378 ****
--- 422,439 ----
  #define GLO_TITLECLOSED_FORE_COLOR   vars[V_TITLECLOSED_FORE_COLOR].global_val.p
  #define VAR_TITLECLOSED_BACK_COLOR   vars[V_TITLECLOSED_BACK_COLOR].current_val.p
  #define GLO_TITLECLOSED_BACK_COLOR   vars[V_TITLECLOSED_BACK_COLOR].global_val.p
+ #define VAR_FOLDER_FORE_COLOR	     vars[V_FOLDER_FORE_COLOR].current_val.p
+ #define GLO_FOLDER_FORE_COLOR	     vars[V_FOLDER_FORE_COLOR].global_val.p
+ #define VAR_FOLDER_BACK_COLOR	     vars[V_FOLDER_BACK_COLOR].current_val.p
+ #define GLO_FOLDER_BACK_COLOR	     vars[V_FOLDER_BACK_COLOR].global_val.p
+ #define VAR_DIRECTORY_FORE_COLOR     vars[V_DIRECTORY_FORE_COLOR].current_val.p
+ #define GLO_DIRECTORY_FORE_COLOR     vars[V_DIRECTORY_FORE_COLOR].global_val.p
+ #define VAR_DIRECTORY_BACK_COLOR     vars[V_DIRECTORY_BACK_COLOR].current_val.p
+ #define GLO_DIRECTORY_BACK_COLOR     vars[V_DIRECTORY_BACK_COLOR].global_val.p
+ #define VAR_FOLDER_LIST_FORE_COLOR   vars[V_FOLDER_LIST_FORE_COLOR].current_val.p
+ #define GLO_FOLDER_LIST_FORE_COLOR   vars[V_FOLDER_LIST_FORE_COLOR].global_val.p
+ #define VAR_FOLDER_LIST_BACK_COLOR   vars[V_FOLDER_LIST_BACK_COLOR].current_val.p
+ #define GLO_FOLDER_LIST_BACK_COLOR   vars[V_FOLDER_LIST_BACK_COLOR].global_val.p
  #define VAR_STATUS_FORE_COLOR	     vars[V_STATUS_FORE_COLOR].current_val.p
  #define VAR_STATUS_BACK_COLOR	     vars[V_STATUS_BACK_COLOR].current_val.p
  #define VAR_HEADER_GENERAL_FORE_COLOR vars[V_HEADER_GENERAL_FORE_COLOR].current_val.p
***************
*** 443,451 ****
--- 504,515 ----
  #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
+ #define VAR_INDEX_TOKEN_COLORS	     vars[V_INDEX_TOKEN_COLORS].current_val.l
  #ifdef SMIME
  #define VAR_PUBLICCERT_DIR	     vars[V_PUBLICCERT_DIR].current_val.p
  #define GLO_PUBLICCERT_DIR	     vars[V_PUBLICCERT_DIR].global_val.p
diff -rc alpine-2.00/pith/conftype.h alpine-2.00.I.USE/pith/conftype.h
*** alpine-2.00/pith/conftype.h	2008-08-19 17:27:11.000000000 -0700
--- alpine-2.00.I.USE/pith/conftype.h	2011-02-07 20:33:46.000000000 -0800
***************
*** 58,63 ****
--- 58,64 ----
  		, 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
***************
*** 69,74 ****
--- 70,89 ----
  		, 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
***************
*** 79,84 ****
--- 94,100 ----
  		, V_EDITOR
  		, V_SPELLER
  		, V_FILLCOL
+ 		, V_SPECIAL_TEXT
  		, V_REPLY_STRING
  		, V_REPLY_INTRO
  		, V_QUOTE_REPLACE_STRING
***************
*** 114,119 ****
--- 130,138 ----
  		, 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
***************
*** 203,208 ****
--- 222,233 ----
  		, V_TITLE_BACK_COLOR
  		, V_TITLECLOSED_FORE_COLOR
  		, V_TITLECLOSED_BACK_COLOR
+ 		, V_FOLDER_FORE_COLOR
+ 		, V_FOLDER_BACK_COLOR
+ 		, V_DIRECTORY_FORE_COLOR
+ 		, V_DIRECTORY_BACK_COLOR
+ 		, V_FOLDER_LIST_FORE_COLOR
+ 		, V_FOLDER_LIST_BACK_COLOR
  		, V_STATUS_FORE_COLOR
  		, V_STATUS_BACK_COLOR
  		, V_KEYLABEL_FORE_COLOR
***************
*** 223,228 ****
--- 248,255 ----
  		, 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
***************
*** 255,260 ****
--- 282,288 ----
  		, V_IND_FROM_BACK_COLOR
  		, V_IND_OP_FORE_COLOR
  		, V_IND_OP_BACK_COLOR
+ 		, V_INDEX_TOKEN_COLORS
  		, V_VIEW_HDR_COLORS
  		, V_KW_COLORS
  #if defined(DOS) || defined(OS2)
***************
*** 319,324 ****
--- 347,353 ----
  	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,
***************
*** 334,342 ****
--- 363,373 ----
  	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,
***************
*** 380,389 ****
--- 411,424 ----
  	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,
***************
*** 428,439 ****
--- 463,476 ----
  	F_TCAP_WINS,
  	F_ENABLE_SIGDASHES,
  	F_ENABLE_STRIP_SIGDASHES,
+ 	F_NEW_THREAD_ON_BLANK_SUBJECT,
  	F_QUELL_PARTIAL_FETCH,
  	F_QUELL_PERSONAL_NAME_PROMPT,
  	F_QUELL_USER_ID_PROMPT,
  	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,
***************
*** 492,502 ****
--- 529,541 ----
  	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,
***************
*** 514,519 ****
--- 553,559 ----
  	F_RENDER_HTML_INTERNALLY,
  	F_ENABLE_JUMP_CMD,
  	F_FORWARD_AS_ATTACHMENT,
+ 	F_PRESERVE_ORIGINAL_FIELD,
  #ifndef	_WINDOWS
  	F_USE_SYSTEM_TRANS,
  #endif	/* ! _WINDOWS */
***************
*** 703,707 ****
--- 743,748 ----
  
  /* exported protoypes */
  
+ #define DF_THREAD_SORT_KEY  "thread"
  
  #endif /* PITH_CONFTYPE_INCLUDED */
diff -rc alpine-2.00/pith/detoken.c alpine-2.00.I.USE/pith/detoken.c
*** alpine-2.00/pith/detoken.c	2007-08-14 12:02:07.000000000 -0700
--- alpine-2.00.I.USE/pith/detoken.c	2011-02-07 20:33:42.000000000 -0800
***************
*** 24,30 ****
  #include "../pith/reply.h"
  #include "../pith/mailindx.h"
  #include "../pith/options.h"
! 
  
  /*
   * Hook to read signature from local file
--- 24,30 ----
  #include "../pith/reply.h"
  #include "../pith/mailindx.h"
  #include "../pith/options.h"
! #include "../pith/rules.h"
  
  /*
   * Hook to read signature from local file
***************
*** 90,95 ****
--- 90,97 ----
  
      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,116 ****
  	 * there is no reason to mix them, so we don't provide support to
  	 * do so.
  	 */
! 	if(role && role->litsig)
! 	  literal_sig = role->litsig;
! 	else if(ps_global->VAR_LITERAL_SIG)
! 	  literal_sig = ps_global->VAR_LITERAL_SIG;
! 	else if(role && role->sig)
! 	  sigfile = role->sig;
! 	else
! 	  sigfile = ps_global->VAR_SIGNATURE_FILE;
      }
      else if(role && role->template)
        sigfile = role->template;
--- 105,129 ----
  	 * there is no reason to mix them, so we don't provide support to
  	 * do so.
  	 */
!         { RULE_RESULT *rule;
!            rule = get_result_rule(V_COMPOSE_RULES, FOR_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,307 ****
  			}
  		    }
  		}
! 		else if(pt->what_for & FOR_REPLY_INTRO)
  		  repl = get_reply_data(env, role, pt->ctype,
  					subbuf, sizeof(subbuf)-1);
  
--- 314,320 ----
  			}
  		    }
  		}
! 		else if(pt->what_for & (FOR_REPLY_INTRO | FOR_RULE))
  		  repl = get_reply_data(env, role, pt->ctype,
  					subbuf, sizeof(subbuf)-1);
  
diff -rc alpine-2.00/pith/filter.c alpine-2.00.I.USE/pith/filter.c
*** alpine-2.00/pith/filter.c	2008-08-21 16:50:47.000000000 -0700
--- alpine-2.00.I.USE/pith/filter.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 45,50 ****
--- 45,51 ----
  #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"
***************
*** 1020,1026 ****
   */
  char *
  gf_filter(char *cmd, char *prepend, STORE_S *source_so, gf_io_t pc,
! 	  FILTLIST_S *aux_filters, int disable_reset,
  	  void (*pipecb_f)(PIPE_S *, int, void *))
  {
      unsigned char c, obuf[MAX(MB_LEN_MAX,32)];
--- 1021,1027 ----
   */
  char *
  gf_filter(char *cmd, char *prepend, STORE_S *source_so, gf_io_t pc,
! 	  FILTLIST_S *aux_filters, int silent, int disable_reset,
  	  void (*pipecb_f)(PIPE_S *, int, void *))
  {
      unsigned char c, obuf[MAX(MB_LEN_MAX,32)];
***************
*** 1057,1064 ****
       * Spawn filter feeding it data, and reading what it writes.
       */
      so_seek(source_so, 0L, 0);
!     flags = PIPE_WRITE | PIPE_READ | PIPE_NOSHELL |
! 			    (!disable_reset ? PIPE_RESET : 0);
  
      if((fpipe = open_system_pipe(cmd, NULL, NULL, flags, 0, pipecb_f, pipe_report_error)) != NULL){
  
--- 1058,1066 ----
       * Spawn filter feeding it data, and reading what it writes.
       */
      so_seek(source_so, 0L, 0);
!     flags = PIPE_WRITE | PIPE_READ | PIPE_NOSHELL
! 			| (silent ? PIPE_SILENT : 0) 
! 			| (!disable_reset ? PIPE_RESET : 0);
  
      if((fpipe = open_system_pipe(cmd, NULL, NULL, flags, 0, pipecb_f, pipe_report_error)) != NULL){
  
***************
*** 1373,1386 ****
  	register unsigned char t = f->t;
  	register int n = (int) f->n;
  	register int state = f->f1;
  
  	while(GF_GETC(f, c)){
  
  	    if(state){
  		state = 0;
  		if (c != '=') {
! 		    gf_error("Illegal '=' in base64 text");
! 		    /* NO RETURN */
  		}
  	    }
  
--- 1375,1398 ----
  	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 != '=') {
! 		    f->f2++;
! 		    GF_PUTC(f->next, c);
! 		    q_status_message(SM_ORDER,3,3,
! 			_("Warning: Illegal '=' in base64 text"));
! 		    continue;
  		}
  	    }
  
***************
*** 1397,1404 ****
  			break;
  
  		      default:		/* impossible quantum position */
! 			gf_error("Internal base64 decoder error");
! 			/* NO RETURN */
  		    }
  		}
  	    }
--- 1409,1419 ----
  			break;
  
  		      default:		/* impossible quantum position */
! 			f->f2++;
! 			GF_PUTC(f->next, lastc);
! 			q_status_message(SM_ORDER,3,3,
! 			_("Warning: Internal base64 decode error"));
! 			break;
  		    }
  		}
  	    }
***************
*** 1439,1444 ****
--- 1454,1460 ----
  	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 */
      }
  }
  
***************
*** 4979,4984 ****
--- 4995,5001 ----
  	     && p->value
  	     && (HANDLES_LOC(hd->html_data)
  		 || struncmp(p->value, "x-alpine-", 9)
+ 		 || struncmp(p->value, "x-pine-help", 11)
  		 || p->value[0] == '#'))
  	    href = p;
  	  else if(!strucmp(p->attribute, "NAME"))
***************
*** 7587,7592 ****
--- 7604,7610 ----
  		char	*p, buf[MAILTMPLEN];
  		ADDRESS *adr;
  		extern char datestamp[];
+ 		extern char plevstamp[];
  
  		if(!strcmp(s = removing_quotes(s + 4), "ALPINE_VERSION")){
  		    p = ALPINE_VERSION;
***************
*** 7600,7605 ****
--- 7618,7626 ----
  		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);
  		}
***************
*** 9155,9160 ****
--- 9176,9186 ----
  		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)
***************
*** 9196,9201 ****
--- 9222,9233 ----
  #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;	\
***************
*** 9273,9278 ****
--- 9305,9312 ----
  	      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)){
***************
*** 9366,9372 ****
  
  	      case BOL :
  		if(WRAP_FLOW(f)){
! 		    if(c == '>'){
  			WRAP_FL_QC(f) = 1;		/* init it */
  			state = FL_QLEV;		/* go collect it */
  		    }
--- 9400,9410 ----
  
  	      case BOL :
  		if(WRAP_FLOW(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) = 1;		/* init it */
  			state = FL_QLEV;		/* go collect it */
  		    }
***************
*** 9380,9386 ****
  			}
  
  			/* quote level change implies new paragraph */
! 			if(WRAP_FL_QD(f)){
  			    WRAP_FL_QD(f) = 0;
  			    if(WRAP_HARD(f) == 0){
  				WRAP_HARD(f) = 1;
--- 9418,9433 ----
  			}
  
  			/* quote level change implies new paragraph */
! 			if (WRAP_CURLINE(f) > 0 
! 			&& WRAP_CURLINE(f) < WRAP_QSTRLEN(f)
! 			&& (WRAP_QSTR(f, WRAP_CURLINE(f)) != NULL
! 			     || WRAP_QSTR(f, WRAP_CURLINE(f) - 1) != NULL)
! 			&& ((WRAP_QSTR(f, WRAP_CURLINE(f)) != NULL && 
! 			     WRAP_QSTR(f, WRAP_CURLINE(f) - 1) == NULL)
! 			   || (WRAP_QSTR(f, WRAP_CURLINE(f)) == NULL && 
! 			       WRAP_QSTR(f, WRAP_CURLINE(f) - 1) != NULL)
! 			   || strcmp(WRAP_QSTR(f, WRAP_CURLINE(f)),
! 				     WRAP_QSTR(f, WRAP_CURLINE(f) - 1)))){
  			    WRAP_FL_QD(f) = 0;
  			    if(WRAP_HARD(f) == 0){
  				WRAP_HARD(f) = 1;
***************
*** 9432,9439 ****
  		break;
  
  	      case  FL_QLEV :
! 		if(c == '>'){				/* another level */
! 		    WRAP_FL_QC(f)++;
  		}
  		else {
  		    /* if EMBEDed, process it and return here */
--- 9479,9490 ----
  		break;
  
  	      case  FL_QLEV :
! 		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 */
***************
*** 9445,9451 ****
  		    }
  
  		    /* quote level change signals new paragraph */
! 		    if(WRAP_FL_QC(f) != WRAP_FL_QD(f)){
  			WRAP_FL_QD(f) = WRAP_FL_QC(f);
  			if(WRAP_HARD(f) == 0){		/* add hard newline */ 
  			    WRAP_HARD(f) = 1;		/* hard newline */
--- 9496,9511 ----
  		    }
  
  		    /* quote level change signals new paragraph */
! 		    if (WRAP_CURLINE(f) > 0 
! 			&& WRAP_CURLINE(f) < WRAP_QSTRLEN(f)
! 			&& (WRAP_QSTR(f, WRAP_CURLINE(f))
! 			     || WRAP_QSTR(f, WRAP_CURLINE(f) - 1))
! 			&& ((WRAP_QSTR(f, WRAP_CURLINE(f)) && 
! 			     !WRAP_QSTR(f, WRAP_CURLINE(f) - 1))
! 			   || (!WRAP_QSTR(f, WRAP_CURLINE(f)) && 
! 			       WRAP_QSTR(f, WRAP_CURLINE(f) - 1))
! 			   || strcmp(WRAP_QSTR(f, WRAP_CURLINE(f)),
! 				      WRAP_QSTR(f, WRAP_CURLINE(f) - 1)))){
  			WRAP_FL_QD(f) = WRAP_FL_QC(f);
  			if(WRAP_HARD(f) == 0){		/* add hard newline */ 
  			    WRAP_HARD(f) = 1;		/* hard newline */
***************
*** 9502,9507 ****
--- 9562,9574 ----
  		    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 */
***************
*** 9518,9524 ****
  					     &eob);      /* note any embedded*/
  			    wrap_eol(f, 1, &ip, &eib,
  				     &op, &eob);       /* plunk down newline */
! 			    wrap_bol(f, 1, 1, &ip, &eib,
  				     &op, &eob);         /* write any prefix */
  			}
  
--- 9585,9591 ----
  					     &eob);      /* note any embedded*/
  			    wrap_eol(f, 1, &ip, &eib,
  				     &op, &eob);       /* plunk down newline */
! 			    wrap_bol(f, 1, WRAP_FLOW(f), &ip, &eib,
  				     &op, &eob);         /* write any prefix */
  			}
  
***************
*** 10015,10021 ****
  		    wrap_flush_embed(f, &ip, &eib, &op, &eob);
  		    wrap_eol(f, 1, &ip, &eib, &op,
  			     &eob);	    /* plunk down newline */
! 		    wrap_bol(f,1,1, &ip, &eib, &op,
  			     &eob);	      /* write any prefix */
  		}
  
--- 10082,10088 ----
  		    wrap_flush_embed(f, &ip, &eib, &op, &eob);
  		    wrap_eol(f, 1, &ip, &eib, &op,
  			     &eob);	    /* plunk down newline */
! 		    wrap_bol(f,1,WRAP_FLOW(f), &ip, &eib, &op,
  			     &eob);	      /* write any prefix */
  		}
  
***************
*** 10088,10093 ****
--- 10155,10167 ----
  	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 */
***************
*** 10438,10444 ****
  {
      int j, i;
      COLOR_PAIR *col = NULL;
!     char *prefix = NULL, *last_prefix = NULL;
  
      if(ps_global->VAR_QUOTE_REPLACE_STRING){
  	get_pair(ps_global->VAR_QUOTE_REPLACE_STRING, &prefix, &last_prefix, 0, 0);
--- 10512,10519 ----
  {
      int j, i;
      COLOR_PAIR *col = NULL;
!     char *prefix = NULL, *last_prefix = NULL, *wrap_qstr = NULL;
!     int level = 0, oldj, len;
  
      if(ps_global->VAR_QUOTE_REPLACE_STRING){
  	get_pair(ps_global->VAR_QUOTE_REPLACE_STRING, &prefix, &last_prefix, 0, 0);
***************
*** 10447,10456 ****
  	    last_prefix = NULL;
  	}
      }
! 
!     for(j = 0; j < WRAP_FL_QD(f); j++){
  	if(WRAP_USE_CLR(f)){
! 	    if((j % 3) == 0
  	       && ps_global->VAR_QUOTE1_FORE_COLOR
  	       && ps_global->VAR_QUOTE1_BACK_COLOR
  	       && (col = new_color_pair(ps_global->VAR_QUOTE1_FORE_COLOR,
--- 10522,10543 ----
  	    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 = wrap_qstr && *wrap_qstr == ' ' ? 1 : 0;
! 		 j < len && isspace((unsigned char)wrap_qstr[j]); j++){
! 	GF_PUTC_GLO(f->next, wrap_qstr[j]);
!         f->n += ((wrap_qstr[j] == TAB) ? (~f->n & 0x07) + 1 : 1);
!     }
!     
!     for(; j < len && level < len; level++){
!         oldj = j;
!         j = next_level_quote(wrap_qstr, (char **)NULL, j, WRAP_FLOW(f));
  	if(WRAP_USE_CLR(f)){
! 	    if((level % 3) == 0
  	       && ps_global->VAR_QUOTE1_FORE_COLOR
  	       && ps_global->VAR_QUOTE1_BACK_COLOR
  	       && (col = new_color_pair(ps_global->VAR_QUOTE1_FORE_COLOR,
***************
*** 10458,10464 ****
  	       && pico_is_good_colorpair(col)){
                  GF_COLOR_PUTC(f, col);
              }
! 	    else if((j % 3) == 1
  		    && ps_global->VAR_QUOTE2_FORE_COLOR
  		    && ps_global->VAR_QUOTE2_BACK_COLOR
  		    && (col = new_color_pair(ps_global->VAR_QUOTE2_FORE_COLOR,
--- 10545,10551 ----
  	       && pico_is_good_colorpair(col)){
                  GF_COLOR_PUTC(f, col);
              }
! 	    else if((level % 3) == 1
  		    && ps_global->VAR_QUOTE2_FORE_COLOR
  		    && ps_global->VAR_QUOTE2_BACK_COLOR
  		    && (col = new_color_pair(ps_global->VAR_QUOTE2_FORE_COLOR,
***************
*** 10466,10472 ****
  		    && pico_is_good_colorpair(col)){
  	        GF_COLOR_PUTC(f, col);
              }
! 	    else if((j % 3) == 2
  		    && ps_global->VAR_QUOTE3_FORE_COLOR
  		    && ps_global->VAR_QUOTE3_BACK_COLOR
  		    && (col = new_color_pair(ps_global->VAR_QUOTE3_FORE_COLOR,
--- 10553,10559 ----
  		    && pico_is_good_colorpair(col)){
  	        GF_COLOR_PUTC(f, col);
              }
! 	    else if((level % 3) == 2
  		    && ps_global->VAR_QUOTE3_FORE_COLOR
  		    && ps_global->VAR_QUOTE3_BACK_COLOR
  		    && (col = new_color_pair(ps_global->VAR_QUOTE3_FORE_COLOR,
***************
*** 10480,10522 ****
  	    }
  	}
  
  	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;
  	    }
  	    else{
! 		GF_PUTC_GLO(f->next, '>');
! 		GF_PUTC_GLO(f->next, ' ');
! 		f->n += 2;
  	    }
  	}
  	else{
! 	    GF_PUTC_GLO(f->next, '>');
! 	    f->n += 1;
  	}
      }
      if(j && WRAP_LV_FLD(f)){
  	GF_PUTC_GLO(f->next, ' ');
  	f->n++;
      }
!     else if(j && last_prefix){
  	for(i = 0; last_prefix[i]; i++)
  	  GF_PUTC_GLO(f->next, last_prefix[i]);
! 	f->n += utf8_width(last_prefix);	
      }
  
      if(prefix)
        fs_give((void **)&prefix);
      if(last_prefix)
        fs_give((void **)&last_prefix);
  
      return 0;
  }
--- 10567,10626 ----
  	    }
  	}
  
+ 	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_widthis(prefix);
  	    }
  	    else{
! 	      for (i = oldj; i < j; i++)   
! 		GF_PUTC_GLO(f->next, wrap_qstr[i]);
! 	      f->n += j - oldj;
  	    }
  	}
  	else{
! 	    for (i = oldj; i < j; i++)   
! 		GF_PUTC_GLO(f->next, wrap_qstr[i]);
! 	    f->n += j - oldj;
! 	}
! 	for (i = j; isspace((unsigned char)wrap_qstr[i]); i++);
! 	if(!wrap_qstr[i]){
! 	  f->n += i - j;
! 	  for (; j < i; j++)
! 		GF_PUTC_GLO(f->next, ' '); 
! 	}
!         else{
! 	   if((WRAP_LV_FLD(f)
! 		|| !ps_global->VAR_QUOTE_REPLACE_STRING || !prefix)
! 		|| !ps_global->VAR_REPLY_STRING
! 			|| (strcmp(ps_global->VAR_REPLY_STRING, ">")
! 			  && strcmp(ps_global->VAR_REPLY_STRING, "\">\""))){
! 		  GF_PUTC_GLO(f->next, ' ');
! 		  f->n += 1;
! 	   }
  	}
+ 	for (; isspace((unsigned char)wrap_qstr[j]); j++);
      }
      if(j && WRAP_LV_FLD(f)){
  	GF_PUTC_GLO(f->next, ' ');
  	f->n++;
      }
!     else if(j && !value_is_space(wrap_qstr) && last_prefix){
  	for(i = 0; last_prefix[i]; i++)
  	  GF_PUTC_GLO(f->next, last_prefix[i]);
! 	f->n += 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;
  }
***************
*** 10548,10553 ****
--- 10652,10663 ----
      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);
  }
***************
*** 10991,10997 ****
--- 11101,11315 ----
  			    } \
  			}
  
+ #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 -rc alpine-2.00/pith/filter.h alpine-2.00.I.USE/pith/filter.h
*** alpine-2.00/pith/filter.h	2008-08-22 12:46:13.000000000 -0700
--- alpine-2.00.I.USE/pith/filter.h	2011-02-07 20:33:45.000000000 -0800
***************
*** 175,181 ****
  char	   *gf_pipe(gf_io_t, gf_io_t);
  long	    gf_bytes_piped(void);
  char	   *gf_filter(char *, char *, STORE_S *, gf_io_t, FILTLIST_S *, int,
! 		      void (*)(PIPE_S *, int, void *));
  void	    gf_binary_b64(FILTER_S *, int);
  void	    gf_b64_binary(FILTER_S *, int);
  void	    gf_qp_8bit(FILTER_S *, int);
--- 175,181 ----
  char	   *gf_pipe(gf_io_t, gf_io_t);
  long	    gf_bytes_piped(void);
  char	   *gf_filter(char *, char *, STORE_S *, gf_io_t, FILTLIST_S *, int,
! 		      int, void (*)(PIPE_S *, int, void *));
  void	    gf_binary_b64(FILTER_S *, int);
  void	    gf_b64_binary(FILTER_S *, int);
  void	    gf_qp_8bit(FILTER_S *, int);
***************
*** 215,220 ****
--- 215,221 ----
  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 -rc alpine-2.00/pith/filttype.h alpine-2.00.I.USE/pith/filttype.h
*** alpine-2.00/pith/filttype.h	2007-04-25 21:06:02.000000000 -0700
--- alpine-2.00.I.USE/pith/filttype.h	2011-02-07 20:33:42.000000000 -0800
***************
*** 35,40 ****
--- 35,42 ----
      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 -rc alpine-2.00/pith/flag.c alpine-2.00.I.USE/pith/flag.c
*** alpine-2.00/pith/flag.c	2008-07-14 11:01:54.000000000 -0700
--- alpine-2.00.I.USE/pith/flag.c	2011-02-07 20:33:41.000000000 -0800
***************
*** 593,606 ****
  
  	was_invisible = (pelt->hidden || pelt->colhid) ? 1 : 0;
  
  	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)
  		  topthrd = thrd;
  		else
! 		  topthrd = fetch_thread(stream, thrd->top);
  	    }
  
  	    if(topthrd){
--- 593,608 ----
  
  	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(top_thread(stream, thrd->top) == thrd->rawno)
  		  topthrd = thrd;
  		else
! 		  topthrd = fetch_thread(stream, top_thread(stream, thrd->top));
  	    }
  
  	    if(topthrd){
diff -rc alpine-2.00/pith/handle.h alpine-2.00.I.USE/pith/handle.h
*** alpine-2.00/pith/handle.h	2007-11-13 16:47:15.000000000 -0800
--- alpine-2.00.I.USE/pith/handle.h	2011-02-07 20:33:45.000000000 -0800
***************
*** 39,44 ****
--- 39,45 ----
      unsigned	     using_is_used:1;	/* bit below is being used     */
      unsigned	     is_used:1;		/* if not, remove it from list */
      unsigned	     color_unseen:1;	/* we're coloring folders with unseen */
+     unsigned	     color_folder:1;	/* and just folders for that matter... */
      unsigned	     is_dual_do_open:1;	/* choosing this handle means open */
      union {
  	struct {			/* URL corresponding to this handle */
diff -rc alpine-2.00/pith/imap.c alpine-2.00.I.USE/pith/imap.c
*** alpine-2.00/pith/imap.c	2008-07-14 11:01:54.000000000 -0700
--- alpine-2.00.I.USE/pith/imap.c	2011-02-07 20:33:43.000000000 -0800
***************
*** 1108,1110 ****
--- 1108,1172 ----
  
      return(block);
  }
+ 
+ 
+ void
+ pine_delete_pwd(NETMBX *mb, char *user)
+ {
+     char	hostlist0[MAILTMPLEN], hostlist1[MAILTMPLEN];
+     char	port[20], non_def_port[20], insecure[20];
+     STRLIST_S hostlist[2];
+     MMLOGIN_S  *l;
+     struct servent *sv;
+ 
+ 
+     dprint((9, "pine_delete_pwd\n"));
+ 
+ 	/* setup hostlist */
+     non_def_port[0] = '\0';
+     if(mb->port && mb->service &&
+        (sv = getservbyname(mb->service, "tcp")) &&
+        (mb->port != ntohs(sv->s_port))){
+         snprintf(non_def_port, sizeof(non_def_port), ":%lu", mb->port);
+         non_def_port[sizeof(non_def_port)-1] = '\0';
+         dprint((9, "mm_login: using non-default port=%s\n",
+                    non_def_port ? non_def_port : "?"));
+     }
+ 
+     if(*non_def_port){
+         strncpy(hostlist0, mb->host, sizeof(hostlist0)-1);
+         hostlist0[sizeof(hostlist0)-1] = '\0';
+         strncat(hostlist0, non_def_port, sizeof(hostlist0)-strlen(hostlist0)-1);
+         hostlist0[sizeof(hostlist0)-1] = '\0';
+         hostlist[0].name = hostlist0;
+         if(mb->orighost && mb->orighost[0] && strucmp(mb->host, mb->orighost)){
+             strncpy(hostlist1, mb->orighost, sizeof(hostlist1)-1);
+             hostlist1[sizeof(hostlist1)-1] = '\0';
+             strncat(hostlist1, non_def_port, sizeof(hostlist1)-strlen(hostlist1)-1);
+             hostlist1[sizeof(hostlist1)-1] = '\0';
+             hostlist[0].next = &hostlist[1];
+             hostlist[1].name = hostlist1;
+             hostlist[1].next = NULL;
+         }
+         else
+           hostlist[0].next = NULL;
+     }
+     else{
+         hostlist[0].name = mb->host;
+         if(mb->orighost && mb->orighost[0] && strucmp(mb->host, mb->orighost)){
+             hostlist[0].next = &hostlist[1];
+             hostlist[1].name = mb->orighost;
+             hostlist[1].next = NULL;
+         }
+         else
+           hostlist[0].next = NULL;
+     }
+ 
+     for(l = mm_login_list; l; l = l->next)
+       if(imap_same_host(l->hosts, hostlist)
+ 	 && !strcmp(l->user, user ? user : "")
+ 	 && l->passwd){
+ 	l->passwd[0] = '\0';
+ 	break;
+       }
+ }
diff -rc alpine-2.00/pith/imap.h alpine-2.00.I.USE/pith/imap.h
*** alpine-2.00/pith/imap.h	2008-04-23 19:00:26.000000000 -0700
--- alpine-2.00.I.USE/pith/imap.h	2011-02-07 20:33:43.000000000 -0800
***************
*** 123,129 ****
  int     imap_get_passwd(MMLOGIN_S *, char *, char *, STRLIST_S *, int);
  void    imap_set_passwd(MMLOGIN_S **, char *, char *, STRLIST_S *, int, int, int);
  void    imap_flush_passwd_cache(int);
! 
  
  /* currently mandatory to implement stubs */
  
--- 123,129 ----
  int     imap_get_passwd(MMLOGIN_S *, char *, char *, STRLIST_S *, int);
  void    imap_set_passwd(MMLOGIN_S **, char *, char *, STRLIST_S *, int, int, int);
  void    imap_flush_passwd_cache(int);
! void	pine_delete_pwd(NETMBX *mb, char *user);
  
  /* currently mandatory to implement stubs */
  
diff -rc alpine-2.00/pith/indxtype.h alpine-2.00.I.USE/pith/indxtype.h
*** alpine-2.00/pith/indxtype.h	2008-05-28 13:19:56.000000000 -0700
--- alpine-2.00.I.USE/pith/indxtype.h	2011-02-07 20:33:42.000000000 -0800
***************
*** 75,86 ****
  	      iKey, iKeyInit,
  	      iPrefDate, iPrefTime, iPrefDateTime,
  	      iCurPrefDate, iCurPrefTime, iCurPrefDateTime,
! 	      iSize, iSizeComma, iSizeNarrow, iDescripSize,
  	      iNewsAndTo, iToAndNews, iNewsAndRecips, iRecipsAndNews,
  	      iFromTo, iFromToNotNews, iFrom, iTo, iSender, iCc, iNews, iRecips,
  	      iCurNews, iArrow,
  	      iMailbox, iAddress, iInit, iCursorPos,
  	      iDay2Digit, iMon2Digit, iYear2Digit,
  	      iSTime, iKSize,
  	      iRoleNick, iNewLine,
  	      iHeader, iText,
--- 75,89 ----
  	      iKey, iKeyInit,
  	      iPrefDate, iPrefTime, iPrefDateTime,
  	      iCurPrefDate, iCurPrefTime, iCurPrefDateTime,
! 	      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,
***************
*** 102,116 ****
  
  
  /* 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 DEFAULT_REPLY_INTRO "default"
  
--- 105,130 ----
  
  
  /* these are flags for the what_for field in INDEX_PARSE_T */
! #define FOR_NOTHING	0x00000
! #define FOR_INDEX	0x00001
! #define FOR_REPLY_INTRO	0x00002
! #define FOR_TEMPLATE	0x00004  /* or for signature */
! #define FOR_FILT	0x00008
! #define DELIM_USCORE	0x00010
! #define DELIM_PAREN	0x00020
! #define 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 -rc alpine-2.00/pith/init.c alpine-2.00.I.USE/pith/init.c
*** alpine-2.00/pith/init.c	2007-08-16 15:25:10.000000000 -0700
--- alpine-2.00.I.USE/pith/init.c	2011-02-07 20:33:41.000000000 -0800
***************
*** 407,412 ****
--- 407,415 ----
             && 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 -rc alpine-2.00/pith/mailcap.c alpine-2.00.I.USE/pith/mailcap.c
*** alpine-2.00/pith/mailcap.c	2008-03-18 10:24:31.000000000 -0700
--- alpine-2.00.I.USE/pith/mailcap.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 52,57 ****
--- 52,58 ----
      int                needsterminal;
      char              *contenttype;
      char              *command;
+     char	      *nametemplate;
      char              *testcommand;
      char              *label;           /* unused */
      char              *printcommand;    /* unused */
***************
*** 212,217 ****
--- 213,221 ----
  	    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));
  	}
      }
***************
*** 487,492 ****
--- 491,501 ----
  	    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",
***************
*** 973,975 ****
--- 982,1041 ----
      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 -rc alpine-2.00/pith/mailcap.h alpine-2.00.I.USE/pith/mailcap.h
*** alpine-2.00/pith/mailcap.h	2008-03-18 10:24:31.000000000 -0700
--- alpine-2.00.I.USE/pith/mailcap.h	2011-02-07 20:33:46.000000000 -0800
***************
*** 28,33 ****
--- 28,34 ----
  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 -rc alpine-2.00/pith/mailcmd.c alpine-2.00.I.USE/pith/mailcmd.c
*** alpine-2.00/pith/mailcmd.c	2008-07-09 22:01:13.000000000 -0700
--- alpine-2.00.I.USE/pith/mailcmd.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 38,43 ****
--- 38,44 ----
  #include "../pith/ablookup.h"
  #include "../pith/search.h"
  #include "../pith/charconv/utf8.h"
+ #include "../pith/rules.h"
  
  #ifdef _WINDOWS
  #include "../pico/osdep/mswin.h"
***************
*** 659,664 ****
--- 660,666 ----
  	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! */
***************
*** 771,776 ****
--- 773,783 ----
      if(stream)
        sp_set_first_unseen(stream, 0L);
  
+     /* in case we closed the old stream by cancelling the connection, do
+      * not let that interfere with opening the new stream.
+      */
+     ps_global->user_says_cancel = 0;
+ 
      m = context_open((new_context && !open_inbox) ? new_context : NULL,
  		     stream, 
  		     open_inbox ? ps_global->VAR_INBOX_PATH : expanded_file,
***************
*** 974,979 ****
--- 981,987 ----
  
      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
***************
*** 1092,1098 ****
  
      if(!cur_already_set && mn_get_total(ps_global->msgmap) > 0L){
  
! 	perfolder_startup_rule = reset_startup_rule(ps_global->mail_stream);
  
  	if(ps_global->start_entry > 0){
  	    mn_set_cur(ps_global->msgmap, mn_get_revsort(ps_global->msgmap)
--- 1100,1109 ----
  
      if(!cur_already_set && mn_get_total(ps_global->msgmap) > 0L){
  
! 	perfolder_startup_rule = get_perfolder_startup_rule(ps_global->mail_stream,
!                                        V_STARTUP_RULES, newfolder);
! 
! 	reset_startup_rule(ps_global->mail_stream);
  
  	if(ps_global->start_entry > 0){
  	    mn_set_cur(ps_global->msgmap, mn_get_revsort(ps_global->msgmap)
***************
*** 1114,1237 ****
  	    else
  	      use_this_startup_rule = ps_global->inc_startup_rule;
  
! 	    switch(use_this_startup_rule){
! 	      /*
! 	       * For news in incoming collection we're doing the same thing
! 	       * for first-unseen and first-recent. In both those cases you
! 	       * get first-unseen if FAKE_NEW is off and first-recent if
! 	       * FAKE_NEW is on. If FAKE_NEW is on, first unseen is the
! 	       * same as first recent because all recent msgs are unseen
! 	       * and all unrecent msgs are seen (see pine_mail_open).
! 	       */
! 	      case IS_FIRST_UNSEEN:
! first_unseen:
! 		mn_set_cur(ps_global->msgmap,
! 			(sp_first_unseen(m)
! 			 && mn_get_sort(ps_global->msgmap) == SortArrival
! 			 && !mn_get_revsort(ps_global->msgmap)
! 			 && !get_lflag(ps_global->mail_stream, NULL,
! 				       sp_first_unseen(m), MN_EXLD)
! 			 && (n = mn_raw2m(ps_global->msgmap, 
! 					  sp_first_unseen(m))))
! 			   ? n
! 			   : first_sorted_flagged(F_UNSEEN | F_UNDEL, m, pc,
! 					      THREADING() ? 0 : FSF_SKIP_CHID));
! 		break;
! 
! 	      case IS_FIRST_RECENT:
! first_recent:
! 		/*
! 		 * We could really use recent for news but this is the way
! 		 * it has always worked, so we'll leave it. That is, if
! 		 * the FAKE_NEW feature is on, recent and unseen are
! 		 * equivalent, so it doesn't matter. If the feature isn't
! 		 * on, all the undeleted messages are unseen and we start
! 		 * at the first one. User controls with the FAKE_NEW feature.
! 		 */
! 		if(IS_NEWS(ps_global->mail_stream)){
! 		    mn_set_cur(ps_global->msgmap,
! 			       first_sorted_flagged(F_UNSEEN|F_UNDEL, m, pc,
! 					       THREADING() ? 0 : FSF_SKIP_CHID));
! 		}
! 		else{
! 		    mn_set_cur(ps_global->msgmap,
! 			       first_sorted_flagged(F_RECENT | F_UNSEEN
! 						    | F_UNDEL,
! 						    m, pc,
! 					      THREADING() ? 0 : FSF_SKIP_CHID));
! 		}
! 		break;
! 
! 	      case IS_FIRST_IMPORTANT:
! 		mn_set_cur(ps_global->msgmap,
! 			   first_sorted_flagged(F_FLAG|F_UNDEL, m, pc,
! 					      THREADING() ? 0 : FSF_SKIP_CHID));
! 		break;
! 
! 	      case IS_FIRST_IMPORTANT_OR_UNSEEN:
! 
! 		if(IS_NEWS(ps_global->mail_stream))
! 		  goto first_unseen;
! 
! 		{
! 		    MsgNo flagged, first_unseen;
! 
! 		    flagged = first_sorted_flagged(F_FLAG|F_UNDEL, m, pc,
! 					       THREADING() ? 0 : FSF_SKIP_CHID);
! 		    first_unseen = (sp_first_unseen(m)
! 			     && mn_get_sort(ps_global->msgmap) == SortArrival
! 			     && !mn_get_revsort(ps_global->msgmap)
! 			     && !get_lflag(ps_global->mail_stream, NULL,
! 					   sp_first_unseen(m), MN_EXLD)
! 			     && (n = mn_raw2m(ps_global->msgmap, 
! 					      sp_first_unseen(m))))
! 				? n
! 				: first_sorted_flagged(F_UNSEEN|F_UNDEL, m, pc,
! 					       THREADING() ? 0 : FSF_SKIP_CHID);
! 		    mn_set_cur(ps_global->msgmap,
! 			  (MsgNo) MIN((int) flagged, (int) first_unseen));
! 
! 		}
! 
! 		break;
! 
! 	      case IS_FIRST_IMPORTANT_OR_RECENT:
! 
! 		if(IS_NEWS(ps_global->mail_stream))
! 		  goto first_recent;
! 
! 		{
! 		    MsgNo flagged, first_recent;
! 
! 		    flagged = first_sorted_flagged(F_FLAG|F_UNDEL, m, pc,
! 					       THREADING() ? 0 : FSF_SKIP_CHID);
! 		    first_recent = first_sorted_flagged(F_RECENT | F_UNSEEN
! 							| F_UNDEL,
! 							m, pc,
! 					       THREADING() ? 0 : FSF_SKIP_CHID);
! 		    mn_set_cur(ps_global->msgmap,
! 			      (MsgNo) MIN((int) flagged, (int) first_recent));
! 		}
! 
! 		break;
! 
! 	      case IS_FIRST:
! 		mn_set_cur(ps_global->msgmap,
! 			   first_sorted_flagged(F_UNDEL, m, pc,
! 					      THREADING() ? 0 : FSF_SKIP_CHID));
! 		break;
! 
! 	      case IS_LAST:
! 		mn_set_cur(ps_global->msgmap,
! 			   first_sorted_flagged(F_UNDEL, m, pc,
! 			         FSF_LAST | (THREADING() ? 0 : FSF_SKIP_CHID)));
! 		break;
! 
! 	      default:
! 		panic("Unexpected incoming startup case");
! 		break;
! 
! 	    }
  	}
  	else if(IS_NEWS(ps_global->mail_stream)){
  	    /*
--- 1125,1131 ----
  	    else
  	      use_this_startup_rule = ps_global->inc_startup_rule;
  
! 	    find_startup_position(use_this_startup_rule, m, pc);
  	}
  	else if(IS_NEWS(ps_global->mail_stream)){
  	    /*
***************
*** 1409,1417 ****
  	    /* Save read messages? */
  	    if(VAR_READ_MESSAGE_FOLDER && VAR_READ_MESSAGE_FOLDER[0]
  	       && sp_flagged(stream, SP_INBOX)
! 	       && (seen_not_del = count_flagged(stream, F_SEEN | F_UNDEL))){
  
  		if(F_ON(F_AUTO_READ_MSGS,ps_global)
  		   || (pith_opt_read_msg_prompt
  		       && (*pith_opt_read_msg_prompt)(seen_not_del, VAR_READ_MESSAGE_FOLDER)))
  		  /* move inbox's read messages */
--- 1303,1313 ----
  	    /* Save read messages? */
  	    if(VAR_READ_MESSAGE_FOLDER && VAR_READ_MESSAGE_FOLDER[0]
  	       && sp_flagged(stream, SP_INBOX)
! 	       && (F_ON(F_AUTO_READ_MSGS_RULES, ps_global) ||
! 		  (seen_not_del = count_flagged(stream, F_SEEN | F_UNDEL)))){
  
  		if(F_ON(F_AUTO_READ_MSGS,ps_global)
+ 		   || F_ON(F_AUTO_READ_MSGS_RULES, ps_global)
  		   || (pith_opt_read_msg_prompt
  		       && (*pith_opt_read_msg_prompt)(seen_not_del, VAR_READ_MESSAGE_FOLDER)))
  		  /* move inbox's read messages */
***************
*** 1682,1687 ****
--- 1578,1586 ----
      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;
***************
*** 1721,1728 ****
  	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)
  	  strncpy(bufp = buf + 1, "Moved", MIN(5,buflen)); /* change Moving to Moved */
  
  	buf[buflen-1] = '\0';
--- 1620,1628 ----
  	snprintf(buf, buflen, "Moving %s read message%s to \"%s\"",
  		comatose(searched), plural(searched), dstfldr);
  	we_cancel = busy_cue(buf, NULL, 0);
! 	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';
***************
*** 1760,1766 ****
         && ((context_isambig(folder)
  	    && folder_is_nick(folder, FOLDERS(context), 0))
  	   || folder_index(folder, context, FI_FOLDER) > 0)
!        && (seen_undel = count_flagged(stream, F_SEEN | F_UNDEL))){
  
  	for(; f && *archive; archive++){
  	    char *p;
--- 1660,1668 ----
         && ((context_isambig(folder)
  	    && folder_is_nick(folder, FOLDERS(context), 0))
  	   || folder_index(folder, context, FI_FOLDER) > 0)
!        && ((seen_undel = count_flagged(stream, F_SEEN | F_UNDEL))
! 	   || (F_ON(F_AUTO_READ_MSGS,ps_global) &&
! 	       F_ON(F_AUTO_READ_MSGS_RULES, ps_global)))){
  
  	for(; f && *archive; archive++){
  	    char *p;
***************
*** 2158,2165 ****
  
  
  int
! agg_text_select(MAILSTREAM *stream, MSGNO_S *msgmap, char type, int not,
! 		int check_for_my_addresses,
  		char *sstring, char *charset, SEARCHSET **limitsrch)
  {
      int		 old_imap, we_cancel;
--- 2060,2067 ----
  
  
  int
! agg_text_select(MAILSTREAM *stream, MSGNO_S *msgmap, char type, char *namehdr,
! 		int not, int check_for_my_addresses,
  		char *sstring, char *charset, SEARCHSET **limitsrch)
  {
      int		 old_imap, we_cancel;
***************
*** 2308,2313 ****
--- 2210,2219 ----
  
    if(!mepgm)
      switch(type){
+       case 'h' :	                        /* Any header */
+         pgm->header = mail_newsearchheader (namehdr, sstring);
+       break;
+ 
        case 'r' :				/* TO or CC */
  	if(old_imap){
  	    /* No OR on old servers */
***************
*** 2714,2716 ****
--- 2620,2921 ----
  
      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;
+ 
+     saved_stream = stream;              /* horrible hack! */
+     if(!is_absolute_path(dstfldr)
+        && !(save_context = default_save_context(ps_global->context_list)))
+        save_context = ps_global->context_list;
+ 
+     folder_to_save = (char **)fs_get((stream->nmsgs + 1)*sizeof(char *));
+     folder_to_save[0] = NULL;
+     mn_init(&msgmap, stream->nmsgs);
+     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;
+ }
+ 
+ MAILSTREAM *
+ find_open_stream(void)
+ {
+  return saved_stream;
+ }
+ 
+ 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 -rc alpine-2.00/pith/mailcmd.h alpine-2.00.I.USE/pith/mailcmd.h
*** alpine-2.00/pith/mailcmd.h	2008-07-09 22:01:13.000000000 -0700
--- alpine-2.00.I.USE/pith/mailcmd.h	2011-02-07 20:33:44.000000000 -0800
***************
*** 41,46 ****
--- 41,48 ----
  #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
***************
*** 53,58 ****
--- 55,61 ----
  void	   bogus_utf8_command(char *, char *);
  int	   can_set_flag(struct pine *, char *, int);
  void	   cmd_cancelled(char *);
+ void	   cmd_quota(struct pine *);
  int	   cmd_delete(struct pine *, MSGNO_S *, int, char *(*)(struct pine *, MSGNO_S *));
  int	   cmd_undelete(struct pine *, MSGNO_S *, int);
  int	   cmd_expunge_work(MAILSTREAM *, MSGNO_S *);
***************
*** 61,71 ****
  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_incoming(MAILSTREAM *, CONTEXT_S *, char *, char **, char *, size_t);
  void	   cross_delete_crossposts(MAILSTREAM *);
  long	   zoom_index(struct pine *, MAILSTREAM *, MSGNO_S *, int);
  int	   unzoom_index(struct pine *, MAILSTREAM *, MSGNO_S *);
! int	   agg_text_select(MAILSTREAM *, MSGNO_S *, char, int, int, char *,
  			   char *, SEARCHSET **);
  int	   agg_flag_select(MAILSTREAM *, int, int, SEARCHSET **);
  char	  *get_uname(char *, char *, int);
--- 64,81 ----
  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);
+ MAILSTREAM *find_open_stream (void);
+ 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 *);
! int	   agg_text_select(MAILSTREAM *, MSGNO_S *, char, char *, int, int, char *,
  			   char *, SEARCHSET **);
  int	   agg_flag_select(MAILSTREAM *, int, int, SEARCHSET **);
  char	  *get_uname(char *, char *, int);
diff -rc alpine-2.00/pith/mailindx.c alpine-2.00.I.USE/pith/mailindx.c
*** alpine-2.00/pith/mailindx.c	2008-03-03 09:52:11.000000000 -0800
--- alpine-2.00.I.USE/pith/mailindx.c	2011-02-07 20:33:47.000000000 -0800
***************
*** 16,21 ****
--- 16,22 ----
  
  #include "../pith/headers.h"
  #include "../pith/mailindx.h"
+ #include "../pith/pineelt.h"
  #include "../pith/mailview.h"
  #include "../pith/flag.h"
  #include "../pith/icache.h"
***************
*** 39,44 ****
--- 40,46 ----
  #include "../pith/send.h"
  #include "../pith/options.h"
  #include "../pith/ablookup.h"
+ #include "../pith/rules.h"
  #ifdef _WINDOWS
  #include "../pico/osdep/mswin.h"
  #endif
***************
*** 103,109 ****
  void            set_print_format(IELEM_S *, int, int);
  void            set_ielem_widths_in_field(IFIELD_S *);
  
- 
  #define BIGWIDTH 2047
  
  
--- 105,110 ----
***************
*** 227,232 ****
--- 228,234 ----
  	      case iSTime:
  	      case iKSize:
  	      case iSize:
+ 	      case iSizeThread:
  	      case iPrioAlpha:
  		(*answer)[column].req_width = 7;
  		break;
***************
*** 291,296 ****
--- 293,301 ----
  	      case iSDate:
  	      case iSDateTime:
  	      case iSDateTime24:
+ 	      case iPrefDate:
+ 	      case iPrefTime:
+ 	      case iPrefDateTime:
  	        {
  		    /*
  		     * Format a date to see how long it is.
***************
*** 299,312 ****
  		     * of the translated yesterdays and friends but...
  		     */
  		    struct tm tm;
  		    char ss[100];
  
  		    memset(&tm, 0, sizeof(tm));
  		    tm.tm_year = 106;
  		    tm.tm_mon = 11;
  		    tm.tm_mday = 31;
! 		    our_strftime(ss, sizeof(ss), "%x", &tm);
! 		    (*answer)[column].req_width = MIN(MAX(9, utf8_width(ss)), 20);
  		}
  
  		(*answer)[column].monabb_width = monabb_width;
--- 304,332 ----
  		     * of the translated yesterdays and friends but...
  		     */
  		    struct tm tm;
+ 		    int len = 20;
  		    char ss[100];
  
  		    memset(&tm, 0, sizeof(tm));
  		    tm.tm_year = 106;
  		    tm.tm_mon = 11;
  		    tm.tm_mday = 31;
! 		    tm.tm_hour = 3;
! 		    tm.tm_min = 23;
! 		    tm.tm_wday = 3;
! 		    switch((*answer)[column].ctype){
! 			case iPrefTime:
! 			    our_strftime(ss, sizeof(ss), "%X", &tm);
! 			    break;
! 			case iPrefDateTime:
! 			    our_strftime(ss, sizeof(ss), "%c", &tm);
! 			    len = 32;
! 			    break;
! 			default:
! 			    our_strftime(ss, sizeof(ss), "%x", &tm);
! 			    break;
! 		    }
! 		    (*answer)[column].req_width = MIN(MAX(9, utf8_width(ss)), len);
  		}
  
  		(*answer)[column].monabb_width = monabb_width;
***************
*** 355,360 ****
--- 375,387 ----
      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)){
***************
*** 428,441 ****
  static INDEX_PARSE_T itokens[] = {
      {"STATUS",		iStatus,	FOR_INDEX},
      {"MSGNO",		iMessNo,	FOR_INDEX},
!     {"DATE",		iDate,		FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
      {"FROMORTO",	iFromTo,	FOR_INDEX},
      {"FROMORTONOTNEWS",	iFromToNotNews,	FOR_INDEX},
      {"SIZE",		iSize,		FOR_INDEX},
      {"SIZECOMMA",	iSizeComma,	FOR_INDEX},
      {"SIZENARROW",	iSizeNarrow,	FOR_INDEX},
      {"KSIZE",		iKSize,		FOR_INDEX},
!     {"SUBJECT",		iSubject,	FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
      {"FULLSTATUS",	iFStatus,	FOR_INDEX},
      {"IMAPSTATUS",	iIStatus,	FOR_INDEX},
      {"SHORTIMAPSTATUS",	iSIStatus,	FOR_INDEX},
--- 455,469 ----
  static INDEX_PARSE_T itokens[] = {
      {"STATUS",		iStatus,	FOR_INDEX},
      {"MSGNO",		iMessNo,	FOR_INDEX},
!     {"DATE",		iDate,		FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
      {"FROMORTO",	iFromTo,	FOR_INDEX},
      {"FROMORTONOTNEWS",	iFromToNotNews,	FOR_INDEX},
      {"SIZE",		iSize,		FOR_INDEX},
      {"SIZECOMMA",	iSizeComma,	FOR_INDEX},
+     {"SIZETHREAD",	iSizeThread,	FOR_INDEX},
      {"SIZENARROW",	iSizeNarrow,	FOR_INDEX},
      {"KSIZE",		iKSize,		FOR_INDEX},
!     {"SUBJECT",		iSubject,	FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_TRIM},
      {"FULLSTATUS",	iFStatus,	FOR_INDEX},
      {"IMAPSTATUS",	iIStatus,	FOR_INDEX},
      {"SHORTIMAPSTATUS",	iSIStatus,	FOR_INDEX},
***************
*** 444,498 ****
      {"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},
      {"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},
      {"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},
--- 472,529 ----
      {"SUBJECTTEXT",	iSubjectText,	FOR_INDEX},
      {"SUBJKEYTEXT",	iSubjKeyText,	FOR_INDEX},
      {"SUBJKEYINITTEXT", iSubjKeyInitText, 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|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},
***************
*** 501,559 ****
      {"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},
      {"MAILBOX",		iMailbox,	FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
      {"ROLENICK",       	iRoleNick,	FOR_REPLY_INTRO|FOR_TEMPLATE},
      {"INIT",		iInit,		FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
!     {"CURDATE",		iCurDate,	FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
!     {"CURDATEISO",	iCurDateIso,	FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
!     {"CURDATEISOS",	iCurDateIsoS,	FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
!     {"CURTIME24",	iCurTime24,	FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
!     {"CURTIME12",	iCurTime12,	FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
!     {"CURDAY",		iCurDay,	FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
!     {"CURDAY2DIGIT",	iCurDay2Digit,	FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
!     {"CURDAYOFWEEK",	iCurDayOfWeek,	FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
      {"CURDAYOFWEEKABBREV", iCurDayOfWeekAbb,
! 					FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
!     {"CURMONTH",	iCurMon,	FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
!     {"CURMONTH2DIGIT",	iCurMon2Digit,	FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
!     {"CURMONTHLONG",	iCurMonLong,	FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
!     {"CURMONTHABBREV",	iCurMonAbb,	FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
!     {"CURYEAR",		iCurYear,	FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
!     {"CURYEAR2DIGIT",	iCurYear2Digit,	FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
!     {"CURPREFDATE",	iCurPrefDate,	FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
!     {"CURPREFTIME",	iCurPrefTime,	FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT},
      {"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},
      {"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},
      {"HEADER",		iHeader,	FOR_INDEX},
      {"TEXT",		iText,		FOR_INDEX},
      {"ARROW",		iArrow,		FOR_INDEX},
      {"NEWLINE",		iNewLine,	FOR_REPLY_INTRO},
      {"CURSORPOS",	iCursorPos,	FOR_TEMPLATE},
      {NULL,		iNothing,	FOR_NOTHING}
  };
  
  INDEX_PARSE_T *
  itoken(int i)
  {
--- 532,613 ----
      {"NEWSANDRECIPS",	iNewsAndRecips,	FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
      {"MSGID",		iMsgID,		FOR_REPLY_INTRO|FOR_TEMPLATE},
      {"CURNEWS",		iCurNews,	FOR_REPLY_INTRO|FOR_TEMPLATE},
!     {"DAYDATE",		iRDate,		FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE},
!     {"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|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|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|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|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}
  };
  
+ INDEX_PARSE_T itokensinv[sizeof(itokens)/sizeof(itokens[0])];
+ 
+ void
+ inverse_itokens(void)
+ {
+     INDEX_PARSE_T *pt;
+     for (pt = itokens; pt->name; pt++)
+         itokensinv[pt->ctype].ctype = pt - itokens; 
+ 
+ }
+ 
  INDEX_PARSE_T *
  itoken(int i)
  {
***************
*** 913,919 ****
      iSDateTimeS1, iSDateTimeS2, iSDateTimeS3, iSDateTimeS4,
      iSDateTimeIso24, iSDateTimeIsoS24,
      iSDateTimeS124, iSDateTimeS224, iSDateTimeS324, iSDateTimeS424,
!     iSize, iSizeComma, iSizeNarrow, iKSize, iDescripSize,
      iPrio, iPrioBang, iPrioAlpha,
      iAtt, iTime24, iTime12, iTimezone, iMonAbb, iYear, iYear2Digit,
      iDay2Digit, iMon2Digit, iDayOfWeekAbb, iScore, iMonLong, iDayOfWeek
--- 967,973 ----
      iSDateTimeS1, iSDateTimeS2, iSDateTimeS3, iSDateTimeS4,
      iSDateTimeIso24, iSDateTimeIsoS24,
      iSDateTimeS124, iSDateTimeS224, iSDateTimeS324, iSDateTimeS424,
!     iSize, iSizeComma, iSizeNarrow, iKSize, iDescripSize, iSizeThread,
      iPrio, iPrioBang, iPrioAlpha,
      iAtt, iTime24, iTime12, iTimezone, iMonAbb, iYear, iYear2Digit,
      iDay2Digit, iMon2Digit, iDayOfWeekAbb, iScore, iMonLong, iDayOfWeek
***************
*** 1105,1110 ****
--- 1159,1165 ----
  		  case iTime12:
  		  case iSize:
  		  case iKSize:
+ 		  case iSizeThread:
  		    cdesc->actual_length = 7;
  		    cdesc->adjustment = Right;
  		    break;
***************
*** 1198,1204 ****
  	cdesc->ctype != iNothing;
  	cdesc++)
        if(cdesc->ctype == iSize || cdesc->ctype == iKSize ||
!          cdesc->ctype == iSizeNarrow ||
  	 cdesc->ctype == iSizeComma || cdesc->ctype == iDescripSize){
  	  if(cdesc->actual_length == 0){
  	      if((fix=cdesc->width) > 0){ /* had this reserved */
--- 1253,1259 ----
  	cdesc->ctype != iNothing;
  	cdesc++)
        if(cdesc->ctype == iSize || cdesc->ctype == iKSize ||
!          cdesc->ctype == iSizeNarrow  || cdesc->ctype == iSizeThread ||
  	 cdesc->ctype == iSizeComma || cdesc->ctype == iDescripSize){
  	  if(cdesc->actual_length == 0){
  	      if((fix=cdesc->width) > 0){ /* had this reserved */
***************
*** 1581,1590 ****
  
  		/* find next thread which is visible */
  		do{
  		    if(mn_get_revsort(msgmap) && thrd->prevthd)
  		      thrd = fetch_thread(stream, thrd->prevthd);
! 		    else if(!mn_get_revsort(msgmap) && thrd->nextthd)
! 		      thrd = fetch_thread(stream, thrd->nextthd);
  		    else
  		      thrd = NULL;
  		} while(thrd
--- 1636,1647 ----
  
  		/* find next thread which is visible */
  		do{
+ 		   unsigned long branch;
  		    if(mn_get_revsort(msgmap) && thrd->prevthd)
  		      thrd = fetch_thread(stream, thrd->prevthd);
! 			/*branch = get_branch(stream,thrd)*/
! 		    else if(!mn_get_revsort(msgmap) && thrd->branch)
! 		      thrd = fetch_thread(stream, thrd->branch);
  		    else
  		      thrd = NULL;
  		} while(thrd
***************
*** 1970,1975 ****
--- 2027,2033 ----
      ICE_S        *ice, **icep;
      IFIELD_S     *ifield;
      IELEM_S      *ielem;
+     COLOR_PAIR	 *color = NULL;
      struct variable *vars = ps_global->vars;
  
      dprint((8, "=== format_index_line(msgno=%ld,rawno=%ld) ===\n",
***************
*** 1995,2007 ****
       */
      ice = copy_ice(ice);
  
      /* is this a collapsed thread index line? */
!     if(!idata->bogus && THREADING()){
! 	thrd = fetch_thread(idata->stream, idata->rawno);
! 	collapsed = thrd && thrd->next
! 		    && get_lflag(idata->stream, NULL,
! 				 idata->rawno, MN_COLL);
!     }
  
      /* calculate contents of the required fields */
      for(cdesc = ps_global->index_disp_format; cdesc->ctype != iNothing; cdesc++)
--- 2053,2062 ----
       */
      ice = copy_ice(ice);
  
+     thrd = fetch_thread(idata->stream, idata->rawno);
      /* is this a collapsed thread index line? */
!     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++)
***************
*** 2433,2438 ****
--- 2488,2511 ----
  		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"
***************
*** 2499,2505 ****
--- 2572,2601 ----
  
  	        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);
***************
*** 2753,2759 ****
  		    if(first_text){
  			strncpy(str, first_text, BIGWIDTH);
  			str[BIGWIDTH] = '\0';
- 			fs_give((void **) &first_text);
  		    }
  		}
  
--- 2849,2854 ----
***************
*** 2913,2918 ****
--- 3008,3021 ----
  	  if(!ifield->ielem){
  	      ielem  = new_ielem(&ifield->ielem);
  
+ 	      if(color = hdr_color(itokens[itokensinv[cdesc->ctype].ctype].name, NULL, ps_global->index_token_colors)){
+ 		if(pico_usingcolor()){
+ 		  ielem->color = new_color_pair(color->fg, color->bg);
+ 		  ielem->type = eTypeCol;
+ 		}
+ 		free_color_pair(&color);
+ 	      }
+ 
  	      ielem->freedata = 1;
  	      ielem->data = cpystr(str);
  	      ielem->datalen = strlen(str);
***************
*** 3670,3675 ****
--- 3773,3829 ----
      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 there were no rules, we would just return the firsttext
+      * as cached in the pelt pointer, but if we are here and there
+      * is a rule, and the firsttext that is cached changes as a
+      * result of the rule, we need to refetch the text and process it
+      * again
+      */
+    
+     if(pelt && pelt->firsttextraw != NULL){
+ 	char buf[4*1024+1], ftext[6*1024+1], *rule_result;
+ 	strncpy(buf, pelt->firsttextraw, sizeof(buf));
+ 	buf[sizeof(buf)-1] = '\0';
+ 	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);
+ 	}
+ 	ftext[0] = '\0';
+ 	iutf8ncpy(ftext, buf, sizeof(ftext));
+ 	ftext[sizeof(ftext)-1] = '\0';
+ 	removing_trailing_white_space(ftext);
+ 	if(!strcmp(ftext, pelt->firsttext))	/* same as last pass */
+ 	   return(pelt->firsttext);
+ 	if(strlen(pelt->firsttextraw) > 256	/* not the same, but long enough */
+ 	    	&& utf8_width(ftext) >= 50){
+ 	  fs_give((void **)&pelt->firsttext);
+ 	  pelt->firsttext = cpystr(ftext);
+ 	  return pelt->firsttext;
+ 	}
+ 	fs_give((void **)&pelt->firsttext);	/* do it again */
+     }
  
  try_again:
  
***************
*** 3706,3712 ****
  		&& ALLOWED_SUBTYPE(subtype))){
  
  		if((so = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){
! 		    char buf[1025], *p;
  		    unsigned char c;
  		    int success;
  		    int one_space_done = 0;
--- 3860,3866 ----
  		&& ALLOWED_SUBTYPE(subtype))){
  
  		if((so = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){
! 		    char buf[4*1024+1], rawbuf[6*1024+1], *p;
  		    unsigned char c;
  		    int success;
  		    int one_space_done = 0;
***************
*** 3763,3769 ****
--- 3917,3939 ----
  
  			if(p > buf){
  			    size_t l;
+ 			    ENVELOPE *env;
+ 			    char *rule_result;
  
+ 			    if(pelt && pelt->firsttextraw)
+ 				fs_give((void **)&pelt->firsttextraw);
+ 			    iutf8ncpy(rawbuf, buf, sizeof(rawbuf));
+ 			    rawbuf[sizeof(rawbuf)-1] = '\0';
+ 			    removing_trailing_white_space(rawbuf);
+ 			    pelt->firsttextraw = cpystr(rawbuf);
+ 			    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));
***************
*** 3787,3792 ****
--- 3957,3964 ----
  			    goto try_again;
  			}
  		    }
+ 		    if(mc && pelt)
+ 			pelt->firsttext = firsttext;
  		}
  	    }	
  	}
***************
*** 4271,4276 ****
--- 4443,4449 ----
  	    tm.tm_mday = MIN(MAX(d.day, 1), 31);
  	    tm.tm_hour = MIN(MAX(d.hour, 0), 23);
  	    tm.tm_min  = MIN(MAX(d.minute, 0), 59);
+             tm.tm_wday = MIN(MAX(d.wkday, 0), 6);
  	    tmptr = &tm;
  	}
  
***************
*** 5226,5235 ****
  {
      char          *subject, *origsubj, *origstr, *rawsubj, *sptr = NULL;
      char          *p, *border, *q = NULL, *free_subj = NULL;
!     char	  *sp;
      size_t         len;
      int            width = -1;
!     int            depth = 0, mult = 2;
      int            save;
      int            do_subj = 0, truncated_tree = 0;
      PINETHRD_S    *thd, *thdorig;
--- 5399,5408 ----
  {
      char          *subject, *origsubj, *origstr, *rawsubj, *sptr = NULL;
      char          *p, *border, *q = NULL, *free_subj = NULL;
!     char	  *sp, *rule_result;
      size_t         len;
      int            width = -1;
!     int            depth = 0, mult = 2, collapsed, i, we_clear = 0;
      int            save;
      int            do_subj = 0, truncated_tree = 0;
      PINETHRD_S    *thd, *thdorig;
***************
*** 5283,5289 ****
       * origsubj is the original subject but it has been decoded. We need
       * to free it at the end of this routine.
       */
! 
  
      /*
       * prepend_keyword will put the keyword stuff before the subject
--- 5456,5468 ----
       * 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
***************
*** 5371,5380 ****
  
  	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));
  
  	/*
  	 * width is < available strsize and
--- 5550,5557 ----
  
  	if(pith_opt_condense_thread_cue)
  	  width = (*pith_opt_condense_thread_cue)(thd, ice, &str, &strsize, width,
! 	   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
***************
*** 5724,5729 ****
--- 5901,5909 ----
  
      if(free_subj)
        fs_give((void **) &free_subj);
+ 
+     if (we_clear && origsubj)
+       fs_give((void **)&origsubj);
  }
  
  
***************
*** 6002,6012 ****
  	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));
! 
  	fptr = str;
  
  	if(thd)
--- 6182,6189 ----
  	border = str + width;
  	if(pith_opt_condense_thread_cue)
  	  width = (*pith_opt_condense_thread_cue)(thd, ice, &str, &strsize, width,
! 	   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)
***************
*** 6092,6107 ****
  				 ? "To"
  				 : (addr = fetch_cc(idata))
  				 ? "Cc"
! 				 : NULL))
! 		       && set_index_addr(idata, field, addr, "To: ",
! 					 strsize-1, fptr))
! 		      break;
  
  		    if(ctype == iFromTo &&
  		       (newsgroups = fetch_newsgroups(idata)) &&
  		       *newsgroups){
! 			snprintf(fptr, strsize, "To: %-*.*s", strsize-1-4, strsize-1-4,
! 				newsgroups);
  			break;
  		    }
  
--- 6269,6301 ----
  				 ? "To"
  				 : (addr = fetch_cc(idata))
  				 ? "Cc"
! 				 : 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){
! 			   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;
  		    }
  
***************
*** 6114,6120 ****
  	      break;
  
  	  case iFrom:
! 	    set_index_addr(idata, "From", fetch_from(idata), NULL, strsize-1, fptr);
  	    break;
  
  	  case iAddress:
--- 6308,6322 ----
  	      break;
  
  	  case iFrom:
! 	   { 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:
***************
*** 6411,6413 ****
--- 6613,6676 ----
  	}
      }
  }
+ 
+ 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 -rc alpine-2.00/pith/mailindx.h alpine-2.00.I.USE/pith/mailindx.h
*** alpine-2.00/pith/mailindx.h	2008-02-01 10:42:29.000000000 -0800
--- alpine-2.00.I.USE/pith/mailindx.h	2011-02-07 20:33:45.000000000 -0800
***************
*** 29,34 ****
--- 29,37 ----
  
  
  /* 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 *);
***************
*** 36,41 ****
--- 39,45 ----
  void	       free_index_format(INDEX_COL_S **);
  void	       reset_index_format(void);
  INDEX_PARSE_T *itoktype(char *, int);
+ void 	       inverse_itokens(void);
  char	      *prepend_keyword_subject(MAILSTREAM *, long, char *, SubjKW, IELEM_S **, char *);
  int	       get_index_line_color(MAILSTREAM *, SEARCHSET *, PAT_STATE **, COLOR_PAIR **);
  void	       setup_for_index_index_screen(void);
diff -rc alpine-2.00/pith/mailview.c alpine-2.00.I.USE/pith/mailview.c
*** alpine-2.00/pith/mailview.c	2008-07-11 16:20:32.000000000 -0700
--- alpine-2.00.I.USE/pith/mailview.c	2011-02-07 20:33:45.000000000 -0800
***************
*** 51,57 ****
  #include "../pith/escapes.h"
  #include "../pith/keyword.h"
  #include "../pith/smime.h"
! 
  
  #define FBUF_LEN	(50)
  
--- 51,60 ----
  #include "../pith/escapes.h"
  #include "../pith/keyword.h"
  #include "../pith/smime.h"
! #include "../pith/osdep/color.h"
! #include "../pico/estruct.h"
! #include "../pico/pico.h"
! #include "../pico/efunc.h"
  
  #define FBUF_LEN	(50)
  
***************
*** 281,289 ****
  	    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));
  	    }
  
  	    if((flgs & FM_DISPLAY)
--- 284,300 ----
  	    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_quote_test, gf_line_test_opt(color_signature, &is_in_sig));
  	    }
  
  	    if((flgs & FM_DISPLAY)
***************
*** 291,298 ****
  	       && 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));
  	    }
  
  	    if(!(flgs & FM_NOWRAP)){
  		wrapflags = (flgs & FM_DISPLAY) ? (GFW_HANDLES|GFW_SOFTHYPHEN) : GFW_NONE;
--- 302,311 ----
  	       && pico_usingcolor()
  	       && ps_global->VAR_QUOTE1_FORE_COLOR
  	       && ps_global->VAR_QUOTE1_BACK_COLOR){
! 		gf_link_filter(gf_quote_test, gf_line_test_opt(color_a_quote, NULL));
  	    }
+ 	    else
+ 		gf_link_filter(gf_quote_test,gf_line_test_opt(select_quote, NULL));
  
  	    if(!(flgs & FM_NOWRAP)){
  		wrapflags = (flgs & FM_DISPLAY) ? (GFW_HANDLES|GFW_SOFTHYPHEN) : GFW_NONE;
***************
*** 1096,1122 ****
  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;
      COLOR_PAIR      *col = NULL;
  
      if(is_in_sig == NULL)
        return 0;
  
      in_sig_block = (int *) is_in_sig;
      
!     if(!strcmp(line, SIGDASHES))
!       *in_sig_block = START_SIG_BLOCK; 
!     else if(*line == '\0')
        /* 
         * Suggested by Eduardo: allow for a blank line right after 
         * the sigdashes. 
         */
        *in_sig_block = (*in_sig_block == START_SIG_BLOCK)
  			  ? IN_SIG_BLOCK : OUT_SIG_BLOCK;
      else
        *in_sig_block = (*in_sig_block != OUT_SIG_BLOCK)
  			  ? IN_SIG_BLOCK : OUT_SIG_BLOCK;
  
      if(*in_sig_block != OUT_SIG_BLOCK
         && VAR_SIGNATURE_FORE_COLOR && VAR_SIGNATURE_BACK_COLOR
         && (col = new_color_pair(VAR_SIGNATURE_FORE_COLOR,
--- 1109,1197 ----
  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, 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;
+     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';
+ 
+     plb = line_isblank((ps_global->prefix && *ps_global->prefix 
+ 			? ps_global->prefix : ">"), PLine, GLine, PPLine, NSTRING);
+     qs = do_quote_match((ps_global->prefix && *ps_global->prefix 
+ 			? ps_global->prefix : ">"),
+                        GLine, NLine, PLine, rqstr, NSTRING, plb);
+     if(linenum > 0)
+        strncpy(PPLine, PLine, NSTRING);
+     strncpy(buf2, rqstr, NSTRING);
+     i = buf2 && buf2[0] ? strlen(buf2) : 0;
+     free_qs(&qs);
+ 
+     /* determine if buf and buf2 are the same quote string */
+     if (!struncmp(buf, buf2, qstrlen)){
+       for (j = qstrlen; buf2[j] && isspace((unsigned char)buf2[j]); j++);
+       if (!buf2[j] || buf2[j] == '|' || (buf2[j] == '*' && buf2[j+1] != '>'))
+          same_qstr++;
+     }
+ 
      in_sig_block = (int *) is_in_sig;
      
!     if (*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,
***************
*** 1480,1497 ****
      return(0);
  }
  
  
  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	   buf[256], color[256];
      HANDLE_S	  *h;
      URL_HILITE_S  *uh;
  
!     for(lp = 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);
--- 1555,1632 ----
      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;
!     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;
  
!     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);
***************
*** 1501,1506 ****
--- 1636,1645 ----
  	  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)
***************
*** 1509,1515 ****
--- 1648,1663 ----
  	      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){
***************
*** 1526,1561 ****
  
  	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",
  		weburlp ? "http://" : (mailurlp ? "mailto:" : ""), n, up);
! 	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);
  	else if(F_OFF(F_SLCTBL_ITEM_NOBOLD, ps_global))
! 	  ins = gf_line_test_new_ins(ins, up, 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);
  
  	/* in case it was the current selection */
! 	ins = gf_line_test_new_ins(ins, up + n, 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);
  	else
! 	  ins = gf_line_test_new_ins(ins, up + n, url_embed(TAG_BOLDOFF), 2);
  
  	urlp = weburlp = mailurlp = NULL;
      }
  
      return(0);
  }
  
--- 1674,1731 ----
  
  	uh = (URL_HILITE_S *) local;
  
! 	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';
! 	}
  
  	if(handle_start_color(color, sizeof(color), &l, uh->hdr_color))
! 	  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, 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, begin_line, buf, (int) buf[2] + 3);
  
  	/* in case it was the current selection */
! 	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, end_line, color, l);
  	else
! 	  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);
  }
  
***************
*** 1676,1681 ****
--- 1846,1922 ----
  }
  
  
+ /* 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';
+ 
+ 
+      plb = line_isblank((ps_global->prefix && *ps_global->prefix 
+ 		? ps_global->prefix : ">"), PLine, GLine, PPLine, NSTRING);
+ 
+      qs = do_quote_match((ps_global->prefix && *ps_global->prefix 
+ 		? ps_global->prefix : ">"), GLine, NLine, PLine, 
+ 							rqstr, NSTRING, plb);
+      if (raw)
+         strncpy(buf, rqstr, NSTRING);
+      else
+         flatten_qstring(qs, buf, NSTRING);
+      free_qs(&qs);
+ 
+      /* do not paint an extra level for a line with a >From string at the
+       * begining of it
+       */
+      if (buf[0]){
+        i = strlen(buf);
+        if (strlen(line) >= i + 6 && !strncmp(line+i-1,">From ", 6))
+            buf[i - 1] = '\0';
+      }
+      strncpy(tmp_20k_buf, buf, buflen);
+      if (linenum > 0)
+        strncpy((who ? PPLine1 : PPLine2), PLine, buflen);
+      strncpy((who ? GLine1 : GLine2), GLine, buflen);
+      strncpy((who ? PLine1 : PLine2), PLine, buflen);
+      return 1;
+ }
+ 
  
  #define	UES_LEN	12
  #define	UES_MAX	32
***************
*** 2377,2384 ****
        format_addr_string(s, n, sect, "Return-Path: ", e->return_path,
  			 flags, oacs, pc);
  
!     if((which & FE_NEWSGROUPS) && e->newsgroups)
        format_newsgroup_string("Newsgroups: ", e->newsgroups, flags, pc);
  
      if((which & FE_FOLLOWUPTO) && e->followup_to)
        format_newsgroup_string("Followup-To: ", e->followup_to, flags, pc);
--- 2618,2638 ----
        format_addr_string(s, n, sect, "Return-Path: ", e->return_path,
  			 flags, oacs, pc);
  
!     if((which & FE_NEWSGROUPS) && e->newsgroups){
! 	int bogus = NIL;
        format_newsgroup_string("Newsgroups: ", e->newsgroups, flags, pc);
+       if (!e->ngpathexists && e->message_id &&
+        strncmp (e->message_id,"<alpine.",8) &&
+        strncmp (e->message_id,"<Pine.",6) &&
+        strncmp (e->message_id,"<MS-C.",6) &&
+        strncmp (e->message_id,"<MailManager.",13) &&
+        strncmp (e->message_id,"<EasyMail.",11) &&
+        strncmp (e->message_id,"<ML-",4)) bogus = T;
+ 
+ 	if(bogus)
+ 	  q_status_message(SM_ORDER, 0, 3,
+      "Unverified Newsgroup header -- Message MAY or MAY NOT have been posted");
+     }
  
      if((which & FE_FOLLOWUPTO) && e->followup_to)
        format_newsgroup_string("Followup-To: ", e->followup_to, flags, pc);
***************
*** 2488,2493 ****
--- 2742,2962 ----
      return(color_pair);
  }
  
+ void
+ interval_free(ival)
+   IVAL_S **ival;
+ {
+   if (!(*ival))
+     return;
+ 
+   if ((*ival)->next)
+     interval_free(&((*ival)->next));
+ 
+   fs_give((void **)(ival));
+ }
+ 
+ IVAL_S *
+ compute_interval (string, endm)
+  char *string;
+  int endm;
+ {
+   IVAL_S *ival = NULL, *nextival= NULL, *d;
+   regmatch_t pmatch;
+ 
+   if(ps_global->paterror == 0)
+     if (regexec(&ps_global->colorpat, string, 1, &pmatch, 0) == 0){
+        ival = (IVAL_S *) fs_get(sizeof(IVAL_S));
+        memset (ival, 0, sizeof(IVAL_S));
+        ival->start = endm + pmatch.rm_so;
+        ival->end   = endm + pmatch.rm_eo;
+        nextival = compute_interval(string+pmatch.rm_so+1, ival->start+1);
+        if (nextival){
+ 	   if (nextival->start <= ival->end){
+ 	      ival->end  = nextival->end;
+ 	      d = nextival->next;
+ 	      nextival->next = NULL;
+ 	      ival->next = d;
+ 	      interval_free(&nextival);
+ 	   }
+ 	   else
+ 	      ival->next = nextival;
+        }
+     }
+   return ival;
+ }
+ 
+ void
+ regex_pattern(plist)
+   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(ins, p, ival, last_end, col)
+     LT_INS_S **ins;
+     char **p;
+     IVAL_S *ival;
+     int last_end;
+     COLOR_PAIR *col;
+ {
+    struct variable *vars = ps_global->vars;
+ 
+    if (ival){
+       *p += ival->start - last_end;
+       ins = gf_line_test_new_ins(ins, *p,  color_embed(col->fg, col->bg),
+ 				   (2 * RGBLEN) + 4);
+       *p += ival->end - ival->start;
+       ins = gf_line_test_new_ins(ins, *p, color_embed(VAR_NORM_FORE_COLOR,
+ 		      VAR_NORM_BACK_COLOR), (2 * RGBLEN) + 4);
+       ins = insert_color_special_text(ins, p, ival->next, ival->end, col);
+    }
+    return ins;
+ }  
+ 
+ int
+ length_color(p, begin_color)
+   char *p;
+   int  begin_color;
+ {
+   int len = 0, done = begin_color ? 0 : -1;
+   char *orig = p;
+ 
+   while (*p  && done <= 0){
+         switch(*p++){
+            case TAG_HANDLE :
+              p += *p + 1; 
+ 	     done++;
+            break;
+ 
+            case TAG_FGCOLOR :
+            case TAG_BGCOLOR :
+              p += RGBLEN;
+ 	     if (!begin_color)
+ 		done++;  
+            break;
+ 
+            default :
+              break;
+         }
+    }
+    len = p - orig;
+    return len;
+ }
+ 
+ int
+ any_color_in_string(p)
+   char *p;
+ {
+    int rv = 0;
+    char *orig = p;
+    while (*p && !rv)
+       if (*p++ == TAG_EMBED)
+ 	rv = p - orig;
+    return rv;
+ }
+ 
+ void
+ remove_spaces_ival(ivalp, p)
+   IVAL_S **ivalp;
+   char *p;
+ {
+     IVAL_S *ival;
+     int i;
+     if (!ivalp || !*ivalp)
+     return;
+     ival = *ivalp;
+     for (i = 0; isspace((unsigned char) p[ival->start + i]); i++);
+     if (ival->start + i < ival->end)  /* do not do this if match only spaces */
+       ival->start += i;
+     else
+       return;
+     for (i = 0; isspace((unsigned char) p[ival->end - i - 1]); i++);
+      ival->end -= i;
+     if (ival->next)
+ 	remove_spaces_ival(&(ival->next), p);
+ }
+ 
+ int
+ color_this_text(linenum, line, ins, local)
+     long       linenum;
+     char      *line;
+     LT_INS_S **ins;
+     void      *local;
+ {
+     struct variable *vars = ps_global->vars;
+     COLOR_PAIR *col = NULL;
+     char *p;
+     int i = 0;
+     static char *pattern = NULL;
+ /*  char *buf;
+ 
+     select_quote(linenum, line, ins, (void *)code);
+     for (i = 0; tmp_20k_buf[i] && (buf[i] = tmp_20k_buf[i]); i++);
+     buf[i] = '\0'; */
+     p = line + 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 -rc alpine-2.00/pith/mailview.h alpine-2.00.I.USE/pith/mailview.h
*** alpine-2.00/pith/mailview.h	2008-06-03 08:54:15.000000000 -0700
--- alpine-2.00.I.USE/pith/mailview.h	2011-02-07 20:33:43.000000000 -0800
***************
*** 29,34 ****
--- 29,40 ----
  #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 */
***************
*** 125,130 ****
--- 131,145 ----
  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
***************
*** 141,146 ****
--- 156,162 ----
  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 -rc alpine-2.00/pith/Makefile.am alpine-2.00.I.USE/pith/Makefile.am
*** alpine-2.00/pith/Makefile.am	2008-06-03 08:54:15.000000000 -0700
--- alpine-2.00.I.USE/pith/Makefile.am	2011-02-07 20:33:42.000000000 -0800
***************
*** 25,31 ****
  	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 \
  	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
  
--- 25,31 ----
  	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 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 -rc alpine-2.00/pith/Makefile.in alpine-2.00.I.USE/pith/Makefile.in
*** alpine-2.00/pith/Makefile.in	2008-06-03 08:54:15.000000000 -0700
--- alpine-2.00.I.USE/pith/Makefile.in	2011-02-07 20:33:42.000000000 -0800
***************
*** 77,83 ****
  	margin.$(OBJEXT) mimedesc.$(OBJEXT) mimetype.$(OBJEXT) \
  	msgno.$(OBJEXT) newmail.$(OBJEXT) news.$(OBJEXT) \
  	pattern.$(OBJEXT) pipe.$(OBJEXT) readfile.$(OBJEXT) \
! 	remote.$(OBJEXT) reply.$(OBJEXT) rfc2231.$(OBJEXT) \
  	save.$(OBJEXT) search.$(OBJEXT) sequence.$(OBJEXT) \
  	send.$(OBJEXT) sort.$(OBJEXT) state.$(OBJEXT) status.$(OBJEXT) \
  	store.$(OBJEXT) stream.$(OBJEXT) string.$(OBJEXT) \
--- 77,83 ----
  	margin.$(OBJEXT) mimedesc.$(OBJEXT) mimetype.$(OBJEXT) \
  	msgno.$(OBJEXT) newmail.$(OBJEXT) news.$(OBJEXT) \
  	pattern.$(OBJEXT) pipe.$(OBJEXT) readfile.$(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) \
***************
*** 275,281 ****
  	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 \
  	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
  
--- 275,281 ----
  	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 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
  
***************
*** 404,409 ****
--- 404,410 ----
  @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 -rc alpine-2.00/pith/makefile.wnt alpine-2.00.I.USE/pith/makefile.wnt
*** alpine-2.00/pith/makefile.wnt	2007-10-24 14:58:00.000000000 -0700
--- alpine-2.00.I.USE/pith/makefile.wnt	2011-02-07 20:33:42.000000000 -0800
***************
*** 44,50 ****
  	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 \
  	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
  
--- 44,50 ----
  	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 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,59 ****
  	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 \
  	status.obj store.obj stream.obj string.obj strlst.obj takeaddr.obj tempfile.obj text.obj \
  	thread.obj adjtime.obj url.obj util.obj
  
--- 53,59 ----
  	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 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 -rc alpine-2.00/pith/mimetype.c alpine-2.00.I.USE/pith/mimetype.c
*** alpine-2.00/pith/mimetype.c	2008-03-06 12:54:01.000000000 -0800
--- alpine-2.00.I.USE/pith/mimetype.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 178,183 ****
--- 178,212 ----
  	  panic("Unhandled mime type search");
      }
  
+     /* if we still can not find the type, but it is a .docx (or alike) extension
+ 	set the type here. Do not use the grope function.
+      */
+     if(rv == 0){
+ 	rv = 1;	/* assume success */
+ 	mt_map->to.mime.type = TYPEAPPLICATION;
+ 	if(!strucmp(mt_map->from.ext, "docx"))
+ 	    mt_map->to.mime.subtype = cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.WORDPROCESSINGML.DOCUMENT");
+ 	else if(!strucmp(mt_map->from.ext, "xslx"))
+ 	    mt_map->to.mime.subtype = cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.SPREADSHEETML.SHEET");
+ 	else if(!strucmp(mt_map->from.ext, "xltx"))
+ 	    mt_map->to.mime.subtype = cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.SPREADSHEETML.TEMPLATE");
+ 	else if(!strucmp(mt_map->from.ext, "potx"))
+ 	    mt_map->to.mime.subtype = cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.PRESENTATIONML.TEMPLATE");
+ 	else if(!strucmp(mt_map->from.ext, "ppsx"))
+ 	    mt_map->to.mime.subtype = cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.PRESENTATIONML.SLIDESHOW");
+ 	else if(!strucmp(mt_map->from.ext, "pptx"))
+ 	    mt_map->to.mime.subtype = cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.PRESENTATIONML.PRESENTATION");
+ 	else if(!strucmp(mt_map->from.ext, "sldx"))
+ 	    mt_map->to.mime.subtype = cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.PRESENTATIONML.SLIDE");
+ 	else if(!strucmp(mt_map->from.ext, "dotx"))
+ 	    mt_map->to.mime.subtype = cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.WORDPROCESSINGML.TEMPLATE");
+ 	else if(!strucmp(mt_map->from.ext, "xlam"))
+ 	    mt_map->to.mime.subtype = cpystr("VND.MS-EXCEL.ADDIN.MACROENABLED.12");
+ 	else if(!strucmp(mt_map->from.ext, "xslb"))
+ 	    mt_map->to.mime.subtype = cpystr("VND.MS-EXCEL.SHEET.BINARY.MACROENABLED.12");
+ 	else rv = 0;	/* else, failure */
+     }
+ 
  
      return(rv);
  }
diff -rc alpine-2.00/pith/msgno.c alpine-2.00.I.USE/pith/msgno.c
*** alpine-2.00/pith/msgno.c	2007-12-03 16:13:55.000000000 -0800
--- alpine-2.00.I.USE/pith/msgno.c	2011-02-07 20:33:47.000000000 -0800
***************
*** 932,937 ****
--- 932,943 ----
  	if((*peltp)->pthrd)
  	  fs_give((void **) &(*peltp)->pthrd);
  
+ 	if((*peltp)->firsttext)
+ 	  fs_give((void **) &(*peltp)->firsttext);
+ 
+ 	if((*peltp)->firsttextraw)
+ 	  fs_give((void **) &(*peltp)->firsttextraw);
+ 
  	if((*peltp)->ice)
  	  free_ice(&(*peltp)->ice);
  
diff -rc alpine-2.00/pith/newmail.c alpine-2.00.I.USE/pith/newmail.c
*** alpine-2.00/pith/newmail.c	2008-07-14 11:01:54.000000000 -0700
--- alpine-2.00.I.USE/pith/newmail.c	2011-02-07 20:33:47.000000000 -0800
***************
*** 684,692 ****
      if(!for_new_mail_win)
        q_status_message5(SM_ASYNC | SM_DING, 0, 60,
  		      "%s%s%s%.80s%.80s", intro,
!  		      from ? ((number > 1L) ? " Most recent f" : " F") : "",
!  		      from ? "rom " : "",
!  		      from ? from : "",
  		      subjtext);
  #if (!defined(DOS) && !defined(OS2) && !defined(LEAVEOUTFIFO)) || defined(_WINDOWS)
      else {
--- 684,692 ----
      if(!for_new_mail_win)
        q_status_message5(SM_ASYNC | SM_DING, 0, 60,
  		      "%s%s%s%.80s%.80s", intro,
!  		      from && from[0] ? ((number > 1L) ? " Most recent f" : " F") : "",
!  		      from && from[0] ? "rom " : "",
!  		      from && from[0] ? from : "",
  		      subjtext);
  #if (!defined(DOS) && !defined(OS2) && !defined(LEAVEOUTFIFO)) || defined(_WINDOWS)
      else {
***************
*** 724,732 ****
  	}
  	else
  	  snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s%.80s", intro,
! 		   from ? ((number > 1L) ? " Most recent f" : " F") : "",
! 		   from ? "rom " : "",
! 		   from ? from : "");
  
  	(*pith_opt_icon_text)(tmp_20k_buf, IT_NEWMAIL);
      }
--- 724,732 ----
  	}
  	else
  	  snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s%.80s", intro,
! 		   from && from[0] ? ((number > 1L) ? " Most recent f" : " F") : "",
! 		   from && from[0] ? "rom " : "",
! 		   from && from[0] ? from : "");
  
  	(*pith_opt_icon_text)(tmp_20k_buf, IT_NEWMAIL);
      }
diff -rc alpine-2.00/pith/osdep/color.c alpine-2.00.I.USE/pith/osdep/color.c
*** alpine-2.00/pith/osdep/color.c	2006-09-26 12:30:49.000000000 -0700
--- alpine-2.00.I.USE/pith/osdep/color.c	2011-02-07 20:33:42.000000000 -0800
***************
*** 31,37 ****
  
  #include <system.h>
  #include "./color.h"
! 
  
  
  /*
--- 31,37 ----
  
  #include <system.h>
  #include "./color.h"
! #include "./collate.h"
  
  
  /*
***************
*** 91,93 ****
--- 91,1278 ----
  {
      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. This 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      advance_quote_string(char *, char *, int);
+ int	 isaword(char *,int ,int);
+ int	 isamailbox(char *,int ,int);
+ 
+ 
+ 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(qs, word, typeqs, beginw, endw, offset, neednext)
+    char *qs;
+    char word[NSTRING];
+    QStrType   typeqs;
+    int beginw, endw, offset, 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(cl)
+   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(cl)
+   QSTRING_S *cl;
+ {
+ 
+   if (!cl)            /* nothing in, nothing out */
+      return cl;
+ 
+   if (cl->qstype != qsNormal)
+      free_qs(&cl);
+ 
+   if (cl)
+      cl->next = qs_normal_part(cl->next);
+ 
+   return cl;
+ }
+ 
+ /*
+  * this function removes trailing spaces from a quote string, but leaves the
+  * last one if there are trailing spaces
+  */ 
+ QSTRING_S *
+ qs_remove_trailing_spaces(cl)
+     QSTRING_S *cl;
+ {
+   QSTRING_S *rl = cl;
+   if (!cl)            /* nothing in, nothing out */
+      return cl;
+ 
+   if (cl->next)
+      cl->next = qs_remove_trailing_spaces(cl->next);
+   else{
+     if (value_is_space(cl->value))
+        free_qs(&cl);
+     else{
+        int i, l;
+        i = l = strlen(cl->value) - 1;
+        while (cl->value && cl->value[i]
+         && ISspace(cl->value[i]))
+            i--;
+         i += (i < l) ? 2 : 1;
+         cl->value[i] = '\0';
+     }
+   }
+   return cl;
+ }
+ 
+ /*
+  * 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(cl)
+   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 reaelly don't have enough evidence to return anything,
+ 	 * different from the normal part of cl, but it could be possible
+ 	 * that we may want to accept the not-normal part, so we better
+ 	 * make an extra test to determine what needs to be freed
+ 	 */
+ 	  while (pl && cl && 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';
+ }
+ 
+ /*
+  * 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 || !word[0])
+       return (QSTRING_S *) NULL;
+ 
+    while (!finished){
+        /*
+         * Before we apply our rules, let's advance past the quote string
+         * given by the user, this will avoid not recognition of the
+         * user's indent string and application of the arbitrary rules
+         * below. Notice that this step may bring bugs into this
+         * procedure, but these bugs will only appear if the indent string
+         * is really really strange and the text to be justified
+         * cooperates a lot too, so in general this will not be a problem.
+         * If you are concerned about this bug, simply remove the
+         * following lines after this comment and before the "switch"
+         * command below and use a more normal quote string!.
+         */
+        i += advance_quote_string(qs, word, i);
+        if (!word[i]) /* went too far? */
+           return qs_add(qs, word, qsNormal, 0, i, 0, 0);
+ 
+       switch (c = (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(word,i,j)
+  char word[NSTRING];
+  int i;
+  int j;
+ {
+   return i <= j && is_cletter(word[i]) ?
+           (i < j ? isaword(word,i+1,j) : 1) : 0;
+ }
+ 
+ int
+ isamailbox(word,i,j)
+ char word[NSTRING];
+ int i, 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(cl)
+   QSTRING_S *cl;
+ {
+      QSTRING_S *np = cl;
+      QSTRING_S *cp = np;               /* this variable trails cl */
+ 
+      while(1){
+         while (cl && cl->qstype == qsNormal)
+             cl = cl->next;
+ 
+         if (cl){
+          if (((cl->qstype == qsWord) || (cl->qstype == qsChar))
+                && !exists_good_part(cl)){
+              if (np == cl)     /* qsword or qschar at the beginning */
+                 free_qs(&cp);
+              else{
+                 while (np->next != cl)
+                     np = np->next;
+                 free_qs(&(np->next));
+             }
+             break;
+          }
+          else
+             cl = cl->next;
+         }
+         else
+          break;
+     }
+     return cp;
+ }
+ 
+ int
+ exists_good_part (cl)
+   QSTRING_S *cl;
+ {
+    return (cl ? (((cl->qstype != qsWord) && (cl->qstype != qsChar)
+                  && 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(q, GLine, NLine, PLine, rqstr, rqstrlen, plb)
+   char *q,  *GLine, *NLine, *PLine, *rqstr;
+   int   rqstrlen, plb;
+ {
+     QSTRING_S *cl, *nl = NULL, *pl = NULL;
+     int c, n, p,i, j, NewP, NewC, NewN, clength, same = 0;
+     char nbuf[NSTRING], pbuf[NSTRING], buf[NSTRING];
+ 
+     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(q, l, i)
+    char *q;
+    char l[NSTRING];
+    int   i;
+ {
+     int n = 0, j = 0, is = 0, es = 0;
+     int k, m, p, adv;
+     char qs[NSTRING] = {'\0'};
+     if(!q || !*q)
+       return(0);
+     for (p = strlen(q); (p > 0) && (q[p - 1] == ' '); p--, es++);
+     if (!p){  /* string contains only spaces */
+        for (k = 0; 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 (word, plb)
+  char word[NSTRING];
+   int  plb;
+ {
+   int i = 0, finished = 0, c, nxt, j, k, digit = 0, bdigits = -1, alpha = 0;
+ 
+    if (!word || !word[0])
+       return i;
+ 
+    for (i = 0, j = 0; ISspace(word[i]); i++, j++);
+    while ((i < NSTRING - 2) && !finished){
+       switch (c = now(word,i)){
+           case NBSP:
+           case TAB :
+           case ' ' : for (; ISspace(word[i]); i++);
+                      if (!is_indent_char(now(word,i)))
+                        finished++;
+                   break;
+ 
+            case '+' :
+            case '.' :
+            case ']' :
+            case '*' :
+            case '}' :
+            case '-' :
+            case RPAREN:
+                   nxt = next(word,i);
+                   if ((c == '.' && allowed_after_period(nxt) && alpha)
+                        || (c == '*' && allowed_after_star(nxt))
+                        || (c == '}' && allowed_after_braces(nxt))
+                        || (c == '-' && allowed_after_dash(nxt))
+                        || (c == '+' && allowed_after_dash(nxt))
+                        || (c == RPAREN && allowed_after_parenth(nxt))
+                        || (c == ']' && allowed_after_parenth(nxt)))
+                      i++;
+                   else
+                      finished++;
+                   break;
+ 
+             default : if (is_a_digit(c) && plb){
+                         if (bdigits < 0)
+                            bdigits = i;  /* first digit */
+                         for (k = i; is_a_digit(now(word,k)); k++);
+                         if (k - bdigits > 2){ /* more than 2 digits? */
+                            i = bdigits; /* too many! */
+                            finished++;
+                         }
+                         else{
+                            if(allowed_after_digit(now(word,k),word,k)){
+                              alpha++;
+                              i = k;
+                            }
+                            else{
+                              i = bdigits;
+                              finished++;
+                            }
+                         }
+                       }
+                       else
+                         finished++;
+                    break;
+ 
+       }
+    }
+    if (i == j)
+       i = 0;  /* there must be something more than spaces in an indent string */
+    return i;
+ }
+ 
+ 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;
+ }
+ 
diff -rc alpine-2.00/pith/osdep/color.h alpine-2.00.I.USE/pith/osdep/color.h
*** alpine-2.00/pith/osdep/color.h	2008-03-24 12:35:31.000000000 -0700
--- alpine-2.00.I.USE/pith/osdep/color.h	2011-02-07 20:33:42.000000000 -0800
***************
*** 43,48 ****
--- 43,69 ----
  #define PSC_REV		0x2
  #define PSC_RET		0x4	/* return an allocated copy of previous color */
  
+ /*
+  * 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)
+ 
+ 
  
  /*
   * MATCH_NORM_COLOR means that the color that is set to this value
***************
*** 92,97 ****
--- 113,123 ----
  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 *);
  
  
  #endif /* PITH_OSDEP_COLOR_INCLUDED */
diff -rc alpine-2.00/pith/osdep/domnames.c alpine-2.00.I.USE/pith/osdep/domnames.c
*** alpine-2.00/pith/osdep/domnames.c	2006-11-17 18:46:41.000000000 -0800
--- alpine-2.00.I.USE/pith/osdep/domnames.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 51,57 ****
      char          **alias;
      char           *maybe = NULL;
  
!     gethostname(hname, MAX_ADDRESS);
      he = gethostbyname(hname);
      hostname[0] = '\0';
  
--- 51,70 ----
      char          **alias;
      char           *maybe = NULL;
  
!     if (gethostname(hname, MAX_ADDRESS)) hname[0] = 0xff;
! 				/* sanity check of hostname string */
!     for (dn = hname; (*dn > 0x20) && (*dn < 0x7f); ++dn);
!     if (*dn) {			/* only if invalid string returned */
! #if 0
!       hostname[0] = domainname[0] = '\0';
! #else
!       /* Contrary to the comments above, the UNIX code does not expect
! 	 these strings to be blank.
!       */
!       strcpy (hostname, (strcpy (domainname,"unknown")));
! #endif
!       return;
!     }
      he = gethostbyname(hname);
      hostname[0] = '\0';
  
diff -rc alpine-2.00/pith/osdep/hostname.c alpine-2.00.I.USE/pith/osdep/hostname.c
*** alpine-2.00/pith/osdep/hostname.c	2006-12-11 10:06:32.000000000 -0800
--- alpine-2.00.I.USE/pith/osdep/hostname.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 47,53 ****
  {
  #if	HAVE_GETHOSTNAME
  
!     return(gethostname(hostname, size));
  
  #elif	HAVE_UNAME
  
--- 47,57 ----
  {
  #if	HAVE_GETHOSTNAME
  
!     if(gethostname(hostname, size)) return -1;
! 				/* sanity check of hostname string */
!     for (*dn = hname; (*dn > 0x20) && (*dn < 0x7f); ++dn);
!     if (*dn) strcpy (hostname,"unknown");
!     return 0;
  
  #elif	HAVE_UNAME
  
diff -rc alpine-2.00/pith/pattern.c alpine-2.00.I.USE/pith/pattern.c
*** alpine-2.00/pith/pattern.c	2008-07-14 11:01:54.000000000 -0700
--- alpine-2.00.I.USE/pith/pattern.c	2011-02-07 20:33:41.000000000 -0800
***************
*** 1755,1761 ****
  	    SortOrder def_sort;
  	    int       def_sort_rev;
  
! 	    if(decode_sort(p, &def_sort, &def_sort_rev) != -1){
  		action->sort_is_set = 1;
  		action->sortorder = def_sort;
  		action->revsort   = (def_sort_rev ? 1 : 0);
--- 1755,1761 ----
  	    SortOrder def_sort;
  	    int       def_sort_rev;
  
! 	    if(decode_sort(p, &def_sort, &def_sort_rev, 0) != -1){
  		action->sort_is_set = 1;
  		action->sortorder = def_sort;
  		action->revsort   = (def_sort_rev ? 1 : 0);
***************
*** 5482,5487 ****
--- 5482,5496 ----
  		break;
  	      
  	      case '#':
+ #ifndef _WINDOWS
+ 		if(!struncmp(patfolder, "#md/", 4)
+ 		       || !struncmp(patfolder, "#mc/", 4)){
+ 		  maildir_file_path(patfolder, tmp1);
+ 		  if(!strcmp(patfolder, stream->mailbox))
+ 		     match++;
+ 		  break;
+ 		}
+ #endif
  	        if(!strcmp(patfolder, stream->mailbox))
  		  match++;
  
***************
*** 7894,7900 ****
      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;
  #define	FILTMSG_MAX	30
  
      if(!stream)
--- 7903,7909 ----
      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, *save_dstfldr = NULL, *save_dstfldr2 = NULL;
  #define	FILTMSG_MAX	30
  
      if(!stream)
***************
*** 7928,7933 ****
--- 7937,7952 ----
      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);
+ 	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;
***************
*** 7991,7996 ****
--- 8010,8020 ----
      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 -rc alpine-2.00/pith/pineelt.h alpine-2.00.I.USE/pith/pineelt.h
*** alpine-2.00/pith/pineelt.h	2008-07-09 22:01:13.000000000 -0700
--- alpine-2.00.I.USE/pith/pineelt.h	2011-02-07 20:33:47.000000000 -0800
***************
*** 40,45 ****
--- 40,47 ----
  	PINETHRD_S  *pthrd;
  	PARTEX_S    *exceptions;
  	ICE_S       *ice;
+ 	char	    *firsttext;
+ 	char	    *firsttextraw;
  	/* per-message pine state bits */
  	unsigned int hidden:1;
  	unsigned int excluded:1;
diff -rc alpine-2.00/pith/pine.hlp alpine-2.00.I.USE/pith/pine.hlp
*** alpine-2.00/pith/pine.hlp	2008-08-22 17:07:05.000000000 -0700
--- alpine-2.00.I.USE/pith/pine.hlp	2011-02-07 20:33:48.000000000 -0800
***************
*** 88,93 ****
--- 88,94 ----
      ALPINE_VERSION
      ALPINE_REVISION
      ALPINE_COMPILE_DATE
+     ALPINE_PATCHLEVEL
      ALPINE_TODAYS_DATE
      C_CLIENT_VERSION
      _LOCAL_FULLNAME_
***************
*** 158,163 ****
--- 159,172 ----
  </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 by the University of Washington.
  It is intended to be an easy-to-use program for
***************
*** 919,924 ****
--- 928,1016 ----
  &lt;End of Configuration Notes&gt;
  </BODY>
  </HTML>
+ ====== h_patches ======
+ <html>
+ <head>
+ <TITLE>Information on patches added to this release</TITLE>
+ </head>
+ <body>
+ <H1>Information on patches added to this release</H1>
+ <P>
+ This version of Alpine has been modified by including patches from
+ <A HREF="http://staff.washington.edu/chappa/alpine/">
+ http://staff.washington.edu/chappa/alpine/</A>. These patches include
+ new features and bug fixes. More complete information on each patch
+ included in this version can be found in the web.
+ 
+ <P>If you have any problems with this release of Alpine, please contact
+ Eduardo Chappa <A HREF="mailto:chappa@washington.edu">&lt;chappa@washington.edu&gt;</A>.
+ 
+ <P>The list of patches included in this release are:
+ <P>New Features:
+ 
+ <UL>
+  <LI> Enhanced Fancy thread interface. <A HREF="http://staff.washington.edu/chappa/alpine/info/fancy.html">(more)</A>
+ <!--chtml if pinemode="os_windows"-->
+ 
+ <!--chtml else-->
+  <LI> Patch that gives support for the maildir driver in Alpine <A HREF="h_config_maildir">(more)</A>
+ <!--chtml endif-->
+  <LI> Rules patch, to make Alpine flexible. <A HREF="h_config_new_rules">(more)</A>
+  <LI> Send mail from the command Line. <A HREF="http://staff.washington.edu/chappa/alpine/info/outgoing.html">(more)</A>
+  <LI> Add a few more options when replying to a message <A HREF="h_config_alt_reply_menu">(more)</A>
+  <LI> Choose a role when composing a message from a mailto: link <A HREF="http://staff.washington.edu/chappa/alpine/info/composeurl.html">(more)</A>
+  <LI> Alpine justifies paragraphs with more than one level of indentation. <A HREF="h_compose_justify">(more)</A>
+  <LI> Patch to write accents and foreign characters <A HREF="http://staff.washington.edu/chappa/alpine/info/WrtAcc.html">(more)</A>
+  <LI> Change your From Header without any effort! <A HREF="http://staff.washington.edu/chappa/alpine/info/fromheader.html">(more)</A>
+  <LI> Tab checks folders on cycles <A HREF="h_config_circular_tab">(more)</A>
+  <LI> Patch for Pico to update its status line according to cursor movements <A HREF="http://staff.washington.edu/chappa/alpine/info/status.html">(more)</A>
+  <LI> Reuse your old search pattern to create a new one <A HREF="http://staff.washington.edu/chappa/alpine/info/insertpat.html">(more)</A>
+  <LI> Paint special text in the body of a message in any color. <A HREF="h_config_special_text_to_color">(more)</A>
+  <LI> Select messages by the content of an arbitrary header. <A HREF="http://staff.washington.edu/chappa/alpine/info/searchheader.html">(more)</A>
+  <LI> Remove incorrect passwords from memory <A HREF="http://staff.washington.edu/chappa/alpine/info/delpassword.html">(more)</A>
+  <LI> Get the quota report in an IMAP server <A HREF="http://staff.washington.edu/chappa/alpine/info/quota.html">(more)</A>
+  <LI> Remove text until the end of the file or a message <A HREF="http://staff.washington.edu/chappa/alpine/info/DelText.html">(more)</A>
+  <LI> Get the internal name of a help topic to use it with a x-alpine-help or x-pine-help URL scheme. <A HREF="http://staff.washington.edu/chappa/alpine/info/help.html">(more)</A>
+  <LI> Get the number of characters in a composed message <A HREF="http://staff.washington.edu/chappa/alpine/info/count.html">(more)</A>
+  <LI> Configure ignoring change in size of a message <A HREF="h_config_ignore_size">(more)</A>
+  <LI> Add one more token to a sending filter <A HREF="http://staff.washington.edu/chappa/alpine/info/addressfilter.html">(more)</A>
+  <LI> Make Alpine preserve To: and Cc: fields <A HREF="h_config_preserve_field">(more)</A>
+  <LI> Allow non utf-8 piped input in Alpine <A HREF="http://staff.washington.edu/chappa/alpine/info/noutf8.html">(more)</A>
+  <LI> Allow errors in base64 encoding <A HREF="http://staff.washington.edu/chappa/alpine/info/base64errors.html">(more)</A>
+  <LI> Get the name of the slow server <A HREF="http://staff.washington.edu/chappa/alpine/info/streaminfo.html">(more)</A>
+  <LI> Color the text in the folder list screen <A HREF="http://staff.washington.edu/chappa/alpine/info/colorfolder.html">(more)</A>
+  <LI> Color text in the index screen <A HREF="http://staff.washington.edu/chappa/alpine/info/tokencolor.html">(more)</A>
+  <LI> Avoid clearing the screen when executing a display filter <A HREF="http://staff.washington.edu/chappa/alpine/info/silenttoken.html">(more)</A>
+  <LI> Cache OPENINGTEXT information <A HREF="http://staff.washington.edu/chappa/alpine/info/cachefirsttext.html">(more)</A>
+  <LI> Recognize multiline URLs <A HREF="http://staff.washington.edu/chappa/alpine/info/longurl.html">(more)</A>
+  <LI> Recognize the nametemplate token in a mailcap file <A HREF="http://staff.washington.edu/chappa/alpine/info/nametemplate.html">(more)</A>
+  <LI> Create new threads even when replying to a message <A HREF="http://staff.washington.edu/chappa/alpine/info/newthread.html">(more)</A>
+ </UL>
+ 
+ <P>Bug Fixes:
+ 
+ <UL>
+  <LI> Fix a bug that makes Alpine not to give a warning if the Newsgroup header is present <A HREF="http://staff.washington.edu/chappa/alpine/info/unverified.html">(more)</A>
+  <LI> Fix a bug in Pico which makes it not update the screen <A HREF="http://staff.washington.edu/chappa/alpine/info/replacebug.html">(more)</A>
+  <LI> Fix a bug in Pico and Pilot that makes them crash for bad locale information <A HREF="http://staff.washington.edu/chappa/alpine/info/nlinfobug.html">(more)</A>
+  <LI> Fix a bug in Alpine that makes it not to set a flag in a filtered message <A HREF="http://staff.washington.edu/chappa/alpine/info/filterflagbug.html">(more)</A>
+  <LI> Fix a bug that makes Alpine crash when suspending it <A HREF="http://staff.washington.edu/chappa/alpine/info/streamlock.html">(more)</A>
+  <LI> Fix a bug that makes Alpine crash when opening a unix type folder <A HREF="http://staff.washington.edu/chappa/alpine/info/unixnullbug.html">(more)</A>
+  <LI> Force update of the index screen after adding an address to the addressbook <A HREF="http://staff.washington.edu/chappa/alpine/info/updateindexcolors.html">(more)</A>
+  <LI> Fix a bug that makes Alpine ignore the week day of a preftime token <A HREF="http://staff.washington.edu/chappa/alpine/info/preftimebug.html">(more)</A>
+  <LI> Fix the type of a .docx document <A HREF="http://staff.washington.edu/chappa/alpine/info/docxmimetype.html">(more)</A>
+  <LI> Parse environment variables correctly <A HREF="http://staff.washington.edu/chappa/alpine/info/envvar.html">(more)</A>
+  <LI> Do not reopen a folder that is meant to be closed <A HREF="http://staff.washington.edu/chappa/alpine/info/closebug.html">(more)</A>
+  <LI> Fix a bug that makes Alpine crash when the screen is resized <A HREF="http://staff.washington.edu/chappa/alpine/info/resizeldap.html">(more)</A>
+  <LI> Fix a bug in the threading algorithm <A HREF="http://staff.washington.edu/chappa/alpine/info/threadbug.html">(more)</A>
+  <LI> Fix a memory leak in Alpine <A HREF="http://staff.washington.edu/chappa/alpine/info/composerleak.html">(more)</A>
+  <LI> Fix a bug that sends Alpine in an infinite loop <A HREF="http://staff.washington.edu/chappa/alpine/info/scrolltool.html">(more)</A>
+  <LI> Fix a bug that makes Alpine not give a correct new mail message <A HREF="http://staff.washington.edu/chappa/alpine/info/newmailmsg.html">(more)</A>
+  <LI> Fix a bug that makes Alpine not show a login prompt <A HREF="http://staff.washington.edu/chappa/alpine/info/loginbug.html">(more)</A>
+  <LI> Patch by Mark Crispin, which fixes a bug which makes Alpine not generate correct headers for servers that return UTF-8 names. <A HREF="http://staff.washington.edu/chappa/alpine/patches/others.html#markhostbug-2.00">(more)</A>
+ </UL>
+ </body>
+ </html>
  ====== h_news_legal ======
  <html>
  <head>
***************
*** 3035,3043 ****
--- 3127,3137 ----
  <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>
***************
*** 3120,3125 ****
--- 3214,3220 ----
  <li><a href="h_config_prefix_editing">FEATURE: <!--#echo var="FEAT_enable-reply-indent-string-editing"--></a>
  <li><a href="h_config_enable_search_and_repl">FEATURE: <!--#echo var="FEAT_enable-search-and-replace"--></a>
  <li><a href="h_config_sigdashes">FEATURE: <!--#echo var="FEAT_enable-sigdashes"--></a>
+ <li><a href="h_config_new_thread_blank_subject">FEATURE: <!--#echo var="FEAT_new-thread-on-blank-subject"--></a>
  <li><a href="h_config_can_suspend">FEATURE: <!--#echo var="FEAT_enable-suspend"--></a>
  <li><a href="h_config_enable_tab_complete">FEATURE: <!--#echo var="FEAT_enable-tab-completion"--></a>
  <li><a href="h_config_enable_take_export">FEATURE: <!--#echo var="FEAT_enable-take-export"--></a>
***************
*** 3136,3142 ****
--- 3231,3239 ----
  <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>
  <li><a href="h_config_hide_nntp_path">FEATURE: <!--#echo var="FEAT_hide-nntp-path"--></a>
  <li><a href="h_config_attach_in_reply">FEATURE: <!--#echo var="FEAT_include-attachments-in-reply"--></a>
***************
*** 3402,3407 ****
--- 3499,3505 ----
  <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>
***************
*** 3430,3438 ****
--- 3528,3538 ----
  <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>
***************
*** 4058,4063 ****
--- 4158,4172 ----
  key will Exit the Help system altogether.
  
  <P>
+ The "N" command will tell you the internal name of the help text you are 
+ reading each time, so that you can send this name in the text of a message 
+ and create a direct link to that internal help using the x-pine-help URL 
+ scheme. For example, the direct link to this item is 
+ x-pine-help:h_special_help_nav. If you add this text to a message, then
+ a person using Pine to read such message would have a direct link to this
+ help text.
+ 
+ <P>
  When you are finished reading this help text, you can press the
  <!--chtml if pinemode="function_key"-->
  F3 function
***************
*** 5316,5321 ****
--- 5425,5583 ----
  &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 has not been defined yet.
+ 
+ <P>
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
+ ======= h_thread_index_sort_score =======
+ <HTML>
+ <HEAD>
+ <TITLE>SORT OPTION: Score</TITLE>
+ </HEAD>
+ <BODY>
+ <H1>SORT OPTION: Score</H1>
+ 
+ The <EM>Score</EM> sort option 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>
***************
*** 6503,6508 ****
--- 6765,6810 ----
  &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>
***************
*** 18069,18074 ****
--- 18371,18377 ----
  <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.
***************
*** 18081,18087 ****
  <P>
  <P>
  
! <H1><EM>Tokens Available for all Cases (except Filter Rules)</EM></H1>
  
  <DL>
  <DT>SUBJECT</DT>
--- 18384,18390 ----
  <P>
  <P>
  
! <H1><EM>Tokens Available for all Cases (except Filter Rules or in some cases for new-rules)</EM></H1>
  
  <DL>
  <DT>SUBJECT</DT>
***************
*** 18114,18119 ****
--- 18417,18431 ----
  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 
***************
*** 18161,18166 ****
--- 18473,18487 ----
  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
***************
*** 18169,18174 ****
--- 18490,18503 ----
  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
***************
*** 18650,18655 ****
--- 18979,18992 ----
  <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.
***************
*** 19265,19270 ****
--- 19602,19679 ----
  </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>
***************
*** 21253,21258 ****
--- 21662,21763 ----
  &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>
***************
*** 22015,22020 ****
--- 22520,22564 ----
  &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>
***************
*** 22285,22290 ****
--- 22829,23726 ----
  &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>
***************
*** 22592,22597 ****
--- 24028,24070 ----
  &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>
***************
*** 22713,22718 ****
--- 24186,24198 ----
  improve security.  The number is unique to the current Alpine session
  and is only generated once per session.
  </DD>
+ 
+ <DT>_SILENT_</DT>
+ <DD>When the filter is executed, this token tells Alpine not to repaint
+ the screen while the command is being executed. This can be used with 
+ filters that do not interact with the user, and therefore repainting 
+ the screen is not necessary. 
+ </DD>
  </DL>
  
  <P>
***************
*** 22749,22754 ****
--- 24229,24240 ----
  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 
***************
*** 25861,25866 ****
--- 27347,27422 ----
  &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>
***************
*** 27467,27472 ****
--- 29023,29058 ----
  &lt;End of help on this topic&gt;
  </BODY>
  </HTML>
+ ====== h_config_new_thread_blank_subject =====
+ <HTML>
+ <HEAD>
+ <TITLE>FEATURE: <!--#echo var="FEAT_new-thread-on-blank-subject"--></TITLE>
+ </HEAD>
+ <BODY>
+ <H1>FEATURE: <!--#echo var="FEAT_new-thread-on-blank-subject"--></H1>
+ 
+ When this feature is enabled (the default) Alpine will create a new thread
+ every time that the subject line becomes empty at any time during composition.
+ 
+ <P>
+ This behavior is particularly useful in case you are replying to a message.
+ Replying to a message causes the message to be in the same thread than the
+ original message that is being replied to. However, many authors want to create
+ a new message (in a different thread) while replying to a message, and they do
+ this by changing the full subject, by first deleting the original subject and
+ typing the new subject of the current message.
+ 
+ <P>
+ Enabling this feature causes that any time that the subject is deleted, the 
+ message being composed will be considered the first message of a new thread.
+ 
+ <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_strip_sigdashes =====
  <HTML>
  <HEAD>
***************
*** 27517,27522 ****
--- 29103,29144 ----
  &lt;End of help on this topic&gt;
  </BODY>
  </HTML>
+ ====== h_config_preserve_field =====
+ <HTML>
+ <HEAD>
+ <TITLE>FEATURE: <!--#echo var="FEAT_preserve-original-fields"--></TITLE>
+ </HEAD>
+ <BODY>
+ <H1>FEATURE: <!--#echo var="FEAT_preserve-original-fields"--></H1>
+ 
+ When you reply to a message that has been sent to several recipients, some of
+ them may have been added in different parts of the headers. For example,
+ some of the recipients will be listed in the To: header, while others will
+ be listed in the Cc: header.
+ <P>
+ If this feature is disabled, the default behavior of Alpine will be used, 
+ and that is, that almost all recipients of the message will be 
+ listed in the Cc: field. However, if you enable this feature, then, 
+ excepting you, recipients originally listed in the Cc: field will be 
+ listed again in the Cc: field, and those listed in the To: field in the 
+ original message will be listed in the To: field again. The person in the 
+ From: field will be added to the To: field.
+ <P>
+ Note that this will cause some messages that you send in Alpine to look
+ different. In particular, the To: field of a message will not be put in the
+ Cc: field, as is normally done. In fact, most people expect this to happen.
+ If you find that this is a problem you should disable this feature. You can
+ still make Alpine have this behavior on a per message basis. In order to do
+ this, you will see a new option in the menu for the &quot;Reply to all
+ recipients?&quot; question. In this case, pressing &quot;p&quot; will make
+ Alpine toggle its question so you can preserve the To: and Cc: fields for that
+ message.
+ <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_sub_lists =====
  <HTML>
  <HEAD>
***************
*** 27701,27706 ****
--- 29323,29344 ----
  &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>
***************
*** 28297,28302 ****
--- 29935,30005 ----
  &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>
***************
*** 28820,28825 ****
--- 30523,30560 ----
  &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>
***************
*** 29127,29132 ****
--- 30862,30910 ----
  &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>
***************
*** 29281,29286 ****
--- 31059,31087 ----
  &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>
***************
*** 29731,29736 ****
--- 31532,31554 ----
  &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 ^D marks a thread deleted, but if
+ this feature is set, it will remove all threads that share the same missing
+ parent with this thread.
+ 
+ <P>
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
  ====== h_config_news_cross_deletes =====
  <HTML>
  <HEAD>
***************
*** 30209,30214 ****
--- 32027,32066 ----
  &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>
***************
*** 30479,30484 ****
--- 32331,32357 ----
  &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_auto_include_reply =====
  <HTML>
  <HEAD>
***************
*** 31142,31147 ****
--- 33015,33113 ----
  &lt;End of help on this topic&gt;
  </BODY>
  </HTML>
+ ====== h_config_folder_color =====
+ <HTML>
+ <HEAD>
+ <TITLE>OPTION: Folder Color</TITLE>
+ </HEAD>
+ <BODY>
+ <H1>OPTION: Folder Color</H1>
+ 
+ Sets the colors Alpine uses for coloring a folder in the FOLDER LIST
+ screen. By default, the Folder Color is the normal text color.
+ 
+ <P>
+ If you set a color for this feature, other than the normal color
+ (the default), or a color for
+ <A HREF="h_config_directory_color">Directory Color</A>, then directories
+ will be colored according to the color specified in the
+ <A HREF="h_config_directory_color">Directory Color</A> option. In this
+ case, the color will be the only indication that the colored name
+ refers to a directory. The normal behavior is that Alpine
+ indicates that a name refers to a directory by appending a
+ separator (like &quot;/&quot; or &quot;.&quot;) to the name of
+ the folder.
+ 
+ <P>
+ If a folder is a directory, then the folder name will be painted
+ according to the color defined by this variable, and a separator
+ indicator  (like &quot;/&quot; or &quot;.&quot;) will be added 
+ to the name. That
+ indicator will be painted according to the color defined in the
+ <A HREF="h_config_directory_color">Directory Color</A> option.
+ 
+ <P>
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
+ ====== h_config_directory_color =====
+ <HTML>
+ <HEAD>
+ <TITLE>OPTION: Directory Color</TITLE>
+ </HEAD>
+ <BODY>
+ <H1>OPTION: Directory Color</H1>
+ 
+ Sets the colors Alpine uses for coloring a directory in the FOLDER LIST
+ screen. By default, the Folder Color is the normal text color.
+ <P>
+ If you set a color for this feature, other than the normal color
+ (the default), or a color for
+ <A HREF="h_config_folder_color">Folder Color</A>, then folders
+ will be colored according to the color specified in the
+ <A HREF="h_config_folder_color">Folder Color</A> option. In this
+ case, the color will be the only indication that the colored name
+ refers to a directory. The normal behavior is that Alpine
+ indicates that a name refers to a directory by appending a
+ separator (like &quot;/&quot; or &quot;.&quot;) to the name of
+ the folder.
+ <P>
+ If a folder is a directory, then the folder name will be painted
+ according to the color defined by the option
+ <A HREF="h_config_folder_color">Folder Color</A>, and the separator
+ indicator  (like &quot;/&quot; or &quot;.&quot;) will be added
+ after the name. That
+ indicator will be painted according to the color defined in this
+ option.
+ <P>
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
+ ====== h_config_folder_list_color =====
+ <HTML>
+ <HEAD>
+ <TITLE>OPTION: Folder-List Color</TITLE>
+ </HEAD>
+ <BODY>
+ <H1>OPTION: Folder-List Color</H1>
+ 
+ Sets the colors Alpine uses for coloring normal text in the FOLDER LIST
+ screen. By default, the Folder-List Color is the normal text color.
+ <P>
+ This text refers to the informative text that Alpine displays so you
+ can recognize each collection. The color of the content of each collection
+ is determined by the options <A HREF="h_config_folder_color">Folder Color</A>
+ and <A HREF="h_config_directory_color">Directory Color</A>.
+ <P>
+ Unlike the options
+ <A HREF="h_config_folder_color">Folder Color</A>
+ and <A HREF="h_config_directory_color">Directory Color</A>, configuring
+ this option does not affect the way that it tradinionally reports folders,
+ directories and folders that are directories.
+ <P>
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
  ====== h_config_incunseen_color =====
  <HTML>
  <HEAD>
***************
*** 31197,31202 ****
--- 33163,33192 ----
  &lt;End of help on this topic&gt;
  </BODY>
  </HTML>
+ ====== h_config_special_text_color =====
+ <HTML>
+ <HEAD>
+ <TITLE>OPTION: Special Text Color</TITLE>
+ </HEAD>
+ <BODY>
+ <H1>OPTION: Special Text Color</H1>
+ 
+ Sets the color Pine uses for coloring any text in the body of the message
+ that is not part of a handle (and internal or external link that Pine 
+ paints in a different color). By default, this variable is not defined, 
+ which means that text that matches the pattern is not painted in any
+ particular way. This variable must be set in a special form if you
+ want text to be painted.
+ 
+ <P>
+ <A HREF="h_color_setup">Descriptions of the available commands</A>
+ <P>
+ Look <A HREF="h_edit_nav_cmds">here</A>
+ to see the available Editing and Navigation commands.
+ <P>
+ &lt;End of help on this topic&gt;
+ </BODY>
+ </HTML>
  ====== h_config_prompt_color =====
  <HTML>
  <HEAD>
***************
*** 31464,31469 ****
--- 33454,33488 ----
  &lt;End of help on this topic&gt;
  </BODY>
  </HTML>
+ ====== h_config_indextoken_color =====
+ <HTML>
+ <HEAD>
+ <TITLE>OPTION: <!--#echo var="VAR_index-token-colors"--></TITLE>
+ </HEAD>
+ <BODY>
+ <H1>OPTION: <!--#echo var="VAR_index-token-colors"--></H1>
+ 
+ This option allows you to set up the color in which any token, not specified by the
+ previous options, will be colored in the MESSAGE INDEX screen. 
+ <P>
+ In order to use this option, you must press the &quot;I&quot; <B>IndxHdr</B> command, and add
+ a token that can be used in the index format. 
+ The list of available tokens is <A HREF="h_index_tokens">here</A>.
+ <P>
+ If you fail to enter a valid token your entry will be ignored, and you will be asked to
+ enter a new one. Once you have entered a valid token, a line will be added to the
+ configuration screen that you can use to set up the colors in which that token will
+ be painted. This is done in the same way that you configure colors for other
+ variables.
+ 
+ <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_customhdr_pattern =====
  <HTML>
  <HEAD>
***************
*** 35075,35077 ****
--- 37094,37099 ----
  ========== h_select_by_smaller_size ==========
  Enter a number or ^C to cancel. All messages less than this many characters
  in size will be selected. Examples: 2176, 1.53K (1530), or 3M (3000000).
+ ========== h_preserve_field ==========
+ Use 'p' to toggle between preserving or not preserving the original To:
+ and Cc: fields of the message. Enter ^C to cancel message.
diff -rc alpine-2.00/pith/reply.c alpine-2.00.I.USE/pith/reply.c
*** alpine-2.00/pith/reply.c	2008-06-03 12:27:23.000000000 -0700
--- alpine-2.00.I.USE/pith/reply.c	2011-02-07 20:33:44.000000000 -0800
***************
*** 45,50 ****
--- 45,52 ----
  #include "../pith/ablookup.h"
  #include "../pith/mailcmd.h"
  #include "../pith/margin.h"
+ #include "../pith/copyaddr.h"
+ #include "../pith/rules.h"
  
  
  /*
***************
*** 372,391 ****
  	/* Put Reply-To or From in To. */
  	*to_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->to,
  				 (ADDRESS *) NULL, saved_from, RCA_ALL);
- 	/* and the rest in cc */
  	if(replytoall){
! 	    *cc_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->cc,
  				     outgoing->to, saved_to, RCA_ALL);
! 	    while(*cc_tail)		/* stay on last address */
! 	      cc_tail = &(*cc_tail)->next;
  
! 	    *cc_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->cc,
  				     outgoing->to, saved_cc, RCA_ALL);
! 	    while(*cc_tail)
! 	      cc_tail = &(*cc_tail)->next;
  
! 	    *cc_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->cc,
  				     outgoing->to, saved_resent, RCA_ALL);
  	}
      }
      else if(saved_to){
--- 374,410 ----
  	/* Put Reply-To or From in To. */
  	*to_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->to,
  				 (ADDRESS *) NULL, saved_from, RCA_ALL);
  	if(replytoall){
! 	    if(ps->preserve){
! 		while(*to_tail)
! 		   to_tail = &(*to_tail)->next;
! 
! 	        *to_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->to,
! 				 (ADDRESS *) NULL, saved_to, RCA_ALL);
! 
! 		while(*to_tail)
! 		   to_tail = &(*to_tail)->next;
! 
! 		*to_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->cc,
! 				     outgoing->to, saved_resent, RCA_ALL);
! 
! 		*cc_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->cc,
! 				     outgoing->to, saved_cc, RCA_ALL);
! 	    }
! 	    else{	/* and the rest in cc */
! 		*cc_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->cc,
  				     outgoing->to, saved_to, RCA_ALL);
! 		while(*cc_tail)		/* stay on last address */
! 	           cc_tail = &(*cc_tail)->next;
  
! 		*cc_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->cc,
  				     outgoing->to, saved_cc, RCA_ALL);
! 		while(*cc_tail)
! 		      cc_tail = &(*cc_tail)->next;
  
! 		*cc_tail = reply_cp_addr(ps, 0, NULL, NULL, outgoing->cc,
  				     outgoing->to, saved_resent, RCA_ALL);
+ 	    }
  	}
      }
      else if(saved_to){
***************
*** 796,803 ****
  reply_quote_str(ENVELOPE *env)
  {
      char *prefix, *repl, *p, buf[MAX_PREFIX+1], pbf[MAX_SUBSTITUTION+1];
  
!     strncpy(buf, ps_global->VAR_REPLY_STRING, sizeof(buf)-1);
      buf[sizeof(buf)-1] = '\0';
  
      /* set up the prefix to quote included text */
--- 815,841 ----
  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, reply_string, sizeof(buf)-1);
      buf[sizeof(buf)-1] = '\0';
  
      /* set up the prefix to quote included text */
***************
*** 849,858 ****
  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)));
  }
  
  
--- 887,915 ----
  int
  reply_quote_str_contains_tokens(void)
  {
!    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)));
  }
  
  
***************
*** 954,960 ****
  	if(!orig_body
  	   || orig_body->type == TYPETEXT
  	   || reply_raw_body
! 	   || F_OFF(F_ATTACHMENTS_IN_REPLY, ps_global)){
  	    char *charset = NULL;
  
  	    /*------ Simple text-only message ----*/
--- 1011,1017 ----
  	if(!orig_body
  	   || orig_body->type == TYPETEXT
  	   || reply_raw_body
! 	   || !ps_global->reply.attach){
  	    char *charset = NULL;
  
  	    /*------ Simple text-only message ----*/
***************
*** 962,968 ****
  	    body->type		     = TYPETEXT;
  	    body->contents.text.data = msgtext;
  	    reply_delimiter(env, role, pc);
! 	    if(F_ON(F_INCLUDE_HEADER, ps_global))
  	      reply_forward_header(stream, msgno, sect_prefix,
  				   env, pc, prefix);
  
--- 1019,1025 ----
  	    body->type		     = TYPETEXT;
  	    body->contents.text.data = msgtext;
  	    reply_delimiter(env, role, pc);
! 	    if(ps_global->reply.inchdr)
  	      reply_forward_header(stream, msgno, sect_prefix,
  				   env, pc, prefix);
  
***************
*** 1020,1026 ****
  
  		if(reply_body_text(orig_body, &tmp_body)){
  		    reply_delimiter(env, role, pc);
! 		    if(F_ON(F_INCLUDE_HEADER, ps_global))
  		      reply_forward_header(stream, msgno, sect_prefix,
  					   env, pc, prefix);
  
--- 1077,1083 ----
  
  		if(reply_body_text(orig_body, &tmp_body)){
  		    reply_delimiter(env, role, pc);
! 		    if(ps_global->reply.inchdr)
  		      reply_forward_header(stream, msgno, sect_prefix,
  					   env, pc, prefix);
  
***************
*** 1058,1064 ****
  		        body->nested.part->body.subtype = cpystr("Plain");
  		    }
  		    reply_delimiter(env, role, pc);
! 		    if(F_ON(F_INCLUDE_HEADER, ps_global))
  		      reply_forward_header(stream, msgno, sect_prefix,
  					   env, pc, prefix);
  
--- 1115,1121 ----
  		        body->nested.part->body.subtype = cpystr("Plain");
  		    }
  		    reply_delimiter(env, role, pc);
! 		    if(ps_global->reply.inchdr)
  		      reply_forward_header(stream, msgno, sect_prefix,
  					   env, pc, prefix);
  
***************
*** 1081,1087 ****
  		    int partnum;
  
  		    reply_delimiter(env, role, pc);
! 		    if(F_ON(F_INCLUDE_HEADER, ps_global))
  		      reply_forward_header(stream, msgno, sect_prefix,
  					   env, pc, prefix);
  
--- 1138,1144 ----
  		    int partnum;
  
  		    reply_delimiter(env, role, pc);
! 		    if(ps_global->reply.inchdr)
  		      reply_forward_header(stream, msgno, sect_prefix,
  					   env, pc, prefix);
  
***************
*** 1316,1321 ****
--- 1373,1382 ----
      buf[0] = '\0';
  
      switch(type){
+       case iFfrom:
+ 	addr = env && env->sparep ? env->sparep : NULL;
+ 	break;
+ 
        case iFrom:
  	addr = env ? env->from : NULL;
  	break;
***************
*** 1701,1721 ****
  
  	break;
  
        case iFrom:
        case iTo:
        case iCc:
        case iSender:
        case iRecips:
        case iInit:
  	get_addr_data(env, type, buf, maxlen);
  	break;
  
!       case iRoleNick:
! 	if(role && role->nick){
! 	    strncpy(buf, role->nick, maxlen);
! 	    buf[maxlen] = '\0';
! 	}
! 	break;
  
        case iNewLine:
  	if(maxlen >= strlen(NEWLINE)){
--- 1762,1912 ----
  
  	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 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 = find_open_stream();
! 	 MSGNO_S *msgmap = NULL;
!          long msgno;
!          MESSAGECACHE *mc;
! 	 strncpy(buf, "_FLAG_", maxlen);	/* default value */
! 	 if (stream){
! 	     mn_init(&msgmap, stream->nmsgs);
! 	     msgno =  mn_m2raw(msgmap, rules_cursor_pos(stream));
! 	     if (msgno > 0L) mc = stream ? mail_elt(stream,  msgno) : NULL;
! 	     if (mc)
! 	        sprintf(buf,"%s%s%s%s",mc->flagged ? "*" : "",
!                 mc->recent   ? (mc->seen ? "R" : "N") : (mc->seen) ? "R" : "U",
!                 mc->answered ? "A" : "",
!                 mc->deleted  ? "D" : "" );
! 	     mn_give(&msgmap);
! 	 }
! 	 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)){
***************
*** 1744,1749 ****
--- 1935,1945 ----
  
  	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);
***************
*** 1793,1798 ****
--- 1989,2002 ----
  
  	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;
***************
*** 1851,1857 ****
      if(!env)
        return;
  
!     strncpy(buf, ps_global->VAR_REPLY_INTRO, MAX_DELIM);
      buf[MAX_DELIM] = '\0';
      /* preserve exact default behavior from before */
      if(!strcmp(buf, DEFAULT_REPLY_INTRO)){
--- 2055,2072 ----
      if(!env)
        return;
  
!     { 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)){
***************
*** 2110,2115 ****
--- 2325,2331 ----
  {
      size_t l;
      char  *p, buftmp[MAILTMPLEN];
+     RULE_RESULT *rule;
      
      if(!env)
        return(NULL);
***************
*** 2117,2125 ****
      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';
  	/* 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)
--- 2333,2352 ----
      dprint((9, "checking subject: \"%s\"\n",
  	       env->subject ? env->subject : "NULL"));
  
!     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)
***************
*** 2620,2628 ****
   		 * tied our hands, alter the prefix to continue flowed
   		 * formatting...
   		 */
!  		if(flow_res)
  		  wrapflags |= GFW_FLOW_RESULT;
  
  		filters[filtcnt].filter = gf_wrap;
  		/* 
  		 * The 80 will cause longer lines than what is likely
--- 2847,2858 ----
   		 * tied our hands, alter the prefix to continue flowed
   		 * formatting...
   		 */
!  		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
***************
*** 2656,2664 ****
  	 * We also want to fold "> " quotes so we get the
  	 * attributions correct.
   	 */
! 	if(flow_res && prefix && !strucmp(prefix, "> "))
  	  *(prefix_p = prefix + 1) = '\0';
! 
  	if(!(wrapflags & GFW_FLOWED)
  	   && flow_res){
  	    filters[filtcnt].filter = gf_line_test;
--- 2886,2894 ----
  	 * We also want to fold "> " quotes so we get the
  	 * attributions correct.
   	 */
! 	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;
***************
*** 2691,2699 ****
      }
  
      if(prefix){
! 	if(ps_global->full_header != 2
! 	   && (F_ON(F_ENABLE_SIGDASHES, ps_global)
! 	       || F_ON(F_ENABLE_STRIP_SIGDASHES, ps_global))){
  	    dashdata = 0;
  	    filters[filtcnt].filter = gf_line_test;
  	    filters[filtcnt++].data = gf_line_test_opt(sigdash_strip, &dashdata);
--- 2921,2927 ----
      }
  
      if(prefix){
! 	if(ps_global->reply.strip){
  	    dashdata = 0;
  	    filters[filtcnt].filter = gf_line_test;
  	    filters[filtcnt++].data = gf_line_test_opt(sigdash_strip, &dashdata);
***************
*** 2718,2724 ****
  	dq.do_color   = 0;
  	dq.delete_all = 1;
  
! 	filters[filtcnt].filter = gf_line_test;
  	filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq);
      }
  
--- 2946,2952 ----
  	dq.do_color   = 0;
  	dq.delete_all = 1;
  
! 	filters[filtcnt].filter = gf_quote_test;
  	filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq);
      }
  
diff -rc alpine-2.00/pith/rules.c alpine-2.00.I.USE/pith/rules.c
*** alpine-2.00/pith/rules.c	2011-02-07 20:34:02.000000000 -0800
--- alpine-2.00.I.USE/pith/rules.c	2011-02-07 20:33:42.000000000 -0800
***************
*** 0 ****
--- 1,1149 ----
+ /* This module was written by
+  *
+  * Eduardo Chappa (chappa@washington.edu)
+  * http://staff.washington.edu/chappa/pine/
+  *
+  *  Original Version: November 1999
+  *  Last Modified   : January 24, 2008
+  *
+  * Send bug reports about this module to the address above.
+  */
+ 
+ #include "../pith/headers.h"
+ #include "../pith/state.h"
+ #include "../pith/conf.h"
+ #include "../pith/copyaddr.h"
+ #include "../pith/rules.h"
+ 
+ /* Internal Prototypes */
+ 
+ int   test_condition  (CONDITION_S *, int, ENVELOPE *);
+ int   test_in         (CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int);
+ int   test_ni         (CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int);
+ int   test_not_in     (CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int);
+ int   test_not_ni     (CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int);
+ int   test_eq         (CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int);
+ int   test_not_eq     (CONDITION_S *, TOKEN_VALUE *, ENVELOPE *, int);
+ int   isolate_condition (char *, char **, int *);
+ char  *test_rule      (RULELIST *, int, ENVELOPE *, int *);
+ char  *trim           (RULEACTION_S *, int, ENVELOPE *);
+ char  *rextrim        (RULEACTION_S *, int, ENVELOPE *);
+ char  *raw_value      (RULEACTION_S *, int, ENVELOPE *);
+ char  *extended_value (RULEACTION_S *, int, ENVELOPE *);
+ char  *exec_fcn	      (RULEACTION_S *, int, ENVELOPE *);
+ char  *expand         (char *, void *);
+ char  *get_name_token (char *);
+ char  *advance_to_char (char *, char, int, int *);
+ char  **functions_for_token (char *);
+ void  free_token_value (TOKEN_VALUE **);
+ void  free_condition  (CONDITION_S **);
+ void  free_ruleaction (RULEACTION_S **);
+ void  free_rule       (RULE_S **);
+ void  free_rule_list  (RULELIST **);
+ void  free_alloc_rule (void **, int);
+ void  *alloc_mem      (size_t);
+ void  add_rule        (int, int);
+ void  set_rule_list    (struct variable *);
+ void  parse_patterns_into_action(TOKEN_VALUE **);
+ void  free_parsed_value(TOKEN_VALUE **value);
+ RULE_S   *parse_rule  (char *, int);
+ RULELIST *get_rule_list (char **, int, int);
+ TOKEN_VALUE *parse_group_data (char *,int *);
+ TOKEN_VALUE *copy_parsed_value (TOKEN_VALUE *, int, ENVELOPE *);
+ CONDITION_S *fill_condition (char *);
+ CONDITION_S *parse_condition (char *, int *);
+ PRULELIST_S *add_prule        (PRULELIST_S *, PRULELIST_S *);
+ RULEACTION_S *parse_action (char *, int);
+ 
+ REL_TOKEN rel_rules_test[] = {
+    {EQ_REL,     Equal,          test_eq},
+    {IN_REL,     Subset,         test_in},
+    {NI_REL,     Includes,       test_ni},
+    {NOT_EQ_REL, NotEqual,       test_not_eq},
+    {NOT_IN_REL, NotSubset,      test_not_in},
+    {NOT_NI_REL, NotIncludes,    test_not_ni},
+    {NULL,       EndTypes,       NULL}
+ };
+ 
+ #define NREL  (sizeof(rel_rules_test)/sizeof(rel_rules_test[0]) - 1)
+ 
+ RULE_FCN rule_fcns[] = {
+ {COPY_FCN,      extended_value, FOR_SAVE|FOR_COMPOSE},
+ {SAVE_FCN,      extended_value, FOR_SAVE},
+ {EXEC_FCN,	exec_fcn,	FOR_REPLACE|FOR_TRIM|FOR_RESUB|FOR_COMPOSE},
+ {REPLY_FCN,     extended_value, FOR_REPLY_INTRO},
+ {TRIM_FCN,      trim,           FOR_TRIM|FOR_RESUB|FOR_COMPOSE},
+ {REPLACE_FCN,   extended_value, FOR_REPLACE},
+ {SORT_FCN,      raw_value,      FOR_SORT},
+ {INDEX_FCN,     raw_value,      FOR_INDEX},
+ {COMMAND_FCN,   raw_value,      FOR_KEY},
+ {REPLYSTR_FCN,  raw_value,      FOR_COMPOSE},
+ {SIGNATURE_FCN, raw_value,      FOR_COMPOSE},
+ {RESUB_FCN,     extended_value, FOR_RESUB},
+ {STARTUP_FCN,   raw_value,      FOR_STARTUP},
+ {REXTRIM_FCN,   rextrim,        FOR_TRIM|FOR_RESUB|FOR_COMPOSE},
+ {THRDSTYLE_FCN, raw_value,      FOR_THREAD},
+ {THRDINDEX_FCN, raw_value,      FOR_THREAD},
+ {SMTP_FCN,      raw_value,      FOR_COMPOSE},
+ {NULL,          0,              FOR_NOTHING}
+ };
+ 
+ char* token_rules[] = {
+    FROM_TOKEN,
+    NICK_TOKEN,
+    OTEXT_TOKEN,
+    OTEXTNQ_TOKEN,
+    ROLE_TOKEN,
+    FOLDER_TOKEN,
+    SUBJ_TOKEN,
+    PROCID_TOKEN,
+    THDDSPSTY_TOKEN,
+    THDNDXSTY_TOKEN,
+    FLAG_TOKEN,
+    COLLECT_TOKEN,
+    THDDSPSTY_TOKEN,
+    ADDR_TOKEN,
+    TO_TOKEN,
+    ADDTO_TOKEN,
+    ADDCC_TOKEN,
+    ADDRECIP_TOKEN,
+    SCREEN_TOKEN,
+    KEY_TOKEN,
+    SEND_TOKEN,
+    CC_TOKEN,
+    LCC_TOKEN,
+    BCC_TOKEN,
+    FFROM_TOKEN,
+    FADDRESS_TOKEN,
+    NULL
+ };
+ 
+ #define NTOKENS  (sizeof(token_rules)/sizeof(token_rules[0]) - 1)
+ #define NFCN    (sizeof(rule_fcns)/sizeof(rule_fcns[0]) - 1)
+ 
+ char *subj_fcn[]    = {SUBJ_TOKEN,    REPLACE_FCN, TRIM_FCN, REXTRIM_FCN, EXEC_FCN};
+ char *from_fcn[]    = {FROM_TOKEN,    REPLACE_FCN, TRIM_FCN, REXTRIM_FCN, EXEC_FCN};
+ char *otext_fcn[]   = {OTEXT_TOKEN,   REPLACE_FCN, TRIM_FCN, REXTRIM_FCN, EXEC_FCN};
+ char *otextnq_fcn[] = {OTEXTNQ_TOKEN, REPLACE_FCN, TRIM_FCN, REXTRIM_FCN, EXEC_FCN};
+ 
+ char *adto_fcn[] = {ADDTO_TOKEN, EXEC_FCN, NULL, NULL, NULL};
+ 
+ char **fcns_for_index[] = {subj_fcn, from_fcn, otext_fcn, otextnq_fcn};
+ 
+ #define NFCNFI    (sizeof(fcns_for_index)/sizeof(fcns_for_index[0])) /*for idx*/
+ #define NFPT      (sizeof(fcns_for_index[0])) /* functions pert token */
+ 
+ SPAREP_S *
+ get_sparep_for_rule(char *value, int flag)
+ {
+   SPAREP_S *rv;
+   rv = (SPAREP_S *) alloc_mem(sizeof(SPAREP_S));
+   rv->flag = flag;
+   rv->value = value ? cpystr(value) : NULL;
+   return rv;
+ }
+ 
+ void free_sparep_for_rule(void **sparep)
+ {
+   SPAREP_S *spare = (SPAREP_S *) *sparep;
+   if(!spare) return;
+   if(spare->value)
+      fs_give((void **)&spare->value);
+   fs_give((void **)sparep);
+ }
+ 
+ 
+ int context_for_function(char *name)
+ {
+   int i, j;
+   for (i = 0; i < NFCN && strcmp(rule_fcns[i].name, name); i++);
+   return i == NFCN ? 0 : rule_fcns[i].what_for;
+ 
+ }
+ 
+ char **functions_for_token(char *name)
+ {
+   int i;
+   for (i = 0; i < NFCNFI && strcmp(fcns_for_index[i][0], name); i++);
+   return i == NFCNFI ? NULL : fcns_for_index[i];
+ }
+ 
+ void
+ free_alloc_rule (void **voidtext, int code)
+ {
+   switch(code){
+      case FREEREGEX : regfree((regex_t *)*voidtext);
+ 			break;
+ 	default: break;
+   }
+ }
+ 
+ 
+ 
+ void free_token_value(TOKEN_VALUE **token)
+ {
+    if(token && *token){
+      if ((*token)->testxt)
+ 	fs_give((void **)&(*token)->testxt);
+      free_alloc_rule (&(*token)->voidtxt, (*token)->codefcn);
+      if((*token)->next)
+ 	free_token_value(&(*token)->next);
+      fs_give((void **)token);
+    }
+ }
+ 
+ void free_condition(CONDITION_S **condition)
+ {
+    if(condition && *condition){
+      if ((*condition)->tname)
+ 	fs_give((void **)&((*condition)->tname));
+      if ((*condition)->value)
+ 	free_token_value(&((*condition)->value));
+      if((*condition)->next)
+ 	free_condition(&((*condition)->next));
+      fs_give((void **)condition);
+    }
+ }
+ 
+ void free_ruleaction(RULEACTION_S **raction)
+ {
+    if(raction && *raction){
+      if ((*raction)->token)
+ 	fs_give((void **)&((*raction)->token));
+      if ((*raction)->function)
+ 	fs_give((void **)&((*raction)->function));
+      if ((*raction)->value)
+ 	free_token_value(&(*raction)->value);
+      fs_give((void **)raction);
+    }
+ }
+ 
+ void free_rule(RULE_S **rule)
+ {
+    if(rule && *rule){
+      free_condition(&((*rule)->condition));
+      free_ruleaction(&((*rule)->action));
+      fs_give((void **)rule);
+    }
+ }
+ 
+ void free_rule_list(RULELIST **rule)
+ {
+   if(!*rule)
+     return;
+ 
+   if((*rule)->next)
+     free_rule_list(&((*rule)->next));
+ 
+   if((*rule)->prule)
+     free_rule(&((*rule)->prule));
+ 
+   fs_give((void **)rule);
+ }
+ 
+ void
+ free_parsed_rule_list(PRULELIST_S **rule)
+ {
+   if(!*rule)
+     return;
+ 
+   if((*rule)->next)
+     free_parsed_rule_list(&((*rule)->next));
+ 
+   if((*rule)->rlist)
+     free_rule_list(&((*rule)->rlist));
+ 
+   fs_give((void **)rule);
+ }
+ 
+ void *
+ alloc_mem (size_t amount)
+ {
+    void *genmem;
+    memset(genmem = fs_get(amount), 0, amount);
+    return genmem;
+ }
+ 
+ 
+ void
+ parse_patterns_into_action(TOKEN_VALUE **tokenp)
+ {
+   if(!*tokenp)
+     return;
+ 
+   if((*tokenp)->testxt){
+       regex_t preg;
+ 
+       (*tokenp)->voidtxt = NULL;
+       (*tokenp)->voidtxt = fs_get(sizeof(regex_t));
+       if (regcomp((regex_t *)(*tokenp)->voidtxt, 
+ 			(*tokenp)->testxt, REG_EXTENDED) != 0){
+          regfree((regex_t *)(*tokenp)->voidtxt);
+ 	 (*tokenp)->voidtxt = NULL;
+       }
+   }
+   if((*tokenp)->voidtxt)
+      (*tokenp)->codefcn = FREEREGEX;
+   if((*tokenp)->next)
+      parse_patterns_into_action(&(*tokenp)->next);
+ }
+ 
+ 
+ int
+ isolate_condition (char *data, char **cvalue, int  *len)
+ {
+   char *p = data;
+   int done = 0, error = 0, next_condition = 0, l;
+ 
+   if(*p == '"' && p[strlen(p) - 1] == '"'){
+     p[strlen(p) - 1] = '\0';
+     p++;
+   }
+   *cvalue = NULL;
+   while (*p && !done){
+ 	switch (*p){
+ 	   case '_': *cvalue = advance_to_char(p,'}', STRICTLY, NULL);
+ 		     if(*cvalue){
+ 			strcat(*cvalue,"}");
+ 			p += strlen(*cvalue);
+ 		     }
+ 		     else
+ 			error++;
+ 		     done++;
+ 	   case ' ': p++;
+ 		     break;
+ 	   case '&': if (*(p+1) == '&'){	/* looking for && */
+ 			p += 2;
+ 			next_condition++;
+ 		     }
+ 		     else{
+ 			error++;
+ 			done++;
+ 		     }
+ 		     break;
+ 	   case '=': /* looking for => or -> */
+ 	   case '-': if ((*(p+1) == '>') && (!next_condition)){
+ 		        is_save = (*p == '-');
+ 			p += 2;
+ 		     }
+ 		     else
+ 			error++;
+ 		     done++;
+ 		     break;
+ 	   default : done++;
+ 		     error++;
+ 		     break;
+ 	}
+   }
+   *len = p - data;
+   return error ? -1 : (*cvalue ? 1 : 0);
+ }
+ 
+ TOKEN_VALUE *
+ parse_group_data (char *data, int *error)
+ {
+   TOKEN_VALUE *rvalue;
+   char *p;
+   int offset, err = 0;
+ 
+   if(error)
+     *error = 0;
+ 
+   if (!data)
+      return (TOKEN_VALUE *) NULL;
+ 
+   rvalue = (TOKEN_VALUE *) alloc_mem(sizeof(TOKEN_VALUE));
+   if (p = advance_to_char(data,';', STRICTLY, &offset)){
+       rvalue->testxt = cpystr(p);
+       data += strlen(p) + 1 + offset;
+       rvalue->next   = parse_group_data(data, error);
+   }
+   else if (p = advance_to_char(data,'}', STRICTLY, NULL))
+       rvalue->testxt = cpystr(p);
+   else if (data && *data == '}')
+       rvalue->testxt = cpystr("");
+   else{
+       err++;
+       free_token_value(&rvalue);
+   }
+   if (error)
+     *error += err;
+   return(rvalue);
+ }
+ 
+ CONDITION_S *
+ fill_condition(char *data)
+ {
+   CONDITION_S *condition;
+   int i, done, error = 0;
+   char *group;
+ 
+   for (i = 0, done = 0; !done && (i < NTOKENS); i++)
+       done = strncmp(data,token_rules[i], strlen(token_rules[i])) ? 0 : 1;
+   if (done){
+      condition = (CONDITION_S *) alloc_mem(sizeof(CONDITION_S));
+      condition->tname = cpystr(token_rules[--i]);
+   }
+   else
+      return (CONDITION_S *)NULL;
+ 
+   data += strlen(token_rules[i]);
+   for (; *data && *data == ' '; data++);
+   if (*data){
+      for (i = 0, done = 0; !done && (i < NREL); i++)
+        done = strncmp(data, rel_rules_test[i].value, 2) ? 0 : 1;
+      if (done)
+        condition->ttype = rel_rules_test[--i].ttype;
+      else{
+ 	 free_condition(&condition);
+ 	 return (CONDITION_S *) NULL;
+      }
+   }
+   data += 2;
+   for (; *data && *data == ' '; data++);
+   if (*data++ != '{'){
+      free_condition(&condition);
+      return (CONDITION_S *) NULL;
+   }
+   group = advance_to_char(data,'}', STRICTLY, &error); 
+   if (group || (!group &&  error < 0)){
+      condition->value = parse_group_data(data, &error);
+      if(group && error)
+ 	free_condition(&condition);
+      if(group)
+         fs_give((void **) &group);
+   }
+   else
+      free_condition(&condition);
+   return condition;
+ }
+ 
+ /* eoc = end of condition, equal to -1 on error */
+ CONDITION_S *
+ parse_condition (char *data, int *eoc)
+ {
+   CONDITION_S *condition = NULL;
+   char *p = data, *cvalue;
+   int len, error = 0, rv;
+ 
+   if((rv = isolate_condition(data, &cvalue, &len)) > 0){
+     if(condition = fill_condition(cvalue))
+        condition->next = parse_condition(data+len, eoc);
+     else
+        error++;
+   }
+   *eoc += len;
+   if (error)
+     *eoc = -1;
+   return condition;
+ }
+ 
+ RULEACTION_S *
+ parse_action (char *data, int context)
+ {
+   int i, done;
+   RULEACTION_S *raction = NULL;
+   char *function, *p = data;
+ 
+   if (!p)
+      return (RULEACTION_S *) NULL;
+ 
+   for (; *p && *p == ' '; p++);
+   if (!*p)
+      return (RULEACTION_S *) NULL;
+ 
+   if (is_save){
+      raction = (RULEACTION_S *) alloc_mem(sizeof(RULEACTION_S));
+      raction->function = cpystr("_SAVE_");
+      raction->value    = (TOKEN_VALUE *) alloc_mem(sizeof(TOKEN_VALUE));
+      raction->context |= FOR_SAVE;
+      raction->exec     = extended_value;
+      raction->value->testxt = cpystr(p);
+      return raction;
+   }
+   for (i = 0, done = 0; !done && (i < NFCN); i++)
+        done = (strstr(p,rule_fcns[i].name) == p);
+   p += done ? strlen(rule_fcns[--i].name) + 1 : 0;
+   if(!*p || (rule_fcns[i].what_for && !(rule_fcns[i].what_for & context)))
+      return (RULEACTION_S *) NULL;
+   if (done){
+      raction = (RULEACTION_S *) alloc_mem(sizeof(RULEACTION_S));
+ 	/* We assign raction->token to be subject. This is not necessary for
+ 	   most rules. It is done only for rules that need it and will not
+ 	   make any difference in rules that do not need it. It will hopefully
+ 	   reduce complexity in the language
+ 	 */
+      raction->token    = cpystr(SUBJ_TOKEN);
+      raction->function = cpystr(rule_fcns[i].name);
+      raction->context  = rule_fcns[i].what_for;
+      raction->exec     = rule_fcns[i].execute;
+      raction->value    = (TOKEN_VALUE *) alloc_mem(sizeof(TOKEN_VALUE));
+      raction->value->testxt = advance_to_char(p,'}', STRICTLY, NULL);
+      if(!raction->value->testxt)
+        free_ruleaction(&raction);
+      return raction;
+   }
+ 
+   done = (((function = strstr(p, "_TRIM_")) != NULL)
+ 	  ? 1 : ((function = strstr(p, "_COPY_")) != NULL)
+ 	  ? 2 : ((function = strstr(p, "_EXEC_")) != NULL)
+ 	  ? 3 : ((function = strstr(p, "_REXTRIM_")) != NULL)
+ 	  ? 4 : ((function = strstr(p, "_REPLACE_")) != NULL)
+ 	  ? 5 : 0);
+ 
+   if(!function)
+      return (RULEACTION_S *) NULL;
+ 
+   *function = '\0';
+    raction = (RULEACTION_S *) alloc_mem(sizeof(RULEACTION_S));
+    raction->token = get_name_token(p);
+   *function = '_';
+    p += strlen(raction->token) + 1;
+    for (; *p && *p == ' '; p++);
+    if (!strncmp(p,":=",2))
+       p += 2;
+    else{
+       free_ruleaction(&raction);
+       return (RULEACTION_S *) NULL;
+    }
+    for (; *p && *p == ' '; p++);
+    if (p != function){
+       free_ruleaction(&raction);
+       return (RULEACTION_S *) NULL;
+    }
+    p += done <= 3 ? 6 : 9; /* 6 = strlen("_EXEC_"), 9 = strlen("_REPLACE_") */
+    if (*p != '{'){
+       free_ruleaction(&raction);
+       return (RULEACTION_S *) NULL;
+    }
+    *p = '\0';
+    for(i = 0; i < NFCN && strcmp(function, rule_fcns[i].name);i++);
+    raction->function   = cpystr(function);
+    raction->is_trim    = strcmp(function,"_TRIM_")    ? 0 : 1;
+    raction->is_rextrim = strcmp(function,"_REXTRIM_") ? 0 : 1;
+    raction->is_replace = strcmp(function,"_REPLACE_") ? 0 : 1;
+    raction->context  = rule_fcns[i].what_for;
+    raction->exec     = rule_fcns[i].execute;
+    *p++ = '{';
+    if((raction->value = parse_group_data(p, NULL)) == NULL 
+ 	|| raction->value->testxt == NULL)
+       free_ruleaction(&raction);
+    if(raction && raction->is_rextrim)
+       parse_patterns_into_action(&raction->value);
+    return raction;
+ }
+ 
+ RULE_S *
+ parse_rule (char *data, int context)
+ {
+   RULE_S *prule;	/*parsed rule */
+   int len = 0;
+   
+   if (!(prule = (RULE_S *) alloc_mem(sizeof(RULE_S))) ||
+ 	!(prule->condition = parse_condition(data, &len)) ||
+ 	!(prule->action = parse_action(data+len, context)))
+       free_rule(&prule);
+ 
+   return prule;
+ }
+ 
+ RULELIST *
+ get_rule_list(char **list, int context, int i)
+ {
+   RULE_S *rule;
+   RULELIST *trulelist = NULL;
+ 
+   if (list[i] && *list[i]){
+      if(rule = parse_rule(list[i], context)){
+ 	trulelist  = (RULELIST *)alloc_mem(sizeof(RULELIST));
+ 	trulelist->prule = rule;
+ 	trulelist->next = get_rule_list(list, context, i+1);
+      }
+      else
+ 	trulelist = get_rule_list(list, context, i+1);
+   }
+   return trulelist;
+ }
+ 
+ PRULELIST_S *
+ add_prule(PRULELIST_S *rule_list, PRULELIST_S *rule)
+ {
+    if (!rule_list)
+       rule_list = (PRULELIST_S *) alloc_mem(sizeof(PRULELIST_S));
+ 
+    if(rule_list->next)
+      rule_list->next = add_prule(rule_list->next, rule);
+    else{
+      if (rule_list->rlist)
+ 	rule_list->next = rule;
+      else
+ 	rule_list = rule;
+    }
+    return rule_list;
+ }  
+ 
+ void
+ add_rule(int code, int context)
+ {
+   char **list = ps_global->vars[code].current_val.l;
+   PRULELIST_S *prulelist, *trulelist, *orulelist;
+ 
+   if (list && *list && **list){
+      trulelist = (PRULELIST_S *)alloc_mem(sizeof(PRULELIST_S));
+      trulelist->varnum = code;
+      if (trulelist->rlist = get_rule_list(list, context, 0))
+         ps_global->rule_list = add_prule(ps_global->rule_list, trulelist);
+      else
+ 	free_parsed_rule_list(&trulelist);
+   }
+ }
+ 
+ /* see create_rule_list below */
+ void
+ set_rule_list(struct variable *vars)
+ {
+     set_current_val(&vars[V_THREAD_DISP_STYLE_RULES], TRUE, TRUE);
+     set_current_val(&vars[V_THREAD_INDEX_STYLE_RULES], TRUE, TRUE);
+     set_current_val(&vars[V_COMPOSE_RULES], TRUE, TRUE);
+     set_current_val(&vars[V_FORWARD_RULES], TRUE, TRUE);
+     set_current_val(&vars[V_INDEX_RULES], TRUE, TRUE);
+     set_current_val(&vars[V_KEY_RULES], FALSE, TRUE);
+     set_current_val(&vars[V_REPLACE_RULES], TRUE, TRUE);
+     set_current_val(&vars[V_REPLY_INDENT_RULES], TRUE, TRUE);
+     set_current_val(&vars[V_REPLY_LEADIN_RULES], TRUE, TRUE);
+     set_current_val(&vars[V_RESUB_RULES], TRUE, TRUE);
+     set_current_val(&vars[V_SAVE_RULES], TRUE, TRUE);
+     set_current_val(&vars[V_SMTP_RULES], TRUE, TRUE);
+     set_current_val(&vars[V_SORT_RULES], TRUE, TRUE);
+     set_current_val(&vars[V_STARTUP_RULES], TRUE, TRUE);
+ }
+ 
+ /* see set_rule_list above */
+ void
+ create_rule_list(struct variable *vars)
+ {
+   set_rule_list(vars);
+   add_rule(V_THREAD_DISP_STYLE_RULES, FOR_THREAD);
+   add_rule(V_THREAD_INDEX_STYLE_RULES, FOR_THREAD);
+   add_rule(V_COMPOSE_RULES, FOR_COMPOSE);
+   add_rule(V_FORWARD_RULES, FOR_COMPOSE);
+   add_rule(V_INDEX_RULES, FOR_INDEX);
+   add_rule(V_KEY_RULES, FOR_KEY);
+   add_rule(V_REPLACE_RULES, FOR_REPLACE);
+   add_rule(V_REPLY_INDENT_RULES, FOR_COMPOSE);
+   add_rule(V_REPLY_LEADIN_RULES, FOR_REPLY_INTRO);
+   add_rule(V_RESUB_RULES, FOR_RESUB|FOR_TRIM);
+   add_rule(V_SAVE_RULES, FOR_SAVE);
+   add_rule(V_SMTP_RULES, FOR_COMPOSE);
+   add_rule(V_SORT_RULES, FOR_SORT);
+   add_rule(V_STARTUP_RULES, FOR_STARTUP);
+ }
+ 
+ int
+ condition_contains_token(CONDITION_S *condition, char *token)
+ {
+   return condition ? (!strcmp(condition->tname, token) 
+ 			? 1
+ 			: condition_contains_token(condition->next, token)) 
+ 		    : 0;
+ }
+ 
+ RULELIST *
+ get_rulelist_from_code(int code, PRULELIST_S *list)
+ {
+   return list ? (list->varnum == code ? list->rlist 
+ 			      : get_rulelist_from_code(code, list->next))
+ 	      : (RULELIST *) NULL;
+ }   
+ 
+ char *
+ test_rule(RULELIST *rlist, int ctxt, ENVELOPE *env, int *n)
+ {
+   char *result;
+ 
+   if(!rlist)
+      return NULL;
+ 
+   if (result = process_rule(rlist->prule, ctxt, env))
+       return result;
+   else{
+        (*n)++;
+        return test_rule(rlist->next, ctxt, env, n);
+   } 
+ }
+ 
+ RULE_S *
+ get_rule (RULELIST *rule, int n)
+ {
+   return rule ? (n ? get_rule(rule->next, n-1) : rule->prule) 
+ 	      : (RULE_S *) NULL;
+ }
+ 
+ /* get_result_rule:
+  * Parameters: list: the list of rules to be passed to the function to check
+  *             rule_context: context of the rule
+  *             env : envelope used to check the rule, if needed.
+  *
+  * Returns: The value of the first rule that is satisfied in the list, or
+  *          NULL if not. This function should be called in the following 
+  *          way (notice that memory is freed by caller).
+  *
+  * You should use this function to obtain the result of a rule. You can
+  * also call directly "process_rule", but I advice to use this function if
+  * there's no difference on which function to call.
+ 
+    RULE_RESULT *rule;
+ 
+    rule = (RULE_RESULT *) 
+            get_result_rule(V_SOME_RULE, context, envelope);
+ 
+    if (rule){ 
+        assign the value of rule->result;
+        if (rule->result)
+           fs_give((void **)&rule->result);
+        fs_give((void **)&rule);
+    }
+  */
+ 
+ RULE_RESULT *
+ get_result_rule(int code, int rule_context, ENVELOPE *env)
+ {
+     char  *rule_result;
+     RULE_RESULT *rule = NULL;
+     RULELIST *rlist;
+     int n = 0;
+ 
+     if(!(rule_context & FOR_RULE))
+       rule_context |= FOR_RULE;
+     rlist = get_rulelist_from_code(code, ps_global->rule_list);
+     if (rlist){
+        rule_result = test_rule(rlist, rule_context, env, &n);
+        if (rule_result && *rule_result){
+           rule = (RULE_RESULT *) fs_get (sizeof(RULE_RESULT));
+           rule->result = rule_result;
+           rule->number = n;
+        }
+     }
+     return rule;
+ }
+ 
+ char *get_rule_result(int rule_context, char *newfolder, int code)
+ {   
+     char        *rule_result = NULL;
+     ENVELOPE    *news_envelope;
+     RULE_RESULT *rule;
+ 
+     if (IS_NEWS(ps_global->mail_stream)){
+        news_envelope = mail_newenvelope();
+        news_envelope->newsgroups = cpystr(newfolder);
+     }
+     else
+        news_envelope = NULL;
+ 
+     rule = get_result_rule(code, rule_context, news_envelope);
+ 
+     if (news_envelope)
+         mail_free_envelope (&news_envelope);
+ 
+     if (rule){
+         rule_result = cpystr(rule->result);
+         if (rule->result)
+           fs_give((void **)&rule->result);
+         fs_give((void **)&rule);
+     }
+     return rule_result;
+ }
+ 
+ /* process_rule:
+    Parameters: rule_data, is a rule. It's obtained as
+                 rule_data = ps_global->VAR_SOME_RULE[n], for
+                 some integer n
+                 rule_context: context of the rule, and
+                 env: An envelope if needed.
+ 
+    Returns   : The value of the processed rule_data if the processing was 
+                successful and matches context and possibly the envelope, or
+                NULL if there's no match
+  */
+ 
+ char *
+ process_rule (RULE_S *prule, int rule_context, ENVELOPE *env)
+ {
+     char *result = NULL;
+     int rv;
+     CONDITION_S *condition;
+ 
+    if(!prule)
+      return NULL;
+ 
+    if(!(rule_context & FOR_RULE))
+       rule_context |= FOR_RULE;
+ 
+    for(condition = prule->condition; 
+ 		   condition && 
+ 		   (rv = test_condition(condition, rule_context, env));
+ 		   condition = condition->next);
+ 
+    if(rv && !condition)
+       result = (prule->action->exec)(prule->action, rule_context, env);
+ 
+    return result;
+ }
+ 
+ TOKEN_VALUE *
+ copy_parsed_value(TOKEN_VALUE *value, int ctxt, ENVELOPE *env)
+ {
+    TOKEN_VALUE *tval = NULL;
+ 
+    if(!value)
+       return NULL;
+ 
+    if(value->testxt){
+      tval = (TOKEN_VALUE *) alloc_mem(sizeof(TOKEN_VALUE));
+      tval->testxt = detoken_src(value->testxt, ctxt, env, NULL, NULL, NULL);
+      tval->voidtxt = value->voidtxt;
+      tval->codefcn = value->codefcn;     
+    }
+    if(value->next)
+      tval->next = copy_parsed_value(value->next, ctxt, env);
+ 
+    return tval;
+ }
+ 
+ void
+ free_parsed_value(TOKEN_VALUE **value)
+ {
+    TOKEN_VALUE *tval = NULL;
+ 
+    if(!*value)
+       return;
+ 
+    if((*value)->testxt)
+      fs_give((void **)&(*value)->testxt);
+ 
+    if((*value)->next)
+      free_parsed_value(&(*value)->next);
+ 
+     fs_give((void **)value);
+ }
+ 
+ 
+ int
+ test_condition(CONDITION_S *condition, int rule_context, ENVELOPE *env)
+ {
+    int next_step;
+    TOKEN_VALUE *group;
+ 
+    group = copy_parsed_value(condition->value, rule_context, env);
+    next_step = (*rel_rules_test[condition->ttype].execute)(condition, group, env, rule_context);
+    free_parsed_value(&group);
+    return next_step;
+ }
+ 
+ /* returns the name of the token it found or NULL if there is no token, the
+  * real value of the token is obtained by calling the detoken_src function.
+  */ 
+ 
+ char *
+ get_name_token (char *condition)
+ {
+   char *p = NULL, *q, *s;
+ 
+     if ((q = strchr(condition,'_')) && (s = strchr(q+1,'_'))){
+ 	char c = *++s;
+ 	*s = '\0';
+ 	 p = cpystr(q);
+ 	*s = c;
+     }
+     return p;
+ }
+ 
+ /* This function tests if a string contained in the variable "group" is
+  * in the "condition"
+  */
+ int test_in (CONDITION_S *condition, TOKEN_VALUE *group, ENVELOPE *env, 
+ 		int context)
+ {
+  int rv = 0;
+  char *test;
+  TOKEN_VALUE *test_group = group;
+ 
+  test = env && env->sparep && ((SPAREP_S *)env->sparep)->flag & USE_RAW_SP
+ 	? cpystr(((SPAREP_S *)env->sparep)->value)
+ 	: detoken_src(condition->tname, context, env, NULL, NULL, NULL);
+  if (test){
+     while (rv == 0 && test_group){
+        if(!*test || strstr(test_group->testxt, test))
+ 	  rv++;
+        else
+ 	  test_group = test_group->next;
+     }
+     fs_give((void **)&test);
+  }
+  return rv;
+ }
+ 
+ int test_ni (CONDITION_S *condition, TOKEN_VALUE *group, 
+ 		ENVELOPE *env, int context)
+ {
+  int rv = 0;
+  char *test;
+  TOKEN_VALUE *test_group = group;
+ 
+  test = env && env->sparep && ((SPAREP_S *)env->sparep)->flag & USE_RAW_SP
+ 	? cpystr(((SPAREP_S *)env->sparep)->value)
+ 	: detoken_src(condition->tname, context, env, NULL, NULL, NULL);
+  if (test){
+     if(!test_group)
+       rv++;
+     while (rv == 0 && test_group){
+        if(!*test_group->testxt || strstr(test, test_group->testxt))
+ 	  rv++;
+        else
+ 	  test_group = test_group->next;
+     }
+     fs_give((void **)&test);
+  }
+  return rv;
+ }
+ 
+ int test_not_in (CONDITION_S *condition, TOKEN_VALUE *group, 
+ 		ENVELOPE *env, int context)
+ {
+  return !test_in(condition, group, env, context);
+ }
+ 
+ int test_not_ni (CONDITION_S *condition, TOKEN_VALUE *group, 
+ 		ENVELOPE *env, int context)
+ {
+  return !test_ni(condition, group, env, context);
+ }
+ 
+ int test_eq (CONDITION_S *condition, TOKEN_VALUE *group, 
+ 		ENVELOPE *env, int context)
+ {
+  int rv = 0;
+  char *test;
+  TOKEN_VALUE *test_group = group;
+ 
+  test = env && env->sparep && ((SPAREP_S *)env->sparep)->flag & USE_RAW_SP
+ 	? cpystr(((SPAREP_S *)env->sparep)->value)
+ 	:detoken_src(condition->tname, context, env, NULL, NULL, NULL);
+  if (test){
+     while (rv == 0 && test_group){
+        if((!*test && !*test_group->testxt) || !strcmp(test_group->testxt, test))
+ 	  rv++;
+        else
+ 	  test_group = test_group->next;
+     }
+     fs_give((void **)&test);
+  }
+  return rv;
+ }
+ 
+ int test_not_eq (CONDITION_S *condition, TOKEN_VALUE *group, 
+ 		ENVELOPE *env, int context)
+ {
+  return !test_eq(condition, group, env, context);
+ }
+ 
+ char *
+ do_trim (char *test, TOKEN_VALUE *tval)
+ {
+    char *begin_text;
+    int offset = 0;
+ 
+    if (!tval)
+       return test;
+ 
+    while(begin_text = strstr(test+offset,tval->testxt)){
+       strcpy(begin_text, begin_text+strlen(tval->testxt));
+       offset = begin_text - test;
+    }
+ 
+    return do_trim(test, tval->next);
+ }
+ 
+ char *
+ trim (RULEACTION_S *action, int context, ENVELOPE *env)
+ {
+  char *begin_text, *test;
+  RULEACTION_S *taction = action;
+  int offset;
+ 
+  if (taction->context & context){
+     if (test = detoken_src(taction->token, context, env, NULL, NULL, NULL))
+        test = do_trim(test, taction->value);
+     return test;
+  }
+  return NULL;
+ }
+ 
+ 
+ char *
+ do_rextrim (char *test, TOKEN_VALUE *tval)
+ {
+    char *begin_text, *trim_text;
+    int offset = 0;
+ 
+    if (!tval)
+       return test;
+ 
+    trim_text = expand(test, tval->voidtxt);
+    while(trim_text && (begin_text = strstr(test+offset,trim_text))){
+       strcpy(begin_text, begin_text+strlen(trim_text));
+       offset = begin_text - test;
+    }
+ 
+    return do_rextrim(test, tval->next);
+ }
+ 
+ char *
+ rextrim (RULEACTION_S *action, int context, ENVELOPE *env)
+ {
+  char *test = NULL;
+  RULEACTION_S *taction = action;
+ 
+  if (taction->context & context &&
+     (test = detoken_src(taction->token, context, env, NULL, NULL, NULL)))
+ 	test = do_rextrim(test, taction->value);
+  return test;
+ }
+ 
+ char *
+ raw_value (RULEACTION_S *action, int context, ENVELOPE *env)
+ {
+ return (action->context & context) ? cpystr(action->value->testxt) : NULL;
+ }
+ 
+ char *
+ extended_value (RULEACTION_S *action, int ctxt, ENVELOPE *env)
+ {
+ return (action->context & ctxt) 
+ 	? detoken_src(action->value->testxt, ctxt, env, NULL, NULL, NULL)
+ 	: NULL;
+ }
+ 
+ /* advances given_string until it finds given_char  */
+ char *
+ advance_to_char(char *given_string, char given_char, int flag, int *error) 
+ {
+    char *b, *s, c;
+    int i, err  = 0, quoted ;
+ 
+    if (error)
+       *error = 0;
+ 
+    if (!given_string || !*given_string)
+        return NULL;
+ 
+    b = s = cpystr(given_string);
+    for(i = 0, quoted = 0, c = *s; c ; c = *++s){
+       if(c == '\\'){
+ 	 quoted++;
+ 	 continue;
+       }
+       if(quoted){
+ 	quoted = 0;
+ 	if (c == given_char){
+ 	  err += flag & STRICTLY ? 0 : 1;
+ 	  err++;
+ 	  break;
+ 	}
+ 	b[i++] = '\\';
+       }
+       if(c == given_char){
+ 	 err += flag & STRICTLY ? 0 : 1;
+ 	 break;
+       }
+       b[i++] = c;
+    }
+    b[i] = '\0';
+    if (b && (strlen(b) == strlen(given_string)) && (flag & STRICTLY))
+       return NULL;   /* character not found */
+ 
+    if(b && !*b){
+      fs_give((void **)&b);
+      err = -1;
+    }
+ 
+    if (error)
+       *error = err;
+ 
+    return b;
+ }
+ 
+ /* Regular Expressions Support */
+ char *
+ expand (char *string, void *pattern)
+ {
+  char c, *ret_string = NULL;
+  regmatch_t pmatch;
+  
+   if((regex_t *)pattern == NULL)
+      return NULL;
+ 
+   if(regexec((regex_t *)pattern, string , 1, &pmatch, 0) == 0 
+ 	&& pmatch.rm_so < pmatch.rm_eo){
+       c = string[pmatch.rm_eo];
+       string[pmatch.rm_eo] = '\0';
+       ret_string = cpystr(string+pmatch.rm_so);
+       string[pmatch.rm_eo] = c;
+   }
+   return ret_string;
+ }
+ 
+ 
+ char *
+ exec_fcn (RULEACTION_S *action, int ctxt, ENVELOPE *env)
+ {
+   STORE_S *output_so;
+   gf_io_t	gc, pc;
+   char *status, *rv, *cmd, *test;
+ 
+   if(!(action->context & ctxt))
+     return NULL;
+ 
+   if((test = detoken_src(action->token, ctxt, env, NULL, NULL, NULL)) != NULL)
+     gf_set_readc(&gc, test, (unsigned long)strlen(test), CharStar, 0);
+ 
+   if((output_so = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL)
+      gf_set_so_writec(&pc, output_so);
+ 
+   cmd = (char *)fs_get((strlen(action->value->testxt) + strlen("_TMPFILE_") + 2)*sizeof(char));
+   sprintf(cmd,"%s _TMPFILE_", action->value->testxt);
+   status = (*ps_global->tools.exec_rule)(cmd, gc, pc);
+ 
+   so_seek(output_so, 0L, 0);
+   rv = cpystr(output_so->dp);
+   gf_clear_so_writec(output_so);
+   so_give(&output_so);
+   if(test)
+     fs_give((void **)&test);
+ 
+   return status ? NULL : rv;
+ }
+ 
+ ENVELOPE *
+ rules_fetchenvelope(INDEXDATA_S *idata, int *we_clear)
+ {
+   ENVELOPE *env;
+ 
+   if (idata->no_fetch){
+      if(we_clear)
+         *we_clear = 1;
+     env = mail_newenvelope();
+     env->from     = copyaddrlist(idata->from);
+     env->to       = copyaddrlist(idata->to);
+     env->cc       = copyaddrlist(idata->cc);
+     env->sender   = copyaddrlist(idata->sender);
+     env->subject  = cpystr(idata->subject);
+     env->date     = cpystr((unsigned char *) idata->date);
+     env->newsgroups = cpystr(idata->newsgroups);
+     return env;
+   }
+   if(we_clear)
+      *we_clear = 0;
+   env = pine_mail_fetchenvelope(idata->stream, idata->rawno);
+   return env;
+ }
diff -rc alpine-2.00/pith/rules.h alpine-2.00.I.USE/pith/rules.h
*** alpine-2.00/pith/rules.h	2011-02-07 20:34:02.000000000 -0800
--- alpine-2.00.I.USE/pith/rules.h	2011-02-07 20:33:42.000000000 -0800
***************
*** 0 ****
--- 1,151 ----
+ /* Included file rules.h */
+ 
+ #ifndef PITH_RULES_INCLUDED
+ #define PITH_RULES_INCLUDED
+ 
+ #include "../pith/conftype.h"
+ #include "../pith/detoken.h"
+ #include "../pith/indxtype.h"
+ #include "../pith/rulestype.h"
+ 
+ int is_save;	/* this rule has the form condition -> folder */
+ 
+ /* Exported prototypes */
+ 
+ void  create_rule_list (struct variable *);
+ SPAREP_S *get_sparep_for_rule(char *, int);
+ void  free_sparep_for_rule(void **);
+ void  free_parsed_rule_list (PRULELIST_S **);
+ RULE_RESULT *get_result_rule (int, int, ENVELOPE *);
+ char  *get_rule_result (int , char *, int);
+ char  *process_rule   (RULE_S *, int, ENVELOPE *);
+ char  **functions_for_token (char *);
+ RULELIST *get_rulelist_from_code (int, PRULELIST_S *);
+ RULE_S   *get_rule  (RULELIST *, int);
+ int   condition_contains_token (CONDITION_S *, char *);
+ int   context_for_function (char *);
+ ENVELOPE *rules_fetchenvelope(INDEXDATA_S *idata, int *we_clear);
+ 
+ /* Separators:
+  *
+  * A separator is a string that separates the rule condition with the rule
+  * action. Below is the list of separators
+  *
+  */
+ 
+ #define  SAVE_TO_SEP  "->"
+ #define  APPLY_SEP    "=>"
+ 
+ /*------- Definitions of tokens -------*/
+ /*------ Keep the list alphabetically sorted, thanks -------*/
+ 
+ #define ADDR_TOKEN	"_ADDRESS_"
+ #define ADDCC_TOKEN	"_ADDRESSCC_"
+ #define ADDRECIP_TOKEN	"_ADDRESSRECIPS_"
+ #define ADDTO_TOKEN	"_ADDRESSTO_"
+ #define BCC_TOKEN	"_BCC_"
+ #define CC_TOKEN	"_CC_"
+ #define COLLECT_TOKEN	"_COLLECTION_"
+ #define FLAG_TOKEN	"_FLAG_"
+ #define FOLDER_TOKEN	"_FOLDER_"
+ #define FADDRESS_TOKEN	"_FORWARDADDRESS_"
+ #define FFROM_TOKEN	"_FORWARDFROM_"
+ #define FROM_TOKEN	"_FROM_"
+ #define KEY_TOKEN	"_PKEY_"
+ #define LCC_TOKEN	"_LCC_"
+ #define NICK_TOKEN	"_NICK_"
+ #define OTEXT_TOKEN	"_OPENINGTEXT_"
+ #define OTEXTNQ_TOKEN	"_OPENINGTEXTNQ_"
+ #define PROCID_TOKEN	"_PROCID_"
+ #define ROLE_TOKEN	"_ROLE_"
+ #define SCREEN_TOKEN	"_SCREEN_"
+ #define SEND_TOKEN	"_SENDER_"
+ #define SUBJ_TOKEN	"_SUBJECT_"
+ #define THDDSPSTY_TOKEN	"_THREADSTYLE_"
+ #define THDNDXSTY_TOKEN	"_THREADINDEX_"
+ #define TO_TOKEN	"_TO_"
+ 
+ /*------ Definitions of relational operands -------------*/
+ 
+ typedef struct {
+         char       *value;
+ 	TestType    ttype;
+         int        (*execute)();
+ } REL_TOKEN;
+ 
+ /* Relational Operands */
+ #define AND_REL     "&&"        /* For putting more than one condition  */
+ #define IN_REL      "<<"        /* For belonging relation */
+ #define NI_REL      ">>"        /* For contain relation   */
+ #define NOT_IN_REL  "!<"        /* Negation of IN_REL   */
+ #define NOT_NI_REL  "!>"        /* Negation of NI_REL   */
+ #define EQ_REL      "=="        /* Test of equality     */
+ #define NOT_EQ_REL  "!="        /* Test of inequality   */
+ #define OPEN_SET    "{"         /* Braces to open a set */
+ #define CLOSE_SET   "}"         /* Braces to close a set*/
+ 
+ /*--- Context in which these variables can be used ---*/
+ 
+ typedef struct use_context {
+     char        *name;
+     int          what_for;
+ } USE_IN_CONTEXT;
+ 
+ 
+ static USE_IN_CONTEXT tokens_use[] = {
+     {NICK_TOKEN,	FOR_SAVE},
+     {FROM_TOKEN,	FOR_SAVE},
+     {OTEXT_TOKEN,	FOR_SAVE|FOR_FOLDER},
+     {OTEXTNQ_TOKEN,	FOR_SAVE|FOR_FOLDER},
+     {ROLE_TOKEN,	FOR_COMPOSE},
+     {FOLDER_TOKEN,	FOR_SAVE|FOR_FOLDER|FOR_THREAD|FOR_COMPOSE},
+     {SUBJ_TOKEN,	FOR_SAVE|FOR_FOLDER|FOR_COMPOSE},
+     {FLAG_TOKEN,	FOR_SAVE|FOR_FLAG},
+     {COLLECT_TOKEN,	FOR_SAVE|FOR_COMPOSE|FOR_FOLDER|FOR_THREAD},
+     {THDDSPSTY_TOKEN,	FOR_THREAD},
+     {THDNDXSTY_TOKEN,	FOR_THREAD},
+     {ADDR_TOKEN,	FOR_SAVE|FOR_FOLDER},
+     {TO_TOKEN,		FOR_SAVE},
+     {ADDTO_TOKEN,	FOR_SAVE|FOR_COMPOSE},
+     {ADDCC_TOKEN,	FOR_SAVE|FOR_COMPOSE},
+     {ADDRECIP_TOKEN,	FOR_SAVE|FOR_COMPOSE},
+     {SCREEN_TOKEN,	FOR_KEY},
+     {KEY_TOKEN,		FOR_KEY},
+     {SEND_TOKEN,	FOR_SAVE},
+     {CC_TOKEN,		FOR_SAVE},
+     {BCC_TOKEN,		FOR_COMPOSE},
+     {LCC_TOKEN,		FOR_COMPOSE},
+     {FFROM_TOKEN,	FOR_COMPOSE},
+     {FADDRESS_TOKEN,	FOR_COMPOSE},
+     {NULL,		FOR_NOTHING}
+ };
+ 
+ 
+ typedef struct {
+         char         *name;
+         char*        (*execute)();
+         int          what_for;
+ } RULE_FCN;
+ 
+ #define COMMAND_FCN	"_COMMAND_"
+ #define COPY_FCN	"_COPY_"
+ #define EXEC_FCN	"_EXEC_"
+ #define INDEX_FCN       "_INDEX_"
+ #define REPLACE_FCN     "_REPLACE_"
+ #define REPLYSTR_FCN    "_RESTR_"
+ #define REPLY_FCN       "_REPLY_"
+ #define RESUB_FCN       "_RESUB_"
+ #define REXTRIM_FCN	"_REXTRIM_"
+ #define SAVE_FCN        "_SAVE_"
+ #define SIGNATURE_FCN   "_SIGNATURE_"
+ #define SMTP_FCN        "_SMTP_"
+ #define SORT_FCN        "_SORT_"
+ #define STARTUP_FCN     "_STARTUP_"
+ #define THRDSTYLE_FCN   "_THREADSTYLE_"
+ #define THRDINDEX_FCN   "_THREADINDEX_"
+ #define TRIM_FCN        "_TRIM_"
+ 
+ #define STRICTLY  0x1
+ #define RELAXED 0x2
+ 
+ #endif 	/* PITH_RULES_INCLUDED */
diff -rc alpine-2.00/pith/rulestype.h alpine-2.00.I.USE/pith/rulestype.h
*** alpine-2.00/pith/rulestype.h	2011-02-07 20:34:02.000000000 -0800
--- alpine-2.00.I.USE/pith/rulestype.h	2011-02-07 20:33:42.000000000 -0800
***************
*** 0 ****
--- 1,78 ----
+ #ifndef PITH_RULESTYPE_INCLUDED
+ #define PITH_RULESTYPE_INCLUDED
+ 
+ typedef struct rule {
+ 	char *result;	/* The result of the rule */
+ 	int number;	/* The number of the rule that succeded, -1 if not */
+ } RULE_RESULT;
+ 
+ typedef struct {
+         char    *value;
+         int     type;
+ } RULE_ACTION;
+ 
+ 
+ #define TOKEN_VALUE	struct tokenvalue_s
+ #define CONDITION_S	struct condition_s
+ #define RULEACTION_S	struct ruleaction_s
+ #define RULE_S		struct rule_s
+ #define RULELIST	struct rulelist_s
+ #define PRULELIST_S	struct parsedrulelist_s
+ 
+ #define FREEREGEX	1
+ 
+ TOKEN_VALUE {
+ 	char	*testxt;
+ 	void	*voidtxt;
+ 	int	codefcn;
+ 	TOKEN_VALUE *next;
+ };
+ 
+ typedef enum {Equal, Subset, Includes,
+ 		NotEqual, NotSubset, NotIncludes,
+ 		EndTypes} TestType;
+ 
+ CONDITION_S {
+     char	*tname;		/* tname ttype {value} */
+     TestType	ttype;		/* tname ttype {value} */
+     TOKEN_VALUE	*value;		/* value to check against */
+     CONDITION_S	*next;		/* next condition to test */
+ };
+ 
+ RULEACTION_S {
+    char *token;		/* token := function{value} or token = null  */
+    char *function;	/* token := function{value} or simply function{value}*/
+    TOKEN_VALUE  *value; /* token := function{value} or simply function{value}*/
+    int   context;	/* context in which this rule can be used */
+    char* (*exec)();
+    unsigned int is_trim:1;
+    unsigned int is_rextrim:1;
+    unsigned int is_replace:1;
+ };
+ 
+ RULE_S {
+   CONDITION_S  *condition;
+   RULEACTION_S *action;
+ };
+ 
+ RULELIST {
+    RULE_S *prule;
+    RULELIST *next;
+ };
+ 
+ PRULELIST_S {
+    int varnum;		/* number associated to the variable */
+    RULELIST *rlist;
+    PRULELIST_S *next;
+ };
+ 
+ #define USE_RAW_SP      0x001
+ #define PROCESS_SP      0x010
+ 
+ typedef struct sparep {
+    int flag;
+    char *value;
+ } SPAREP_S;
+ 
+ 
+ #endif	/* PITH_RULESTYPE_INCLUDED */
diff -rc alpine-2.00/pith/save.c alpine-2.00.I.USE/pith/save.c
*** alpine-2.00/pith/save.c	2008-05-02 14:58:34.000000000 -0700
--- alpine-2.00.I.USE/pith/save.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 421,426 ****
--- 421,427 ----
  {
      int		  rv, rc, j, our_stream = 0, cancelled = 0;
      int           delete, filter, k, worry_about_keywords = 0;
+     int		  flags_for_save = F_ANS|F_FWD|F_FLAG|F_SEEN|F_KEYWORD;
      char	 *save_folder, *seq, *flags = NULL, date[64], tmp[MAILTMPLEN];
      long	  i, nmsgs, rawno;
      size_t        len;
***************
*** 864,870 ****
  	    STRING msg;
  
  	    pkg.stream = stream;
! 	    pkg.flags = NULL;
  	    pkg.date = date;
  	    pkg.msg = &msg;
  	    pkg.msgmap = msgmap;
--- 865,871 ----
  	    STRING msg;
  
  	    pkg.stream = stream;
! 	    pkg.flags = flgs & SV_FIX_DELS ? NULL : cpystr("\\DELETED");
  	    pkg.date = date;
  	    pkg.msg = &msg;
  	    pkg.msgmap = msgmap;
***************
*** 938,944 ****
  	    mc = (rawno > 0L && stream && rawno <= stream->nmsgs)
  		    ? mail_elt(stream, rawno) : NULL;
  
! 	    flags = flag_string(stream, rawno, F_ANS|F_FWD|F_FLAG|F_SEEN|F_KEYWORD);
  	      
  	    if(mc && mc->day)
  	      mail_date(date, mc);
--- 939,946 ----
  	    mc = (rawno > 0L && stream && rawno <= stream->nmsgs)
  		    ? mail_elt(stream, rawno) : NULL;
  
! 	    flags_for_save |= flgs & SV_FIX_DELS ? 0 : F_DEL;
! 	    flags = flag_string(stream, rawno, flags_for_save);
  	      
  	    if(mc && mc->day)
  	      mail_date(date, mc);
***************
*** 946,952 ****
  	      *date = '\0';
  
  	    rv = save_fetch_append(stream, mn_m2raw(msgmap, i),
! 				   NULL, save_stream, save_folder, context,
  				   mc ? mc->rfc822_size : 0L, flags, date, so);
  
  	    if(flags)
--- 948,954 ----
  	      *date = '\0';
  
  	    rv = save_fetch_append(stream, mn_m2raw(msgmap, i),
! 				   NULL, save_stream, folder, context,
  				   mc ? mc->rfc822_size : 0L, flags, date, so);
  
  	    if(flags)
***************
*** 1043,1048 ****
--- 1045,1051 ----
      MESSAGECACHE *mc;
      char *fetch;
      int rc;
+     int flags_for_save = F_ANS|F_FWD|F_FLAG|F_SEEN|F_KEYWORD;
      unsigned long raw, hlen, tlen, mlen;
  
      if(pkg->so && (pkg->msgno > 0L)) {
***************
*** 1051,1060 ****
  		? mail_elt(pkg->stream, raw) : NULL;
  	if(mc){
  	    size = mc->rfc822_size;
! 	    if(pkg->flags)
  	      fs_give((void **) &pkg->flags);
! 
! 	    pkg->flags = flag_string(pkg->stream, raw, F_ANS|F_FWD|F_FLAG|F_SEEN|F_KEYWORD);
  	}
  
  	if(mc && mc->day)
--- 1054,1065 ----
  		? mail_elt(pkg->stream, raw) : NULL;
  	if(mc){
  	    size = mc->rfc822_size;
! 	    if(pkg->flags){
! 	      if(strstr(pkg->flags,"\\DELETED"))
! 	        flags_for_save |= F_DEL;
  	      fs_give((void **) &pkg->flags);
! 	    }
! 	    pkg->flags = flag_string(pkg->stream, raw, flags_for_save);
  	}
  
  	if(mc && mc->day)
***************
*** 1136,1141 ****
--- 1141,1147 ----
  		    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 -rc alpine-2.00/pith/send.c alpine-2.00.I.USE/pith/send.c
*** alpine-2.00/pith/send.c	2008-08-06 11:25:58.000000000 -0700
--- alpine-2.00.I.USE/pith/send.c	2011-02-07 20:33:43.000000000 -0800
***************
*** 43,48 ****
--- 43,49 ----
  #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"
***************
*** 52,58 ****
  /* 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},
    {"Reply-To",    Address,	0, 1, 1, 0},
    {TONAME,        Address,	1, 1, 1, 1},
    {CCNAME,        Address,	1, 1, 1, 1},
--- 53,59 ----
  /* name::type::canedit::writehdr::localcopy::rcptto */
  PINEFIELD pf_template[] = {
    {"X-Auth-Received",    FreeText,	0, 1, 1, 0},	/* N_AUTHRCVD */
!   {"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},
***************
*** 256,261 ****
--- 257,269 ----
  
      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);
+ 	    strcpy(tmp, tmp2);
+ 	}
+ #endif
  	if(!(IS_REMOTE(tmp) || is_absolute_path(tmp))){
  	    /*
  	     * The mbox is relative to the home directory.
***************
*** 1228,1234 ****
  	    *p = *(p+4);
  
          pf->type        = pf_template[i].type;
! 	pf->canedit     = pf_template[i].canedit;
  	pf->rcptto      = pf_template[i].rcptto;
  	pf->writehdr    = pf_template[i].writehdr;
  	pf->localcopy   = pf_template[i].localcopy;
--- 1236,1242 ----
  	    *p = *(p+4);
  
          pf->type        = pf_template[i].type;
! 	pf->canedit     = (i == N_FROM) ? CAN_EDIT(ps_global) : pf_template[i].canedit;
  	pf->rcptto      = pf_template[i].rcptto;
  	pf->writehdr    = pf_template[i].writehdr;
  	pf->localcopy   = pf_template[i].localcopy;
***************
*** 1737,1745 ****
      char         error_buf[200], *error_mess = NULL, *postcmd;
      ADDRESS     *a;
      ENVELOPE	*fake_env = NULL;
!     int          addr_error_count, we_cancel = 0;
      long	 smtp_opts = 0L;
!     char	*verbose_file = NULL;
      BODY	*bp = NULL;
      PINEFIELD	*pf;
      BODY	*origBody = body;
--- 1745,1753 ----
      char         error_buf[200], *error_mess = NULL, *postcmd;
      ADDRESS     *a;
      ENVELOPE	*fake_env = NULL;
!     int          addr_error_count, we_cancel = 0, choice, num_rules = 0, added_rules = -1;
      long	 smtp_opts = 0L;
!     char	*verbose_file = NULL, **smtp_list;
      BODY	*bp = NULL;
      PINEFIELD	*pf;
      BODY	*origBody = body;
***************
*** 1892,1911 ****
       * 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, 
       */
!     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);
!     }
!     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);
      }
      else if((postcmd = smtp_command(ps_global->c_client_error, sizeof(ps_global->c_client_error))) != NULL){
  	char *cmdlist[2];
--- 1900,1948 ----
       * 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(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;
!     }
!     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];
***************
*** 2141,2146 ****
--- 2178,2185 ----
  	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 -rc alpine-2.00/pith/send.h alpine-2.00.I.USE/pith/send.h
*** alpine-2.00/pith/send.h	2008-06-30 15:03:35.000000000 -0700
--- alpine-2.00.I.USE/pith/send.h	2011-02-07 20:33:43.000000000 -0800
***************
*** 158,163 ****
--- 158,165 ----
      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 -rc alpine-2.00/pith/sort.c alpine-2.00.I.USE/pith/sort.c
*** alpine-2.00/pith/sort.c	2008-07-09 22:01:13.000000000 -0700
--- alpine-2.00.I.USE/pith/sort.c	2011-02-07 20:33:47.000000000 -0800
***************
*** 29,35 ****
  #include "../pith/signal.h"
  #include "../pith/busy.h"
  #include "../pith/icache.h"
! 
  
  /*
   * global place to store mail_sort and mail_thread results
--- 29,35 ----
  #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
***************
*** 90,96 ****
    ----*/
  void
  sort_folder(MAILSTREAM *stream, MSGNO_S *msgmap, SortOrder new_sort,
! 	    int new_rev, unsigned int flags)
  {
      long	   raw_current, i, j;
      unsigned long *sort = NULL;
--- 90,96 ----
    ----*/
  void
  sort_folder(MAILSTREAM *stream, MSGNO_S *msgmap, SortOrder new_sort,
! 	    int new_rev, unsigned int flags, int first)
  {
      long	   raw_current, i, j;
      unsigned long *sort = NULL;
***************
*** 100,105 ****
--- 100,114 ----
      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" : ""));
  
***************
*** 529,548 ****
   * argument also means arrival/reverse.
   */
  int
! decode_sort(char *sort_spec, SortOrder *def_sort, int *def_sort_rev)
  {
      char *sep;
      char *fix_this = NULL;
!     int   x, reverse;
  
      if(!sort_spec || !*sort_spec){
! 	*def_sort = SortArrival;
  	*def_sort_rev = 0;
          return(0);
      }
  
      if(struncmp(sort_spec, "reverse", strlen(sort_spec)) == 0){
! 	*def_sort = SortArrival;
  	*def_sort_rev = 1;
          return(0);
      }
--- 538,557 ----
   * argument also means arrival/reverse.
   */
  int
! decode_sort(char *sort_spec, SortOrder *def_sort, int *def_sort_rev, int thread)
  {
      char *sep;
      char *fix_this = NULL;
!     int   x = 0, reverse;
  
      if(!sort_spec || !*sort_spec){
! 	*def_sort = thread ? SortThread : SortArrival;
  	*def_sort_rev = 0;
          return(0);
      }
  
      if(struncmp(sort_spec, "reverse", strlen(sort_spec)) == 0){
! 	*def_sort = thread ? SortThread : SortArrival;
  	*def_sort_rev = 1;
          return(0);
      }
***************
*** 571,577 ****
      if(ps_global->sort_types[x] == EndofList)
        return(-1);
  
!     *def_sort     = ps_global->sort_types[x];
      *def_sort_rev = reverse;
      return(0);
  }
--- 580,586 ----
      if(ps_global->sort_types[x] == EndofList)
        return(-1);
  
!     *def_sort	  = ps_global->sort_types[x];
      *def_sort_rev = reverse;
      return(0);
  }
***************
*** 685,694 ****
      PAT_S        *pat;
      SortOrder	  the_sort_order;
      int           sort_is_rev;
! 
      /* set default order */
      the_sort_order = ps_global->def_sort;
!     sort_is_rev    = ps_global->def_sort_rev;
  
      if(ps_global->mail_stream && nonempty_patterns(rflags, &pstate)){
  	for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)){
--- 694,719 ----
      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    = 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)){
***************
*** 701,709 ****
  	   && pat->action->sort_is_set){
  	    the_sort_order = pat->action->sortorder;
  	    sort_is_rev    = pat->action->revsort;
  	}
      }
  
      sort_folder(ps_global->mail_stream, ps_global->msgmap,
! 		the_sort_order, sort_is_rev, flags);
  }
--- 726,776 ----
  	   && 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, 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 -rc alpine-2.00/pith/sort.h alpine-2.00.I.USE/pith/sort.h
*** alpine-2.00/pith/sort.h	2006-09-22 13:06:05.000000000 -0700
--- alpine-2.00.I.USE/pith/sort.h	2011-02-07 20:33:42.000000000 -0800
***************
*** 22,28 ****
  
  
  #define	refresh_sort(S,M,F)	sort_folder((S), (M), mn_get_sort(M), \
! 					    mn_get_revsort(M), (F))
  
  struct global_sort_data {
      MSGNO_S *msgmap;
--- 22,28 ----
  
  
  #define	refresh_sort(S,M,F)	sort_folder((S), (M), mn_get_sort(M), \
! 					    mn_get_revsort(M), (F), 1)
  
  struct global_sort_data {
      MSGNO_S *msgmap;
***************
*** 41,49 ****
  
  /* exported protoypes */
  char	*sort_name(SortOrder);
! void	 sort_folder(MAILSTREAM *, MSGNO_S *, SortOrder, int, unsigned);
! int	 decode_sort(char *, SortOrder *, int *);
  void	 reset_sort_order(unsigned);
! 
  
  #endif /* PITH_SORT_INCLUDED */
--- 41,49 ----
  
  /* exported protoypes */
  char	*sort_name(SortOrder);
! 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 -rc alpine-2.00/pith/state.c alpine-2.00.I.USE/pith/state.c
*** alpine-2.00/pith/state.c	2008-06-03 15:31:05.000000000 -0700
--- alpine-2.00.I.USE/pith/state.c	2011-02-07 20:33:45.000000000 -0800
***************
*** 32,38 ****
  #include "../pith/remote.h"
  #include "../pith/list.h"
  #include "../pith/smime.h"
! 
  
  /*
   * Globals referenced throughout pine...
--- 32,38 ----
  #include "../pith/remote.h"
  #include "../pith/list.h"
  #include "../pith/smime.h"
! #include "../pith/rules.h"
  
  /*
   * Globals referenced throughout pine...
***************
*** 73,78 ****
--- 73,79 ----
  
      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;
***************
*** 115,120 ****
--- 116,124 ----
      if(!(pps && (*pps)))
        return;
  
+     if((*pps)->subject != NULL)
+       fs_give((void **)&(*pps)->subject);
+ 
      if((*pps)->hostname != NULL)
        fs_give((void **)&(*pps)->hostname);
  
***************
*** 130,135 ****
--- 134,142 ----
      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);
  
***************
*** 182,187 ****
--- 189,197 ----
      if((*pps)->hdr_colors)
        free_spec_colors(&(*pps)->hdr_colors);
  
+     if((*pps)->index_token_colors)
+       free_spec_colors(&(*pps)->index_token_colors);
+ 
      if((*pps)->keywords)
        free_keyword_list(&(*pps)->keywords);
  
***************
*** 202,207 ****
--- 212,220 ----
      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 -rc alpine-2.00/pith/state.h alpine-2.00.I.USE/pith/state.h
*** alpine-2.00/pith/state.h	2008-06-03 08:54:15.000000000 -0700
--- alpine-2.00.I.USE/pith/state.h	2011-02-07 20:33:47.000000000 -0800
***************
*** 32,38 ****
  #include "../pith/stream.h"
  #include "../pith/color.h"
  #include "../pith/user.h"
! 
  
  /*
   * Printing control structure
--- 32,38 ----
  #include "../pith/stream.h"
  #include "../pith/color.h"
  #include "../pith/user.h"
! #include "../pith/rulestype.h"
  
  /*
   * Printing control structure
***************
*** 104,112 ****
--- 104,118 ----
      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];
+     QUOTALIST	*quota;
      char         last_unambig_folder[MAXPATH+1];
      char         last_save_folder[MAXPATH+1];
      CONTEXT_S   *last_save_context;
***************
*** 122,127 ****
--- 128,134 ----
      unsigned     mangled_header:1;	/* header needs repainting */
      unsigned     mangled_body:1;	/* body of screen needs repainting */
      unsigned     mangled_screen:1;	/* whole screen needs repainting */
+     unsigned     resize_for_pico:1;	/* screen needs repainting due to resizing */
  
      unsigned     in_init_seq:1;		/* executing initial cmd list */
      unsigned     save_in_init_seq:1;
***************
*** 135,140 ****
--- 142,149 ----
      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;
***************
*** 168,173 ****
--- 177,183 ----
      unsigned	 intr_pending:1;	/* received SIGINT and haven't acted */
      unsigned	 expunge_in_progress:1;	/* don't want to re-enter c-client   */
      unsigned	 never_allow_changing_from:1;	/* not even for roles */
+     unsigned	 newthread:1;		/* start a new thread on composing */
  
      unsigned	 readonly_pinerc:1;
      unsigned	 view_all_except:1;
***************
*** 239,249 ****
--- 249,272 ----
      char       **feat_list_back_compat;
  
      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 */
      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 */
  
***************
*** 281,288 ****
--- 304,316 ----
      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;
+ 
      int          last_expire_year, last_expire_month;
  
      int		 printer_category;
***************
*** 295,300 ****
--- 323,332 ----
  
      int		 nmw_width;
  
+     char	*subject;
+     int		 send_immediately;
+     int		 failed_read;
+ 
      int          hours_to_timeout;
  
      int          tcp_query_timeout;
***************
*** 317,322 ****
--- 349,356 ----
      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 */
  
***************
*** 328,333 ****
--- 362,368 ----
      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;
***************
*** 338,343 ****
--- 373,381 ----
      char	 last_error[500];
      INIT_ERR_S  *init_errs;
  
+     PRULELIST_S *rule_list;
+     char	*pressed_key;
+ 
      PRINT_S	*print;
  
  #ifdef SMIME
diff -rc alpine-2.00/pith/store.c alpine-2.00.I.USE/pith/store.c
*** alpine-2.00/pith/store.c	2008-06-03 12:27:23.000000000 -0700
--- alpine-2.00.I.USE/pith/store.c	2011-02-07 20:33:42.000000000 -0800
***************
*** 170,175 ****
--- 170,183 ----
  		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 -rc alpine-2.00/pith/stream.c alpine-2.00.I.USE/pith/stream.c
*** alpine-2.00/pith/stream.c	2008-03-25 11:57:53.000000000 -0700
--- alpine-2.00.I.USE/pith/stream.c	2011-02-07 20:33:46.000000000 -0800
***************
*** 3318,3323 ****
--- 3318,3342 ----
  }
  
  
+ /* Some stream is locked checks to see if there is any stream for which we
+  * are in a callback from c-client
+  */
+ 
+ int
+ some_stream_is_locked(void)
+ {
+     int rv = 0, i;
+     MAILSTREAM *m;
+ 
+     for(i = 0; rv == 0 && i < ps_global->s_pool.nstream; i++){
+ 	m = ps_global->s_pool.streams[i];
+ 	if(m && m->lock)
+ 	  rv++;
+      }
+ 
+     return(rv);
+ }
+ 
  /*
   * Very simple version of appenduid_cb until we need something
   * more complex.
diff -rc alpine-2.00/pith/stream.h alpine-2.00.I.USE/pith/stream.h
*** alpine-2.00/pith/stream.h	2007-06-15 16:23:02.000000000 -0700
--- alpine-2.00.I.USE/pith/stream.h	2011-02-07 20:33:46.000000000 -0800
***************
*** 460,465 ****
--- 460,466 ----
  int	       is_imap_stream(MAILSTREAM *);
  int	       modern_imap_stream(MAILSTREAM *);
  int	       streams_died(void);
+ int	       some_stream_is_locked(void);
  void           appenduid_cb(char *mailbox,unsigned long uidvalidity, SEARCHSET *set);
  imapuid_t      get_last_append_uid(void);
  MAILSTREAM    *mail_cmd_stream(CONTEXT_S *, int *);
diff -rc alpine-2.00/pith/string.c alpine-2.00.I.USE/pith/string.c
*** alpine-2.00/pith/string.c	2008-01-09 12:45:31.000000000 -0800
--- alpine-2.00.I.USE/pith/string.c	2011-02-07 20:33:42.000000000 -0800
***************
*** 19,24 ****
--- 19,25 ----
      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 
***************
*** 131,136 ****
--- 132,162 ----
      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';
+ }
  
  
  /*----------------------------------------------------------------------
***************
*** 2859,2861 ****
--- 2885,2919 ----
  	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 -rc alpine-2.00/pith/string.h alpine-2.00.I.USE/pith/string.h
*** alpine-2.00/pith/string.h	2007-08-15 13:28:09.000000000 -0700
--- alpine-2.00.I.USE/pith/string.h	2011-02-07 20:33:42.000000000 -0800
***************
*** 85,96 ****
--- 85,98 ----
  
  /* 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 -rc alpine-2.00/pith/text.c alpine-2.00.I.USE/pith/text.c
*** alpine-2.00/pith/text.c	2008-03-18 10:24:31.000000000 -0700
--- alpine-2.00.I.USE/pith/text.c	2011-02-07 20:33:43.000000000 -0800
***************
*** 91,97 ****
      char       *err, *charset;
      int		filtcnt = 0, error_found = 0, column, wrapit;
      int         is_in_sig = OUT_SIG_BLOCK;
!     int         is_flowed_msg = 0;
      int         is_delsp_yes = 0;
      int         filt_only_c0 = 0;
      char       *parmval;
--- 91,97 ----
      char       *err, *charset;
      int		filtcnt = 0, error_found = 0, column, wrapit;
      int         is_in_sig = OUT_SIG_BLOCK;
!     int         is_flowed_msg = 0, add_me = 1, doraw = RAWSTRING;
      int         is_delsp_yes = 0;
      int         filt_only_c0 = 0;
      char       *parmval;
***************
*** 170,175 ****
--- 170,184 ----
  						       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.
***************
*** 179,185 ****
  	   && pico_usingcolor()
  	   && VAR_SIGNATURE_FORE_COLOR
  	   && VAR_SIGNATURE_BACK_COLOR){
! 	    filters[filtcnt].filter = gf_line_test;
  	    filters[filtcnt++].data = gf_line_test_opt(color_signature,
  						       &is_in_sig);
  	}
--- 188,194 ----
  	   && pico_usingcolor()
  	   && VAR_SIGNATURE_FORE_COLOR
  	   && VAR_SIGNATURE_BACK_COLOR){
! 	    filters[filtcnt].filter = gf_quote_test;
  	    filters[filtcnt++].data = gf_line_test_opt(color_signature,
  						       &is_in_sig);
  	}
***************
*** 197,205 ****
  	   && pico_usingcolor()
  	   && VAR_QUOTE1_FORE_COLOR
  	   && VAR_QUOTE1_BACK_COLOR){
! 	    filters[filtcnt].filter = gf_line_test;
! 	    filters[filtcnt++].data = gf_line_test_opt(color_a_quote,
! 						       &is_flowed_msg);
  	}
      }
      else if(!strucmp(att->body->subtype, "richtext")){
--- 206,214 ----
  	   && pico_usingcolor()
  	   && VAR_QUOTE1_FORE_COLOR
  	   && VAR_QUOTE1_BACK_COLOR){
! 	    add_me = 0;
! 	    filters[filtcnt].filter = gf_quote_test;
! 	    filters[filtcnt++].data = gf_line_test_opt(color_a_quote, &is_flowed_msg);
  	}
      }
      else if(!strucmp(att->body->subtype, "richtext")){
***************
*** 280,285 ****
--- 289,299 ----
  	}
      }
  
+     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
***************
*** 304,310 ****
  	    dq.handlesp   = handlesp;
  	    dq.do_color   = (!(flags & FM_NOCOLOR) && pico_usingcolor());
  
! 	    filters[filtcnt].filter = gf_line_test;
  	    filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq);
  	}
  	if(ps_global->VAR_QUOTE_REPLACE_STRING
--- 318,324 ----
  	    dq.handlesp   = handlesp;
  	    dq.do_color   = (!(flags & FM_NOCOLOR) && pico_usingcolor());
  
! 	    filters[filtcnt].filter = gf_quote_test;
  	    filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq);
  	}
  	if(ps_global->VAR_QUOTE_REPLACE_STRING
***************
*** 363,369 ****
  	dq.handlesp   = handlesp;
  	dq.do_color   = (!(flags & FM_NOCOLOR) && pico_usingcolor());
  
! 	filters[filtcnt].filter = gf_line_test;
  	filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq);
      }
  
--- 377,383 ----
  	dq.handlesp   = handlesp;
  	dq.do_color   = (!(flags & FM_NOCOLOR) && pico_usingcolor());
  
! 	filters[filtcnt].filter = gf_quote_test;
  	filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq);
      }
  
***************
*** 568,574 ****
  {
      DELQ_S *dq;
      char   *lp;
!     int     i, lines, not_a_quote = 0;
      size_t  len;
  
      dq = (DELQ_S *) local;
--- 582,588 ----
  {
      DELQ_S *dq;
      char   *lp;
!     int     i, lines, not_a_quote = 0, code;
      size_t  len;
  
      dq = (DELQ_S *) local;
***************
*** 588,593 ****
--- 602,609 ----
  	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
***************
*** 627,639 ****
  	    }
  	}
  
! 	/* skip over whitespace */
! 	if(!dq->is_flowed)
! 	  while(isspace((unsigned char) *lp))
! 	    lp++;
! 
! 	/* check first character to see if it is a quote */
! 	if(!not_a_quote && *lp != '>')
  	  not_a_quote++;
  
  	if(not_a_quote){
--- 643,654 ----
  	    }
  	}
  
! 	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 -rc alpine-2.00/pith/thread.c alpine-2.00.I.USE/pith/thread.c
*** alpine-2.00/pith/thread.c	2008-03-03 09:52:11.000000000 -0800
--- alpine-2.00.I.USE/pith/thread.c	2011-02-07 20:33:41.000000000 -0800
***************
*** 29,40 ****
  #include "../pith/mailcmd.h"
  #include "../pith/ablookup.h"
  
  
  /*
   * Internal prototypes
   */
  long *sort_thread_flatten(THREADNODE *, MAILSTREAM *, long *,
! 			  char *, long, PINETHRD_S *, unsigned);
  void		   make_thrdflags_consistent(MAILSTREAM *, MSGNO_S *, PINETHRD_S *, int);
  THREADNODE	  *collapse_threadnode_tree(THREADNODE *);
  THREADNODE	  *collapse_threadnode_tree_sorted(THREADNODE *);
--- 29,41 ----
  #include "../pith/mailcmd.h"
  #include "../pith/ablookup.h"
  
+ static int erase_thread_info = 1;
  
  /*
   * Internal prototypes
   */
  long *sort_thread_flatten(THREADNODE *, MAILSTREAM *, long *,
! 			  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 *);
***************
*** 94,113 ****
  set_flags_for_thread(MAILSTREAM *stream, MSGNO_S *msgmap, int f, PINETHRD_S *thrd, int v)
  {
      PINETHRD_S *nthrd, *bthrd;
  
      if(!(stream && thrd && msgmap))
        return;
  
      set_lflag(stream, msgmap, mn_raw2m(msgmap, thrd->rawno), f, v);
  
!     if(thrd->next){
! 	nthrd = fetch_thread(stream, thrd->next);
  	if(nthrd)
  	  set_flags_for_thread(stream, msgmap, f, nthrd, v);
      }
  
!     if(thrd->branch){
! 	bthrd = fetch_thread(stream, thrd->branch);
  	if(bthrd)
  	  set_flags_for_thread(stream, msgmap, f, bthrd, v);
      }
--- 95,116 ----
  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(next = get_next(stream,thrd)){
! 	nthrd = fetch_thread(stream, next);
  	if(nthrd)
  	  set_flags_for_thread(stream, msgmap, f, nthrd, v);
      }
  
! 
!     if(branch = get_branch(stream, thrd)){
! 	bthrd = fetch_thread(stream, branch);
  	if(bthrd)
  	  set_flags_for_thread(stream, msgmap, f, bthrd, v);
      }
***************
*** 121,127 ****
      MESSAGECACHE *mc;
      PINELT_S     *peltp;
  
!     if(!(stream && stream->spare))
        return;
      
      ps_global->view_skipped_index = 0;
--- 124,130 ----
      MESSAGECACHE *mc;
      PINELT_S     *peltp;
  
!     if(!(stream && stream->spare) || !erase_thread_info)
        return;
      
      ps_global->view_skipped_index = 0;
***************
*** 154,160 ****
      PINETHRD_S   *thrd = NULL;
      unsigned long msgno, rawno;
      int           un_view_thread = 0;
!     long          raw_current;
      char         *dup_chk = NULL;
  
  
--- 157,163 ----
      PINETHRD_S   *thrd = NULL;
      unsigned long msgno, rawno;
      int           un_view_thread = 0;
!     long          raw_current, branch;
      char         *dup_chk = NULL;
  
  
***************
*** 167,176 ****
       * 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);
  
      /* dup_chk is like sort with an origin of 1 */
      dup_chk = (char *) fs_get((mn_get_nmsgs(g_sort.msgmap)+1) * sizeof(char));
--- 170,180 ----
       * way. If the dummy node is at the top-level, then its children are
       * promoted to the top-level as separate threads.
       */
!      collapsed_tree = F_ON(F_ENHANCED_THREAD, ps_global)
! 			? copy_tree(tree)
! 			: (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));
***************
*** 181,187 ****
      (void) sort_thread_flatten(collapsed_tree, stream,
  			       &g_sort.msgmap->sort[1],
  			       dup_chk, mn_get_nmsgs(g_sort.msgmap),
! 			       NULL, THD_TOP);
  
      /* reset the inverse array */
      msgno_reset_isort(g_sort.msgmap);
--- 185,191 ----
      (void) sort_thread_flatten(collapsed_tree, stream,
  			       &g_sort.msgmap->sort[1],
  			       dup_chk, mn_get_nmsgs(g_sort.msgmap),
! 			       NULL, THD_TOP, 0, 1L, 0L);
  
      /* reset the inverse array */
      msgno_reset_isort(g_sort.msgmap);
***************
*** 339,350 ****
  	else{
  	    thrd = fetch_head_thread(stream);
  	    while(thrd){
  		/*
  		 * The top-level threads aren't hidden by collapse.
  		 */
  		msgno = mn_raw2m(g_sort.msgmap, thrd->rawno);
! 		if(msgno)
! 		  set_lflag(stream, g_sort.msgmap, msgno, MN_CHID, 0);
  
  		if(thrd->next){
  		    PINETHRD_S *nthrd;
--- 343,356 ----
  	else{
  	    thrd = fetch_head_thread(stream);
  	    while(thrd){
+ 		unsigned long raw = thrd->rawno;
+ 		unsigned long top = top_thread(stream, raw);
  		/*
  		 * The top-level threads aren't hidden by collapse.
  		 */
  		msgno = mn_raw2m(g_sort.msgmap, thrd->rawno);
! 		if(msgno && !get_lflag(stream, NULL,thrd->rawno, MN_COLL))
! 		   set_lflag(stream, g_sort.msgmap, msgno, MN_CHID, 0);
  
  		if(thrd->next){
  		    PINETHRD_S *nthrd;
***************
*** 358,366 ****
  							  MN_COLL));
  		}
  
! 		if(thrd->nextthd)
! 		  thrd = fetch_thread(stream, thrd->nextthd);
! 		else
  		  thrd = NULL;
  	    }
  	}
--- 364,373 ----
  							  MN_COLL));
  		}
  
! 		while (thrd && top_thread(stream, thrd->rawno) == top
! 				&& thrd->nextthd)
! 		thrd = fetch_thread(stream, thrd->nextthd);
! 		if (!(thrd && thrd->nextthd))
  		  thrd = NULL;
  	    }
  	}
***************
*** 411,417 ****
  			  int a_parent_is_collapsed)
  {
      PINETHRD_S *nthrd, *bthrd;
!     unsigned long msgno;
  
      if(!thrd)
        return;
--- 418,424 ----
  			  int a_parent_is_collapsed)
  {
      PINETHRD_S *nthrd, *bthrd;
!     unsigned long msgno, next, branch;
  
      if(!thrd)
        return;
***************
*** 429,436 ****
  	  set_lflag(stream, msgmap, msgno, MN_CHID, 0);
      }
  
!     if(thrd->next){
! 	nthrd = fetch_thread(stream, thrd->next);
  	if(nthrd)
  	  make_thrdflags_consistent(stream, msgmap, nthrd,
  				    a_parent_is_collapsed
--- 436,443 ----
  	  set_lflag(stream, msgmap, msgno, MN_CHID, 0);
      }
  
!     if(next = get_next(stream, thrd)){
! 	nthrd = fetch_thread(stream, next);
  	if(nthrd)
  	  make_thrdflags_consistent(stream, msgmap, nthrd,
  				    a_parent_is_collapsed
***************
*** 439,446 ****
  						  MN_COLL));
      }
  
!     if(thrd->branch){
! 	bthrd = fetch_thread(stream, thrd->branch);
  	if(bthrd)
  	  make_thrdflags_consistent(stream, msgmap, bthrd,
  				    a_parent_is_collapsed);
--- 446,453 ----
  						  MN_COLL));
      }
  
!     if(branch = get_branch(stream, thrd)){
! 	bthrd = fetch_thread(stream, branch);
  	if(bthrd)
  	  make_thrdflags_consistent(stream, msgmap, bthrd,
  				    a_parent_is_collapsed);
***************
*** 487,495 ****
  long *
  sort_thread_flatten(THREADNODE *node, MAILSTREAM *stream,
  		    long *entry, char *dup_chk, long maxno,
! 		    PINETHRD_S *thrd, unsigned int flags)
  {
!     PINETHRD_S *newthrd = NULL;
  
      if(node){
  	if(node->num > 0L && node->num <= maxno){		/* holes happen */
--- 494,503 ----
  long *
  sort_thread_flatten(THREADNODE *node, MAILSTREAM *stream,
  		    long *entry, char *dup_chk, long maxno,
! 		    PINETHRD_S *thrd, unsigned int flags,
! 		    int adopted, long top, long threadno)
  {
!     PINETHRD_S *newthrd = NULL, *save_thread = NULL;
  
      if(node){
  	if(node->num > 0L && node->num <= maxno){		/* holes happen */
***************
*** 497,502 ****
--- 505,513 ----
  		*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.
***************
*** 505,524 ****
  		if(newthrd){
  		  entry++;
  
  		  if(node->next)
  		    entry = sort_thread_flatten(node->next, stream,
  						entry, dup_chk, maxno,
! 						newthrd, THD_NEXT);
  
  		  if(node->branch)
  		    entry = sort_thread_flatten(node->branch, stream,
  						entry, dup_chk, maxno,
  						newthrd,
! 						(flags == THD_TOP) ? THD_TOP
! 								   : THD_BRANCH);
  		}
  	    }
  	}
      }
  
      return(entry);
--- 516,566 ----
  		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, 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),
! 						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);
***************
*** 787,793 ****
   */
  void
  collapse_or_expand(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap,
! 		   long unsigned int msgno)
  {
      int           collapsed, adjust_current = 0;
      PINETHRD_S   *thrd = NULL, *nthrd;
--- 829,835 ----
   */
  void
  collapse_or_expand(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap,
! 		   long unsigned int msgno, int display)
  {
      int           collapsed, adjust_current = 0;
      PINETHRD_S   *thrd = NULL, *nthrd;
***************
*** 840,846 ****
      if(!thrd)
        return;
  
!     collapsed = get_lflag(stream, NULL, thrd->rawno, MN_COLL) && thrd->next;
  
      if(collapsed){
  	msgno = mn_raw2m(msgmap, thrd->rawno);
--- 882,888 ----
      if(!thrd)
        return;
  
!     collapsed = this_thread_is_kolapsed(ps_global, stream, msgmap, thrd->rawno);
  
      if(collapsed){
  	msgno = mn_raw2m(msgmap, thrd->rawno);
***************
*** 858,870 ****
  	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)
  	      set_thread_subtree(stream, nthrd, msgmap, 1, MN_CHID);
  
  	    clear_index_cache_ent(stream, msgno, 0);
  	}
      }
!     else
        q_status_message(SM_ORDER, 0, 1,
  		       _("No thread to collapse or expand on this line"));
      
--- 900,912 ----
  	msgno = mn_raw2m(msgmap, thrd->rawno);
  	if(msgno > 0L && msgno <= mn_get_total(msgmap)){
  	    set_lflag(stream, msgmap, msgno, MN_COLL, 1);
! 	    if((thrd->next) && ((nthrd = fetch_thread(stream, thrd->next)) != NULL))
  	      set_thread_subtree(stream, nthrd, msgmap, 1, MN_CHID);
  
  	    clear_index_cache_ent(stream, msgno, 0);
  	}
      }
!     else if(display)
        q_status_message(SM_ORDER, 0, 1,
  		       _("No thread to collapse or expand on this line"));
      
***************
*** 951,968 ****
      unsigned long count = 0;
      PINETHRD_S *nthrd, *bthrd;
      MESSAGECACHE *mc;
  
      if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
        return count;
      
!     if(thrd->next){
! 	nthrd = fetch_thread(stream, thrd->next);
  	if(nthrd)
  	  count += count_flags_in_thread(stream, nthrd, flags);
      }
  
!     if(thrd->branch){
! 	bthrd = fetch_thread(stream, thrd->branch);
  	if(bthrd)
  	  count += count_flags_in_thread(stream, bthrd, flags);
      }
--- 993,1011 ----
      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(next = get_next(stream, thrd)){
! 	nthrd = fetch_thread(stream, next);
  	if(nthrd)
  	  count += count_flags_in_thread(stream, nthrd, flags);
      }
  
!     if(branch = get_branch(stream, thrd)){
! 	bthrd = fetch_thread(stream, branch);
  	if(bthrd)
  	  count += count_flags_in_thread(stream, bthrd, flags);
      }
***************
*** 1050,1069 ****
  mark_msgs_in_thread(MAILSTREAM *stream, PINETHRD_S *thrd, MSGNO_S *msgmap)
  {
      int           count = 0;
      PINETHRD_S   *nthrd, *bthrd;
      MESSAGECACHE *mc;
  
      if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
        return count;
  
!     if(thrd->next){
! 	nthrd = fetch_thread(stream, thrd->next);
  	if(nthrd)
  	  count += mark_msgs_in_thread(stream, nthrd, msgmap);
      }
  
!     if(thrd->branch){
! 	bthrd = fetch_thread(stream, thrd->branch);
  	if(bthrd)
  	  count += mark_msgs_in_thread(stream, bthrd, msgmap);
      }
--- 1093,1113 ----
  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(next = get_next(stream, thrd)){
! 	nthrd = fetch_thread(stream, next);
  	if(nthrd)
  	  count += mark_msgs_in_thread(stream, nthrd, msgmap);
      }
  
!     if(branch = get_branch(stream, thrd)){
! 	bthrd = fetch_thread(stream, branch);
  	if(bthrd)
  	  count += mark_msgs_in_thread(stream, bthrd, msgmap);
      }
***************
*** 1097,1103 ****
                        		/* flags to set or clear */
                    		/* set or clear? */
  {
!     unsigned long msgno;
      PINETHRD_S *nthrd, *bthrd;
  
      if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
--- 1141,1147 ----
                        		/* flags to set or clear */
                    		/* set or clear? */
  {
!     unsigned long msgno, next, branch;
      PINETHRD_S *nthrd, *bthrd;
  
      if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
***************
*** 1121,1134 ****
      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(nthrd)
  	  set_thread_lflags(stream, nthrd, msgmap, flags, v);
      }
  
!     if(thrd->branch){
! 	bthrd = fetch_thread(stream, thrd->branch);
  	if(bthrd)
  	  set_thread_lflags(stream, bthrd, msgmap, flags, v);
      }
--- 1165,1178 ----
      if(msgno > 0L && flags == MN_CHID2 && v == 1)
        clear_index_cache_ent(stream, msgno, 0);
  
!     if(next = get_next(stream, thrd)){
! 	nthrd = fetch_thread(stream, next);
  	if(nthrd)
  	  set_thread_lflags(stream, nthrd, msgmap, flags, v);
      }
  
!     if(branch = get_branch(stream,thrd)){
! 	bthrd = fetch_thread(stream, branch);
  	if(bthrd)
  	  set_thread_lflags(stream, bthrd, msgmap, flags, v);
      }
***************
*** 1217,1235 ****
      char        to_us = ' ';
      char        branch_to_us = ' ';
      PINETHRD_S *nthrd, *bthrd;
      MESSAGECACHE *mc;
  
      if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs)
        return to_us;
  
!     if(thrd->next){
! 	nthrd = fetch_thread(stream, thrd->next);
  	if(nthrd)
  	  to_us = to_us_symbol_for_thread(stream, nthrd, consider_flagged);
      }
  
      if(((consider_flagged && to_us != '*') || (!consider_flagged && to_us != '+'))
!        && thrd->branch){
  	bthrd = fetch_thread(stream, thrd->branch);
  	if(bthrd)
  	  branch_to_us = to_us_symbol_for_thread(stream, bthrd, consider_flagged);
--- 1261,1280 ----
      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(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 != '+'))
!        && (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);
***************
*** 1279,1285 ****
  		  break;
  	      }
  	    
! 	    if(to_us != '+' && resent_to_us(&idata))
  	      to_us = '+';
  
  	    if(to_us == ' ' && F_ON(F_MARK_FOR_CC,ps_global))
--- 1324,1330 ----
  		  break;
  	      }
  	    
! 	    if(to_us != '+' && !idata.bogus && resent_to_us(&idata))
  	      to_us = '+';
  
  	    if(to_us == ' ' && F_ON(F_MARK_FOR_CC,ps_global))
***************
*** 1327,1333 ****
  
      set_lflag(stream, msgmap, msgno, flags, v);
  
!     if(thrd->next && (hiding || !get_lflag(stream,NULL,thrd->rawno,MN_COLL))){
  	nthrd = fetch_thread(stream, thrd->next);
  	if(nthrd)
  	  set_thread_subtree(stream, nthrd, msgmap, v, flags);
--- 1372,1379 ----
  
      set_lflag(stream, msgmap, msgno, flags, v);
  
!     if(thrd->next
! 	 && (hiding || !get_lflag(stream,NULL,thrd->rawno,MN_COLL))){
  	nthrd = fetch_thread(stream, thrd->next);
  	if(nthrd)
  	  set_thread_subtree(stream, nthrd, msgmap, v, flags);
***************
*** 1367,1374 ****
      if(rawno)
        thrd = fetch_thread(stream, rawno);
  
!     if(thrd && thrd->top && thrd->top != thrd->rawno)
!       thrd = fetch_thread(stream, thrd->top);
      
      if(!thrd)
        return 0;
--- 1413,1420 ----
      if(rawno)
        thrd = fetch_thread(stream, rawno);
  
!     if(thrd && thrd->top && top_thread(stream,thrd->top) != thrd->rawno)
!       thrd = fetch_thread(stream, top_thread(stream,thrd->top));
      
      if(!thrd)
        return 0;
***************
*** 1432,1438 ****
        thrd = fetch_thread(stream, rawno);
      
      if(thrd && thrd->top)
!       topthrd = fetch_thread(stream, thrd->top);
      
      if(!topthrd)
        return 0;
--- 1478,1484 ----
        thrd = fetch_thread(stream, rawno);
      
      if(thrd && thrd->top)
!       topthrd = fetch_thread(stream, top_thread(stream,thrd->top));
      
      if(!topthrd)
        return 0;
***************
*** 1538,1543 ****
--- 1584,1590 ----
  set_search_bit_for_thread(MAILSTREAM *stream, PINETHRD_S *thrd, SEARCHSET **msgset)
  {
      PINETHRD_S *nthrd, *bthrd;
+     unsigned long next, branch;
  
      if(!(stream && thrd))
        return;
***************
*** 1546,1560 ****
         && (!(msgset && *msgset) || in_searchset(*msgset, thrd->rawno)))
        mm_searched(stream, thrd->rawno);
  
!     if(thrd->next){
! 	nthrd = fetch_thread(stream, thrd->next);
  	if(nthrd)
  	  set_search_bit_for_thread(stream, nthrd, msgset);
      }
  
!     if(thrd->branch){
! 	bthrd = fetch_thread(stream, thrd->branch);
  	if(bthrd)
  	  set_search_bit_for_thread(stream, bthrd, msgset);
      }
  }
--- 1593,2185 ----
         && (!(msgset && *msgset) || in_searchset(*msgset, thrd->rawno)))
        mm_searched(stream, thrd->rawno);
  
!     if(next= get_next(stream, thrd)){
! 	nthrd = fetch_thread(stream, next);
  	if(nthrd)
  	  set_search_bit_for_thread(stream, nthrd, msgset);
      }
  
!     if(branch = get_branch(stream, thrd)){
! 	bthrd = fetch_thread(stream, branch);
  	if(bthrd)
  	  set_search_bit_for_thread(stream, bthrd, msgset);
      }
  }
+ 
+ /*
+  * 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;
+ }
+ 
+ void
+ find_msgmap(MAILSTREAM *stream, MSGNO_S *msgmap, int flags, SortOrder ordersort, unsigned is_rev)
+ {
+    int we_cancel;
+    long *old_arrival,*new_arrival;
+    long init_thread, end_thread, current;
+    long k = 1L, j, last_thread = 0L;
+    long i, tmsg, ntmsg, nthreads;
+    char        sort_msg[MAX_SCREEN_COLS+1] = {'\0'};
+    PINETHRD_S *thrd, *tthrd, *nthrd;
+  
+    erase_thread_info = 0;
+    current = mn_m2raw(msgmap, mn_get_cur(msgmap));
+ 
+    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));
+    memset(old_arrival, 0, tmsg*sizeof(long));
+    for (i= 1L;(i <= mn_get_total(msgmap)) && (old_arrival[i] = msgmap->sort[i]); i++);
+ 
+    /* now sort by thread */
+    sort_folder(stream, msgmap, SortThread, 0, SRT_VRB, 0);
+    ntmsg = mn_get_total(msgmap) + 1;
+ 
+    if (tmsg != ntmsg){	/* oh oh, something happened,we better try again */
+ 	fs_give((void **)&old_arrival);
+ 	find_msgmap(stream, msgmap, flags, ordersort, is_rev);
+ 	return;
+    }
+ 
+    /* reconstruct the msgmap */
+ 
+    new_arrival = (long *) fs_get(tmsg * sizeof(long));
+    memset(new_arrival, 0, tmsg*sizeof(long));
+    i = mn_get_total(msgmap);
+    while (new_arrival[1] == 0){ /* think of this as (tmsg > 0) */
+         int done = 0;
+ 	long n = mn_get_total(msgmap);
+ 
+         init_thread = top_thread(stream, old_arrival[i]);
+ 	thrd = fetch_thread(stream, init_thread);
+         while ((new_arrival[n] != 0) && !done){ /* compare raw numbers */
+           done = (new_arrival[n] == init_thread); 
+           n--;
+         }
+         if (!done){
+ 	   k = 1L;
+ 	   mn_set_cur(msgmap, mn_raw2m(msgmap, init_thread));
+ 	   if  (move_next_thread(ps_global, stream, msgmap, 0) <= 0)
+ 	 	j = mn_get_total(msgmap) - mn_raw2m(msgmap, init_thread) + 1;
+ 	   else
+ 		j = mn_get_cur(msgmap) - mn_raw2m(msgmap, init_thread);
+            end_thread = mn_raw2m(msgmap, init_thread) + j;
+            while (k <= j){
+               new_arrival[tmsg - k] = msgmap->sort[end_thread - k];
+               k++;
+            }
+            tmsg -= j;
+        }
+        i--;
+    }
+    relink_threads(stream, msgmap, new_arrival);
+    for (i = 1; (i <= mn_get_total(msgmap)) 
+ 		&&  (msgmap->sort[i] = new_arrival[i]); i++);
+    msgno_reset_isort(msgmap);
+ 
+    fs_give((void **)&new_arrival);
+    fs_give((void **)&old_arrival);
+ 
+ 
+    if(is_rev && (mn_get_total(msgmap) > 1L)){
+       long *rev_sort;
+       long i = 1L, l = mn_get_total(msgmap);
+ 
+       rev_sort = (long *) fs_get((mn_get_total(msgmap)+1L) * sizeof(long));
+       memset(rev_sort, 0, (mn_get_total(msgmap)+1L)*sizeof(long));
+       while (l > 0L){
+ 	 if (top_thread(stream, msgmap->sort[l]) == msgmap->sort[l]){
+ 	    long init_thread = msgmap->sort[l];
+ 	    long j, k;
+ 
+ 	    mn_set_cur(msgmap, mn_raw2m(msgmap, init_thread));
+ 	    if (move_next_thread(ps_global, stream, msgmap, 0) <= 0)
+ 	 	j = mn_get_total(msgmap) - mn_raw2m(msgmap, init_thread) + 1;
+ 	    else
+ 		j = mn_get_cur(msgmap) - mn_raw2m(msgmap, init_thread);
+ 	    for (k = 0L; (k < j) && (rev_sort[i+k] = msgmap->sort[l+k]); k++);
+ 	    i += j;
+ 	 }
+ 	 l--;
+       }
+       relink_threads(stream, msgmap, rev_sort);
+       for (i = 1L; i <=  mn_get_total(msgmap); i++)
+         msgmap->sort[i] = rev_sort[i];
+       msgno_reset_isort(msgmap);
+       fs_give((void **)&rev_sort);
+    }
+    mn_reset_cur(msgmap, first_sorted_flagged(is_rev ? F_NONE : F_SRCHBACK,
+ 			stream, mn_raw2m(msgmap, current), FSF_SKIP_CHID));
+    msgmap->top = -1L;
+ 
+    sp_set_unsorted_newmail(ps_global->mail_stream, 0);
+ 
+    for(i = 1L; i <= ps_global->mail_stream->nmsgs; i++)
+       mail_elt(ps_global->mail_stream, i)->spare7 = 0;
+ 
+    mn_set_sort(msgmap, SortThread);
+    mn_set_revsort(msgmap, is_rev);
+    erase_thread_info = 1;
+    clear_index_cache(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;
+ }
+ 
diff -rc alpine-2.00/pith/thread.h alpine-2.00.I.USE/pith/thread.h
*** alpine-2.00/pith/thread.h	2006-09-22 13:06:05.000000000 -0700
--- alpine-2.00.I.USE/pith/thread.h	2011-02-07 20:33:41.000000000 -0800
***************
*** 37,42 ****
--- 37,43 ----
      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,98 ****
  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	      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);
--- 93,99 ----
  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, 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,111 ****
  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 **);
! 
  
  #endif /* PITH_THREAD_INCLUDED */
--- 107,130 ----
  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 -rc alpine-2.00/pith/url.c alpine-2.00.I.USE/pith/url.c
*** alpine-2.00/pith/url.c	2007-08-29 15:31:51.000000000 -0700
--- alpine-2.00.I.USE/pith/url.c	2011-02-07 20:33:45.000000000 -0800
***************
*** 52,58 ****
  rfc1738_scan(char *line, int *len)
  {
      char *colon, *start, *end;
!     int   n;
  
      /* process each : in the line */
      for(; (colon = strindex(line, ':')) != NULL; line = end){
--- 52,58 ----
  rfc1738_scan(char *line, int *len)
  {
      char *colon, *start, *end;
!     int   n, delim;
  
      /* process each : in the line */
      for(; (colon = strindex(line, ':')) != NULL; line = end){
***************
*** 113,119 ****
  			    && !struncmp(start + 1, "elnet", 5))))
  		|| (n == 8
  		    && (*start == 'P' || *start == 'p')
! 		    && !struncmp(start + 1, "rospero", 7)))
  	       || url_external_specific_handler(start, n))){
  		/*
  		 * Second, make sure that everything to the right of the
--- 113,125 ----
  			    && !struncmp(start + 1, "elnet", 5))))
  		|| (n == 8
  		    && (*start == 'P' || *start == 'p')
! 		    && !struncmp(start + 1, "rospero", 7))
! 		|| (n == 11
! 		    && (*start == 'x' || *start == 'X')
! 		    && !struncmp(start + 1, "-pine-help", 10))
! 		|| (n == 13
! 		    && (*start == 'x' || *start == 'X')
! 		    && !struncmp(start + 1, "-alpine-help", 12)))
  	       || url_external_specific_handler(start, n))){
  		/*
  		 * Second, make sure that everything to the right of the
***************
*** 130,135 ****
--- 136,142 ----
  
  		if(i != j){
  		    *len = end - start;
+ 		    delim = start > line && *(start - 1) == '<';
  
  		    /*
  		     * Special case handling for comma.
***************
*** 139,146 ****
  		     * In most cases any way, that's why we have the
  		     * exception.
  		     */
! 		    if(*(end - 1) == ','
! 		       || (*(end - 1) == '.' && (!*end  || *end == ' ')))
  		      (*len)--;
  
  		    if(*len - (colon - start) > 0)
--- 146,153 ----
  		     * In most cases any way, that's why we have the
  		     * exception.
  		     */
! 		    if(delim == 0 && (*(end - 1) == ','
! 		       || (*(end - 1) == '.' && (!*end  || *end == ' '))))
  		      (*len)--;
  
  		    if(*len - (colon - start) > 0)
diff -rc alpine-2.00/README.maildir alpine-2.00.I.USE/README.maildir
*** alpine-2.00/README.maildir	2011-02-07 20:34:02.000000000 -0800
--- alpine-2.00.I.USE/README.maildir	2011-02-07 20:33:41.000000000 -0800
***************
*** 0 ****
--- 1,153 ----
+ ---------------------------------------
+ 
+ Maildir Driver for Alpine 1.0
+ By Eduardo Chappa <chappa@washington.edu>
+ http://staff.washington.edu/chappa/alpine/
+ 
+ ---------------------------------------
+ 1. General Information About This Patch
+ ---------------------------------------
+ 
+ This patch adds support for the maildir format to Alpine. We take the 
+ approach that this patch is one more driver among the number of formats 
+ supported by Alpine (more generally c-client). This approach differs from 
+ older versions of similar patches, in that once a maildir patch was 
+ applied, it was assumed that all your folders would be created in the 
+ maildir format. 
+ 
+ This patch does not assume that maildir is a preferred format, instead 
+ puts maildir in equal footing with other formats (mbox, mbx, mix, etc), 
+ and so a maildir folder in the mail/ collection is treated in the same way 
+ as any other folder in any other format. In other words, just by reading 
+ the name of a folder, or opening it, or doing any operation with it, you 
+ can not know in which format the folder is.
+ 
+ This implies that if you want to add a folder in the maildir format to the 
+ mail/ collection, then you must add by pressing "A" in the folder list 
+ collection and enter "#driver.md/mail/name_maildir_folder".
+ 
+ If you only want to use maildir, however, you can do so too. In this case, 
+ you must create a maildir collection. In that collection, only maildir 
+ folders will be listed. If there is any folder in any other format, that 
+ folder will be ignored. In another words, any folder listed there is in 
+ maildir format and can be accessed through that collection, conversely, 
+ any folder not listed there is not in maildir format and there is no way 
+ to access it using this collection.
+ 
+ In order to create a maildir collection, you could press M S L, and "A" to 
+ add a collection. Fill in the required fields as follows:
+ 
+ Nickname  : Anything
+ Server    :
+ Path      : #md/relative/path/to/maildir/collection/
+ View      :
+ 
+ For example, if "path" is set to "#md/mail/", then Alpine will look for your 
+ maildir folders that are in ~/mail/.
+ 
+ The code in this patch is mostly based in code for the unix driver plus 
+ some combinations of the mh, mbx and nntp drivers for the c-client 
+ library. Those drivers were designed by Mark Crispin, and bugs in this 
+ code are not his bugs, but my own.
+ 
+   I got all the specification for this patch from 
+ http://cr.yp.to/proto/maildir.html. If you know of a place with a better 
+ specification for maildir format please let me know. The method this patch 
+ uses to create a unique filename for a message is one of the "old 
+ fashioned" methods. I realize that this is old fashioned, but it is 
+ portable, and portability is the main reason why I decided to use an old 
+ fashioned method (most methods are not portable. See the word 
+ "Unfortunately" in that document).
+ 
+ --------------
+ 2. Other Goals
+ --------------
+ 
+   It is intended that this code will work well with any application 
+ written using the c-client library. Of paramount importance is to make the 
+ associated imap server work well when the server accesses a folder in 
+ Maildir format. The program mailutil should also work flawlessly with this 
+ implemetation of the driver.
+ 
+   It is intended that this driver be fast and stable. We intend not to 
+ patch Alpine to make this driver do its work, unless such patching is for 
+ fixing bugs in Alpine or to pass parameters to the driver.
+ 
+ ------------------------------------------------------------------------ 
+ 3. What are the known bugs of this implementation of the Maildir driver? 
+ ------------------------------------------------------------------------
+ 
+   I don't know any at this time. There have been bugs before, though, but 
+ I try to fix bugs as soon as they are reported. A complete list of updates 
+ for this patch, which includes bug fixes, improvements and addition of new 
+ features can be found at
+ 
+  http://staff.washington.edu/chappa/alpine/updates/maildir.html
+ 
+ ----------
+ 4. On UIDs
+ ----------
+ 
+  This patch keeps uids in the name of the file that contains the message, 
+ by adding a ",u=" string to the file name to save the uid of a message. A 
+ file is kept between sessions to save information on the last uid assigned 
+ and its time of validity. Only one session with writing access can write 
+ uids, all others must wait for the other session to assign them. The 
+ session assigning uids creates a ".uidtemp" file which other sessions must 
+ not disturb.
+ 
+   Uid support appeared in Alpine 1.00 (snapshot 925), and is experimental,
+ please report any problems.
+ 
+ --------------------------------------------
+ 5. Configuring Alpine and Setting up a Maildir 
+ --------------------------------------------
+ 
+ Once this approach was chosen, it implied the following:
+ 
+     * This patch assumes that your INBOX is located at "$HOME/Maildir".  
+       This is a directory which should have three subdirectories "cur", 
+       "tmp" and "new". Mail is delivered to 'new' and read from 'cur'. I 
+       have added a configuration option "maildir-location" which can be 
+       used to tell Alpine where your Maildir inbox is, in case your system 
+       do not use the above directory (e.g. your system may use 
+       "~/.maildir"). In this case define that variable to be the name of 
+       the directory where your e-mail is being delivered (e.g.  
+       ".maildir").
+ 
+     * If you want to use the above configuration as your inbox, you must 
+       define your inbox-path as "#md/inbox" (no quotes).  You can define 
+       the inbox-path like above even if you have changed the 
+       maildir-location variable. That's the whole point of that variable.
+ 
+ -----------------------------------
+ 6. What about Courier file systems?
+ -----------------------------------
+ 
+ In a courier file system all folders are subfolders of a root folder 
+ called INBOX. Normally INBOX is located at ~/Maildir and subfolders are 
+ "dot" directories in ~/Maildir. For example ~/Maildir/.Trash is a 
+ subfolder of INBOX and is accessed with the nickname "INBOX.Trash".
+ 
+ You can not access folders in this way unless you preceed them with the 
+ string "#mc/". The purpose of the string "#mc/" is to warn Alpine that a 
+ collection in the Courier format is going to be accessed, so you can 
+ SELECT a folder like "#mc/INBOX.Trash", but not "INBOX.Trash"
+ 
+ You can access a collection through a server, but if you want to access a 
+ collection of folders created using the Courier server, you MUST edit your
+ ".pinerc" file and enter the definition of the collection as follows:
+ 
+ folder-collections="Anything you want" #mc/INBOX.[]
+ 
+ You can replace the string "#mc/INBOX." by something different, for example
+ "#mc/Courier/." will make Alpine search for your collection in ~/Courier.
+ 
+ You can not add this directly into Alpine because Alpine fails to accept this 
+ value from its input, but it takes it correctly when it is added through 
+ the ".pinerc" file.
+ 
+ You can access your inbox as "#mc/INBOX" or "#md/INBOX". Both definitions 
+ point to the same place.
+ 
+ Last Updated February 9, 2008
diff -rc alpine-2.00/web/src/alpined.d/alpined.c alpine-2.00.I.USE/web/src/alpined.d/alpined.c
*** alpine-2.00/web/src/alpined.d/alpined.c	2008-08-22 13:41:37.000000000 -0700
--- alpine-2.00.I.USE/web/src/alpined.d/alpined.c	2011-02-07 20:33:43.000000000 -0800
***************
*** 2795,2801 ****
  			      init_save_defaults();
  			      break;
  			    case V_SORT_KEY:
! 			      decode_sort(ps_global->VAR_SORT_KEY, &ps_global->def_sort, &def_sort_rev);
  			      break;
  			    case V_VIEW_HDR_COLORS :
  			      set_custom_spec_colors(ps_global);
--- 2795,2801 ----
  			      init_save_defaults();
  			      break;
  			    case V_SORT_KEY:
! 			      decode_sort(ps_global->VAR_SORT_KEY, &ps_global->def_sort, &def_sort_rev, 0);
  			      break;
  			    case V_VIEW_HDR_COLORS :
  			      set_custom_spec_colors(ps_global);
***************
*** 6271,6277 ****
  				      && mn_get_revsort(sp_msgmap(ps_global->mail_stream)) == reversed))
  				sort_folder(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream),
  					    ps_global->sort_types[i], 
! 					    reversed, 0);
  
  			      break;
  			  }
--- 6271,6277 ----
  				      && mn_get_revsort(sp_msgmap(ps_global->mail_stream)) == reversed))
  				sort_folder(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream),
  					    ps_global->sort_types[i], 
! 					    reversed, 0, 1);
  
  			      break;
  			  }
***************
*** 6848,6854 ****
  		    /* BUG: fix charset not to be NULL below */
  		    if(agg_text_select(ps_global->mail_stream,
  				       sp_msgmap(ps_global->mail_stream),
! 				       field, not, 0, text, NULL, NULL))
  		      /* BUG: plug in "charset" above? */
  		      return(peSelectError(interp, "programmer botch"));
  		}
--- 6848,6854 ----
  		    /* BUG: fix charset not to be NULL below */
  		    if(agg_text_select(ps_global->mail_stream,
  				       sp_msgmap(ps_global->mail_stream),
! 				       field, NULL, not, 0, text, NULL, NULL))
  		      /* BUG: plug in "charset" above? */
  		      return(peSelectError(interp, "programmer botch"));
  		}
diff -rc alpine-2.00/web/src/alpined.d/Makefile.am alpine-2.00.I.USE/web/src/alpined.d/Makefile.am
*** alpine-2.00/web/src/alpined.d/Makefile.am	2008-08-12 13:47:04.000000000 -0700
--- alpine-2.00.I.USE/web/src/alpined.d/Makefile.am	2011-02-07 20:33:46.000000000 -0800
***************
*** 50,52 ****
--- 50,53 ----
  	 debug.c status.c stubs.c alpined.h color.h ldap.h
  	echo "char datestamp[]="\"`date`\"";" > local.c
  	echo "char hoststamp[]="\"`hostname`\"";" >> local.c
+ 	cat ../../../patchlevel >> local.c
diff -rc alpine-2.00/web/src/alpined.d/Makefile.in alpine-2.00.I.USE/web/src/alpined.d/Makefile.in
*** alpine-2.00/web/src/alpined.d/Makefile.in	2008-08-13 08:44:42.000000000 -0700
--- alpine-2.00.I.USE/web/src/alpined.d/Makefile.in	2011-02-07 20:33:46.000000000 -0800
***************
*** 619,624 ****
--- 619,625 ----
  	 debug.c status.c stubs.c alpined.h color.h ldap.h
  	echo "char datestamp[]="\"`date`\"";" > local.c
  	echo "char hoststamp[]="\"`hostname`\"";" >> local.c
+ 	cat ../../../patchlevel >> local.c
  # Tell versions [3.59,3.63) of GNU make to not export all variables.
  # Otherwise a system limit (for SysV at least) may be exceeded.
  .NOEXPORT: