diff options
author | Eduardo Chappa <echappa@gmx.com> | 2013-02-03 00:59:38 -0700 |
---|---|---|
committer | Eduardo Chappa <echappa@gmx.com> | 2013-02-03 00:59:38 -0700 |
commit | 094ca96844842928810f14844413109fc6cdd890 (patch) | |
tree | e60efbb980f38ba9308ccb4fb2b77b87bbc115f3 /alpine/roleconf.c | |
download | alpine-094ca96844842928810f14844413109fc6cdd890.tar.xz |
Initial Alpine Version
Diffstat (limited to 'alpine/roleconf.c')
-rw-r--r-- | alpine/roleconf.c | 8187 |
1 files changed, 8187 insertions, 0 deletions
diff --git a/alpine/roleconf.c b/alpine/roleconf.c new file mode 100644 index 00000000..fad1e661 --- /dev/null +++ b/alpine/roleconf.c @@ -0,0 +1,8187 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: roleconf.c 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $"; +#endif + +/* + * ======================================================================== + * Copyright 2006-2008 University of Washington + * Copyright 2013 Eduardo Chappa + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include "headers.h" +#include "roleconf.h" +#include "colorconf.h" +#include "conftype.h" +#include "confscroll.h" +#include "keymenu.h" +#include "status.h" +#include "radio.h" +#include "reply.h" +#include "folder.h" +#include "addrbook.h" +#include "mailcmd.h" +#include "setup.h" +#include "../pith/state.h" +#include "../pith/conf.h" +#include "../pith/msgno.h" +#include "../pith/bitmap.h" +#include "../pith/sort.h" +#include "../pith/addrstring.h" +#include "../pith/list.h" +#include "../pith/flag.h" +#include "../pith/bldaddr.h" +#include "../pith/news.h" +#include "../pith/util.h" +#include "../pith/detoken.h" +#include "../pith/icache.h" +#include "../pith/ablookup.h" +#include "../pith/pattern.h" +#include "../pith/tempfile.h" + + +#define NOT "! " +#define NOTLEN 2 + + +#define ARB_HELP _("HELP FOR ARBITRARY HEADER PATTERNS") +#define ADDXHDRS _("Add Extra Headers") + + +/* + * Internal prototypes + */ +int role_select_tool(struct pine *, int, CONF_S **, unsigned); +PATTERN_S *addrlst_to_pattern(ADDRESS *); +void role_config_init_disp(struct pine *, CONF_S **, long, PAT_STATE *); +void add_patline_to_display(struct pine *, CONF_S **, int, CONF_S **, CONF_S **, PAT_LINE_S *, long); +void add_role_to_display(CONF_S **, PAT_LINE_S *, PAT_S *, int, CONF_S **, int, long); +void add_fake_first_role(CONF_S **, int, long); +int role_config_tool(struct pine *, int, CONF_S **, unsigned); +int role_config_add(struct pine *, CONF_S **, long); +int role_config_replicate(struct pine *, CONF_S **, long); +int role_config_edit(struct pine *, CONF_S **, long); +int role_config_del(struct pine *, CONF_S **, long); +void delete_a_role(CONF_S **, long); +int role_config_shuffle(struct pine *, CONF_S **); +int role_config_addfile(struct pine *, CONF_S **, long); +int role_config_delfile(struct pine *, CONF_S **, long); +void swap_literal_roles(CONF_S *, CONF_S *); +void swap_file_roles(CONF_S *, CONF_S *); +void move_role_into_file(CONF_S **, int); +void move_role_outof_file(CONF_S **, int); +void move_role_around_file(CONF_S **, int); +int role_config_edit_screen(struct pine *, PAT_S *, char *, long, PAT_S **); +void setup_dummy_pattern_var(struct variable *, char *, PATTERN_S *); +void setup_role_pat(struct pine *, CONF_S **, struct variable *, HelpType, char *, + struct key_menu *, + int (*tool)(struct pine *, int, CONF_S **, unsigned), + EARB_S **, int); +void setup_role_pat_alt(struct pine *, CONF_S **, struct variable *, HelpType, char *, + struct key_menu *, + int (*tool)(struct pine *, int, CONF_S **, unsigned), + int, int); +void free_earb(EARB_S **); +void calculate_inick_stuff(struct pine *); +int check_role_folders(char **, unsigned); +void maybe_add_to_incoming(CONTEXT_S *, char *); +int role_filt_exitcheck(CONF_S **, unsigned); +int role_filt_text_tool(struct pine *, int, CONF_S **, unsigned); +int role_filt_addhdr_tool(struct pine *, int, CONF_S **, unsigned); +int role_addhdr_tool(struct pine *, int, CONF_S **, unsigned); +int role_filt_radiobutton_tool(struct pine *, int, CONF_S **, unsigned); +int role_sort_tool(struct pine *, int, CONF_S **, unsigned); +char **get_role_specific_folder(CONF_S **); +int role_litsig_text_tool(struct pine *, int, CONF_S **, unsigned); +int role_cstm_text_tool(struct pine *, int, CONF_S **, unsigned); +int role_text_tool(struct pine *, int, CONF_S **, unsigned); +int role_text_tool_inick(struct pine *, int, CONF_S **, unsigned); +int role_text_tool_kword(struct pine *, int, CONF_S **, unsigned); +int role_text_tool_charset(struct pine *, int, CONF_S **, unsigned); +int role_text_tool_afrom(struct pine *, int, CONF_S **, unsigned); +char *role_type_print(char *, size_t, char *, long); +int feat_checkbox_tool(struct pine *, int, CONF_S **, unsigned); +void toggle_feat_option_bit(struct pine *, int, struct variable *, char *); +NAMEVAL_S *feat_feature_list(int); +int inabook_checkbox_tool(struct pine *, int, CONF_S **, unsigned); +void toggle_inabook_type_bit(struct pine *, int, struct variable *, char *); +NAMEVAL_S *inabook_feature_list(int); + + +static char *set_choose = "--- --------------------"; +static long role_global_flags; +static PAT_STATE *role_global_pstate; + + +int +role_select_screen(struct pine *ps, ACTION_S **role, int alt_compose) +{ + CONF_S *ctmp = NULL, *first_line = NULL; + OPT_SCREEN_S screen; + PAT_S *pat, *sel_pat = NULL; + int ret = -1; + int change_default = 0; + long rflags = ROLE_DO_ROLES; + char *helptitle; + HelpType help; + PAT_STATE pstate; + + if(!role) + return(ret); + + *role = NULL; + + if(!(nonempty_patterns(rflags, &pstate) && + first_pattern(&pstate))){ + q_status_message(SM_ORDER, 3, 3, + _("No roles available. Use Setup/Rules to add roles.")); + return(ret); + } + + + if(alt_compose){ + menu_init_binding(&role_select_km, + alt_compose == MC_FORWARD ? 'F' : + alt_compose == MC_REPLY ? 'R' : + alt_compose == MC_COMPOSE ? 'C' : 'B', + MC_CHOICE, + alt_compose == MC_FORWARD ? "F" : + alt_compose == MC_REPLY ? "R" : + alt_compose == MC_COMPOSE ? "C" : "B", + alt_compose == MC_FORWARD ? "[" N_("ForwardAs") "]" : + alt_compose == MC_REPLY ? "[" N_("ReplyAs") "]" : + alt_compose == MC_COMPOSE ? "[" N_("ComposeAs") "]" : "[" N_("BounceAs") "]", + DEFAULT_KEY); + menu_add_binding(&role_select_km, ctrl('J'), MC_CHOICE); + menu_add_binding(&role_select_km, ctrl('M'), MC_CHOICE); + } + else{ + menu_init_binding(&role_select_km, 'S', MC_CHOICE, "S", "[" N_("Select") "]", + DEFAULT_KEY); + menu_add_binding(&role_select_km, ctrl('J'), MC_CHOICE); + menu_add_binding(&role_select_km, ctrl('M'), MC_CHOICE); + } + + help = h_role_select; + if(alt_compose == MC_BOUNCE) + helptitle = _("HELP FOR SELECTING A ROLE TO BOUNCE AS"); + else if(alt_compose) + helptitle = _("HELP FOR SELECTING A ROLE TO COMPOSE AS"); + else + helptitle = _("HELP FOR SELECTING A ROLE"); + + menu_init_binding(&role_select_km, 'D', MC_TOGGLE, "D", "changeDef", CHANGEDEF_KEY); + + for(pat = first_pattern(&pstate); + pat; + pat = next_pattern(&pstate)){ + new_confline(&ctmp); + if(!first_line) + first_line = ctmp; + + ctmp->value = cpystr((pat->patgrp && pat->patgrp->nick) + ? pat->patgrp->nick : "?"); + ctmp->d.r.selected = &sel_pat; + ctmp->d.r.pat = pat; + ctmp->d.r.change_def = &change_default; + ctmp->keymenu = &role_select_km; + ctmp->help = help; + ctmp->help_title = helptitle; + ctmp->tool = role_select_tool; + ctmp->flags = CF_STARTITEM; + ctmp->valoffset = 4; + } + + memset(&screen, 0, sizeof(screen)); + /* TRANSLATORS: Print something1 using something2. + "roles" is something1 */ + (void)conf_scroll_screen(ps, &screen, first_line, _("SELECT ROLE"), + _("roles"), 0); + + if(sel_pat){ + *role = sel_pat->action; + if(change_default == 1) + ps_global->default_role = *role; + else if(change_default == 2) + ps_global->default_role = NULL; + + ret = 0; + } + + ps->mangled_screen = 1; + return(ret); +} + + +int +role_select_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) +{ + int retval = 0, newval; + + switch(cmd){ + case MC_CHOICE : + *((*cl)->d.r.selected) = (*cl)->d.r.pat; + retval = simple_exit_cmd(flags); + break; + + case MC_TOGGLE : + newval = (*((*cl)->d.r.change_def) + 1) % 3; + *((*cl)->d.r.change_def) = newval; + menu_init_binding((*cl)->keymenu, 'D', MC_TOGGLE, "D", + (newval == 0) ? "changeDef" : (newval == 1) ? "removeDef" : "leaveDef", + CHANGEDEF_KEY); + if(newval == 1){ + if(ps_global->default_role) + q_status_message(SM_ORDER, 0, 3, + _("Default role will be changed to the role you Select")); + else + q_status_message(SM_ORDER, 0, 3, + _("Default role will be set to the role you Select")); + } + else if(newval == 2){ + q_status_message(SM_ORDER, 0, 3, _("Default role will be unset")); + } + else{ /* newval == 0 */ + if(ps_global->default_role) + q_status_message(SM_ORDER, 0, 3, _("Default role will remain unchanged")); + else + q_status_message(SM_ORDER, 0, 3, _("Default role will remain unset")); + } + + ps->mangled_footer = 1; + retval = 0; + break; + + case MC_EXIT : + retval = simple_exit_cmd(flags); + break; + + default: + retval = -1; + break; + } + + if(retval > 0) + ps->mangled_body = 1; + + return(retval); +} + + +void +role_config_screen(struct pine *ps, long int rflags, int edit_exceptions) +{ + CONF_S *first_line; + OPT_SCREEN_S screen; + char title[100]; + int readonly_warning = 0; + PAT_STATE pstate; + struct variable *v = NULL; + + dprint((4, "role_config_screen()\n")); + + if(ps->fix_fixed_warning) + offer_to_fix_pinerc(ps); + + ew = edit_exceptions ? ps_global->ew_for_except_vars : Main; + + if(ps->restricted) + readonly_warning = 1; + else{ + PINERC_S *prc = NULL; + + switch(ew){ + case Main: + prc = ps->prc; + rflags |= PAT_USE_MAIN; + break; + case Post: + prc = ps->post_prc; + rflags |= PAT_USE_POST; + break; + default: + break; + } + + readonly_warning = prc ? prc->readonly : 1; + if(prc && prc->quit_to_edit){ + quit_to_edit_msg(prc); + return; + } + } + + if(!any_patterns(rflags, &pstate)) + return; + + if(rflags & ROLE_DO_ROLES) + v = &ps_global->vars[V_PAT_ROLES]; + else if(rflags & ROLE_DO_INCOLS) + v = &ps_global->vars[V_PAT_INCOLS]; + else if(rflags & ROLE_DO_OTHER) + v = &ps_global->vars[V_PAT_OTHER]; + else if(rflags & ROLE_DO_SCORES) + v = &ps_global->vars[V_PAT_SCORES]; + else if(rflags & ROLE_DO_FILTER) + v = &ps_global->vars[V_PAT_FILTS]; + else if(rflags & ROLE_DO_SRCH) + v = &ps_global->vars[V_PAT_SRCH]; + + if((ps_global->ew_for_except_vars != Main) && (ew == Main)){ + char **lval; + + if((lval=LVAL(v, ps_global->ew_for_except_vars)) && + lval[0] && strcmp(INHERIT, lval[0]) != 0){ + role_type_print(title, sizeof(title), _("Warning: \"%sRules\" are overridden in your exceptions configuration"), rflags); + q_status_message(SM_ORDER, 7, 7, title); + } + } + + role_type_print(title, sizeof(title), "%sRules", rflags); + if(fixed_var(v, "change", title)) + return; + +uh_oh: + first_line = NULL; + + snprintf(title, sizeof(title), "SETUP%s ", edit_exceptions ? " EXCEPTIONAL" : ""); + title[sizeof(title)-1] = '\0'; + role_type_print(title+strlen(title), sizeof(title)-strlen(title), "%sRULES", rflags); + role_global_flags = rflags; + role_global_pstate = &pstate; + role_config_init_disp(ps, &first_line, rflags, &pstate); + + if(!first_line){ + role_global_flags = 0; + ps->mangled_screen = 1; + q_status_message(SM_ORDER,5,5, + _("Unexpected problem: config file modified externally?")); + q_status_message1(SM_ORDER,5,5, + _("Perhaps a newer version of pine was used to set variable \"%s\"?"), + v ? v->name : "?"); + dprint((1, "Unexpected problem: config file modified externally?\nPerhaps by a newer pine? Variable \"%s\" has unexpected contents.\n", + (v && v->name) ? v->name : "?")); + return; + } + + memset(&screen, 0, sizeof(screen)); + screen.deferred_ro_warning = readonly_warning; + /* TRANSLATORS: Print something1 using something2. + "rules" is something1 */ + switch(conf_scroll_screen(ps, &screen, first_line, title, _("rules"), 0)){ + case 0: + break; + + case 10: + /* flush changes and re-read orig */ + close_patterns(rflags); + break; + + case 1: + if(write_patterns(rflags)) + goto uh_oh; + + /* + * Flush out current_vals of anything we've possibly changed. + */ + + if(ps_global->default_role){ + q_status_message(SM_ORDER,0,3, "Default role is unset"); + ps_global->default_role = NULL; + } + + close_patterns((rflags & ROLE_MASK) | PAT_USE_CURRENT); + + /* scores may have changed */ + if(rflags & ROLE_DO_SCORES){ + int i; + MAILSTREAM *m; + + for(i = 0; i < ps_global->s_pool.nstream; i++){ + m = ps_global->s_pool.streams[i]; + if(m){ + clear_folder_scores(m); + clear_index_cache(m, 0); + } + } + + if(mn_get_sort(sp_msgmap(ps_global->mail_stream)) == SortScore) + refresh_sort(ps_global->mail_stream, + sp_msgmap(ps_global->mail_stream), SRT_VRB); + } + + /* recalculate need for scores */ + scores_are_used(SCOREUSE_INVALID); + + /* we may want to fetch more or fewer headers each fetch */ + calc_extra_hdrs(); + if(get_extra_hdrs()) + (void) mail_parameters(NULL, SET_IMAPEXTRAHEADERS, + (void *) get_extra_hdrs()); + + if(rflags & ROLE_DO_INCOLS && pico_usingcolor()) + clear_index_cache(ps_global->mail_stream, 0); + + if(rflags & ROLE_DO_FILTER) + role_process_filters(); + + /* + * ROLE_DO_OTHER is made up of a bunch of different variables + * that may have changed. Assume they all changed and fix them. + */ + if(rflags & ROLE_DO_OTHER){ + reset_index_format(); + clear_index_cache(ps_global->mail_stream, 0); + if(!mn_get_mansort(ps_global->msgmap)) + reset_sort_order(SRT_VRB); + } + + break; + + default: + q_status_message(SM_ORDER,7,10, "conf_scroll_screen unexpected ret"); + break; + } + + role_global_flags = 0; + ps->mangled_screen = 1; +} + + +/* + * This is called from process_cmd to add a new pattern to the end of the + * list of patterns. The pattern is seeded with values from the current + * message. + */ +void +role_take(struct pine *ps, MSGNO_S *msgmap, int rtype) +{ + PAT_S *defpat, *newpat = NULL; + PAT_LINE_S *new_patline, *patline; + ENVELOPE *env = NULL; + long rflags; + char *s, title[100], specific_fldr[MAXPATH+1]; + PAT_STATE pstate; + EditWhich ew; + + dprint((4, "role_take()\n")); + + if(mn_get_cur(msgmap) > 0){ + env = pine_mail_fetchstructure(ps->mail_stream, + mn_m2raw(msgmap, mn_get_cur(msgmap)), + NULL); + + if(!env){ + q_status_message(SM_ORDER, 3, 7, + _("problem getting addresses from message")); + return; + } + } + + switch(rtype){ + case 'r': + rflags = ROLE_DO_ROLES; + ew = ps_global->ew_for_role_take; + break; + case 's': + rflags = ROLE_DO_SCORES; + ew = ps_global->ew_for_score_take; + break; + case 'i': + rflags = ROLE_DO_INCOLS; + ew = ps_global->ew_for_incol_take; + break; + case 'f': + rflags = ROLE_DO_FILTER; + ew = ps_global->ew_for_filter_take; + break; + case 'o': + rflags = ROLE_DO_OTHER; + ew = ps_global->ew_for_other_take; + break; + case 'c': + rflags = ROLE_DO_SRCH; + ew = ps_global->ew_for_srch_take; + break; + + default: + cmd_cancelled(NULL); + return; + } + + switch(ew){ + case Main: + rflags |= PAT_USE_MAIN; + break; + case Post: + rflags |= PAT_USE_POST; + break; + default: + break; + } + + if(!any_patterns(rflags, &pstate)){ + q_status_message(SM_ORDER, 3, 7, _("problem accessing rules")); + return; + } + + /* set this so that even if we don't edit at all, we'll be asked */ + rflags |= ROLE_CHANGES; + + /* + * Make a pattern out of the information in the envelope and + * use that as the default pattern we give to the role editor. + * It will have a pattern but no actions set. + */ + defpat = (PAT_S *)fs_get(sizeof(*defpat)); + memset((void *)defpat, 0, sizeof(*defpat)); + + defpat->patgrp = (PATGRP_S *)fs_get(sizeof(*defpat->patgrp)); + memset((void *)defpat->patgrp, 0, sizeof(*defpat->patgrp)); + + if(env){ + if(env->to) + defpat->patgrp->to = addrlst_to_pattern(env->to); + + if(env->from) + defpat->patgrp->from = addrlst_to_pattern(env->from); + + if(env->cc) + defpat->patgrp->cc = addrlst_to_pattern(env->cc); + + if(env->sender && + (!env->from || !address_is_same(env->sender, env->from))) + defpat->patgrp->sender = addrlst_to_pattern(env->sender); + + /* + * Env->newsgroups is already comma-separated and there shouldn't be + * any commas or backslashes in newsgroup names, so we don't add the + * roletake escapes. + */ + if(env->newsgroups) + defpat->patgrp->news = string_to_pattern(env->newsgroups); + + /* + * Subject may have commas or backslashes, so we add escapes. + */ + if(env->subject){ + char *q, *t = NULL; + + /* + * Mail_strip_subject not only strips the Re's and Fwd's but + * it also canonicalizes to UTF-8. + */ + mail_strip_subject(env->subject, &q); + if(q != NULL){ + t = add_roletake_escapes(q); + fs_give((void **)&q); + } + + if(t){ + defpat->patgrp->subj = string_to_pattern(t); + fs_give((void **)&t); + } + } + } + + if(IS_NEWS(ps->mail_stream)) + defpat->patgrp->fldr_type = FLDR_NEWS; + else + defpat->patgrp->fldr_type = FLDR_EMAIL; + + specific_fldr[0] = specific_fldr[sizeof(specific_fldr)-1] = '\0'; + if(sp_flagged(ps->mail_stream, SP_INBOX)) + strncpy(specific_fldr, ps_global->inbox_name, sizeof(specific_fldr)-1); + else if(ps->context_current + && ps->context_current->use & CNTXT_INCMNG && + folder_is_nick(ps->cur_folder, FOLDERS(ps->context_current), 0)) + strncpy(specific_fldr, ps->cur_folder, sizeof(specific_fldr)-1); + else + context_apply(specific_fldr, ps->context_current, ps->cur_folder, + sizeof(specific_fldr)); + + if(specific_fldr[0]){ + s = add_comma_escapes(specific_fldr); + if(s){ + if(rtype == 'f') + defpat->patgrp->fldr_type = FLDR_SPECIFIC; + + defpat->patgrp->folder = string_to_pattern(s); + fs_give((void **)&s); + } + } + + role_type_print(title, sizeof(title), "ADD NEW %sRULE", rflags); + + /* + * Role_config_edit_screen is sometimes called as a tool or a sub + * routine called from a tool within conf_scroll_screen, but here it + * is going to be at the top-level (we're not inside conf_scroll_screen + * right now). It uses opt_screen to set the ro_warning bit. We need + * to let it know that we're at the top, which we do by setting + * opt_screen to NULL. Otherwise, the thing that opt_screen is pointing + * to is just random stack stuff from some previous conf_scroll_screen + * call which has already exited. + */ + opt_screen = NULL; + + if(role_config_edit_screen(ps, defpat, title, rflags, + &newpat) == 1 && newpat){ + + if(ps->never_allow_changing_from && newpat->action && + newpat->action->from) + q_status_message(SM_ORDER|SM_DING, 3, 7, + _("Site policy doesn't allow changing From address so From is ignored")); + + if(rflags & ROLE_DO_ROLES && newpat->patgrp && newpat->patgrp->nick){ + PAT_S *pat; + + for(pat = first_pattern(&pstate); + pat; + pat = next_pattern(&pstate)){ + if(pat->patgrp && pat->patgrp->nick && + !strucmp(pat->patgrp->nick, newpat->patgrp->nick)){ + q_status_message(SM_ORDER|SM_DING, 3, 7, _("Warning: The nickname of the new role is already in use.")); + break; + } + } + } + + + set_pathandle(rflags); + + /* need a new patline */ + new_patline = (PAT_LINE_S *)fs_get(sizeof(*new_patline)); + memset((void *)new_patline, 0, sizeof(*new_patline)); + new_patline->type = Literal; + (*cur_pat_h)->dirtypinerc = 1; + + /* tie together with new pattern */ + new_patline->first = new_patline->last = newpat; + newpat->patline = new_patline; + + /* find last current patline */ + for(patline = (*cur_pat_h)->patlinehead; + patline && patline->next; + patline = patline->next) + ; + + /* add new patline to end of list */ + if(patline){ + patline->next = new_patline; + new_patline->prev = patline; + } + else + (*cur_pat_h)->patlinehead = new_patline; + + if(write_patterns(rflags) == 0){ + char msg[60]; + + /* + * Flush out current_vals of anything we've possibly changed. + */ + + if(rflags & ROLE_DO_ROLES && ps_global->default_role){ + q_status_message(SM_ORDER,0,3, "Default role is unset"); + ps_global->default_role = NULL; + } + + close_patterns(rflags | PAT_USE_CURRENT); + + role_type_print(msg, sizeof(msg), "New %srule saved", rflags); + q_status_message(SM_ORDER, 0, 3, msg); + + /* scores may have changed */ + if(rflags & ROLE_DO_SCORES){ + int i; + MAILSTREAM *m; + + for(i = 0; i < ps_global->s_pool.nstream; i++){ + m = ps_global->s_pool.streams[i]; + if(m){ + clear_folder_scores(m); + clear_index_cache(m, 0); + } + } + + /* We've already bound msgmap to global mail_stream + * at the start of this function, but if we wanted to + * we could clean this up. + */ + if(mn_get_sort(msgmap) == SortScore) + refresh_sort(ps_global->mail_stream, msgmap, SRT_VRB); + } + + if(rflags & ROLE_DO_FILTER) + role_process_filters(); + + /* recalculate need for scores */ + scores_are_used(SCOREUSE_INVALID); + + /* we may want to fetch more or fewer headers each fetch */ + calc_extra_hdrs(); + if(get_extra_hdrs()) + (void) mail_parameters(NULL, SET_IMAPEXTRAHEADERS, + (void *) get_extra_hdrs()); + + if(rflags & ROLE_DO_INCOLS && pico_usingcolor()) + clear_index_cache(ps_global->mail_stream, 0); + + /* + * ROLE_DO_OTHER is made up of a bunch of different variables + * that may have changed. Assume they all changed and fix them. + */ + if(rflags & ROLE_DO_OTHER){ + reset_index_format(); + clear_index_cache(ps_global->mail_stream, 0); + if(!mn_get_mansort(msgmap)) + reset_sort_order(SRT_VRB); + } + } + } + else + cmd_cancelled(NULL); + + free_pat(&defpat); + ps->mangled_screen = 1; +} + + +PATTERN_S * +addrlst_to_pattern(struct mail_address *addr) +{ + char *s, *t, *u, *v; + PATTERN_S *p = NULL; + size_t l; + + if(addr){ + l = est_size(addr); + t = s = (char *) fs_get((l+1) * sizeof(char)); + s[0] = '\0'; + while(addr){ + u = simple_addr_string(addr, tmp_20k_buf, SIZEOF_20KBUF); + v = add_roletake_escapes(u); + if(v){ + if(*v && t != s) + sstrncpy(&t, ",", l-(t-s)); + + sstrncpy(&t, v, l-(t-s)); + fs_give((void **)&v); + } + + addr = addr->next; + } + + s[l] = '\0'; + + if(*s) + p = string_to_pattern(s); + + fs_give((void **) &s); + } + + return(p); +} + + +void +role_config_init_disp(struct pine *ps, CONF_S **first_line, long int rflags, PAT_STATE *pstate) +{ + PAT_LINE_S *patline; + CONF_S *ctmp = NULL; + int inherit = 0, added_fake = 0; + + if(first_line) + *first_line = NULL; + + /* + * Set cur_pat_h and manipulate directly. + */ + set_pathandle(rflags); + patline = *cur_pat_h ? (*cur_pat_h)->patlinehead : NULL; + if(patline && patline->type == Inherit){ + add_patline_to_display(ps, &ctmp, 0, first_line, NULL, patline, rflags); + patline = patline->next; + } + + if(!patline){ + add_fake_first_role(&ctmp, 0, rflags); + added_fake++; + if(first_line && !*first_line) + (*first_line) = ctmp; + } + + for(; patline; patline = patline->next) + add_patline_to_display(ps, &ctmp, 0, first_line, NULL, patline, rflags); + + /* + * If there are no actual patterns so far, we need to have an Add line + * for the cursor to be on. This would happen if all of the patlines + * were File includes and none of the files contained patterns. + */ + if(!first_pattern(role_global_pstate) || + ((inherit=first_pattern(role_global_pstate)->inherit) && + !next_pattern(role_global_pstate))){ + + /* + * Find the start and prepend the fake first role. + */ + while(ctmp && ctmp->prev) + ctmp = ctmp->prev; + + if(!added_fake){ + add_fake_first_role(&ctmp, inherit ? 0 : 1, rflags); + if(first_line && !*first_line) + (*first_line) = ctmp; + } + } +} + + +void +add_patline_to_display(struct pine *ps, CONF_S **ctmp, int before, CONF_S **first_line, CONF_S **top_line, PAT_LINE_S *patline, long int rflags) +{ + PAT_S *pat; + int len, firstitem, wid; + char *q; + char buf[6*MAX_SCREEN_COLS+1]; + + /* put dashed line around file contents */ + if(patline->type == File){ + + new_confline(ctmp); + if(before){ + /* + * New_confline appends ctmp after old current instead of inserting + * it, so we have to adjust. We have + * <- a <-> b <-> p <-> c -> and want <- a <-> p <-> b <-> c -> + */ + + CONF_S *a, *b, *c, *p; + + p = *ctmp; + b = (*ctmp)->prev; + c = (*ctmp)->next; + a = b ? b->prev : NULL; + if(a) + a->next = p; + + if(b){ + b->prev = p; + b->next = c; + } + + if(c) + c->prev = b; + + p->prev = a; + p->next = b; + } + + if(top_line && *top_line == NULL) + *top_line = (*ctmp); + + len = strlen(patline->filename) + 100; + + q = (char *) fs_get((len + 1) * sizeof(char)); + snprintf(q, len+1, "From file %s%s", patline->filename, + patline->readonly ? " (ReadOnly)" : ""); + q[len-1] = '\0'; + + if((wid=utf8_width(q)) > ps->ttyo->screen_cols -2) + utf8_snprintf(buf, sizeof(buf), "--%.*w", ps->ttyo->screen_cols -2, q); + else + snprintf(buf, sizeof(buf), "--%s%s", q, repeat_char(ps->ttyo->screen_cols -2-wid, '-')); + + (*ctmp)->value = cpystr(buf); + + fs_give((void **)&q); + (*ctmp)->flags |= (CF_NOSELECT | CF_STARTITEM); + (*ctmp)->d.r.patline = patline; + firstitem = 0; + } + else + firstitem = 1; + + for(pat = patline->first; pat; pat = pat->next){ + + /* Check that pattern has a role and is of right type */ + if(pat->inherit || + (pat->action && + (((rflags & ROLE_DO_ROLES) && pat->action->is_a_role) || + ((rflags & ROLE_DO_INCOLS) && pat->action->is_a_incol) || + ((rflags & ROLE_DO_SRCH) && pat->action->is_a_srch) || + ((rflags & ROLE_DO_OTHER) && pat->action->is_a_other) || + ((rflags & ROLE_DO_SCORES) && pat->action->is_a_score) || + ((rflags & ROLE_DO_FILTER) && pat->action->is_a_filter)))){ + add_role_to_display(ctmp, patline, pat, 0, + (first_line && *first_line == NULL) + ? first_line : + (top_line && *top_line == NULL) + ? top_line : NULL, + firstitem, rflags); + firstitem = 1; + if(top_line && *top_line == NULL && first_line) + *top_line = *first_line; + } + + } + + if(patline->type == File){ + new_confline(ctmp); + len = strlen(patline->filename) + 100; + + q = (char *) fs_get((len + 1) * sizeof(char)); + snprintf(q, len+1, "End of Rules from %s", patline->filename); + q[len-1] = '\0'; + + if((wid=utf8_width(q)) > ps->ttyo->screen_cols -2) + utf8_snprintf(buf, sizeof(buf), "--%.*w", ps->ttyo->screen_cols -2, q); + else + snprintf(buf, sizeof(buf), "--%s%s", q, repeat_char(ps->ttyo->screen_cols -2-wid, '-')); + + (*ctmp)->value = cpystr(buf); + + fs_give((void **)&q); + (*ctmp)->flags |= CF_NOSELECT; + (*ctmp)->d.r.patline = patline; + } +} + + +void +add_role_to_display(CONF_S **ctmp, PAT_LINE_S *patline, PAT_S *pat, int before, CONF_S **first_line, int firstitem, long int rflags) +{ + char title[80]; + + if(!(pat && (pat->action || pat->inherit))) + return; + + new_confline(ctmp); + if(first_line && !pat->inherit) + *first_line = *ctmp; + + if(before){ + /* + * New_confline appends ctmp after old current instead of inserting + * it, so we have to adjust. We have + * <- a <-> b <-> p <-> c -> and want <- a <-> p <-> b <-> c -> + */ + + CONF_S *a, *b, *c, *p; + + p = *ctmp; + b = (*ctmp)->prev; + c = (*ctmp)->next; + a = b ? b->prev : NULL; + if(a) + a->next = p; + + if(b){ + b->prev = p; + b->next = c; + } + + if(c) + c->prev = b; + + p->prev = a; + p->next = b; + } + + role_type_print(title, sizeof(title), _("HELP FOR %sRULE CONFIGURATION"), rflags); + + if(pat->inherit){ + (*ctmp)->flags |= ((firstitem ? CF_STARTITEM : 0) | + CF_NOSELECT | CF_INHERIT); + } + else{ + (*ctmp)->flags |= (firstitem ? CF_STARTITEM : 0); + (*ctmp)->value = cpystr((pat && pat->patgrp && pat->patgrp->nick) + ? pat->patgrp->nick : "?"); + } + + (*ctmp)->d.r.patline = patline; + (*ctmp)->d.r.pat = pat; + (*ctmp)->keymenu = &role_conf_km; + (*ctmp)->help = (rflags & ROLE_DO_INCOLS) ? h_rules_incols : + (rflags & ROLE_DO_OTHER) ? h_rules_other : + (rflags & ROLE_DO_FILTER) ? h_rules_filter : + (rflags & ROLE_DO_SCORES) ? h_rules_score : + (rflags & ROLE_DO_ROLES) ? h_rules_roles : + (rflags & ROLE_DO_SRCH) ? h_rules_srch : + NO_HELP; + (*ctmp)->help_title = title; + (*ctmp)->tool = role_config_tool; + (*ctmp)->valoffset = 4; +} + + +void +add_fake_first_role(CONF_S **ctmp, int before, long int rflags) +{ + char title[80]; + char add[80]; + + new_confline(ctmp); + + if(before){ + /* + * New_confline appends ctmp after old current instead of inserting + * it, so we have to adjust. We have + * <- a <-> b <-> p <-> c -> and want <- a <-> p <-> b <-> c -> + */ + + CONF_S *a, *b, *c, *p; + + p = *ctmp; + b = (*ctmp)->prev; + c = (*ctmp)->next; + a = b ? b->prev : NULL; + if(a) + a->next = p; + + if(b){ + b->prev = p; + b->next = c; + } + + if(c) + c->prev = b; + + p->prev = a; + p->next = b; + } + + role_type_print(title, sizeof(title), _("HELP FOR %sRULE CONFIGURATION"), rflags); + role_type_print(add, sizeof(add), _("Use Add to add a %sRule"), rflags); + + (*ctmp)->value = cpystr(add); + (*ctmp)->keymenu = &role_conf_km; + (*ctmp)->help = (rflags & ROLE_DO_INCOLS) ? h_rules_incols : + (rflags & ROLE_DO_OTHER) ? h_rules_other : + (rflags & ROLE_DO_FILTER) ? h_rules_filter : + (rflags & ROLE_DO_SCORES) ? h_rules_score : + (rflags & ROLE_DO_ROLES) ? h_rules_roles : + (rflags & ROLE_DO_SRCH) ? h_rules_srch : + NO_HELP; + (*ctmp)->help_title = title; + (*ctmp)->tool = role_config_tool; + (*ctmp)->flags |= CF_STARTITEM; + (*ctmp)->valoffset = 4; +} + + +int +role_config_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) +{ + int first_one = 0, rv = 0; + char exitpmt[80]; + PAT_S *pat; + + if(!(pat = first_pattern(role_global_pstate)) || + (pat->inherit && !next_pattern(role_global_pstate))) + first_one++; + + switch(cmd){ + case MC_DELETE : + if(first_one) + q_status_message(SM_ORDER|SM_DING, 0, 3, + _("Nothing to Delete, use Add")); + else + rv = role_config_del(ps, cl, role_global_flags); + + break; + + case MC_ADD : + rv = role_config_add(ps, cl, role_global_flags); + break; + + case MC_EDIT : + if(first_one) + rv = role_config_add(ps, cl, role_global_flags); + else + rv = role_config_edit(ps, cl, role_global_flags); + + break; + + case MC_SHUFFLE : + if(first_one) + q_status_message(SM_ORDER|SM_DING, 0, 3, + _("Nothing to Shuffle, use Add")); + else + rv = role_config_shuffle(ps, cl); + + break; + + case MC_EXIT : + role_type_print(exitpmt, sizeof(exitpmt), "%sRule Setup", role_global_flags); + rv = screen_exit_cmd(flags, exitpmt); + break; + + case MC_ADDFILE : + rv = role_config_addfile(ps, cl, role_global_flags); + break; + + case MC_DELFILE : + rv = role_config_delfile(ps, cl, role_global_flags); + break; + + case MC_COPY : + if(first_one) + q_status_message(SM_ORDER|SM_DING, 0, 3, + _("Nothing to Replicate, use Add")); + else + rv = role_config_replicate(ps, cl, role_global_flags); + + break; + + default: + rv = -1; + break; + } + + return(rv); +} + + +/* + * Add a new role. + * + * Returns 1 -- There were changes + * 0 -- No changes + */ +int +role_config_add(struct pine *ps, CONF_S **cl, long int rflags) +{ + int rv = 0, first_pat = 0; + PAT_S *new_pat = NULL, *cur_pat; + PAT_LINE_S *new_patline, *cur_patline; + PAT_STATE pstate; + char title[80]; + + if((*cl)->d.r.patline && + (*cl)->d.r.patline->readonly + && (*cl)->d.r.patline->type == File){ + q_status_message(SM_ORDER, 0, 3, _("Can't add rule to ReadOnly file")); + return(rv); + } + + role_type_print(title, sizeof(title), "ADD A %sRULE", rflags); + + if(role_config_edit_screen(ps, NULL, title, rflags, + &new_pat) == 1 && new_pat){ + if(ps->never_allow_changing_from && + new_pat->action && + new_pat->action->from) + q_status_message(SM_ORDER|SM_DING, 0, 3, + _("Site policy doesn't allow changing From address so From is ignored")); + + if(rflags & ROLE_DO_ROLES && + new_pat->patgrp && + new_pat->patgrp->nick && + nonempty_patterns(ROLE_DO_ROLES, &pstate)){ + PAT_S *pat; + + for(pat = first_pattern(&pstate); + pat; + pat = next_pattern(&pstate)){ + if(pat->patgrp && pat->patgrp->nick && + !strucmp(pat->patgrp->nick, new_pat->patgrp->nick)){ + q_status_message(SM_ORDER|SM_DING, 3, 7, _("Warning: The nickname of the new role is already in use.")); + break; + } + } + } + + rv = 1; + cur_pat = (*cl)->d.r.pat; + if(!cur_pat) + first_pat++; + + set_pathandle(rflags); + cur_patline = first_pat ? (*cur_pat_h)->patlinehead : cur_pat->patline; + + /* need a new pat_line */ + if(first_pat || (cur_patline && cur_patline->type == Literal)){ + new_patline = (PAT_LINE_S *)fs_get(sizeof(*new_patline)); + memset((void *)new_patline, 0, sizeof(*new_patline)); + new_patline->type = Literal; + (*cur_pat_h)->dirtypinerc = 1; + } + + if(cur_patline){ + if(first_pat || cur_patline->type == Literal){ + new_patline->prev = cur_patline; + new_patline->next = cur_patline->next; + if(cur_patline->next) + cur_patline->next->prev = new_patline; + + cur_patline->next = new_patline; + + /* tie new patline and new pat together */ + new_pat->patline = new_patline; + new_patline->first = new_patline->last = new_pat; + } + else if(cur_patline->type == File){ /* don't need a new pat_line */ + /* tie together */ + new_pat->patline = cur_patline; + cur_patline->dirty = 1; + + /* Splice new_pat after cur_pat */ + new_pat->prev = cur_pat; + new_pat->next = cur_pat->next; + if(cur_pat->next) + cur_pat->next->prev = new_pat; + else + cur_patline->last = new_pat; + + cur_pat->next = new_pat; + } + } + else{ + /* tie new first patline and pat together */ + new_pat->patline = new_patline; + new_patline->first = new_patline->last = new_pat; + + /* set head of list */ + (*cur_pat_h)->patlinehead = new_patline; + } + + /* + * If this is the first role, we replace the "Use Add" fake role + * with this real one. + */ + if(first_pat){ + /* Adjust conf_scroll_screen variables */ + (*cl)->d.r.pat = new_pat; + (*cl)->d.r.patline = new_pat->patline; + if((*cl)->value) + fs_give((void **)&(*cl)->value); + + (*cl)->value = cpystr((new_pat && new_pat->patgrp && + new_pat->patgrp->nick) + ? new_pat->patgrp->nick : "?"); + } + /* Else we are inserting a new role after the cur role */ + else + add_role_to_display(cl, new_pat->patline, new_pat, 0, NULL, + 1, rflags); + } + + return(rv); +} + + +/* + * Replicate a role. + * + * Returns 1 -- There were changes + * 0 -- No changes + */ +int +role_config_replicate(struct pine *ps, CONF_S **cl, long int rflags) +{ + int rv = 0, first_pat = 0; + PAT_S *new_pat = NULL, *cur_pat, *defpat = NULL; + PAT_LINE_S *new_patline, *cur_patline; + PAT_STATE pstate; + char title[80]; + + if((*cl)->d.r.patline && + (*cl)->d.r.patline->readonly + && (*cl)->d.r.patline->type == File){ + q_status_message(SM_ORDER, 0, 3, _("Can't add rule to ReadOnly file")); + return(rv); + } + + if((*cl)->d.r.pat && (defpat = copy_pat((*cl)->d.r.pat))){ + /* change nickname */ + if(defpat->patgrp && defpat->patgrp->nick){ +#define CLONEWORD " Copy" + char *oldnick = defpat->patgrp->nick; + size_t len; + + len = strlen(oldnick)+strlen(CLONEWORD); + defpat->patgrp->nick = (char *)fs_get((len+1) * sizeof(char)); + strncpy(defpat->patgrp->nick, oldnick, len); + defpat->patgrp->nick[len] = '\0'; + strncat(defpat->patgrp->nick, CLONEWORD, + len+1-1-strlen(defpat->patgrp->nick)); + fs_give((void **)&oldnick); + if(defpat->action){ + if(defpat->action->nick) + fs_give((void **)&defpat->action->nick); + + defpat->action->nick = cpystr(defpat->patgrp->nick); + } + } + + /* set this so that even if we don't edit at all, we'll be asked */ + rflags |= ROLE_CHANGES; + + role_type_print(title, sizeof(title), "CHANGE THIS %sRULE", rflags); + + if(role_config_edit_screen(ps, defpat, title, rflags, + &new_pat) == 1 && new_pat){ + + if(ps->never_allow_changing_from && + new_pat->action && + new_pat->action->from) + q_status_message(SM_ORDER|SM_DING, 0, 3, + _("Site policy doesn't allow changing From address so From is ignored")); + + if(rflags & ROLE_DO_ROLES && + new_pat->patgrp && + new_pat->patgrp->nick && + nonempty_patterns(ROLE_DO_ROLES, &pstate)){ + PAT_S *pat; + + for(pat = first_pattern(&pstate); + pat; + pat = next_pattern(&pstate)){ + if(pat->patgrp && pat->patgrp->nick && + !strucmp(pat->patgrp->nick, new_pat->patgrp->nick)){ + q_status_message(SM_ORDER|SM_DING, 3, 7, _("Warning: The nickname of the new role is already in use.")); + break; + } + } + } + + rv = 1; + cur_pat = (*cl)->d.r.pat; + if(!cur_pat) + first_pat++; + + set_pathandle(rflags); + cur_patline = first_pat ? (*cur_pat_h)->patlinehead : cur_pat->patline; + + /* need a new pat_line */ + if(first_pat || (cur_patline && cur_patline->type == Literal)){ + new_patline = (PAT_LINE_S *)fs_get(sizeof(*new_patline)); + memset((void *)new_patline, 0, sizeof(*new_patline)); + new_patline->type = Literal; + (*cur_pat_h)->dirtypinerc = 1; + } + + if(cur_patline){ + if(first_pat || cur_patline->type == Literal){ + new_patline->prev = cur_patline; + new_patline->next = cur_patline->next; + if(cur_patline->next) + cur_patline->next->prev = new_patline; + + cur_patline->next = new_patline; + + /* tie new patline and new pat together */ + new_pat->patline = new_patline; + new_patline->first = new_patline->last = new_pat; + } + else if(cur_patline->type == File){ /* don't need a new pat_line */ + /* tie together */ + new_pat->patline = cur_patline; + cur_patline->dirty = 1; + + /* Splice new_pat after cur_pat */ + new_pat->prev = cur_pat; + new_pat->next = cur_pat->next; + if(cur_pat->next) + cur_pat->next->prev = new_pat; + else + cur_patline->last = new_pat; + + cur_pat->next = new_pat; + } + } + else{ + /* tie new first patline and pat together */ + new_pat->patline = new_patline; + new_patline->first = new_patline->last = new_pat; + + /* set head of list */ + (*cur_pat_h)->patlinehead = new_patline; + } + + /* + * If this is the first role, we replace the "Use Add" fake role + * with this real one. + */ + if(first_pat){ + /* Adjust conf_scroll_screen variables */ + (*cl)->d.r.pat = new_pat; + (*cl)->d.r.patline = new_pat->patline; + if((*cl)->value) + fs_give((void **)&(*cl)->value); + + (*cl)->value = cpystr((new_pat && new_pat->patgrp && + new_pat->patgrp->nick) + ? new_pat->patgrp->nick : "?"); + } + /* Else we are inserting a new role after the cur role */ + else + add_role_to_display(cl, new_pat->patline, new_pat, 0, NULL, + 1, rflags); + } + } + + if(defpat) + free_pat(&defpat); + + return(rv); +} + + +/* + * Change the current role. + * + * Returns 1 -- There were changes + * 0 -- No changes + */ +int +role_config_edit(struct pine *ps, CONF_S **cl, long int rflags) +{ + int rv = 0; + PAT_S *new_pat = NULL, *cur_pat; + char title[80]; + + if((*cl)->d.r.patline->readonly){ + q_status_message(SM_ORDER, 0, 3, _("Can't change ReadOnly rule")); + return(rv); + } + + cur_pat = (*cl)->d.r.pat; + + role_type_print(title, sizeof(title), "CHANGE THIS %sRULE", rflags); + + if(role_config_edit_screen(ps, cur_pat, title, + rflags, &new_pat) == 1 && new_pat){ + + if(ps->never_allow_changing_from && + new_pat->action && + new_pat->action->from) + q_status_message(SM_ORDER|SM_DING, 0, 3, + _("Site policy doesn't allow changing From address so From is ignored")); + + if(rflags & ROLE_DO_ROLES && new_pat->patgrp && new_pat->patgrp->nick){ + PAT_S *pat; + + for(pat = first_pattern(role_global_pstate); + pat; + pat = next_pattern(role_global_pstate)){ + if(pat->patgrp && pat->patgrp->nick && pat != cur_pat && + !strucmp(pat->patgrp->nick, new_pat->patgrp->nick)){ + q_status_message(SM_ORDER|SM_DING, 3, 7, _("Warning: The nickname of this role is also used for another role.")); + break; + } + } + } + + rv = 1; + + /* + * Splice in new_pat in place of cur_pat + */ + + if(cur_pat->prev) + cur_pat->prev->next = new_pat; + + if(cur_pat->next) + cur_pat->next->prev = new_pat; + + new_pat->prev = cur_pat->prev; + new_pat->next = cur_pat->next; + + /* tie together patline and pat (new_pat gets patline in editor) */ + if(new_pat->patline->first == cur_pat) + new_pat->patline->first = new_pat; + + if(new_pat->patline->last == cur_pat) + new_pat->patline->last = new_pat; + + if(new_pat->patline->type == Literal){ + set_pathandle(rflags); + if(*cur_pat_h) + (*cur_pat_h)->dirtypinerc = 1; + } + else + new_pat->patline->dirty = 1; + + cur_pat->next = NULL; + free_pat(&cur_pat); + + /* Adjust conf_scroll_screen variables */ + (*cl)->d.r.pat = new_pat; + (*cl)->d.r.patline = new_pat->patline; + if((*cl)->value) + fs_give((void **)&(*cl)->value); + + (*cl)->value = cpystr((new_pat->patgrp && new_pat->patgrp->nick) + ? new_pat->patgrp->nick : "?"); + } + + return(rv); +} + + +/* + * Delete a role. + * + * Returns 1 -- There were changes + * 0 -- No changes + */ +int +role_config_del(struct pine *ps, CONF_S **cl, long int rflags) +{ + int rv = 0; + char msg[80]; + char prompt[100]; + + if((*cl)->d.r.patline->readonly){ + q_status_message(SM_ORDER, 0, 3, _("Can't delete ReadOnly rule")); + return(rv); + } + + role_type_print(msg, sizeof(msg), _("Really delete %srule"), rflags); + snprintf(prompt, sizeof(prompt), "%s \"%s\" ", msg, (*cl)->value); + prompt[sizeof(prompt)-1] = '\0'; + + ps->mangled_footer = 1; + if(want_to(prompt,'n','n',h_config_role_del, WT_FLUSH_IN) == 'y'){ + rv = ps->mangled_body = 1; + delete_a_role(cl, rflags); + } + else + q_status_message(SM_ORDER, 0, 3, _("Rule not deleted")); + + return(rv); +} + + +void +delete_a_role(CONF_S **cl, long int rflags) +{ + PAT_S *cur_pat; + CONF_S *cp, *cq; + PAT_LINE_S *cur_patline; + int inherit = 0; + + cur_pat = (*cl)->d.r.pat; + cur_patline = (*cl)->d.r.patline; + + if(cur_patline->type == Literal){ /* delete patline */ + set_pathandle(rflags); + if(cur_patline->prev) + cur_patline->prev->next = cur_patline->next; + else{ + if(*cur_pat_h) /* this has to be true */ + (*cur_pat_h)->patlinehead = cur_patline->next; + } + + if(cur_patline->next) + cur_patline->next->prev = cur_patline->prev; + + if(*cur_pat_h) /* this has to be true */ + (*cur_pat_h)->dirtypinerc = 1; + + cur_patline->next = NULL; + free_patline(&cur_patline); + } + else if(cur_patline->type == File){ /* or delete pat */ + if(cur_pat->prev) + cur_pat->prev->next = cur_pat->next; + else + cur_patline->first = cur_pat->next; + + if(cur_pat->next) + cur_pat->next->prev = cur_pat->prev; + else + cur_patline->last = cur_pat->prev; + + cur_patline->dirty = 1; + + cur_pat->next = NULL; + free_pat(&cur_pat); + } + + /* delete the conf line */ + + /* deleting last real rule */ + if(!first_pattern(role_global_pstate) || + ((inherit=first_pattern(role_global_pstate)->inherit) && + !next_pattern(role_global_pstate))){ + + cq = *cl; + + /* + * Find the start and prepend the fake first role. + */ + while(*cl && (*cl)->prev) + *cl = (*cl)->prev; + + add_fake_first_role(cl, inherit ? 0 : 1, rflags); + snip_confline(&cq); + opt_screen->top_line = (*cl); + opt_screen->current = (*cl); + } + else{ + /* find next selectable line */ + for(cp = (*cl)->next; + cp && (cp->flags & CF_NOSELECT); + cp = cp->next) + ; + + if(!cp){ /* no next selectable, find previous selectable */ + if(*cl == opt_screen->top_line) + opt_screen->top_line = (*cl)->prev; + + for(cp = (*cl)->prev; + cp && (cp->flags & CF_NOSELECT); + cp = cp->prev) + ; + } + else if(*cl == opt_screen->top_line) + opt_screen->top_line = (*cl)->next; + + cq = *cl; + *cl = cp; + snip_confline(&cq); + } +} + + +/* + * Shuffle the current role up or down. + * + * Returns 1 -- There were changes + * 0 -- No changes + */ +int +role_config_shuffle(struct pine *ps, CONF_S **cl) +{ + int rv = 0, deefault, i; + int readonlyabove = 0, readonlybelow = 0; + ESCKEY_S opts[5]; + HelpType help; + char tmp[200]; + CONF_S *a, *b; + PAT_TYPE curtype, prevtype, nexttype; + + if(!((*cl)->prev || (*cl)->next)){ + q_status_message(SM_ORDER, 0, 3, + _("Shuffle only makes sense when there is more than one rule defined")); + return(rv); + } + + /* Move it up or down? */ + i = 0; + opts[i].ch = 'u'; + opts[i].rval = 'u'; + opts[i].name = "U"; + opts[i++].label = N_("Up"); + + opts[i].ch = 'd'; + opts[i].rval = 'd'; + opts[i].name = "D"; + opts[i++].label = N_("Down"); + + opts[i].ch = 'b'; + opts[i].rval = 'b'; + opts[i].name = "B"; + opts[i++].label = N_("Before File"); + + opts[i].ch = 'a'; + opts[i].rval = 'a'; + opts[i].name = "A"; + opts[i++].label = N_("After File"); + + opts[i].ch = -1; + deefault = 'u'; + + curtype = ((*cl)->d.r.patline) ? (*cl)->d.r.patline->type : TypeNotSet; + + prevtype = ((*cl)->prev && (*cl)->prev->d.r.patline) + ? (*cl)->prev->d.r.patline->type : TypeNotSet; + if(curtype == File && prevtype == File && (*cl)->prev->d.r.pat == NULL) + prevtype = TypeNotSet; + + nexttype = ((*cl)->next && (*cl)->next->d.r.patline) + ? (*cl)->next->d.r.patline->type : TypeNotSet; + if(curtype == File && nexttype == File && (*cl)->next->d.r.pat == NULL) + nexttype = TypeNotSet; + + + if(curtype == Literal){ + if(prevtype == TypeNotSet || + prevtype == Inherit){ /* no up, at top */ + opts[0].ch = -2; + opts[2].ch = -2; + deefault = 'd'; + } + else if(prevtype == Literal){ /* regular up */ + opts[2].ch = -2; + } + else if(prevtype == File){ /* file above us */ + if((*cl)->prev->d.r.patline->readonly) + readonlyabove++; + } + + if(nexttype == TypeNotSet){ /* no down, at bottom */ + opts[1].ch = -2; + opts[3].ch = -2; + } + else if(nexttype == Literal){ /* regular down */ + opts[3].ch = -2; + } + else if(nexttype == File){ /* file below us */ + if((*cl)->next->d.r.patline->readonly) + readonlybelow++; + } + } + else if(curtype == File){ + if((*cl)->d.r.patline && (*cl)->d.r.patline->readonly){ + q_status_message(SM_ORDER, 0, 3, _("Can't change ReadOnly file")); + return(0); + } + + opts[2].ch = -2; + opts[3].ch = -2; + } + else{ + q_status_message(SM_ORDER, 0, 3, + "Programming Error: unknown line type in role_shuffle"); + return(rv); + } + + snprintf(tmp, sizeof(tmp), "Shuffle \"%s\" %s%s%s%s%s%s%s ? ", + (*cl)->value, + (opts[0].ch != -2) ? N_("UP") : "", + (opts[0].ch != -2 && opts[1].ch != -2) ? " or " : "", + (opts[1].ch != -2) ? N_("DOWN") : "", + ((opts[0].ch != -2 || + opts[1].ch != -2) && opts[2].ch != -2) ? " or " : "", + (opts[2].ch != -2) ? N_("BEFORE") : "", + ((opts[0].ch != -2 || + opts[1].ch != -2 || + opts[2].ch != -2) && opts[3].ch != -2) ? " or " : "", + (opts[3].ch != -2) ? N_("AFTER") : ""); + tmp[sizeof(tmp)-1] = '\0'; + + help = (opts[0].ch == -2) ? h_role_shuf_down + : (opts[1].ch == -2) ? h_role_shuf_up + : h_role_shuf; + + rv = radio_buttons(tmp, -FOOTER_ROWS(ps), opts, deefault, 'x', + help, RB_NORM); + + if(rv == 'x'){ + cmd_cancelled("Shuffle"); + return(0); + } + + if((readonlyabove && rv == 'u' && curtype != prevtype) || + (readonlybelow && rv == 'd' && curtype != nexttype)){ + q_status_message(SM_ORDER, 0, 3, _("Can't shuffle into ReadOnly file")); + return(0); + } + + if(rv == 'u' && curtype == Literal && prevtype == Literal){ + rv = 1; + a = (*cl)->prev; + b = (*cl); + if(a == opt_screen->top_line) + opt_screen->top_line = b; + + swap_literal_roles(a, b); + ps->mangled_body = 1; + } + else if(rv == 'd' && curtype == Literal && nexttype == Literal){ + rv = 1; + a = (*cl); + b = (*cl)->next; + if(a == opt_screen->top_line) + opt_screen->top_line = b; + + swap_literal_roles(a, b); + ps->mangled_body = 1; + } + else if(rv == 'u' && curtype == File && prevtype == File){ + rv = 1; + a = (*cl)->prev; + b = (*cl); + if(a == opt_screen->top_line) + opt_screen->top_line = b; + + swap_file_roles(a, b); + ps->mangled_body = 1; + } + else if(rv == 'u' && curtype == File){ + rv = 1; + move_role_outof_file(cl, 1); + ps->mangled_body = 1; + } + else if(rv == 'd' && curtype == File && nexttype == File){ + rv = 1; + a = (*cl); + b = (*cl)->next; + if(a == opt_screen->top_line) + opt_screen->top_line = b; + + swap_file_roles(a, b); + ps->mangled_body = 1; + } + else if(rv == 'd' && curtype == File){ + rv = 1; + if(*cl == opt_screen->top_line) + opt_screen->top_line = (*cl)->next; + + move_role_outof_file(cl, 0); + ps->mangled_body = 1; + } + else if(rv == 'u' && curtype == Literal && prevtype == File){ + rv = 1; + move_role_into_file(cl, 1); + ps->mangled_body = 1; + } + else if(rv == 'd' && curtype == Literal && nexttype == File){ + rv = 1; + if(*cl == opt_screen->top_line) + opt_screen->top_line = (*cl)->next; + + move_role_into_file(cl, 0); + ps->mangled_body = 1; + } + else if(rv == 'b'){ + rv = 1; + move_role_around_file(cl, 1); + ps->mangled_body = 1; + } + else if(rv == 'a'){ + rv = 1; + if(*cl == opt_screen->top_line) + opt_screen->top_line = (*cl)->next; + + move_role_around_file(cl, 0); + ps->mangled_body = 1; + } + + return(rv); +} + + +int +role_config_addfile(struct pine *ps, CONF_S **cl, long int rflags) +{ + char filename[MAXPATH+1], full_filename[MAXPATH+1]; + char dir2[MAXPATH+1], pdir[MAXPATH+1]; + char *lc, *newfile = NULL; + PAT_LINE_S *file_patline; + int rv = 0, len; + int r = 1, flags; + HelpType help = NO_HELP; + PAT_TYPE curtype; + CONF_S *first_line = NULL, *add_line, *save_current; + struct variable *vars = ps->vars; + + if(ps->restricted){ + q_status_message(SM_ORDER, 0, 3, "Alpine demo can't read files"); + return(rv); + } + + curtype = ((*cl)->d.r.patline && (*cl)->d.r.patline) + ? (*cl)->d.r.patline->type : TypeNotSet; + + if(curtype == File){ + q_status_message(SM_ORDER, 0, 3, _("Current rule is already part of a file. Move outside any files first.")); + return(rv); + } + + /* + * Parse_pattern_file uses signature_path to figure out where to look + * for the file. In signature_path we read signature files relative + * to the pinerc dir, so if user selects one that is in there we'll + * use relative instead of absolute, so it looks nicer. + */ + pdir[0] = '\0'; + if(VAR_OPER_DIR){ + strncpy(pdir, VAR_OPER_DIR, sizeof(pdir)-1); + pdir[sizeof(pdir)-1] = '\0'; + len = strlen(pdir) + 1; + } + else if((lc = last_cmpnt(ps->pinerc)) != NULL){ + strncpy(pdir, ps->pinerc, MIN(sizeof(pdir)-1,lc-ps->pinerc)); + pdir[MIN(sizeof(pdir)-1, lc-ps->pinerc)] = '\0'; + len = strlen(pdir); + } + + strncpy(dir2, pdir, sizeof(dir2)-1); + dir2[sizeof(dir2)-1] = '\0'; + filename[0] = '\0'; + full_filename[0] = '\0'; + ps->mangled_footer = 1; + + while(1){ + flags = OE_APPEND_CURRENT; + r = optionally_enter(filename, -FOOTER_ROWS(ps), 0, sizeof(filename), + "Name of file to be added to rules: ", + NULL, help, &flags); + + if(r == 3){ + help = (help == NO_HELP) ? h_config_role_addfile : NO_HELP; + continue; + } + else if(r == 10 || r == 11){ /* Browser or File Completion */ + continue; + } + else if(r == 1 || (r == 0 && filename[0] == '\0')){ + cmd_cancelled("IncludeFile"); + return(rv); + } + else if(r == 4){ + continue; + } + else if(r != 0){ + Writechar(BELL, 0); + continue; + } + + removing_leading_and_trailing_white_space(filename); + if(is_absolute_path(filename)) + newfile = cpystr(filename); + else{ + build_path(full_filename, dir2, filename, sizeof(full_filename)); + removing_leading_and_trailing_white_space(full_filename); + if(!strncmp(full_filename, pdir, strlen(pdir))) + newfile = cpystr(full_filename + len); + else + newfile = cpystr(full_filename); + } + + if(newfile && *newfile) + break; + } + + if(!newfile) + return(rv); + + set_pathandle(rflags); + + if((file_patline = parse_pat_file(newfile)) != NULL){ + /* + * Insert the file after the current line. + */ + PAT_LINE_S *cur_patline; + int first_pat; + + rv = ps->mangled_screen = 1; + first_pat = !(*cl)->d.r.pat; + cur_patline = (*cl)->d.r.patline ? (*cl)->d.r.patline : + (*cur_pat_h) ? (*cur_pat_h)->patlinehead : NULL; + + if(*cur_pat_h) + (*cur_pat_h)->dirtypinerc = 1; + + file_patline->dirty = 1; + + if(cur_patline){ + file_patline->prev = cur_patline; + file_patline->next = cur_patline->next; + if(cur_patline->next) + cur_patline->next->prev = file_patline; + + cur_patline->next = file_patline; + } + else{ + /* set head of list */ + if(*cur_pat_h) + (*cur_pat_h)->patlinehead = file_patline; + } + + if(first_pat){ + if(file_patline->first){ + /* get rid of Fake Add line */ + add_line = *cl; + opt_screen->top_line = NULL; + add_patline_to_display(ps, cl, 0, &first_line, + &opt_screen->top_line, file_patline, + rflags); + opt_screen->current = first_line; + snip_confline(&add_line); + } + else{ + /* we're _appending_ to the Fake Add line */ + save_current = opt_screen->current; + add_patline_to_display(ps, cl, 0, NULL, NULL, file_patline, + rflags); + opt_screen->current = save_current; + } + } + else{ + opt_screen->top_line = NULL; + save_current = opt_screen->current; + add_patline_to_display(ps, cl, 0, &first_line, + &opt_screen->top_line, file_patline, + rflags); + if(first_line) + opt_screen->current = first_line; + else + opt_screen->current = save_current; + } + } + + if(newfile) + fs_give((void **)&newfile); + + return(rv); +} + + +int +role_config_delfile(struct pine *ps, CONF_S **cl, long int rflags) +{ + int rv = 0; + PAT_LINE_S *cur_patline; + char prompt[100]; + + if(!(cur_patline = (*cl)->d.r.patline)){ + q_status_message(SM_ORDER, 0, 3, + "Unknown problem in role_config_delfile"); + return(rv); + } + + if(cur_patline->type != File){ + q_status_message(SM_ORDER, 0, 3, _("Current rule is not part of a file. Use Delete to remove current rule")); + return(rv); + } + + snprintf(prompt, sizeof(prompt), _("Really remove rule file \"%s\" from rules config "), + cur_patline->filename); + prompt[sizeof(prompt)-1] = '\0'; + + ps->mangled_footer = 1; + if(want_to(prompt,'n','n',h_config_role_delfile, WT_FLUSH_IN) == 'y'){ + CONF_S *ctmp, *cp; + + set_pathandle(rflags); + rv = ps->mangled_screen = 1; + if(*cur_pat_h) + (*cur_pat_h)->dirtypinerc = 1; + + if(cur_patline->prev) + cur_patline->prev->next = cur_patline->next; + else{ + if(*cur_pat_h) + (*cur_pat_h)->patlinehead = cur_patline->next; + } + + if(cur_patline->next) + cur_patline->next->prev = cur_patline->prev; + + /* delete the conf lines */ + + /* find the first one associated with this file */ + for(ctmp = *cl; + ctmp && ctmp->prev && ctmp->prev->d.r.patline == cur_patline; + ctmp = ctmp->prev) + ; + + if(ctmp->prev) /* this file wasn't the first thing in config */ + *cl = ctmp->prev; + else{ /* this file was first in config */ + for(cp = ctmp; cp && cp->next; cp = cp->next) + ; + + if(cp->d.r.patline == cur_patline) + *cl = NULL; + else + *cl = cp; + } + + /* delete lines from the file */ + while(ctmp && ctmp->d.r.patline == cur_patline){ + cp = ctmp; + ctmp = ctmp->next; + snip_confline(&cp); + } + + /* deleting last real rule */ + if(!first_pattern(role_global_pstate)){ + /* + * Find the start and prepend the fake first role + * in there. + */ + while(*cl && (*cl)->prev) + *cl = (*cl)->prev; + + add_fake_first_role(cl, 1, rflags); + } + else if(first_pattern(role_global_pstate)->inherit && + !next_pattern(role_global_pstate)){ + while(*cl && (*cl)->prev) + *cl = (*cl)->prev; + + /* append fake first after inherit */ + add_fake_first_role(cl, 0, rflags); + } + + opt_screen->top_line = first_confline(*cl); + opt_screen->current = first_sel_confline(opt_screen->top_line); + + cur_patline->next = NULL; + free_patline(&cur_patline); + } + else + q_status_message(SM_ORDER, 0, 3, _("Rule file not removed")); + + return(rv); +} + + +/* + * Swap from a, b to b, a. + */ +void +swap_literal_roles(CONF_S *a, CONF_S *b) +{ + PAT_LINE_S *patline_a, *patline_b; + + patline_a = a->d.r.patline; + patline_b = b->d.r.patline; + + set_pathandle(role_global_flags); + if(*cur_pat_h) + (*cur_pat_h)->dirtypinerc = 1; + + /* first swap the patlines */ + if(patline_a->next == patline_b){ + patline_b->prev = patline_a->prev; + if(patline_a->prev) + patline_a->prev->next = patline_b; + + patline_a->next = patline_b->next; + if(patline_b->next) + patline_b->next->prev = patline_a; + + patline_b->next = patline_a; + patline_a->prev = patline_b; + } + else{ + PAT_LINE_S *new_a_prev, *new_a_next; + + new_a_prev = patline_b->prev; + new_a_next = patline_b->next; + + patline_b->prev = patline_a->prev; + patline_b->next = patline_a->next; + if(patline_b->prev) + patline_b->prev->next = patline_b; + if(patline_b->next) + patline_b->next->prev = patline_b; + + patline_a->prev = new_a_prev; + patline_a->next = new_a_next; + if(patline_a->prev) + patline_a->prev->next = patline_a; + if(patline_a->next) + patline_a->next->prev = patline_a; + } + + /* + * If patline_b is now the first one in the list, we need to fix the + * head of the list to point to this new role. + */ + if(patline_b->prev == NULL && *cur_pat_h) + (*cur_pat_h)->patlinehead = patline_b; + + + /* and then swap the conf lines */ + + b->prev = a->prev; + if(a->prev) + a->prev->next = b; + + a->next = b->next; + if(b->next) + b->next->prev = a; + + b->next = a; + a->prev = b; +} + + +/* + * Swap from a, b to b, a. + */ +void +swap_file_roles(CONF_S *a, CONF_S *b) +{ + PAT_S *pat_a, *pat_b; + PAT_LINE_S *patline; + + pat_a = a->d.r.pat; + pat_b = b->d.r.pat; + patline = pat_a->patline; + + patline->dirty = 1; + + /* first swap the pats */ + if(pat_a->next == pat_b){ + pat_b->prev = pat_a->prev; + if(pat_a->prev) + pat_a->prev->next = pat_b; + + pat_a->next = pat_b->next; + if(pat_b->next) + pat_b->next->prev = pat_a; + + pat_b->next = pat_a; + pat_a->prev = pat_b; + } + else{ + PAT_S *new_a_prev, *new_a_next; + + new_a_prev = pat_b->prev; + new_a_next = pat_b->next; + + pat_b->prev = pat_a->prev; + pat_b->next = pat_a->next; + if(pat_b->prev) + pat_b->prev->next = pat_b; + if(pat_b->next) + pat_b->next->prev = pat_b; + + pat_a->prev = new_a_prev; + pat_a->next = new_a_next; + if(pat_a->prev) + pat_a->prev->next = pat_a; + if(pat_a->next) + pat_a->next->prev = pat_a; + } + + /* + * Fix the first and last pointers. + */ + if(patline->first == pat_a) + patline->first = pat_b; + if(patline->last == pat_b) + patline->last = pat_a; + + /* and then swap the conf lines */ + + b->prev = a->prev; + if(a->prev) + a->prev->next = b; + + a->next = b->next; + if(b->next) + b->next->prev = a; + + b->next = a; + a->prev = b; +} + + +/* + */ +void +move_role_into_file(CONF_S **cl, int up) +{ + PAT_LINE_S *cur_patline, *file_patline; + PAT_S *pat; + CONF_S *a, *b; + + cur_patline = (*cl)->d.r.patline; + + if(up){ + file_patline = (*cl)->prev->d.r.patline; + a = (*cl)->prev; + b = (*cl); + b->d.r.patline = file_patline; + } + else{ + file_patline = (*cl)->next->d.r.patline; + a = (*cl); + b = (*cl)->next; + a->d.r.patline = file_patline; + } + + set_pathandle(role_global_flags); + if(*cur_pat_h) + (*cur_pat_h)->dirtypinerc = 1; + + file_patline->dirty = 1; + + pat = cur_patline->first; + + if(!up && *cur_pat_h && cur_patline == (*cur_pat_h)->patlinehead) + (*cur_pat_h)->patlinehead = (*cur_pat_h)->patlinehead->next; + + if(file_patline->first){ + if(up){ + file_patline->last->next = pat; + pat->prev = file_patline->last; + file_patline->last = pat; + } + else{ + file_patline->first->prev = pat; + pat->next = file_patline->first; + file_patline->first = pat; + } + } + else /* will be only role in file */ + file_patline->first = file_patline->last = pat; + + pat->patline = file_patline; + + /* delete the now unused cur_patline */ + cur_patline->first = cur_patline->last = NULL; + if(cur_patline->prev) + cur_patline->prev->next = cur_patline->next; + if(cur_patline->next) + cur_patline->next->prev = cur_patline->prev; + + cur_patline->next = NULL; + free_patline(&cur_patline); + + /* and then swap the conf lines */ + + b->prev = a->prev; + if(a->prev) + a->prev->next = b; + + a->next = b->next; + if(b->next) + b->next->prev = a; + + b->next = a; + a->prev = b; +} + + +/* + */ +void +move_role_outof_file(CONF_S **cl, int up) +{ + PAT_LINE_S *file_patline, *new_patline; + PAT_S *pat; + CONF_S *a, *b; + + new_patline = (PAT_LINE_S *)fs_get(sizeof(*new_patline)); + memset((void *)new_patline, 0, sizeof(*new_patline)); + new_patline->type = Literal; + + file_patline = (*cl)->d.r.patline; + pat = (*cl)->d.r.pat; + + if(up){ + a = (*cl)->prev; + b = (*cl); + + if(pat->prev) + pat->prev->next = pat->next; + else + file_patline->first = pat->next; + + if(pat->next) + pat->next->prev = pat->prev; + else + file_patline->last = pat->prev; + + if(file_patline->first) + file_patline->first->prev = NULL; + + if(file_patline->last) + file_patline->last->next = NULL; + + if(file_patline->prev) + file_patline->prev->next = new_patline; + + new_patline->prev = file_patline->prev; + new_patline->next = file_patline; + file_patline->prev = new_patline; + b->d.r.patline = new_patline; + } + else{ + a = (*cl); + b = (*cl)->next; + + if(pat->prev) + pat->prev->next = pat->next; + else + file_patline->first = pat->next; + + if(pat->next) + pat->next->prev = pat->prev; + else + file_patline->last = pat->prev; + + if(file_patline->first) + file_patline->first->prev = NULL; + + if(file_patline->last) + file_patline->last->next = NULL; + + if(file_patline->next) + file_patline->next->prev = new_patline; + + new_patline->next = file_patline->next; + new_patline->prev = file_patline; + file_patline->next = new_patline; + a->d.r.patline = new_patline; + } + + set_pathandle(role_global_flags); + if(*cur_pat_h) + (*cur_pat_h)->dirtypinerc = 1; + + file_patline->dirty = 1; + + new_patline->first = new_patline->last = pat; + pat->patline = new_patline; + pat->prev = pat->next = NULL; + + if(up && *cur_pat_h && file_patline == (*cur_pat_h)->patlinehead) + (*cur_pat_h)->patlinehead = new_patline; + + /* and then swap the conf lines */ + + b->prev = a->prev; + if(a->prev) + a->prev->next = b; + + a->next = b->next; + if(b->next) + b->next->prev = a; + + b->next = a; + a->prev = b; +} + + +/* + * This is a move of a literal role from before a file to after a file, + * or vice versa. + */ +void +move_role_around_file(CONF_S **cl, int up) +{ + PAT_LINE_S *file_patline, *lit_patline; + CONF_S *cp; + + set_pathandle(role_global_flags); + lit_patline = (*cl)->d.r.patline; + if(up) + file_patline = (*cl)->prev->d.r.patline; + else{ + if(*cur_pat_h && lit_patline == (*cur_pat_h)->patlinehead) + (*cur_pat_h)->patlinehead = (*cur_pat_h)->patlinehead->next; + + file_patline = (*cl)->next->d.r.patline; + } + + if(*cur_pat_h) + (*cur_pat_h)->dirtypinerc = 1; + + /* remove the lit_patline from the list */ + if(lit_patline->prev) + lit_patline->prev->next = lit_patline->next; + if(lit_patline->next) + lit_patline->next->prev = lit_patline->prev; + + /* and reinsert it on the other side of the file */ + if(up){ + if(*cur_pat_h && file_patline == (*cur_pat_h)->patlinehead) + (*cur_pat_h)->patlinehead = lit_patline; + + lit_patline->prev = file_patline->prev; + lit_patline->next = file_patline; + + if(file_patline->prev) + file_patline->prev->next = lit_patline; + + file_patline->prev = lit_patline; + } + else{ + lit_patline->next = file_patline->next; + lit_patline->prev = file_patline; + + if(file_patline->next) + file_patline->next->prev = lit_patline; + + file_patline->next = lit_patline; + } + + /* + * And then move the conf line around the file conf lines. + */ + + /* find it's new home */ + if(up) + for(cp = (*cl); + cp && cp->prev && cp->prev->d.r.patline == file_patline; + cp = prev_confline(cp)) + ; + else + for(cp = (*cl); + cp && cp->next && cp->next->d.r.patline == file_patline; + cp = next_confline(cp)) + ; + + /* remove it from where it is */ + if((*cl)->prev) + (*cl)->prev->next = (*cl)->next; + if((*cl)->next) + (*cl)->next->prev = (*cl)->prev; + + /* cp points to top or bottom of the file lines */ + if(up){ + (*cl)->prev = cp->prev; + if(cp->prev) + cp->prev->next = (*cl); + + cp->prev = (*cl); + (*cl)->next = cp; + } + else{ + (*cl)->next = cp->next; + if(cp->next) + cp->next->prev = (*cl); + + cp->next = (*cl); + (*cl)->prev = cp; + } +} + + +#define SETUP_PAT_STATUS(ctmp,svar,val,htitle,hval) \ + {char tmp[MAXPATH+1]; \ + int i, j, lv; \ + NAMEVAL_S *f; \ + \ + /* Blank line */ \ + new_confline(&ctmp); \ + ctmp->flags |= CF_NOSELECT | CF_B_LINE; \ + \ + new_confline(&ctmp); \ + ctmp->var = &svar; \ + ctmp->keymenu = &config_radiobutton_keymenu; \ + ctmp->help = NO_HELP; \ + ctmp->tool = NULL; \ + snprintf(tmp, sizeof(tmp), "%-s =", svar.name); \ + tmp[sizeof(tmp)-1] = '\0'; \ + ctmp->varname = cpystr(tmp); \ + ctmp->varnamep = ctmpb = ctmp; \ + ctmp->flags |= (CF_NOSELECT | CF_STARTITEM); \ + \ + new_confline(&ctmp); \ + ctmp->var = NULL; \ + ctmp->valoffset = rindent; \ + ctmp->keymenu = &config_radiobutton_keymenu; \ + ctmp->help = NO_HELP; \ + ctmp->tool = NULL; \ + ctmp->varnamep = ctmpb; \ + ctmp->flags |= CF_NOSELECT; \ + ctmp->value = cpystr("Set Choose One"); \ + \ + new_confline(&ctmp); \ + ctmp->var = NULL; \ + ctmp->valoffset = rindent; \ + ctmp->keymenu = &config_radiobutton_keymenu; \ + ctmp->help = NO_HELP; \ + ctmp->tool = radio_tool; \ + ctmp->varnamep = ctmpb; \ + ctmp->flags |= CF_NOSELECT; \ + ctmp->value = cpystr(set_choose); \ + \ + /* find longest value's name */ \ + for(lv = 0, i = 0; (f = role_status_types(i)); i++) \ + if(lv < (j = utf8_width(f->name))) \ + lv = j; \ + \ + lv = MIN(lv, 100); \ + \ + for(i = 0; (f = role_status_types(i)); i++){ \ + new_confline(&ctmp); \ + ctmp->help_title= htitle; \ + ctmp->var = &svar; \ + ctmp->valoffset = rindent; \ + ctmp->keymenu = &config_radiobutton_keymenu; \ + ctmp->help = hval; \ + ctmp->varmem = i; \ + ctmp->tool = radio_tool; \ + ctmp->varnamep = ctmpb; \ + utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", (((!(def && def->patgrp) || \ + val == -1) && \ + f->value == PAT_STAT_EITHER) || \ + (def && def->patgrp && \ + f->value == val)) \ + ? R_SELD : ' ', \ + lv, lv, f->name); \ + tmp[sizeof(tmp)-1] = '\0'; \ + ctmp->value = cpystr(tmp); \ + } \ + } + +#define SETUP_MSG_STATE(ctmp,svar,val,htitle,hval) \ + {char tmp[MAXPATH+1]; \ + int i, j, lv; \ + NAMEVAL_S *f; \ + \ + /* Blank line */ \ + new_confline(&ctmp); \ + ctmp->flags |= CF_NOSELECT | CF_B_LINE; \ + \ + new_confline(&ctmp); \ + ctmp->var = &svar; \ + ctmp->keymenu = &config_radiobutton_keymenu; \ + ctmp->help = NO_HELP; \ + ctmp->tool = NULL; \ + snprintf(tmp, sizeof(tmp), "%-s =", svar.name); \ + tmp[sizeof(tmp)-1] = '\0'; \ + ctmp->varname = cpystr(tmp); \ + ctmp->varnamep = ctmpb = ctmp; \ + ctmp->flags |= (CF_NOSELECT | CF_STARTITEM); \ + \ + new_confline(&ctmp); \ + ctmp->var = NULL; \ + ctmp->valoffset = rindent; \ + ctmp->keymenu = &config_radiobutton_keymenu; \ + ctmp->help = NO_HELP; \ + ctmp->tool = NULL; \ + ctmp->varnamep = ctmpb; \ + ctmp->flags |= CF_NOSELECT; \ + ctmp->value = cpystr("Set Choose One"); \ + \ + new_confline(&ctmp); \ + ctmp->var = NULL; \ + ctmp->valoffset = rindent; \ + ctmp->keymenu = &config_radiobutton_keymenu; \ + ctmp->help = NO_HELP; \ + ctmp->tool = radio_tool; \ + ctmp->varnamep = ctmpb; \ + ctmp->flags |= CF_NOSELECT; \ + ctmp->value = cpystr(set_choose); \ + \ + /* find longest value's name */ \ + for(lv = 0, i = 0; (f = msg_state_types(i)); i++) \ + if(lv < (j = utf8_width(f->name))) \ + lv = j; \ + \ + lv = MIN(lv, 100); \ + \ + for(i = 0; (f = msg_state_types(i)); i++){ \ + new_confline(&ctmp); \ + ctmp->help_title= htitle; \ + ctmp->var = &svar; \ + ctmp->valoffset = rindent; \ + ctmp->keymenu = &config_radiobutton_keymenu; \ + ctmp->help = hval; \ + ctmp->varmem = i; \ + ctmp->tool = radio_tool; \ + ctmp->varnamep = ctmpb; \ + utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", (f->value == val) \ + ? R_SELD : ' ', \ + lv, lv, f->name); \ + tmp[sizeof(tmp)-1] = '\0'; \ + ctmp->value = cpystr(tmp); \ + } \ + } + + +#define FEAT_SENTDATE 0 +#define FEAT_IFNOTDEL 1 +#define FEAT_NONTERM 2 +bitmap_t feat_option_list; + +#define INABOOK_FROM 0 +#define INABOOK_REPLYTO 1 +#define INABOOK_SENDER 2 +#define INABOOK_TO 3 +#define INABOOK_CC 4 +bitmap_t inabook_type_list; + + +#define INICK_INICK_CONF 0 +#define INICK_FROM_CONF 1 +#define INICK_REPLYTO_CONF 2 +#define INICK_FCC_CONF 3 +#define INICK_LITSIG_CONF 4 /* this needs to come before SIG_CONF */ +#define INICK_SIG_CONF 5 +#define INICK_TEMPL_CONF 6 +#define INICK_CSTM_CONF 7 +#define INICK_SMTP_CONF 8 +#define INICK_NNTP_CONF 9 +CONF_S *inick_confs[INICK_NNTP_CONF+1]; + + +/* + * Screen for editing configuration of a role. + * + * Args ps -- pine struct + * def -- default role values to start with + * title -- part of title at top of screen + * rflags -- which parts of role to edit + * result -- This is the returned PAT_S, freed by caller. + * + * Returns: 0 if no change + * 1 if user requested a change + * (change is stored in raw_server and hasn't been acted upon yet) + * 10 user says abort + */ +int +role_config_edit_screen(struct pine *ps, PAT_S *def, char *title, long int rflags, PAT_S **result) +{ + OPT_SCREEN_S screen, *saved_screen; + CONF_S *ctmp = NULL, *ctmpb, *first_line = NULL; + struct variable nick_var, to_pat_var, from_pat_var, + comment_var, + sender_pat_var, cc_pat_var, recip_pat_var, news_pat_var, + subj_pat_var, inick_var, fldr_type_var, folder_pat_var, + abook_type_var, abook_pat_var, + alltext_pat_var, scorei_pat_var, partic_pat_var, + bodytext_pat_var, age_pat_var, size_pat_var, + keyword_pat_var, charset_pat_var, + stat_new_var, stat_del_var, stat_imp_var, stat_ans_var, + stat_rec_var, stat_8bit_var, + stat_bom_var, stat_boy_var, + cat_cmd_var, cati_var, cat_lim_var, + from_act_var, replyto_act_var, fcc_act_var, + sig_act_var, litsig_act_var, templ_act_var, + cstm_act_var, smtp_act_var, nntp_act_var, + sort_act_var, iform_act_var, startup_var, + repl_type_var, forw_type_var, comp_type_var, score_act_var, + hdrtok_act_var, + rolecolor_vars[2], filter_type_var, folder_act_var, + keyword_set_var, keyword_clr_var, + filt_new_var, filt_del_var, filt_imp_var, filt_ans_var; + struct variable *v, *varlist[65], opt_var, inabook_type_var; + char *nick = NULL, *inick = NULL, *fldr_type_pat = NULL, + *comment = NULL, + *scorei_pat = NULL, *age_pat = NULL, *size_pat = NULL, + *abook_type_pat = NULL, + *stat_new = NULL, *stat_del = NULL, *stat_imp = NULL, + *stat_rec = NULL, *stat_ans = NULL, *stat_8bit = NULL, + *stat_bom = NULL, *stat_boy = NULL, + *filt_new = NULL, *filt_del = NULL, *filt_imp = NULL, + *filt_ans = NULL, *cati = NULL, *cat_lim = NULL, + *from_act = NULL, *replyto_act = NULL, *fcc_act = NULL, + *sig_act = NULL, *litsig_act = NULL, *sort_act = NULL, + *templ_act = NULL, *repl_type = NULL, *forw_type = NULL, + *comp_type = NULL, *rc_fg = NULL, *rc_bg = NULL, + *score_act = NULL, *filter_type = NULL, + *hdrtok_act = NULL, + *iform_act = NULL, *startup_act = NULL, + *old_fg = NULL, *old_bg = NULL; + char **to_pat = NULL, **from_pat = NULL, **sender_pat = NULL, + **cc_pat = NULL, **news_pat = NULL, **recip_pat = NULL, + **partic_pat = NULL, **subj_pat = NULL, + **alltext_pat = NULL, **bodytext_pat = NULL, + **keyword_pat = NULL, **folder_pat = NULL, + **charset_pat = NULL, + **abook_pat = NULL, **folder_act = NULL, + **keyword_set = NULL, **keyword_clr = NULL, + **cat_cmd = NULL, **cstm_act = NULL, **smtp_act = NULL, + **nntp_act = NULL, **spat; + char tmp[MAXPATH+1], **apval, **lval, ***alval, *p; + /* TRANSLATORS: These next 4 are subheading for sections of a configuration screen. */ + char *fstr = _(" CURRENT FOLDER CONDITIONS BEGIN HERE "); + char mstr[50]; + char *astr = _(" ACTIONS BEGIN HERE "); + char *ustr = _(" USES BEGIN HERE "); + char *ostr = _(" OPTIONS BEGIN HERE "); + char *s_p_v_n = _("Subject pattern"); /* longest one of these */ + char *u_s_s = _("Use SMTP Server"); /* ditto */ + char *c_v_n = _("Exit Status Interval"); /* ditto */ + SortOrder def_sort; + int def_sort_rev; + ARBHDR_S *aa, *a; + EARB_S *earb = NULL, *ea; + int rv, i, j, lv, pindent, maxpindent, rindent, + scoreval = 0, edit_role, wid, + edit_incol, edit_score, edit_filter, edit_other, edit_srch, + dval, ival, nval, aval, fval, + per_folder_only, need_uses, need_options; + int (*radio_tool)(struct pine *, int, CONF_S **, unsigned); + int (*addhdr_tool)(struct pine *, int, CONF_S **, unsigned); + int (*t_tool)(struct pine *, int, CONF_S **, unsigned); + NAMEVAL_S *f; + + dprint((4, "role_config_edit_screen()\n")); + edit_role = rflags & ROLE_DO_ROLES; + edit_incol = rflags & ROLE_DO_INCOLS; + edit_score = rflags & ROLE_DO_SCORES; + edit_filter = rflags & ROLE_DO_FILTER; + edit_other = rflags & ROLE_DO_OTHER; + edit_srch = rflags & ROLE_DO_SRCH; + + per_folder_only = (edit_other && + !(edit_role || edit_incol || edit_score || edit_filter || edit_srch)); + need_uses = edit_role; + need_options = !per_folder_only; + + radio_tool = edit_filter ? role_filt_radiobutton_tool + : role_radiobutton_tool; + t_tool = edit_filter ? role_filt_text_tool : role_text_tool; + addhdr_tool = edit_filter ? role_filt_addhdr_tool : role_addhdr_tool; + + rindent = 12; /* radio indent */ + + /* + * We edit by making a nested call to conf_scroll_screen. + * We use some fake struct variables to get back the results in, and + * so we can use the existing tools from the config screen. + */ + varlist[j = 0] = &nick_var; + varlist[++j] = &comment_var; + varlist[++j] = &to_pat_var; + varlist[++j] = &from_pat_var; + varlist[++j] = &sender_pat_var; + varlist[++j] = &cc_pat_var; + varlist[++j] = &recip_pat_var; + varlist[++j] = &partic_pat_var; + varlist[++j] = &news_pat_var; + varlist[++j] = &subj_pat_var; + varlist[++j] = &alltext_pat_var; + varlist[++j] = &bodytext_pat_var; + varlist[++j] = &keyword_pat_var; + varlist[++j] = &charset_pat_var; + varlist[++j] = &age_pat_var; + varlist[++j] = &size_pat_var; + varlist[++j] = &scorei_pat_var; + varlist[++j] = &stat_new_var; + varlist[++j] = &stat_rec_var; + varlist[++j] = &stat_del_var; + varlist[++j] = &stat_imp_var; + varlist[++j] = &stat_ans_var; + varlist[++j] = &stat_8bit_var; + varlist[++j] = &stat_bom_var; + varlist[++j] = &stat_boy_var; + varlist[++j] = &cat_cmd_var; + varlist[++j] = &cati_var; + varlist[++j] = &cat_lim_var; + varlist[++j] = &inick_var; + varlist[++j] = &fldr_type_var; + varlist[++j] = &folder_pat_var; + varlist[++j] = &abook_type_var; + varlist[++j] = &abook_pat_var; + varlist[++j] = &from_act_var; + varlist[++j] = &replyto_act_var; + varlist[++j] = &fcc_act_var; + varlist[++j] = &sig_act_var; + varlist[++j] = &litsig_act_var; + varlist[++j] = &sort_act_var; + varlist[++j] = &iform_act_var; + varlist[++j] = &startup_var; + varlist[++j] = &templ_act_var; + varlist[++j] = &cstm_act_var; + varlist[++j] = &smtp_act_var; + varlist[++j] = &nntp_act_var; + varlist[++j] = &score_act_var; + varlist[++j] = &hdrtok_act_var; + varlist[++j] = &repl_type_var; + varlist[++j] = &forw_type_var; + varlist[++j] = &comp_type_var; + varlist[++j] = &rolecolor_vars[0]; + varlist[++j] = &rolecolor_vars[1]; + varlist[++j] = &filter_type_var; + varlist[++j] = &folder_act_var; + varlist[++j] = &keyword_set_var; + varlist[++j] = &keyword_clr_var; + varlist[++j] = &filt_new_var; + varlist[++j] = &filt_del_var; + varlist[++j] = &filt_imp_var; + varlist[++j] = &filt_ans_var; + varlist[++j] = &opt_var; + varlist[++j] = &inabook_type_var; + varlist[++j] = NULL; + for(j = 0; varlist[j]; j++) + memset(varlist[j], 0, sizeof(struct variable)); + + if(def && ((def->patgrp && def->patgrp->bogus) || (def->action && def->action->bogus))){ + char msg[MAX_SCREEN_COLS+1]; + + snprintf(msg, sizeof(msg), + _("Rule contains unknown %s element, possibly from newer Alpine"), + (def->patgrp && def->patgrp->bogus) ? "pattern" : "action"); + msg[sizeof(msg)-1] = '\0'; + q_status_message(SM_ORDER | SM_DING, 7, 7, msg); + q_status_message(SM_ORDER | SM_DING, 7, 7, + _("Editing with this version of Alpine will destroy information")); + flush_status_messages(0); + } + + role_forw_ptr = role_repl_ptr = role_fldr_ptr = role_filt_ptr = NULL; + role_status1_ptr = role_status2_ptr = role_status3_ptr = NULL; + role_status4_ptr = role_status5_ptr = role_status6_ptr = NULL; + role_status7_ptr = NULL; role_status8_ptr = NULL; + msg_state1_ptr = msg_state2_ptr = NULL; + msg_state3_ptr = msg_state4_ptr = NULL; + role_afrom_ptr = startup_ptr = NULL; + role_comment_ptr = NULL; + + nick_var.name = cpystr(_("Nickname")); + nick_var.is_used = 1; + nick_var.is_user = 1; + apval = APVAL(&nick_var, ew); + *apval = (def && def->patgrp && def->patgrp->nick) + ? cpystr(def->patgrp->nick) : NULL; + + nick_var.global_val.p = cpystr(edit_role + ? "Alternate Role" + : (edit_other + ? "Other Rule" + : (edit_incol + ? "Index Color Rule" + : (edit_score + ? "Score Rule" + : "Filter Rule")))); + set_current_val(&nick_var, FALSE, FALSE); + + role_comment_ptr = &comment_var; /* so radiobuttons can tell */ + comment_var.name = cpystr(_("Comment")); + comment_var.is_used = 1; + comment_var.is_user = 1; + apval = APVAL(&comment_var, ew); + *apval = (def && def->patgrp && def->patgrp->comment) + ? cpystr(def->patgrp->comment) : NULL; + set_current_val(&comment_var, FALSE, FALSE); + + /* TRANSLATORS: Quite a few of the translations to follow are from the + rules editing screens. These are mostly headings of individual categories + of criteria which can be set in a rule. */ + setup_dummy_pattern_var(&to_pat_var, _("To pattern"), + (def && def->patgrp) ? def->patgrp->to : NULL); + setup_dummy_pattern_var(&from_pat_var, _("From pattern"), + (def && def->patgrp) ? def->patgrp->from : NULL); + setup_dummy_pattern_var(&sender_pat_var, _("Sender pattern"), + (def && def->patgrp) ? def->patgrp->sender : NULL); + setup_dummy_pattern_var(&cc_pat_var, _("Cc pattern"), + (def && def->patgrp) ? def->patgrp->cc : NULL); + setup_dummy_pattern_var(&news_pat_var, _("News pattern"), + (def && def->patgrp) ? def->patgrp->news : NULL); + setup_dummy_pattern_var(&subj_pat_var, s_p_v_n, + (def && def->patgrp) ? def->patgrp->subj : NULL); + /* TRANSLATORS: Recip is an abbreviation for Recipients which stands for + all of the recipients of a message. */ + setup_dummy_pattern_var(&recip_pat_var, _("Recip pattern"), + (def && def->patgrp) ? def->patgrp->recip : NULL); + /* TRANSLATORS: Partic is an abbreviation for Participants which stands for + all of the recipients plus the sender of a message. */ + setup_dummy_pattern_var(&partic_pat_var, _("Partic pattern"), + (def && def->patgrp) ? def->patgrp->partic : NULL); + /* TRANSLATORS: AllText means all of the text of a message */ + setup_dummy_pattern_var(&alltext_pat_var, _("AllText pattern"), + (def && def->patgrp) ? def->patgrp->alltext : NULL); + /* TRANSLATORS: BdyText means the text of a message but not the text in the headers */ + setup_dummy_pattern_var(&bodytext_pat_var, _("BdyText pattern"), + (def && def->patgrp) ? def->patgrp->bodytext : NULL); + + setup_dummy_pattern_var(&keyword_pat_var, _("Keyword pattern"), + (def && def->patgrp) ? def->patgrp->keyword : NULL); + setup_dummy_pattern_var(&charset_pat_var, _("Charset pattern"), + (def && def->patgrp) ? def->patgrp->charsets : NULL); + + age_pat_global_ptr = &age_pat_var; + /* TRANSLATORS: Age interval is a setting for how old the message is. */ + age_pat_var.name = cpystr(_("Age interval")); + age_pat_var.is_used = 1; + age_pat_var.is_user = 1; + if(def && def->patgrp && def->patgrp->do_age){ + apval = APVAL(&age_pat_var, ew); + *apval = stringform_of_intvl(def->patgrp->age); + } + + set_current_val(&age_pat_var, FALSE, FALSE); + + size_pat_global_ptr = &size_pat_var; + size_pat_var.name = cpystr(_("Size interval")); + size_pat_var.is_used = 1; + size_pat_var.is_user = 1; + if(def && def->patgrp && def->patgrp->do_size){ + apval = APVAL(&size_pat_var, ew); + *apval = stringform_of_intvl(def->patgrp->size); + } + + set_current_val(&size_pat_var, FALSE, FALSE); + + scorei_pat_global_ptr = &scorei_pat_var; + /* TRANSLATORS: Score is an alpine concept where the score can be kept for a + message to see if it is a message you want to look at. */ + scorei_pat_var.name = cpystr(_("Score interval")); + scorei_pat_var.is_used = 1; + scorei_pat_var.is_user = 1; + if(def && def->patgrp && def->patgrp->do_score){ + apval = APVAL(&scorei_pat_var, ew); + *apval = stringform_of_intvl(def->patgrp->score); + } + + set_current_val(&scorei_pat_var, FALSE, FALSE); + + role_status1_ptr = &stat_del_var; /* so radiobuttons can tell */ + stat_del_var.name = cpystr(_("Message is Deleted?")); + stat_del_var.is_used = 1; + stat_del_var.is_user = 1; + apval = APVAL(&stat_del_var, ew); + *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_del : -1)) ? cpystr(f->name) : NULL; + set_current_val(&stat_del_var, FALSE, FALSE); + + role_status2_ptr = &stat_new_var; /* so radiobuttons can tell */ + stat_new_var.name = cpystr(_("Message is New (Unseen)?")); + stat_new_var.is_used = 1; + stat_new_var.is_user = 1; + apval = APVAL(&stat_new_var, ew); + *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_new : -1)) ? cpystr(f->name) : NULL; + set_current_val(&stat_new_var, FALSE, FALSE); + + role_status3_ptr = &stat_imp_var; /* so radiobuttons can tell */ + stat_imp_var.name = cpystr(_("Message is Important?")); + stat_imp_var.is_used = 1; + stat_imp_var.is_user = 1; + apval = APVAL(&stat_imp_var, ew); + *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_imp : -1)) ? cpystr(f->name) : NULL; + set_current_val(&stat_imp_var, FALSE, FALSE); + + role_status4_ptr = &stat_ans_var; /* so radiobuttons can tell */ + stat_ans_var.name = cpystr(_("Message is Answered?")); + stat_ans_var.is_used = 1; + stat_ans_var.is_user = 1; + apval = APVAL(&stat_ans_var, ew); + *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_ans : -1)) ? cpystr(f->name) : NULL; + set_current_val(&stat_ans_var, FALSE, FALSE); + + role_status5_ptr = &stat_8bit_var; /* so radiobuttons can tell */ + stat_8bit_var.name = cpystr(_("Subject contains raw 8-bit?")); + stat_8bit_var.is_used = 1; + stat_8bit_var.is_user = 1; + apval = APVAL(&stat_8bit_var, ew); + *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_8bitsubj : -1)) ? cpystr(f->name) : NULL; + set_current_val(&stat_8bit_var, FALSE, FALSE); + + role_status6_ptr = &stat_rec_var; /* so radiobuttons can tell */ + stat_rec_var.name = cpystr(_("Message is Recent?")); + stat_rec_var.is_used = 1; + stat_rec_var.is_user = 1; + apval = APVAL(&stat_rec_var, ew); + *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_rec : -1)) ? cpystr(f->name) : NULL; + set_current_val(&stat_rec_var, FALSE, FALSE); + + role_status7_ptr = &stat_bom_var; /* so radiobuttons can tell */ + stat_bom_var.name = cpystr(_("Beginning of Month?")); + stat_bom_var.is_used = 1; + stat_bom_var.is_user = 1; + apval = APVAL(&stat_bom_var, ew); + *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_bom : -1)) ? cpystr(f->name) : NULL; + set_current_val(&stat_bom_var, FALSE, FALSE); + + role_status8_ptr = &stat_boy_var; /* so radiobuttons can tell */ + stat_boy_var.name = cpystr(_("Beginning of Year?")); + stat_boy_var.is_used = 1; + stat_boy_var.is_user = 1; + apval = APVAL(&stat_boy_var, ew); + *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_boy : -1)) ? cpystr(f->name) : NULL; + set_current_val(&stat_boy_var, FALSE, FALSE); + + + + convert_statebits_to_vals((def && def->action) ? def->action->state_setting_bits : 0L, &dval, &aval, &ival, &nval); + msg_state1_ptr = &filt_del_var; /* so radiobuttons can tell */ + /* TRANSLATORS: these are actions that might be taken by the rule */ + filt_del_var.name = cpystr(_("Set Deleted Status")); + filt_del_var.is_used = 1; + filt_del_var.is_user = 1; + apval = APVAL(&filt_del_var, ew); + *apval = (f=msg_state_types(dval)) ? cpystr(f->name) : NULL; + set_current_val(&filt_del_var, FALSE, FALSE); + + msg_state2_ptr = &filt_new_var; /* so radiobuttons can tell */ + filt_new_var.name = cpystr(_("Set New Status")); + filt_new_var.is_used = 1; + filt_new_var.is_user = 1; + apval = APVAL(&filt_new_var, ew); + *apval = (f=msg_state_types(nval)) ? cpystr(f->name) : NULL; + set_current_val(&filt_new_var, FALSE, FALSE); + + msg_state3_ptr = &filt_imp_var; /* so radiobuttons can tell */ + filt_imp_var.name = cpystr(_("Set Important Status")); + filt_imp_var.is_used = 1; + filt_imp_var.is_user = 1; + apval = APVAL(&filt_imp_var, ew); + *apval = (f=msg_state_types(ival)) ? cpystr(f->name) : NULL; + set_current_val(&filt_imp_var, FALSE, FALSE); + + msg_state4_ptr = &filt_ans_var; /* so radiobuttons can tell */ + filt_ans_var.name = cpystr(_("Set Answered Status")); + filt_ans_var.is_used = 1; + filt_ans_var.is_user = 1; + apval = APVAL(&filt_ans_var, ew); + *apval = (f=msg_state_types(aval)) ? cpystr(f->name) : NULL; + set_current_val(&filt_ans_var, FALSE, FALSE); + + inick_var.name = cpystr(_("Initialize settings using role")); + inick_var.is_used = 1; + inick_var.is_user = 1; + apval = APVAL(&inick_var, ew); + *apval = (def && def->action && def->action->inherit_nick && + def->action->inherit_nick[0]) + ? cpystr(def->action->inherit_nick) : NULL; + + role_fldr_ptr = &fldr_type_var; /* so radiobuttons can tell */ + fldr_type_var.name = cpystr(_("Current Folder Type")); + fldr_type_var.is_used = 1; + fldr_type_var.is_user = 1; + apval = APVAL(&fldr_type_var, ew); + *apval = (f=pat_fldr_types((def && def->patgrp) ? def->patgrp->fldr_type : (!def && edit_filter) ? FLDR_SPECIFIC : FLDR_DEFL)) ? cpystr(f->name) : NULL; + set_current_val(&fldr_type_var, FALSE, FALSE); + + setup_dummy_pattern_var(&folder_pat_var, _("Folder List"), + (def && def->patgrp) ? def->patgrp->folder : NULL); + /* special default for folder_pat */ + alval = ALVAL(&folder_pat_var, ew); + if(alval && !*alval && !def && edit_filter){ + char **ltmp; + + ltmp = (char **) fs_get(2 * sizeof(*ltmp)); + ltmp[0] = cpystr(ps_global->inbox_name); + ltmp[1] = NULL; + *alval = ltmp; + set_current_val(&folder_pat_var, FALSE, FALSE); + } + + role_afrom_ptr = &abook_type_var; /* so radiobuttons can tell */ + abook_type_var.name = cpystr(_("Address in address book?")); + abook_type_var.is_used = 1; + abook_type_var.is_user = 1; + apval = APVAL(&abook_type_var, ew); + *apval = (f=inabook_fldr_types((def && def->patgrp) ? def->patgrp->inabook : IAB_EITHER)) ? cpystr(f->name) : NULL; + set_current_val(&abook_type_var, FALSE, FALSE); + + /* TRANSLATORS: Abook is an abbreviation for Address Book */ + setup_dummy_pattern_var(&abook_pat_var, _("Abook List"), + (def && def->patgrp) ? def->patgrp->abooks : NULL); + + /* + * This is a little different from some of the other patterns. Tt is + * actually a char ** in the struct instead of a PATTERN_S. + */ + cat_cmd_global_ptr = &cat_cmd_var; + cat_cmd_var.name = cpystr(_("External Categorizer Commands")); + cat_cmd_var.is_used = 1; + cat_cmd_var.is_user = 1; + cat_cmd_var.is_list = 1; + alval = ALVAL(&cat_cmd_var, ew); + *alval = (def && def->patgrp && def->patgrp->category_cmd && + def->patgrp->category_cmd[0]) + ? copy_list_array(def->patgrp->category_cmd) : NULL; + set_current_val(&cat_cmd_var, FALSE, FALSE); + + cati_global_ptr = &cati_var; + cati_var.name = cpystr(c_v_n); + cati_var.is_used = 1; + cati_var.is_user = 1; + if(def && def->patgrp && def->patgrp->do_cat && def->patgrp->category_cmd && + def->patgrp->category_cmd[0]){ + apval = APVAL(&cati_var, ew); + *apval = stringform_of_intvl(def->patgrp->cat); + } + + set_current_val(&cati_var, FALSE, FALSE); + + cat_lim_global_ptr = &cat_lim_var; + cat_lim_var.name = cpystr(_("Character Limit")); + cat_lim_var.is_used = 1; + cat_lim_var.is_user = 1; + cat_lim_var.global_val.p = cpystr("-1"); + apval = APVAL(&cat_lim_var, ew); + if(def && def->patgrp && def->patgrp->category_cmd && + def->patgrp->category_cmd[0] && def->patgrp->cat_lim != -1){ + *apval = (char *) fs_get(20 * sizeof(char)); + snprintf(*apval, 20, "%ld", def->patgrp->cat_lim); + (*apval)[20-1] = '\0'; + } + + set_current_val(&cat_lim_var, FALSE, FALSE); + + from_act_var.name = cpystr(_("Set From")); + from_act_var.is_used = 1; + from_act_var.is_user = 1; + if(def && def->action && def->action->from){ + char *bufp; + size_t len; + + len = est_size(def->action->from); + bufp = (char *) fs_get(len * sizeof(char)); + apval = APVAL(&from_act_var, ew); + *apval = addr_string_mult(def->action->from, bufp, len); + } + else{ + apval = APVAL(&from_act_var, ew); + *apval = NULL; + } + + replyto_act_var.name = cpystr(_("Set Reply-To")); + replyto_act_var.is_used = 1; + replyto_act_var.is_user = 1; + if(def && def->action && def->action->replyto){ + char *bufp; + size_t len; + + len = est_size(def->action->replyto); + bufp = (char *) fs_get(len * sizeof(char)); + apval = APVAL(&replyto_act_var, ew); + *apval = addr_string_mult(def->action->replyto, bufp, len); + } + else{ + apval = APVAL(&replyto_act_var, ew); + *apval = NULL; + } + + fcc_act_var.name = cpystr(_("Set Fcc")); + fcc_act_var.is_used = 1; + fcc_act_var.is_user = 1; + apval = APVAL(&fcc_act_var, ew); + *apval = (def && def->action && def->action->fcc) + ? cpystr(def->action->fcc) : NULL; + + sort_act_var.name = cpystr(_("Set Sort Order")); + sort_act_var.is_used = 1; + sort_act_var.is_user = 1; + apval = APVAL(&sort_act_var, ew); + if(def && def->action && def->action->is_a_other && + def->action->sort_is_set){ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s", sort_name(def->action->sortorder), + (def->action->revsort) ? "/Reverse" : ""); + tmp_20k_buf[SIZEOF_20KBUF-1] = '\0'; + *apval = cpystr(tmp_20k_buf); + } + else + *apval = NULL; + + iform_act_var.name = cpystr(_("Set Index Format")); + iform_act_var.is_used = 1; + iform_act_var.is_user = 1; + apval = APVAL(&iform_act_var, ew); + *apval = (def && def->action && def->action->is_a_other && + def->action->index_format) + ? cpystr(def->action->index_format) : NULL; + if(ps_global->VAR_INDEX_FORMAT){ + iform_act_var.global_val.p = cpystr(ps_global->VAR_INDEX_FORMAT); + set_current_val(&iform_act_var, FALSE, FALSE); + } + + startup_ptr = &startup_var; + startup_var.name = cpystr(_("Set Startup Rule")); + startup_var.is_used = 1; + startup_var.is_user = 1; + apval = APVAL(&startup_var, ew); + *apval = NULL; + if(def && def->action && def->action->is_a_other){ + *apval = (f=startup_rules(def->action->startup_rule)) + ? cpystr(f->name) : NULL; + set_current_val(&startup_var, FALSE, FALSE); + } + if(!*apval){ + *apval = (f=startup_rules(IS_NOTSET)) ? cpystr(f->name) : NULL; + set_current_val(&startup_var, FALSE, FALSE); + } + + /* TRANSLATORS: LiteralSig is a way to keep the signature in the configuration + file instead of in a separate Signature file. */ + litsig_act_var.name = cpystr(_("Set LiteralSig")); + litsig_act_var.is_used = 1; + litsig_act_var.is_user = 1; + apval = APVAL(&litsig_act_var, ew); + *apval = (def && def->action && def->action->litsig) + ? cpystr(def->action->litsig) : NULL; + + sig_act_var.name = cpystr(_("Set Signature")); + sig_act_var.is_used = 1; + sig_act_var.is_user = 1; + apval = APVAL(&sig_act_var, ew); + *apval = (def && def->action && def->action->sig) + ? cpystr(def->action->sig) : NULL; + + /* TRANSLATORS: A template is a skeleton of a message to be used + for composing a new message */ + templ_act_var.name = cpystr(_("Set Template")); + templ_act_var.is_used = 1; + templ_act_var.is_user = 1; + apval = APVAL(&templ_act_var, ew); + *apval = (def && def->action && def->action->template) + ? cpystr(def->action->template) : NULL; + + /* TRANSLATORS: Hdrs is an abbreviation for Headers */ + cstm_act_var.name = cpystr(_("Set Other Hdrs")); + cstm_act_var.is_used = 1; + cstm_act_var.is_user = 1; + cstm_act_var.is_list = 1; + alval = ALVAL(&cstm_act_var, ew); + *alval = (def && def->action && def->action->cstm) + ? copy_list_array(def->action->cstm) : NULL; + + smtp_act_var.name = cpystr(u_s_s); + smtp_act_var.is_used = 1; + smtp_act_var.is_user = 1; + smtp_act_var.is_list = 1; + alval = ALVAL(&smtp_act_var, ew); + *alval = (def && def->action && def->action->smtp) + ? copy_list_array(def->action->smtp) : NULL; + + nntp_act_var.name = cpystr(_("Use NNTP Server")); + nntp_act_var.is_used = 1; + nntp_act_var.is_user = 1; + nntp_act_var.is_list = 1; + alval = ALVAL(&nntp_act_var, ew); + *alval = (def && def->action && def->action->nntp) + ? copy_list_array(def->action->nntp) : NULL; + + score_act_global_ptr = &score_act_var; + score_act_var.name = cpystr(_("Score Value")); + score_act_var.is_used = 1; + score_act_var.is_user = 1; + if(def && def->action && def->action->scoreval >= SCORE_MIN && + def->action->scoreval <= SCORE_MAX) + scoreval = def->action->scoreval; + + score_act_var.global_val.p = cpystr("0"); + if(scoreval != 0){ + apval = APVAL(&score_act_var, ew); + *apval = (char *)fs_get(20 * sizeof(char)); + snprintf(*apval, 20, "%d", scoreval); + (*apval)[20-1] = '\0'; + } + + set_current_val(&score_act_var, FALSE, FALSE); + + hdrtok_act_var.name = cpystr(_("Score From Header")); + hdrtok_act_var.is_used = 1; + hdrtok_act_var.is_user = 1; + if(def && def->action && def->action->scorevalhdrtok){ + apval = APVAL(&hdrtok_act_var, ew); + *apval = hdrtok_to_stringform(def->action->scorevalhdrtok); + } + + set_current_val(&hdrtok_act_var, FALSE, FALSE); + + role_repl_ptr = &repl_type_var; /* so radiobuttons can tell */ + /* TRANSLATORS: For these, Use is a now. This part of the rule describes how + it will be used when Replying so it is the Reply Use */ + repl_type_var.name = cpystr(_("Reply Use")); + repl_type_var.is_used = 1; + repl_type_var.is_user = 1; + apval = APVAL(&repl_type_var, ew); + *apval = (f=role_repl_types((def && def->action) ? def->action->repl_type : -1)) ? cpystr(f->name) : NULL; + set_current_val(&repl_type_var, FALSE, FALSE); + + role_forw_ptr = &forw_type_var; /* so radiobuttons can tell */ + forw_type_var.name = cpystr(_("Forward Use")); + forw_type_var.is_used = 1; + forw_type_var.is_user = 1; + apval = APVAL(&forw_type_var, ew); + *apval = (f=role_forw_types((def && def->action) ? def->action->forw_type : -1)) ? cpystr(f->name) : NULL; + set_current_val(&forw_type_var, FALSE, FALSE); + + comp_type_var.name = cpystr(_("Compose Use")); + comp_type_var.is_used = 1; + comp_type_var.is_user = 1; + apval = APVAL(&comp_type_var, ew); + *apval = (f=role_comp_types((def && def->action) ? def->action->comp_type : -1)) ? cpystr(f->name) : NULL; + set_current_val(&comp_type_var, FALSE, FALSE); + + rolecolor_vars[0].is_used = 1; + rolecolor_vars[0].is_user = 1; + apval = APVAL(&rolecolor_vars[0], ew); + *apval = (def && def->action && def->action->incol && + def->action->incol->fg[0]) + ? cpystr(def->action->incol->fg) : NULL; + rolecolor_vars[1].is_used = 1; + rolecolor_vars[1].is_user = 1; + rolecolor_vars[0].name = cpystr("ic-foreground-color"); + rolecolor_vars[1].name = cpystr(rolecolor_vars[0].name); + strncpy(rolecolor_vars[1].name + 3, "back", 4); + apval = APVAL(&rolecolor_vars[1], ew); + *apval = (def && def->action && def->action->incol && + def->action->incol->bg[0]) + ? cpystr(def->action->incol->bg) : NULL; + set_current_val(&rolecolor_vars[0], FALSE, FALSE); + set_current_val(&rolecolor_vars[1], FALSE, FALSE); + old_fg = PVAL(&rolecolor_vars[0], ew) ? cpystr(PVAL(&rolecolor_vars[0], ew)) + : NULL; + old_bg = PVAL(&rolecolor_vars[1], ew) ? cpystr(PVAL(&rolecolor_vars[1], ew)) + : NULL; + + + /* save the old opt_screen before calling scroll screen again */ + saved_screen = opt_screen; + + pindent = utf8_width(s_p_v_n); /* the longest one */ + maxpindent = pindent + 6; + for(a = (def && def->patgrp) ? def->patgrp->arbhdr : NULL; a; a = a->next) + if((lv=utf8_width(a->field ? a->field : "")+utf8_width(" pattern")) > pindent) + pindent = lv; + + pindent = MIN(pindent, maxpindent); + + pindent += NOTLEN; /* width of `! ' */ + + pindent += 3; /* width of ` = ' */ + + /* Nickname */ + new_confline(&ctmp); + ctmp->help_title= _("HELP FOR NICKNAME"); + ctmp->var = &nick_var; + ctmp->valoffset = pindent; + ctmp->keymenu = &config_role_keymenu; + ctmp->help = edit_role ? h_config_role_nick : + edit_incol ? h_config_incol_nick : + edit_score ? h_config_score_nick : + edit_other ? h_config_other_nick + : h_config_filt_nick; + ctmp->tool = t_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, nick_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmp; + ctmp->value = pretty_value(ps, ctmp); + ctmp->varmem = -1; + + first_line = ctmp; + if(rflags & ROLE_CHANGES) + first_line->flags |= CF_CHANGES; + + /* Comment */ + new_confline(&ctmp); + ctmp->help_title= _("HELP FOR COMMENT"); + ctmp->var = &comment_var; + ctmp->valoffset = pindent; + ctmp->keymenu = &config_role_keymenu; + ctmp->help = h_config_role_comment; + ctmp->tool = role_litsig_text_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, comment_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmp; + ctmp->value = pretty_value(ps, ctmp); + ctmp->varmem = -1; + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT; + if(ps->ttyo->screen_cols >= (wid=utf8_width(fstr)) + 4){ + int dashes; + + dashes = (ps->ttyo->screen_cols - wid)/2; + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='), + fstr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '=')); + ctmp->value = cpystr(tmp_20k_buf); + } + else + ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '=')); + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + /* Folder Type */ + new_confline(&ctmp); + ctmp->var = &fldr_type_var; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = NULL; + snprintf(tmp, sizeof(tmp), "%s =", fldr_type_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmpb = ctmp; + ctmp->flags |= (CF_NOSELECT | CF_STARTITEM); + + new_confline(&ctmp); + ctmp->var = NULL; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = NULL; + ctmp->varnamep = ctmpb; + ctmp->flags |= CF_NOSELECT; + ctmp->value = cpystr("Set Choose One"); + + new_confline(&ctmp); + ctmp->var = NULL; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = radio_tool; + ctmp->varnamep = ctmpb; + ctmp->flags |= CF_NOSELECT; + ctmp->value = cpystr(set_choose); \ + + /* find longest value's name */ + for(lv = 0, i = 0; (f = pat_fldr_types(i)); i++) + if(lv < (j = utf8_width(f->name))) + lv = j; + + lv = MIN(lv, 100); + + fval = -1; + for(i = 0; (f = pat_fldr_types(i)); i++){ + new_confline(&ctmp); + ctmp->help_title= _("HELP FOR CURRENT FOLDER TYPE"); + ctmp->var = &fldr_type_var; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = edit_role ? h_config_role_fldr_type : + edit_incol ? h_config_incol_fldr_type : + edit_score ? h_config_score_fldr_type : + edit_other ? h_config_other_fldr_type + : h_config_filt_fldr_type; + ctmp->varmem = i; + ctmp->tool = radio_tool; + ctmp->varnamep = ctmpb; + + if((PVAL(&fldr_type_var, ew) && + !strucmp(PVAL(&fldr_type_var, ew), f->name)) + || (!PVAL(&fldr_type_var, ew) && f->value == FLDR_DEFL)) + fval = f->value; + + utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", + (fval == f->value) ? R_SELD : ' ', + lv, lv, f->name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->value = cpystr(tmp); + } + + /* Folder */ + /* 5 is the width of `(*) ' */ + setup_role_pat_alt(ps, &ctmp, &folder_pat_var, + edit_role ? h_config_role_fldr_type : + edit_incol ? h_config_incol_fldr_type : + edit_score ? h_config_score_fldr_type : + edit_other ? h_config_other_fldr_type + : h_config_filt_fldr_type, + _("HELP FOR FOLDER LIST"), + &config_role_patfolder_keymenu, t_tool, rindent+5, + !(fval == FLDR_SPECIFIC)); + + if(!per_folder_only){ /* sorry about that indent */ + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT; + + /* TRANSLATORS: The %s is replaced with one of the 4 or 5 words below, CURRENT, + SCORED, and so on. */ + snprintf(mstr, sizeof(mstr), _(" %s MESSAGE CONDITIONS BEGIN HERE "), + edit_role ? _("CURRENT") : + edit_score ? _("SCORED") : + edit_incol ? _("COLORED") : + edit_filter ? _("FILTERED") : _("CURRENT")); + mstr[sizeof(mstr)-1] = '\0'; + + if(ps->ttyo->screen_cols >= (wid=utf8_width(mstr)) + 4){ + int dashes; + + dashes = (ps->ttyo->screen_cols - wid)/2; + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='), + mstr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '=')); + ctmp->value = cpystr(tmp_20k_buf); + } + else + ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '=')); + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + setup_role_pat(ps, &ctmp, &to_pat_var, + edit_role ? h_config_role_topat : + edit_incol ? h_config_incol_topat : + edit_score ? h_config_score_topat : + edit_other ? h_config_other_topat + : h_config_filt_topat, + _("HELP FOR TO PATTERN"), + &config_role_addr_pat_keymenu, t_tool, &earb, pindent); + + setup_role_pat(ps, &ctmp, &from_pat_var, h_config_role_frompat, + _("HELP FOR FROM PATTERN"), + &config_role_addr_pat_keymenu, t_tool, &earb, pindent); + + setup_role_pat(ps, &ctmp, &sender_pat_var, h_config_role_senderpat, + _("HELP FOR SENDER PATTERN"), + &config_role_addr_pat_keymenu, t_tool, &earb, pindent); + + setup_role_pat(ps, &ctmp, &cc_pat_var, h_config_role_ccpat, + _("HELP FOR CC PATTERN"), + &config_role_addr_pat_keymenu, t_tool, &earb, pindent); + + setup_role_pat(ps, &ctmp, &news_pat_var, h_config_role_newspat, + _("HELP FOR NEWS PATTERN"), + &config_role_keymenu_not, t_tool, &earb, pindent); + + setup_role_pat(ps, &ctmp, &subj_pat_var, h_config_role_subjpat, + _("HELP FOR SUBJECT PATTERN"), + &config_role_keymenu_not, t_tool, &earb, pindent); + + setup_role_pat(ps, &ctmp, &recip_pat_var, h_config_role_recippat, + _("HELP FOR RECIPIENT PATTERN"), + &config_role_addr_pat_keymenu, t_tool, &earb, pindent); + + setup_role_pat(ps, &ctmp, &partic_pat_var, h_config_role_particpat, + _("HELP FOR PARTICIPANT PATTERN"), + &config_role_addr_pat_keymenu, t_tool, &earb, pindent); + + /* Arbitrary Patterns */ + ea = NULL; + for(j = 0, a = (def && def->patgrp) ? def->patgrp->arbhdr : NULL; + a; + j++, a = a->next){ + char *fn = (a->field) ? a->field : ""; + + if(ea){ + ea->next = (EARB_S *)fs_get(sizeof(*ea)); + ea = ea->next; + } + else{ + earb = (EARB_S *)fs_get(sizeof(*ea)); + ea = earb; + } + + memset((void *)ea, 0, sizeof(*ea)); + ea->v = (struct variable *)fs_get(sizeof(struct variable)); + memset((void *)ea->v, 0, sizeof(struct variable)); + ea->a = (ARBHDR_S *)fs_get(sizeof(ARBHDR_S)); + memset((void *)ea->a, 0, sizeof(ARBHDR_S)); + + ea->a->field = cpystr(fn); + + p = (char *) fs_get(strlen(fn) + strlen(" pattern") + 1); + snprintf(p, strlen(fn) + strlen(" pattern") + 1, "%s pattern", fn); + p[strlen(fn) + strlen(" pattern") + 1 - 1] = '\0'; + setup_dummy_pattern_var(ea->v, p, a->p); + fs_give((void **) &p); + setup_role_pat(ps, &ctmp, ea->v, h_config_role_arbpat, + ARB_HELP, &config_role_xtrahdr_keymenu, + t_tool, &earb, pindent); + } + + new_confline(&ctmp); + ctmp->help_title = _("HELP FOR EXTRA HEADERS"); + ctmp->value = cpystr(ADDXHDRS); + ctmp->keymenu = &config_role_keymenu_extra; + ctmp->help = h_config_role_arbpat; + ctmp->tool = addhdr_tool; + ctmp->d.earb = &earb; + ctmp->varmem = -1; + + setup_role_pat(ps, &ctmp, &alltext_pat_var, h_config_role_alltextpat, + _("HELP FOR ALL TEXT PATTERN"), + &config_role_keymenu_not, t_tool, &earb, pindent); + + setup_role_pat(ps, &ctmp, &bodytext_pat_var, h_config_role_bodytextpat, + _("HELP FOR BODY TEXT PATTERN"), + &config_role_keymenu_not, t_tool, &earb, pindent); + + /* Age Interval */ + new_confline(&ctmp); + ctmp->help_title= _("HELP FOR AGE INTERVAL"); + ctmp->var = &age_pat_var; + ctmp->valoffset = pindent; + ctmp->keymenu = &config_text_keymenu; + ctmp->help = h_config_role_age; + ctmp->tool = t_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, age_pat_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmp; + ctmp->value = pretty_value(ps, ctmp); + + /* Size Interval */ + new_confline(&ctmp); + ctmp->help_title= _("HELP FOR SIZE INTERVAL"); + ctmp->var = &size_pat_var; + ctmp->valoffset = pindent; + ctmp->keymenu = &config_text_keymenu; + ctmp->help = h_config_role_size; + ctmp->tool = t_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, size_pat_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmp; + ctmp->value = pretty_value(ps, ctmp); + + if(!edit_score){ + /* Score Interval */ + new_confline(&ctmp); + ctmp->help_title= _("HELP FOR SCORE INTERVAL"); + ctmp->var = &scorei_pat_var; + ctmp->valoffset = pindent; + ctmp->keymenu = &config_text_keymenu; + ctmp->help = h_config_role_scorei; + ctmp->tool = t_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, scorei_pat_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmp; + ctmp->value = pretty_value(ps, ctmp); + } + + /* Keyword Pattern */ + setup_role_pat(ps, &ctmp, &keyword_pat_var, h_config_role_keywordpat, + _("HELP FOR KEYWORD PATTERN"), + &config_role_keyword_keymenu_not, role_text_tool_kword, + NULL, pindent); + + /* Charset Pattern */ + setup_role_pat(ps, &ctmp, &charset_pat_var, h_config_role_charsetpat, + _("HELP FOR CHARACTER SET PATTERN"), + &config_role_charset_keymenu_not, role_text_tool_charset, + NULL, pindent); + + /* Important Status */ + SETUP_PAT_STATUS(ctmp, stat_imp_var, def->patgrp->stat_imp, + _("HELP FOR IMPORTANT STATUS"), h_config_role_stat_imp); + /* New Status */ + SETUP_PAT_STATUS(ctmp, stat_new_var, def->patgrp->stat_new, + _("HELP FOR NEW STATUS"), h_config_role_stat_new); + /* Recent Status */ + SETUP_PAT_STATUS(ctmp, stat_rec_var, def->patgrp->stat_rec, + _("HELP FOR RECENT STATUS"), h_config_role_stat_recent); + /* Deleted Status */ + SETUP_PAT_STATUS(ctmp, stat_del_var, def->patgrp->stat_del, + _("HELP FOR DELETED STATUS"), h_config_role_stat_del); + /* Answered Status */ + SETUP_PAT_STATUS(ctmp, stat_ans_var, def->patgrp->stat_ans, + _("HELP FOR ANSWERED STATUS"), h_config_role_stat_ans); + /* 8-bit Subject */ + SETUP_PAT_STATUS(ctmp, stat_8bit_var, def->patgrp->stat_8bitsubj, + _("HELP FOR 8-BIT SUBJECT"), h_config_role_stat_8bitsubj); + /* Beginning of month */ + SETUP_PAT_STATUS(ctmp, stat_bom_var, def->patgrp->stat_bom, + _("HELP FOR BEGINNING OF MONTH"), h_config_role_bom); + /* Beginning of year */ + SETUP_PAT_STATUS(ctmp, stat_boy_var, def->patgrp->stat_boy, + _("HELP FOR BEGINNING OF YEAR"), h_config_role_boy); + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + /* From in Addrbook */ + new_confline(&ctmp); + ctmp->var = &abook_type_var; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = NULL; + snprintf(tmp, sizeof(tmp), "%s =", abook_type_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmpb = ctmp; + ctmp->flags |= (CF_NOSELECT | CF_STARTITEM); + + new_confline(&ctmp); + ctmp->var = NULL; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = NULL; + ctmp->varnamep = ctmpb; + ctmp->flags |= CF_NOSELECT; + ctmp->value = cpystr("Set Choose One"); + + new_confline(&ctmp); + ctmp->var = NULL; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = radio_tool; + ctmp->varnamep = ctmpb; + ctmp->flags |= CF_NOSELECT; + ctmp->value = cpystr(set_choose); \ + + /* find longest value's name */ + for(lv = 0, i = 0; (f = inabook_fldr_types(i)); i++) + if(lv < (j = utf8_width(f->name))) + lv = j; + + lv = MIN(lv, 100); + + fval = -1; + for(i = 0; (f = inabook_fldr_types(i)); i++){ + new_confline(&ctmp); + ctmp->help_title= _("HELP FOR ADDRESS IN ADDRESS BOOK"); + ctmp->var = &abook_type_var; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = h_config_role_abookfrom; + ctmp->varmem = i; + ctmp->tool = radio_tool; + ctmp->varnamep = ctmpb; + + if((PVAL(&abook_type_var, ew) && + !strucmp(PVAL(&abook_type_var, ew), f->name)) + || (!PVAL(&abook_type_var, ew) && f->value == IAB_DEFL)) + fval = f->value; + + utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", + (fval == f->value) ? R_SELD : ' ', + lv, lv, f->name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->value = cpystr(tmp); + } + + /* Specific list of abooks */ + /* 5 is the width of `(*) ' */ + setup_role_pat_alt(ps, &ctmp, &abook_pat_var, h_config_role_abookfrom, + _("HELP FOR ABOOK LIST"), + &config_role_afrom_keymenu, role_text_tool_afrom, rindent+5, + !(fval == IAB_SPEC_YES || fval == IAB_SPEC_NO)); + + /* Which addresses to check for */ + inabook_type_var.name = cpystr(_("Types of addresses to check for in address book")); + inabook_type_var.is_used = 1; + inabook_type_var.is_user = 1; + inabook_type_var.is_list = 1; + clrbitmap(inabook_type_list); + if(def && def->patgrp && def->patgrp->inabook & IAB_FROM) + setbitn(INABOOK_FROM, inabook_type_list); + if(def && def->patgrp && def->patgrp->inabook & IAB_REPLYTO) + setbitn(INABOOK_REPLYTO, inabook_type_list); + if(def && def->patgrp && def->patgrp->inabook & IAB_SENDER) + setbitn(INABOOK_SENDER, inabook_type_list); + if(def && def->patgrp && def->patgrp->inabook & IAB_TO) + setbitn(INABOOK_TO, inabook_type_list); + if(def && def->patgrp && def->patgrp->inabook & IAB_CC) + setbitn(INABOOK_CC, inabook_type_list); + + /* default setting */ + if(!(bitnset(INABOOK_FROM, inabook_type_list) + || bitnset(INABOOK_REPLYTO, inabook_type_list) + || bitnset(INABOOK_SENDER, inabook_type_list) + || bitnset(INABOOK_TO, inabook_type_list) + || bitnset(INABOOK_CC, inabook_type_list))){ + setbitn(INABOOK_FROM, inabook_type_list); + setbitn(INABOOK_REPLYTO, inabook_type_list); + } + + new_confline(&ctmp); + ctmp->var = &inabook_type_var; + ctmp->varoffset = 4; + ctmp->valoffset = 23; + ctmp->keymenu = &config_checkbox_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = NULL; + snprintf(tmp, sizeof(tmp), "%-20s =", inabook_type_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmpb = ctmp; + ctmp->flags |= (CF_NOSELECT | CF_STARTITEM); + + new_confline(&ctmp); + ctmp->var = NULL; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_checkbox_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = inabook_checkbox_tool; + ctmp->varnamep = ctmpb; + ctmp->flags |= CF_NOSELECT; + ctmp->value = cpystr("Set Address types"); + + new_confline(&ctmp); + ctmp->var = NULL; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_checkbox_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = inabook_checkbox_tool; + ctmp->varnamep = ctmpb; + ctmp->flags |= CF_NOSELECT; + ctmp->value = cpystr(set_choose); + + /* find longest value's name */ + for(lv = 0, i = 0; (f = inabook_feature_list(i)); i++){ + if(lv < (j = utf8_width(f->name))) + lv = j; + } + + lv = MIN(lv, 100); + + for(i = 0; (f = inabook_feature_list(i)); i++){ + new_confline(&ctmp); + ctmp->var = &opt_var; + ctmp->help_title= _("HELP FOR ADDRESS TYPES"); + ctmp->varnamep = ctmpb; + ctmp->keymenu = &config_checkbox_keymenu; + switch(i){ + case INABOOK_FROM: + ctmp->help = h_config_inabook_from; + break; + case INABOOK_REPLYTO: + ctmp->help = h_config_inabook_replyto; + break; + case INABOOK_SENDER: + ctmp->help = h_config_inabook_sender; + break; + case INABOOK_TO: + ctmp->help = h_config_inabook_to; + break; + case INABOOK_CC: + ctmp->help = h_config_inabook_cc; + break; + } + + ctmp->tool = inabook_checkbox_tool; + ctmp->valoffset = rindent; + ctmp->varmem = i; + utf8_snprintf(tmp, sizeof(tmp), "[%c] %-*.*w", + bitnset(f->value, inabook_type_list) ? 'X' : ' ', + lv, lv, f->name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->value = cpystr(tmp); + } + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + /* 4 is indent of "Command", c_v_n is longest of these three, 3 is ` = ' */ + i = 4 + utf8_width(c_v_n) + 3; + + /* External Command Categorizer */ + new_confline(&ctmp); + ctmp->var = &cat_cmd_var; + ctmp->keymenu = &config_text_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = NULL; + snprintf(tmp, sizeof(tmp), "%s =", cat_cmd_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmpb = ctmp; + ctmp->flags |= (CF_NOSELECT | CF_STARTITEM); + + /* Commands */ + new_confline(&ctmp); + ctmp->help_title= _("HELP FOR CATEGORIZER COMMAND"); + ctmp->var = &cat_cmd_var; + ctmp->varoffset = 4; + ctmp->valoffset = i; + ctmp->keymenu = &config_text_wshuf_keymenu; + ctmp->help = h_config_role_cat_cmd; + ctmp->tool = t_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", i-4-3, i-4-3, "Command"); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmpb = ctmp; + ctmp->flags = CF_STARTITEM; + + if((lval = LVAL(&cat_cmd_var, ew)) != NULL && lval[0]){ + for(j = 0; lval[j]; j++){ + if(j) + (void) new_confline(&ctmp); + + ctmp->var = &cat_cmd_var; + ctmp->varmem = j; + ctmp->valoffset = i; + ctmp->keymenu = &config_text_wshuf_keymenu; + ctmp->help = h_config_role_cat_cmd; + ctmp->tool = t_tool; + ctmp->varnamep = ctmp; + ctmp->value = pretty_value(ps, ctmp); + } + } + else + ctmp->value = pretty_value(ps, ctmp); + + /* Exit status interval */ + new_confline(&ctmp); + ctmp->help_title= _("HELP FOR CATEGORIZER EXIT STATUS"); + ctmp->var = &cati_var; + ctmp->varoffset = 4; + ctmp->valoffset = i; + ctmp->keymenu = &config_text_keymenu; + ctmp->help = h_config_role_cat_status; + ctmp->tool = t_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", i-4-3, i-4-3, cati_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmp; + ctmp->value = pretty_value(ps, ctmp); + + /* Character Limit */ + new_confline(&ctmp); + ctmp->help_title= _("HELP FOR CHARACTER LIMIT"); + ctmp->var = &cat_lim_var; + ctmp->varoffset = 4; + ctmp->valoffset = i; + ctmp->keymenu = &config_text_keymenu; + ctmp->help = h_config_role_cat_limit; + ctmp->tool = t_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", i-4-3, i-4-3, cat_lim_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmp; + ctmp->value = pretty_value(ps, ctmp); + ctmp->flags |= CF_NUMBER; + } + + if(!edit_srch){ /* sorry about that indent */ + /* Actions */ + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT; + if(ps->ttyo->screen_cols >= (wid=utf8_width(astr)) + 4){ + int dashes; + + dashes = (ps->ttyo->screen_cols - wid)/2; + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='), + astr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '=')); + ctmp->value = cpystr(tmp_20k_buf); + } + else + ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '=')); + + if(edit_role){ + int roindent; + + roindent = utf8_width(u_s_s); /* the longest one */ + roindent += 3; /* width of ` = ' */ + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + /* Inherit Nickname */ + new_confline(&ctmp); + inick_confs[INICK_INICK_CONF] = ctmp; + ctmp->help_title= _("HELP FOR INITIAL SET NICKNAME"); + ctmp->var = &inick_var; + ctmp->keymenu = &config_role_inick_keymenu; + ctmp->help = h_config_role_inick; + ctmp->tool = role_text_tool_inick; + snprintf(tmp, sizeof(tmp), "%s :", inick_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->valoffset = utf8_width(tmp)+1; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmp; + + /* From Action */ + new_confline(&ctmp); + inick_confs[INICK_FROM_CONF] = ctmp; + ctmp->help_title= _("HELP FOR SET FROM ACTION"); + ctmp->var = &from_act_var; + ctmp->valoffset = roindent; + ctmp->keymenu = &config_role_addr_act_keymenu; + ctmp->help = h_config_role_setfrom; + ctmp->tool = role_text_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, from_act_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmp; + + /* Reply-To Action */ + new_confline(&ctmp); + inick_confs[INICK_REPLYTO_CONF] = ctmp; + ctmp->help_title= _("HELP FOR SET REPLY-TO ACTION"); + ctmp->var = &replyto_act_var; + ctmp->valoffset = roindent; + ctmp->keymenu = &config_role_addr_act_keymenu; + ctmp->help = h_config_role_setreplyto; + ctmp->tool = role_text_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, replyto_act_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmp; + + /* Fcc Action */ + new_confline(&ctmp); + inick_confs[INICK_FCC_CONF] = ctmp; + ctmp->help_title= _("HELP FOR SET FCC ACTION"); + ctmp->var = &fcc_act_var; + ctmp->valoffset = roindent; + ctmp->keymenu = &config_role_actionfolder_keymenu; + ctmp->help = h_config_role_setfcc; + ctmp->tool = role_text_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, fcc_act_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmp; + + /* LitSig Action */ + new_confline(&ctmp); + inick_confs[INICK_LITSIG_CONF] = ctmp; + ctmp->help_title= _("HELP FOR SET LITERAL SIGNATURE ACTION"); + ctmp->var = &litsig_act_var; + ctmp->valoffset = roindent; + ctmp->keymenu = &config_text_keymenu; + ctmp->help = h_config_role_setlitsig; + ctmp->tool = role_litsig_text_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, litsig_act_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmp; + + /* Sig Action */ + new_confline(&ctmp); + inick_confs[INICK_SIG_CONF] = ctmp; + ctmp->help_title= _("HELP FOR SET SIGNATURE ACTION"); + ctmp->var = &sig_act_var; + ctmp->valoffset = roindent; + if(F_ON(F_DISABLE_ROLES_SIGEDIT, ps_global)) + ctmp->keymenu = &config_role_file_res_keymenu; + else + ctmp->keymenu = &config_role_file_keymenu; + + ctmp->help = h_config_role_setsig; + ctmp->tool = role_text_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, sig_act_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmp; + + /* Template Action */ + new_confline(&ctmp); + inick_confs[INICK_TEMPL_CONF] = ctmp; + ctmp->help_title= _("HELP FOR SET TEMPLATE ACTION"); + ctmp->var = &templ_act_var; + ctmp->valoffset = roindent; + if(F_ON(F_DISABLE_ROLES_TEMPLEDIT, ps_global)) + ctmp->keymenu = &config_role_file_res_keymenu; + else + ctmp->keymenu = &config_role_file_keymenu; + + ctmp->help = h_config_role_settempl; + ctmp->tool = role_text_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, templ_act_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmp; + + /* Other Headers Action */ + new_confline(&ctmp); + inick_confs[INICK_CSTM_CONF] = ctmp; + ctmp->help_title= _("HELP FOR SET OTHER HEADERS ACTION"); + ctmp->var = &cstm_act_var; + ctmp->valoffset = roindent; + ctmp->keymenu = &config_text_wshuf_keymenu; + ctmp->help = h_config_role_setotherhdr; + ctmp->tool = role_cstm_text_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, cstm_act_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmpb = ctmp; + ctmp->flags = CF_STARTITEM; + + if((lval = LVAL(&cstm_act_var, ew)) != NULL){ + for(i = 0; lval[i]; i++){ + if(i) + (void)new_confline(&ctmp); + + ctmp->var = &cstm_act_var; + ctmp->varmem = i; + ctmp->valoffset = roindent; + ctmp->keymenu = &config_text_wshuf_keymenu; + ctmp->help = h_config_role_setotherhdr; + ctmp->tool = role_cstm_text_tool; + ctmp->varnamep = ctmpb; + } + } + else + ctmp->varmem = 0; + + /* SMTP Server Action */ + new_confline(&ctmp); + inick_confs[INICK_SMTP_CONF] = ctmp; + ctmp->help_title= _("HELP FOR SMTP SERVER ACTION"); + ctmp->var = &smtp_act_var; + ctmp->valoffset = roindent; + ctmp->keymenu = &config_text_wshuf_keymenu; + ctmp->help = h_config_role_usesmtp; + ctmp->tool = t_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, smtp_act_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmpb = ctmp; + ctmp->flags = CF_STARTITEM; + + if((lval = LVAL(&smtp_act_var, ew)) != NULL){ + for(i = 0; lval[i]; i++){ + if(i) + (void)new_confline(&ctmp); + + ctmp->var = &smtp_act_var; + ctmp->varmem = i; + ctmp->valoffset = roindent; + ctmp->keymenu = &config_text_wshuf_keymenu; + ctmp->help = h_config_role_usesmtp; + ctmp->tool = t_tool; + ctmp->varnamep = ctmpb; + } + } + else + ctmp->varmem = 0; + + /* NNTP Server Action */ + new_confline(&ctmp); + inick_confs[INICK_NNTP_CONF] = ctmp; + ctmp->help_title= _("HELP FOR NNTP SERVER ACTION"); + ctmp->var = &nntp_act_var; + ctmp->valoffset = roindent; + ctmp->keymenu = &config_text_wshuf_keymenu; + ctmp->help = h_config_role_usenntp; + ctmp->tool = t_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, nntp_act_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmpb = ctmp; + ctmp->flags = CF_STARTITEM; + + if((lval = LVAL(&nntp_act_var, ew)) != NULL){ + for(i = 0; lval[i]; i++){ + if(i) + (void)new_confline(&ctmp); + + ctmp->var = &nntp_act_var; + ctmp->varmem = i; + ctmp->valoffset = roindent; + ctmp->keymenu = &config_text_wshuf_keymenu; + ctmp->help = h_config_role_usenntp; + ctmp->tool = t_tool; + ctmp->varnamep = ctmpb; + } + } + else + ctmp->varmem = 0; + + calculate_inick_stuff(ps); + } + else + inick_confs[INICK_INICK_CONF] = NULL; + + if(edit_score){ + int sindent; + + sindent = MAX(utf8_width(score_act_var.name),utf8_width(hdrtok_act_var.name)) + 3; + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + /* Score Value -- This doesn't inherit from inick */ + new_confline(&ctmp); + ctmp->help_title= _("HELP FOR SCORE VALUE ACTION"); + ctmp->var = &score_act_var; + ctmp->valoffset = sindent; + ctmp->keymenu = &config_text_keymenu; + ctmp->help = h_config_role_scoreval; + ctmp->tool = text_tool; + ctmp->flags |= CF_NUMBER; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", sindent-3, sindent-3, score_act_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmp; + ctmp->value = pretty_value(ps, ctmp); + + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT; + ctmp->value = cpystr(" OR"); + + /* Score From Header */ + new_confline(&ctmp); + ctmp->help_title= _("HELP FOR SCORE VALUE FROM HEADER ACTION"); + ctmp->var = &hdrtok_act_var; + ctmp->valoffset = sindent; + ctmp->keymenu = &config_text_keymenu; + ctmp->help = h_config_role_scorehdrtok; + ctmp->tool = text_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", sindent-3, sindent-3, hdrtok_act_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmp; + ctmp->value = pretty_value(ps, ctmp); + } + + if(edit_filter){ + /* + * Filtering got added in stages, so instead of simply having a + * variable in action which is set to one of the three possible + * values (FILTER_KILL, FILTER_STATE, FILTER_FOLDER) we infer + * the value from other variables. (Perhaps it would still make + * sense to change this.) + * Action->kill is set iff the user checks Delete. + * If the user checks the box that says Just Set State, then kill + * is not set and action->folder is not set (and vice versa). + * And finally, FILTER_FOLDER is set if !kill and action->folder is set. + * (And it is set here as the default if there is no default + * action and the user is required to fill in the Folder.) + */ + if(def && def->action && def->action->kill) + fval = FILTER_KILL; + else if(def && def->action && !def->action->kill && + !def->action->folder) + fval = FILTER_STATE; + else + fval = FILTER_FOLDER; + + role_filt_ptr = &filter_type_var; /* so radiobuttons can tell */ + filter_type_var.name = cpystr(_("Filter Action")); + filter_type_var.is_used = 1; + filter_type_var.is_user = 1; + apval = APVAL(&filter_type_var, ew); + *apval = (f=filter_types(fval)) ? cpystr(f->name) : NULL; + set_current_val(&filter_type_var, FALSE, FALSE); + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + /* Filter Type */ + new_confline(&ctmp); + ctmp->var = &filter_type_var; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = NULL; + snprintf(tmp, sizeof(tmp), "%s =", filter_type_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmpb = ctmp; + ctmp->flags |= (CF_NOSELECT | CF_STARTITEM); + + new_confline(&ctmp); + ctmp->var = NULL; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = NULL; + ctmp->varnamep = ctmpb; + ctmp->flags |= CF_NOSELECT; + ctmp->value = cpystr("Set Choose One"); + + new_confline(&ctmp); + ctmp->var = NULL; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = radio_tool; + ctmp->varnamep = ctmpb; + ctmp->flags |= CF_NOSELECT; + ctmp->value = cpystr(set_choose); \ + + /* find longest value's name */ + for(lv = 0, i = 0; (f = filter_types(i)); i++) + if(lv < (j = utf8_width(f->name))) + lv = j; + + lv = MIN(lv, 100); + + for(i = 0; (f = filter_types(i)); i++){ + new_confline(&ctmp); + ctmp->help_title= _("HELP FOR FILTER ACTION"); + ctmp->var = &filter_type_var; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = h_config_filt_rule_type; + ctmp->varmem = i; + ctmp->tool = radio_tool; + ctmp->varnamep = ctmpb; + utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", (f->value == fval) ? R_SELD : ' ', + lv, lv, f->name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->value = cpystr(tmp); + } + + /* Specific list of folders to copy to */ + setup_dummy_pattern_var(&folder_act_var, _("Folder List"), + (def && def->action) + ? def->action->folder : NULL); + + /* 5 is the width of `(*) ' */ + setup_role_pat_alt(ps, &ctmp, &folder_act_var, h_config_filter_folder, + _("HELP FOR FILTER FOLDER NAME"), + &config_role_actionfolder_keymenu, t_tool, rindent+5, + !(fval == FILTER_FOLDER)); + + SETUP_MSG_STATE(ctmp, filt_imp_var, ival, + _("HELP FOR SET IMPORTANT STATUS"), h_config_filt_stat_imp); + SETUP_MSG_STATE(ctmp, filt_new_var, nval, + _("HELP FOR SET NEW STATUS"), h_config_filt_stat_new); + SETUP_MSG_STATE(ctmp, filt_del_var, dval, + _("HELP FOR SET DELETED STATUS"), h_config_filt_stat_del); + SETUP_MSG_STATE(ctmp, filt_ans_var, aval, + _("HELP FOR SET ANSWERED STATUS"), h_config_filt_stat_ans); + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + /* Keywords to be Set */ + setup_dummy_pattern_var(&keyword_set_var, _("Set These Keywords"), + (def && def->action) + ? def->action->keyword_set : NULL); + setup_role_pat(ps, &ctmp, &keyword_set_var, h_config_filter_kw_set, + _("HELP FOR KEYWORDS TO BE SET"), + &config_role_keyword_keymenu, role_text_tool_kword, + NULL, 23); + + /* Keywords to be Cleared */ + setup_dummy_pattern_var(&keyword_clr_var, _("Clear These Keywords"), + (def && def->action) + ? def->action->keyword_clr : NULL); + setup_role_pat(ps, &ctmp, &keyword_clr_var, h_config_filter_kw_clr, + _("HELP FOR KEYWORDS TO BE CLEARED"), + &config_role_keyword_keymenu, role_text_tool_kword, + NULL, 23); + } + + if(edit_other){ + char *pval; + int oindent; + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + new_confline(&ctmp)->var = NULL; + snprintf(tmp, sizeof(tmp), "%s =", sort_act_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmpb = ctmp; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = role_sort_tool; + ctmp->valoffset = rindent; + ctmp->flags |= CF_NOSELECT; + + new_confline(&ctmp)->var = NULL; + ctmp->varnamep = ctmpb; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = role_sort_tool; + ctmp->valoffset = rindent; + ctmp->flags |= CF_NOSELECT; + ctmp->value = cpystr("Set Sort Options"); + + new_confline(&ctmp)->var = NULL; + ctmp->varnamep = ctmpb; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + 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; + ctmp->varnamep = ctmpb; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = h_config_perfolder_sort; + 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++){ + new_confline(&ctmp)->var = &sort_act_var; + ctmp->varnamep = ctmpb; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = h_config_perfolder_sort; + ctmp->tool = role_sort_tool; + ctmp->valoffset = rindent; + ctmp->varmem = i + (j * EndofList); + ctmp->value = generalized_sort_pretty_value(ps, ctmp, + 0); + } + } + + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + oindent = utf8_width(iform_act_var.name) + 3; + + /* Index Format Action */ + new_confline(&ctmp); + ctmp->help_title= _("HELP FOR SET INDEX FORMAT ACTION"); + ctmp->var = &iform_act_var; + ctmp->valoffset = oindent; + ctmp->keymenu = &config_text_keymenu; + ctmp->help = h_config_set_index_format; + ctmp->tool = text_tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", oindent-3, oindent-3, iform_act_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmp; + ctmp->value = pretty_value(ps, ctmp); + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + new_confline(&ctmp); + ctmp->flags |= CF_STARTITEM; + utf8_snprintf(tmp, sizeof(tmp), "%s =", startup_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + standard_radio_setup(ps, &ctmp, &startup_var, NULL); + } + + if(edit_incol && pico_usingcolor()){ + char *pval0, *pval1; + int def; + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + new_confline(&ctmp); + ctmp->var = &rolecolor_vars[0]; /* foreground */ + ctmp->varname = cpystr(_("Index Line Color =")); + ctmp->varnamep = ctmpb = ctmp; + ctmp->flags |= (CF_STARTITEM | CF_NOSELECT); + ctmp->keymenu = &role_color_setting_keymenu; + + pval0 = PVAL(&rolecolor_vars[0], ew); + pval1 = PVAL(&rolecolor_vars[1], ew); + if(pval0 && pval1) + def = !(pval0[0] && pval1[1]); + else + def = 1; + + add_color_setting_disp(ps, &ctmp, &rolecolor_vars[0], ctmpb, + &role_color_setting_keymenu, + &config_checkbox_keymenu, + h_config_incol, + rindent, 0, + def ? ps->VAR_NORM_FORE_COLOR + : PVAL(&rolecolor_vars[0], ew), + def ? ps->VAR_NORM_BACK_COLOR + : PVAL(&rolecolor_vars[1], ew), + def); + } + } + + if(need_options){ + /* Options */ + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT; + if(ps->ttyo->screen_cols >= (wid=utf8_width(ostr)) + 4){ + int dashes; + + dashes = (ps->ttyo->screen_cols - wid)/2; + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='), + ostr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '=')); + ctmp->value = cpystr(tmp_20k_buf); + } + else + ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '=')); + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + opt_var.name = cpystr(_("Features")); + opt_var.is_used = 1; + opt_var.is_user = 1; + opt_var.is_list = 1; + clrbitmap(feat_option_list); + if(def && def->patgrp && def->patgrp->age_uses_sentdate) + setbitn(FEAT_SENTDATE, feat_option_list); + + if(edit_filter){ + if(def && def->action && def->action->move_only_if_not_deleted) + setbitn(FEAT_IFNOTDEL, feat_option_list); + if(def && def->action && def->action->non_terminating) + setbitn(FEAT_NONTERM, feat_option_list); + } + + /* Options */ + new_confline(&ctmp); + ctmp->var = &opt_var; + ctmp->valoffset = 23; + ctmp->keymenu = &config_checkbox_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = NULL; + snprintf(tmp, sizeof(tmp), "%-20s =", opt_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmpb = ctmp; + ctmp->flags |= (CF_NOSELECT | CF_STARTITEM); + + new_confline(&ctmp); + ctmp->var = NULL; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_checkbox_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = feat_checkbox_tool; + ctmp->varnamep = ctmpb; + ctmp->flags |= CF_NOSELECT; + ctmp->value = cpystr("Set Feature Name"); + + new_confline(&ctmp); + ctmp->var = NULL; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_checkbox_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = feat_checkbox_tool; + ctmp->varnamep = ctmpb; + ctmp->flags |= CF_NOSELECT; + ctmp->value = cpystr(set_choose); \ + + /* find longest value's name */ + for(lv = 0, i = 0; (f = feat_feature_list(i)); i++){ + if(!edit_filter && (i == FEAT_IFNOTDEL || i == FEAT_NONTERM)) + continue; + + if(lv < (j = utf8_width(f->name))) + lv = j; + } + + lv = MIN(lv, 100); + + for(i = 0; (f = feat_feature_list(i)); i++){ + if(!edit_filter && (i == FEAT_IFNOTDEL || i == FEAT_NONTERM)) + continue; + + new_confline(&ctmp); + ctmp->var = &opt_var; + ctmp->help_title= _("HELP FOR FILTER FEATURES"); + ctmp->varnamep = ctmpb; + ctmp->keymenu = &config_checkbox_keymenu; + switch(i){ + case FEAT_SENTDATE: + ctmp->help = h_config_filt_opts_sentdate; + break; + case FEAT_IFNOTDEL: + ctmp->help = h_config_filt_opts_notdel; + break; + case FEAT_NONTERM: + ctmp->help = h_config_filt_opts_nonterm; + break; + } + + ctmp->tool = feat_checkbox_tool; + ctmp->valoffset = rindent; + ctmp->varmem = i; + utf8_snprintf(tmp, sizeof(tmp), "[%c] %-*.*w", + bitnset(f->value, feat_option_list) ? 'X' : ' ', + lv, lv, f->name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->value = cpystr(tmp); + } + } + + if(need_uses){ + /* Uses */ + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT; + if(ps->ttyo->screen_cols >= (wid=utf8_width(ustr)) + 4){ + int dashes; + + dashes = (ps->ttyo->screen_cols - wid)/2; + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='), + ustr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '=')); + ctmp->value = cpystr(tmp_20k_buf); + } + else + ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '=')); + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + /* Reply Type */ + new_confline(&ctmp); + ctmp->var = &repl_type_var; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = NULL; + snprintf(tmp, sizeof(tmp), "%s =", repl_type_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmpb = ctmp; + ctmp->flags |= (CF_NOSELECT | CF_STARTITEM); + + new_confline(&ctmp); + ctmp->var = NULL; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = NULL; + ctmp->varnamep = ctmpb; + ctmp->flags |= CF_NOSELECT; + ctmp->value = cpystr("Set Choose One"); + + new_confline(&ctmp); + ctmp->var = NULL; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = radio_tool; + ctmp->varnamep = ctmpb; + ctmp->flags |= CF_NOSELECT; + ctmp->value = cpystr(set_choose); \ + + /* find longest value's name */ + for(lv = 0, i = 0; (f = role_repl_types(i)); i++) + if(lv < (j = utf8_width(f->name))) + lv = j; + + lv = MIN(lv, 100); + + for(i = 0; (f = role_repl_types(i)); i++){ + new_confline(&ctmp); + ctmp->help_title= _("HELP FOR ROLE REPLY USE"); + ctmp->var = &repl_type_var; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = h_config_role_replyuse; + ctmp->varmem = i; + ctmp->tool = radio_tool; + ctmp->varnamep = ctmpb; + utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", (((!(def && def->action) || + def->action->repl_type == -1) && + f->value == ROLE_REPL_DEFL) || + (def && def->action && + f->value == def->action->repl_type)) + ? R_SELD : ' ', + lv, lv, f->name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->value = cpystr(tmp); + } + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + /* Forward Type */ + new_confline(&ctmp); + ctmp->var = &forw_type_var; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = NULL; + snprintf(tmp, sizeof(tmp), "%s =", forw_type_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmpb = ctmp; + ctmp->flags |= (CF_NOSELECT | CF_STARTITEM); + + new_confline(&ctmp); + ctmp->var = NULL; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = NULL; + ctmp->varnamep = ctmpb; + ctmp->flags |= CF_NOSELECT; + ctmp->value = cpystr("Set Choose One"); + + new_confline(&ctmp); + ctmp->var = NULL; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = radio_tool; + ctmp->varnamep = ctmpb; + ctmp->flags |= CF_NOSELECT; + ctmp->value = cpystr(set_choose); \ + + /* find longest value's name */ + for(lv = 0, i = 0; (f = role_forw_types(i)); i++) + if(lv < (j = utf8_width(f->name))) + lv = j; + + lv = MIN(lv, 100); + + for(i = 0; (f = role_forw_types(i)); i++){ + new_confline(&ctmp); + ctmp->help_title= _("HELP FOR ROLE FORWARD USE"); + ctmp->var = &forw_type_var; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = h_config_role_forwarduse; + ctmp->varmem = i; + ctmp->tool = radio_tool; + ctmp->varnamep = ctmpb; + utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", (((!(def && def->action) || + def->action->forw_type == -1) && + f->value == ROLE_FORW_DEFL) || + (def && def->action && + f->value == def->action->forw_type)) + ? R_SELD : ' ', + lv, lv, f->name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->value = cpystr(tmp); + } + + /* Blank line */ + new_confline(&ctmp); + ctmp->flags |= CF_NOSELECT | CF_B_LINE; + + /* Compose Type */ + new_confline(&ctmp); + ctmp->var = &comp_type_var; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = NULL; + snprintf(tmp, sizeof(tmp), "%s =", comp_type_var.name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->varname = cpystr(tmp); + ctmp->varnamep = ctmpb = ctmp; + ctmp->flags |= (CF_NOSELECT | CF_STARTITEM); + + new_confline(&ctmp); + ctmp->var = NULL; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = NULL; + ctmp->varnamep = ctmpb; + ctmp->flags |= CF_NOSELECT; + ctmp->value = cpystr("Set Choose One"); + + new_confline(&ctmp); + ctmp->var = NULL; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = NO_HELP; + ctmp->tool = radio_tool; + ctmp->varnamep = ctmpb; + ctmp->flags |= CF_NOSELECT; + ctmp->value = cpystr(set_choose); \ + + /* find longest value's name */ + for(lv = 0, i = 0; (f = role_comp_types(i)); i++) + if(lv < (j = utf8_width(f->name))) + lv = j; + + lv = MIN(lv, 100); + + for(i = 0; (f = role_comp_types(i)); i++){ + new_confline(&ctmp); + ctmp->help_title= _("HELP FOR ROLE COMPOSE USE"); + ctmp->var = &comp_type_var; + ctmp->valoffset = rindent; + ctmp->keymenu = &config_radiobutton_keymenu; + ctmp->help = h_config_role_composeuse; + ctmp->varmem = i; + ctmp->tool = radio_tool; + ctmp->varnamep = ctmpb; + utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", (((!(def && def->action) || + def->action->comp_type == -1) && + f->value == ROLE_COMP_DEFL) || + (def && def->action && + f->value == def->action->comp_type)) + ? R_SELD : ' ', + lv, lv, f->name); + tmp[sizeof(tmp)-1] = '\0'; + ctmp->value = cpystr(tmp); + } + } + + memset(&screen, 0, sizeof(screen)); + screen.ro_warning = saved_screen ? saved_screen->deferred_ro_warning : 0; + /* TRANSLATORS: Print something1 using something2. + "roles" is something1 */ + rv = conf_scroll_screen(ps, &screen, first_line, title, _("roles"), + (edit_incol && pico_usingcolor()) ? 1 : 0); + + /* + * Now look at the fake variables and extract the information we + * want from them. + */ + + if(rv == 1 && result){ + /* + * We know these variables exist, so we don't have to check that + * apval is nonnull before evaluating *apval. + */ + apval = APVAL(&nick_var, ew); + nick = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(nick); + + apval = APVAL(&comment_var, ew); + comment = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(comment); + + alval = ALVAL(&to_pat_var, ew); + to_pat = *alval; + *alval = NULL; + + alval = ALVAL(&from_pat_var, ew); + from_pat = *alval; + *alval = NULL; + + alval = ALVAL(&sender_pat_var, ew); + sender_pat = *alval; + *alval = NULL; + + alval = ALVAL(&cc_pat_var, ew); + cc_pat = *alval; + *alval = NULL; + + alval = ALVAL(&recip_pat_var, ew); + recip_pat = *alval; + *alval = NULL; + + alval = ALVAL(&partic_pat_var, ew); + partic_pat = *alval; + *alval = NULL; + + alval = ALVAL(&news_pat_var, ew); + news_pat = *alval; + *alval = NULL; + + alval = ALVAL(&subj_pat_var, ew); + subj_pat = *alval; + *alval = NULL; + + alval = ALVAL(&alltext_pat_var, ew); + alltext_pat = *alval; + *alval = NULL; + + alval = ALVAL(&bodytext_pat_var, ew); + bodytext_pat = *alval; + *alval = NULL; + + alval = ALVAL(&keyword_pat_var, ew); + keyword_pat = *alval; + *alval = NULL; + + alval = ALVAL(&charset_pat_var, ew); + charset_pat = *alval; + *alval = NULL; + + apval = APVAL(&age_pat_var, ew); + age_pat = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(age_pat); + + apval = APVAL(&size_pat_var, ew); + size_pat = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(size_pat); + + apval = APVAL(&scorei_pat_var, ew); + scorei_pat = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(scorei_pat); + + apval = APVAL(&stat_del_var, ew); + stat_del = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(stat_del); + + apval = APVAL(&stat_new_var, ew); + stat_new = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(stat_new); + + apval = APVAL(&stat_rec_var, ew); + stat_rec = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(stat_rec); + + apval = APVAL(&stat_imp_var, ew); + stat_imp = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(stat_imp); + + apval = APVAL(&stat_ans_var, ew); + stat_ans = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(stat_ans); + + apval = APVAL(&stat_8bit_var, ew); + stat_8bit = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(stat_8bit); + + apval = APVAL(&stat_bom_var, ew); + stat_bom = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(stat_bom); + + apval = APVAL(&stat_boy_var, ew); + stat_boy = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(stat_boy); + + apval = APVAL(&fldr_type_var, ew); + fldr_type_pat = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(fldr_type_pat); + + alval = ALVAL(&folder_pat_var, ew); + folder_pat = *alval; + *alval = NULL; + + apval = APVAL(&abook_type_var, ew); + abook_type_pat = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(abook_type_pat); + + alval = ALVAL(&abook_pat_var, ew); + abook_pat = *alval; + *alval = NULL; + + apval = APVAL(&cati_var, ew); + cati = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(cati); + + apval = APVAL(&cat_lim_var, ew); + cat_lim = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(cat_lim); + + apval = APVAL(&inick_var, ew); + inick = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(inick); + + apval = APVAL(&from_act_var, ew); + from_act = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(from_act); + + apval = APVAL(&replyto_act_var, ew); + replyto_act = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(replyto_act); + + apval = APVAL(&fcc_act_var, ew); + fcc_act = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(fcc_act); + + apval = APVAL(&litsig_act_var, ew); + litsig_act = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(litsig_act); + + apval = APVAL(&sort_act_var, ew); + sort_act = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(sort_act); + + apval = APVAL(&iform_act_var, ew); + iform_act = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(iform_act); + + apval = APVAL(&startup_var, ew); + startup_act = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(startup_act); + + apval = APVAL(&sig_act_var, ew); + sig_act = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(sig_act); + + apval = APVAL(&templ_act_var, ew); + templ_act = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(templ_act); + + apval = APVAL(&score_act_var, ew); + score_act = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(score_act); + + apval = APVAL(&hdrtok_act_var, ew); + hdrtok_act = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(hdrtok_act); + + apval = APVAL(&repl_type_var, ew); + repl_type = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(repl_type); + + apval = APVAL(&forw_type_var, ew); + forw_type = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(forw_type); + + apval = APVAL(&comp_type_var, ew); + comp_type = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(comp_type); + + apval = APVAL(&rolecolor_vars[0], ew); + rc_fg = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(rc_fg); + + apval = APVAL(&rolecolor_vars[1], ew); + rc_bg = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(rc_bg); + + apval = APVAL(&filter_type_var, ew); + filter_type = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(filter_type); + + alval = ALVAL(&folder_act_var, ew); + folder_act = *alval; + *alval = NULL; + + alval = ALVAL(&keyword_set_var, ew); + keyword_set = *alval; + *alval = NULL; + + alval = ALVAL(&keyword_clr_var, ew); + keyword_clr = *alval; + *alval = NULL; + + apval = APVAL(&filt_imp_var, ew); + filt_imp = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(filt_imp); + + apval = APVAL(&filt_del_var, ew); + filt_del = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(filt_del); + + apval = APVAL(&filt_new_var, ew); + filt_new = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(filt_new); + + apval = APVAL(&filt_ans_var, ew); + filt_ans = *apval; + *apval = NULL; + removing_leading_and_trailing_white_space(filt_ans); + + + alval = ALVAL(&cat_cmd_var, ew); + cat_cmd = *alval; + *alval = NULL; + + alval = ALVAL(&cstm_act_var, ew); + cstm_act = *alval; + *alval = NULL; + + alval = ALVAL(&smtp_act_var, ew); + smtp_act = *alval; + *alval = NULL; + + alval = ALVAL(&nntp_act_var, ew); + nntp_act = *alval; + *alval = NULL; + + if(ps->VAR_OPER_DIR && sig_act && + is_absolute_path(sig_act) && + !in_dir(ps->VAR_OPER_DIR, sig_act)){ + q_status_message1(SM_ORDER | SM_DING, 3, 4, + _("Warning: Sig file can't be outside of %s"), + ps->VAR_OPER_DIR); + } + + if(ps->VAR_OPER_DIR && templ_act && + is_absolute_path(templ_act) && + !in_dir(ps->VAR_OPER_DIR, templ_act)){ + q_status_message1(SM_ORDER | SM_DING, 3, 4, + _("Warning: Template file can't be outside of %s"), + ps->VAR_OPER_DIR); + } + + if(ps->VAR_OPER_DIR && folder_act) + for(i = 0; folder_act[i]; i++){ + if(folder_act[i][0] && is_absolute_path(folder_act[i]) && + !in_dir(ps->VAR_OPER_DIR, folder_act[i])){ + q_status_message1(SM_ORDER | SM_DING, 3, 4, + _("Warning: Folder can't be outside of %s"), + ps->VAR_OPER_DIR); + } + } + + *result = (PAT_S *)fs_get(sizeof(**result)); + memset((void *)(*result), 0, sizeof(**result)); + + (*result)->patgrp = (PATGRP_S *)fs_get(sizeof(*(*result)->patgrp)); + memset((void *)(*result)->patgrp, 0, sizeof(*(*result)->patgrp)); + + (*result)->action = (ACTION_S *)fs_get(sizeof(*(*result)->action)); + memset((void *)(*result)->action, 0, sizeof(*(*result)->action)); + + (*result)->patline = def ? def->patline : NULL; + + if(nick && *nick){ + (*result)->patgrp->nick = nick; + nick = NULL; + } + else + (*result)->patgrp->nick = cpystr(nick_var.global_val.p); + + if(comment && *comment){ + (*result)->patgrp->comment = comment; + comment = NULL; + } + + (*result)->action->nick = cpystr((*result)->patgrp->nick); + + (*result)->action->is_a_role = edit_role ? 1 : 0; + (*result)->action->is_a_incol = edit_incol ? 1 : 0; + (*result)->action->is_a_score = edit_score ? 1 : 0; + (*result)->action->is_a_filter = edit_filter ? 1 : 0; + (*result)->action->is_a_other = edit_other ? 1 : 0; + (*result)->action->is_a_srch = edit_srch ? 1 : 0; + + (*result)->patgrp->to = editlist_to_pattern(to_pat); + if((*result)->patgrp->to && !strncmp(to_pat_var.name, NOT, NOTLEN)) + (*result)->patgrp->to->not = 1; + + (*result)->patgrp->from = editlist_to_pattern(from_pat); + if((*result)->patgrp->from && !strncmp(from_pat_var.name, NOT, NOTLEN)) + (*result)->patgrp->from->not = 1; + + (*result)->patgrp->sender = editlist_to_pattern(sender_pat); + if((*result)->patgrp->sender && + !strncmp(sender_pat_var.name, NOT, NOTLEN)) + (*result)->patgrp->sender->not = 1; + + (*result)->patgrp->cc = editlist_to_pattern(cc_pat); + if((*result)->patgrp->cc && !strncmp(cc_pat_var.name, NOT, NOTLEN)) + (*result)->patgrp->cc->not = 1; + + (*result)->patgrp->recip = editlist_to_pattern(recip_pat); + if((*result)->patgrp->recip && + !strncmp(recip_pat_var.name, NOT, NOTLEN)) + (*result)->patgrp->recip->not = 1; + + (*result)->patgrp->partic = editlist_to_pattern(partic_pat); + if((*result)->patgrp->partic && + !strncmp(partic_pat_var.name, NOT, NOTLEN)) + (*result)->patgrp->partic->not = 1; + + (*result)->patgrp->news = editlist_to_pattern(news_pat); + if((*result)->patgrp->news && !strncmp(news_pat_var.name, NOT, NOTLEN)) + (*result)->patgrp->news->not = 1; + + (*result)->patgrp->subj = editlist_to_pattern(subj_pat); + if((*result)->patgrp->subj && !strncmp(subj_pat_var.name, NOT, NOTLEN)) + (*result)->patgrp->subj->not = 1; + + (*result)->patgrp->alltext = editlist_to_pattern(alltext_pat); + if((*result)->patgrp->alltext && + !strncmp(alltext_pat_var.name, NOT, NOTLEN)) + (*result)->patgrp->alltext->not = 1; + + (*result)->patgrp->bodytext = editlist_to_pattern(bodytext_pat); + if((*result)->patgrp->bodytext && + !strncmp(bodytext_pat_var.name, NOT, NOTLEN)) + (*result)->patgrp->bodytext->not = 1; + + (*result)->patgrp->keyword = editlist_to_pattern(keyword_pat); + if((*result)->patgrp->keyword && + !strncmp(keyword_pat_var.name, NOT, NOTLEN)) + (*result)->patgrp->keyword->not = 1; + + (*result)->patgrp->charsets = editlist_to_pattern(charset_pat); + if((*result)->patgrp->charsets && + !strncmp(charset_pat_var.name, NOT, NOTLEN)) + (*result)->patgrp->charsets->not = 1; + + (*result)->patgrp->age_uses_sentdate = + bitnset(FEAT_SENTDATE, feat_option_list) ? 1 : 0; + + if(age_pat){ + if(((*result)->patgrp->age = parse_intvl(age_pat)) != NULL) + (*result)->patgrp->do_age = 1; + } + + if(size_pat){ + if(((*result)->patgrp->size = parse_intvl(size_pat)) != NULL) + (*result)->patgrp->do_size = 1; + } + + if(scorei_pat){ + if(((*result)->patgrp->score = parse_intvl(scorei_pat)) != NULL) + (*result)->patgrp->do_score = 1; + } + + (*result)->patgrp->cat_lim = -1L; /* default */ + if(cat_cmd){ + if(!cat_cmd[0]) + fs_give((void **) &cat_cmd); + + /* quick check for absolute paths */ + if(cat_cmd) + for(j = 0; cat_cmd[j]; j++) + if(!is_absolute_path(cat_cmd[j])) + q_status_message1(SM_ORDER | SM_DING, 3, 4, + _("Warning: command must be absolute path: \"%s\""), + cat_cmd[j]); + + (*result)->patgrp->category_cmd = cat_cmd; + cat_cmd = NULL; + + if(cati){ + if(((*result)->patgrp->cat = parse_intvl(cati)) != NULL) + (*result)->patgrp->do_cat = 1; + } + if(cat_lim && *cat_lim) + (*result)->patgrp->cat_lim = atol(cat_lim); + } + + if(stat_del && *stat_del){ + for(j = 0; (f = role_status_types(j)); j++) + if(!strucmp(stat_del, f->name)){ + (*result)->patgrp->stat_del = f->value; + break; + } + } + else + (*result)->patgrp->stat_del = PAT_STAT_EITHER; + + if(stat_new && *stat_new){ + for(j = 0; (f = role_status_types(j)); j++) + if(!strucmp(stat_new, f->name)){ + (*result)->patgrp->stat_new = f->value; + break; + } + } + else + (*result)->patgrp->stat_new = PAT_STAT_EITHER; + + if(stat_rec && *stat_rec){ + for(j = 0; (f = role_status_types(j)); j++) + if(!strucmp(stat_rec, f->name)){ + (*result)->patgrp->stat_rec = f->value; + break; + } + } + else + (*result)->patgrp->stat_rec = PAT_STAT_EITHER; + + if(stat_imp && *stat_imp){ + for(j = 0; (f = role_status_types(j)); j++) + if(!strucmp(stat_imp, f->name)){ + (*result)->patgrp->stat_imp = f->value; + break; + } + } + else + (*result)->patgrp->stat_imp = PAT_STAT_EITHER; + + if(stat_ans && *stat_ans){ + for(j = 0; (f = role_status_types(j)); j++) + if(!strucmp(stat_ans, f->name)){ + (*result)->patgrp->stat_ans = f->value; + break; + } + } + else + (*result)->patgrp->stat_ans = PAT_STAT_EITHER; + + if(stat_8bit && *stat_8bit){ + for(j = 0; (f = role_status_types(j)); j++) + if(!strucmp(stat_8bit, f->name)){ + (*result)->patgrp->stat_8bitsubj = f->value; + break; + } + } + else + (*result)->patgrp->stat_8bitsubj = PAT_STAT_EITHER; + + if(stat_bom && *stat_bom){ + for(j = 0; (f = role_status_types(j)); j++) + if(!strucmp(stat_bom, f->name)){ + (*result)->patgrp->stat_bom = f->value; + break; + } + } + else + (*result)->patgrp->stat_bom = PAT_STAT_EITHER; + + if(stat_boy && *stat_boy){ + for(j = 0; (f = role_status_types(j)); j++) + if(!strucmp(stat_boy, f->name)){ + (*result)->patgrp->stat_boy = f->value; + break; + } + } + else + (*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); + /* + * Don't try to re-sort until next open of folder. If user + * $-sorted then it probably shouldn't change anyway. Why + * bother keeping track of that? + */ + } + + (*result)->action->index_format = iform_act; + iform_act = NULL; + + if(startup_act && *startup_act){ + for(j = 0; (f = startup_rules(j)); j++) + if(!strucmp(startup_act, f->name)){ + (*result)->action->startup_rule = f->value; + break; + } + } + else + (*result)->action->startup_rule = IS_NOTSET; + + aa = NULL; + for(ea = earb; ea; ea = ea->next){ + char *xyz; + + if(aa){ + aa->next = (ARBHDR_S *)fs_get(sizeof(*aa)); + aa = aa->next; + } + else{ + (*result)->patgrp->arbhdr = + (ARBHDR_S *)fs_get(sizeof(ARBHDR_S)); + aa = (*result)->patgrp->arbhdr; + } + + memset(aa, 0, sizeof(*aa)); + + aa->field = cpystr((ea->a && ea->a->field) ? ea->a->field : ""); + + alval = ALVAL(ea->v, ew); + spat = *alval; + *alval = NULL; + aa->p = editlist_to_pattern(spat); + if(aa->p && ea->v && ea->v->name && + !strncmp(ea->v->name, NOT, NOTLEN)) + aa->p->not = 1; + + if((xyz = pattern_to_string(aa->p)) != NULL){ + if(!*xyz) + aa->isemptyval = 1; + + fs_give((void **)&xyz); + } + } + + if(fldr_type_pat && *fldr_type_pat){ + for(j = 0; (f = pat_fldr_types(j)); j++) + if(!strucmp(fldr_type_pat, f->name)){ + (*result)->patgrp->fldr_type = f->value; + break; + } + } + else{ + f = pat_fldr_types(FLDR_DEFL); + if(f) + (*result)->patgrp->fldr_type = f->value; + } + + (*result)->patgrp->folder = editlist_to_pattern(folder_pat); + + if(abook_type_pat && *abook_type_pat){ + for(j = 0; (f = inabook_fldr_types(j)); j++) + if(!strucmp(abook_type_pat, f->name)){ + (*result)->patgrp->inabook = f->value; + break; + } + + if(bitnset(INABOOK_FROM, inabook_type_list)) + (*result)->patgrp->inabook |= IAB_FROM; + if(bitnset(INABOOK_REPLYTO, inabook_type_list)) + (*result)->patgrp->inabook |= IAB_REPLYTO; + if(bitnset(INABOOK_SENDER, inabook_type_list)) + (*result)->patgrp->inabook |= IAB_SENDER; + if(bitnset(INABOOK_TO, inabook_type_list)) + (*result)->patgrp->inabook |= IAB_TO; + if(bitnset(INABOOK_CC, inabook_type_list)) + (*result)->patgrp->inabook |= IAB_CC; + + if(!((*result)->patgrp->inabook & IAB_TYPE_MASK)) + (*result)->patgrp->inabook |= (IAB_FROM | IAB_REPLYTO); + } + else{ + f = inabook_fldr_types(IAB_DEFL); + if(f) + (*result)->patgrp->inabook = f->value; + } + + (*result)->patgrp->abooks = editlist_to_pattern(abook_pat); + + + (*result)->action->inherit_nick = inick; + inick = NULL; + (*result)->action->fcc = fcc_act; + fcc_act = NULL; + (*result)->action->litsig = litsig_act; + litsig_act = NULL; + (*result)->action->sig = sig_act; + sig_act = NULL; + (*result)->action->template = templ_act; + templ_act = NULL; + + if(cstm_act){ + /* + * Check for From or Reply-To and eliminate them. + */ + for(i = 0; cstm_act[i]; i++){ + char *free_this; + + if((!struncmp(cstm_act[i],"from",4) && + (cstm_act[i][4] == ':' || + cstm_act[i][4] == '\0')) || + (!struncmp(cstm_act[i],"reply-to",8) && + (cstm_act[i][8] == ':' || + cstm_act[i][8] == '\0'))){ + free_this = cstm_act[i]; + /* slide the rest up */ + for(j = i; cstm_act[j]; j++) + cstm_act[j] = cstm_act[j+1]; + + fs_give((void **)&free_this); + i--; /* recheck now that we've slid them up */ + } + } + + /* nothing left */ + if(!cstm_act[0]) + fs_give((void **)&cstm_act); + + (*result)->action->cstm = cstm_act; + cstm_act = NULL; + } + + if(smtp_act){ + if(!smtp_act[0]) + fs_give((void **)&smtp_act); + + (*result)->action->smtp = smtp_act; + smtp_act = NULL; + } + + if(nntp_act){ + if(!nntp_act[0]) + fs_give((void **)&nntp_act); + + (*result)->action->nntp = nntp_act; + nntp_act = NULL; + } + + if(filter_type && *filter_type){ + (*result)->action->non_terminating = + bitnset(FEAT_NONTERM, feat_option_list) ? 1 : 0; + for(i = 0; (f = filter_types(i)); i++){ + if(!strucmp(filter_type, f->name)){ + if(f->value == FILTER_FOLDER){ + (*result)->action->folder = editlist_to_pattern(folder_act); + (*result)->action->move_only_if_not_deleted = + bitnset(FEAT_IFNOTDEL, feat_option_list) ? 1 : 0; + } + else if(f->value == FILTER_STATE){ + (*result)->action->kill = 0; + } + else if(f->value == FILTER_KILL){ + (*result)->action->kill = 1; + } + + /* + * This is indented an extra indent because we used to condition + * this on !kill. We changed it so that you can set state bits + * even if you're killing. This is marginally helpful if you + * have another client running that doesn't know about this + * filter, but you want to, for example, have the messages show + * up now as deleted instead of having that deferred until we + * exit. It is controlled by the user by setting the status + * action bits along with the Delete. + */ + if(filt_imp && *filt_imp){ + for(j = 0; (f = msg_state_types(j)); j++){ + if(!strucmp(filt_imp, f->name)){ + switch(f->value){ + case ACT_STAT_LEAVE: + break; + case ACT_STAT_SET: + (*result)->action->state_setting_bits |= F_FLAG; + break; + case ACT_STAT_CLEAR: + (*result)->action->state_setting_bits |= F_UNFLAG; + break; + } + break; + } + } + } + + if(filt_del && *filt_del){ + for(j = 0; (f = msg_state_types(j)); j++){ + if(!strucmp(filt_del, f->name)){ + switch(f->value){ + case ACT_STAT_LEAVE: + break; + case ACT_STAT_SET: + (*result)->action->state_setting_bits |= F_DEL; + break; + case ACT_STAT_CLEAR: + (*result)->action->state_setting_bits |= F_UNDEL; + break; + } + break; + } + } + } + + if(filt_ans && *filt_ans){ + for(j = 0; (f = msg_state_types(j)); j++){ + if(!strucmp(filt_ans, f->name)){ + switch(f->value){ + case ACT_STAT_LEAVE: + break; + case ACT_STAT_SET: + (*result)->action->state_setting_bits |= F_ANS; + break; + case ACT_STAT_CLEAR: + (*result)->action->state_setting_bits |= F_UNANS; + break; + } + break; + } + } + } + + if(filt_new && *filt_new){ + for(j = 0; (f = msg_state_types(j)); j++){ + if(!strucmp(filt_new, f->name)){ + switch(f->value){ + case ACT_STAT_LEAVE: + break; + case ACT_STAT_SET: + (*result)->action->state_setting_bits |= F_UNSEEN; + break; + case ACT_STAT_CLEAR: + (*result)->action->state_setting_bits |= F_SEEN; + break; + } + break; + } + } + } + + (*result)->action->keyword_set = + editlist_to_pattern(keyword_set); + (*result)->action->keyword_clr = + editlist_to_pattern(keyword_clr); + + break; + } + } + } + + if(from_act && *from_act) + rfc822_parse_adrlist(&(*result)->action->from, from_act, + ps->maildomain); + + if(replyto_act && *replyto_act) + rfc822_parse_adrlist(&(*result)->action->replyto, replyto_act, + ps->maildomain); + + if(score_act && (j = atoi(score_act)) >= SCORE_MIN && j <= SCORE_MAX) + (*result)->action->scoreval = (long) j; + + if(hdrtok_act) + (*result)->action->scorevalhdrtok = stringform_to_hdrtok(hdrtok_act); + + if(repl_type && *repl_type){ + for(j = 0; (f = role_repl_types(j)); j++) + if(!strucmp(repl_type, f->name)){ + (*result)->action->repl_type = f->value; + break; + } + } + else{ + f = role_repl_types(ROLE_REPL_DEFL); + if(f) + (*result)->action->repl_type = f->value; + } + + if(forw_type && *forw_type){ + for(j = 0; (f = role_forw_types(j)); j++) + if(!strucmp(forw_type, f->name)){ + (*result)->action->forw_type = f->value; + break; + } + } + else{ + f = role_forw_types(ROLE_FORW_DEFL); + if(f) + (*result)->action->forw_type = f->value; + } + + if(comp_type && *comp_type){ + for(j = 0; (f = role_comp_types(j)); j++) + if(!strucmp(comp_type, f->name)){ + (*result)->action->comp_type = f->value; + break; + } + } + else{ + f = role_comp_types(ROLE_COMP_DEFL); + if(f) + (*result)->action->comp_type = f->value; + } + + if(rc_fg && *rc_fg && rc_bg && *rc_bg){ + if(!old_fg || !old_bg || strucmp(old_fg, rc_fg) || + strucmp(old_bg, rc_bg)) + clear_index_cache(ps_global->mail_stream, 0); + + /* + * If same as normal color, don't set it. This may or may + * not surprise the user when they change the normal color. + * This color will track the normal color instead of staying + * the same as the old normal color, which is probably + * what they want. + */ + if(!ps_global->VAR_NORM_FORE_COLOR || + !ps_global->VAR_NORM_BACK_COLOR || + strucmp(ps_global->VAR_NORM_FORE_COLOR, rc_fg) || + strucmp(ps_global->VAR_NORM_BACK_COLOR, rc_bg)) + (*result)->action->incol = new_color_pair(rc_fg, rc_bg); + } + } + + for(j = 0; varlist[j]; j++){ + v = varlist[j]; + free_variable_values(v); + if(v->name) + fs_give((void **)&v->name); + } + + if(earb) + free_earb(&earb); + if(nick) + fs_give((void **)&nick); + if(comment) + fs_give((void **)&comment); + if(to_pat) + free_list_array(&to_pat); + if(from_pat) + free_list_array(&from_pat); + if(sender_pat) + free_list_array(&sender_pat); + if(cc_pat) + free_list_array(&cc_pat); + if(recip_pat) + free_list_array(&recip_pat); + if(partic_pat) + free_list_array(&partic_pat); + if(news_pat) + free_list_array(&news_pat); + if(subj_pat) + free_list_array(&subj_pat); + if(alltext_pat) + free_list_array(&alltext_pat); + if(bodytext_pat) + free_list_array(&bodytext_pat); + if(keyword_pat) + free_list_array(&keyword_pat); + if(charset_pat) + free_list_array(&charset_pat); + if(age_pat) + fs_give((void **)&age_pat); + if(size_pat) + fs_give((void **)&size_pat); + if(scorei_pat) + fs_give((void **)&scorei_pat); + if(cati) + fs_give((void **)&cati); + if(cat_lim) + fs_give((void **)&cat_lim); + if(stat_del) + fs_give((void **)&stat_del); + if(stat_new) + fs_give((void **)&stat_new); + if(stat_rec) + fs_give((void **)&stat_rec); + if(stat_imp) + fs_give((void **)&stat_imp); + if(stat_ans) + fs_give((void **)&stat_ans); + if(stat_8bit) + fs_give((void **)&stat_8bit); + if(stat_bom) + fs_give((void **)&stat_bom); + if(stat_boy) + fs_give((void **)&stat_boy); + if(fldr_type_pat) + fs_give((void **)&fldr_type_pat); + if(folder_pat) + free_list_array(&folder_pat); + if(abook_type_pat) + fs_give((void **)&abook_type_pat); + if(abook_pat) + free_list_array(&abook_pat); + if(inick) + fs_give((void **)&inick); + if(from_act) + fs_give((void **)&from_act); + if(replyto_act) + fs_give((void **)&replyto_act); + if(fcc_act) + fs_give((void **)&fcc_act); + if(litsig_act) + fs_give((void **)&litsig_act); + if(sort_act) + fs_give((void **)&sort_act); + if(iform_act) + fs_give((void **)&iform_act); + if(keyword_set) + free_list_array(&keyword_set); + if(keyword_clr) + free_list_array(&keyword_clr); + if(startup_act) + fs_give((void **)&startup_act); + if(sig_act) + fs_give((void **)&sig_act); + if(templ_act) + fs_give((void **)&templ_act); + if(score_act) + fs_give((void **)&score_act); + if(hdrtok_act) + fs_give((void **)&hdrtok_act); + if(repl_type) + fs_give((void **)&repl_type); + if(forw_type) + fs_give((void **)&forw_type); + if(comp_type) + fs_give((void **)&comp_type); + if(rc_fg) + fs_give((void **)&rc_fg); + if(rc_bg) + fs_give((void **)&rc_bg); + if(old_fg) + fs_give((void **)&old_fg); + if(old_bg) + fs_give((void **)&old_bg); + if(filt_del) + fs_give((void **)&filt_del); + if(filt_new) + fs_give((void **)&filt_new); + if(filt_ans) + fs_give((void **)&filt_ans); + if(filt_imp) + fs_give((void **)&filt_imp); + if(folder_act) + free_list_array(&folder_act); + if(filter_type) + fs_give((void **)&filter_type); + + if(cat_cmd) + free_list_array(&cat_cmd); + + if(cstm_act) + free_list_array(&cstm_act); + + if(smtp_act) + free_list_array(&smtp_act); + + if(nntp_act) + free_list_array(&nntp_act); + + opt_screen = saved_screen; + ps->mangled_screen = 1; + return(rv); +} + + +void +setup_dummy_pattern_var(struct variable *v, char *name, PATTERN_S *defpat) +{ + char ***alval; + + if(!(v && name)) + panic("setup_dummy_pattern_var"); + + v->name = (char *) fs_get(strlen(name)+NOTLEN+1); + snprintf(v->name, strlen(name)+NOTLEN+1, "%s%s", (defpat && defpat->not) ? NOT : "", name); + v->name[ strlen(name)+NOTLEN+1-1] = '\0'; + v->is_used = 1; + v->is_user = 1; + v->is_list = 1; + alval = ALVAL(v, ew); + *alval = pattern_to_editlist(defpat); + set_current_val(v, FALSE, FALSE); +} + + +void +setup_role_pat(struct pine *ps, CONF_S **ctmp, struct variable *v, HelpType help, + char *help_title, struct key_menu *keymenu, + int (*tool)(struct pine *, int, CONF_S **, unsigned), + EARB_S **earb, int indent) +{ + char tmp[MAXPATH+1]; + char **lval; + int i; + CONF_S *ctmpb; + + new_confline(ctmp); + (*ctmp)->help_title = help_title; + (*ctmp)->var = v; + (*ctmp)->valoffset = indent; + (*ctmp)->keymenu = keymenu; + (*ctmp)->help = help; + (*ctmp)->tool = tool; + utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", indent-3, indent-3, (v && v->name) ? v->name : ""); + tmp[sizeof(tmp)-1] = '\0'; + (*ctmp)->varname = cpystr(tmp); + (*ctmp)->varnamep = *ctmp; + (*ctmp)->value = pretty_value(ps, *ctmp); + (*ctmp)->d.earb = earb; + (*ctmp)->varmem = 0; + (*ctmp)->flags = CF_STARTITEM; + + ctmpb = (*ctmp); + + lval = LVAL(v, ew); + if(lval){ + for(i = 0; lval[i]; i++){ + if(i) + new_confline(ctmp); + + (*ctmp)->var = v; + (*ctmp)->varmem = i; + (*ctmp)->valoffset = indent; + (*ctmp)->value = pretty_value(ps, *ctmp); + (*ctmp)->d.earb = earb; + (*ctmp)->keymenu = keymenu; + (*ctmp)->help = help; + (*ctmp)->tool = tool; + (*ctmp)->varnamep = ctmpb; + } + } +} + + +/* + * Watch out for polarity of nosel flag. Setting it means to turn on + * the NOSELECT flag, which means to make that line unselectable. + */ +void +setup_role_pat_alt(struct pine *ps, CONF_S **ctmp, struct variable *v, HelpType help, + char *help_title, struct key_menu *keymenu, + int (*tool)(struct pine *, int, CONF_S **, unsigned), + int voff, int nosel) +{ + char tmp[MAXPATH+1]; + char **lval; + int i, j, k; + CONF_S *ctmpb; + + new_confline(ctmp); + (*ctmp)->help_title = help_title; + (*ctmp)->var = v; + + (*ctmp)->varoffset = voff; + k = utf8_width(v->name); + j = voff+k+3; + (*ctmp)->valoffset = j; + + (*ctmp)->keymenu = keymenu; + (*ctmp)->help = help; + (*ctmp)->tool = tool; + + utf8_snprintf(tmp, sizeof(tmp), "%*.*w =", k, k, v->name); + tmp[sizeof(tmp)-1] = '\0'; + (*ctmp)->varname = cpystr(tmp); + + (*ctmp)->varnamep = *ctmp; + (*ctmp)->value = pretty_value(ps, *ctmp); + (*ctmp)->varmem = 0; + + (*ctmp)->flags = (nosel ? CF_NOSELECT : 0); + + ctmpb = (*ctmp); + + lval = LVAL(v, ew); + if(lval){ + for(i = 0; lval[i]; i++){ + if(i) + new_confline(ctmp); + + (*ctmp)->var = v; + (*ctmp)->varmem = i; + (*ctmp)->varoffset = voff; + (*ctmp)->valoffset = j; + (*ctmp)->value = pretty_value(ps, *ctmp); + (*ctmp)->keymenu = keymenu; + (*ctmp)->help = help; + (*ctmp)->tool = tool; + (*ctmp)->varnamep = ctmpb; + (*ctmp)->flags = (nosel ? CF_NOSELECT : 0); + } + } +} + + +void +free_earb(EARB_S **ea) +{ + if(ea && *ea){ + free_earb(&(*ea)->next); + if((*ea)->v){ + free_variable_values((*ea)->v); + if((*ea)->v->name) + fs_give((void **) &(*ea)->v->name); + + fs_give((void **) &(*ea)->v);; + } + + free_arbhdr(&(*ea)->a); + fs_give((void **) ea); + } +} + + +void +calculate_inick_stuff(struct pine *ps) +{ + ACTION_S *role, *irole; + CONF_S *ctmp, *ctmpa; + struct variable *v; + int i; + char *nick; + + if(inick_confs[INICK_INICK_CONF] == NULL) + return; + + for(i = INICK_FROM_CONF; i <= INICK_NNTP_CONF; i++){ + v = inick_confs[i] ? inick_confs[i]->var : NULL; + if(v){ + if(v->is_list){ + if(v->global_val.l) + free_list_array(&v->global_val.l); + } + else{ + if(v->global_val.p) + fs_give((void **)&v->global_val.p); + } + } + } + + nick = PVAL(inick_confs[INICK_INICK_CONF]->var, ew); + + if(nick){ + /* + * Use an empty role with inherit_nick set to nick and then use the + * combine function to find the action values. + */ + role = (ACTION_S *)fs_get(sizeof(*role)); + memset((void *)role, 0, sizeof(*role)); + role->is_a_role = 1; + role->inherit_nick = cpystr(nick); + irole = combine_inherited_role(role); + + ctmp = inick_confs[INICK_FROM_CONF]; + v = ctmp ? ctmp->var : NULL; + + if(irole && irole->from){ + char *bufp; + size_t len; + + len = est_size(irole->from); + bufp = (char *) fs_get(len * sizeof(char)); + v->global_val.p = addr_string_mult(irole->from, bufp, len); + } + + ctmp = inick_confs[INICK_REPLYTO_CONF]; + v = ctmp ? ctmp->var : NULL; + + if(irole && irole->replyto){ + char *bufp; + size_t len; + + len = est_size(irole->replyto); + bufp = (char *) fs_get(len * sizeof(char)); + v->global_val.p = addr_string_mult(irole->replyto, bufp, len); + } + + ctmp = inick_confs[INICK_FCC_CONF]; + v = ctmp ? ctmp->var : NULL; + v->global_val.p = (irole && irole->fcc) ? cpystr(irole->fcc) : NULL; + + ctmp = inick_confs[INICK_LITSIG_CONF]; + v = ctmp ? ctmp->var : NULL; + v->global_val.p = (irole && irole->litsig) ? cpystr(irole->litsig) + : NULL; + + ctmp = inick_confs[INICK_SIG_CONF]; + v = ctmp ? ctmp->var : NULL; + v->global_val.p = (irole && irole->sig) ? cpystr(irole->sig) : NULL; + + ctmp = inick_confs[INICK_TEMPL_CONF]; + v = ctmp ? ctmp->var : NULL; + v->global_val.p = (irole && irole->template) + ? cpystr(irole->template) : NULL; + + ctmp = inick_confs[INICK_CSTM_CONF]; + v = ctmp ? ctmp->var : NULL; + v->global_val.l = (irole && irole->cstm) ? copy_list_array(irole->cstm) + : NULL; + + ctmp = inick_confs[INICK_SMTP_CONF]; + v = ctmp ? ctmp->var : NULL; + v->global_val.l = (irole && irole->smtp) ? copy_list_array(irole->smtp) + : NULL; + + ctmp = inick_confs[INICK_NNTP_CONF]; + v = ctmp ? ctmp->var : NULL; + v->global_val.l = (irole && irole->nntp) ? copy_list_array(irole->nntp) + : NULL; + + free_action(&role); + free_action(&irole); + } + + for(i = INICK_INICK_CONF; i <= INICK_NNTP_CONF; i++){ + ctmp = inick_confs[i]; + v = ctmp ? ctmp->var : NULL; + /* + * If we didn't set a global_val using the nick above, then + * set one here for each variable that uses one. + */ + if(v && !v->global_val.p){ + char *str, *astr, *lc, pdir[MAXPATH+1]; + ADDRESS *addr; + int len; + + switch(i){ + case INICK_FROM_CONF: + addr = generate_from(); + astr = addr_list_string(addr, NULL, 1); + str = (astr && astr[0]) ? astr : "?"; + v->global_val.p = (char *)fs_get((strlen(str) + 20) * + sizeof(char)); + snprintf(v->global_val.p, strlen(str) + 20, "%s%s)", DSTRING, str); + v->global_val.p[strlen(str) + 20 - 1] = '\0'; + if(astr) + fs_give((void **)&astr); + + if(addr) + mail_free_address(&addr); + + break; + + case INICK_FCC_CONF: + v->global_val.p = cpystr(VSTRING); + break; + + case INICK_LITSIG_CONF: + /* + * This default works this way because of the ordering + * of the choices in the detoken routine. + */ + if(ps->VAR_LITERAL_SIG){ + str = ps->VAR_LITERAL_SIG; + v->global_val.p = (char *)fs_get((strlen(str) + 20) * + sizeof(char)); + snprintf(v->global_val.p, strlen(str) + 20, + "%s%s)", DSTRING, str); + v->global_val.p[strlen(str) + 20 - 1] = '\0'; + } + + break; + + case INICK_SIG_CONF: + pdir[0] = '\0'; + if(ps_global->VAR_OPER_DIR){ + strncpy(pdir, ps_global->VAR_OPER_DIR, MAXPATH); + pdir[MAXPATH] = '\0'; + len = strlen(pdir) + 1; + } + else if((lc = last_cmpnt(ps_global->pinerc)) != NULL){ + strncpy(pdir, ps_global->pinerc, + MIN(MAXPATH,lc-ps_global->pinerc)); + pdir[MIN(MAXPATH, lc-ps_global->pinerc)] = '\0'; + len = strlen(pdir); + } + + if(pdir[0] && ps->VAR_SIGNATURE_FILE && + ps->VAR_SIGNATURE_FILE[0] && + is_absolute_path(ps->VAR_SIGNATURE_FILE) && + !strncmp(ps->VAR_SIGNATURE_FILE, pdir, len)){ + str = ps->VAR_SIGNATURE_FILE + len; + } + else + str = (ps->VAR_SIGNATURE_FILE && ps->VAR_SIGNATURE_FILE[0]) + ? ps->VAR_SIGNATURE_FILE : NULL; + if(str){ + v->global_val.p = (char *)fs_get((strlen(str) + 20) * + sizeof(char)); + snprintf(v->global_val.p, strlen(str) + 20, "%s%s)", DSTRING, str); + v->global_val.p[strlen(str) + 20 - 1] = '\0'; + } + + break; + + case INICK_INICK_CONF: + case INICK_REPLYTO_CONF: + case INICK_TEMPL_CONF: + case INICK_CSTM_CONF: + case INICK_SMTP_CONF: + case INICK_NNTP_CONF: + break; + } + } + + if(v) + set_current_val(v, FALSE, FALSE); + + if(ctmp){ + CONF_S *ctmpsig = NULL; + struct variable *vlsig; + + for(ctmpa = ctmp; + ctmpa && ctmpa->varnamep == ctmp; + ctmpa = ctmpa->next){ + if(ctmpa->value) + fs_give((void **)&ctmpa->value); + + ctmpa->value = pretty_value(ps, ctmpa); + } + + if(i == INICK_SIG_CONF){ + /* + * Turn off NOSELECT, but possibly turn it on again + * in next line. + */ + if((ctmpsig = inick_confs[INICK_SIG_CONF]) != NULL) + ctmpsig->flags &= ~CF_NOSELECT; + + if(inick_confs[INICK_LITSIG_CONF] && + (vlsig = inick_confs[INICK_LITSIG_CONF]->var) && + vlsig->current_val.p && + vlsig->current_val.p[0]){ + if(ctmp->value) + fs_give((void **)&ctmp->value); + + ctmp->value = + cpystr("<Ignored: using LiteralSig instead>"); + + ctmp->flags |= CF_NOSELECT; + } + } + } + } +} + + +/* Arguments: + * lst: a list of folders + * action: a 1 or 0 value which basically says that str is associated with + * the filter action if true or the Current Folder type if false. + * Return: + * Returns 2 on success (user wants to exit) and 0 on failure. + * + * This function cycles through a list of folders and checks whether or not each + * folder exists. If they exist, return 2, if they don't exist, notify the user + * or offer to create depending on whether or not it is a filter action or not. + * With each of these prompts, the user can abort their desire to exit. + */ +int +check_role_folders(char **lst, unsigned int action) +{ + char *cur_fn, wt_res, prompt[MAX_SCREEN_COLS]; + int i, rv = 2; + CONTEXT_S *cntxt = NULL; + char nbuf1[MAX_SCREEN_COLS], nbuf2[MAX_SCREEN_COLS]; + int space, w1, w2, exists; + + if(!(lst && *lst)){ + if(action) + q_status_message(SM_ORDER, 3, 5, + _("Set a valid Filter Action before Exiting")); + else + q_status_message(SM_ORDER, 3, 5, + _("Set a valid Specific Folder before Exiting")); + rv = 0; + return rv; + } + + for(i = 0; lst[i]; i++){ + if(action) + cur_fn = detoken_src(lst[i], FOR_FILT, NULL, NULL, NULL, NULL); + else + cur_fn = lst[i]; + + removing_leading_and_trailing_white_space(cur_fn); + if(*cur_fn != '\0'){ + space = MAXPROMPT; + if(is_absolute_path(cur_fn) || !context_isambig(cur_fn)) + cntxt = NULL; + else + cntxt = default_save_context(ps_global->context_list); + + if(!(exists=folder_exists(cntxt, cur_fn)) + && (action + || (ps_global->context_list->use & CNTXT_INCMNG + && !folder_is_nick(cur_fn,FOLDERS(ps_global->context_list), 0)))){ + if(cntxt && (action == 1)){ + space -= 37; /* for fixed part of prompt below */ + w1 = MAX(1,MIN(strlen(cur_fn),space/2)); + w2 = MIN(MAX(1,space-w1),strlen(cntxt->nickname)); + w1 += MAX(0,space-w1-w2); + snprintf(prompt, sizeof(prompt), + _("Folder \"%s\" in <%s> doesn't exist. Create"), + short_str(cur_fn,nbuf1,sizeof(nbuf1),w1,MidDots), + short_str(cntxt->nickname,nbuf2,sizeof(nbuf2),w2,MidDots)); + prompt[sizeof(prompt)-1] = '\0'; + } + else if(cntxt && (action == 0)){ + space -= 51; /* for fixed part of prompt below */ + w1 = MAX(1,MIN(strlen(cur_fn),space/2)); + w2 = MIN(MAX(1,space-w1),strlen(cntxt->nickname)); + w1 += MAX(0,space-w1-w2); + snprintf(prompt, sizeof(prompt), + _("Folder \"%s\" in <%s> doesn't exist. Exit and save anyway"), + short_str(cur_fn,nbuf1,sizeof(nbuf1),w1,MidDots), + short_str(cntxt->nickname,nbuf2,sizeof(nbuf2),w2,MidDots)); + prompt[sizeof(prompt)-1] = '\0'; + } + else if(!cntxt && (action == 1)){ + space -= 31; /* for fixed part of prompt below */ + w1 = MAX(1,space); + snprintf(prompt, sizeof(prompt), + _("Folder \"%s\" doesn't exist. Create"), + short_str(cur_fn,nbuf1,sizeof(nbuf1),w1,MidDots)); + prompt[sizeof(prompt)-1] = '\0'; + } + else{ /*!cntxt && (action == 0) */ + space -= 45; /* for fixed part of prompt below */ + w1 = MAX(1,space); + snprintf(prompt, sizeof(prompt), + _("Folder \"%s\" doesn't exist. Exit and save anyway"), + short_str(cur_fn,nbuf1,sizeof(nbuf1),w1,MidDots)); + prompt[sizeof(prompt)-1] = '\0'; + } + + wt_res = want_to(prompt, 'n', 'x', NO_HELP, WT_NORM); + if(wt_res == 'y'){ + if(action){ + if(context_create(cntxt, NULL, cur_fn)){ + q_status_message(SM_ORDER,3,5,_("Folder created")); + maybe_add_to_incoming(cntxt, cur_fn); + } + } + /* No message to notify of changes being saved, we can't */ + /* assume that the role screen isn't exited yet */ + rv = 2; + } + else if(wt_res == 'n' && action){ + rv = 2; + q_status_message(SM_ORDER,3,5,_("Folder not created")); + } + else{ + q_status_message(SM_ORDER,3,5,_("Exit cancelled")); + rv = 0; + break; + } + } + else{ + if(exists & FEX_ERROR){ + if(ps_global->mm_log_error && ps_global->c_client_error) + q_status_message(SM_ORDER,3,5,ps_global->c_client_error); + else + q_status_message1(SM_ORDER,3,5,"\"%s\": Trouble checking for folder existence", cur_fn); + } + + rv = 2; + } + } + else{ /* blank item in list of folders */ + if(action && lst[i+1] == '\0') + q_status_message(SM_ORDER,3,5,_("Set a valid Filter Action before Exiting")); + else /* !action && lst[i+1] == '\0' */ + q_status_message(SM_ORDER,3,5,_("Set a valid Specific Folder before Exiting")); + rv = 0; + break; + } + + if(cur_fn && cur_fn != lst[i]) + fs_give((void **) &cur_fn); + } + + return(rv); +} + + +void +maybe_add_to_incoming(CONTEXT_S *cntxt, char *cur_fn) +{ + char name[MAILTMPLEN], nname[32]; + char nbuf1[MAX_SCREEN_COLS], nbuf2[MAX_SCREEN_COLS]; + char prompt[MAX_SCREEN_COLS]; + char ***alval; + int i, found, space, w1, w2; + FOLDER_S *f; + + if(ps_global->context_list->use & CNTXT_INCMNG && + ((alval = ALVAL(&ps_global->vars[V_INCOMING_FOLDERS], Main)) != NULL)){ + (void)context_apply(name, cntxt, cur_fn, sizeof(name)); + /* + * Since the folder didn't exist it is very unlikely that it is + * in the incoming-folders list already, but we're just checking + * to be sure. We should really be canonicalizing both names + * before comparing, but... + */ + for(found = 0, i = 0; *alval && (*alval)[i] && !found; i++){ + char *nickname, *folder; + + get_pair((*alval)[i], &nickname, &folder, 0, 0); + if(folder && !strucmp((*alval)[i], folder)) + found++; + + if(nickname) + fs_give((void **)&nickname); + if(folder) + fs_give((void **)&folder); + } + + if(found) + return; + + space = MAXPROMPT; + space -= 15; /* for fixed part of prompt below */ + w2 = MAX(1, + MIN(space/2,MIN(strlen(ps_global->context_list->nickname),20))); + w1 = MAX(1,space - w2); + snprintf(prompt, sizeof(prompt), + "Add \"%s\" to %s list", + short_str(name,nbuf1,sizeof(nbuf1),w1,MidDots), + short_str(ps_global->context_list->nickname,nbuf2,sizeof(nbuf2),w2,MidDots)); + prompt[sizeof(prompt)-1] = '\0'; + if(want_to(prompt, 'n', 'x', NO_HELP, WT_NORM) == 'y'){ + char *pp; + + nname[0] = '\0'; + space = MAXPROMPT; + space -= 25; + w1 = MAX(1, space); + snprintf(prompt, sizeof(prompt), "Nickname for folder \"%s\" : ", + short_str(name,nbuf1,sizeof(nbuf1),w1,MidDots)); + prompt[sizeof(prompt)-1] = '\0'; + while(1){ + int rc; + int flags = OE_APPEND_CURRENT; + + rc = optionally_enter(nname, -FOOTER_ROWS(ps_global), 0, + sizeof(nname), prompt, NULL, + NO_HELP, &flags); + removing_leading_and_trailing_white_space(nname); + if(rc == 0 && *nname){ + /* see if nickname already exists */ + found = 0; + if(!strucmp(ps_global->inbox_name, nname)) + found++; + + for(i = 0; + !found && + i < folder_total(FOLDERS(ps_global->context_list)); + i++){ + FOLDER_S *f; + + f = folder_entry(i, FOLDERS(ps_global->context_list)); + if(!strucmp(FLDR_NAME(f), nname)) + found++; + } + + if(found){ + q_status_message1(SM_ORDER | SM_DING, 3, 5, + _("Nickname \"%s\" is already in use"), + nname); + continue; + } + + break; + } + else if(rc == 3) + q_status_message(SM_ORDER, 0, 3, _("No help yet.")); + else if(rc == 1){ + q_status_message1(SM_ORDER, 0, 3, + _("Not adding nickname to %s list"), + ps_global->context_list->nickname); + return; + } + } + + pp = put_pair(nname, name); + f = new_folder(name, line_hash(pp)); + f->nickname = cpystr(nname); + f->name_len = strlen(nname); + folder_insert(folder_total(FOLDERS(ps_global->context_list)), f, + FOLDERS(ps_global->context_list)); + + if(!*alval){ + i = 0; + *alval = (char **)fs_get(2 * sizeof(char *)); + } + else{ + for(i = 0; (*alval)[i]; i++) + ; + + fs_resize((void **)alval, (i + 2) * sizeof(char *)); + } + + (*alval)[i] = pp; + (*alval)[i+1] = NULL; + set_current_val(&ps_global->vars[V_INCOMING_FOLDERS], TRUE, TRUE); + write_pinerc(ps_global, ew, WRP_NONE); + } + } +} + + +int +role_filt_exitcheck(CONF_S **cl, unsigned int flags) +{ + int rv, j, action; + char **to_folder = NULL, **spec_fldr = NULL; + CONF_S *ctmp; + NAMEVAL_S *f; +#define ACT_UNKNOWN 0 +#define ACT_KILL 1 +#define ACT_MOVE 2 +#define ACT_MOVE_NOFOLDER 3 +#define ACT_STATE 4 + + /* + * We have to locate the lines which define the Filter Action and + * then check to see that it is set to something before allowing + * user to Exit. + */ + action = ACT_UNKNOWN; + if(flags & CF_CHANGES && role_filt_ptr && PVAL(role_filt_ptr,ew)){ + for(j = 0; (f = filter_types(j)); j++) + if(!strucmp(PVAL(role_filt_ptr,ew), f->name)) + break; + + switch(f ? f->value : -1){ + case FILTER_KILL: + action = ACT_KILL; + break; + + case FILTER_STATE: + action = ACT_STATE; + break; + + case FILTER_FOLDER: + /* + * Check that the folder is set to something. + */ + + action = ACT_MOVE_NOFOLDER; + /* go to end of screen */ + for(ctmp = (*cl); + ctmp && ctmp->next; + ctmp = next_confline(ctmp)) + ; + + /* back up to start of Filter Action */ + for(; + ctmp && + !(ctmp->flags & CF_STARTITEM && ctmp->var == role_filt_ptr); + ctmp = prev_confline(ctmp)) + ; + + /* skip back past NOSELECTs */ + for(; + ctmp && (ctmp->flags & CF_NOSELECT); + ctmp = next_confline(ctmp)) + ; + + /* find line with new var (the Folder line) */ + for(; + ctmp && (ctmp->var == role_filt_ptr); + ctmp = next_confline(ctmp)) + ; + + /* ok, we're finally at the Folder line */ + if(ctmp && ctmp->var && LVAL(ctmp->var,ew)){ + to_folder = copy_list_array(LVAL(ctmp->var,ew)); + if(to_folder && to_folder[0]) + action = ACT_MOVE; + } + + break; + + default: + dprint((1, + "Can't happen, role_filt_ptr set to %s\n", + PVAL(role_filt_ptr,ew) ? PVAL(role_filt_ptr,ew) : "?")); + break; + } + } + + if(flags & CF_CHANGES){ + switch(want_to((action == ACT_KILL) + ? _("Commit changes (\"Yes\" means matching messages will be deleted)") + : EXIT_PMT, 'y', 'x', h_config_undo, WT_FLUSH_IN)){ + case 'y': + switch(action){ + case ACT_KILL: + if((spec_fldr = get_role_specific_folder(cl)) != NULL){ + rv = check_role_folders(spec_fldr, 0); + free_list_array(&spec_fldr); + if(rv == 2) + q_status_message(SM_ORDER,0,3,_("Ok, messages matching that Pattern will be deleted")); + } + else{ + q_status_message(SM_ORDER, 0, 3, + _("Ok, messages matching that Pattern will be deleted")); + rv = 2; + } + break; + + case ACT_MOVE: + if((spec_fldr = get_role_specific_folder(cl)) != NULL){ + rv = check_role_folders(spec_fldr, 0); + free_list_array(&spec_fldr); + if(to_folder && rv == 2) + rv = check_role_folders(to_folder, 1); + } + else + rv = check_role_folders(to_folder, 1); + + break; + + case ACT_MOVE_NOFOLDER: + rv = 0; + q_status_message(SM_ORDER, 3, 5, + _("Set a valid Filter Action before Exiting")); + break; + + case ACT_STATE: + if((spec_fldr = get_role_specific_folder(cl)) != NULL){ + rv = check_role_folders(spec_fldr, 0); + free_list_array(&spec_fldr); + } + else + rv = 2; + + break; + + default: + rv = 2; + dprint((1, + "This can't happen, role_filt_ptr or to_folder not set\n")); + break; + } + + break; + + case 'n': + q_status_message(SM_ORDER,3,5,_("No filter changes saved")); + rv = 10; + break; + + case 'x': /* ^C */ + default : + q_status_message(SM_ORDER,3,5,_("Changes not yet saved")); + rv = 0; + break; + } + } + else + rv = 2; + + if(to_folder) + free_list_array(&to_folder); + + return(rv); +} + + +/* + * Don't allow exit unless user has set the action to something. + */ +int +role_filt_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) +{ + int rv; + + switch(cmd){ + case MC_EXIT: + rv = role_filt_exitcheck(cl, flags); + break; + + default: + rv = role_text_tool(ps, cmd, cl, flags); + break; + } + + return(rv); +} + + +int +role_filt_addhdr_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) +{ + int rv; + + switch(cmd){ + case MC_EXIT: + rv = role_filt_exitcheck(cl, flags); + break; + + default: + rv = role_addhdr_tool(ps, cmd, cl, flags); + break; + } + + return rv; +} + +int +role_addhdr_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) +{ + int rv; + + switch(cmd){ + case MC_ADDHDR: + case MC_EXIT: + rv = role_text_tool(ps, cmd, cl, flags); + break; + + default: + rv = -1; + break; + } + + return rv; +} + +/* + * Don't allow exit unless user has set the action to something. + */ +int +role_filt_radiobutton_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) +{ + int rv; + + switch(cmd){ + case MC_EXIT: + rv = role_filt_exitcheck(cl, flags); + break; + + default: + rv = role_radiobutton_tool(ps, cmd, cl, flags); + break; + } + + return(rv); +} + + +/* + * simple radio-button style variable handler + */ +int +role_radiobutton_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) +{ + int rv = 0, i; + CONF_S *ctmp, *spec_ctmp = NULL; + NAMEVAL_S *rule; + char **apval; + + switch(cmd){ + case MC_CHOICE : /* set/unset feature */ + + /* back up to first line */ + for(ctmp = (*cl); + ctmp && ctmp->prev && !(ctmp->prev->flags & CF_NOSELECT); + ctmp = prev_confline(ctmp)) + ; + + for(i = 0; ctmp && (!(ctmp->flags & CF_NOSELECT) + || (*cl)->var == role_fldr_ptr + || (*cl)->var == role_afrom_ptr + || (*cl)->var == role_filt_ptr); + ctmp = next_confline(ctmp), i++){ + if(((*cl)->var == role_fldr_ptr) || + ((*cl)->var == role_afrom_ptr) || + ((*cl)->var == role_filt_ptr)){ + if((((*cl)->var == role_fldr_ptr) && !pat_fldr_types(i)) + || (((*cl)->var == role_afrom_ptr) + && !inabook_fldr_types(i)) + || (((*cl)->var == role_filt_ptr) && !filter_types(i))){ + spec_ctmp = ctmp; + break; + } + } + + ctmp->value[1] = ' '; + } + + /* turn on current value */ + (*cl)->value[1] = R_SELD; + + if((*cl)->var == role_fldr_ptr){ + for(ctmp = spec_ctmp; + ctmp && ctmp->varnamep == spec_ctmp; + ctmp = next_confline(ctmp)) + if((*cl)->varmem == FLDR_SPECIFIC) + ctmp->flags &= ~CF_NOSELECT; + else + ctmp->flags |= CF_NOSELECT; + + rule = pat_fldr_types((*cl)->varmem); + } + else if((*cl)->var == role_afrom_ptr){ + for(ctmp = spec_ctmp; + ctmp && ctmp->varnamep == spec_ctmp; + ctmp = next_confline(ctmp)) + if(((*cl)->varmem == IAB_SPEC_YES) + || ((*cl)->varmem == IAB_SPEC_NO)) + ctmp->flags &= ~CF_NOSELECT; + else + ctmp->flags |= CF_NOSELECT; + + rule = inabook_fldr_types((*cl)->varmem); + } + else if((*cl)->var == role_filt_ptr){ + for(ctmp = spec_ctmp; + ctmp && ctmp->varnamep == spec_ctmp; + ctmp = next_confline(ctmp)) + if((*cl)->varmem == FILTER_FOLDER) + ctmp->flags &= ~CF_NOSELECT; + else + ctmp->flags |= CF_NOSELECT; + + rule = filter_types((*cl)->varmem); + } + else if((*cl)->var == role_forw_ptr) + rule = role_forw_types((*cl)->varmem); + else if((*cl)->var == role_repl_ptr) + rule = role_repl_types((*cl)->varmem); + else if((*cl)->var == role_status1_ptr || + (*cl)->var == role_status2_ptr || + (*cl)->var == role_status3_ptr || + (*cl)->var == role_status4_ptr || + (*cl)->var == role_status5_ptr || + (*cl)->var == role_status6_ptr || + (*cl)->var == role_status7_ptr || + (*cl)->var == role_status8_ptr) + rule = role_status_types((*cl)->varmem); + else if((*cl)->var == msg_state1_ptr || + (*cl)->var == msg_state2_ptr || + (*cl)->var == msg_state3_ptr || + (*cl)->var == msg_state4_ptr) + rule = msg_state_types((*cl)->varmem); + else + rule = role_comp_types((*cl)->varmem); + + apval = APVAL((*cl)->var, ew); + if(apval && *apval) + fs_give((void **)apval); + + if(apval) + *apval = cpystr(rule->name); + + ps->mangled_body = 1; /* BUG: redraw it all for now? */ + rv = 1; + + break; + + case MC_EXIT: /* exit */ + rv = role_text_tool(ps, cmd, cl, flags); + break; + + default : + rv = -1; + break; + } + + return(rv); +} + + +int +role_sort_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) +{ + int rv = 0, i; + CONF_S *ctmp; + char **apval; + SortOrder def_sort; + int def_sort_rev; + + apval = APVAL((*cl)->var, ew); + + switch(cmd){ + case MC_CHOICE : /* set/unset feature */ + + if((*cl)->varmem >= 0){ + def_sort_rev = (*cl)->varmem >= (short) EndofList; + def_sort = (SortOrder)((*cl)->varmem - (def_sort_rev * EndofList)); + + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s", sort_name(def_sort), + (def_sort_rev) ? "/Reverse" : ""); + tmp_20k_buf[SIZEOF_20KBUF-1] = '\0'; + } + + if(apval){ + if(*apval) + fs_give((void **)apval); + + if((*cl)->varmem >= 0) + *apval = cpystr(tmp_20k_buf); + } + + /* back up to first line */ + for(ctmp = (*cl); + ctmp && ctmp->prev && !(ctmp->prev->flags & CF_NOSELECT); + ctmp = prev_confline(ctmp)) + ; + + /* turn off all values */ + for(i = 0; + ctmp && !(ctmp->flags & CF_NOSELECT); + ctmp = next_confline(ctmp), i++) + ctmp->value[1] = ' '; + + /* turn on current value */ + (*cl)->value[1] = R_SELD; + + ps->mangled_body = 1; /* BUG: redraw it all for now? */ + rv = 1; + + break; + + case MC_EXIT: /* exit */ + rv = role_text_tool(ps, cmd, cl, flags); + break; + + default : + rv = -1; + break; + } + + return(rv); +} + +/* + * Return an allocated list of the Specific Folder list for + * roles, or NULL if Current Folder type is not set to + * to Specific Folder + * + * WARNING, the method used in obtaining the specific folder is + * VERY dependent on the order in which it is presented on the + * screen. If the Current Folder radio buttons were changed, + * this function would probably need to be fixed accordingly. + */ +char ** +get_role_specific_folder(CONF_S **cl) +{ + CONF_S *ctmp; + + /* go to the first line */ + for(ctmp = *cl; + ctmp && ctmp->prev; + ctmp = prev_confline(ctmp)) + ; + + /* go to the current folder radio button list */ + while(ctmp && ctmp->var != role_fldr_ptr) + ctmp = next_confline(ctmp); + + /* go to the specific folder button (caution) */ + while(ctmp && ctmp->varmem != FLDR_SPECIFIC) + ctmp = next_confline(ctmp); + + /* check if selected (assumption of format "(*)" */ + if(ctmp && ctmp->value[1] == R_SELD){ + /* go to next line, the start of the list */ + ctmp = next_confline(ctmp); + if(LVAL(ctmp->var, ew)) + return copy_list_array(LVAL(ctmp->var, ew)); + else{ + char **ltmp; + + /* + * Need to allocate empty string so as not to confuse it + * with the possibility that Specific Folder is not selected. + */ + ltmp = (char **) fs_get(2 * sizeof(char *)); + ltmp[0] = cpystr(""); + ltmp[1] = NULL; + return(ltmp); + } + } + else + return NULL; +} + + +/* + */ +int +role_litsig_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) +{ + int rv; + + switch(cmd){ + case MC_ADD : + case MC_EDIT : + rv = litsig_text_tool(ps, cmd, cl, flags); + if(rv) + calculate_inick_stuff(ps); + + break; + + default : + rv = role_text_tool(ps, cmd, cl, flags); + break; + } + + return(rv); +} + + +/* + */ +int +role_cstm_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) +{ + int rv; + + switch(cmd){ + case MC_EXIT : + rv = role_text_tool(ps, cmd, cl, flags); + break; + + default : + rv = text_tool(ps, cmd, cl, flags); + if(rv == 1 && (*cl)->var){ + char **lval; + + lval = LVAL((*cl)->var, ew); + if(lval && lval[(*cl)->varmem] && + ((!struncmp(lval[(*cl)->varmem],"from",4) && + (lval[(*cl)->varmem][4] == ':' || + lval[(*cl)->varmem][4] == '\0')) || + (!struncmp(lval[(*cl)->varmem],"reply-to",8) && + (lval[(*cl)->varmem][8] == ':' || + lval[(*cl)->varmem][8] == '\0')))) + q_status_message1(SM_ORDER|SM_DING, 5, 7, + "Use \"Set %s\" instead, Change ignored", + !struncmp(lval[(*cl)->varmem],"from",4) + ? "From" : "Reply-To"); + } + + break; + } + + return(rv); +} + + +/* + */ +int +role_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) +{ + OPT_SCREEN_S *saved_screen; + int rv = -1, oeflags, len, sig, r, i, cancel = 0; + char *file, *err, title[20], *newfile, *lc, *addr, *fldr = NULL, *tmpfldr; + char dir2[MAXPATH+1], pdir[MAXPATH+1], *p; + char full_filename[MAXPATH+1], filename[MAXPATH+1]; + char tmp[MAXPATH+1], **spec_fldr, **apval; + EARB_S *earb, *ea, *eaprev; + CONF_S *ctmp, *ctmpb, *newcp, *ctend; + HelpType help; + + switch(cmd){ + case MC_EXIT : + if(flags & CF_CHANGES){ + switch(want_to(EXIT_PMT, 'y', 'x', h_config_role_undo, WT_FLUSH_IN)){ + case 'y': + if((spec_fldr = get_role_specific_folder(cl)) != NULL){ + rv = check_role_folders(spec_fldr, 0); + free_list_array(&spec_fldr); + } + else + rv = 2; + break; + + case 'n': + q_status_message(SM_ORDER,3,5,_("No changes saved")); + rv = 10; + break; + + case 'x': /* ^C */ + q_status_message(SM_ORDER,3,5,_("Changes not yet saved")); + rv = 0; + break; + } + } + else + rv = 2; + + break; + + case MC_NOT : /* toggle between !matching and matching */ + ctmp = (*cl)->varnamep; + if(ctmp->varname && ctmp->var && ctmp->var->name){ + if(!strncmp(ctmp->varname, NOT, NOTLEN) && + !strncmp(ctmp->var->name, NOT, NOTLEN)){ + rplstr(ctmp->var->name, strlen(ctmp->var->name)+1, NOTLEN, ""); + rplstr(ctmp->varname, strlen(ctmp->varname)+1, NOTLEN, ""); + strncpy(ctmp->varname+strlen(ctmp->varname)-1, + repeat_char(NOTLEN, ' '), NOTLEN+1); + strncat(ctmp->varname, "=", NOTLEN); + } + else{ + rplstr(ctmp->var->name, strlen(ctmp->var->name)+NOTLEN+1, 0, NOT); + strncpy(ctmp->varname+strlen(ctmp->varname)-1-NOTLEN, "=", NOTLEN); + rplstr(ctmp->varname, strlen(ctmp->varname)+NOTLEN+1, 0, NOT); + } + + rv = 1; + } + + break; + + case MC_CHOICE : /* Choose a file */ + /* + * In signature_path we read signature files relative to the pinerc + * dir, so if user selects one that is in there we'll make it + * relative instead of absolute, so it looks nicer. + */ + pdir[0] = '\0'; + if(ps_global->VAR_OPER_DIR){ + strncpy(pdir, ps_global->VAR_OPER_DIR, MAXPATH); + pdir[MAXPATH] = '\0'; + len = strlen(pdir) + 1; + } + else if((lc = last_cmpnt(ps_global->pinerc)) != NULL){ + strncpy(pdir, ps_global->pinerc, MIN(MAXPATH,lc-ps_global->pinerc)); + pdir[MIN(MAXPATH, lc-ps_global->pinerc)] = '\0'; + len = strlen(pdir); + } + + strncpy(title, "CHOOSE A", 15); + strncpy(dir2, pdir, MAXPATH); + + filename[0] = '\0'; + build_path(full_filename, dir2, filename, sizeof(full_filename)); + + r = file_lister(title, dir2, sizeof(dir2), filename, sizeof(filename), TRUE, FB_READ); + ps->mangled_screen = 1; + + if(r == 1){ + build_path(full_filename, dir2, filename, sizeof(full_filename)); + removing_leading_and_trailing_white_space(full_filename); + if(!strncmp(full_filename, pdir, strlen(pdir))) + newfile = cpystr(full_filename + len); + else + newfile = cpystr(full_filename); + + apval = APVAL((*cl)->var, ew); + if(apval && *apval) + fs_give((void **)apval); + + if(apval) + *apval = newfile; + + if((*cl)->value) + fs_give((void **)&((*cl)->value)); + + (*cl)->value = pretty_value(ps, *cl); + rv = 1; + } + else + rv = 0; + + break; + + case MC_CHOICEB : /* Choose Addresses, no full names */ + addr = addr_book_multaddr_nf(); + ps->mangled_screen = 1; + if(addr && (*cl)->var && (*cl)->var->is_list){ + char **ltmp, *tmp; + int i; + + i = 0; + for(tmp = addr; *tmp; tmp++) + if(*tmp == ',') + i++; /* conservative count of ,'s */ + + ltmp = parse_list(addr, i + 1, PL_COMMAQUOTE, NULL); + fs_give((void **) &addr); + + if(ltmp && ltmp[0]) + config_add_list(ps, cl, ltmp, NULL, 0); + + if(ltmp) + fs_give((void **) <mp); + + if((*cl)->value) + fs_give((void **)&((*cl)->value)); + + (*cl)->value = pretty_value(ps, *cl); + rv = 1; + } + else + rv = 0; + + break; + + case MC_CHOICEC : /* Choose an Address, no full name */ + addr = addr_book_oneaddr(); + ps->mangled_screen = 1; + if(addr){ + apval = APVAL((*cl)->var, ew); + if(apval && *apval) /* replace current value */ + fs_give((void **)apval); + + if(apval) + *apval = addr; + + if((*cl)->value) + fs_give((void **)&((*cl)->value)); + + (*cl)->value = pretty_value(ps, *cl); + rv = 1; + } + else + rv = 0; + + break; + + case MC_CHOICED : /* Choose a Folder */ + case MC_CHOICEE : + saved_screen = opt_screen; + if(cmd == MC_CHOICED) + tmpfldr = folder_for_config(FOR_PATTERN); + else + tmpfldr = folder_for_config(0); + + if(tmpfldr){ + fldr = add_comma_escapes(tmpfldr); + fs_give((void**) &tmpfldr); + } + + opt_screen = saved_screen; + + ps->mangled_screen = 1; + if(fldr && *fldr && (*cl)->var && (*cl)->var->is_list){ + char **ltmp; + + ltmp = (char **) fs_get(2 * sizeof(char *)); + ltmp[0] = fldr; + ltmp[1] = NULL; + fldr = NULL; + + if(ltmp && ltmp[0]) + config_add_list(ps, cl, ltmp, NULL, 0); + + if(ltmp) + fs_give((void **) <mp); + + if((*cl)->value) + fs_give((void **) &((*cl)->value)); + + (*cl)->value = pretty_value(ps, *cl); + rv = 1; + } + else if(fldr && *fldr && (*cl)->var && !(*cl)->var->is_list){ + apval = APVAL((*cl)->var, ew); + if(apval && *apval) /* replace current value */ + fs_give((void **)apval); + + if(apval){ + *apval = fldr; + fldr = NULL; + } + + if((*cl)->value) + fs_give((void **) &((*cl)->value)); + + (*cl)->value = pretty_value(ps, *cl); + rv = 1; + } + else + rv = 0; + + if(fldr) + fs_give((void **) &fldr); + + break; + + case MC_EDITFILE : + file = ((*cl)->var && PVAL((*cl)->var, ew)) + ? cpystr(PVAL((*cl)->var, ew)) : NULL; + if(file) + removing_leading_and_trailing_white_space(file); + + sig = (srchstr((*cl)->varname, "signature") != NULL); + if(!file || !*file){ + err = (char *)fs_get(100 * sizeof(char)); + snprintf(err, 100, "No %s file defined. First define a file name.", + sig ? "signature" : "template"); + err[100-1] = '\0'; + } + else{ + if(file[len=(strlen(file)-1)] == '|') + file[len] = '\0'; + + snprintf(title, sizeof(title), "%s EDITOR", sig ? "SIGNATURE" : "TEMPLATE"); + title[sizeof(title)-1] = '\0'; + err = signature_edit(file, title); + } + + fs_give((void **)&file); + if(err){ + q_status_message1(SM_ORDER, 3, 5, "%s", err); + fs_give((void **)&err); + } + + rv = 0; + ps->mangled_screen = 1; + break; + + /* Add an arbitrary header to this role */ + case MC_ADDHDR : + rv = 0; + /* make earb point to last one */ + for(earb = *(*cl)->d.earb; earb && earb->next; earb = earb->next) + ; + + /* Add new one to end of list */ + ea = (EARB_S *)fs_get(sizeof(*ea)); + memset((void *)ea, 0, sizeof(*ea)); + ea->v = (struct variable *)fs_get(sizeof(struct variable)); + memset((void *)ea->v, 0, sizeof(struct variable)); + ea->a = (ARBHDR_S *)fs_get(sizeof(ARBHDR_S)); + memset((void *)ea->a, 0, sizeof(ARBHDR_S)); + + /* get new header field name */ + help = NO_HELP; + tmp[0] = '\0'; + while(1){ + i = optionally_enter(tmp, -FOOTER_ROWS(ps), 0, sizeof(tmp), + _("Enter the name of the header field to be added: "), + NULL, help, NULL); + if(i == 0) + break; + else if(i == 1){ + cmd_cancelled("eXtraHdr"); + cancel = 1; + break; + } + else if(i == 3){ + help = help == NO_HELP ? h_config_add_pat_hdr : NO_HELP; + continue; + } + else + break; + } + + ps->mangled_footer = 1; + + removing_leading_and_trailing_white_space(tmp); + if(tmp[strlen(tmp)-1] == ':') /* remove trailing colon */ + tmp[strlen(tmp)-1] = '\0'; + + removing_trailing_white_space(tmp); + + if(cancel || !tmp[0]) + break; + + tmp[0] = islower((unsigned char)tmp[0]) ? toupper((unsigned char)tmp[0]) + : tmp[0]; + ea->a->field = cpystr(tmp); + + if(earb) + earb->next = ea; + else + *((*cl)->d.earb) = ea; + + /* go to first line */ + for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp)) + ; + + /* + * Go to the Add Extra Headers line. We will put the + * new header before this line. + */ + for(; ctmp; ctmp = next_confline(ctmp)) + if(ctmp->value && !strcmp(ctmp->value, ADDXHDRS)) + break; + + /* move back one */ + if(ctmp) + ctmp = prev_confline(ctmp); + + /* + * Add a new line after this point, which is after the last + * extra header (if any) or after the Participant pattern, and + * before the Add Extra Headers placeholder line. + */ + p = (char *) fs_get(strlen(tmp) + strlen(" pattern") + 1); + snprintf(p, strlen(tmp) + strlen(" pattern") + 1, "%s pattern", tmp); + p[strlen(tmp) + strlen(" pattern") + 1 - 1] = '\0'; + setup_dummy_pattern_var(ea->v, p, NULL); + fs_give((void **) &p); + + /* find what indent should be */ + if(ctmp && ctmp->varnamep && ctmp->varnamep->varname) + i = MIN(MAX(utf8_width(ctmp->varnamep->varname) + 1, 3), 200); + else + i = 20; + + setup_role_pat(ps, &ctmp, ea->v, h_config_role_arbpat, + ARB_HELP, &config_role_xtrahdr_keymenu, + ctmp->prev->tool, ctmp->prev->d.earb, i); + + /* + * move current line to new line + */ + + newcp = ctmp; + + /* check if new line comes before the top of the screen */ + ctmpb = (opt_screen && opt_screen->top_line) + ? opt_screen->top_line->prev : NULL; + for(; ctmpb; ctmpb = prev_confline(ctmpb)) + if(ctmpb == newcp) + break; + /* + * Keep the right lines visible. + * The if triggers if the new line is off the top of the screen, and + * it makes the new line be the top line. + * The else counts how many lines down the screen the new line is. + */ + + i = 0; + if(ctmpb == newcp) + opt_screen->top_line = newcp; + else{ + for(ctmp = opt_screen->top_line; ctmp && ctmp != newcp; + i++, ctmp = next_confline(ctmp)) + ; + } + + if(i >= BODY_LINES(ps)){ /* new line is off screen */ + /* move top line down this far */ + i = i + 1 - BODY_LINES(ps); + for(ctmp = opt_screen->top_line; + i > 0; + i--, ctmp = next_confline(ctmp)) + ; + + opt_screen->top_line = ctmp; + } + + *cl = newcp; + + ps->mangled_screen = 1; + rv = 1; + break; + + /* Delete an arbitrary header from this role */ + case MC_DELHDR : + /* + * Find this one in earb list. We don't have a good way to locate + * it so we match the ea->v->name with ctmp->varname. + */ + rv = 0; + eaprev = NULL; + for(ea = *(*cl)->d.earb; ea; ea = ea->next){ + if((*cl)->varnamep && (*cl)->varnamep->varname + && ea->v && ea->v->name + && !strncmp((*cl)->varnamep->varname, + ea->v->name, strlen(ea->v->name))) + break; + + eaprev = ea; + } + + snprintf(tmp, sizeof(tmp), _("Really remove \"%s\" pattern from this rule"), + (ea && ea->a && ea->a->field) ? ea->a->field : "this"); + tmp[sizeof(tmp)-1] = '\0'; + if(want_to(tmp, 'y', 'n', NO_HELP, WT_NORM) != 'y'){ + cmd_cancelled("RemoveHdr"); + return(rv); + } + + /* delete the earb element from the list */ + if(ea){ + if(eaprev) + eaprev->next = ea->next; + else + *(*cl)->d.earb = ea->next; + + ea->next = NULL; + free_earb(&ea); + } + + /* remember start of deleted header */ + ctmp = (*cl && (*cl)->varnamep) ? (*cl)->varnamep : NULL; + + /* and end of deleted header */ + for(ctend = *cl; ctend; ctend = next_confline(ctend)) + if(!ctend->next || ctend->next->varnamep != ctmp) + break; + + /* check if top line is one we're deleting */ + for(ctmpb = ctmp; ctmpb; ctmpb = next_confline(ctmpb)){ + if(ctmpb == opt_screen->top_line) + break; + + if(ctmpb == (*cl)) + break; + } + + if(ctmpb == opt_screen->top_line) + opt_screen->top_line = ctend ? ctend->next : NULL; + + /* move current line after this header */ + *cl = ctend ? ctend->next : NULL; + + /* remove deleted header lines */ + if(ctmp && ctend){ + /* remove from linked list */ + if(ctmp->prev) + ctmp->prev->next = ctend->next; + + if(ctend->next) + ctend->next->prev = ctmp->prev; + + /* free memory */ + ctmp->prev = ctend->next = NULL; + free_conflines(&ctmp); + } + + ps->mangled_body = 1; + rv = 1; + break; + + default : + if(((*cl)->var == scorei_pat_global_ptr + || (*cl)->var == age_pat_global_ptr + || (*cl)->var == size_pat_global_ptr + || (*cl)->var == cati_global_ptr) + && + (cmd == MC_EDIT || (cmd == MC_ADD && !PVAL((*cl)->var, ew)))){ + char prompt[60]; + + rv = 0; + snprintf(prompt, sizeof(prompt), "%s the interval : ", + PVAL((*cl)->var, ew) ? "Change" : "Enter"); + prompt[sizeof(prompt)-1] = '\0'; + + ps->mangled_footer = 1; + help = NO_HELP; + tmp[0] = '\0'; + snprintf(tmp, sizeof(tmp), + "%s", PVAL((*cl)->var, ew) ? PVAL((*cl)->var, ew) : ""); + tmp[sizeof(tmp)-1] = '\0'; + while(1){ + oeflags = OE_APPEND_CURRENT; + i = optionally_enter(tmp, -FOOTER_ROWS(ps), 0, sizeof(tmp), + prompt, NULL, help, &oeflags); + if(i == 0){ + rv = ps->mangled_body = 1; + apval = APVAL((*cl)->var, ew); + if(apval && *apval) + fs_give((void **)apval); + + if(apval && tmp[0]) + *apval = cpystr(tmp); + + fix_side_effects(ps, (*cl)->var, 0); + if((*cl)->value) + fs_give((void **)&(*cl)->value); + + (*cl)->value = pretty_value(ps, *cl); + } + else if(i == 1) + cmd_cancelled(cmd == MC_ADD ? "Add" : "Change"); + else if(i == 3){ + help = help == NO_HELP ? h_config_edit_scorei : NO_HELP; + continue; + } + else if(i == 4) + continue; + + break; + } + } + else{ + if(cmd == MC_ADD && (*cl)->var && !(*cl)->var->is_list) + cmd = MC_EDIT; + + rv = text_toolit(ps, cmd, cl, flags, 1); + + /* make sure the earb pointers are set */ + for(ctmp = (*cl)->varnamep; + ctmp->next && ctmp->next->var == ctmp->var; + ctmp = next_confline(ctmp)) + ctmp->next->d.earb = ctmp->d.earb; + } + + break; + } + + /* + * If the inherit nickname changed, we have to re-calculate the + * global_vals and values for the action variables. + * We may have to do the same if literal sig changed, too. + */ + if(rv) + calculate_inick_stuff(ps); + + return(rv); +} + + +/* + */ +int +role_text_tool_inick(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) +{ + int rv = -1; + char **apval; + + switch(cmd){ + case MC_EXIT : + rv = role_text_tool(ps, cmd, cl, flags); + break; + + case MC_CHOICE : /* Choose a role nickname */ + {void (*prev_screen)(struct pine *) = ps->prev_screen, + (*redraw)(void) = ps->redrawer; + OPT_SCREEN_S *saved_screen; + ACTION_S *role; + + ps->redrawer = NULL; + ps->next_screen = SCREEN_FUN_NULL; + + saved_screen = opt_screen; + if(role_select_screen(ps, &role, 0) == 0){ + apval = APVAL((*cl)->var, ew); + if(apval && *apval) + fs_give((void **)apval); + + if(apval) + *apval = (role && role->nick) ? cpystr(role->nick) : NULL; + + if((*cl)->value) + fs_give((void **)&((*cl)->value)); + + (*cl)->value = pretty_value(ps, *cl); + rv = 1; + } + else{ + ps->next_screen = prev_screen; + ps->redrawer = redraw; + rv = 0; + } + + opt_screen = saved_screen; + } + + ps->mangled_screen = 1; + break; + + case MC_EDIT : + case MC_ADD : + case MC_DELETE : + rv = text_tool(ps, cmd, cl, flags); + ps->mangled_screen = 1; + break; + + default : + rv = text_tool(ps, cmd, cl, flags); + break; + } + + /* + * If the inherit nickname changed, we have to re-calculate the + * global_vals and values for the action variables. + * We may have to do the same if literal sig changed, too. + */ + if(rv) + calculate_inick_stuff(ps); + + return(rv); +} + + +/* + */ +int +role_text_tool_kword(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) +{ + int i, j, rv = -1; + char **lval; + + switch(cmd){ + case MC_CHOICE : /* Choose keywords from list and add them */ + {void (*prev_screen)(struct pine *) = ps->prev_screen, + (*redraw)(void) = ps->redrawer; + OPT_SCREEN_S *saved_screen; + char *esc; + char **kw; + + ps->redrawer = NULL; + ps->next_screen = SCREEN_FUN_NULL; + + saved_screen = opt_screen; + + if((kw=choose_list_of_keywords()) != NULL){ + for(i = 0; kw[i]; i++){ + esc = add_roletake_escapes(kw[i]); + fs_give((void **) &kw[i]); + kw[i] = esc; + } + + /* eliminate duplicates before the add */ + lval = LVAL((*cl)->var, ew); + if(lval && *lval){ + for(i = 0; kw[i]; ){ + /* if kw[i] is a dup, eliminate it */ + for(j = 0; lval[j]; j++) + if(!strcmp(kw[i], lval[j])) + break; + + if(lval[j]){ /* it is a dup */ + for(j = i; kw[j]; j++) + kw[j] = kw[j+1]; + } + else + i++; + } + } + + if(kw[0]) + config_add_list(ps, cl, kw, NULL, 0); + + fs_give((void **) &kw); + + if((*cl)->value) + fs_give((void **) &((*cl)->value)); + + (*cl)->value = pretty_value(ps, *cl); + rv = 1; + } + else{ + ps->next_screen = prev_screen; + ps->redrawer = redraw; + rv = 0; + } + + opt_screen = saved_screen; + } + + ps->mangled_screen = 1; + break; + + case MC_EDIT : + case MC_ADD : + case MC_DELETE : + case MC_NOT : + rv = role_text_tool(ps, cmd, cl, flags); + ps->mangled_screen = 1; + break; + + case MC_EXIT : + default : + rv = role_text_tool(ps, cmd, cl, flags); + break; + } + + return(rv); +} + + +/* + */ +int +role_text_tool_charset(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) +{ + int i, j, rv = -1; + char **lval; + + switch(cmd){ + case MC_CHOICE : /* Choose charsets from list and add them */ + {void (*prev_screen)(struct pine *) = ps->prev_screen, + (*redraw)(void) = ps->redrawer; + OPT_SCREEN_S *saved_screen; + char *esc; + char **kw; + + ps->redrawer = NULL; + ps->next_screen = SCREEN_FUN_NULL; + + saved_screen = opt_screen; + + if((kw=choose_list_of_charsets()) != NULL){ + for(i = 0; kw[i]; i++){ + esc = add_roletake_escapes(kw[i]); + fs_give((void **) &kw[i]); + kw[i] = esc; + } + + /* eliminate duplicates before the add */ + lval = LVAL((*cl)->var, ew); + if(lval && *lval){ + for(i = 0; kw[i]; ){ + /* if kw[i] is a dup, eliminate it */ + for(j = 0; lval[j]; j++) + if(!strcmp(kw[i], lval[j])) + break; + + if(lval[j]){ /* it is a dup */ + for(j = i; kw[j]; j++) + kw[j] = kw[j+1]; + } + else + i++; + } + } + + if(kw[0]) + config_add_list(ps, cl, kw, NULL, 0); + + fs_give((void **) &kw); + + if((*cl)->value) + fs_give((void **) &((*cl)->value)); + + (*cl)->value = pretty_value(ps, *cl); + rv = 1; + } + else{ + ps->next_screen = prev_screen; + ps->redrawer = redraw; + rv = 0; + } + + opt_screen = saved_screen; + } + + ps->mangled_screen = 1; + break; + + case MC_EDIT : + case MC_ADD : + case MC_DELETE : + case MC_NOT : + rv = role_text_tool(ps, cmd, cl, flags); + ps->mangled_screen = 1; + break; + + case MC_EXIT : + default : + rv = role_text_tool(ps, cmd, cl, flags); + break; + } + + return(rv); +} + + +/* + * Choose an address book nickname + */ +int +role_text_tool_afrom(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) +{ + int rv = -1; + + switch(cmd){ + case MC_EXIT : + rv = role_text_tool(ps, cmd, cl, flags); + break; + + case MC_CHOICE : /* Choose an addressbook */ + {OPT_SCREEN_S *saved_screen; + char *abook = NULL, *abookesc = NULL; + + ps->redrawer = NULL; + ps->next_screen = SCREEN_FUN_NULL; + saved_screen = opt_screen; + + abook = abook_select_screen(ps); + if(abook){ + abookesc = add_comma_escapes(abook); + fs_give((void**) &abook); + } + + ps->mangled_screen = 1; + if(abookesc && *abookesc && (*cl)->var && (*cl)->var->is_list){ + char **ltmp; + + ltmp = (char **) fs_get(2 * sizeof(char *)); + ltmp[0] = abookesc; + ltmp[1] = NULL; + abookesc = NULL; + + if(ltmp && ltmp[0]) + config_add_list(ps, cl, ltmp, NULL, 0); + + if(ltmp) + fs_give((void **) <mp); + + if((*cl)->value) + fs_give((void **) &((*cl)->value)); + + (*cl)->value = pretty_value(ps, *cl); + rv = 1; + } + else + rv = 0; + + if(abookesc) + fs_give((void **) &abookesc); + + opt_screen = saved_screen; + } + + ps->mangled_screen = 1; + break; + + default : + rv = text_tool(ps, cmd, cl, flags); + ps->mangled_screen = 1; + break; + } + + return(rv); +} + + +/* + * Args fmt -- a printf style fmt string with a single %s + * buf -- place to put result, assumed large enough (strlen(fmt)+11) + * rflags -- controls what goes in buf + * + * Returns -- pointer to buf + */ +char * +role_type_print(char *buf, size_t buflen, char *fmt, long int rflags) +{ +#define CASE_MIXED 1 +#define CASE_UPPER 2 +#define CASE_LOWER 3 + int cas = CASE_UPPER; + int prev_word_is_a = 0; + char *q, *p; + + /* find %sRule to see what case */ + if((p = srchstr(fmt, "%srule")) != NULL){ + if(p[2] == 'R'){ + if(p[3] == 'U') + cas = CASE_UPPER; + else + cas = CASE_MIXED; + } + else + cas = CASE_LOWER; + + if(p-3 >= fmt && + p[-1] == SPACE && + (p[-2] == 'a' || p[-2] == 'A') + && p[-3] == SPACE) + prev_word_is_a++; + } + + if(cas == CASE_UPPER) + q = (rflags & ROLE_DO_INCOLS) ? "INDEX COLOR " : + (rflags & ROLE_DO_FILTER) ? "FILTERING " : + (rflags & ROLE_DO_SCORES) ? "SCORING " : + (rflags & ROLE_DO_OTHER) ? "OTHER " : + (rflags & ROLE_DO_SRCH) ? "SEARCH " : + (rflags & ROLE_DO_ROLES) ? "ROLE " : ""; + else if(cas == CASE_LOWER) + q = (rflags & ROLE_DO_INCOLS) ? "index color " : + (rflags & ROLE_DO_FILTER) ? "filtering " : + (rflags & ROLE_DO_SCORES) ? "scoring " : + (rflags & ROLE_DO_OTHER) ? "other " : + (rflags & ROLE_DO_OTHER) ? "search " : + (rflags & ROLE_DO_ROLES) ? "role " : ""; + else + q = (rflags & ROLE_DO_INCOLS) ? "Index Color " : + (rflags & ROLE_DO_FILTER) ? "Filtering " : + (rflags & ROLE_DO_SCORES) ? "Scoring " : + (rflags & ROLE_DO_OTHER) ? "Other " : + (rflags & ROLE_DO_OTHER) ? "Search " : + (rflags & ROLE_DO_ROLES) ? "Role " : ""; + + /* it ain't right to say "a index" */ + if(prev_word_is_a && !struncmp(q, "index", 5)) + q += 6; + + snprintf(buf, buflen, fmt, q); + buf[buflen-1] = '\0'; + return(buf); +} + + +/* + * filter option list manipulation tool + * + * + * returns: -1 on unrecognized cmd, 0 if no change, 1 if change + */ +int +feat_checkbox_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) +{ + int rv = 0; + + switch(cmd){ + case MC_TOGGLE: /* mark/unmark option */ + rv = 1; + toggle_feat_option_bit(ps, (*cl)->varmem, (*cl)->var, (*cl)->value); + break; + + case MC_EXIT: /* exit */ + rv = role_filt_exitcheck(cl, flags); + break; + + default : + rv = -1; + break; + } + + return(rv); +} + + +void +toggle_feat_option_bit(struct pine *ps, int index, struct variable *var, char *value) +{ + NAMEVAL_S *f; + + f = feat_feature_list(index); + + /* flip the bit */ + if(bitnset(f->value, feat_option_list)) + clrbitn(f->value, feat_option_list); + else + setbitn(f->value, feat_option_list); + + if(value) + value[1] = bitnset(f->value, feat_option_list) ? 'X' : ' '; +} + + +NAMEVAL_S * +feat_feature_list(int index) +{ + static NAMEVAL_S opt_feat_list[] = { + {"use-date-header-for-age", NULL, FEAT_SENTDATE}, + {"move-only-if-not-deleted", NULL, FEAT_IFNOTDEL}, + {"dont-stop-even-if-rule-matches", NULL, FEAT_NONTERM} + }; + + return((index >= 0 && + index < (sizeof(opt_feat_list)/sizeof(opt_feat_list[0]))) + ? &opt_feat_list[index] : NULL); +} + + +/* + * address type list manipulation tool + * + * + * returns: -1 on unrecognized cmd, 0 if no change, 1 if change + */ +int +inabook_checkbox_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) +{ + int rv = 0; + + switch(cmd){ + case MC_TOGGLE: /* mark/unmark option */ + rv = 1; + toggle_inabook_type_bit(ps, (*cl)->varmem, (*cl)->var, (*cl)->value); + break; + + case MC_EXIT: /* exit */ + rv = role_filt_exitcheck(cl, flags); + break; + + default : + rv = -1; + break; + } + + return(rv); +} + + +void +toggle_inabook_type_bit(struct pine *ps, int index, struct variable *var, char *value) +{ + NAMEVAL_S *f; + + f = inabook_feature_list(index); + + /* flip the bit */ + if(bitnset(f->value, inabook_type_list)) + clrbitn(f->value, inabook_type_list); + else + setbitn(f->value, inabook_type_list); + + if(value) + value[1] = bitnset(f->value, inabook_type_list) ? 'X' : ' '; +} + + +NAMEVAL_S * +inabook_feature_list(int index) +{ + static NAMEVAL_S inabook_feat_list[] = { + {"From", NULL, INABOOK_FROM}, + {"Reply-To", NULL, INABOOK_REPLYTO}, + {"Sender", NULL, INABOOK_SENDER}, + {"To", NULL, INABOOK_TO}, + {"Cc", NULL, INABOOK_CC} + }; + + return((index >= 0 && + index < (sizeof(inabook_feat_list)/sizeof(inabook_feat_list[0]))) + ? &inabook_feat_list[index] : NULL); +} |