diff --git a/alpine/adrbkcmd.c b/alpine/adrbkcmd.c index 66b1191..23d25a3 100644 --- a/alpine/adrbkcmd.c +++ b/alpine/adrbkcmd.c @@ -4128,6 +4128,8 @@ ab_compose_internal(BuildTo bldto, int allow_role) * 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{ @@ -4135,6 +4137,7 @@ ab_compose_internal(BuildTo bldto, int allow_role) 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 --git a/alpine/alpine.c b/alpine/alpine.c index e0c1f40..99a8a23 100644 --- a/alpine/alpine.c +++ b/alpine/alpine.c @@ -497,6 +497,7 @@ main(int argc, char **argv) /* 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){ @@ -3245,6 +3246,9 @@ goodnight_gracey(struct pine *pine_state, int exit_val) 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 --git a/alpine/confscroll.c b/alpine/confscroll.c index 2fe034b..2b69445 100644 --- a/alpine/confscroll.c +++ b/alpine/confscroll.c @@ -51,6 +51,7 @@ static char rcsid[] = "$Id: confscroll.c 1169 2008-08-27 06:42:06Z hubert@u.wash #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") @@ -2442,6 +2443,9 @@ delete: * 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); @@ -5206,6 +5210,30 @@ fix_side_effects(struct pine *ps, struct variable *var, int revert) 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); diff --git a/alpine/dispfilt.c b/alpine/dispfilt.c index 16ade44..41927ae 100644 --- a/alpine/dispfilt.c +++ b/alpine/dispfilt.c @@ -461,3 +461,63 @@ df_valid_test(struct mail_bodystruct *body, char *test) 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 --git a/alpine/dispfilt.h b/alpine/dispfilt.h index c61a7a8..833ff6f 100644 --- a/alpine/dispfilt.h +++ b/alpine/dispfilt.h @@ -25,7 +25,7 @@ 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 --git a/alpine/folder.c b/alpine/folder.c index c48536f..46803f5 100644 --- a/alpine/folder.c +++ b/alpine/folder.c @@ -248,7 +248,7 @@ folder_screen(struct pine *ps) 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; @@ -345,6 +345,7 @@ folder_screen(struct pine *ps) pine_mail_close(*fs.cache_streamp); ps->prev_screen = folder_screen; + strcpy(ps->screen_name, "unknown"); } diff --git a/alpine/mailcmd.c b/alpine/mailcmd.c index 204c314..943f074 100644 --- a/alpine/mailcmd.c +++ b/alpine/mailcmd.c @@ -73,6 +73,7 @@ static char rcsid[] = "$Id: mailcmd.c 1266 2009-07-14 18:39:12Z hubert@u.washing #include "../pith/tempfile.h" #include "../pith/search.h" #include "../pith/margin.h" +#include "../pith/rules.h" #ifdef _WINDOWS #include "../pico/osdep/mswin.h" #endif @@ -2708,6 +2709,9 @@ role_compose(struct pine *state) 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': @@ -2758,12 +2762,12 @@ save_prompt(struct pine *state, CONTEXT_S **cntxt, char *nfldr, size_t len_nfldr 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 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; + char *folder, folder2[MAXPATH]; HelpType help; SaveDel del = DontAsk; SavePreserveOrder pre = DontAskPreserve; @@ -2771,6 +2775,7 @@ save_prompt(struct pine *state, CONTEXT_S **cntxt, char *nfldr, size_t len_nfldr static HISTORY_S *history = NULL; CONTEXT_S *tc; ESCKEY_S ekey[10]; + RULE_RESULT *rule; if(!cntxt) alpine_panic("no context ptr in save_prompt"); @@ -2780,6 +2785,15 @@ save_prompt(struct pine *state, CONTEXT_S **cntxt, char *nfldr, size_t len_nfldr 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)) diff --git a/alpine/mailindx.c b/alpine/mailindx.c index c5862c6..0e83c90 100644 --- a/alpine/mailindx.c +++ b/alpine/mailindx.c @@ -229,6 +229,8 @@ mail_index_screen(struct pine *state) 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 @@ -240,10 +242,14 @@ mail_index_screen(struct pine *state) 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"); } diff --git a/alpine/mailview.c b/alpine/mailview.c index c151a1e..45d90e9 100644 --- a/alpine/mailview.c +++ b/alpine/mailview.c @@ -244,6 +244,8 @@ mail_view_screen(struct pine *ps) 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")); @@ -480,6 +482,8 @@ mail_view_screen(struct pine *ps) } while(ps->next_screen == SCREEN_FUN_NULL); + strcpy(ps->screen_name, "unknown"); + if(we_cancel) cancel_busy_cue(-1); diff --git a/alpine/osdep/termin.gen.c b/alpine/osdep/termin.gen.c index dfea78f..9af7674 100644 --- a/alpine/osdep/termin.gen.c +++ b/alpine/osdep/termin.gen.c @@ -33,6 +33,8 @@ static char rcsid[] = "$Id: termin.gen.c 1025 2008-04-08 22:59:38Z hubert@u.wash #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" @@ -72,7 +74,8 @@ int pcpine_oe_cursor(int, long); * 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 @@ -114,6 +117,41 @@ read_command(char **utf8str) *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(); @@ -1158,6 +1196,7 @@ process_config_input(UCS *ch) if(ps_global->initial_cmds && !*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 --git a/alpine/reply.c b/alpine/reply.c index 89c0d9b..0e0a3e2 100644 --- a/alpine/reply.c +++ b/alpine/reply.c @@ -62,7 +62,8 @@ The evolution continues... #include "../pith/tempfile.h" #include "../pith/busy.h" #include "../pith/ablookup.h" - +#include "../pith/copyaddr.h" +#include "../pith/rules.h" /* * Internal Prototypes @@ -109,11 +110,12 @@ reply(struct pine *pine_state, ACTION_S *role_arg) 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; + 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 @@ -139,6 +141,69 @@ reply(struct pine *pine_state, ACTION_S *role_arg) && 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(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... @@ -287,8 +352,18 @@ reply(struct pine *pine_state, ACTION_S *role_arg) outgoing->subject = cpystr("Re: several messages"); } } - else - outgoing->subject = reply_subject(env->subject, NULL, 0); + else{ + RULE_RESULT *rule; + rule = get_result_rule(V_RESUB_RULES,FOR_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 */ @@ -307,13 +382,7 @@ reply(struct pine *pine_state, ACTION_S *role_arg) if(sp_expunge_count(pine_state->mail_stream)) /* cur msg expunged */ goto done_early; - /* Setup possible role */ - if (ps_global->reply.role_chosen) - role = ps_global->reply.role_chosen; - else if(role_arg) - role = copy_action(role_arg); - - if(!role){ + if(!do_role_early){ rflags = ROLE_REPLY; if(!ps_global->reply.role_chosen && nonempty_patterns(rflags, &dummy)){ /* setup default role */ @@ -724,6 +793,9 @@ reply(struct pine *pine_state, ACTION_S *role_arg) if(prefix) fs_give((void **)&prefix); + if (ps_global->role) + fs_give((void **)&ps_global->role); + if(fcc) fs_give((void **) &fcc); @@ -1598,9 +1670,14 @@ forward(struct pine *ps, ACTION_S *role_arg) } } - if(role) + 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; @@ -1832,6 +1909,7 @@ forward(struct pine *ps, ACTION_S *role_arg) #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); diff --git a/alpine/roleconf.c b/alpine/roleconf.c index a226f47..0d00b79 100644 --- a/alpine/roleconf.c +++ b/alpine/roleconf.c @@ -7706,6 +7706,11 @@ role_text_tool_inick(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) 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 --git a/alpine/send.c b/alpine/send.c index 41dff03..af7d2a1 100644 --- a/alpine/send.c +++ b/alpine/send.c @@ -63,7 +63,7 @@ static char rcsid[] = "$Id: send.c 1142 2008-08-13 17:22:21Z hubert@u.washington #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; @@ -240,6 +240,11 @@ alt_compose_screen(struct pine *pine_state) 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); @@ -449,8 +454,12 @@ compose_mail(char *given_to, char *fcc_arg, ACTION_S *role_arg, ps_global->next_screen = prev_screen; ps_global->redrawer = redraw; - if(role) + if (ps_global->role) + fs_give((void **)&ps_global->role); + if(role){ role = combine_inherited_role(role); + ps_global->role = cpystr(role->nick); + } } break; @@ -645,9 +654,14 @@ compose_mail(char *given_to, char *fcc_arg, ACTION_S *role_arg, } } - if(role) + 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 @@ -2477,6 +2491,26 @@ pine_send(ENVELOPE *outgoing, struct mail_bodystruct **body, 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); diff --git a/pith/Makefile.am b/pith/Makefile.am index 09d8f99..de2ea57 100644 --- a/pith/Makefile.am +++ b/pith/Makefile.am @@ -26,7 +26,7 @@ libpith_a_SOURCES = ablookup.c abdlc.c addrbook.c addrstring.c adrbklib.c bldadd filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c ical.c imap.c init.c \ keyword.c ldap.c list.c mailcap.c mailcmd.c mailindx.c maillist.c mailview.c \ margin.c mimedesc.c mimetype.c msgno.c newmail.c news.c pattern.c pipe.c \ - readfile.c remote.c reply.c rfc2231.c save.c search.c sequence.c send.c sort.c \ + readfile.c remote.c reply.c rfc2231.c rules.c save.c search.c sequence.c send.c sort.c \ state.c status.c store.c stream.c string.c strlst.c takeaddr.c tempfile.c text.c \ thread.c adjtime.c url.c util.c helptext.c smkeys.c smime.c diff --git a/pith/Makefile.in b/pith/Makefile.in index 64b9a46..ea51bc9 100644 --- a/pith/Makefile.in +++ b/pith/Makefile.in @@ -134,7 +134,7 @@ am_libpith_a_OBJECTS = ablookup.$(OBJEXT) abdlc.$(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) \ + 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) \ @@ -437,7 +437,7 @@ libpith_a_SOURCES = ablookup.c abdlc.c addrbook.c addrstring.c adrbklib.c bldadd filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c ical.c imap.c init.c \ keyword.c ldap.c list.c mailcap.c mailcmd.c mailindx.c maillist.c mailview.c \ margin.c mimedesc.c mimetype.c msgno.c newmail.c news.c pattern.c pipe.c \ - readfile.c remote.c reply.c rfc2231.c save.c search.c sequence.c send.c sort.c \ + readfile.c remote.c reply.c rfc2231.c rules.c save.c search.c sequence.c send.c sort.c \ state.c status.c store.c stream.c string.c strlst.c takeaddr.c tempfile.c text.c \ thread.c adjtime.c url.c util.c helptext.c smkeys.c smime.c @@ -580,6 +580,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rules.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/pith/adrbklib.c b/pith/adrbklib.c index fe054d9..09e093c 100644 --- a/pith/adrbklib.c +++ b/pith/adrbklib.c @@ -5138,8 +5138,14 @@ init_addrbooks(OpenStatus want_status, int reset_to_top, int open_if_only_one, i if(as.cur >= as.how_many_personals) pab->type |= GLOBAL; - pab->access = adrbk_access(pab); - + if(ps_global->mail_stream && + ps_global->mail_stream->lock && (pab->type & REMOTE_VIA_IMAP)){ + as.initialized = 0; + pab->access = NoAccess; + } + else{ + pab->access = adrbk_access(pab); + } /* global address books are forced readonly */ if(pab->type & GLOBAL && pab->access != NoAccess) pab->access = ReadOnly; diff --git a/pith/conf.c b/pith/conf.c index cea59de..59e6744 100644 --- a/pith/conf.c +++ b/pith/conf.c @@ -29,6 +29,7 @@ static char rcsid[] = "$Id: conf.c 1266 2009-07-14 18:39:12Z hubert@u.washington #include "../pith/remote.h" #include "../pith/keyword.h" #include "../pith/mailview.h" +#include "../pith/rules.h" #include "../pith/list.h" #include "../pith/status.h" #include "../pith/ldap.h" @@ -223,6 +224,36 @@ CONF_TXT_T cf_text_unk_character_set[] = "Defaults to nothing, which is equivale CONF_TXT_T cf_text_editor[] = "Specifies the program invoked by ^_ in the Composer,\n# or the \"enable-alternate-editor-implicitly\" feature."; +CONF_TXT_T cf_text_compose_rules[] = "Allows a user to set rules when composing messages."; + +CONF_TXT_T cf_text_forward_rules[] = "Allows a user to set rules when forwarding messages."; + +CONF_TXT_T cf_text_reply_rules[] = "Allows a user to set rules when replying messages."; + +CONF_TXT_T cf_text_index_rules[] = "Allows a user to supersede global index format variable in designated folders."; + +CONF_TXT_T cf_text_key_def_rules[] = "Allows a user to override keystrokes in certain screens."; + +CONF_TXT_T cf_text_replace_rules[] = "Allows a user to change the form a specify field in the index-format is \n# displayed."; + +CONF_TXT_T cf_text_reply_indent_rules[] = "Allows a user to change the form a specify a reply-indent-string\n# based of rules."; + +CONF_TXT_T cf_text_reply_leadin_rules[] = "Allows a user to replace the reply-leadin message based on different parameters."; + +CONF_TXT_T cf_text_reply_subject_rules[] = "Allows a user to replace the subject of a message in a customs based way"; + +CONF_TXT_T cf_text_thread_displaystyle_rule[] = "Allows a user to specify the threading style of specific folders"; + +CONF_TXT_T cf_text_thread_indexstyle_rule[] = "Allows a user to specify the threading index style of specific folders"; + +CONF_TXT_T cf_text_save_rules[] = "Allows a user to specify a save folder message for specific senders or folders."; + +CONF_TXT_T cf_text_smtp_rules[] = "Allows a user to specify a smtp server to be used when sending e-mail,\n# according to the rules specified here."; + +CONF_TXT_T cf_text_sort_rules[] = "Allows a user to specify the sort default order of a specific folder."; + +CONF_TXT_T cf_text_startup_rules[] = "Allows a user to specify the position of a highlighted message when opening a \n# folder."; + CONF_TXT_T cf_text_speller[] = "Specifies the program invoked by ^T in the Composer."; #ifdef _WINDOWS @@ -555,6 +586,34 @@ static struct variable variables[] = { NULL, cf_text_thread_exp_char}, {"threading-lastreply-character", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, "Threading Last Reply Character", cf_text_thread_lastreply_char}, +{"threading-display-style-rule", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, + "Threading Display Style Rule", cf_text_thread_displaystyle_rule}, +{"threading-index-style-rule", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, + "Threading Index Style Rule", cf_text_thread_indexstyle_rule}, +{"compose-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, + "Compose Rules", cf_text_compose_rules}, +{"forward-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, + "Forward Rules", cf_text_forward_rules}, +{"index-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, + "Index Rules", cf_text_index_rules}, +{"key-definition-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, + "Key Definition Rules", cf_text_key_def_rules}, +{"replace-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, + "Replace Rules", cf_text_replace_rules}, +{"reply-indent-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, + "Reply Indent Rules", cf_text_reply_indent_rules}, +{"reply-leadin-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, + "Reply Leadin Rules", cf_text_reply_leadin_rules}, +{"reply-subject-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, + "Reply Subject Rules", cf_text_reply_subject_rules}, +{"save-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, + "Save Rules", cf_text_save_rules}, +{"smtp-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, + "Smtp Rules", cf_text_smtp_rules}, +{"sort-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, + "Sort Rules", cf_text_sort_rules}, +{"startup-rules", 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, + "Startup Rules", cf_text_startup_rules}, #ifndef _WINDOWS {"display-character-set", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, NULL, cf_text_disp_char_set}, @@ -2653,6 +2712,7 @@ init_vars(struct pine *ps, void (*cmds_f) (struct pine *, char **)) if(cmds_f) (*cmds_f)(ps, VAR_INIT_CMD_LIST); + (void)create_rule_list(ps_global->vars); #ifdef _WINDOWS mswin_set_quit_confirm (F_OFF(F_QUIT_WO_CONFIRM, ps_global)); #endif /* _WINDOWS */ @@ -3099,6 +3159,8 @@ feature_list(int index) F_FORCE_LOW_SPEED, h_config_force_low_speed, PREF_OS_LWSD, 0}, {"auto-move-read-msgs", "Auto Move Read Messages", F_AUTO_READ_MSGS, h_config_auto_read_msgs, PREF_MISC, 0}, + {"auto-move-read-msgs-using-rules", "Auto Move Read Messages Using Rules", + F_AUTO_READ_MSGS_RULES, h_config_auto_read_msgs_rules, PREF_MISC, 0}, {"auto-unselect-after-apply", NULL, F_AUTO_UNSELECT, h_config_auto_unselect, PREF_MISC, 0}, {"auto-unzoom-after-apply", NULL, @@ -7725,6 +7787,34 @@ config_help(int var, int feature) 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 : diff --git a/pith/conf.h b/pith/conf.h index a2e5a8a..cf66627 100644 --- a/pith/conf.h +++ b/pith/conf.h @@ -148,6 +148,46 @@ #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 diff --git a/pith/conftype.h b/pith/conftype.h index 42573ce..cff46b3 100644 --- a/pith/conftype.h +++ b/pith/conftype.h @@ -70,6 +70,20 @@ typedef enum { V_PERSONAL_NAME = 0 , V_THREAD_MORE_CHAR , V_THREAD_EXP_CHAR , V_THREAD_LASTREPLY_CHAR + , V_THREAD_DISP_STYLE_RULES + , V_THREAD_INDEX_STYLE_RULES + , V_COMPOSE_RULES + , V_FORWARD_RULES + , V_INDEX_RULES + , V_KEY_RULES + , V_REPLACE_RULES + , V_REPLY_INDENT_RULES + , V_REPLY_LEADIN_RULES + , V_RESUB_RULES + , V_SAVE_RULES + , V_SMTP_RULES + , V_SORT_RULES + , V_STARTUP_RULES #ifndef _WINDOWS , V_CHAR_SET , V_OLD_CHAR_SET @@ -334,6 +348,7 @@ typedef enum { F_FULL_AUTO_EXPUNGE, F_EXPUNGE_MANUALLY, F_AUTO_READ_MSGS, + F_AUTO_READ_MSGS_RULES, F_AUTO_FCC_ONLY, F_READ_IN_NEWSRC_ORDER, F_SELECT_WO_CONFIRM, diff --git a/pith/detoken.c b/pith/detoken.c index 01f2d51..43687e5 100644 --- a/pith/detoken.c +++ b/pith/detoken.c @@ -25,7 +25,7 @@ static char rcsid[] = "$Id: detoken.c 769 2007-10-24 00:15:40Z hubert@u.washingt #include "../pith/reply.h" #include "../pith/mailindx.h" #include "../pith/options.h" - +#include "../pith/rules.h" /* * Hook to read signature from local file @@ -91,6 +91,8 @@ detoken(ACTION_S *role, ENVELOPE *env, int prenewlines, int postnewlines, if(is_sig){ /* + * First we check if there is a rule about signatures, if there is + * use it, otherwise keep going and do the following: * If role->litsig is set, we use it; * Else, if VAR_LITERAL_SIG is set, we use that; * Else, if role->sig is set, we use that; @@ -104,14 +106,25 @@ detoken(ACTION_S *role, ENVELOPE *env, int prenewlines, int postnewlines, * there is no reason to mix them, so we don't provide support to * do so. */ - if(role && role->litsig) - literal_sig = role->litsig; - else if(ps_global->VAR_LITERAL_SIG) - literal_sig = ps_global->VAR_LITERAL_SIG; - else if(role && role->sig) - sigfile = role->sig; - else - sigfile = ps_global->VAR_SIGNATURE_FILE; + { RULE_RESULT *rule; + rule = get_result_rule(V_COMPOSE_RULES, FOR_COMPOSE, env); + if (rule){ + sigfile = cpystr(rule->result); + if (rule->result) + fs_give((void **)&rule->result); + fs_give((void **)&rule); + } + } + if (!sigfile){ + if(role && role->litsig) + literal_sig = role->litsig; + else if(ps_global->VAR_LITERAL_SIG) + literal_sig = ps_global->VAR_LITERAL_SIG; + else if(role && role->sig) + sigfile = role->sig; + else + sigfile = ps_global->VAR_SIGNATURE_FILE; + } } else if(role && role->template) sigfile = role->template; @@ -302,7 +315,7 @@ top: } } } - else if(pt->what_for & FOR_REPLY_INTRO) + else if(pt->what_for & (FOR_REPLY_INTRO | FOR_RULE)) repl = get_reply_data(env, role, pt->ctype, subbuf, sizeof(subbuf)-1); diff --git a/pith/indxtype.h b/pith/indxtype.h index 33ef5d9..c34ea39 100644 --- a/pith/indxtype.h +++ b/pith/indxtype.h @@ -84,6 +84,11 @@ typedef enum {iNothing, iStatus, iFStatus, iIStatus, iSIStatus, iCurNews, iArrow, iMailbox, iAddress, iInit, iCursorPos, iDay2Digit, iMon2Digit, iYear2Digit, + iFolder, iFlag, iCollection, iRole, iProcid, iScreen, iPkey, + iNick, iFccFrom, iFccSender, iAltAddress, + iAddressTo, iAddressCc, iAddressRecip, iAddressSender, + iBcc, iLcc, + iFfrom, iFadd, iSTime, iSTime24, iKSize, iRoleNick, iNewLine, iHeader, iText, @@ -105,15 +110,26 @@ typedef struct index_parse_tokens { /* these are flags for the what_for field in INDEX_PARSE_T */ -#define FOR_NOTHING 0x00 -#define FOR_INDEX 0x01 -#define FOR_REPLY_INTRO 0x02 -#define FOR_TEMPLATE 0x04 /* or for signature */ -#define FOR_FILT 0x08 -#define DELIM_USCORE 0x10 -#define DELIM_PAREN 0x20 -#define DELIM_COLON 0x40 - +#define FOR_NOTHING 0x00000 +#define FOR_INDEX 0x00001 +#define FOR_REPLY_INTRO 0x00002 +#define FOR_TEMPLATE 0x00004 /* or for signature */ +#define FOR_FILT 0x00008 +#define DELIM_USCORE 0x00010 +#define DELIM_PAREN 0x00020 +#define DELIM_COLON 0x00040 +#define FOR_FOLDER 0x00080 /* for rules */ +#define FOR_RULE 0x00100 /* for rules */ +#define FOR_TRIM 0x00200 /* for rules */ +#define FOR_RESUB 0x00400 /* for rules */ +#define FOR_REPLACE 0x00800 /* for rules */ +#define FOR_SORT 0x01000 /* for rules */ +#define FOR_FLAG 0x02000 /* for rules */ +#define FOR_COMPOSE 0x04000 /* for rules */ +#define FOR_THREAD 0x08000 /* for rules */ +#define FOR_STARTUP 0x10000 /* for rules */ +#define FOR_KEY 0x20000 /* for rules */ +#define FOR_SAVE 0x40000 /* for rules */ #define DEFAULT_REPLY_INTRO "default" diff --git a/pith/mailcmd.c b/pith/mailcmd.c index 9a852c9..b1ab110 100644 --- a/pith/mailcmd.c +++ b/pith/mailcmd.c @@ -39,6 +39,7 @@ static char rcsid[] = "$Id: mailcmd.c 1142 2008-08-13 17:22:21Z hubert@u.washing #include "../pith/ablookup.h" #include "../pith/search.h" #include "../pith/charconv/utf8.h" +#include "../pith/rules.h" #ifdef _WINDOWS #include "../pico/osdep/mswin.h" @@ -665,6 +666,7 @@ do_broach_folder(char *newfolder, CONTEXT_S *new_context, MAILSTREAM **streamp, strncpy(ps_global->cur_folder, p, sizeof(ps_global->cur_folder)-1); ps_global->cur_folder[sizeof(ps_global->cur_folder)-1] = '\0'; ps_global->context_current = ps_global->context_list; + setup_threading_index_style(); reset_index_format(); clear_index_cache(ps_global->mail_stream, 0); /* MUST sort before restoring msgno! */ @@ -991,6 +993,7 @@ do_broach_folder(char *newfolder, CONTEXT_S *new_context, MAILSTREAM **streamp, clear_index_cache(ps_global->mail_stream, 0); reset_index_format(); + setup_threading_index_style(); /* * Start news reading with messages the user's marked deleted @@ -1114,7 +1117,10 @@ do_broach_folder(char *newfolder, CONTEXT_S *new_context, MAILSTREAM **streamp, if(!cur_already_set && mn_get_total(ps_global->msgmap) > 0L){ - perfolder_startup_rule = reset_startup_rule(ps_global->mail_stream); + perfolder_startup_rule = get_perfolder_startup_rule(ps_global->mail_stream, + V_STARTUP_RULES, newfolder); + + reset_startup_rule(ps_global->mail_stream); if(ps_global->start_entry > 0){ mn_set_cur(ps_global->msgmap, mn_get_revsort(ps_global->msgmap) @@ -1136,124 +1142,7 @@ do_broach_folder(char *newfolder, CONTEXT_S *new_context, MAILSTREAM **streamp, else use_this_startup_rule = ps_global->inc_startup_rule; - switch(use_this_startup_rule){ - /* - * For news in incoming collection we're doing the same thing - * for first-unseen and first-recent. In both those cases you - * get first-unseen if FAKE_NEW is off and first-recent if - * FAKE_NEW is on. If FAKE_NEW is on, first unseen is the - * same as first recent because all recent msgs are unseen - * and all unrecent msgs are seen (see pine_mail_open). - */ - case IS_FIRST_UNSEEN: -first_unseen: - mn_set_cur(ps_global->msgmap, - (sp_first_unseen(m) - && mn_get_sort(ps_global->msgmap) == SortArrival - && !mn_get_revsort(ps_global->msgmap) - && !get_lflag(ps_global->mail_stream, NULL, - sp_first_unseen(m), MN_EXLD) - && (n = mn_raw2m(ps_global->msgmap, - sp_first_unseen(m)))) - ? n - : first_sorted_flagged(F_UNSEEN | F_UNDEL, m, pc, - THREADING() ? 0 : FSF_SKIP_CHID)); - break; - - case IS_FIRST_RECENT: -first_recent: - /* - * We could really use recent for news but this is the way - * it has always worked, so we'll leave it. That is, if - * the FAKE_NEW feature is on, recent and unseen are - * equivalent, so it doesn't matter. If the feature isn't - * on, all the undeleted messages are unseen and we start - * at the first one. User controls with the FAKE_NEW feature. - */ - if(IS_NEWS(ps_global->mail_stream)){ - mn_set_cur(ps_global->msgmap, - first_sorted_flagged(F_UNSEEN|F_UNDEL, m, pc, - THREADING() ? 0 : FSF_SKIP_CHID)); - } - else{ - mn_set_cur(ps_global->msgmap, - first_sorted_flagged(F_RECENT | F_UNSEEN - | F_UNDEL, - m, pc, - THREADING() ? 0 : FSF_SKIP_CHID)); - } - break; - - case IS_FIRST_IMPORTANT: - mn_set_cur(ps_global->msgmap, - first_sorted_flagged(F_FLAG|F_UNDEL, m, pc, - THREADING() ? 0 : FSF_SKIP_CHID)); - break; - - case IS_FIRST_IMPORTANT_OR_UNSEEN: - - if(IS_NEWS(ps_global->mail_stream)) - goto first_unseen; - - { - MsgNo flagged, first_unseen; - - flagged = first_sorted_flagged(F_FLAG|F_UNDEL, m, pc, - THREADING() ? 0 : FSF_SKIP_CHID); - first_unseen = (sp_first_unseen(m) - && mn_get_sort(ps_global->msgmap) == SortArrival - && !mn_get_revsort(ps_global->msgmap) - && !get_lflag(ps_global->mail_stream, NULL, - sp_first_unseen(m), MN_EXLD) - && (n = mn_raw2m(ps_global->msgmap, - sp_first_unseen(m)))) - ? n - : first_sorted_flagged(F_UNSEEN|F_UNDEL, m, pc, - THREADING() ? 0 : FSF_SKIP_CHID); - mn_set_cur(ps_global->msgmap, - (MsgNo) MIN((int) flagged, (int) first_unseen)); - - } - - break; - - case IS_FIRST_IMPORTANT_OR_RECENT: - - if(IS_NEWS(ps_global->mail_stream)) - goto first_recent; - - { - MsgNo flagged, first_recent; - - flagged = first_sorted_flagged(F_FLAG|F_UNDEL, m, pc, - THREADING() ? 0 : FSF_SKIP_CHID); - first_recent = first_sorted_flagged(F_RECENT | F_UNSEEN - | F_UNDEL, - m, pc, - THREADING() ? 0 : FSF_SKIP_CHID); - mn_set_cur(ps_global->msgmap, - (MsgNo) MIN((int) flagged, (int) first_recent)); - } - - break; - - case IS_FIRST: - mn_set_cur(ps_global->msgmap, - first_sorted_flagged(F_UNDEL, m, pc, - THREADING() ? 0 : FSF_SKIP_CHID)); - break; - - case IS_LAST: - mn_set_cur(ps_global->msgmap, - first_sorted_flagged(F_UNDEL, m, pc, - FSF_LAST | (THREADING() ? 0 : FSF_SKIP_CHID))); - break; - - default: - alpine_panic("Unexpected incoming startup case"); - break; - - } + find_startup_position(use_this_startup_rule, m, pc); } else if(IS_NEWS(ps_global->mail_stream)){ /* @@ -1431,9 +1320,11 @@ expunge_and_close(MAILSTREAM *stream, char **final_msg, long unsigned int flags) /* Save read messages? */ if(VAR_READ_MESSAGE_FOLDER && VAR_READ_MESSAGE_FOLDER[0] && sp_flagged(stream, SP_INBOX) - && (seen_not_del = count_flagged(stream, F_SEEN | F_UNDEL))){ + && (F_ON(F_AUTO_READ_MSGS_RULES, ps_global) || + (seen_not_del = count_flagged(stream, F_SEEN | F_UNDEL)))){ if(F_ON(F_AUTO_READ_MSGS,ps_global) + || F_ON(F_AUTO_READ_MSGS_RULES, ps_global) || (pith_opt_read_msg_prompt && (*pith_opt_read_msg_prompt)(seen_not_del, VAR_READ_MESSAGE_FOLDER))) /* move inbox's read messages */ @@ -1716,6 +1607,9 @@ move_read_msgs(MAILSTREAM *stream, char *dstfldr, char *buf, size_t buflen, long char *bufp = NULL; MESSAGECACHE *mc; + if (F_ON(F_AUTO_READ_MSGS_RULES, ps_global)) + return move_read_msgs_using_rules(stream, dstfldr, buf); + if(!is_absolute_path(dstfldr) && !(save_context = default_save_context(ps_global->context_list))) save_context = ps_global->context_list; @@ -1755,8 +1649,9 @@ move_read_msgs(MAILSTREAM *stream, char *dstfldr, char *buf, size_t buflen, long snprintf(buf, buflen, "Moving %s read message%s to \"%s\"", comatose(searched), plural(searched), dstfldr); we_cancel = busy_cue(buf, NULL, 0); - if(save(ps_global, stream, save_context, dstfldr, msgmap, - SV_DELETE | SV_FIX_DELS | SV_INBOXWOCNTXT) == searched) + ps_global->exiting = 1; + if((save(ps_global, stream, save_context, dstfldr, msgmap, + SV_DELETE | SV_FIX_DELS | SV_INBOXWOCNTXT) == searched)) strncpy(bufp = buf + 1, "Moved", MIN(5,buflen)); /* change Moving to Moved */ buf[buflen-1] = '\0'; @@ -1794,7 +1689,9 @@ move_read_incoming(MAILSTREAM *stream, CONTEXT_S *context, char *folder, && ((context_isambig(folder) && folder_is_nick(folder, FOLDERS(context), 0)) || folder_index(folder, context, FI_FOLDER) > 0) - && (seen_undel = count_flagged(stream, F_SEEN | F_UNDEL))){ + && ((seen_undel = count_flagged(stream, F_SEEN | F_UNDEL)) + || (F_ON(F_AUTO_READ_MSGS,ps_global) && + F_ON(F_AUTO_READ_MSGS_RULES, ps_global)))){ for(; f && *archive; archive++){ char *p; @@ -2761,3 +2658,295 @@ get_uname(char *mailbox, char *target, int len) return(*target ? target : NULL); } + +char * +move_read_msgs_using_rules(MAILSTREAM *stream, char *dstfldr, char *buf) +{ + CONTEXT_S *save_context = NULL; + char **folder_to_save = NULL; + int num, we_cancel; + long i, j, success; + MSGNO_S *msgmap = NULL; + unsigned long nmsgs = 0L, stream_nmsgs; + + if(!is_absolute_path(dstfldr) + && !(save_context = default_save_context(ps_global->context_list))) + save_context = ps_global->context_list; + + folder_to_save = (char **)fs_get((stream->nmsgs + 1)*sizeof(char *)); + folder_to_save[0] = NULL; + mn_init(&msgmap, stream->nmsgs); + stream_nmsgs = stream->nmsgs; + for (i = 1L; i <= stream_nmsgs ; i++){ + set_lflag(stream, msgmap, i, MN_SLCT, 0); + folder_to_save[i] = get_lflag(stream, NULL, i, MN_EXLD) + ? NULL : get_folder_to_save(stream, i, dstfldr); + } + for (i = 1L; i <= stream_nmsgs; i++){ + num = 0; + if (folder_to_save[i]){ + mn_init(&msgmap, stream_nmsgs); + for (j = i; j <= stream_nmsgs ; j++){ + if (folder_to_save[j]){ + if (!strcmp(folder_to_save[i], folder_to_save[j])){ + set_lflag(stream, msgmap, j, MN_SLCT, 1); + num++; + if (j != i) + fs_give((void **)&folder_to_save[j]); + } + } + } + pseudo_selected(stream, msgmap); + sprintf(buf, "Moving %s read message%s to \"%.45s\"", + comatose(num), plural(num), folder_to_save[i]); + we_cancel = busy_cue(buf, NULL, 1); + ps_global->exiting = 1; + if(success = save(ps_global, stream,save_context, folder_to_save[i], + msgmap, SV_DELETE | SV_FIX_DELS)) + nmsgs += success; + if(we_cancel) + cancel_busy_cue(success ? 0 : -1); + for (j = i; j <= stream_nmsgs ; j++) + set_lflag(stream, msgmap, j, MN_SLCT, 0); + fs_give((void **)&folder_to_save[i]); + mn_give(&msgmap); + } + } + ps_global->exiting = 0; /* useful if we call from aggregate operations */ + sprintf(buf, "Moved automatically %s message%s", + comatose(nmsgs), plural(nmsgs)); + if (folder_to_save) + fs_give((void **)folder_to_save); + rule_curpos = 0L; + return buf; +} + +char * +get_folder_to_save(MAILSTREAM *stream, long i, char *dstfldr) +{ + MESSAGECACHE *mc = NULL; + RULE_RESULT *rule; + MSGNO_S *msgmap = NULL; + char *folder_to_save = NULL, *save_folder = NULL; + int n; + long msgno; + + /* The plan is as follows: Select each message of the folder. We + * need to set the cursor correctly so that iFlag gets the value + * correctly too, otherwise iFlag will get the value of the position + * of the cursor. After that we need to look for a rule that applies + * to the message and get the saving folder. If we get a saving folder, + * and we used the _FLAG_ token, use that folder, if no + * _FLAG_ token was used, move only if seen and not deleted, to the + * folder specified in the saving rule. If we did not get a saving + * folder from the rule, just save in the default folder. + */ + mn_init(&msgmap, stream->nmsgs); + rule_curpos = i; + msgno = mn_m2raw(msgmap, i); + if (msgno > 0L){ + mc = mail_elt(stream, msgno); + rule = (RULE_RESULT *) + get_result_rule(V_SAVE_RULES, FOR_SAVE, mc->private.msg.env); + if (rule){ + folder_to_save = cpystr(rule->result); + n = rule->number; + fs_give((void **)&rule->result); + fs_give((void **)&rule); + } + } + + if (folder_to_save && *folder_to_save){ + RULELIST *list = get_rulelist_from_code(V_SAVE_RULES, + ps_global->rule_list); + RULE_S *prule = get_rule(list, n); + if (condition_contains_token(prule->condition, "_FLAG_") + || (mc->valid && mc->seen && !mc->deleted) + || (!mc->valid && mc->searched)) + save_folder = cpystr(folder_to_save); + else + save_folder = NULL; + } + else + if (!mc || (mc->seen && !mc->deleted)) + save_folder = cpystr(dstfldr); + mn_give(&msgmap); + rule_curpos = 0L; + return save_folder; +} + +unsigned long +rules_cursor_pos(MAILSTREAM *stream) +{ + MSGNO_S *msgmap = sp_msgmap(stream); + return rule_curpos != 0L ? rule_curpos : mn_m2raw(msgmap,mn_get_cur(msgmap)); +} + +void +setup_threading_index_style(void) +{ + RULE_RESULT *rule; + NAMEVAL_S *v; + int i; + + rule = get_result_rule(V_THREAD_INDEX_STYLE_RULES, FOR_THREAD, NULL); + if (rule || ps_global->VAR_THREAD_INDEX_STYLE){ + for(i = 0; v = thread_index_styles(i); i++) + if(!strucmp(rule ? rule->result : ps_global->VAR_THREAD_INDEX_STYLE, + rule ? (v ? v->name : "" ) : S_OR_L(v))){ + ps_global->thread_index_style = v->value; + break; + } + if (rule){ + if (rule->result) + fs_give((void **)&rule->result); + fs_give((void **)&rule); + } + } +} + +unsigned +get_perfolder_startup_rule(MAILSTREAM *stream, int rule_type, char *folder) +{ + unsigned startup_rule; + char *rule_result; + + startup_rule = reset_startup_rule(stream); + rule_result = get_rule_result(FOR_STARTUP, folder, rule_type); + if (rule_result && *rule_result){ + int i; + NAMEVAL_S *v; + + for(i = 0; v = incoming_startup_rules(i); i++) + if(!strucmp(rule_result, v->name)){ + startup_rule = v->value; + break; + } + fs_give((void **)&rule_result); + } + return startup_rule; +} + +void +find_startup_position(int rule, MAILSTREAM *m, long pc) +{ + long n; + switch(rule){ + /* + * For news in incoming collection we're doing the same thing + * for first-unseen and first-recent. In both those cases you + * get first-unseen if FAKE_NEW is off and first-recent if + * FAKE_NEW is on. If FAKE_NEW is on, first unseen is the + * same as first recent because all recent msgs are unseen + * and all unrecent msgs are seen (see pine_mail_open). + */ + case IS_FIRST_UNSEEN: +first_unseen: + mn_set_cur(ps_global->msgmap, + (sp_first_unseen(m) + && mn_get_sort(ps_global->msgmap) == SortArrival + && !mn_get_revsort(ps_global->msgmap) + && !get_lflag(ps_global->mail_stream, NULL, + sp_first_unseen(m), MN_EXLD) + && (n = mn_raw2m(ps_global->msgmap, + sp_first_unseen(m)))) + ? n + : first_sorted_flagged(F_UNSEEN | F_UNDEL, m, pc, + THREADING() ? 0 : FSF_SKIP_CHID)); + break; + + case IS_FIRST_RECENT: +first_recent: + /* + * We could really use recent for news but this is the way + * it has always worked, so we'll leave it. That is, if + * the FAKE_NEW feature is on, recent and unseen are + * equivalent, so it doesn't matter. If the feature isn't + * on, all the undeleted messages are unseen and we start + * at the first one. User controls with the FAKE_NEW feature. + */ + if(IS_NEWS(ps_global->mail_stream)){ + mn_set_cur(ps_global->msgmap, + first_sorted_flagged(F_UNSEEN|F_UNDEL, m, pc, + THREADING() ? 0 : FSF_SKIP_CHID)); + } + else{ + mn_set_cur(ps_global->msgmap, + first_sorted_flagged(F_RECENT | F_UNSEEN + | F_UNDEL, + m, pc, + THREADING() ? 0 : FSF_SKIP_CHID)); + } + break; + + case IS_FIRST_IMPORTANT: + mn_set_cur(ps_global->msgmap, + first_sorted_flagged(F_FLAG|F_UNDEL, m, pc, + THREADING() ? 0 : FSF_SKIP_CHID)); + break; + + case IS_FIRST_IMPORTANT_OR_UNSEEN: + + if(IS_NEWS(ps_global->mail_stream)) + goto first_unseen; + + { + MsgNo flagged, first_unseen; + + flagged = first_sorted_flagged(F_FLAG|F_UNDEL, m, pc, + THREADING() ? 0 : FSF_SKIP_CHID); + first_unseen = (sp_first_unseen(m) + && mn_get_sort(ps_global->msgmap) == SortArrival + && !mn_get_revsort(ps_global->msgmap) + && !get_lflag(ps_global->mail_stream, NULL, + sp_first_unseen(m), MN_EXLD) + && (n = mn_raw2m(ps_global->msgmap, + sp_first_unseen(m)))) + ? n + : first_sorted_flagged(F_UNSEEN|F_UNDEL, m, pc, + THREADING() ? 0 : FSF_SKIP_CHID); + mn_set_cur(ps_global->msgmap, + (MsgNo) MIN((int) flagged, (int) first_unseen)); + + } + + break; + + case IS_FIRST_IMPORTANT_OR_RECENT: + + if(IS_NEWS(ps_global->mail_stream)) + goto first_recent; + + { + MsgNo flagged, first_recent; + + flagged = first_sorted_flagged(F_FLAG|F_UNDEL, m, pc, + THREADING() ? 0 : FSF_SKIP_CHID); + first_recent = first_sorted_flagged(F_RECENT | F_UNSEEN + | F_UNDEL, + m, pc, + THREADING() ? 0 : FSF_SKIP_CHID); + mn_set_cur(ps_global->msgmap, + (MsgNo) MIN((int) flagged, (int) first_recent)); + } + + break; + + case IS_FIRST: + mn_set_cur(ps_global->msgmap, + first_sorted_flagged(F_UNDEL, m, pc, + THREADING() ? 0 : FSF_SKIP_CHID)); + break; + + case IS_LAST: + mn_set_cur(ps_global->msgmap, + first_sorted_flagged(F_UNDEL, m, pc, + FSF_LAST | (THREADING() ? 0 : FSF_SKIP_CHID))); + break; + + default: + alpine_panic("Unexpected incoming startup case"); + break; + + } +} diff --git a/pith/mailcmd.h b/pith/mailcmd.h index 0e00895..a7aa268 100644 --- a/pith/mailcmd.h +++ b/pith/mailcmd.h @@ -42,6 +42,8 @@ #define DB_FROMTAB 0x02 /* opening because of TAB command */ #define DB_INBOXWOCNTXT 0x04 /* interpret inbox as one true inbox */ +static MAILSTREAM *saved_stream; +static unsigned long rule_curpos = 0L; /* * generic "is aggregate message command?" test @@ -63,7 +65,13 @@ int do_broach_folder(char *, CONTEXT_S *, MAILSTREAM **, unsigned long); void expunge_and_close(MAILSTREAM *, char **, unsigned long); void agg_select_all(MAILSTREAM *, MSGNO_S *, long *, int); char *move_read_msgs(MAILSTREAM *, char *, char *, size_t, long); +char *move_read_msgs_using_rules (MAILSTREAM *, char *, char *); +unsigned get_perfolder_startup_rule (MAILSTREAM *, int, char *); +void setup_threading_index_style (void); +void find_startup_position (int, MAILSTREAM *, long); +char *get_folder_to_save (MAILSTREAM *, long, char *); char *move_read_incoming(MAILSTREAM *, CONTEXT_S *, char *, char **, char *, size_t); +unsigned long rules_cursor_pos (MAILSTREAM *); void cross_delete_crossposts(MAILSTREAM *); long zoom_index(struct pine *, MAILSTREAM *, MSGNO_S *, int); int unzoom_index(struct pine *, MAILSTREAM *, MSGNO_S *); diff --git a/pith/mailindx.c b/pith/mailindx.c index 4c64996..6f11327 100644 --- a/pith/mailindx.c +++ b/pith/mailindx.c @@ -41,6 +41,7 @@ static char rcsid[] = "$Id: mailindx.c 1266 2009-07-14 18:39:12Z hubert@u.washin #include "../pith/send.h" #include "../pith/options.h" #include "../pith/ablookup.h" +#include "../pith/rules.h" #ifdef _WINDOWS #include "../pico/osdep/mswin.h" #endif @@ -378,6 +379,13 @@ reset_index_format(void) PAT_STATE pstate; PAT_S *pat; int we_set_it = 0; + char *rule; + + if(rule = get_rule_result(FOR_INDEX, ps_global->cur_folder, V_INDEX_RULES)){ + init_index_format(rule, &ps_global->index_disp_format); + fs_give((void **)&rule); + return; + } if(ps_global->mail_stream && nonempty_patterns(rflags, &pstate)){ for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)){ @@ -451,14 +459,14 @@ free_hdrtok(HEADER_TOK_S **hdrtok) static INDEX_PARSE_T itokens[] = { {"STATUS", iStatus, FOR_INDEX}, {"MSGNO", iMessNo, FOR_INDEX}, - {"DATE", iDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, + {"DATE", iDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE}, {"FROMORTO", iFromTo, FOR_INDEX}, {"FROMORTONOTNEWS", iFromToNotNews, FOR_INDEX}, {"SIZE", iSize, FOR_INDEX}, {"SIZECOMMA", iSizeComma, FOR_INDEX}, {"SIZENARROW", iSizeNarrow, FOR_INDEX}, {"KSIZE", iKSize, FOR_INDEX}, - {"SUBJECT", iSubject, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, + {"SUBJECT", iSubject, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE|FOR_TRIM}, {"SHORTSUBJECT", iShortSubject, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, {"FULLSTATUS", iFStatus, FOR_INDEX}, {"IMAPSTATUS", iIStatus, FOR_INDEX}, @@ -470,56 +478,60 @@ static INDEX_PARSE_T itokens[] = { {"SUBJECTTEXT", iSubjectText, FOR_INDEX}, {"SUBJKEYTEXT", iSubjKeyText, FOR_INDEX}, {"SUBJKEYINITTEXT", iSubjKeyInitText, FOR_INDEX}, - {"OPENINGTEXT", iOpeningText, FOR_INDEX}, - {"OPENINGTEXTNQ", iOpeningTextNQ, FOR_INDEX}, - {"KEY", iKey, FOR_INDEX}, - {"KEYINIT", iKeyInit, FOR_INDEX}, + {"OPENINGTEXT", iOpeningText, FOR_INDEX|FOR_RULE|FOR_SAVE|FOR_TRIM}, + {"OPENINGTEXTNQ", iOpeningTextNQ, FOR_INDEX|FOR_RULE|FOR_SAVE|FOR_TRIM}, + {"KEY", iKey, FOR_INDEX|FOR_RULE|FOR_SAVE|FOR_COMPOSE}, + {"KEYINIT", iKeyInit, FOR_INDEX|FOR_RULE|FOR_SAVE|FOR_COMPOSE}, {"DESCRIPSIZE", iDescripSize, FOR_INDEX}, {"ATT", iAtt, FOR_INDEX}, {"SCORE", iScore, FOR_INDEX}, {"PRIORITY", iPrio, FOR_INDEX}, {"PRIORITYALPHA", iPrioAlpha, FOR_INDEX}, - {"PRIORITY!", iPrioBang, FOR_INDEX}, - {"LONGDATE", iLDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"SHORTDATE1", iS1Date, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"SHORTDATE2", iS2Date, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"SHORTDATE3", iS3Date, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"SHORTDATE4", iS4Date, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"DATEISO", iDateIso, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"SHORTDATEISO", iDateIsoS, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"SMARTDATE", iSDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"SMARTTIME", iSTime, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, + {"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}, {"SMARTTIME24", iSTime24, 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}, + {"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}, + {"ADDRESSSENDER", iAddressSender, 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}, @@ -528,56 +540,71 @@ static INDEX_PARSE_T itokens[] = { {"NEWSANDRECIPS", iNewsAndRecips, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, {"MSGID", iMsgID, FOR_REPLY_INTRO|FOR_TEMPLATE}, {"CURNEWS", iCurNews, FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"DAYDATE", iRDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"PREFDATE", iPrefDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"PREFTIME", iPrefTime, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"PREFDATETIME", iPrefDateTime, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"DAY", iDay, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"DAYORDINAL", iDayOrdinal, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"DAY2DIGIT", iDay2Digit, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"MONTHLONG", iMonLong, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"MONTH", iMon, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"MONTH2DIGIT", iMon2Digit, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"YEAR", iYear, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"YEAR2DIGIT", iYear2Digit, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"ADDRESS", iAddress, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, + {"DAYDATE", iRDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE}, + {"PREFDATE", iPrefDate, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE}, + {"PREFTIME", iPrefTime, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE}, + {"PREFDATETIME", iPrefDateTime, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE}, + {"DAY", iDay, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE}, + {"DAYORDINAL", iDayOrdinal, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE}, + {"DAY2DIGIT", iDay2Digit, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE}, + {"MONTHLONG", iMonLong, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE}, + {"MONTH", iMon, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE}, + {"MONTH2DIGIT", iMon2Digit, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE}, + {"YEAR", iYear, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE}, + {"YEAR2DIGIT", iYear2Digit, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE|FOR_SAVE}, + {"ADDRESS", iAddress, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_RULE}, {"MAILBOX", iMailbox, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, {"ROLENICK", iRoleNick, FOR_REPLY_INTRO|FOR_TEMPLATE}, {"INIT", iInit, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, - {"CURDATE", iCurDate, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"CURDATEISO", iCurDateIso, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"CURDATEISOS", iCurDateIsoS, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"CURTIME24", iCurTime24, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"CURTIME12", iCurTime12, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"CURDAY", iCurDay, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"CURDAY2DIGIT", iCurDay2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"CURDAYOFWEEK", iCurDayOfWeek, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, + {"CURDATE", iCurDate, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"CURDATEISO", iCurDateIso, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"CURDATEISOS", iCurDateIsoS, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"CURTIME24", iCurTime24, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"CURTIME12", iCurTime12, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"CURDAY", iCurDay, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"CURDAY2DIGIT", iCurDay2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"CURDAYOFWEEK", iCurDayOfWeek, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, {"CURDAYOFWEEKABBREV", iCurDayOfWeekAbb, - FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"CURMONTH", iCurMon, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"CURMONTH2DIGIT", iCurMon2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"CURMONTHLONG", iCurMonLong, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"CURMONTHABBREV", iCurMonAbb, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"CURYEAR", iCurYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"CURYEAR2DIGIT", iCurYear2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"CURPREFDATE", iCurPrefDate, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"CURPREFTIME", iCurPrefTime, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, + FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"CURMONTH", iCurMon, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"CURMONTH2DIGIT", iCurMon2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"CURMONTHLONG", iCurMonLong, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"CURMONTHABBREV", iCurMonAbb, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"CURYEAR", iCurYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"CURYEAR2DIGIT", iCurYear2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"CURPREFDATE", iCurPrefDate, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"CURPREFTIME", iCurPrefTime, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, {"CURPREFDATETIME", iCurPrefDateTime, - FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"LASTMONTH", iLstMon, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"LASTMONTH2DIGIT", iLstMon2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"LASTMONTHLONG", iLstMonLong, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"LASTMONTHABBREV", iLstMonAbb, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"LASTMONTHYEAR", iLstMonYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, + FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"LASTMONTH", iLstMon, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"LASTMONTH2DIGIT", iLstMon2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"LASTMONTHLONG", iLstMonLong, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"LASTMONTHABBREV", iLstMonAbb, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"LASTMONTHYEAR", iLstMonYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, {"LASTMONTHYEAR2DIGIT", iLstMonYear2Digit, - FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"LASTYEAR", iLstYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, - {"LASTYEAR2DIGIT", iLstYear2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT}, + FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"LASTYEAR", iLstYear, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, + {"LASTYEAR2DIGIT", iLstYear2Digit, FOR_REPLY_INTRO|FOR_TEMPLATE|FOR_FILT|FOR_RULE|FOR_SAVE}, {"HEADER", iHeader, FOR_INDEX}, {"TEXT", iText, FOR_INDEX}, {"ARROW", iArrow, FOR_INDEX}, {"NEWLINE", iNewLine, FOR_REPLY_INTRO}, {"CURSORPOS", iCursorPos, FOR_TEMPLATE}, + {"NICK", iNick, FOR_RULE|FOR_SAVE}, + {"FCCFROM", iFccFrom, FOR_RULE|FOR_SAVE}, + {"FCCSENDER", iFccSender, FOR_RULE|FOR_SAVE}, + {"ALTADDRESS", iAltAddress, 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} }; @@ -2484,6 +2511,24 @@ format_index_index_line(INDEXDATA_S *idata) from_str(cdesc->ctype, idata, str, sizeof(str), ice); break; + case iAddressTo: + case iAddressCc: + case iAddressRecip: + {ENVELOPE *env; + int we_clear; + env = rules_fetchenvelope(idata, &we_clear); + sprintf(str, "%-*.*s", ifield->width, ifield->width, + detoken_src((cdesc->ctype == iAddressTo + ? "_ADDRESSTO_" + : (cdesc->ctype == iAddressCc + ? "_ADRESSCC_" + : "_ADRESSRECIPS_")), FOR_INDEX, + env, NULL, NULL, NULL)); + if(we_clear) + mail_free_envelope(&env); + } + break; + case iTo: if(((field = ((addr = fetch_to(idata)) ? "To" @@ -3855,7 +3900,17 @@ try_again: if(p > buf){ size_t l; - + ENVELOPE *env; + char *rule_result; + + if(rule_result = find_value((delete_quotes + ? "_OPENINGTEXTNQ_" : "_OPENINGTEXT_"), + buf, PROCESS_SP, idata, 4)){ + collspaces(rule_result); + strncpy(buf, rule_result, sizeof(buf)); + buf[sizeof(buf) - 1] = '\0'; + fs_give((void **) &rule_result); + } l = strlen(buf); l += 100; firsttext = fs_get((l+1) * sizeof(char)); @@ -5434,10 +5489,10 @@ subj_str(INDEXDATA_S *idata, char *str, size_t strsize, SubjKW kwtype, int openi { char *subject, *origsubj, *origstr, *rawsubj, *sptr = NULL; char *p, *border, *q = NULL, *free_subj = NULL; - char *sp; + char *sp, *rule_result; size_t len; int width = -1; - int depth = 0, mult = 2; + int depth = 0, mult = 2, collapsed, i, we_clear = 0; int save; int do_subj = 0, truncated_tree = 0; PINETHRD_S *thd, *thdorig; @@ -5493,6 +5548,14 @@ subj_str(INDEXDATA_S *idata, char *str, size_t strsize, SubjKW kwtype, int openi * 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); + } + if(shorten) shorten_subject(origsubj); @@ -5935,6 +5998,9 @@ subj_str(INDEXDATA_S *idata, char *str, size_t strsize, SubjKW kwtype, int openi if(free_subj) fs_give((void **) &free_subj); + + if (we_clear && origsubj) + fs_give((void **)&origsubj); } @@ -6303,16 +6369,33 @@ from_str(IndexColType ctype, INDEXDATA_S *idata, char *str, size_t strsize, ICE_ ? "To" : (addr = fetch_cc(idata)) ? "Cc" - : NULL)) - && set_index_addr(idata, field, addr, "To: ", - strsize-1, fptr)) - break; + : NULL))){ + char *rule_result; + rule_result = find_value("_FROM_", NULL, 0, idata, 1); + if (!rule_result) + set_index_addr(idata, field, addr, "To: ", + strsize-1, fptr); + else{ + sprintf(str, "%-*.*s", strsize-1, strsize-1, + rule_result); + fs_give((void **)&rule_result); + } + break; + } if(ctype == iFromTo && (newsgroups = fetch_newsgroups(idata)) && *newsgroups){ - snprintf(fptr, strsize, "To: %-*.*s", (int)(strsize-1-4), (int)(strsize-1-4), - newsgroups); + char *rule_result; + rule_result = find_value("_FROM_", NULL, 0, idata, 1); + if (!rule_result) + sprintf(str, "To: %-*.*s", strsize-1-4, + strsize-1-4, newsgroups); + else{ + sprintf(str, "%-*.*s", strsize-1, strsize-1, + rule_result); + fs_give((void **)&rule_result); + } break; } @@ -6325,7 +6408,15 @@ from_str(IndexColType ctype, INDEXDATA_S *idata, char *str, size_t strsize, ICE_ break; case iFrom: - set_index_addr(idata, "From", fetch_from(idata), NULL, strsize-1, fptr); + { char *rule_result; + rule_result = find_value("_FROM_", NULL, 0, idata, 4); + if (!rule_result) + set_index_addr(idata, "From", fetch_from(idata), NULL, strsize-1, fptr); + else{ + sprintf(str, "%-*.*s", strsize-1, strsize-1, rule_result); + fs_give((void **)&rule_result); + } + } break; case iAddress: @@ -6623,3 +6714,64 @@ set_print_format(IELEM_S *ielem, int width, int leftadj) } } } + +void +setup_threading_display_style(void) +{ + RULE_RESULT *rule; + NAMEVAL_S *v; + int i; + + rule = get_result_rule(V_THREAD_DISP_STYLE_RULES, FOR_THREAD, NULL); + if (rule || ps_global->VAR_THREAD_DISP_STYLE){ + for(i = 0; v = thread_disp_styles(i); i++) + if(!strucmp(rule ? rule->result : ps_global->VAR_THREAD_DISP_STYLE, + rule ? (v ? v->name : "" ) : S_OR_L(v))){ + ps_global->thread_disp_style = v->value; + break; + } + if (rule){ + if (rule->result) + fs_give((void **)&rule->result); + fs_give((void **)&rule); + } + } +} + +char * +find_value(char *token, char *use_this, int flag, INDEXDATA_S *idata, int nfcn) +{ + int n = 0, i, rule_context, we_clear; + char *rule_result = NULL, **list; + ENVELOPE *env; + RULELIST *rule; + RULE_S *prule; + + env = rules_fetchenvelope(idata, &we_clear); + if(env && env->sparep) + fs_give((void **)&env->sparep); + if(we_clear) + mail_free_envelope(&env); + if(rule = get_rulelist_from_code(V_REPLACE_RULES, ps_global->rule_list)){ + list = functions_for_token(token); + while(rule_result == NULL && (prule = get_rule(rule,n++))){ + rule_context = 0; + if (prule->action->token && !strcmp(prule->action->token, token)){ + for (i = 0; i < nfcn; i++) + if(list[i+1] && !strcmp(prule->action->function, list[i+1])) + rule_context |= context_for_function(list[i+1]); + if (rule_context){ + env = rules_fetchenvelope(idata, &we_clear); + if(use_this) + env->sparep = get_sparep_for_rule(use_this, flag); + rule_result = process_rule(prule, rule_context, env); + if(env->sparep) + free_sparep_for_rule(&env->sparep); + if(we_clear) + mail_free_envelope(&env); + } + } + } + } + return rule_result; +} diff --git a/pith/mailindx.h b/pith/mailindx.h index 355faec..248ef94 100644 --- a/pith/mailindx.h +++ b/pith/mailindx.h @@ -30,6 +30,9 @@ extern void (*setup_header_widths)(MAILSTREAM *); /* exported prototypes */ +SortOrder translate (char *, int); +char *find_value (char *, char *, int, INDEXDATA_S *, int); +void setup_threading_display_style (void); int msgline_hidden(MAILSTREAM *, MSGNO_S *, long, int); void adjust_cur_to_visible(MAILSTREAM *, MSGNO_S *); unsigned long line_hash(char *); diff --git a/pith/makefile.wnt b/pith/makefile.wnt index 267ab76..0d1d2d2 100644 --- a/pith/makefile.wnt +++ b/pith/makefile.wnt @@ -46,7 +46,7 @@ HFILES= ../include/system.h ../include/general.h \ init.h keyword.h ldap.h list.h mailcap.h mailcmd.h mailindx.h maillist.h \ mailpart.h mailview.h margin.h mimedesc.h mimetype.h msgno.h newmail.h news.h \ options.h pattern.h pineelt.h pipe.h readfile.h remote.h remtype.h repltype.h reply.h \ - rfc2231.h save.h savetype.h search.h send.h sequence.h signal.h smime.h smkeys.h sort.h sorttype.h \ + rfc2231.h rules.h save.h savetype.h search.h send.h sequence.h signal.h smime.h smkeys.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 @@ -56,9 +56,9 @@ OFILES= ablookup.obj abdlc.obj addrbook.obj addrstring.obj adrbklib.obj bldaddr. ical.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 \ - smime.obj smkeys.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 + readfile.obj remote.obj reply.obj rfc2231.obj rules.obj save.obj search.obj sequence.obj \ + send.obj smime.obj smkeys.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 all: libpith.lib diff --git a/pith/pine.hlp b/pith/pine.hlp index 41d7521..874b5bf 100644 --- a/pith/pine.hlp +++ b/pith/pine.hlp @@ -4214,6 +4214,7 @@ There are also additional details on
-
+