Add support for tab-completion when selecting by rule
[alpine.git] / alpine / roleconf.c
blobd3cc207852e54f11aff14d51cfd56f798f95bcf5
1 /*
2 * ========================================================================
3 * Copyright 2006-2008 University of Washington
4 * Copyright 2013-2022 Eduardo Chappa
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
15 #include "headers.h"
16 #include "roleconf.h"
17 #include "colorconf.h"
18 #include "conftype.h"
19 #include "confscroll.h"
20 #include "keymenu.h"
21 #include "status.h"
22 #include "radio.h"
23 #include "reply.h"
24 #include "folder.h"
25 #include "addrbook.h"
26 #include "mailcmd.h"
27 #include "setup.h"
28 #include "../pith/state.h"
29 #include "../pith/conf.h"
30 #include "../pith/msgno.h"
31 #include "../pith/bitmap.h"
32 #include "../pith/sort.h"
33 #include "../pith/addrstring.h"
34 #include "../pith/list.h"
35 #include "../pith/flag.h"
36 #include "../pith/bldaddr.h"
37 #include "../pith/news.h"
38 #include "../pith/util.h"
39 #include "../pith/detoken.h"
40 #include "../pith/icache.h"
41 #include "../pith/ablookup.h"
42 #include "../pith/pattern.h"
43 #include "../pith/tempfile.h"
46 #define NOT "! "
47 #define NOTLEN 2
50 #define ARB_HELP _("HELP FOR ARBITRARY HEADER PATTERNS")
51 #define ADDXHDRS _("Add Extra Headers")
55 * Internal prototypes
57 int role_select_tool(struct pine *, int, CONF_S **, unsigned);
58 PATTERN_S *addrlst_to_pattern(ADDRESS *);
59 void role_config_init_disp(struct pine *, CONF_S **, long, PAT_STATE *);
60 void add_patline_to_display(struct pine *, CONF_S **, int, CONF_S **, CONF_S **, PAT_LINE_S *, long);
61 void add_role_to_display(CONF_S **, PAT_LINE_S *, PAT_S *, int, CONF_S **, int, long);
62 void add_fake_first_role(CONF_S **, int, long);
63 int role_config_tool(struct pine *, int, CONF_S **, unsigned);
64 int role_config_add(struct pine *, CONF_S **, long);
65 int role_config_replicate(struct pine *, CONF_S **, long);
66 int role_config_edit(struct pine *, CONF_S **, long);
67 int role_config_del(struct pine *, CONF_S **, long);
68 void delete_a_role(CONF_S **, long);
69 int role_config_shuffle(struct pine *, CONF_S **);
70 int role_config_addfile(struct pine *, CONF_S **, long);
71 int role_config_delfile(struct pine *, CONF_S **, long);
72 void swap_literal_roles(CONF_S *, CONF_S *);
73 void swap_file_roles(CONF_S *, CONF_S *);
74 void move_role_into_file(CONF_S **, int);
75 void move_role_outof_file(CONF_S **, int);
76 void move_role_around_file(CONF_S **, int);
77 int role_config_edit_screen(struct pine *, PAT_S *, char *, long, PAT_S **);
78 void setup_dummy_pattern_var(struct variable *, char *, PATTERN_S *);
79 void setup_role_pat(struct pine *, CONF_S **, struct variable *, HelpType, char *,
80 struct key_menu *,
81 int (*tool)(struct pine *, int, CONF_S **, unsigned),
82 EARB_S **, int);
83 void setup_role_pat_alt(struct pine *, CONF_S **, struct variable *, HelpType, char *,
84 struct key_menu *,
85 int (*tool)(struct pine *, int, CONF_S **, unsigned),
86 int, int);
87 void free_earb(EARB_S **);
88 void calculate_inick_stuff(struct pine *);
89 int check_role_folders(char **, unsigned);
90 void maybe_add_to_incoming(CONTEXT_S *, char *);
91 int role_filt_exitcheck(CONF_S **, unsigned);
92 int role_filt_text_tool(struct pine *, int, CONF_S **, unsigned);
93 int role_filt_addhdr_tool(struct pine *, int, CONF_S **, unsigned);
94 int role_addhdr_tool(struct pine *, int, CONF_S **, unsigned);
95 int role_filt_radiobutton_tool(struct pine *, int, CONF_S **, unsigned);
96 int role_sort_tool(struct pine *, int, CONF_S **, unsigned);
97 char **get_role_specific_folder(CONF_S **);
98 int role_litsig_text_tool(struct pine *, int, CONF_S **, unsigned);
99 int role_cstm_text_tool(struct pine *, int, CONF_S **, unsigned);
100 int role_text_tool(struct pine *, int, CONF_S **, unsigned);
101 int role_text_tool_inick(struct pine *, int, CONF_S **, unsigned);
102 int role_text_tool_kword(struct pine *, int, CONF_S **, unsigned);
103 int role_text_tool_charset(struct pine *, int, CONF_S **, unsigned);
104 int role_text_tool_afrom(struct pine *, int, CONF_S **, unsigned);
105 char *role_type_print(char *, size_t, char *, long);
106 int feat_checkbox_tool(struct pine *, int, CONF_S **, unsigned);
107 void toggle_feat_option_bit(struct pine *, int, struct variable *, char *);
108 NAMEVAL_S *feat_feature_list(int);
109 int inabook_checkbox_tool(struct pine *, int, CONF_S **, unsigned);
110 void toggle_inabook_type_bit(struct pine *, int, struct variable *, char *);
111 NAMEVAL_S *inabook_feature_list(int);
114 static char *set_choose = "--- --------------------";
115 static long role_global_flags;
116 static PAT_STATE *role_global_pstate;
120 role_select_screen(struct pine *ps, ACTION_S **role, int alt_compose)
122 CONF_S *ctmp = NULL, *first_line = NULL;
123 OPT_SCREEN_S screen;
124 PAT_S *pat, *sel_pat = NULL;
125 int ret = -1;
126 int change_default = 0;
127 long rflags = ROLE_DO_ROLES;
128 char *helptitle;
129 HelpType help;
130 PAT_STATE pstate;
132 if(!role)
133 return(ret);
135 *role = NULL;
137 if(!(nonempty_patterns(rflags, &pstate) &&
138 first_pattern(&pstate))){
139 q_status_message(SM_ORDER, 3, 3,
140 _("No roles available. Use Setup/Rules to add roles."));
141 return(ret);
145 if(alt_compose){
146 menu_init_binding(&role_select_km,
147 alt_compose == MC_FORWARD ? 'F' :
148 alt_compose == MC_REPLY ? 'R' :
149 alt_compose == MC_COMPOSE ? 'C' : 'B',
150 MC_CHOICE,
151 alt_compose == MC_FORWARD ? "F" :
152 alt_compose == MC_REPLY ? "R" :
153 alt_compose == MC_COMPOSE ? "C" : "B",
154 alt_compose == MC_FORWARD ? "[" N_("ForwardAs") "]" :
155 alt_compose == MC_REPLY ? "[" N_("ReplyAs") "]" :
156 alt_compose == MC_COMPOSE ? "[" N_("ComposeAs") "]" : "[" N_("BounceAs") "]",
157 DEFAULT_KEY);
158 menu_add_binding(&role_select_km, ctrl('J'), MC_CHOICE);
159 menu_add_binding(&role_select_km, ctrl('M'), MC_CHOICE);
161 else{
162 menu_init_binding(&role_select_km, 'S', MC_CHOICE, "S", "[" N_("Select") "]",
163 DEFAULT_KEY);
164 menu_add_binding(&role_select_km, ctrl('J'), MC_CHOICE);
165 menu_add_binding(&role_select_km, ctrl('M'), MC_CHOICE);
168 help = h_role_select;
169 if(alt_compose == MC_BOUNCE)
170 helptitle = _("HELP FOR SELECTING A ROLE TO BOUNCE AS");
171 else if(alt_compose)
172 helptitle = _("HELP FOR SELECTING A ROLE TO COMPOSE AS");
173 else
174 helptitle = _("HELP FOR SELECTING A ROLE");
176 menu_init_binding(&role_select_km, 'D', MC_TOGGLE, "D", "changeDef", CHANGEDEF_KEY);
178 for(pat = first_pattern(&pstate);
179 pat;
180 pat = next_pattern(&pstate)){
181 new_confline(&ctmp);
182 if(!first_line)
183 first_line = ctmp;
185 ctmp->value = cpystr((pat->patgrp && pat->patgrp->nick)
186 ? pat->patgrp->nick : "?");
187 ctmp->d.r.selected = &sel_pat;
188 ctmp->d.r.pat = pat;
189 ctmp->d.r.change_def = &change_default;
190 ctmp->keymenu = &role_select_km;
191 ctmp->help = help;
192 ctmp->help_title = helptitle;
193 ctmp->tool = role_select_tool;
194 ctmp->flags = CF_STARTITEM;
195 ctmp->valoffset = 4;
198 memset(&screen, 0, sizeof(screen));
199 /* TRANSLATORS: Print something1 using something2.
200 "roles" is something1 */
201 (void)conf_scroll_screen(ps, &screen, first_line, _("SELECT ROLE"),
202 _("roles"), 0, NULL);
204 if(sel_pat){
205 *role = sel_pat->action;
206 if(change_default == 1)
207 ps_global->default_role = *role;
208 else if(change_default == 2)
209 ps_global->default_role = NULL;
211 ret = 0;
214 ps->mangled_screen = 1;
215 return(ret);
220 role_select_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
222 int retval = 0, newval;
224 switch(cmd){
225 case MC_CHOICE :
226 *((*cl)->d.r.selected) = (*cl)->d.r.pat;
227 retval = simple_exit_cmd(flags);
228 break;
230 case MC_TOGGLE :
231 newval = (*((*cl)->d.r.change_def) + 1) % 3;
232 *((*cl)->d.r.change_def) = newval;
233 menu_init_binding((*cl)->keymenu, 'D', MC_TOGGLE, "D",
234 (newval == 0) ? "changeDef" : (newval == 1) ? "removeDef" : "leaveDef",
235 CHANGEDEF_KEY);
236 if(newval == 1){
237 if(ps_global->default_role)
238 q_status_message(SM_ORDER, 0, 3,
239 _("Default role will be changed to the role you Select"));
240 else
241 q_status_message(SM_ORDER, 0, 3,
242 _("Default role will be set to the role you Select"));
244 else if(newval == 2){
245 q_status_message(SM_ORDER, 0, 3, _("Default role will be unset"));
247 else{ /* newval == 0 */
248 if(ps_global->default_role)
249 q_status_message(SM_ORDER, 0, 3, _("Default role will remain unchanged"));
250 else
251 q_status_message(SM_ORDER, 0, 3, _("Default role will remain unset"));
254 ps->mangled_footer = 1;
255 retval = 0;
256 break;
258 case MC_EXIT :
259 retval = simple_exit_cmd(flags);
260 break;
262 default:
263 retval = -1;
264 break;
267 if(retval > 0)
268 ps->mangled_body = 1;
270 return(retval);
274 void
275 role_config_screen(struct pine *ps, long int rflags, int edit_exceptions)
277 CONF_S *first_line;
278 OPT_SCREEN_S screen;
279 char title[100];
280 int readonly_warning = 0;
281 PAT_STATE pstate;
282 struct variable *v = NULL;
284 dprint((4, "role_config_screen()\n"));
286 if(ps->fix_fixed_warning)
287 offer_to_fix_pinerc(ps);
289 ew = edit_exceptions ? ps_global->ew_for_except_vars : Main;
291 if(ps->restricted)
292 readonly_warning = 1;
293 else{
294 PINERC_S *prc = NULL;
296 switch(ew){
297 case Main:
298 prc = ps->prc;
299 rflags |= PAT_USE_MAIN;
300 break;
301 case Post:
302 prc = ps->post_prc;
303 rflags |= PAT_USE_POST;
304 break;
305 default:
306 break;
309 readonly_warning = prc ? prc->readonly : 1;
310 if(prc && prc->quit_to_edit){
311 quit_to_edit_msg(prc);
312 return;
316 if(!any_patterns(rflags, &pstate))
317 return;
319 if(rflags & ROLE_DO_ROLES)
320 v = &ps_global->vars[V_PAT_ROLES];
321 else if(rflags & ROLE_DO_INCOLS)
322 v = &ps_global->vars[V_PAT_INCOLS];
323 else if(rflags & ROLE_DO_OTHER)
324 v = &ps_global->vars[V_PAT_OTHER];
325 else if(rflags & ROLE_DO_SCORES)
326 v = &ps_global->vars[V_PAT_SCORES];
327 else if(rflags & ROLE_DO_FILTER)
328 v = &ps_global->vars[V_PAT_FILTS];
329 else if(rflags & ROLE_DO_SRCH)
330 v = &ps_global->vars[V_PAT_SRCH];
332 if((ps_global->ew_for_except_vars != Main) && (ew == Main)){
333 char **lval;
335 if((lval=LVAL(v, ps_global->ew_for_except_vars)) &&
336 lval[0] && strcmp(INHERIT, lval[0]) != 0){
337 role_type_print(title, sizeof(title), _("Warning: \"%sRules\" are overridden in your exceptions configuration"), rflags);
338 q_status_message(SM_ORDER, 7, 7, title);
342 role_type_print(title, sizeof(title), "%sRules", rflags);
343 if(fixed_var(v, "change", title))
344 return;
346 uh_oh:
347 first_line = NULL;
349 snprintf(title, sizeof(title), "SETUP%s ", edit_exceptions ? " EXCEPTIONAL" : "");
350 title[sizeof(title)-1] = '\0';
351 role_type_print(title+strlen(title), sizeof(title)-strlen(title), "%sRULES", rflags);
352 role_global_flags = rflags;
353 role_global_pstate = &pstate;
354 role_config_init_disp(ps, &first_line, rflags, &pstate);
356 if(!first_line){
357 role_global_flags = 0;
358 ps->mangled_screen = 1;
359 q_status_message(SM_ORDER,5,5,
360 _("Unexpected problem: config file modified externally?"));
361 q_status_message1(SM_ORDER,5,5,
362 _("Perhaps a newer version of pine was used to set variable \"%s\"?"),
363 v ? v->name : "?");
364 dprint((1, "Unexpected problem: config file modified externally?\nPerhaps by a newer pine? Variable \"%s\" has unexpected contents.\n",
365 (v && v->name) ? v->name : "?"));
366 return;
369 memset(&screen, 0, sizeof(screen));
370 screen.deferred_ro_warning = readonly_warning;
371 /* TRANSLATORS: Print something1 using something2.
372 "rules" is something1 */
373 switch(conf_scroll_screen(ps, &screen, first_line, title, _("rules"), 0, NULL)){
374 case 0:
375 break;
377 case 10:
378 /* flush changes and re-read orig */
379 close_patterns(rflags);
380 break;
382 case 1:
383 if(write_patterns(rflags))
384 goto uh_oh;
387 * Flush out current_vals of anything we've possibly changed.
390 if(ps_global->default_role){
391 q_status_message(SM_ORDER,0,3, "Default role is unset");
392 ps_global->default_role = NULL;
395 close_patterns((rflags & ROLE_MASK) | PAT_USE_CURRENT);
397 /* scores may have changed */
398 if(rflags & ROLE_DO_SCORES){
399 int i;
400 MAILSTREAM *m;
402 for(i = 0; i < ps_global->s_pool.nstream; i++){
403 m = ps_global->s_pool.streams[i];
404 if(m){
405 clear_folder_scores(m);
406 clear_index_cache(m, 0);
410 if(mn_get_sort(sp_msgmap(ps_global->mail_stream)) == SortScore)
411 refresh_sort(ps_global->mail_stream,
412 sp_msgmap(ps_global->mail_stream), SRT_VRB);
415 /* recalculate need for scores */
416 scores_are_used(SCOREUSE_INVALID);
418 /* we may want to fetch more or fewer headers each fetch */
419 calc_extra_hdrs();
420 if(get_extra_hdrs())
421 (void) mail_parameters(NULL, SET_IMAPEXTRAHEADERS,
422 (void *) get_extra_hdrs());
424 if(rflags & ROLE_DO_INCOLS && pico_usingcolor())
425 clear_index_cache(ps_global->mail_stream, 0);
427 if(rflags & ROLE_DO_FILTER)
428 role_process_filters();
431 * ROLE_DO_OTHER is made up of a bunch of different variables
432 * that may have changed. Assume they all changed and fix them.
434 if(rflags & ROLE_DO_OTHER){
435 reset_index_format();
436 clear_index_cache(ps_global->mail_stream, 0);
437 if(!mn_get_mansort(ps_global->msgmap))
438 reset_sort_order(SRT_VRB);
441 break;
443 default:
444 q_status_message(SM_ORDER,7,10, "conf_scroll_screen unexpected ret");
445 break;
448 role_global_flags = 0;
449 ps->mangled_screen = 1;
454 * This is called from process_cmd to add a new pattern to the end of the
455 * list of patterns. The pattern is seeded with values from the current
456 * message.
458 void
459 role_take(struct pine *ps, MSGNO_S *msgmap, int rtype)
461 PAT_S *defpat, *newpat = NULL;
462 PAT_LINE_S *new_patline, *patline;
463 ENVELOPE *env = NULL;
464 long rflags;
465 char *s, title[100], specific_fldr[MAXPATH+1];
466 PAT_STATE pstate;
467 EditWhich ew;
469 dprint((4, "role_take()\n"));
471 if(mn_get_cur(msgmap) > 0){
472 env = pine_mail_fetchstructure(ps->mail_stream,
473 mn_m2raw(msgmap, mn_get_cur(msgmap)),
474 NULL);
476 if(!env){
477 q_status_message(SM_ORDER, 3, 7,
478 _("problem getting addresses from message"));
479 return;
483 switch(rtype){
484 case 'r':
485 rflags = ROLE_DO_ROLES;
486 ew = ps_global->ew_for_role_take;
487 break;
488 case 's':
489 rflags = ROLE_DO_SCORES;
490 ew = ps_global->ew_for_score_take;
491 break;
492 case 'i':
493 rflags = ROLE_DO_INCOLS;
494 ew = ps_global->ew_for_incol_take;
495 break;
496 case 'f':
497 rflags = ROLE_DO_FILTER;
498 ew = ps_global->ew_for_filter_take;
499 break;
500 case 'o':
501 rflags = ROLE_DO_OTHER;
502 ew = ps_global->ew_for_other_take;
503 break;
504 case 'c':
505 rflags = ROLE_DO_SRCH;
506 ew = ps_global->ew_for_srch_take;
507 break;
509 default:
510 cmd_cancelled(NULL);
511 return;
514 switch(ew){
515 case Main:
516 rflags |= PAT_USE_MAIN;
517 break;
518 case Post:
519 rflags |= PAT_USE_POST;
520 break;
521 default:
522 break;
525 if(!any_patterns(rflags, &pstate)){
526 q_status_message(SM_ORDER, 3, 7, _("problem accessing rules"));
527 return;
530 /* set this so that even if we don't edit at all, we'll be asked */
531 rflags |= ROLE_CHANGES;
534 * Make a pattern out of the information in the envelope and
535 * use that as the default pattern we give to the role editor.
536 * It will have a pattern but no actions set.
538 defpat = (PAT_S *)fs_get(sizeof(*defpat));
539 memset((void *)defpat, 0, sizeof(*defpat));
541 defpat->patgrp = (PATGRP_S *)fs_get(sizeof(*defpat->patgrp));
542 memset((void *)defpat->patgrp, 0, sizeof(*defpat->patgrp));
544 if(env){
545 if(env->to)
546 defpat->patgrp->to = addrlst_to_pattern(env->to);
548 if(env->from)
549 defpat->patgrp->from = addrlst_to_pattern(env->from);
551 if(env->cc)
552 defpat->patgrp->cc = addrlst_to_pattern(env->cc);
554 if(env->sender &&
555 (!env->from || !address_is_same(env->sender, env->from)))
556 defpat->patgrp->sender = addrlst_to_pattern(env->sender);
559 * Env->newsgroups is already comma-separated and there shouldn't be
560 * any commas or backslashes in newsgroup names, so we don't add the
561 * roletake escapes.
563 if(env->newsgroups)
564 defpat->patgrp->news = string_to_pattern(env->newsgroups);
567 * Subject may have commas or backslashes, so we add escapes.
569 if(env->subject){
570 char *q, *t = NULL;
573 * Mail_strip_subject not only strips the Re's and Fwd's but
574 * it also canonicalizes to UTF-8.
576 mail_strip_subject(env->subject, &q);
577 if(q != NULL){
578 t = add_roletake_escapes(q);
579 fs_give((void **)&q);
582 if(t){
583 defpat->patgrp->subj = string_to_pattern(t);
584 fs_give((void **)&t);
589 if(IS_NEWS(ps->mail_stream))
590 defpat->patgrp->fldr_type = FLDR_NEWS;
591 else
592 defpat->patgrp->fldr_type = FLDR_EMAIL;
594 specific_fldr[0] = specific_fldr[sizeof(specific_fldr)-1] = '\0';
595 if(sp_flagged(ps->mail_stream, SP_INBOX))
596 strncpy(specific_fldr, ps_global->inbox_name, sizeof(specific_fldr)-1);
597 else if(ps->context_current
598 && ps->context_current->use & CNTXT_INCMNG &&
599 folder_is_nick(ps->cur_folder, FOLDERS(ps->context_current), 0))
600 strncpy(specific_fldr, ps->cur_folder, sizeof(specific_fldr)-1);
601 else
602 context_apply(specific_fldr, ps->context_current, ps->cur_folder,
603 sizeof(specific_fldr));
605 if(specific_fldr[0]){
606 s = add_comma_escapes(specific_fldr);
607 if(s){
608 if(rtype == 'f')
609 defpat->patgrp->fldr_type = FLDR_SPECIFIC;
611 defpat->patgrp->folder = string_to_pattern(s);
612 fs_give((void **)&s);
616 role_type_print(title, sizeof(title), "ADD NEW %sRULE", rflags);
619 * Role_config_edit_screen is sometimes called as a tool or a sub
620 * routine called from a tool within conf_scroll_screen, but here it
621 * is going to be at the top-level (we're not inside conf_scroll_screen
622 * right now). It uses opt_screen to set the ro_warning bit. We need
623 * to let it know that we're at the top, which we do by setting
624 * opt_screen to NULL. Otherwise, the thing that opt_screen is pointing
625 * to is just random stack stuff from some previous conf_scroll_screen
626 * call which has already exited.
628 opt_screen = NULL;
630 if(role_config_edit_screen(ps, defpat, title, rflags,
631 &newpat) == 1 && newpat){
633 if(ps->never_allow_changing_from && newpat->action &&
634 newpat->action->from)
635 q_status_message(SM_ORDER|SM_DING, 3, 7,
636 _("Site policy doesn't allow changing From address so From is ignored"));
638 if(rflags & ROLE_DO_ROLES && newpat->patgrp && newpat->patgrp->nick){
639 PAT_S *pat;
641 for(pat = first_pattern(&pstate);
642 pat;
643 pat = next_pattern(&pstate)){
644 if(pat->patgrp && pat->patgrp->nick &&
645 !strucmp(pat->patgrp->nick, newpat->patgrp->nick)){
646 q_status_message(SM_ORDER|SM_DING, 3, 7, _("Warning: The nickname of the new role is already in use."));
647 break;
653 set_pathandle(rflags);
655 /* need a new patline */
656 new_patline = (PAT_LINE_S *)fs_get(sizeof(*new_patline));
657 memset((void *)new_patline, 0, sizeof(*new_patline));
658 new_patline->type = Literal;
659 (*cur_pat_h)->dirtypinerc = 1;
661 /* tie together with new pattern */
662 new_patline->first = new_patline->last = newpat;
663 newpat->patline = new_patline;
665 /* find last current patline */
666 for(patline = (*cur_pat_h)->patlinehead;
667 patline && patline->next;
668 patline = patline->next)
671 /* add new patline to end of list */
672 if(patline){
673 patline->next = new_patline;
674 new_patline->prev = patline;
676 else
677 (*cur_pat_h)->patlinehead = new_patline;
679 if(write_patterns(rflags) == 0){
680 char msg[60];
683 * Flush out current_vals of anything we've possibly changed.
686 if(rflags & ROLE_DO_ROLES && ps_global->default_role){
687 q_status_message(SM_ORDER,0,3, "Default role is unset");
688 ps_global->default_role = NULL;
691 close_patterns(rflags | PAT_USE_CURRENT);
693 role_type_print(msg, sizeof(msg), "New %srule saved", rflags);
694 q_status_message(SM_ORDER, 0, 3, msg);
696 /* scores may have changed */
697 if(rflags & ROLE_DO_SCORES){
698 int i;
699 MAILSTREAM *m;
701 for(i = 0; i < ps_global->s_pool.nstream; i++){
702 m = ps_global->s_pool.streams[i];
703 if(m){
704 clear_folder_scores(m);
705 clear_index_cache(m, 0);
709 /* We've already bound msgmap to global mail_stream
710 * at the start of this function, but if we wanted to
711 * we could clean this up.
713 if(mn_get_sort(msgmap) == SortScore)
714 refresh_sort(ps_global->mail_stream, msgmap, SRT_VRB);
717 if(rflags & ROLE_DO_FILTER)
718 role_process_filters();
720 /* recalculate need for scores */
721 scores_are_used(SCOREUSE_INVALID);
723 /* we may want to fetch more or fewer headers each fetch */
724 calc_extra_hdrs();
725 if(get_extra_hdrs())
726 (void) mail_parameters(NULL, SET_IMAPEXTRAHEADERS,
727 (void *) get_extra_hdrs());
729 if(rflags & ROLE_DO_INCOLS && pico_usingcolor())
730 clear_index_cache(ps_global->mail_stream, 0);
733 * ROLE_DO_OTHER is made up of a bunch of different variables
734 * that may have changed. Assume they all changed and fix them.
736 if(rflags & ROLE_DO_OTHER){
737 reset_index_format();
738 clear_index_cache(ps_global->mail_stream, 0);
739 if(!mn_get_mansort(msgmap))
740 reset_sort_order(SRT_VRB);
744 else
745 cmd_cancelled(NULL);
747 free_pat(&defpat);
748 ps->mangled_screen = 1;
752 PATTERN_S *
753 addrlst_to_pattern(struct mail_address *addr)
755 char *s, *t, *u, *v;
756 PATTERN_S *p = NULL;
757 size_t l;
759 if(addr){
760 l = est_size(addr);
761 t = s = (char *) fs_get((l+1) * sizeof(char));
762 s[0] = '\0';
763 while(addr){
764 u = simple_addr_string(addr, tmp_20k_buf, SIZEOF_20KBUF);
765 v = add_roletake_escapes(u);
766 if(v){
767 if(*v && t != s)
768 sstrncpy(&t, ",", l-(t-s));
770 sstrncpy(&t, v, l-(t-s));
771 fs_give((void **)&v);
774 addr = addr->next;
777 s[l] = '\0';
779 if(*s)
780 p = string_to_pattern(s);
782 fs_give((void **) &s);
785 return(p);
789 void
790 role_config_init_disp(struct pine *ps, CONF_S **first_line, long int rflags, PAT_STATE *pstate)
792 PAT_LINE_S *patline;
793 CONF_S *ctmp = NULL;
794 int inherit = 0, added_fake = 0;
796 if(first_line)
797 *first_line = NULL;
800 * Set cur_pat_h and manipulate directly.
802 set_pathandle(rflags);
803 patline = *cur_pat_h ? (*cur_pat_h)->patlinehead : NULL;
804 if(patline && patline->type == Inherit){
805 add_patline_to_display(ps, &ctmp, 0, first_line, NULL, patline, rflags);
806 patline = patline->next;
809 if(!patline){
810 add_fake_first_role(&ctmp, 0, rflags);
811 added_fake++;
812 if(first_line && !*first_line)
813 (*first_line) = ctmp;
816 for(; patline; patline = patline->next)
817 add_patline_to_display(ps, &ctmp, 0, first_line, NULL, patline, rflags);
820 * If there are no actual patterns so far, we need to have an Add line
821 * for the cursor to be on. This would happen if all of the patlines
822 * were File includes and none of the files contained patterns.
824 if(!first_pattern(role_global_pstate) ||
825 ((inherit=first_pattern(role_global_pstate)->inherit) &&
826 !next_pattern(role_global_pstate))){
829 * Find the start and prepend the fake first role.
831 while(ctmp && ctmp->prev)
832 ctmp = ctmp->prev;
834 if(!added_fake){
835 add_fake_first_role(&ctmp, inherit ? 0 : 1, rflags);
836 if(first_line && !*first_line)
837 (*first_line) = ctmp;
843 void
844 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)
846 PAT_S *pat;
847 int len, firstitem, wid;
848 char *q;
849 char buf[6*MAX_SCREEN_COLS+1];
851 /* put dashed line around file contents */
852 if(patline->type == File){
854 new_confline(ctmp);
855 if(before){
857 * New_confline appends ctmp after old current instead of inserting
858 * it, so we have to adjust. We have
859 * <- a <-> b <-> p <-> c -> and want <- a <-> p <-> b <-> c ->
862 CONF_S *a, *b, *c, *p;
864 p = *ctmp;
865 b = (*ctmp)->prev;
866 c = (*ctmp)->next;
867 a = b ? b->prev : NULL;
868 if(a)
869 a->next = p;
871 if(b){
872 b->prev = p;
873 b->next = c;
876 if(c)
877 c->prev = b;
879 p->prev = a;
880 p->next = b;
883 if(top_line && *top_line == NULL)
884 *top_line = (*ctmp);
886 len = strlen(patline->filename) + 100;
888 q = (char *) fs_get((len + 1) * sizeof(char));
889 snprintf(q, len+1, "From file %s%s", patline->filename,
890 patline->readonly ? " (ReadOnly)" : "");
891 q[len-1] = '\0';
893 if((wid=utf8_width(q)) > ps->ttyo->screen_cols -2)
894 utf8_snprintf(buf, sizeof(buf), "--%.*w", ps->ttyo->screen_cols -2, q);
895 else
896 snprintf(buf, sizeof(buf), "--%s%s", q, repeat_char(ps->ttyo->screen_cols -2-wid, '-'));
898 (*ctmp)->value = cpystr(buf);
900 fs_give((void **)&q);
901 (*ctmp)->flags |= (CF_NOSELECT | CF_STARTITEM);
902 (*ctmp)->d.r.patline = patline;
903 firstitem = 0;
905 else
906 firstitem = 1;
908 for(pat = patline->first; pat; pat = pat->next){
910 /* Check that pattern has a role and is of right type */
911 if(pat->inherit ||
912 (pat->action &&
913 (((rflags & ROLE_DO_ROLES) && pat->action->is_a_role) ||
914 ((rflags & ROLE_DO_INCOLS) && pat->action->is_a_incol) ||
915 ((rflags & ROLE_DO_SRCH) && pat->action->is_a_srch) ||
916 ((rflags & ROLE_DO_OTHER) && pat->action->is_a_other) ||
917 ((rflags & ROLE_DO_SCORES) && pat->action->is_a_score) ||
918 ((rflags & ROLE_DO_FILTER) && pat->action->is_a_filter)))){
919 add_role_to_display(ctmp, patline, pat, 0,
920 (first_line && *first_line == NULL)
921 ? first_line :
922 (top_line && *top_line == NULL)
923 ? top_line : NULL,
924 firstitem, rflags);
925 firstitem = 1;
926 if(top_line && *top_line == NULL && first_line)
927 *top_line = *first_line;
932 if(patline->type == File){
933 new_confline(ctmp);
934 len = strlen(patline->filename) + 100;
936 q = (char *) fs_get((len + 1) * sizeof(char));
937 snprintf(q, len+1, "End of Rules from %s", patline->filename);
938 q[len-1] = '\0';
940 if((wid=utf8_width(q)) > ps->ttyo->screen_cols -2)
941 utf8_snprintf(buf, sizeof(buf), "--%.*w", ps->ttyo->screen_cols -2, q);
942 else
943 snprintf(buf, sizeof(buf), "--%s%s", q, repeat_char(ps->ttyo->screen_cols -2-wid, '-'));
945 (*ctmp)->value = cpystr(buf);
947 fs_give((void **)&q);
948 (*ctmp)->flags |= CF_NOSELECT;
949 (*ctmp)->d.r.patline = patline;
954 void
955 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)
957 char title[80];
959 if(!(pat && (pat->action || pat->inherit)))
960 return;
962 new_confline(ctmp);
963 if(first_line && !pat->inherit)
964 *first_line = *ctmp;
966 if(before){
968 * New_confline appends ctmp after old current instead of inserting
969 * it, so we have to adjust. We have
970 * <- a <-> b <-> p <-> c -> and want <- a <-> p <-> b <-> c ->
973 CONF_S *a, *b, *c, *p;
975 p = *ctmp;
976 b = (*ctmp)->prev;
977 c = (*ctmp)->next;
978 a = b ? b->prev : NULL;
979 if(a)
980 a->next = p;
982 if(b){
983 b->prev = p;
984 b->next = c;
987 if(c)
988 c->prev = b;
990 p->prev = a;
991 p->next = b;
994 role_type_print(title, sizeof(title), _("HELP FOR %sRULE CONFIGURATION"), rflags);
996 if(pat->inherit){
997 (*ctmp)->flags |= ((firstitem ? CF_STARTITEM : 0) |
998 CF_NOSELECT | CF_INHERIT);
1000 else{
1001 (*ctmp)->flags |= (firstitem ? CF_STARTITEM : 0);
1002 (*ctmp)->value = cpystr((pat && pat->patgrp && pat->patgrp->nick)
1003 ? pat->patgrp->nick : "?");
1006 (*ctmp)->d.r.patline = patline;
1007 (*ctmp)->d.r.pat = pat;
1008 (*ctmp)->keymenu = &role_conf_km;
1009 (*ctmp)->help = (rflags & ROLE_DO_INCOLS) ? h_rules_incols :
1010 (rflags & ROLE_DO_OTHER) ? h_rules_other :
1011 (rflags & ROLE_DO_FILTER) ? h_rules_filter :
1012 (rflags & ROLE_DO_SCORES) ? h_rules_score :
1013 (rflags & ROLE_DO_ROLES) ? h_rules_roles :
1014 (rflags & ROLE_DO_SRCH) ? h_rules_srch :
1015 NO_HELP;
1016 (*ctmp)->help_title = title;
1017 (*ctmp)->tool = role_config_tool;
1018 (*ctmp)->valoffset = 4;
1022 void
1023 add_fake_first_role(CONF_S **ctmp, int before, long int rflags)
1025 char title[80];
1026 char add[80];
1028 new_confline(ctmp);
1030 if(before){
1032 * New_confline appends ctmp after old current instead of inserting
1033 * it, so we have to adjust. We have
1034 * <- a <-> b <-> p <-> c -> and want <- a <-> p <-> b <-> c ->
1037 CONF_S *a, *b, *c, *p;
1039 p = *ctmp;
1040 b = (*ctmp)->prev;
1041 c = (*ctmp)->next;
1042 a = b ? b->prev : NULL;
1043 if(a)
1044 a->next = p;
1046 if(b){
1047 b->prev = p;
1048 b->next = c;
1051 if(c)
1052 c->prev = b;
1054 p->prev = a;
1055 p->next = b;
1058 role_type_print(title, sizeof(title), _("HELP FOR %sRULE CONFIGURATION"), rflags);
1059 role_type_print(add, sizeof(add), _("Use Add to add a %sRule"), rflags);
1061 (*ctmp)->value = cpystr(add);
1062 (*ctmp)->keymenu = &role_conf_km;
1063 (*ctmp)->help = (rflags & ROLE_DO_INCOLS) ? h_rules_incols :
1064 (rflags & ROLE_DO_OTHER) ? h_rules_other :
1065 (rflags & ROLE_DO_FILTER) ? h_rules_filter :
1066 (rflags & ROLE_DO_SCORES) ? h_rules_score :
1067 (rflags & ROLE_DO_ROLES) ? h_rules_roles :
1068 (rflags & ROLE_DO_SRCH) ? h_rules_srch :
1069 NO_HELP;
1070 (*ctmp)->help_title = title;
1071 (*ctmp)->tool = role_config_tool;
1072 (*ctmp)->flags |= CF_STARTITEM;
1073 (*ctmp)->valoffset = 4;
1078 role_config_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
1080 int first_one = 0, rv = 0;
1081 char exitpmt[80];
1082 PAT_S *pat;
1084 if(!(pat = first_pattern(role_global_pstate)) ||
1085 (pat->inherit && !next_pattern(role_global_pstate)))
1086 first_one++;
1088 switch(cmd){
1089 case MC_DELETE :
1090 if(first_one)
1091 q_status_message(SM_ORDER|SM_DING, 0, 3,
1092 _("Nothing to Delete, use Add"));
1093 else
1094 rv = role_config_del(ps, cl, role_global_flags);
1096 break;
1098 case MC_ADD :
1099 rv = role_config_add(ps, cl, role_global_flags);
1100 break;
1102 case MC_EDIT :
1103 if(first_one)
1104 rv = role_config_add(ps, cl, role_global_flags);
1105 else
1106 rv = role_config_edit(ps, cl, role_global_flags);
1108 break;
1110 case MC_SHUFFLE :
1111 if(first_one)
1112 q_status_message(SM_ORDER|SM_DING, 0, 3,
1113 _("Nothing to Shuffle, use Add"));
1114 else
1115 rv = role_config_shuffle(ps, cl);
1117 break;
1119 case MC_EXIT :
1120 role_type_print(exitpmt, sizeof(exitpmt), "%sRule Setup", role_global_flags);
1121 rv = screen_exit_cmd(flags, exitpmt);
1122 break;
1124 case MC_ADDFILE :
1125 rv = role_config_addfile(ps, cl, role_global_flags);
1126 break;
1128 case MC_DELFILE :
1129 rv = role_config_delfile(ps, cl, role_global_flags);
1130 break;
1132 case MC_COPY :
1133 if(first_one)
1134 q_status_message(SM_ORDER|SM_DING, 0, 3,
1135 _("Nothing to Replicate, use Add"));
1136 else
1137 rv = role_config_replicate(ps, cl, role_global_flags);
1139 break;
1141 default:
1142 rv = -1;
1143 break;
1146 return(rv);
1151 * Add a new role.
1153 * Returns 1 -- There were changes
1154 * 0 -- No changes
1157 role_config_add(struct pine *ps, CONF_S **cl, long int rflags)
1159 int rv = 0, first_pat = 0;
1160 PAT_S *new_pat = NULL, *cur_pat;
1161 PAT_LINE_S *new_patline = NULL, *cur_patline;
1162 PAT_STATE pstate;
1163 char title[80];
1165 if((*cl)->d.r.patline &&
1166 (*cl)->d.r.patline->readonly
1167 && (*cl)->d.r.patline->type == File){
1168 q_status_message(SM_ORDER, 0, 3, _("Can't add rule to ReadOnly file"));
1169 return(rv);
1172 role_type_print(title, sizeof(title), "ADD A %sRULE", rflags);
1174 if(role_config_edit_screen(ps, NULL, title, rflags,
1175 &new_pat) == 1 && new_pat){
1176 if(ps->never_allow_changing_from &&
1177 new_pat->action &&
1178 new_pat->action->from)
1179 q_status_message(SM_ORDER|SM_DING, 0, 3,
1180 _("Site policy doesn't allow changing From address so From is ignored"));
1182 if(rflags & ROLE_DO_ROLES &&
1183 new_pat->patgrp &&
1184 new_pat->patgrp->nick &&
1185 nonempty_patterns(ROLE_DO_ROLES, &pstate)){
1186 PAT_S *pat;
1188 for(pat = first_pattern(&pstate);
1189 pat;
1190 pat = next_pattern(&pstate)){
1191 if(pat->patgrp && pat->patgrp->nick &&
1192 !strucmp(pat->patgrp->nick, new_pat->patgrp->nick)){
1193 q_status_message(SM_ORDER|SM_DING, 3, 7, _("Warning: The nickname of the new role is already in use."));
1194 break;
1199 rv = 1;
1200 cur_pat = (*cl)->d.r.pat;
1201 if(!cur_pat)
1202 first_pat++;
1204 set_pathandle(rflags);
1205 cur_patline = first_pat ? (*cur_pat_h)->patlinehead : cur_pat->patline;
1207 /* need a new pat_line */
1208 if(first_pat || (cur_patline && cur_patline->type == Literal)){
1209 new_patline = (PAT_LINE_S *)fs_get(sizeof(*new_patline));
1210 memset((void *)new_patline, 0, sizeof(*new_patline));
1211 new_patline->type = Literal;
1212 (*cur_pat_h)->dirtypinerc = 1;
1215 if(cur_patline){
1216 if(first_pat || cur_patline->type == Literal){
1217 new_patline->prev = cur_patline;
1218 new_patline->next = cur_patline->next;
1219 if(cur_patline->next)
1220 cur_patline->next->prev = new_patline;
1222 cur_patline->next = new_patline;
1224 /* tie new patline and new pat together */
1225 new_pat->patline = new_patline;
1226 new_patline->first = new_patline->last = new_pat;
1228 else if(cur_patline->type == File){ /* don't need a new pat_line */
1229 /* tie together */
1230 new_pat->patline = cur_patline;
1231 cur_patline->dirty = 1;
1233 /* Splice new_pat after cur_pat */
1234 new_pat->prev = cur_pat;
1235 new_pat->next = cur_pat->next;
1236 if(cur_pat->next)
1237 cur_pat->next->prev = new_pat;
1238 else
1239 cur_patline->last = new_pat;
1241 cur_pat->next = new_pat;
1244 else{
1245 /* tie new first patline and pat together */
1246 new_pat->patline = new_patline;
1247 new_patline->first = new_patline->last = new_pat;
1249 /* set head of list */
1250 (*cur_pat_h)->patlinehead = new_patline;
1254 * If this is the first role, we replace the "Use Add" fake role
1255 * with this real one.
1257 if(first_pat){
1258 /* Adjust conf_scroll_screen variables */
1259 (*cl)->d.r.pat = new_pat;
1260 (*cl)->d.r.patline = new_pat->patline;
1261 if((*cl)->value)
1262 fs_give((void **)&(*cl)->value);
1264 (*cl)->value = cpystr((new_pat && new_pat->patgrp &&
1265 new_pat->patgrp->nick)
1266 ? new_pat->patgrp->nick : "?");
1268 /* Else we are inserting a new role after the cur role */
1269 else
1270 add_role_to_display(cl, new_pat->patline, new_pat, 0, NULL,
1271 1, rflags);
1274 return(rv);
1279 * Replicate a role.
1281 * Returns 1 -- There were changes
1282 * 0 -- No changes
1285 role_config_replicate(struct pine *ps, CONF_S **cl, long int rflags)
1287 int rv = 0, first_pat = 0;
1288 PAT_S *new_pat = NULL, *cur_pat, *defpat = NULL;
1289 PAT_LINE_S *new_patline = NULL, *cur_patline;
1290 PAT_STATE pstate;
1291 char title[80];
1293 if((*cl)->d.r.patline &&
1294 (*cl)->d.r.patline->readonly
1295 && (*cl)->d.r.patline->type == File){
1296 q_status_message(SM_ORDER, 0, 3, _("Can't add rule to ReadOnly file"));
1297 return(rv);
1300 if((*cl)->d.r.pat && (defpat = copy_pat((*cl)->d.r.pat))){
1301 /* change nickname */
1302 if(defpat->patgrp && defpat->patgrp->nick){
1303 #define CLONEWORD " Copy"
1304 char *oldnick = defpat->patgrp->nick;
1305 size_t len;
1307 len = strlen(oldnick)+strlen(CLONEWORD);
1308 defpat->patgrp->nick = (char *)fs_get((len+1) * sizeof(char));
1309 strncpy(defpat->patgrp->nick, oldnick, len);
1310 defpat->patgrp->nick[len] = '\0';
1311 strncat(defpat->patgrp->nick, CLONEWORD,
1312 len+1-1-strlen(defpat->patgrp->nick));
1313 fs_give((void **)&oldnick);
1314 if(defpat->action){
1315 if(defpat->action->nick)
1316 fs_give((void **)&defpat->action->nick);
1318 defpat->action->nick = cpystr(defpat->patgrp->nick);
1322 /* set this so that even if we don't edit at all, we'll be asked */
1323 rflags |= ROLE_CHANGES;
1325 role_type_print(title, sizeof(title), "CHANGE THIS %sRULE", rflags);
1327 if(role_config_edit_screen(ps, defpat, title, rflags,
1328 &new_pat) == 1 && new_pat){
1330 if(ps->never_allow_changing_from &&
1331 new_pat->action &&
1332 new_pat->action->from)
1333 q_status_message(SM_ORDER|SM_DING, 0, 3,
1334 _("Site policy doesn't allow changing From address so From is ignored"));
1336 if(rflags & ROLE_DO_ROLES &&
1337 new_pat->patgrp &&
1338 new_pat->patgrp->nick &&
1339 nonempty_patterns(ROLE_DO_ROLES, &pstate)){
1340 PAT_S *pat;
1342 for(pat = first_pattern(&pstate);
1343 pat;
1344 pat = next_pattern(&pstate)){
1345 if(pat->patgrp && pat->patgrp->nick &&
1346 !strucmp(pat->patgrp->nick, new_pat->patgrp->nick)){
1347 q_status_message(SM_ORDER|SM_DING, 3, 7, _("Warning: The nickname of the new role is already in use."));
1348 break;
1353 rv = 1;
1354 cur_pat = (*cl)->d.r.pat;
1355 if(!cur_pat)
1356 first_pat++;
1358 set_pathandle(rflags);
1359 cur_patline = first_pat ? (*cur_pat_h)->patlinehead : cur_pat->patline;
1361 /* need a new pat_line */
1362 if(first_pat || (cur_patline && cur_patline->type == Literal)){
1363 new_patline = (PAT_LINE_S *)fs_get(sizeof(*new_patline));
1364 memset((void *)new_patline, 0, sizeof(*new_patline));
1365 new_patline->type = Literal;
1366 (*cur_pat_h)->dirtypinerc = 1;
1369 if(cur_patline){
1370 if(first_pat || cur_patline->type == Literal){
1371 new_patline->prev = cur_patline;
1372 new_patline->next = cur_patline->next;
1373 if(cur_patline->next)
1374 cur_patline->next->prev = new_patline;
1376 cur_patline->next = new_patline;
1378 /* tie new patline and new pat together */
1379 new_pat->patline = new_patline;
1380 new_patline->first = new_patline->last = new_pat;
1382 else if(cur_patline->type == File){ /* don't need a new pat_line */
1383 /* tie together */
1384 new_pat->patline = cur_patline;
1385 cur_patline->dirty = 1;
1387 /* Splice new_pat after cur_pat */
1388 new_pat->prev = cur_pat;
1389 new_pat->next = cur_pat->next;
1390 if(cur_pat->next)
1391 cur_pat->next->prev = new_pat;
1392 else
1393 cur_patline->last = new_pat;
1395 cur_pat->next = new_pat;
1398 else{
1399 /* tie new first patline and pat together */
1400 new_pat->patline = new_patline;
1401 new_patline->first = new_patline->last = new_pat;
1403 /* set head of list */
1404 (*cur_pat_h)->patlinehead = new_patline;
1408 * If this is the first role, we replace the "Use Add" fake role
1409 * with this real one.
1411 if(first_pat){
1412 /* Adjust conf_scroll_screen variables */
1413 (*cl)->d.r.pat = new_pat;
1414 (*cl)->d.r.patline = new_pat->patline;
1415 if((*cl)->value)
1416 fs_give((void **)&(*cl)->value);
1418 (*cl)->value = cpystr((new_pat && new_pat->patgrp &&
1419 new_pat->patgrp->nick)
1420 ? new_pat->patgrp->nick : "?");
1422 /* Else we are inserting a new role after the cur role */
1423 else
1424 add_role_to_display(cl, new_pat->patline, new_pat, 0, NULL,
1425 1, rflags);
1429 if(defpat)
1430 free_pat(&defpat);
1432 return(rv);
1437 * Change the current role.
1439 * Returns 1 -- There were changes
1440 * 0 -- No changes
1443 role_config_edit(struct pine *ps, CONF_S **cl, long int rflags)
1445 int rv = 0;
1446 PAT_S *new_pat = NULL, *cur_pat;
1447 char title[80];
1449 if((*cl)->d.r.patline->readonly){
1450 q_status_message(SM_ORDER, 0, 3, _("Can't change ReadOnly rule"));
1451 return(rv);
1454 cur_pat = (*cl)->d.r.pat;
1456 role_type_print(title, sizeof(title), "CHANGE THIS %sRULE", rflags);
1458 if(role_config_edit_screen(ps, cur_pat, title,
1459 rflags, &new_pat) == 1 && new_pat){
1461 if(ps->never_allow_changing_from &&
1462 new_pat->action &&
1463 new_pat->action->from)
1464 q_status_message(SM_ORDER|SM_DING, 0, 3,
1465 _("Site policy doesn't allow changing From address so From is ignored"));
1467 if(rflags & ROLE_DO_ROLES && new_pat->patgrp && new_pat->patgrp->nick){
1468 PAT_S *pat;
1470 for(pat = first_pattern(role_global_pstate);
1471 pat;
1472 pat = next_pattern(role_global_pstate)){
1473 if(pat->patgrp && pat->patgrp->nick && pat != cur_pat &&
1474 !strucmp(pat->patgrp->nick, new_pat->patgrp->nick)){
1475 q_status_message(SM_ORDER|SM_DING, 3, 7, _("Warning: The nickname of this role is also used for another role."));
1476 break;
1481 rv = 1;
1484 * Splice in new_pat in place of cur_pat
1487 if(cur_pat->prev)
1488 cur_pat->prev->next = new_pat;
1490 if(cur_pat->next)
1491 cur_pat->next->prev = new_pat;
1493 new_pat->prev = cur_pat->prev;
1494 new_pat->next = cur_pat->next;
1496 /* tie together patline and pat (new_pat gets patline in editor) */
1497 if(new_pat->patline->first == cur_pat)
1498 new_pat->patline->first = new_pat;
1500 if(new_pat->patline->last == cur_pat)
1501 new_pat->patline->last = new_pat;
1503 if(new_pat->patline->type == Literal){
1504 set_pathandle(rflags);
1505 if(*cur_pat_h)
1506 (*cur_pat_h)->dirtypinerc = 1;
1508 else
1509 new_pat->patline->dirty = 1;
1511 cur_pat->next = NULL;
1512 free_pat(&cur_pat);
1514 /* Adjust conf_scroll_screen variables */
1515 (*cl)->d.r.pat = new_pat;
1516 (*cl)->d.r.patline = new_pat->patline;
1517 if((*cl)->value)
1518 fs_give((void **)&(*cl)->value);
1520 (*cl)->value = cpystr((new_pat->patgrp && new_pat->patgrp->nick)
1521 ? new_pat->patgrp->nick : "?");
1524 return(rv);
1529 * Delete a role.
1531 * Returns 1 -- There were changes
1532 * 0 -- No changes
1535 role_config_del(struct pine *ps, CONF_S **cl, long int rflags)
1537 int rv = 0;
1538 char msg[80];
1539 char prompt[100];
1541 if((*cl)->d.r.patline->readonly){
1542 q_status_message(SM_ORDER, 0, 3, _("Can't delete ReadOnly rule"));
1543 return(rv);
1546 role_type_print(msg, sizeof(msg), _("Really delete %srule"), rflags);
1547 snprintf(prompt, sizeof(prompt), "%s \"%s\" ", msg, (*cl)->value);
1548 prompt[sizeof(prompt)-1] = '\0';
1550 ps->mangled_footer = 1;
1551 if(want_to(prompt,'n','n',h_config_role_del, WT_FLUSH_IN) == 'y'){
1552 rv = ps->mangled_body = 1;
1553 delete_a_role(cl, rflags);
1555 else
1556 q_status_message(SM_ORDER, 0, 3, _("Rule not deleted"));
1558 return(rv);
1562 void
1563 delete_a_role(CONF_S **cl, long int rflags)
1565 PAT_S *cur_pat;
1566 CONF_S *cp, *cq;
1567 PAT_LINE_S *cur_patline;
1568 int inherit = 0;
1570 cur_pat = (*cl)->d.r.pat;
1571 cur_patline = (*cl)->d.r.patline;
1573 if(cur_patline->type == Literal){ /* delete patline */
1574 set_pathandle(rflags);
1575 if(cur_patline->prev)
1576 cur_patline->prev->next = cur_patline->next;
1577 else{
1578 if(*cur_pat_h) /* this has to be true */
1579 (*cur_pat_h)->patlinehead = cur_patline->next;
1582 if(cur_patline->next)
1583 cur_patline->next->prev = cur_patline->prev;
1585 if(*cur_pat_h) /* this has to be true */
1586 (*cur_pat_h)->dirtypinerc = 1;
1588 cur_patline->next = NULL;
1589 free_patline(&cur_patline);
1591 else if(cur_patline->type == File){ /* or delete pat */
1592 if(cur_pat->prev)
1593 cur_pat->prev->next = cur_pat->next;
1594 else
1595 cur_patline->first = cur_pat->next;
1597 if(cur_pat->next)
1598 cur_pat->next->prev = cur_pat->prev;
1599 else
1600 cur_patline->last = cur_pat->prev;
1602 cur_patline->dirty = 1;
1604 cur_pat->next = NULL;
1605 free_pat(&cur_pat);
1608 /* delete the conf line */
1610 /* deleting last real rule */
1611 if(!first_pattern(role_global_pstate) ||
1612 ((inherit=first_pattern(role_global_pstate)->inherit) &&
1613 !next_pattern(role_global_pstate))){
1615 cq = *cl;
1618 * Find the start and prepend the fake first role.
1620 while(*cl && (*cl)->prev)
1621 *cl = (*cl)->prev;
1623 add_fake_first_role(cl, inherit ? 0 : 1, rflags);
1624 snip_confline(&cq);
1625 opt_screen->top_line = (*cl);
1626 opt_screen->current = (*cl);
1628 else{
1629 /* find next selectable line */
1630 for(cp = (*cl)->next;
1631 cp && (cp->flags & CF_NOSELECT);
1632 cp = cp->next)
1635 if(!cp){ /* no next selectable, find previous selectable */
1636 if(*cl == opt_screen->top_line)
1637 opt_screen->top_line = (*cl)->prev;
1639 for(cp = (*cl)->prev;
1640 cp && (cp->flags & CF_NOSELECT);
1641 cp = cp->prev)
1644 else if(*cl == opt_screen->top_line)
1645 opt_screen->top_line = (*cl)->next;
1647 cq = *cl;
1648 *cl = cp;
1649 snip_confline(&cq);
1655 * Shuffle the current role up or down.
1657 * Returns 1 -- There were changes
1658 * 0 -- No changes
1661 role_config_shuffle(struct pine *ps, CONF_S **cl)
1663 int rv = 0, deefault, i;
1664 int readonlyabove = 0, readonlybelow = 0;
1665 ESCKEY_S opts[5];
1666 HelpType help;
1667 char tmp[200];
1668 CONF_S *a, *b;
1669 PAT_TYPE curtype, prevtype, nexttype;
1671 if(!((*cl)->prev || (*cl)->next)){
1672 q_status_message(SM_ORDER, 0, 3,
1673 _("Shuffle only makes sense when there is more than one rule defined"));
1674 return(rv);
1677 /* Move it up or down? */
1678 i = 0;
1679 opts[i].ch = 'u';
1680 opts[i].rval = 'u';
1681 opts[i].name = "U";
1682 opts[i++].label = N_("Up");
1684 opts[i].ch = 'd';
1685 opts[i].rval = 'd';
1686 opts[i].name = "D";
1687 opts[i++].label = N_("Down");
1689 opts[i].ch = 'b';
1690 opts[i].rval = 'b';
1691 opts[i].name = "B";
1692 opts[i++].label = N_("Before File");
1694 opts[i].ch = 'a';
1695 opts[i].rval = 'a';
1696 opts[i].name = "A";
1697 opts[i++].label = N_("After File");
1699 opts[i].ch = -1;
1700 deefault = 'u';
1702 curtype = ((*cl)->d.r.patline) ? (*cl)->d.r.patline->type : TypeNotSet;
1704 prevtype = ((*cl)->prev && (*cl)->prev->d.r.patline)
1705 ? (*cl)->prev->d.r.patline->type : TypeNotSet;
1706 if(curtype == File && prevtype == File && (*cl)->prev->d.r.pat == NULL)
1707 prevtype = TypeNotSet;
1709 nexttype = ((*cl)->next && (*cl)->next->d.r.patline)
1710 ? (*cl)->next->d.r.patline->type : TypeNotSet;
1711 if(curtype == File && nexttype == File && (*cl)->next->d.r.pat == NULL)
1712 nexttype = TypeNotSet;
1715 if(curtype == Literal){
1716 if(prevtype == TypeNotSet ||
1717 prevtype == Inherit){ /* no up, at top */
1718 opts[0].ch = -2;
1719 opts[2].ch = -2;
1720 deefault = 'd';
1722 else if(prevtype == Literal){ /* regular up */
1723 opts[2].ch = -2;
1725 else if(prevtype == File){ /* file above us */
1726 if((*cl)->prev->d.r.patline->readonly)
1727 readonlyabove++;
1730 if(nexttype == TypeNotSet){ /* no down, at bottom */
1731 opts[1].ch = -2;
1732 opts[3].ch = -2;
1734 else if(nexttype == Literal){ /* regular down */
1735 opts[3].ch = -2;
1737 else if(nexttype == File){ /* file below us */
1738 if((*cl)->next->d.r.patline->readonly)
1739 readonlybelow++;
1742 else if(curtype == File){
1743 if((*cl)->d.r.patline && (*cl)->d.r.patline->readonly){
1744 q_status_message(SM_ORDER, 0, 3, _("Can't change ReadOnly file"));
1745 return(0);
1748 opts[2].ch = -2;
1749 opts[3].ch = -2;
1751 else{
1752 q_status_message(SM_ORDER, 0, 3,
1753 "Programming Error: unknown line type in role_shuffle");
1754 return(rv);
1757 snprintf(tmp, sizeof(tmp), "Shuffle \"%s\" %s%s%s%s%s%s%s ? ",
1758 (*cl)->value,
1759 (opts[0].ch != -2) ? N_("UP") : "",
1760 (opts[0].ch != -2 && opts[1].ch != -2) ? " or " : "",
1761 (opts[1].ch != -2) ? N_("DOWN") : "",
1762 ((opts[0].ch != -2 ||
1763 opts[1].ch != -2) && opts[2].ch != -2) ? " or " : "",
1764 (opts[2].ch != -2) ? N_("BEFORE") : "",
1765 ((opts[0].ch != -2 ||
1766 opts[1].ch != -2 ||
1767 opts[2].ch != -2) && opts[3].ch != -2) ? " or " : "",
1768 (opts[3].ch != -2) ? N_("AFTER") : "");
1769 tmp[sizeof(tmp)-1] = '\0';
1771 help = (opts[0].ch == -2) ? h_role_shuf_down
1772 : (opts[1].ch == -2) ? h_role_shuf_up
1773 : h_role_shuf;
1775 rv = radio_buttons(tmp, -FOOTER_ROWS(ps), opts, deefault, 'x',
1776 help, RB_NORM);
1778 if(rv == 'x'){
1779 cmd_cancelled("Shuffle");
1780 return(0);
1783 if((readonlyabove && rv == 'u' && curtype != prevtype) ||
1784 (readonlybelow && rv == 'd' && curtype != nexttype)){
1785 q_status_message(SM_ORDER, 0, 3, _("Can't shuffle into ReadOnly file"));
1786 return(0);
1789 if(rv == 'u' && curtype == Literal && prevtype == Literal){
1790 rv = 1;
1791 a = (*cl)->prev;
1792 b = (*cl);
1793 if(a == opt_screen->top_line)
1794 opt_screen->top_line = b;
1796 swap_literal_roles(a, b);
1797 ps->mangled_body = 1;
1799 else if(rv == 'd' && curtype == Literal && nexttype == Literal){
1800 rv = 1;
1801 a = (*cl);
1802 b = (*cl)->next;
1803 if(a == opt_screen->top_line)
1804 opt_screen->top_line = b;
1806 swap_literal_roles(a, b);
1807 ps->mangled_body = 1;
1809 else if(rv == 'u' && curtype == File && prevtype == File){
1810 rv = 1;
1811 a = (*cl)->prev;
1812 b = (*cl);
1813 if(a == opt_screen->top_line)
1814 opt_screen->top_line = b;
1816 swap_file_roles(a, b);
1817 ps->mangled_body = 1;
1819 else if(rv == 'u' && curtype == File){
1820 rv = 1;
1821 move_role_outof_file(cl, 1);
1822 ps->mangled_body = 1;
1824 else if(rv == 'd' && curtype == File && nexttype == File){
1825 rv = 1;
1826 a = (*cl);
1827 b = (*cl)->next;
1828 if(a == opt_screen->top_line)
1829 opt_screen->top_line = b;
1831 swap_file_roles(a, b);
1832 ps->mangled_body = 1;
1834 else if(rv == 'd' && curtype == File){
1835 rv = 1;
1836 if(*cl == opt_screen->top_line)
1837 opt_screen->top_line = (*cl)->next;
1839 move_role_outof_file(cl, 0);
1840 ps->mangled_body = 1;
1842 else if(rv == 'u' && curtype == Literal && prevtype == File){
1843 rv = 1;
1844 move_role_into_file(cl, 1);
1845 ps->mangled_body = 1;
1847 else if(rv == 'd' && curtype == Literal && nexttype == File){
1848 rv = 1;
1849 if(*cl == opt_screen->top_line)
1850 opt_screen->top_line = (*cl)->next;
1852 move_role_into_file(cl, 0);
1853 ps->mangled_body = 1;
1855 else if(rv == 'b'){
1856 rv = 1;
1857 move_role_around_file(cl, 1);
1858 ps->mangled_body = 1;
1860 else if(rv == 'a'){
1861 rv = 1;
1862 if(*cl == opt_screen->top_line)
1863 opt_screen->top_line = (*cl)->next;
1865 move_role_around_file(cl, 0);
1866 ps->mangled_body = 1;
1869 return(rv);
1874 role_config_addfile(struct pine *ps, CONF_S **cl, long int rflags)
1876 char filename[MAXPATH+1], full_filename[MAXPATH+1];
1877 char dir2[MAXPATH+1], pdir[MAXPATH+1];
1878 char *lc, *newfile = NULL;
1879 PAT_LINE_S *file_patline;
1880 int rv = 0, len = 0;
1881 int r = 1, flags;
1882 HelpType help = NO_HELP;
1883 PAT_TYPE curtype;
1884 CONF_S *first_line = NULL, *add_line, *save_current;
1885 struct variable *vars = ps->vars;
1887 if(ps->restricted){
1888 q_status_message(SM_ORDER, 0, 3, "Alpine demo can't read files");
1889 return(rv);
1892 curtype = ((*cl)->d.r.patline && (*cl)->d.r.patline)
1893 ? (*cl)->d.r.patline->type : TypeNotSet;
1895 if(curtype == File){
1896 q_status_message(SM_ORDER, 0, 3, _("Current rule is already part of a file. Move outside any files first."));
1897 return(rv);
1901 * Parse_pattern_file uses signature_path to figure out where to look
1902 * for the file. In signature_path we read signature files relative
1903 * to the pinerc dir, so if user selects one that is in there we'll
1904 * use relative instead of absolute, so it looks nicer.
1906 pdir[0] = '\0';
1907 if(VAR_OPER_DIR){
1908 strncpy(pdir, VAR_OPER_DIR, sizeof(pdir)-1);
1909 pdir[sizeof(pdir)-1] = '\0';
1910 len = strlen(pdir) + 1;
1912 else if((lc = last_cmpnt(ps->pinerc)) != NULL){
1913 strncpy(pdir, ps->pinerc, MIN(sizeof(pdir)-1,lc-ps->pinerc));
1914 pdir[MIN(sizeof(pdir)-1, lc-ps->pinerc)] = '\0';
1915 len = strlen(pdir);
1918 strncpy(dir2, pdir, sizeof(dir2)-1);
1919 dir2[sizeof(dir2)-1] = '\0';
1920 filename[0] = '\0';
1921 full_filename[0] = '\0';
1922 ps->mangled_footer = 1;
1924 while(1){
1925 flags = OE_APPEND_CURRENT;
1926 r = optionally_enter(filename, -FOOTER_ROWS(ps), 0, sizeof(filename),
1927 "Name of file to be added to rules: ",
1928 NULL, help, &flags);
1930 if(r == 3){
1931 help = (help == NO_HELP) ? h_config_role_addfile : NO_HELP;
1932 continue;
1934 else if(r == 10 || r == 11){ /* Browser or File Completion */
1935 continue;
1937 else if(r == 1 || (r == 0 && filename[0] == '\0')){
1938 cmd_cancelled("IncludeFile");
1939 return(rv);
1941 else if(r == 4){
1942 continue;
1944 else if(r != 0){
1945 Writechar(BELL, 0);
1946 continue;
1949 removing_leading_and_trailing_white_space(filename);
1950 if(is_absolute_path(filename))
1951 newfile = cpystr(filename);
1952 else{
1953 build_path(full_filename, dir2, filename, sizeof(full_filename));
1954 removing_leading_and_trailing_white_space(full_filename);
1955 if(!strncmp(full_filename, pdir, strlen(pdir)))
1956 newfile = cpystr(full_filename + len);
1957 else
1958 newfile = cpystr(full_filename);
1961 if(newfile && *newfile)
1962 break;
1965 if(!newfile)
1966 return(rv);
1968 set_pathandle(rflags);
1970 if((file_patline = parse_pat_file(newfile)) != NULL){
1972 * Insert the file after the current line.
1974 PAT_LINE_S *cur_patline;
1975 int first_pat;
1977 rv = ps->mangled_screen = 1;
1978 first_pat = !(*cl)->d.r.pat;
1979 cur_patline = (*cl)->d.r.patline ? (*cl)->d.r.patline :
1980 (*cur_pat_h) ? (*cur_pat_h)->patlinehead : NULL;
1982 if(*cur_pat_h)
1983 (*cur_pat_h)->dirtypinerc = 1;
1985 file_patline->dirty = 1;
1987 if(cur_patline){
1988 file_patline->prev = cur_patline;
1989 file_patline->next = cur_patline->next;
1990 if(cur_patline->next)
1991 cur_patline->next->prev = file_patline;
1993 cur_patline->next = file_patline;
1995 else{
1996 /* set head of list */
1997 if(*cur_pat_h)
1998 (*cur_pat_h)->patlinehead = file_patline;
2001 if(first_pat){
2002 if(file_patline->first){
2003 /* get rid of Fake Add line */
2004 add_line = *cl;
2005 opt_screen->top_line = NULL;
2006 add_patline_to_display(ps, cl, 0, &first_line,
2007 &opt_screen->top_line, file_patline,
2008 rflags);
2009 opt_screen->current = first_line;
2010 snip_confline(&add_line);
2012 else{
2013 /* we're _appending_ to the Fake Add line */
2014 save_current = opt_screen->current;
2015 add_patline_to_display(ps, cl, 0, NULL, NULL, file_patline,
2016 rflags);
2017 opt_screen->current = save_current;
2020 else{
2021 opt_screen->top_line = NULL;
2022 save_current = opt_screen->current;
2023 add_patline_to_display(ps, cl, 0, &first_line,
2024 &opt_screen->top_line, file_patline,
2025 rflags);
2026 if(first_line)
2027 opt_screen->current = first_line;
2028 else
2029 opt_screen->current = save_current;
2033 if(newfile)
2034 fs_give((void **)&newfile);
2036 return(rv);
2041 role_config_delfile(struct pine *ps, CONF_S **cl, long int rflags)
2043 int rv = 0;
2044 PAT_LINE_S *cur_patline;
2045 char prompt[100];
2047 if(!(cur_patline = (*cl)->d.r.patline)){
2048 q_status_message(SM_ORDER, 0, 3,
2049 "Unknown problem in role_config_delfile");
2050 return(rv);
2053 if(cur_patline->type != File){
2054 q_status_message(SM_ORDER, 0, 3, _("Current rule is not part of a file. Use Delete to remove current rule"));
2055 return(rv);
2058 snprintf(prompt, sizeof(prompt), _("Really remove rule file \"%s\" from rules config "),
2059 cur_patline->filename);
2060 prompt[sizeof(prompt)-1] = '\0';
2062 ps->mangled_footer = 1;
2063 if(want_to(prompt,'n','n',h_config_role_delfile, WT_FLUSH_IN) == 'y'){
2064 CONF_S *ctmp, *cp;
2066 set_pathandle(rflags);
2067 rv = ps->mangled_screen = 1;
2068 if(*cur_pat_h)
2069 (*cur_pat_h)->dirtypinerc = 1;
2071 if(cur_patline->prev)
2072 cur_patline->prev->next = cur_patline->next;
2073 else{
2074 if(*cur_pat_h)
2075 (*cur_pat_h)->patlinehead = cur_patline->next;
2078 if(cur_patline->next)
2079 cur_patline->next->prev = cur_patline->prev;
2081 /* delete the conf lines */
2083 /* find the first one associated with this file */
2084 for(ctmp = *cl;
2085 ctmp && ctmp->prev && ctmp->prev->d.r.patline == cur_patline;
2086 ctmp = ctmp->prev)
2089 if(ctmp->prev) /* this file wasn't the first thing in config */
2090 *cl = ctmp->prev;
2091 else{ /* this file was first in config */
2092 for(cp = ctmp; cp && cp->next; cp = cp->next)
2095 if(cp->d.r.patline == cur_patline)
2096 *cl = NULL;
2097 else
2098 *cl = cp;
2101 /* delete lines from the file */
2102 while(ctmp && ctmp->d.r.patline == cur_patline){
2103 cp = ctmp;
2104 ctmp = ctmp->next;
2105 snip_confline(&cp);
2108 /* deleting last real rule */
2109 if(!first_pattern(role_global_pstate)){
2111 * Find the start and prepend the fake first role
2112 * in there.
2114 while(*cl && (*cl)->prev)
2115 *cl = (*cl)->prev;
2117 add_fake_first_role(cl, 1, rflags);
2119 else if(first_pattern(role_global_pstate)->inherit &&
2120 !next_pattern(role_global_pstate)){
2121 while(*cl && (*cl)->prev)
2122 *cl = (*cl)->prev;
2124 /* append fake first after inherit */
2125 add_fake_first_role(cl, 0, rflags);
2128 opt_screen->top_line = first_confline(*cl);
2129 opt_screen->current = first_sel_confline(opt_screen->top_line);
2131 cur_patline->next = NULL;
2132 free_patline(&cur_patline);
2134 else
2135 q_status_message(SM_ORDER, 0, 3, _("Rule file not removed"));
2137 return(rv);
2142 * Swap from a, b to b, a.
2144 void
2145 swap_literal_roles(CONF_S *a, CONF_S *b)
2147 PAT_LINE_S *patline_a, *patline_b;
2149 patline_a = a->d.r.patline;
2150 patline_b = b->d.r.patline;
2152 set_pathandle(role_global_flags);
2153 if(*cur_pat_h)
2154 (*cur_pat_h)->dirtypinerc = 1;
2156 /* first swap the patlines */
2157 if(patline_a->next == patline_b){
2158 patline_b->prev = patline_a->prev;
2159 if(patline_a->prev)
2160 patline_a->prev->next = patline_b;
2162 patline_a->next = patline_b->next;
2163 if(patline_b->next)
2164 patline_b->next->prev = patline_a;
2166 patline_b->next = patline_a;
2167 patline_a->prev = patline_b;
2169 else{
2170 PAT_LINE_S *new_a_prev, *new_a_next;
2172 new_a_prev = patline_b->prev;
2173 new_a_next = patline_b->next;
2175 patline_b->prev = patline_a->prev;
2176 patline_b->next = patline_a->next;
2177 if(patline_b->prev)
2178 patline_b->prev->next = patline_b;
2179 if(patline_b->next)
2180 patline_b->next->prev = patline_b;
2182 patline_a->prev = new_a_prev;
2183 patline_a->next = new_a_next;
2184 if(patline_a->prev)
2185 patline_a->prev->next = patline_a;
2186 if(patline_a->next)
2187 patline_a->next->prev = patline_a;
2191 * If patline_b is now the first one in the list, we need to fix the
2192 * head of the list to point to this new role.
2194 if(patline_b->prev == NULL && *cur_pat_h)
2195 (*cur_pat_h)->patlinehead = patline_b;
2198 /* and then swap the conf lines */
2200 b->prev = a->prev;
2201 if(a->prev)
2202 a->prev->next = b;
2204 a->next = b->next;
2205 if(b->next)
2206 b->next->prev = a;
2208 b->next = a;
2209 a->prev = b;
2214 * Swap from a, b to b, a.
2216 void
2217 swap_file_roles(CONF_S *a, CONF_S *b)
2219 PAT_S *pat_a, *pat_b;
2220 PAT_LINE_S *patline;
2222 pat_a = a->d.r.pat;
2223 pat_b = b->d.r.pat;
2224 patline = pat_a->patline;
2226 patline->dirty = 1;
2228 /* first swap the pats */
2229 if(pat_a->next == pat_b){
2230 pat_b->prev = pat_a->prev;
2231 if(pat_a->prev)
2232 pat_a->prev->next = pat_b;
2234 pat_a->next = pat_b->next;
2235 if(pat_b->next)
2236 pat_b->next->prev = pat_a;
2238 pat_b->next = pat_a;
2239 pat_a->prev = pat_b;
2241 else{
2242 PAT_S *new_a_prev, *new_a_next;
2244 new_a_prev = pat_b->prev;
2245 new_a_next = pat_b->next;
2247 pat_b->prev = pat_a->prev;
2248 pat_b->next = pat_a->next;
2249 if(pat_b->prev)
2250 pat_b->prev->next = pat_b;
2251 if(pat_b->next)
2252 pat_b->next->prev = pat_b;
2254 pat_a->prev = new_a_prev;
2255 pat_a->next = new_a_next;
2256 if(pat_a->prev)
2257 pat_a->prev->next = pat_a;
2258 if(pat_a->next)
2259 pat_a->next->prev = pat_a;
2263 * Fix the first and last pointers.
2265 if(patline->first == pat_a)
2266 patline->first = pat_b;
2267 if(patline->last == pat_b)
2268 patline->last = pat_a;
2270 /* and then swap the conf lines */
2272 b->prev = a->prev;
2273 if(a->prev)
2274 a->prev->next = b;
2276 a->next = b->next;
2277 if(b->next)
2278 b->next->prev = a;
2280 b->next = a;
2281 a->prev = b;
2287 void
2288 move_role_into_file(CONF_S **cl, int up)
2290 PAT_LINE_S *cur_patline, *file_patline;
2291 PAT_S *pat;
2292 CONF_S *a, *b;
2294 cur_patline = (*cl)->d.r.patline;
2296 if(up){
2297 file_patline = (*cl)->prev->d.r.patline;
2298 a = (*cl)->prev;
2299 b = (*cl);
2300 b->d.r.patline = file_patline;
2302 else{
2303 file_patline = (*cl)->next->d.r.patline;
2304 a = (*cl);
2305 b = (*cl)->next;
2306 a->d.r.patline = file_patline;
2309 set_pathandle(role_global_flags);
2310 if(*cur_pat_h)
2311 (*cur_pat_h)->dirtypinerc = 1;
2313 file_patline->dirty = 1;
2315 pat = cur_patline->first;
2317 if(!up && *cur_pat_h && cur_patline == (*cur_pat_h)->patlinehead)
2318 (*cur_pat_h)->patlinehead = (*cur_pat_h)->patlinehead->next;
2320 if(file_patline->first){
2321 if(up){
2322 file_patline->last->next = pat;
2323 pat->prev = file_patline->last;
2324 file_patline->last = pat;
2326 else{
2327 file_patline->first->prev = pat;
2328 pat->next = file_patline->first;
2329 file_patline->first = pat;
2332 else /* will be only role in file */
2333 file_patline->first = file_patline->last = pat;
2335 pat->patline = file_patline;
2337 /* delete the now unused cur_patline */
2338 cur_patline->first = cur_patline->last = NULL;
2339 if(cur_patline->prev)
2340 cur_patline->prev->next = cur_patline->next;
2341 if(cur_patline->next)
2342 cur_patline->next->prev = cur_patline->prev;
2344 cur_patline->next = NULL;
2345 free_patline(&cur_patline);
2347 /* and then swap the conf lines */
2349 b->prev = a->prev;
2350 if(a->prev)
2351 a->prev->next = b;
2353 a->next = b->next;
2354 if(b->next)
2355 b->next->prev = a;
2357 b->next = a;
2358 a->prev = b;
2364 void
2365 move_role_outof_file(CONF_S **cl, int up)
2367 PAT_LINE_S *file_patline, *new_patline;
2368 PAT_S *pat;
2369 CONF_S *a, *b;
2371 new_patline = (PAT_LINE_S *)fs_get(sizeof(*new_patline));
2372 memset((void *)new_patline, 0, sizeof(*new_patline));
2373 new_patline->type = Literal;
2375 file_patline = (*cl)->d.r.patline;
2376 pat = (*cl)->d.r.pat;
2378 if(up){
2379 a = (*cl)->prev;
2380 b = (*cl);
2382 if(pat->prev)
2383 pat->prev->next = pat->next;
2384 else
2385 file_patline->first = pat->next;
2387 if(pat->next)
2388 pat->next->prev = pat->prev;
2389 else
2390 file_patline->last = pat->prev;
2392 if(file_patline->first)
2393 file_patline->first->prev = NULL;
2395 if(file_patline->last)
2396 file_patline->last->next = NULL;
2398 if(file_patline->prev)
2399 file_patline->prev->next = new_patline;
2401 new_patline->prev = file_patline->prev;
2402 new_patline->next = file_patline;
2403 file_patline->prev = new_patline;
2404 b->d.r.patline = new_patline;
2406 else{
2407 a = (*cl);
2408 b = (*cl)->next;
2410 if(pat->prev)
2411 pat->prev->next = pat->next;
2412 else
2413 file_patline->first = pat->next;
2415 if(pat->next)
2416 pat->next->prev = pat->prev;
2417 else
2418 file_patline->last = pat->prev;
2420 if(file_patline->first)
2421 file_patline->first->prev = NULL;
2423 if(file_patline->last)
2424 file_patline->last->next = NULL;
2426 if(file_patline->next)
2427 file_patline->next->prev = new_patline;
2429 new_patline->next = file_patline->next;
2430 new_patline->prev = file_patline;
2431 file_patline->next = new_patline;
2432 a->d.r.patline = new_patline;
2435 set_pathandle(role_global_flags);
2436 if(*cur_pat_h)
2437 (*cur_pat_h)->dirtypinerc = 1;
2439 file_patline->dirty = 1;
2441 new_patline->first = new_patline->last = pat;
2442 pat->patline = new_patline;
2443 pat->prev = pat->next = NULL;
2445 if(up && *cur_pat_h && file_patline == (*cur_pat_h)->patlinehead)
2446 (*cur_pat_h)->patlinehead = new_patline;
2448 /* and then swap the conf lines */
2450 b->prev = a->prev;
2451 if(a->prev)
2452 a->prev->next = b;
2454 a->next = b->next;
2455 if(b->next)
2456 b->next->prev = a;
2458 b->next = a;
2459 a->prev = b;
2464 * This is a move of a literal role from before a file to after a file,
2465 * or vice versa.
2467 void
2468 move_role_around_file(CONF_S **cl, int up)
2470 PAT_LINE_S *file_patline, *lit_patline;
2471 CONF_S *cp;
2473 set_pathandle(role_global_flags);
2474 lit_patline = (*cl)->d.r.patline;
2475 if(up)
2476 file_patline = (*cl)->prev->d.r.patline;
2477 else{
2478 if(*cur_pat_h && lit_patline == (*cur_pat_h)->patlinehead)
2479 (*cur_pat_h)->patlinehead = (*cur_pat_h)->patlinehead->next;
2481 file_patline = (*cl)->next->d.r.patline;
2484 if(*cur_pat_h)
2485 (*cur_pat_h)->dirtypinerc = 1;
2487 /* remove the lit_patline from the list */
2488 if(lit_patline->prev)
2489 lit_patline->prev->next = lit_patline->next;
2490 if(lit_patline->next)
2491 lit_patline->next->prev = lit_patline->prev;
2493 /* and reinsert it on the other side of the file */
2494 if(up){
2495 if(*cur_pat_h && file_patline == (*cur_pat_h)->patlinehead)
2496 (*cur_pat_h)->patlinehead = lit_patline;
2498 lit_patline->prev = file_patline->prev;
2499 lit_patline->next = file_patline;
2501 if(file_patline->prev)
2502 file_patline->prev->next = lit_patline;
2504 file_patline->prev = lit_patline;
2506 else{
2507 lit_patline->next = file_patline->next;
2508 lit_patline->prev = file_patline;
2510 if(file_patline->next)
2511 file_patline->next->prev = lit_patline;
2513 file_patline->next = lit_patline;
2517 * And then move the conf line around the file conf lines.
2520 /* find it's new home */
2521 if(up)
2522 for(cp = (*cl);
2523 cp && cp->prev && cp->prev->d.r.patline == file_patline;
2524 cp = prev_confline(cp))
2526 else
2527 for(cp = (*cl);
2528 cp && cp->next && cp->next->d.r.patline == file_patline;
2529 cp = next_confline(cp))
2532 /* remove it from where it is */
2533 if((*cl)->prev)
2534 (*cl)->prev->next = (*cl)->next;
2535 if((*cl)->next)
2536 (*cl)->next->prev = (*cl)->prev;
2538 /* cp points to top or bottom of the file lines */
2539 if(up){
2540 (*cl)->prev = cp->prev;
2541 if(cp->prev)
2542 cp->prev->next = (*cl);
2544 cp->prev = (*cl);
2545 (*cl)->next = cp;
2547 else{
2548 (*cl)->next = cp->next;
2549 if(cp->next)
2550 cp->next->prev = (*cl);
2552 cp->next = (*cl);
2553 (*cl)->prev = cp;
2558 #define SETUP_PAT_STATUS(ctmp,svar,val,htitle,hval) \
2559 {char tmp[MAXPATH+1]; \
2560 int i, j, lv; \
2561 NAMEVAL_S *f; \
2563 /* Blank line */ \
2564 new_confline(&ctmp); \
2565 ctmp->flags |= CF_NOSELECT | CF_B_LINE; \
2567 new_confline(&ctmp); \
2568 ctmp->var = &svar; \
2569 ctmp->keymenu = &config_radiobutton_keymenu; \
2570 ctmp->help = NO_HELP; \
2571 ctmp->tool = NULL; \
2572 snprintf(tmp, sizeof(tmp), "%-s =", svar.name); \
2573 tmp[sizeof(tmp)-1] = '\0'; \
2574 ctmp->varname = cpystr(tmp); \
2575 ctmp->varnamep = ctmpb = ctmp; \
2576 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM); \
2578 new_confline(&ctmp); \
2579 ctmp->var = NULL; \
2580 ctmp->valoffset = rindent; \
2581 ctmp->keymenu = &config_radiobutton_keymenu; \
2582 ctmp->help = NO_HELP; \
2583 ctmp->tool = NULL; \
2584 ctmp->varnamep = ctmpb; \
2585 ctmp->flags |= CF_NOSELECT; \
2586 ctmp->value = cpystr("Set Choose One"); \
2588 new_confline(&ctmp); \
2589 ctmp->var = NULL; \
2590 ctmp->valoffset = rindent; \
2591 ctmp->keymenu = &config_radiobutton_keymenu; \
2592 ctmp->help = NO_HELP; \
2593 ctmp->tool = radio_tool; \
2594 ctmp->varnamep = ctmpb; \
2595 ctmp->flags |= CF_NOSELECT; \
2596 ctmp->value = cpystr(set_choose); \
2598 /* find longest value's name */ \
2599 for(lv = 0, i = 0; (f = role_status_types(i)); i++) \
2600 if(lv < (j = utf8_width(f->name))) \
2601 lv = j; \
2603 lv = MIN(lv, 100); \
2605 for(i = 0; (f = role_status_types(i)); i++){ \
2606 new_confline(&ctmp); \
2607 ctmp->help_title= htitle; \
2608 ctmp->var = &svar; \
2609 ctmp->valoffset = rindent; \
2610 ctmp->keymenu = &config_radiobutton_keymenu; \
2611 ctmp->help = hval; \
2612 ctmp->varmem = i; \
2613 ctmp->tool = radio_tool; \
2614 ctmp->varnamep = ctmpb; \
2615 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", (((!(def && def->patgrp) || \
2616 val == -1) && \
2617 f->value == PAT_STAT_EITHER) || \
2618 (def && def->patgrp && \
2619 f->value == val)) \
2620 ? R_SELD : ' ', \
2621 lv, lv, f->name); \
2622 tmp[sizeof(tmp)-1] = '\0'; \
2623 ctmp->value = cpystr(tmp); \
2627 #define SETUP_MSG_STATE(ctmp,svar,val,htitle,hval) \
2628 {char tmp[MAXPATH+1]; \
2629 int i, j, lv; \
2630 NAMEVAL_S *f; \
2632 /* Blank line */ \
2633 new_confline(&ctmp); \
2634 ctmp->flags |= CF_NOSELECT | CF_B_LINE; \
2636 new_confline(&ctmp); \
2637 ctmp->var = &svar; \
2638 ctmp->keymenu = &config_radiobutton_keymenu; \
2639 ctmp->help = NO_HELP; \
2640 ctmp->tool = NULL; \
2641 snprintf(tmp, sizeof(tmp), "%-s =", svar.name); \
2642 tmp[sizeof(tmp)-1] = '\0'; \
2643 ctmp->varname = cpystr(tmp); \
2644 ctmp->varnamep = ctmpb = ctmp; \
2645 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM); \
2647 new_confline(&ctmp); \
2648 ctmp->var = NULL; \
2649 ctmp->valoffset = rindent; \
2650 ctmp->keymenu = &config_radiobutton_keymenu; \
2651 ctmp->help = NO_HELP; \
2652 ctmp->tool = NULL; \
2653 ctmp->varnamep = ctmpb; \
2654 ctmp->flags |= CF_NOSELECT; \
2655 ctmp->value = cpystr("Set Choose One"); \
2657 new_confline(&ctmp); \
2658 ctmp->var = NULL; \
2659 ctmp->valoffset = rindent; \
2660 ctmp->keymenu = &config_radiobutton_keymenu; \
2661 ctmp->help = NO_HELP; \
2662 ctmp->tool = radio_tool; \
2663 ctmp->varnamep = ctmpb; \
2664 ctmp->flags |= CF_NOSELECT; \
2665 ctmp->value = cpystr(set_choose); \
2667 /* find longest value's name */ \
2668 for(lv = 0, i = 0; (f = msg_state_types(i)); i++) \
2669 if(lv < (j = utf8_width(f->name))) \
2670 lv = j; \
2672 lv = MIN(lv, 100); \
2674 for(i = 0; (f = msg_state_types(i)); i++){ \
2675 new_confline(&ctmp); \
2676 ctmp->help_title= htitle; \
2677 ctmp->var = &svar; \
2678 ctmp->valoffset = rindent; \
2679 ctmp->keymenu = &config_radiobutton_keymenu; \
2680 ctmp->help = hval; \
2681 ctmp->varmem = i; \
2682 ctmp->tool = radio_tool; \
2683 ctmp->varnamep = ctmpb; \
2684 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", (f->value == val) \
2685 ? R_SELD : ' ', \
2686 lv, lv, f->name); \
2687 tmp[sizeof(tmp)-1] = '\0'; \
2688 ctmp->value = cpystr(tmp); \
2693 #define FEAT_SENTDATE 0
2694 #define FEAT_IFNOTDEL 1
2695 #define FEAT_NONTERM 2
2696 bitmap_t feat_option_list;
2698 #define INABOOK_FROM 0
2699 #define INABOOK_REPLYTO 1
2700 #define INABOOK_SENDER 2
2701 #define INABOOK_TO 3
2702 #define INABOOK_CC 4
2703 bitmap_t inabook_type_list;
2706 #define INICK_INICK_CONF 0
2707 #define INICK_FROM_CONF 1
2708 #define INICK_REPLYTO_CONF 2
2709 #define INICK_FCC_CONF 3
2710 #define INICK_LITSIG_CONF 4 /* this needs to come before SIG_CONF */
2711 #define INICK_SIG_CONF 5
2712 #define INICK_TEMPL_CONF 6
2713 #define INICK_CSTM_CONF 7
2714 #define INICK_SMTP_CONF 8
2715 #define INICK_NNTP_CONF 9
2716 CONF_S *inick_confs[INICK_NNTP_CONF+1];
2720 * Screen for editing configuration of a role.
2722 * Args ps -- pine struct
2723 * def -- default role values to start with
2724 * title -- part of title at top of screen
2725 * rflags -- which parts of role to edit
2726 * result -- This is the returned PAT_S, freed by caller.
2728 * Returns: 0 if no change
2729 * 1 if user requested a change
2730 * (change is stored in raw_server and hasn't been acted upon yet)
2731 * 10 user says abort
2734 role_config_edit_screen(struct pine *ps, PAT_S *def, char *title, long int rflags, PAT_S **result)
2736 OPT_SCREEN_S screen, *saved_screen;
2737 CONF_S *ctmp = NULL, *ctmpb, *first_line = NULL;
2738 struct variable nick_var, to_pat_var, from_pat_var,
2739 comment_var,
2740 sender_pat_var, cc_pat_var, recip_pat_var, news_pat_var,
2741 subj_pat_var, inick_var, fldr_type_var, folder_pat_var,
2742 abook_type_var, abook_pat_var,
2743 alltext_pat_var, scorei_pat_var, partic_pat_var,
2744 bodytext_pat_var, age_pat_var, size_pat_var,
2745 keyword_pat_var, charset_pat_var,
2746 stat_new_var, stat_del_var, stat_imp_var, stat_ans_var,
2747 stat_rec_var, stat_8bit_var,
2748 stat_bom_var, stat_boy_var,
2749 cat_cmd_var, cati_var, cat_lim_var,
2750 from_act_var, replyto_act_var, fcc_act_var,
2751 sig_act_var, litsig_act_var, templ_act_var,
2752 cstm_act_var, smtp_act_var, nntp_act_var,
2753 sort_act_var, iform_act_var, startup_var,
2754 repl_type_var, forw_type_var, comp_type_var, score_act_var,
2755 hdrtok_act_var,
2756 rolecolor_vars[2], filter_type_var, folder_act_var,
2757 keyword_set_var, keyword_clr_var,
2758 filt_new_var, filt_del_var, filt_imp_var, filt_ans_var;
2759 struct variable *v, *varlist[65], opt_var, inabook_type_var;
2760 char *nick = NULL, *inick = NULL, *fldr_type_pat = NULL,
2761 *comment = NULL,
2762 *scorei_pat = NULL, *age_pat = NULL, *size_pat = NULL,
2763 *abook_type_pat = NULL,
2764 *stat_new = NULL, *stat_del = NULL, *stat_imp = NULL,
2765 *stat_rec = NULL, *stat_ans = NULL, *stat_8bit = NULL,
2766 *stat_bom = NULL, *stat_boy = NULL,
2767 *filt_new = NULL, *filt_del = NULL, *filt_imp = NULL,
2768 *filt_ans = NULL, *cati = NULL, *cat_lim = NULL,
2769 *from_act = NULL, *replyto_act = NULL, *fcc_act = NULL,
2770 *sig_act = NULL, *litsig_act = NULL, *sort_act = NULL,
2771 *templ_act = NULL, *repl_type = NULL, *forw_type = NULL,
2772 *comp_type = NULL, *rc_fg = NULL, *rc_bg = NULL,
2773 *score_act = NULL, *filter_type = NULL,
2774 *hdrtok_act = NULL,
2775 *iform_act = NULL, *startup_act = NULL,
2776 *old_fg = NULL, *old_bg = NULL;
2777 char **to_pat = NULL, **from_pat = NULL, **sender_pat = NULL,
2778 **cc_pat = NULL, **news_pat = NULL, **recip_pat = NULL,
2779 **partic_pat = NULL, **subj_pat = NULL,
2780 **alltext_pat = NULL, **bodytext_pat = NULL,
2781 **keyword_pat = NULL, **folder_pat = NULL,
2782 **charset_pat = NULL,
2783 **abook_pat = NULL, **folder_act = NULL,
2784 **keyword_set = NULL, **keyword_clr = NULL,
2785 **cat_cmd = NULL, **cstm_act = NULL, **smtp_act = NULL,
2786 **nntp_act = NULL, **spat;
2787 char tmp[MAXPATH+1], **apval, **lval, ***alval, *p;
2788 /* TRANSLATORS: These next 4 are subheading for sections of a configuration screen. */
2789 char *fstr = _(" CURRENT FOLDER CONDITIONS BEGIN HERE ");
2790 char mstr[50];
2791 char *astr = _(" ACTIONS BEGIN HERE ");
2792 char *ustr = _(" USES BEGIN HERE ");
2793 char *ostr = _(" OPTIONS BEGIN HERE ");
2794 char *s_p_v_n = _("Subject pattern"); /* longest one of these */
2795 char *u_s_s = _("Use SMTP Server"); /* ditto */
2796 char *c_v_n = _("Exit Status Interval"); /* ditto */
2797 SortOrder def_sort;
2798 int def_sort_rev;
2799 ARBHDR_S *aa, *a;
2800 EARB_S *earb = NULL, *ea;
2801 int rv, i, j, lv, pindent, maxpindent, rindent,
2802 scoreval = 0, edit_role, wid,
2803 edit_incol, edit_score, edit_filter, edit_other, edit_srch,
2804 dval, ival, nval, aval, fval,
2805 per_folder_only, need_uses, need_options;
2806 int (*radio_tool)(struct pine *, int, CONF_S **, unsigned);
2807 int (*addhdr_tool)(struct pine *, int, CONF_S **, unsigned);
2808 int (*t_tool)(struct pine *, int, CONF_S **, unsigned);
2809 NAMEVAL_S *f;
2811 dprint((4, "role_config_edit_screen()\n"));
2812 edit_role = rflags & ROLE_DO_ROLES;
2813 edit_incol = rflags & ROLE_DO_INCOLS;
2814 edit_score = rflags & ROLE_DO_SCORES;
2815 edit_filter = rflags & ROLE_DO_FILTER;
2816 edit_other = rflags & ROLE_DO_OTHER;
2817 edit_srch = rflags & ROLE_DO_SRCH;
2819 per_folder_only = (edit_other &&
2820 !(edit_role || edit_incol || edit_score || edit_filter || edit_srch));
2821 need_uses = edit_role;
2822 need_options = !per_folder_only;
2824 radio_tool = edit_filter ? role_filt_radiobutton_tool
2825 : role_radiobutton_tool;
2826 t_tool = edit_filter ? role_filt_text_tool : role_text_tool;
2827 addhdr_tool = edit_filter ? role_filt_addhdr_tool : role_addhdr_tool;
2829 rindent = 12; /* radio indent */
2832 * We edit by making a nested call to conf_scroll_screen.
2833 * We use some fake struct variables to get back the results in, and
2834 * so we can use the existing tools from the config screen.
2836 varlist[j = 0] = &nick_var;
2837 varlist[++j] = &comment_var;
2838 varlist[++j] = &to_pat_var;
2839 varlist[++j] = &from_pat_var;
2840 varlist[++j] = &sender_pat_var;
2841 varlist[++j] = &cc_pat_var;
2842 varlist[++j] = &recip_pat_var;
2843 varlist[++j] = &partic_pat_var;
2844 varlist[++j] = &news_pat_var;
2845 varlist[++j] = &subj_pat_var;
2846 varlist[++j] = &alltext_pat_var;
2847 varlist[++j] = &bodytext_pat_var;
2848 varlist[++j] = &keyword_pat_var;
2849 varlist[++j] = &charset_pat_var;
2850 varlist[++j] = &age_pat_var;
2851 varlist[++j] = &size_pat_var;
2852 varlist[++j] = &scorei_pat_var;
2853 varlist[++j] = &stat_new_var;
2854 varlist[++j] = &stat_rec_var;
2855 varlist[++j] = &stat_del_var;
2856 varlist[++j] = &stat_imp_var;
2857 varlist[++j] = &stat_ans_var;
2858 varlist[++j] = &stat_8bit_var;
2859 varlist[++j] = &stat_bom_var;
2860 varlist[++j] = &stat_boy_var;
2861 varlist[++j] = &cat_cmd_var;
2862 varlist[++j] = &cati_var;
2863 varlist[++j] = &cat_lim_var;
2864 varlist[++j] = &inick_var;
2865 varlist[++j] = &fldr_type_var;
2866 varlist[++j] = &folder_pat_var;
2867 varlist[++j] = &abook_type_var;
2868 varlist[++j] = &abook_pat_var;
2869 varlist[++j] = &from_act_var;
2870 varlist[++j] = &replyto_act_var;
2871 varlist[++j] = &fcc_act_var;
2872 varlist[++j] = &sig_act_var;
2873 varlist[++j] = &litsig_act_var;
2874 varlist[++j] = &sort_act_var;
2875 varlist[++j] = &iform_act_var;
2876 varlist[++j] = &startup_var;
2877 varlist[++j] = &templ_act_var;
2878 varlist[++j] = &cstm_act_var;
2879 varlist[++j] = &smtp_act_var;
2880 varlist[++j] = &nntp_act_var;
2881 varlist[++j] = &score_act_var;
2882 varlist[++j] = &hdrtok_act_var;
2883 varlist[++j] = &repl_type_var;
2884 varlist[++j] = &forw_type_var;
2885 varlist[++j] = &comp_type_var;
2886 varlist[++j] = &rolecolor_vars[0];
2887 varlist[++j] = &rolecolor_vars[1];
2888 varlist[++j] = &filter_type_var;
2889 varlist[++j] = &folder_act_var;
2890 varlist[++j] = &keyword_set_var;
2891 varlist[++j] = &keyword_clr_var;
2892 varlist[++j] = &filt_new_var;
2893 varlist[++j] = &filt_del_var;
2894 varlist[++j] = &filt_imp_var;
2895 varlist[++j] = &filt_ans_var;
2896 varlist[++j] = &opt_var;
2897 varlist[++j] = &inabook_type_var;
2898 varlist[++j] = NULL;
2899 for(j = 0; varlist[j]; j++)
2900 memset(varlist[j], 0, sizeof(struct variable));
2902 if(def && ((def->patgrp && def->patgrp->bogus) || (def->action && def->action->bogus))){
2903 char msg[MAX_SCREEN_COLS+1];
2905 snprintf(msg, sizeof(msg),
2906 _("Rule contains unknown %s element, possibly from newer Alpine"),
2907 (def->patgrp && def->patgrp->bogus) ? "pattern" : "action");
2908 msg[sizeof(msg)-1] = '\0';
2909 q_status_message(SM_ORDER | SM_DING, 7, 7, msg);
2910 q_status_message(SM_ORDER | SM_DING, 7, 7,
2911 _("Editing with this version of Alpine will destroy information"));
2912 flush_status_messages(0);
2915 role_forw_ptr = role_repl_ptr = role_fldr_ptr = role_filt_ptr = NULL;
2916 role_status1_ptr = role_status2_ptr = role_status3_ptr = NULL;
2917 role_status4_ptr = role_status5_ptr = role_status6_ptr = NULL;
2918 role_status7_ptr = NULL; role_status8_ptr = NULL;
2919 msg_state1_ptr = msg_state2_ptr = NULL;
2920 msg_state3_ptr = msg_state4_ptr = NULL;
2921 role_afrom_ptr = startup_ptr = NULL;
2922 role_comment_ptr = NULL;
2924 nick_var.name = cpystr(_("Nickname"));
2925 nick_var.is_used = 1;
2926 nick_var.is_user = 1;
2927 apval = APVAL(&nick_var, ew);
2928 *apval = (def && def->patgrp && def->patgrp->nick)
2929 ? cpystr(def->patgrp->nick) : NULL;
2931 nick_var.global_val.p = cpystr(edit_role
2932 ? "Alternate Role"
2933 : (edit_other
2934 ? "Other Rule"
2935 : (edit_incol
2936 ? "Index Color Rule"
2937 : (edit_score
2938 ? "Score Rule"
2939 : "Filter Rule"))));
2940 set_current_val(&nick_var, FALSE, FALSE);
2942 role_comment_ptr = &comment_var; /* so radiobuttons can tell */
2943 comment_var.name = cpystr(_("Comment"));
2944 comment_var.is_used = 1;
2945 comment_var.is_user = 1;
2946 apval = APVAL(&comment_var, ew);
2947 *apval = (def && def->patgrp && def->patgrp->comment)
2948 ? cpystr(def->patgrp->comment) : NULL;
2949 set_current_val(&comment_var, FALSE, FALSE);
2951 /* TRANSLATORS: Quite a few of the translations to follow are from the
2952 rules editing screens. These are mostly headings of individual categories
2953 of criteria which can be set in a rule. */
2954 setup_dummy_pattern_var(&to_pat_var, _("To pattern"),
2955 (def && def->patgrp) ? def->patgrp->to : NULL);
2956 setup_dummy_pattern_var(&from_pat_var, _("From pattern"),
2957 (def && def->patgrp) ? def->patgrp->from : NULL);
2958 setup_dummy_pattern_var(&sender_pat_var, _("Sender pattern"),
2959 (def && def->patgrp) ? def->patgrp->sender : NULL);
2960 setup_dummy_pattern_var(&cc_pat_var, _("Cc pattern"),
2961 (def && def->patgrp) ? def->patgrp->cc : NULL);
2962 setup_dummy_pattern_var(&news_pat_var, _("News pattern"),
2963 (def && def->patgrp) ? def->patgrp->news : NULL);
2964 setup_dummy_pattern_var(&subj_pat_var, s_p_v_n,
2965 (def && def->patgrp) ? def->patgrp->subj : NULL);
2966 /* TRANSLATORS: Recip is an abbreviation for Recipients which stands for
2967 all of the recipients of a message. */
2968 setup_dummy_pattern_var(&recip_pat_var, _("Recip pattern"),
2969 (def && def->patgrp) ? def->patgrp->recip : NULL);
2970 /* TRANSLATORS: Partic is an abbreviation for Participants which stands for
2971 all of the recipients plus the sender of a message. */
2972 setup_dummy_pattern_var(&partic_pat_var, _("Partic pattern"),
2973 (def && def->patgrp) ? def->patgrp->partic : NULL);
2974 /* TRANSLATORS: AllText means all of the text of a message */
2975 setup_dummy_pattern_var(&alltext_pat_var, _("AllText pattern"),
2976 (def && def->patgrp) ? def->patgrp->alltext : NULL);
2977 /* TRANSLATORS: BdyText means the text of a message but not the text in the headers */
2978 setup_dummy_pattern_var(&bodytext_pat_var, _("BdyText pattern"),
2979 (def && def->patgrp) ? def->patgrp->bodytext : NULL);
2981 setup_dummy_pattern_var(&keyword_pat_var, _("Keyword pattern"),
2982 (def && def->patgrp) ? def->patgrp->keyword : NULL);
2983 setup_dummy_pattern_var(&charset_pat_var, _("Charset pattern"),
2984 (def && def->patgrp) ? def->patgrp->charsets : NULL);
2986 age_pat_global_ptr = &age_pat_var;
2987 /* TRANSLATORS: Age interval is a setting for how old the message is. */
2988 age_pat_var.name = cpystr(_("Age interval"));
2989 age_pat_var.is_used = 1;
2990 age_pat_var.is_user = 1;
2991 if(def && def->patgrp && def->patgrp->do_age){
2992 apval = APVAL(&age_pat_var, ew);
2993 *apval = stringform_of_intvl(def->patgrp->age);
2996 set_current_val(&age_pat_var, FALSE, FALSE);
2998 size_pat_global_ptr = &size_pat_var;
2999 size_pat_var.name = cpystr(_("Size interval"));
3000 size_pat_var.is_used = 1;
3001 size_pat_var.is_user = 1;
3002 if(def && def->patgrp && def->patgrp->do_size){
3003 apval = APVAL(&size_pat_var, ew);
3004 *apval = stringform_of_intvl(def->patgrp->size);
3007 set_current_val(&size_pat_var, FALSE, FALSE);
3009 scorei_pat_global_ptr = &scorei_pat_var;
3010 /* TRANSLATORS: Score is an alpine concept where the score can be kept for a
3011 message to see if it is a message you want to look at. */
3012 scorei_pat_var.name = cpystr(_("Score interval"));
3013 scorei_pat_var.is_used = 1;
3014 scorei_pat_var.is_user = 1;
3015 if(def && def->patgrp && def->patgrp->do_score){
3016 apval = APVAL(&scorei_pat_var, ew);
3017 *apval = stringform_of_intvl(def->patgrp->score);
3020 set_current_val(&scorei_pat_var, FALSE, FALSE);
3022 role_status1_ptr = &stat_del_var; /* so radiobuttons can tell */
3023 stat_del_var.name = cpystr(_("Message is Deleted?"));
3024 stat_del_var.is_used = 1;
3025 stat_del_var.is_user = 1;
3026 apval = APVAL(&stat_del_var, ew);
3027 *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_del : -1)) ? cpystr(f->name) : NULL;
3028 set_current_val(&stat_del_var, FALSE, FALSE);
3030 role_status2_ptr = &stat_new_var; /* so radiobuttons can tell */
3031 stat_new_var.name = cpystr(_("Message is New (Unseen)?"));
3032 stat_new_var.is_used = 1;
3033 stat_new_var.is_user = 1;
3034 apval = APVAL(&stat_new_var, ew);
3035 *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_new : -1)) ? cpystr(f->name) : NULL;
3036 set_current_val(&stat_new_var, FALSE, FALSE);
3038 role_status3_ptr = &stat_imp_var; /* so radiobuttons can tell */
3039 stat_imp_var.name = cpystr(_("Message is Important?"));
3040 stat_imp_var.is_used = 1;
3041 stat_imp_var.is_user = 1;
3042 apval = APVAL(&stat_imp_var, ew);
3043 *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_imp : -1)) ? cpystr(f->name) : NULL;
3044 set_current_val(&stat_imp_var, FALSE, FALSE);
3046 role_status4_ptr = &stat_ans_var; /* so radiobuttons can tell */
3047 stat_ans_var.name = cpystr(_("Message is Answered?"));
3048 stat_ans_var.is_used = 1;
3049 stat_ans_var.is_user = 1;
3050 apval = APVAL(&stat_ans_var, ew);
3051 *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_ans : -1)) ? cpystr(f->name) : NULL;
3052 set_current_val(&stat_ans_var, FALSE, FALSE);
3054 role_status5_ptr = &stat_8bit_var; /* so radiobuttons can tell */
3055 stat_8bit_var.name = cpystr(_("Subject contains raw 8-bit?"));
3056 stat_8bit_var.is_used = 1;
3057 stat_8bit_var.is_user = 1;
3058 apval = APVAL(&stat_8bit_var, ew);
3059 *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_8bitsubj : -1)) ? cpystr(f->name) : NULL;
3060 set_current_val(&stat_8bit_var, FALSE, FALSE);
3062 role_status6_ptr = &stat_rec_var; /* so radiobuttons can tell */
3063 stat_rec_var.name = cpystr(_("Message is Recent?"));
3064 stat_rec_var.is_used = 1;
3065 stat_rec_var.is_user = 1;
3066 apval = APVAL(&stat_rec_var, ew);
3067 *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_rec : -1)) ? cpystr(f->name) : NULL;
3068 set_current_val(&stat_rec_var, FALSE, FALSE);
3070 role_status7_ptr = &stat_bom_var; /* so radiobuttons can tell */
3071 stat_bom_var.name = cpystr(_("Beginning of Month?"));
3072 stat_bom_var.is_used = 1;
3073 stat_bom_var.is_user = 1;
3074 apval = APVAL(&stat_bom_var, ew);
3075 *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_bom : -1)) ? cpystr(f->name) : NULL;
3076 set_current_val(&stat_bom_var, FALSE, FALSE);
3078 role_status8_ptr = &stat_boy_var; /* so radiobuttons can tell */
3079 stat_boy_var.name = cpystr(_("Beginning of Year?"));
3080 stat_boy_var.is_used = 1;
3081 stat_boy_var.is_user = 1;
3082 apval = APVAL(&stat_boy_var, ew);
3083 *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_boy : -1)) ? cpystr(f->name) : NULL;
3084 set_current_val(&stat_boy_var, FALSE, FALSE);
3088 convert_statebits_to_vals((def && def->action) ? def->action->state_setting_bits : 0L, &dval, &aval, &ival, &nval);
3089 msg_state1_ptr = &filt_del_var; /* so radiobuttons can tell */
3090 /* TRANSLATORS: these are actions that might be taken by the rule */
3091 filt_del_var.name = cpystr(_("Set Deleted Status"));
3092 filt_del_var.is_used = 1;
3093 filt_del_var.is_user = 1;
3094 apval = APVAL(&filt_del_var, ew);
3095 *apval = (f=msg_state_types(dval)) ? cpystr(f->name) : NULL;
3096 set_current_val(&filt_del_var, FALSE, FALSE);
3098 msg_state2_ptr = &filt_new_var; /* so radiobuttons can tell */
3099 filt_new_var.name = cpystr(_("Set New Status"));
3100 filt_new_var.is_used = 1;
3101 filt_new_var.is_user = 1;
3102 apval = APVAL(&filt_new_var, ew);
3103 *apval = (f=msg_state_types(nval)) ? cpystr(f->name) : NULL;
3104 set_current_val(&filt_new_var, FALSE, FALSE);
3106 msg_state3_ptr = &filt_imp_var; /* so radiobuttons can tell */
3107 filt_imp_var.name = cpystr(_("Set Important Status"));
3108 filt_imp_var.is_used = 1;
3109 filt_imp_var.is_user = 1;
3110 apval = APVAL(&filt_imp_var, ew);
3111 *apval = (f=msg_state_types(ival)) ? cpystr(f->name) : NULL;
3112 set_current_val(&filt_imp_var, FALSE, FALSE);
3114 msg_state4_ptr = &filt_ans_var; /* so radiobuttons can tell */
3115 filt_ans_var.name = cpystr(_("Set Answered Status"));
3116 filt_ans_var.is_used = 1;
3117 filt_ans_var.is_user = 1;
3118 apval = APVAL(&filt_ans_var, ew);
3119 *apval = (f=msg_state_types(aval)) ? cpystr(f->name) : NULL;
3120 set_current_val(&filt_ans_var, FALSE, FALSE);
3122 inick_var.name = cpystr(_("Initialize settings using role"));
3123 inick_var.is_used = 1;
3124 inick_var.is_user = 1;
3125 apval = APVAL(&inick_var, ew);
3126 *apval = (def && def->action && def->action->inherit_nick &&
3127 def->action->inherit_nick[0])
3128 ? cpystr(def->action->inherit_nick) : NULL;
3130 role_fldr_ptr = &fldr_type_var; /* so radiobuttons can tell */
3131 fldr_type_var.name = cpystr(_("Current Folder Type"));
3132 fldr_type_var.is_used = 1;
3133 fldr_type_var.is_user = 1;
3134 apval = APVAL(&fldr_type_var, ew);
3135 *apval = (f=pat_fldr_types((def && def->patgrp) ? def->patgrp->fldr_type : (!def && edit_filter) ? FLDR_SPECIFIC : FLDR_DEFL)) ? cpystr(f->name) : NULL;
3136 set_current_val(&fldr_type_var, FALSE, FALSE);
3138 setup_dummy_pattern_var(&folder_pat_var, _("Folder List"),
3139 (def && def->patgrp) ? def->patgrp->folder : NULL);
3140 /* special default for folder_pat */
3141 alval = ALVAL(&folder_pat_var, ew);
3142 if(alval && !*alval && !def && edit_filter){
3143 char **ltmp;
3145 ltmp = (char **) fs_get(2 * sizeof(*ltmp));
3146 ltmp[0] = cpystr(ps_global->inbox_name);
3147 ltmp[1] = NULL;
3148 *alval = ltmp;
3149 set_current_val(&folder_pat_var, FALSE, FALSE);
3152 role_afrom_ptr = &abook_type_var; /* so radiobuttons can tell */
3153 abook_type_var.name = cpystr(_("Address in address book?"));
3154 abook_type_var.is_used = 1;
3155 abook_type_var.is_user = 1;
3156 apval = APVAL(&abook_type_var, ew);
3157 *apval = (f=inabook_fldr_types((def && def->patgrp) ? def->patgrp->inabook : IAB_EITHER)) ? cpystr(f->name) : NULL;
3158 set_current_val(&abook_type_var, FALSE, FALSE);
3160 /* TRANSLATORS: Abook is an abbreviation for Address Book */
3161 setup_dummy_pattern_var(&abook_pat_var, _("Abook List"),
3162 (def && def->patgrp) ? def->patgrp->abooks : NULL);
3165 * This is a little different from some of the other patterns. Tt is
3166 * actually a char ** in the struct instead of a PATTERN_S.
3168 cat_cmd_global_ptr = &cat_cmd_var;
3169 cat_cmd_var.name = cpystr(_("External Categorizer Commands"));
3170 cat_cmd_var.is_used = 1;
3171 cat_cmd_var.is_user = 1;
3172 cat_cmd_var.is_list = 1;
3173 alval = ALVAL(&cat_cmd_var, ew);
3174 *alval = (def && def->patgrp && def->patgrp->category_cmd &&
3175 def->patgrp->category_cmd[0])
3176 ? copy_list_array(def->patgrp->category_cmd) : NULL;
3177 set_current_val(&cat_cmd_var, FALSE, FALSE);
3179 cati_global_ptr = &cati_var;
3180 cati_var.name = cpystr(c_v_n);
3181 cati_var.is_used = 1;
3182 cati_var.is_user = 1;
3183 if(def && def->patgrp && def->patgrp->do_cat && def->patgrp->category_cmd &&
3184 def->patgrp->category_cmd[0]){
3185 apval = APVAL(&cati_var, ew);
3186 *apval = stringform_of_intvl(def->patgrp->cat);
3189 set_current_val(&cati_var, FALSE, FALSE);
3191 cat_lim_global_ptr = &cat_lim_var;
3192 cat_lim_var.name = cpystr(_("Character Limit"));
3193 cat_lim_var.is_used = 1;
3194 cat_lim_var.is_user = 1;
3195 cat_lim_var.global_val.p = cpystr("-1");
3196 apval = APVAL(&cat_lim_var, ew);
3197 if(def && def->patgrp && def->patgrp->category_cmd &&
3198 def->patgrp->category_cmd[0] && def->patgrp->cat_lim != -1){
3199 *apval = (char *) fs_get(20 * sizeof(char));
3200 snprintf(*apval, 20, "%ld", def->patgrp->cat_lim);
3201 (*apval)[20-1] = '\0';
3204 set_current_val(&cat_lim_var, FALSE, FALSE);
3206 from_act_var.name = cpystr(_("Set From"));
3207 from_act_var.is_used = 1;
3208 from_act_var.is_user = 1;
3209 if(def && def->action && def->action->from){
3210 char *bufp;
3211 size_t len;
3213 len = est_size(def->action->from);
3214 bufp = (char *) fs_get(len * sizeof(char));
3215 apval = APVAL(&from_act_var, ew);
3216 *apval = addr_string_mult(def->action->from, bufp, len);
3218 else{
3219 apval = APVAL(&from_act_var, ew);
3220 *apval = NULL;
3223 replyto_act_var.name = cpystr(_("Set Reply-To"));
3224 replyto_act_var.is_used = 1;
3225 replyto_act_var.is_user = 1;
3226 if(def && def->action && def->action->replyto){
3227 char *bufp;
3228 size_t len;
3230 len = est_size(def->action->replyto);
3231 bufp = (char *) fs_get(len * sizeof(char));
3232 apval = APVAL(&replyto_act_var, ew);
3233 *apval = addr_string_mult(def->action->replyto, bufp, len);
3235 else{
3236 apval = APVAL(&replyto_act_var, ew);
3237 *apval = NULL;
3240 fcc_act_var.name = cpystr(_("Set Fcc"));
3241 fcc_act_var.is_used = 1;
3242 fcc_act_var.is_user = 1;
3243 apval = APVAL(&fcc_act_var, ew);
3244 *apval = (def && def->action && def->action->fcc)
3245 ? cpystr(def->action->fcc) : NULL;
3247 sort_act_var.name = cpystr(_("Set Sort Order"));
3248 sort_act_var.is_used = 1;
3249 sort_act_var.is_user = 1;
3250 apval = APVAL(&sort_act_var, ew);
3251 if(def && def->action && def->action->is_a_other &&
3252 def->action->sort_is_set){
3253 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s", sort_name(def->action->sortorder),
3254 (def->action->revsort) ? "/Reverse" : "");
3255 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
3256 *apval = cpystr(tmp_20k_buf);
3258 else
3259 *apval = NULL;
3261 iform_act_var.name = cpystr(_("Set Index Format"));
3262 iform_act_var.is_used = 1;
3263 iform_act_var.is_user = 1;
3264 apval = APVAL(&iform_act_var, ew);
3265 *apval = (def && def->action && def->action->is_a_other &&
3266 def->action->index_format)
3267 ? cpystr(def->action->index_format) : NULL;
3268 if(ps_global->VAR_INDEX_FORMAT){
3269 iform_act_var.global_val.p = cpystr(ps_global->VAR_INDEX_FORMAT);
3270 set_current_val(&iform_act_var, FALSE, FALSE);
3273 startup_ptr = &startup_var;
3274 startup_var.name = cpystr(_("Set Startup Rule"));
3275 startup_var.is_used = 1;
3276 startup_var.is_user = 1;
3277 apval = APVAL(&startup_var, ew);
3278 *apval = NULL;
3279 if(def && def->action && def->action->is_a_other){
3280 *apval = (f=startup_rules(def->action->startup_rule))
3281 ? cpystr(f->name) : NULL;
3282 set_current_val(&startup_var, FALSE, FALSE);
3284 if(!*apval){
3285 *apval = (f=startup_rules(IS_NOTSET)) ? cpystr(f->name) : NULL;
3286 set_current_val(&startup_var, FALSE, FALSE);
3289 /* TRANSLATORS: LiteralSig is a way to keep the signature in the configuration
3290 file instead of in a separate Signature file. */
3291 litsig_act_var.name = cpystr(_("Set LiteralSig"));
3292 litsig_act_var.is_used = 1;
3293 litsig_act_var.is_user = 1;
3294 apval = APVAL(&litsig_act_var, ew);
3295 *apval = (def && def->action && def->action->litsig)
3296 ? cpystr(def->action->litsig) : NULL;
3298 sig_act_var.name = cpystr(_("Set Signature"));
3299 sig_act_var.is_used = 1;
3300 sig_act_var.is_user = 1;
3301 apval = APVAL(&sig_act_var, ew);
3302 *apval = (def && def->action && def->action->sig)
3303 ? cpystr(def->action->sig) : NULL;
3305 /* TRANSLATORS: A template is a skeleton of a message to be used
3306 for composing a new message */
3307 templ_act_var.name = cpystr(_("Set Template"));
3308 templ_act_var.is_used = 1;
3309 templ_act_var.is_user = 1;
3310 apval = APVAL(&templ_act_var, ew);
3311 *apval = (def && def->action && def->action->template)
3312 ? cpystr(def->action->template) : NULL;
3314 /* TRANSLATORS: Hdrs is an abbreviation for Headers */
3315 cstm_act_var.name = cpystr(_("Set Other Hdrs"));
3316 cstm_act_var.is_used = 1;
3317 cstm_act_var.is_user = 1;
3318 cstm_act_var.is_list = 1;
3319 alval = ALVAL(&cstm_act_var, ew);
3320 *alval = (def && def->action && def->action->cstm)
3321 ? copy_list_array(def->action->cstm) : NULL;
3323 smtp_act_var.name = cpystr(u_s_s);
3324 smtp_act_var.is_used = 1;
3325 smtp_act_var.is_user = 1;
3326 smtp_act_var.is_list = 1;
3327 alval = ALVAL(&smtp_act_var, ew);
3328 *alval = (def && def->action && def->action->smtp)
3329 ? copy_list_array(def->action->smtp) : NULL;
3331 nntp_act_var.name = cpystr(_("Use NNTP Server"));
3332 nntp_act_var.is_used = 1;
3333 nntp_act_var.is_user = 1;
3334 nntp_act_var.is_list = 1;
3335 alval = ALVAL(&nntp_act_var, ew);
3336 *alval = (def && def->action && def->action->nntp)
3337 ? copy_list_array(def->action->nntp) : NULL;
3339 score_act_global_ptr = &score_act_var;
3340 score_act_var.name = cpystr(_("Score Value"));
3341 score_act_var.is_used = 1;
3342 score_act_var.is_user = 1;
3343 if(def && def->action && def->action->scoreval >= SCORE_MIN &&
3344 def->action->scoreval <= SCORE_MAX)
3345 scoreval = def->action->scoreval;
3347 score_act_var.global_val.p = cpystr("0");
3348 if(scoreval != 0){
3349 apval = APVAL(&score_act_var, ew);
3350 *apval = (char *)fs_get(20 * sizeof(char));
3351 snprintf(*apval, 20, "%d", scoreval);
3352 (*apval)[20-1] = '\0';
3355 set_current_val(&score_act_var, FALSE, FALSE);
3357 hdrtok_act_var.name = cpystr(_("Score From Header"));
3358 hdrtok_act_var.is_used = 1;
3359 hdrtok_act_var.is_user = 1;
3360 if(def && def->action && def->action->scorevalhdrtok){
3361 apval = APVAL(&hdrtok_act_var, ew);
3362 *apval = hdrtok_to_stringform(def->action->scorevalhdrtok);
3365 set_current_val(&hdrtok_act_var, FALSE, FALSE);
3367 role_repl_ptr = &repl_type_var; /* so radiobuttons can tell */
3368 /* TRANSLATORS: For these, Use is a now. This part of the rule describes how
3369 it will be used when Replying so it is the Reply Use */
3370 repl_type_var.name = cpystr(_("Reply Use"));
3371 repl_type_var.is_used = 1;
3372 repl_type_var.is_user = 1;
3373 apval = APVAL(&repl_type_var, ew);
3374 *apval = (f=role_repl_types((def && def->action) ? def->action->repl_type : -1)) ? cpystr(f->name) : NULL;
3375 set_current_val(&repl_type_var, FALSE, FALSE);
3377 role_forw_ptr = &forw_type_var; /* so radiobuttons can tell */
3378 forw_type_var.name = cpystr(_("Forward Use"));
3379 forw_type_var.is_used = 1;
3380 forw_type_var.is_user = 1;
3381 apval = APVAL(&forw_type_var, ew);
3382 *apval = (f=role_forw_types((def && def->action) ? def->action->forw_type : -1)) ? cpystr(f->name) : NULL;
3383 set_current_val(&forw_type_var, FALSE, FALSE);
3385 comp_type_var.name = cpystr(_("Compose Use"));
3386 comp_type_var.is_used = 1;
3387 comp_type_var.is_user = 1;
3388 apval = APVAL(&comp_type_var, ew);
3389 *apval = (f=role_comp_types((def && def->action) ? def->action->comp_type : -1)) ? cpystr(f->name) : NULL;
3390 set_current_val(&comp_type_var, FALSE, FALSE);
3392 rolecolor_vars[0].is_used = 1;
3393 rolecolor_vars[0].is_user = 1;
3394 apval = APVAL(&rolecolor_vars[0], ew);
3395 *apval = (def && def->action && def->action->incol &&
3396 def->action->incol->fg[0])
3397 ? cpystr(def->action->incol->fg) : NULL;
3398 rolecolor_vars[1].is_used = 1;
3399 rolecolor_vars[1].is_user = 1;
3400 rolecolor_vars[0].name = cpystr("ic-foreground-color");
3401 rolecolor_vars[1].name = cpystr("ic-background-color");
3402 apval = APVAL(&rolecolor_vars[1], ew);
3403 *apval = (def && def->action && def->action->incol &&
3404 def->action->incol->bg[0])
3405 ? cpystr(def->action->incol->bg) : NULL;
3406 set_current_val(&rolecolor_vars[0], FALSE, FALSE);
3407 set_current_val(&rolecolor_vars[1], FALSE, FALSE);
3408 old_fg = PVAL(&rolecolor_vars[0], ew) ? cpystr(PVAL(&rolecolor_vars[0], ew))
3409 : NULL;
3410 old_bg = PVAL(&rolecolor_vars[1], ew) ? cpystr(PVAL(&rolecolor_vars[1], ew))
3411 : NULL;
3414 /* save the old opt_screen before calling scroll screen again */
3415 saved_screen = opt_screen;
3417 pindent = utf8_width(s_p_v_n); /* the longest one */
3418 maxpindent = pindent + 6;
3419 for(a = (def && def->patgrp) ? def->patgrp->arbhdr : NULL; a; a = a->next)
3420 if((lv=utf8_width(a->field ? a->field : "")+utf8_width(" pattern")) > pindent)
3421 pindent = lv;
3423 pindent = MIN(pindent, maxpindent);
3425 pindent += NOTLEN; /* width of `! ' */
3427 pindent += 3; /* width of ` = ' */
3429 /* Nickname */
3430 new_confline(&ctmp);
3431 ctmp->help_title= _("HELP FOR NICKNAME");
3432 ctmp->var = &nick_var;
3433 ctmp->valoffset = pindent;
3434 ctmp->keymenu = &config_role_keymenu;
3435 ctmp->help = edit_role ? h_config_role_nick :
3436 edit_incol ? h_config_incol_nick :
3437 edit_score ? h_config_score_nick :
3438 edit_other ? h_config_other_nick
3439 : h_config_filt_nick;
3440 ctmp->tool = t_tool;
3441 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, nick_var.name);
3442 tmp[sizeof(tmp)-1] = '\0';
3443 ctmp->varname = cpystr(tmp);
3444 ctmp->varnamep = ctmp;
3445 ctmp->value = pretty_value(ps, ctmp);
3446 ctmp->varmem = -1;
3448 first_line = ctmp;
3449 if(rflags & ROLE_CHANGES)
3450 first_line->flags |= CF_CHANGES;
3452 /* Comment */
3453 new_confline(&ctmp);
3454 ctmp->help_title= _("HELP FOR COMMENT");
3455 ctmp->var = &comment_var;
3456 ctmp->valoffset = pindent;
3457 ctmp->keymenu = &config_role_keymenu;
3458 ctmp->help = h_config_role_comment;
3459 ctmp->tool = role_litsig_text_tool;
3460 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, comment_var.name);
3461 tmp[sizeof(tmp)-1] = '\0';
3462 ctmp->varname = cpystr(tmp);
3463 ctmp->varnamep = ctmp;
3464 ctmp->value = pretty_value(ps, ctmp);
3465 ctmp->varmem = -1;
3467 /* Blank line */
3468 new_confline(&ctmp);
3469 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
3471 new_confline(&ctmp);
3472 ctmp->flags |= CF_NOSELECT;
3473 if(ps->ttyo->screen_cols >= (wid=utf8_width(fstr)) + 4){
3474 int dashes;
3476 dashes = (ps->ttyo->screen_cols - wid)/2;
3477 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='),
3478 fstr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '='));
3479 ctmp->value = cpystr(tmp_20k_buf);
3481 else
3482 ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '='));
3484 /* Blank line */
3485 new_confline(&ctmp);
3486 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
3488 /* Folder Type */
3489 new_confline(&ctmp);
3490 ctmp->var = &fldr_type_var;
3491 ctmp->keymenu = &config_radiobutton_keymenu;
3492 ctmp->help = NO_HELP;
3493 ctmp->tool = NULL;
3494 snprintf(tmp, sizeof(tmp), "%s =", fldr_type_var.name);
3495 tmp[sizeof(tmp)-1] = '\0';
3496 ctmp->varname = cpystr(tmp);
3497 ctmp->varnamep = ctmpb = ctmp;
3498 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM);
3500 new_confline(&ctmp);
3501 ctmp->var = NULL;
3502 ctmp->valoffset = rindent;
3503 ctmp->keymenu = &config_radiobutton_keymenu;
3504 ctmp->help = NO_HELP;
3505 ctmp->tool = NULL;
3506 ctmp->varnamep = ctmpb;
3507 ctmp->flags |= CF_NOSELECT;
3508 ctmp->value = cpystr("Set Choose One");
3510 new_confline(&ctmp);
3511 ctmp->var = NULL;
3512 ctmp->valoffset = rindent;
3513 ctmp->keymenu = &config_radiobutton_keymenu;
3514 ctmp->help = NO_HELP;
3515 ctmp->tool = radio_tool;
3516 ctmp->varnamep = ctmpb;
3517 ctmp->flags |= CF_NOSELECT;
3518 ctmp->value = cpystr(set_choose); \
3520 /* find longest value's name */
3521 for(lv = 0, i = 0; (f = pat_fldr_types(i)); i++)
3522 if(lv < (j = utf8_width(f->name)))
3523 lv = j;
3525 lv = MIN(lv, 100);
3527 fval = -1;
3528 for(i = 0; (f = pat_fldr_types(i)); i++){
3529 new_confline(&ctmp);
3530 ctmp->help_title= _("HELP FOR CURRENT FOLDER TYPE");
3531 ctmp->var = &fldr_type_var;
3532 ctmp->valoffset = rindent;
3533 ctmp->keymenu = &config_radiobutton_keymenu;
3534 ctmp->help = edit_role ? h_config_role_fldr_type :
3535 edit_incol ? h_config_incol_fldr_type :
3536 edit_score ? h_config_score_fldr_type :
3537 edit_other ? h_config_other_fldr_type
3538 : h_config_filt_fldr_type;
3539 ctmp->varmem = i;
3540 ctmp->tool = radio_tool;
3541 ctmp->varnamep = ctmpb;
3543 if((PVAL(&fldr_type_var, ew) &&
3544 !strucmp(PVAL(&fldr_type_var, ew), f->name))
3545 || (!PVAL(&fldr_type_var, ew) && f->value == FLDR_DEFL))
3546 fval = f->value;
3548 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w",
3549 (fval == f->value) ? R_SELD : ' ',
3550 lv, lv, f->name);
3551 tmp[sizeof(tmp)-1] = '\0';
3552 ctmp->value = cpystr(tmp);
3555 /* Folder */
3556 /* 5 is the width of `(*) ' */
3557 setup_role_pat_alt(ps, &ctmp, &folder_pat_var,
3558 edit_role ? h_config_role_fldr_type :
3559 edit_incol ? h_config_incol_fldr_type :
3560 edit_score ? h_config_score_fldr_type :
3561 edit_other ? h_config_other_fldr_type
3562 : h_config_filt_fldr_type,
3563 _("HELP FOR FOLDER LIST"),
3564 &config_role_patfolder_keymenu, t_tool, rindent+5,
3565 !(fval == FLDR_SPECIFIC));
3567 if(!per_folder_only){ /* sorry about that indent */
3569 /* Blank line */
3570 new_confline(&ctmp);
3571 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
3573 new_confline(&ctmp);
3574 ctmp->flags |= CF_NOSELECT;
3576 /* TRANSLATORS: The %s is replaced with one of the 4 or 5 words below, CURRENT,
3577 SCORED, and so on. */
3578 snprintf(mstr, sizeof(mstr), _(" %s MESSAGE CONDITIONS BEGIN HERE "),
3579 edit_role ? _("CURRENT") :
3580 edit_score ? _("SCORED") :
3581 edit_incol ? _("COLORED") :
3582 edit_filter ? _("FILTERED") : _("CURRENT"));
3583 mstr[sizeof(mstr)-1] = '\0';
3585 if(ps->ttyo->screen_cols >= (wid=utf8_width(mstr)) + 4){
3586 int dashes;
3588 dashes = (ps->ttyo->screen_cols - wid)/2;
3589 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='),
3590 mstr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '='));
3591 ctmp->value = cpystr(tmp_20k_buf);
3593 else
3594 ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '='));
3596 /* Blank line */
3597 new_confline(&ctmp);
3598 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
3600 setup_role_pat(ps, &ctmp, &to_pat_var,
3601 edit_role ? h_config_role_topat :
3602 edit_incol ? h_config_incol_topat :
3603 edit_score ? h_config_score_topat :
3604 edit_other ? h_config_other_topat
3605 : h_config_filt_topat,
3606 _("HELP FOR TO PATTERN"),
3607 &config_role_addr_pat_keymenu, t_tool, &earb, pindent);
3609 setup_role_pat(ps, &ctmp, &from_pat_var, h_config_role_frompat,
3610 _("HELP FOR FROM PATTERN"),
3611 &config_role_addr_pat_keymenu, t_tool, &earb, pindent);
3613 setup_role_pat(ps, &ctmp, &sender_pat_var, h_config_role_senderpat,
3614 _("HELP FOR SENDER PATTERN"),
3615 &config_role_addr_pat_keymenu, t_tool, &earb, pindent);
3617 setup_role_pat(ps, &ctmp, &cc_pat_var, h_config_role_ccpat,
3618 _("HELP FOR CC PATTERN"),
3619 &config_role_addr_pat_keymenu, t_tool, &earb, pindent);
3621 setup_role_pat(ps, &ctmp, &news_pat_var, h_config_role_newspat,
3622 _("HELP FOR NEWS PATTERN"),
3623 &config_role_keymenu_not, t_tool, &earb, pindent);
3625 setup_role_pat(ps, &ctmp, &subj_pat_var, h_config_role_subjpat,
3626 _("HELP FOR SUBJECT PATTERN"),
3627 &config_role_keymenu_not, t_tool, &earb, pindent);
3629 setup_role_pat(ps, &ctmp, &recip_pat_var, h_config_role_recippat,
3630 _("HELP FOR RECIPIENT PATTERN"),
3631 &config_role_addr_pat_keymenu, t_tool, &earb, pindent);
3633 setup_role_pat(ps, &ctmp, &partic_pat_var, h_config_role_particpat,
3634 _("HELP FOR PARTICIPANT PATTERN"),
3635 &config_role_addr_pat_keymenu, t_tool, &earb, pindent);
3637 /* Arbitrary Patterns */
3638 ea = NULL;
3639 for(j = 0, a = (def && def->patgrp) ? def->patgrp->arbhdr : NULL;
3641 j++, a = a->next){
3642 char *fn = (a->field) ? a->field : "";
3644 if(ea){
3645 ea->next = (EARB_S *)fs_get(sizeof(*ea));
3646 ea = ea->next;
3648 else{
3649 earb = (EARB_S *)fs_get(sizeof(*ea));
3650 ea = earb;
3653 memset((void *)ea, 0, sizeof(*ea));
3654 ea->v = (struct variable *)fs_get(sizeof(struct variable));
3655 memset((void *)ea->v, 0, sizeof(struct variable));
3656 ea->a = (ARBHDR_S *)fs_get(sizeof(ARBHDR_S));
3657 memset((void *)ea->a, 0, sizeof(ARBHDR_S));
3659 ea->a->field = cpystr(fn);
3661 p = (char *) fs_get(strlen(fn) + strlen(" pattern") + 1);
3662 snprintf(p, strlen(fn) + strlen(" pattern") + 1, "%s pattern", fn);
3663 p[strlen(fn) + strlen(" pattern") + 1 - 1] = '\0';
3664 setup_dummy_pattern_var(ea->v, p, a->p);
3665 fs_give((void **) &p);
3666 setup_role_pat(ps, &ctmp, ea->v, h_config_role_arbpat,
3667 ARB_HELP, &config_role_xtrahdr_keymenu,
3668 t_tool, &earb, pindent);
3671 new_confline(&ctmp);
3672 ctmp->help_title = _("HELP FOR EXTRA HEADERS");
3673 ctmp->value = cpystr(ADDXHDRS);
3674 ctmp->keymenu = &config_role_keymenu_extra;
3675 ctmp->help = h_config_role_arbpat;
3676 ctmp->tool = addhdr_tool;
3677 ctmp->d.earb = &earb;
3678 ctmp->varmem = -1;
3680 setup_role_pat(ps, &ctmp, &alltext_pat_var, h_config_role_alltextpat,
3681 _("HELP FOR ALL TEXT PATTERN"),
3682 &config_role_keymenu_not, t_tool, &earb, pindent);
3684 setup_role_pat(ps, &ctmp, &bodytext_pat_var, h_config_role_bodytextpat,
3685 _("HELP FOR BODY TEXT PATTERN"),
3686 &config_role_keymenu_not, t_tool, &earb, pindent);
3688 /* Age Interval */
3689 new_confline(&ctmp);
3690 ctmp->help_title= _("HELP FOR AGE INTERVAL");
3691 ctmp->var = &age_pat_var;
3692 ctmp->valoffset = pindent;
3693 ctmp->keymenu = &config_text_keymenu;
3694 ctmp->help = h_config_role_age;
3695 ctmp->tool = t_tool;
3696 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, age_pat_var.name);
3697 tmp[sizeof(tmp)-1] = '\0';
3698 ctmp->varname = cpystr(tmp);
3699 ctmp->varnamep = ctmp;
3700 ctmp->value = pretty_value(ps, ctmp);
3702 /* Size Interval */
3703 new_confline(&ctmp);
3704 ctmp->help_title= _("HELP FOR SIZE INTERVAL");
3705 ctmp->var = &size_pat_var;
3706 ctmp->valoffset = pindent;
3707 ctmp->keymenu = &config_text_keymenu;
3708 ctmp->help = h_config_role_size;
3709 ctmp->tool = t_tool;
3710 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, size_pat_var.name);
3711 tmp[sizeof(tmp)-1] = '\0';
3712 ctmp->varname = cpystr(tmp);
3713 ctmp->varnamep = ctmp;
3714 ctmp->value = pretty_value(ps, ctmp);
3716 if(!edit_score){
3717 /* Score Interval */
3718 new_confline(&ctmp);
3719 ctmp->help_title= _("HELP FOR SCORE INTERVAL");
3720 ctmp->var = &scorei_pat_var;
3721 ctmp->valoffset = pindent;
3722 ctmp->keymenu = &config_text_keymenu;
3723 ctmp->help = h_config_role_scorei;
3724 ctmp->tool = t_tool;
3725 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, scorei_pat_var.name);
3726 tmp[sizeof(tmp)-1] = '\0';
3727 ctmp->varname = cpystr(tmp);
3728 ctmp->varnamep = ctmp;
3729 ctmp->value = pretty_value(ps, ctmp);
3732 /* Keyword Pattern */
3733 setup_role_pat(ps, &ctmp, &keyword_pat_var, h_config_role_keywordpat,
3734 _("HELP FOR KEYWORD PATTERN"),
3735 &config_role_keyword_keymenu_not, role_text_tool_kword,
3736 NULL, pindent);
3738 /* Charset Pattern */
3739 setup_role_pat(ps, &ctmp, &charset_pat_var, h_config_role_charsetpat,
3740 _("HELP FOR CHARACTER SET PATTERN"),
3741 &config_role_charset_keymenu_not, role_text_tool_charset,
3742 NULL, pindent);
3744 /* Important Status */
3745 SETUP_PAT_STATUS(ctmp, stat_imp_var, def->patgrp->stat_imp,
3746 _("HELP FOR IMPORTANT STATUS"), h_config_role_stat_imp);
3747 /* New Status */
3748 SETUP_PAT_STATUS(ctmp, stat_new_var, def->patgrp->stat_new,
3749 _("HELP FOR NEW STATUS"), h_config_role_stat_new);
3750 /* Recent Status */
3751 SETUP_PAT_STATUS(ctmp, stat_rec_var, def->patgrp->stat_rec,
3752 _("HELP FOR RECENT STATUS"), h_config_role_stat_recent);
3753 /* Deleted Status */
3754 SETUP_PAT_STATUS(ctmp, stat_del_var, def->patgrp->stat_del,
3755 _("HELP FOR DELETED STATUS"), h_config_role_stat_del);
3756 /* Answered Status */
3757 SETUP_PAT_STATUS(ctmp, stat_ans_var, def->patgrp->stat_ans,
3758 _("HELP FOR ANSWERED STATUS"), h_config_role_stat_ans);
3759 /* 8-bit Subject */
3760 SETUP_PAT_STATUS(ctmp, stat_8bit_var, def->patgrp->stat_8bitsubj,
3761 _("HELP FOR 8-BIT SUBJECT"), h_config_role_stat_8bitsubj);
3762 /* Beginning of month */
3763 SETUP_PAT_STATUS(ctmp, stat_bom_var, def->patgrp->stat_bom,
3764 _("HELP FOR BEGINNING OF MONTH"), h_config_role_bom);
3765 /* Beginning of year */
3766 SETUP_PAT_STATUS(ctmp, stat_boy_var, def->patgrp->stat_boy,
3767 _("HELP FOR BEGINNING OF YEAR"), h_config_role_boy);
3769 /* Blank line */
3770 new_confline(&ctmp);
3771 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
3773 /* From in Addrbook */
3774 new_confline(&ctmp);
3775 ctmp->var = &abook_type_var;
3776 ctmp->keymenu = &config_radiobutton_keymenu;
3777 ctmp->help = NO_HELP;
3778 ctmp->tool = NULL;
3779 snprintf(tmp, sizeof(tmp), "%s =", abook_type_var.name);
3780 tmp[sizeof(tmp)-1] = '\0';
3781 ctmp->varname = cpystr(tmp);
3782 ctmp->varnamep = ctmpb = ctmp;
3783 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM);
3785 new_confline(&ctmp);
3786 ctmp->var = NULL;
3787 ctmp->valoffset = rindent;
3788 ctmp->keymenu = &config_radiobutton_keymenu;
3789 ctmp->help = NO_HELP;
3790 ctmp->tool = NULL;
3791 ctmp->varnamep = ctmpb;
3792 ctmp->flags |= CF_NOSELECT;
3793 ctmp->value = cpystr("Set Choose One");
3795 new_confline(&ctmp);
3796 ctmp->var = NULL;
3797 ctmp->valoffset = rindent;
3798 ctmp->keymenu = &config_radiobutton_keymenu;
3799 ctmp->help = NO_HELP;
3800 ctmp->tool = radio_tool;
3801 ctmp->varnamep = ctmpb;
3802 ctmp->flags |= CF_NOSELECT;
3803 ctmp->value = cpystr(set_choose); \
3805 /* find longest value's name */
3806 for(lv = 0, i = 0; (f = inabook_fldr_types(i)); i++)
3807 if(lv < (j = utf8_width(f->name)))
3808 lv = j;
3810 lv = MIN(lv, 100);
3812 fval = -1;
3813 for(i = 0; (f = inabook_fldr_types(i)); i++){
3814 new_confline(&ctmp);
3815 ctmp->help_title= _("HELP FOR ADDRESS IN ADDRESS BOOK");
3816 ctmp->var = &abook_type_var;
3817 ctmp->valoffset = rindent;
3818 ctmp->keymenu = &config_radiobutton_keymenu;
3819 ctmp->help = h_config_role_abookfrom;
3820 ctmp->varmem = i;
3821 ctmp->tool = radio_tool;
3822 ctmp->varnamep = ctmpb;
3824 if((PVAL(&abook_type_var, ew) &&
3825 !strucmp(PVAL(&abook_type_var, ew), f->name))
3826 || (!PVAL(&abook_type_var, ew) && f->value == IAB_DEFL))
3827 fval = f->value;
3829 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w",
3830 (fval == f->value) ? R_SELD : ' ',
3831 lv, lv, f->name);
3832 tmp[sizeof(tmp)-1] = '\0';
3833 ctmp->value = cpystr(tmp);
3836 /* Specific list of abooks */
3837 /* 5 is the width of `(*) ' */
3838 setup_role_pat_alt(ps, &ctmp, &abook_pat_var, h_config_role_abookfrom,
3839 _("HELP FOR ABOOK LIST"),
3840 &config_role_afrom_keymenu, role_text_tool_afrom, rindent+5,
3841 !(fval == IAB_SPEC_YES || fval == IAB_SPEC_NO));
3843 /* Which addresses to check for */
3844 inabook_type_var.name = cpystr(_("Types of addresses to check for in address book"));
3845 inabook_type_var.is_used = 1;
3846 inabook_type_var.is_user = 1;
3847 inabook_type_var.is_list = 1;
3848 clrbitmap(inabook_type_list);
3849 if(def && def->patgrp && def->patgrp->inabook & IAB_FROM)
3850 setbitn(INABOOK_FROM, inabook_type_list);
3851 if(def && def->patgrp && def->patgrp->inabook & IAB_REPLYTO)
3852 setbitn(INABOOK_REPLYTO, inabook_type_list);
3853 if(def && def->patgrp && def->patgrp->inabook & IAB_SENDER)
3854 setbitn(INABOOK_SENDER, inabook_type_list);
3855 if(def && def->patgrp && def->patgrp->inabook & IAB_TO)
3856 setbitn(INABOOK_TO, inabook_type_list);
3857 if(def && def->patgrp && def->patgrp->inabook & IAB_CC)
3858 setbitn(INABOOK_CC, inabook_type_list);
3860 /* default setting */
3861 if(!(bitnset(INABOOK_FROM, inabook_type_list)
3862 || bitnset(INABOOK_REPLYTO, inabook_type_list)
3863 || bitnset(INABOOK_SENDER, inabook_type_list)
3864 || bitnset(INABOOK_TO, inabook_type_list)
3865 || bitnset(INABOOK_CC, inabook_type_list))){
3866 setbitn(INABOOK_FROM, inabook_type_list);
3867 setbitn(INABOOK_REPLYTO, inabook_type_list);
3870 new_confline(&ctmp);
3871 ctmp->var = &inabook_type_var;
3872 ctmp->varoffset = 4;
3873 ctmp->valoffset = 23;
3874 ctmp->keymenu = &config_checkbox_keymenu;
3875 ctmp->help = NO_HELP;
3876 ctmp->tool = NULL;
3877 snprintf(tmp, sizeof(tmp), "%-20s =", inabook_type_var.name);
3878 tmp[sizeof(tmp)-1] = '\0';
3879 ctmp->varname = cpystr(tmp);
3880 ctmp->varnamep = ctmpb = ctmp;
3881 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM);
3883 new_confline(&ctmp);
3884 ctmp->var = NULL;
3885 ctmp->valoffset = rindent;
3886 ctmp->keymenu = &config_checkbox_keymenu;
3887 ctmp->help = NO_HELP;
3888 ctmp->tool = inabook_checkbox_tool;
3889 ctmp->varnamep = ctmpb;
3890 ctmp->flags |= CF_NOSELECT;
3891 ctmp->value = cpystr("Set Address types");
3893 new_confline(&ctmp);
3894 ctmp->var = NULL;
3895 ctmp->valoffset = rindent;
3896 ctmp->keymenu = &config_checkbox_keymenu;
3897 ctmp->help = NO_HELP;
3898 ctmp->tool = inabook_checkbox_tool;
3899 ctmp->varnamep = ctmpb;
3900 ctmp->flags |= CF_NOSELECT;
3901 ctmp->value = cpystr(set_choose);
3903 /* find longest value's name */
3904 for(lv = 0, i = 0; (f = inabook_feature_list(i)); i++){
3905 if(lv < (j = utf8_width(f->name)))
3906 lv = j;
3909 lv = MIN(lv, 100);
3911 for(i = 0; (f = inabook_feature_list(i)); i++){
3912 new_confline(&ctmp);
3913 ctmp->var = &opt_var;
3914 ctmp->help_title= _("HELP FOR ADDRESS TYPES");
3915 ctmp->varnamep = ctmpb;
3916 ctmp->keymenu = &config_checkbox_keymenu;
3917 switch(i){
3918 case INABOOK_FROM:
3919 ctmp->help = h_config_inabook_from;
3920 break;
3921 case INABOOK_REPLYTO:
3922 ctmp->help = h_config_inabook_replyto;
3923 break;
3924 case INABOOK_SENDER:
3925 ctmp->help = h_config_inabook_sender;
3926 break;
3927 case INABOOK_TO:
3928 ctmp->help = h_config_inabook_to;
3929 break;
3930 case INABOOK_CC:
3931 ctmp->help = h_config_inabook_cc;
3932 break;
3935 ctmp->tool = inabook_checkbox_tool;
3936 ctmp->valoffset = rindent;
3937 ctmp->varmem = i;
3938 utf8_snprintf(tmp, sizeof(tmp), "[%c] %-*.*w",
3939 bitnset(f->value, inabook_type_list) ? 'X' : ' ',
3940 lv, lv, f->name);
3941 tmp[sizeof(tmp)-1] = '\0';
3942 ctmp->value = cpystr(tmp);
3945 /* Blank line */
3946 new_confline(&ctmp);
3947 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
3949 /* 4 is indent of "Command", c_v_n is longest of these three, 3 is ` = ' */
3950 i = 4 + utf8_width(c_v_n) + 3;
3952 /* External Command Categorizer */
3953 new_confline(&ctmp);
3954 ctmp->var = &cat_cmd_var;
3955 ctmp->keymenu = &config_text_keymenu;
3956 ctmp->help = NO_HELP;
3957 ctmp->tool = NULL;
3958 snprintf(tmp, sizeof(tmp), "%s =", cat_cmd_var.name);
3959 tmp[sizeof(tmp)-1] = '\0';
3960 ctmp->varname = cpystr(tmp);
3961 ctmp->varnamep = ctmpb = ctmp;
3962 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM);
3964 /* Commands */
3965 new_confline(&ctmp);
3966 ctmp->help_title= _("HELP FOR CATEGORIZER COMMAND");
3967 ctmp->var = &cat_cmd_var;
3968 ctmp->varoffset = 4;
3969 ctmp->valoffset = i;
3970 ctmp->keymenu = &config_text_wshuf_keymenu;
3971 ctmp->help = h_config_role_cat_cmd;
3972 ctmp->tool = t_tool;
3973 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", i-4-3, i-4-3, "Command");
3974 tmp[sizeof(tmp)-1] = '\0';
3975 ctmp->varname = cpystr(tmp);
3976 ctmp->varnamep = ctmpb = ctmp;
3977 ctmp->flags = CF_STARTITEM;
3979 if((lval = LVAL(&cat_cmd_var, ew)) != NULL && lval[0]){
3980 for(j = 0; lval[j]; j++){
3981 if(j)
3982 (void) new_confline(&ctmp);
3984 ctmp->var = &cat_cmd_var;
3985 ctmp->varmem = j;
3986 ctmp->valoffset = i;
3987 ctmp->keymenu = &config_text_wshuf_keymenu;
3988 ctmp->help = h_config_role_cat_cmd;
3989 ctmp->tool = t_tool;
3990 ctmp->varnamep = ctmp;
3991 ctmp->value = pretty_value(ps, ctmp);
3994 else
3995 ctmp->value = pretty_value(ps, ctmp);
3997 /* Exit status interval */
3998 new_confline(&ctmp);
3999 ctmp->help_title= _("HELP FOR CATEGORIZER EXIT STATUS");
4000 ctmp->var = &cati_var;
4001 ctmp->varoffset = 4;
4002 ctmp->valoffset = i;
4003 ctmp->keymenu = &config_text_keymenu;
4004 ctmp->help = h_config_role_cat_status;
4005 ctmp->tool = t_tool;
4006 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", i-4-3, i-4-3, cati_var.name);
4007 tmp[sizeof(tmp)-1] = '\0';
4008 ctmp->varname = cpystr(tmp);
4009 ctmp->varnamep = ctmp;
4010 ctmp->value = pretty_value(ps, ctmp);
4012 /* Character Limit */
4013 new_confline(&ctmp);
4014 ctmp->help_title= _("HELP FOR CHARACTER LIMIT");
4015 ctmp->var = &cat_lim_var;
4016 ctmp->varoffset = 4;
4017 ctmp->valoffset = i;
4018 ctmp->keymenu = &config_text_keymenu;
4019 ctmp->help = h_config_role_cat_limit;
4020 ctmp->tool = t_tool;
4021 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", i-4-3, i-4-3, cat_lim_var.name);
4022 tmp[sizeof(tmp)-1] = '\0';
4023 ctmp->varname = cpystr(tmp);
4024 ctmp->varnamep = ctmp;
4025 ctmp->value = pretty_value(ps, ctmp);
4026 ctmp->flags |= CF_NUMBER;
4029 if(!edit_srch){ /* sorry about that indent */
4030 /* Actions */
4032 /* Blank line */
4033 new_confline(&ctmp);
4034 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4036 new_confline(&ctmp);
4037 ctmp->flags |= CF_NOSELECT;
4038 if(ps->ttyo->screen_cols >= (wid=utf8_width(astr)) + 4){
4039 int dashes;
4041 dashes = (ps->ttyo->screen_cols - wid)/2;
4042 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='),
4043 astr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '='));
4044 ctmp->value = cpystr(tmp_20k_buf);
4046 else
4047 ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '='));
4049 if(edit_role){
4050 int roindent;
4052 roindent = utf8_width(u_s_s); /* the longest one */
4053 roindent += 3; /* width of ` = ' */
4055 /* Blank line */
4056 new_confline(&ctmp);
4057 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4059 /* Inherit Nickname */
4060 new_confline(&ctmp);
4061 inick_confs[INICK_INICK_CONF] = ctmp;
4062 ctmp->help_title= _("HELP FOR INITIAL SET NICKNAME");
4063 ctmp->var = &inick_var;
4064 ctmp->keymenu = &config_role_inick_keymenu;
4065 ctmp->help = h_config_role_inick;
4066 ctmp->tool = role_text_tool_inick;
4067 snprintf(tmp, sizeof(tmp), "%s :", inick_var.name);
4068 tmp[sizeof(tmp)-1] = '\0';
4069 ctmp->valoffset = utf8_width(tmp)+1;
4070 ctmp->varname = cpystr(tmp);
4071 ctmp->varnamep = ctmp;
4073 /* From Action */
4074 new_confline(&ctmp);
4075 inick_confs[INICK_FROM_CONF] = ctmp;
4076 ctmp->help_title= _("HELP FOR SET FROM ACTION");
4077 ctmp->var = &from_act_var;
4078 ctmp->valoffset = roindent;
4079 ctmp->keymenu = &config_role_addr_act_keymenu;
4080 ctmp->help = h_config_role_setfrom;
4081 ctmp->tool = role_text_tool;
4082 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, from_act_var.name);
4083 tmp[sizeof(tmp)-1] = '\0';
4084 ctmp->varname = cpystr(tmp);
4085 ctmp->varnamep = ctmp;
4087 /* Reply-To Action */
4088 new_confline(&ctmp);
4089 inick_confs[INICK_REPLYTO_CONF] = ctmp;
4090 ctmp->help_title= _("HELP FOR SET REPLY-TO ACTION");
4091 ctmp->var = &replyto_act_var;
4092 ctmp->valoffset = roindent;
4093 ctmp->keymenu = &config_role_addr_act_keymenu;
4094 ctmp->help = h_config_role_setreplyto;
4095 ctmp->tool = role_text_tool;
4096 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, replyto_act_var.name);
4097 tmp[sizeof(tmp)-1] = '\0';
4098 ctmp->varname = cpystr(tmp);
4099 ctmp->varnamep = ctmp;
4101 /* Fcc Action */
4102 new_confline(&ctmp);
4103 inick_confs[INICK_FCC_CONF] = ctmp;
4104 ctmp->help_title= _("HELP FOR SET FCC ACTION");
4105 ctmp->var = &fcc_act_var;
4106 ctmp->valoffset = roindent;
4107 ctmp->keymenu = &config_role_actionfolder_keymenu;
4108 ctmp->help = h_config_role_setfcc;
4109 ctmp->tool = role_text_tool;
4110 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, fcc_act_var.name);
4111 tmp[sizeof(tmp)-1] = '\0';
4112 ctmp->varname = cpystr(tmp);
4113 ctmp->varnamep = ctmp;
4115 /* LitSig Action */
4116 new_confline(&ctmp);
4117 inick_confs[INICK_LITSIG_CONF] = ctmp;
4118 ctmp->help_title= _("HELP FOR SET LITERAL SIGNATURE ACTION");
4119 ctmp->var = &litsig_act_var;
4120 ctmp->valoffset = roindent;
4121 ctmp->keymenu = &config_text_keymenu;
4122 ctmp->help = h_config_role_setlitsig;
4123 ctmp->tool = role_litsig_text_tool;
4124 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, litsig_act_var.name);
4125 tmp[sizeof(tmp)-1] = '\0';
4126 ctmp->varname = cpystr(tmp);
4127 ctmp->varnamep = ctmp;
4129 /* Sig Action */
4130 new_confline(&ctmp);
4131 inick_confs[INICK_SIG_CONF] = ctmp;
4132 ctmp->help_title= _("HELP FOR SET SIGNATURE ACTION");
4133 ctmp->var = &sig_act_var;
4134 ctmp->valoffset = roindent;
4135 if(F_ON(F_DISABLE_ROLES_SIGEDIT, ps_global))
4136 ctmp->keymenu = &config_role_file_res_keymenu;
4137 else
4138 ctmp->keymenu = &config_role_file_keymenu;
4140 ctmp->help = h_config_role_setsig;
4141 ctmp->tool = role_text_tool;
4142 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, sig_act_var.name);
4143 tmp[sizeof(tmp)-1] = '\0';
4144 ctmp->varname = cpystr(tmp);
4145 ctmp->varnamep = ctmp;
4147 /* Template Action */
4148 new_confline(&ctmp);
4149 inick_confs[INICK_TEMPL_CONF] = ctmp;
4150 ctmp->help_title= _("HELP FOR SET TEMPLATE ACTION");
4151 ctmp->var = &templ_act_var;
4152 ctmp->valoffset = roindent;
4153 if(F_ON(F_DISABLE_ROLES_TEMPLEDIT, ps_global))
4154 ctmp->keymenu = &config_role_file_res_keymenu;
4155 else
4156 ctmp->keymenu = &config_role_file_keymenu;
4158 ctmp->help = h_config_role_settempl;
4159 ctmp->tool = role_text_tool;
4160 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, templ_act_var.name);
4161 tmp[sizeof(tmp)-1] = '\0';
4162 ctmp->varname = cpystr(tmp);
4163 ctmp->varnamep = ctmp;
4165 /* Other Headers Action */
4166 new_confline(&ctmp);
4167 inick_confs[INICK_CSTM_CONF] = ctmp;
4168 ctmp->help_title= _("HELP FOR SET OTHER HEADERS ACTION");
4169 ctmp->var = &cstm_act_var;
4170 ctmp->valoffset = roindent;
4171 ctmp->keymenu = &config_text_wshuf_keymenu;
4172 ctmp->help = h_config_role_setotherhdr;
4173 ctmp->tool = role_cstm_text_tool;
4174 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, cstm_act_var.name);
4175 tmp[sizeof(tmp)-1] = '\0';
4176 ctmp->varname = cpystr(tmp);
4177 ctmp->varnamep = ctmpb = ctmp;
4178 ctmp->flags = CF_STARTITEM;
4180 if((lval = LVAL(&cstm_act_var, ew)) != NULL){
4181 for(i = 0; lval[i]; i++){
4182 if(i)
4183 (void)new_confline(&ctmp);
4185 ctmp->var = &cstm_act_var;
4186 ctmp->varmem = i;
4187 ctmp->valoffset = roindent;
4188 ctmp->keymenu = &config_text_wshuf_keymenu;
4189 ctmp->help = h_config_role_setotherhdr;
4190 ctmp->tool = role_cstm_text_tool;
4191 ctmp->varnamep = ctmpb;
4194 else
4195 ctmp->varmem = 0;
4197 /* SMTP Server Action */
4198 new_confline(&ctmp);
4199 inick_confs[INICK_SMTP_CONF] = ctmp;
4200 ctmp->help_title= _("HELP FOR SMTP SERVER ACTION");
4201 ctmp->var = &smtp_act_var;
4202 ctmp->valoffset = roindent;
4203 ctmp->keymenu = &config_text_wshuf_keymenu;
4204 ctmp->help = h_config_role_usesmtp;
4205 ctmp->tool = t_tool;
4206 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, smtp_act_var.name);
4207 tmp[sizeof(tmp)-1] = '\0';
4208 ctmp->varname = cpystr(tmp);
4209 ctmp->varnamep = ctmpb = ctmp;
4210 ctmp->flags = CF_STARTITEM;
4212 if((lval = LVAL(&smtp_act_var, ew)) != NULL){
4213 for(i = 0; lval[i]; i++){
4214 if(i)
4215 (void)new_confline(&ctmp);
4217 ctmp->var = &smtp_act_var;
4218 ctmp->varmem = i;
4219 ctmp->valoffset = roindent;
4220 ctmp->keymenu = &config_text_wshuf_keymenu;
4221 ctmp->help = h_config_role_usesmtp;
4222 ctmp->tool = t_tool;
4223 ctmp->varnamep = ctmpb;
4226 else
4227 ctmp->varmem = 0;
4229 /* NNTP Server Action */
4230 new_confline(&ctmp);
4231 inick_confs[INICK_NNTP_CONF] = ctmp;
4232 ctmp->help_title= _("HELP FOR NNTP SERVER ACTION");
4233 ctmp->var = &nntp_act_var;
4234 ctmp->valoffset = roindent;
4235 ctmp->keymenu = &config_text_wshuf_keymenu;
4236 ctmp->help = h_config_role_usenntp;
4237 ctmp->tool = t_tool;
4238 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, nntp_act_var.name);
4239 tmp[sizeof(tmp)-1] = '\0';
4240 ctmp->varname = cpystr(tmp);
4241 ctmp->varnamep = ctmpb = ctmp;
4242 ctmp->flags = CF_STARTITEM;
4244 if((lval = LVAL(&nntp_act_var, ew)) != NULL){
4245 for(i = 0; lval[i]; i++){
4246 if(i)
4247 (void)new_confline(&ctmp);
4249 ctmp->var = &nntp_act_var;
4250 ctmp->varmem = i;
4251 ctmp->valoffset = roindent;
4252 ctmp->keymenu = &config_text_wshuf_keymenu;
4253 ctmp->help = h_config_role_usenntp;
4254 ctmp->tool = t_tool;
4255 ctmp->varnamep = ctmpb;
4258 else
4259 ctmp->varmem = 0;
4261 calculate_inick_stuff(ps);
4263 else
4264 inick_confs[INICK_INICK_CONF] = NULL;
4266 if(edit_score){
4267 int sindent;
4269 sindent = MAX(utf8_width(score_act_var.name),utf8_width(hdrtok_act_var.name)) + 3;
4271 /* Blank line */
4272 new_confline(&ctmp);
4273 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4275 /* Score Value -- This doesn't inherit from inick */
4276 new_confline(&ctmp);
4277 ctmp->help_title= _("HELP FOR SCORE VALUE ACTION");
4278 ctmp->var = &score_act_var;
4279 ctmp->valoffset = sindent;
4280 ctmp->keymenu = &config_text_keymenu;
4281 ctmp->help = h_config_role_scoreval;
4282 ctmp->tool = text_tool;
4283 ctmp->flags |= CF_NUMBER;
4284 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", sindent-3, sindent-3, score_act_var.name);
4285 tmp[sizeof(tmp)-1] = '\0';
4286 ctmp->varname = cpystr(tmp);
4287 ctmp->varnamep = ctmp;
4288 ctmp->value = pretty_value(ps, ctmp);
4290 new_confline(&ctmp);
4291 ctmp->flags |= CF_NOSELECT;
4292 ctmp->value = cpystr(" OR");
4294 /* Score From Header */
4295 new_confline(&ctmp);
4296 ctmp->help_title= _("HELP FOR SCORE VALUE FROM HEADER ACTION");
4297 ctmp->var = &hdrtok_act_var;
4298 ctmp->valoffset = sindent;
4299 ctmp->keymenu = &config_text_keymenu;
4300 ctmp->help = h_config_role_scorehdrtok;
4301 ctmp->tool = text_tool;
4302 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", sindent-3, sindent-3, hdrtok_act_var.name);
4303 tmp[sizeof(tmp)-1] = '\0';
4304 ctmp->varname = cpystr(tmp);
4305 ctmp->varnamep = ctmp;
4306 ctmp->value = pretty_value(ps, ctmp);
4309 if(edit_filter){
4311 * Filtering got added in stages, so instead of simply having a
4312 * variable in action which is set to one of the three possible
4313 * values (FILTER_KILL, FILTER_STATE, FILTER_FOLDER) we infer
4314 * the value from other variables. (Perhaps it would still make
4315 * sense to change this.)
4316 * Action->kill is set iff the user checks Delete.
4317 * If the user checks the box that says Just Set State, then kill
4318 * is not set and action->folder is not set (and vice versa).
4319 * And finally, FILTER_FOLDER is set if !kill and action->folder is set.
4320 * (And it is set here as the default if there is no default
4321 * action and the user is required to fill in the Folder.)
4323 if(def && def->action && def->action->kill)
4324 fval = FILTER_KILL;
4325 else if(def && def->action && !def->action->kill &&
4326 !def->action->folder)
4327 fval = FILTER_STATE;
4328 else
4329 fval = FILTER_FOLDER;
4331 role_filt_ptr = &filter_type_var; /* so radiobuttons can tell */
4332 filter_type_var.name = cpystr(_("Filter Action"));
4333 filter_type_var.is_used = 1;
4334 filter_type_var.is_user = 1;
4335 apval = APVAL(&filter_type_var, ew);
4336 *apval = (f=filter_types(fval)) ? cpystr(f->name) : NULL;
4337 set_current_val(&filter_type_var, FALSE, FALSE);
4339 /* Blank line */
4340 new_confline(&ctmp);
4341 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4343 /* Filter Type */
4344 new_confline(&ctmp);
4345 ctmp->var = &filter_type_var;
4346 ctmp->keymenu = &config_radiobutton_keymenu;
4347 ctmp->help = NO_HELP;
4348 ctmp->tool = NULL;
4349 snprintf(tmp, sizeof(tmp), "%s =", filter_type_var.name);
4350 tmp[sizeof(tmp)-1] = '\0';
4351 ctmp->varname = cpystr(tmp);
4352 ctmp->varnamep = ctmpb = ctmp;
4353 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM);
4355 new_confline(&ctmp);
4356 ctmp->var = NULL;
4357 ctmp->valoffset = rindent;
4358 ctmp->keymenu = &config_radiobutton_keymenu;
4359 ctmp->help = NO_HELP;
4360 ctmp->tool = NULL;
4361 ctmp->varnamep = ctmpb;
4362 ctmp->flags |= CF_NOSELECT;
4363 ctmp->value = cpystr("Set Choose One");
4365 new_confline(&ctmp);
4366 ctmp->var = NULL;
4367 ctmp->valoffset = rindent;
4368 ctmp->keymenu = &config_radiobutton_keymenu;
4369 ctmp->help = NO_HELP;
4370 ctmp->tool = radio_tool;
4371 ctmp->varnamep = ctmpb;
4372 ctmp->flags |= CF_NOSELECT;
4373 ctmp->value = cpystr(set_choose); \
4375 /* find longest value's name */
4376 for(lv = 0, i = 0; (f = filter_types(i)); i++)
4377 if(lv < (j = utf8_width(f->name)))
4378 lv = j;
4380 lv = MIN(lv, 100);
4382 for(i = 0; (f = filter_types(i)); i++){
4383 new_confline(&ctmp);
4384 ctmp->help_title= _("HELP FOR FILTER ACTION");
4385 ctmp->var = &filter_type_var;
4386 ctmp->valoffset = rindent;
4387 ctmp->keymenu = &config_radiobutton_keymenu;
4388 ctmp->help = h_config_filt_rule_type;
4389 ctmp->varmem = i;
4390 ctmp->tool = radio_tool;
4391 ctmp->varnamep = ctmpb;
4392 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", (f->value == fval) ? R_SELD : ' ',
4393 lv, lv, f->name);
4394 tmp[sizeof(tmp)-1] = '\0';
4395 ctmp->value = cpystr(tmp);
4398 /* Specific list of folders to copy to */
4399 setup_dummy_pattern_var(&folder_act_var, _("Folder List"),
4400 (def && def->action)
4401 ? def->action->folder : NULL);
4403 /* 5 is the width of `(*) ' */
4404 setup_role_pat_alt(ps, &ctmp, &folder_act_var, h_config_filter_folder,
4405 _("HELP FOR FILTER FOLDER NAME"),
4406 &config_role_actionfolder_keymenu, t_tool, rindent+5,
4407 !(fval == FILTER_FOLDER));
4409 SETUP_MSG_STATE(ctmp, filt_imp_var, ival,
4410 _("HELP FOR SET IMPORTANT STATUS"), h_config_filt_stat_imp);
4411 SETUP_MSG_STATE(ctmp, filt_new_var, nval,
4412 _("HELP FOR SET NEW STATUS"), h_config_filt_stat_new);
4413 SETUP_MSG_STATE(ctmp, filt_del_var, dval,
4414 _("HELP FOR SET DELETED STATUS"), h_config_filt_stat_del);
4415 SETUP_MSG_STATE(ctmp, filt_ans_var, aval,
4416 _("HELP FOR SET ANSWERED STATUS"), h_config_filt_stat_ans);
4418 /* Blank line */
4419 new_confline(&ctmp);
4420 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4422 /* Keywords to be Set */
4423 setup_dummy_pattern_var(&keyword_set_var, _("Set These Keywords"),
4424 (def && def->action)
4425 ? def->action->keyword_set : NULL);
4426 setup_role_pat(ps, &ctmp, &keyword_set_var, h_config_filter_kw_set,
4427 _("HELP FOR KEYWORDS TO BE SET"),
4428 &config_role_keyword_keymenu, role_text_tool_kword,
4429 NULL, 23);
4431 /* Keywords to be Cleared */
4432 setup_dummy_pattern_var(&keyword_clr_var, _("Clear These Keywords"),
4433 (def && def->action)
4434 ? def->action->keyword_clr : NULL);
4435 setup_role_pat(ps, &ctmp, &keyword_clr_var, h_config_filter_kw_clr,
4436 _("HELP FOR KEYWORDS TO BE CLEARED"),
4437 &config_role_keyword_keymenu, role_text_tool_kword,
4438 NULL, 23);
4441 if(edit_other){
4442 char *pval;
4443 int oindent;
4445 /* Blank line */
4446 new_confline(&ctmp);
4447 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4449 new_confline(&ctmp)->var = NULL;
4450 snprintf(tmp, sizeof(tmp), "%s =", sort_act_var.name);
4451 tmp[sizeof(tmp)-1] = '\0';
4452 ctmp->varname = cpystr(tmp);
4453 ctmp->varnamep = ctmpb = ctmp;
4454 ctmp->keymenu = &config_radiobutton_keymenu;
4455 ctmp->help = NO_HELP;
4456 ctmp->tool = role_sort_tool;
4457 ctmp->valoffset = rindent;
4458 ctmp->flags |= CF_NOSELECT;
4460 new_confline(&ctmp)->var = NULL;
4461 ctmp->varnamep = ctmpb;
4462 ctmp->keymenu = &config_radiobutton_keymenu;
4463 ctmp->help = NO_HELP;
4464 ctmp->tool = role_sort_tool;
4465 ctmp->valoffset = rindent;
4466 ctmp->flags |= CF_NOSELECT;
4467 ctmp->value = cpystr("Set Sort Options");
4469 new_confline(&ctmp)->var = NULL;
4470 ctmp->varnamep = ctmpb;
4471 ctmp->keymenu = &config_radiobutton_keymenu;
4472 ctmp->help = NO_HELP;
4473 ctmp->tool = role_sort_tool;
4474 ctmp->valoffset = rindent;
4475 ctmp->flags |= CF_NOSELECT;
4476 ctmp->value = cpystr(set_choose); \
4478 pval = PVAL(&sort_act_var, ew);
4479 if(pval)
4480 decode_sort(pval, &def_sort, &def_sort_rev);
4482 /* allow user to set their default sort order */
4483 new_confline(&ctmp)->var = &sort_act_var;
4484 ctmp->varnamep = ctmpb;
4485 ctmp->keymenu = &config_radiobutton_keymenu;
4486 ctmp->help = h_config_perfolder_sort;
4487 ctmp->tool = role_sort_tool;
4488 ctmp->valoffset = rindent;
4489 ctmp->varmem = -1;
4490 ctmp->value = generalized_sort_pretty_value(ps, ctmp, 0);
4492 for(j = 0; j < 2; j++){
4493 for(i = 0; ps->sort_types[i] != EndofList; i++){
4494 new_confline(&ctmp)->var = &sort_act_var;
4495 ctmp->varnamep = ctmpb;
4496 ctmp->keymenu = &config_radiobutton_keymenu;
4497 ctmp->help = h_config_perfolder_sort;
4498 ctmp->tool = role_sort_tool;
4499 ctmp->valoffset = rindent;
4500 ctmp->varmem = i + (j * EndofList);
4501 ctmp->value = generalized_sort_pretty_value(ps, ctmp,
4507 /* Blank line */
4508 new_confline(&ctmp);
4509 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4511 oindent = utf8_width(iform_act_var.name) + 3;
4513 /* Index Format Action */
4514 new_confline(&ctmp);
4515 ctmp->help_title= _("HELP FOR SET INDEX FORMAT ACTION");
4516 ctmp->var = &iform_act_var;
4517 ctmp->valoffset = oindent;
4518 ctmp->keymenu = &config_text_keymenu;
4519 ctmp->help = h_config_set_index_format;
4520 ctmp->tool = text_tool;
4521 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", oindent-3, oindent-3, iform_act_var.name);
4522 tmp[sizeof(tmp)-1] = '\0';
4523 ctmp->varname = cpystr(tmp);
4524 ctmp->varnamep = ctmp;
4525 ctmp->value = pretty_value(ps, ctmp);
4527 /* Blank line */
4528 new_confline(&ctmp);
4529 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4531 new_confline(&ctmp);
4532 ctmp->flags |= CF_STARTITEM;
4533 utf8_snprintf(tmp, sizeof(tmp), "%s =", startup_var.name);
4534 tmp[sizeof(tmp)-1] = '\0';
4535 ctmp->varname = cpystr(tmp);
4536 standard_radio_setup(ps, &ctmp, &startup_var, NULL);
4539 if(edit_incol && pico_usingcolor()){
4540 char *pval0, *pval1;
4541 int def;
4543 /* Blank line */
4544 new_confline(&ctmp);
4545 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4547 new_confline(&ctmp);
4548 ctmp->var = &rolecolor_vars[0]; /* foreground */
4549 ctmp->varname = cpystr(_("Index Line Color ="));
4550 ctmp->varnamep = ctmpb = ctmp;
4551 ctmp->flags |= (CF_STARTITEM | CF_NOSELECT);
4552 ctmp->keymenu = &role_color_setting_keymenu;
4554 pval0 = PVAL(&rolecolor_vars[0], ew);
4555 pval1 = PVAL(&rolecolor_vars[1], ew);
4556 if(pval0 && pval1)
4557 def = !(pval0[0] && pval1[1]);
4558 else
4559 def = 1;
4561 add_color_setting_disp(ps, &ctmp, &rolecolor_vars[0], ctmpb,
4562 &role_color_setting_keymenu,
4563 &config_checkbox_keymenu,
4564 h_config_incol,
4565 rindent, 0,
4566 def ? ps->VAR_NORM_FORE_COLOR
4567 : PVAL(&rolecolor_vars[0], ew),
4568 def ? ps->VAR_NORM_BACK_COLOR
4569 : PVAL(&rolecolor_vars[1], ew),
4570 def);
4574 if(need_options){
4575 /* Options */
4577 /* Blank line */
4578 new_confline(&ctmp);
4579 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4581 new_confline(&ctmp);
4582 ctmp->flags |= CF_NOSELECT;
4583 if(ps->ttyo->screen_cols >= (wid=utf8_width(ostr)) + 4){
4584 int dashes;
4586 dashes = (ps->ttyo->screen_cols - wid)/2;
4587 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='),
4588 ostr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '='));
4589 ctmp->value = cpystr(tmp_20k_buf);
4591 else
4592 ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '='));
4594 /* Blank line */
4595 new_confline(&ctmp);
4596 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4598 opt_var.name = cpystr(_("Features"));
4599 opt_var.is_used = 1;
4600 opt_var.is_user = 1;
4601 opt_var.is_list = 1;
4602 clrbitmap(feat_option_list);
4603 if(def && def->patgrp && def->patgrp->age_uses_sentdate)
4604 setbitn(FEAT_SENTDATE, feat_option_list);
4606 if(edit_filter){
4607 if(def && def->action && def->action->move_only_if_not_deleted)
4608 setbitn(FEAT_IFNOTDEL, feat_option_list);
4609 if(def && def->action && def->action->non_terminating)
4610 setbitn(FEAT_NONTERM, feat_option_list);
4613 /* Options */
4614 new_confline(&ctmp);
4615 ctmp->var = &opt_var;
4616 ctmp->valoffset = 23;
4617 ctmp->keymenu = &config_checkbox_keymenu;
4618 ctmp->help = NO_HELP;
4619 ctmp->tool = NULL;
4620 snprintf(tmp, sizeof(tmp), "%-20s =", opt_var.name);
4621 tmp[sizeof(tmp)-1] = '\0';
4622 ctmp->varname = cpystr(tmp);
4623 ctmp->varnamep = ctmpb = ctmp;
4624 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM);
4626 new_confline(&ctmp);
4627 ctmp->var = NULL;
4628 ctmp->valoffset = rindent;
4629 ctmp->keymenu = &config_checkbox_keymenu;
4630 ctmp->help = NO_HELP;
4631 ctmp->tool = feat_checkbox_tool;
4632 ctmp->varnamep = ctmpb;
4633 ctmp->flags |= CF_NOSELECT;
4634 ctmp->value = cpystr("Set Feature Name");
4636 new_confline(&ctmp);
4637 ctmp->var = NULL;
4638 ctmp->valoffset = rindent;
4639 ctmp->keymenu = &config_checkbox_keymenu;
4640 ctmp->help = NO_HELP;
4641 ctmp->tool = feat_checkbox_tool;
4642 ctmp->varnamep = ctmpb;
4643 ctmp->flags |= CF_NOSELECT;
4644 ctmp->value = cpystr(set_choose); \
4646 /* find longest value's name */
4647 for(lv = 0, i = 0; (f = feat_feature_list(i)); i++){
4648 if(!edit_filter && (i == FEAT_IFNOTDEL || i == FEAT_NONTERM))
4649 continue;
4651 if(lv < (j = utf8_width(f->name)))
4652 lv = j;
4655 lv = MIN(lv, 100);
4657 for(i = 0; (f = feat_feature_list(i)); i++){
4658 if(!edit_filter && (i == FEAT_IFNOTDEL || i == FEAT_NONTERM))
4659 continue;
4661 new_confline(&ctmp);
4662 ctmp->var = &opt_var;
4663 ctmp->help_title= _("HELP FOR FILTER FEATURES");
4664 ctmp->varnamep = ctmpb;
4665 ctmp->keymenu = &config_checkbox_keymenu;
4666 switch(i){
4667 case FEAT_SENTDATE:
4668 ctmp->help = h_config_filt_opts_sentdate;
4669 break;
4670 case FEAT_IFNOTDEL:
4671 ctmp->help = h_config_filt_opts_notdel;
4672 break;
4673 case FEAT_NONTERM:
4674 ctmp->help = h_config_filt_opts_nonterm;
4675 break;
4678 ctmp->tool = feat_checkbox_tool;
4679 ctmp->valoffset = rindent;
4680 ctmp->varmem = i;
4681 utf8_snprintf(tmp, sizeof(tmp), "[%c] %-*.*w",
4682 bitnset(f->value, feat_option_list) ? 'X' : ' ',
4683 lv, lv, f->name);
4684 tmp[sizeof(tmp)-1] = '\0';
4685 ctmp->value = cpystr(tmp);
4689 if(need_uses){
4690 /* Uses */
4692 /* Blank line */
4693 new_confline(&ctmp);
4694 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4696 new_confline(&ctmp);
4697 ctmp->flags |= CF_NOSELECT;
4698 if(ps->ttyo->screen_cols >= (wid=utf8_width(ustr)) + 4){
4699 int dashes;
4701 dashes = (ps->ttyo->screen_cols - wid)/2;
4702 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='),
4703 ustr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '='));
4704 ctmp->value = cpystr(tmp_20k_buf);
4706 else
4707 ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '='));
4709 /* Blank line */
4710 new_confline(&ctmp);
4711 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4713 /* Reply Type */
4714 new_confline(&ctmp);
4715 ctmp->var = &repl_type_var;
4716 ctmp->keymenu = &config_radiobutton_keymenu;
4717 ctmp->help = NO_HELP;
4718 ctmp->tool = NULL;
4719 snprintf(tmp, sizeof(tmp), "%s =", repl_type_var.name);
4720 tmp[sizeof(tmp)-1] = '\0';
4721 ctmp->varname = cpystr(tmp);
4722 ctmp->varnamep = ctmpb = ctmp;
4723 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM);
4725 new_confline(&ctmp);
4726 ctmp->var = NULL;
4727 ctmp->valoffset = rindent;
4728 ctmp->keymenu = &config_radiobutton_keymenu;
4729 ctmp->help = NO_HELP;
4730 ctmp->tool = NULL;
4731 ctmp->varnamep = ctmpb;
4732 ctmp->flags |= CF_NOSELECT;
4733 ctmp->value = cpystr("Set Choose One");
4735 new_confline(&ctmp);
4736 ctmp->var = NULL;
4737 ctmp->valoffset = rindent;
4738 ctmp->keymenu = &config_radiobutton_keymenu;
4739 ctmp->help = NO_HELP;
4740 ctmp->tool = radio_tool;
4741 ctmp->varnamep = ctmpb;
4742 ctmp->flags |= CF_NOSELECT;
4743 ctmp->value = cpystr(set_choose); \
4745 /* find longest value's name */
4746 for(lv = 0, i = 0; (f = role_repl_types(i)); i++)
4747 if(lv < (j = utf8_width(f->name)))
4748 lv = j;
4750 lv = MIN(lv, 100);
4752 for(i = 0; (f = role_repl_types(i)); i++){
4753 new_confline(&ctmp);
4754 ctmp->help_title= _("HELP FOR ROLE REPLY USE");
4755 ctmp->var = &repl_type_var;
4756 ctmp->valoffset = rindent;
4757 ctmp->keymenu = &config_radiobutton_keymenu;
4758 ctmp->help = h_config_role_replyuse;
4759 ctmp->varmem = i;
4760 ctmp->tool = radio_tool;
4761 ctmp->varnamep = ctmpb;
4762 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", (((!(def && def->action) ||
4763 def->action->repl_type == -1) &&
4764 f->value == ROLE_REPL_DEFL) ||
4765 (def && def->action &&
4766 f->value == def->action->repl_type))
4767 ? R_SELD : ' ',
4768 lv, lv, f->name);
4769 tmp[sizeof(tmp)-1] = '\0';
4770 ctmp->value = cpystr(tmp);
4773 /* Blank line */
4774 new_confline(&ctmp);
4775 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4777 /* Forward Type */
4778 new_confline(&ctmp);
4779 ctmp->var = &forw_type_var;
4780 ctmp->keymenu = &config_radiobutton_keymenu;
4781 ctmp->help = NO_HELP;
4782 ctmp->tool = NULL;
4783 snprintf(tmp, sizeof(tmp), "%s =", forw_type_var.name);
4784 tmp[sizeof(tmp)-1] = '\0';
4785 ctmp->varname = cpystr(tmp);
4786 ctmp->varnamep = ctmpb = ctmp;
4787 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM);
4789 new_confline(&ctmp);
4790 ctmp->var = NULL;
4791 ctmp->valoffset = rindent;
4792 ctmp->keymenu = &config_radiobutton_keymenu;
4793 ctmp->help = NO_HELP;
4794 ctmp->tool = NULL;
4795 ctmp->varnamep = ctmpb;
4796 ctmp->flags |= CF_NOSELECT;
4797 ctmp->value = cpystr("Set Choose One");
4799 new_confline(&ctmp);
4800 ctmp->var = NULL;
4801 ctmp->valoffset = rindent;
4802 ctmp->keymenu = &config_radiobutton_keymenu;
4803 ctmp->help = NO_HELP;
4804 ctmp->tool = radio_tool;
4805 ctmp->varnamep = ctmpb;
4806 ctmp->flags |= CF_NOSELECT;
4807 ctmp->value = cpystr(set_choose); \
4809 /* find longest value's name */
4810 for(lv = 0, i = 0; (f = role_forw_types(i)); i++)
4811 if(lv < (j = utf8_width(f->name)))
4812 lv = j;
4814 lv = MIN(lv, 100);
4816 for(i = 0; (f = role_forw_types(i)); i++){
4817 new_confline(&ctmp);
4818 ctmp->help_title= _("HELP FOR ROLE FORWARD USE");
4819 ctmp->var = &forw_type_var;
4820 ctmp->valoffset = rindent;
4821 ctmp->keymenu = &config_radiobutton_keymenu;
4822 ctmp->help = h_config_role_forwarduse;
4823 ctmp->varmem = i;
4824 ctmp->tool = radio_tool;
4825 ctmp->varnamep = ctmpb;
4826 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", (((!(def && def->action) ||
4827 def->action->forw_type == -1) &&
4828 f->value == ROLE_FORW_DEFL) ||
4829 (def && def->action &&
4830 f->value == def->action->forw_type))
4831 ? R_SELD : ' ',
4832 lv, lv, f->name);
4833 tmp[sizeof(tmp)-1] = '\0';
4834 ctmp->value = cpystr(tmp);
4837 /* Blank line */
4838 new_confline(&ctmp);
4839 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4841 /* Compose Type */
4842 new_confline(&ctmp);
4843 ctmp->var = &comp_type_var;
4844 ctmp->keymenu = &config_radiobutton_keymenu;
4845 ctmp->help = NO_HELP;
4846 ctmp->tool = NULL;
4847 snprintf(tmp, sizeof(tmp), "%s =", comp_type_var.name);
4848 tmp[sizeof(tmp)-1] = '\0';
4849 ctmp->varname = cpystr(tmp);
4850 ctmp->varnamep = ctmpb = ctmp;
4851 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM);
4853 new_confline(&ctmp);
4854 ctmp->var = NULL;
4855 ctmp->valoffset = rindent;
4856 ctmp->keymenu = &config_radiobutton_keymenu;
4857 ctmp->help = NO_HELP;
4858 ctmp->tool = NULL;
4859 ctmp->varnamep = ctmpb;
4860 ctmp->flags |= CF_NOSELECT;
4861 ctmp->value = cpystr("Set Choose One");
4863 new_confline(&ctmp);
4864 ctmp->var = NULL;
4865 ctmp->valoffset = rindent;
4866 ctmp->keymenu = &config_radiobutton_keymenu;
4867 ctmp->help = NO_HELP;
4868 ctmp->tool = radio_tool;
4869 ctmp->varnamep = ctmpb;
4870 ctmp->flags |= CF_NOSELECT;
4871 ctmp->value = cpystr(set_choose); \
4873 /* find longest value's name */
4874 for(lv = 0, i = 0; (f = role_comp_types(i)); i++)
4875 if(lv < (j = utf8_width(f->name)))
4876 lv = j;
4878 lv = MIN(lv, 100);
4880 for(i = 0; (f = role_comp_types(i)); i++){
4881 new_confline(&ctmp);
4882 ctmp->help_title= _("HELP FOR ROLE COMPOSE USE");
4883 ctmp->var = &comp_type_var;
4884 ctmp->valoffset = rindent;
4885 ctmp->keymenu = &config_radiobutton_keymenu;
4886 ctmp->help = h_config_role_composeuse;
4887 ctmp->varmem = i;
4888 ctmp->tool = radio_tool;
4889 ctmp->varnamep = ctmpb;
4890 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", (((!(def && def->action) ||
4891 def->action->comp_type == -1) &&
4892 f->value == ROLE_COMP_DEFL) ||
4893 (def && def->action &&
4894 f->value == def->action->comp_type))
4895 ? R_SELD : ' ',
4896 lv, lv, f->name);
4897 tmp[sizeof(tmp)-1] = '\0';
4898 ctmp->value = cpystr(tmp);
4902 memset(&screen, 0, sizeof(screen));
4903 screen.ro_warning = saved_screen ? saved_screen->deferred_ro_warning : 0;
4904 /* TRANSLATORS: Print something1 using something2.
4905 "roles" is something1 */
4906 rv = conf_scroll_screen(ps, &screen, first_line, title, _("roles"),
4907 (edit_incol && pico_usingcolor()) ? 1 : 0, NULL);
4910 * Now look at the fake variables and extract the information we
4911 * want from them.
4914 if(rv == 1 && result){
4916 * We know these variables exist, so we don't have to check that
4917 * apval is nonnull before evaluating *apval.
4919 apval = APVAL(&nick_var, ew);
4920 nick = *apval;
4921 *apval = NULL;
4922 removing_leading_and_trailing_white_space(nick);
4924 apval = APVAL(&comment_var, ew);
4925 comment = *apval;
4926 *apval = NULL;
4927 removing_leading_and_trailing_white_space(comment);
4929 alval = ALVAL(&to_pat_var, ew);
4930 to_pat = *alval;
4931 *alval = NULL;
4933 alval = ALVAL(&from_pat_var, ew);
4934 from_pat = *alval;
4935 *alval = NULL;
4937 alval = ALVAL(&sender_pat_var, ew);
4938 sender_pat = *alval;
4939 *alval = NULL;
4941 alval = ALVAL(&cc_pat_var, ew);
4942 cc_pat = *alval;
4943 *alval = NULL;
4945 alval = ALVAL(&recip_pat_var, ew);
4946 recip_pat = *alval;
4947 *alval = NULL;
4949 alval = ALVAL(&partic_pat_var, ew);
4950 partic_pat = *alval;
4951 *alval = NULL;
4953 alval = ALVAL(&news_pat_var, ew);
4954 news_pat = *alval;
4955 *alval = NULL;
4957 alval = ALVAL(&subj_pat_var, ew);
4958 subj_pat = *alval;
4959 *alval = NULL;
4961 alval = ALVAL(&alltext_pat_var, ew);
4962 alltext_pat = *alval;
4963 *alval = NULL;
4965 alval = ALVAL(&bodytext_pat_var, ew);
4966 bodytext_pat = *alval;
4967 *alval = NULL;
4969 alval = ALVAL(&keyword_pat_var, ew);
4970 keyword_pat = *alval;
4971 *alval = NULL;
4973 alval = ALVAL(&charset_pat_var, ew);
4974 charset_pat = *alval;
4975 *alval = NULL;
4977 apval = APVAL(&age_pat_var, ew);
4978 age_pat = *apval;
4979 *apval = NULL;
4980 removing_leading_and_trailing_white_space(age_pat);
4982 apval = APVAL(&size_pat_var, ew);
4983 size_pat = *apval;
4984 *apval = NULL;
4985 removing_leading_and_trailing_white_space(size_pat);
4987 apval = APVAL(&scorei_pat_var, ew);
4988 scorei_pat = *apval;
4989 *apval = NULL;
4990 removing_leading_and_trailing_white_space(scorei_pat);
4992 apval = APVAL(&stat_del_var, ew);
4993 stat_del = *apval;
4994 *apval = NULL;
4995 removing_leading_and_trailing_white_space(stat_del);
4997 apval = APVAL(&stat_new_var, ew);
4998 stat_new = *apval;
4999 *apval = NULL;
5000 removing_leading_and_trailing_white_space(stat_new);
5002 apval = APVAL(&stat_rec_var, ew);
5003 stat_rec = *apval;
5004 *apval = NULL;
5005 removing_leading_and_trailing_white_space(stat_rec);
5007 apval = APVAL(&stat_imp_var, ew);
5008 stat_imp = *apval;
5009 *apval = NULL;
5010 removing_leading_and_trailing_white_space(stat_imp);
5012 apval = APVAL(&stat_ans_var, ew);
5013 stat_ans = *apval;
5014 *apval = NULL;
5015 removing_leading_and_trailing_white_space(stat_ans);
5017 apval = APVAL(&stat_8bit_var, ew);
5018 stat_8bit = *apval;
5019 *apval = NULL;
5020 removing_leading_and_trailing_white_space(stat_8bit);
5022 apval = APVAL(&stat_bom_var, ew);
5023 stat_bom = *apval;
5024 *apval = NULL;
5025 removing_leading_and_trailing_white_space(stat_bom);
5027 apval = APVAL(&stat_boy_var, ew);
5028 stat_boy = *apval;
5029 *apval = NULL;
5030 removing_leading_and_trailing_white_space(stat_boy);
5032 apval = APVAL(&fldr_type_var, ew);
5033 fldr_type_pat = *apval;
5034 *apval = NULL;
5035 removing_leading_and_trailing_white_space(fldr_type_pat);
5037 alval = ALVAL(&folder_pat_var, ew);
5038 folder_pat = *alval;
5039 *alval = NULL;
5041 apval = APVAL(&abook_type_var, ew);
5042 abook_type_pat = *apval;
5043 *apval = NULL;
5044 removing_leading_and_trailing_white_space(abook_type_pat);
5046 alval = ALVAL(&abook_pat_var, ew);
5047 abook_pat = *alval;
5048 *alval = NULL;
5050 apval = APVAL(&cati_var, ew);
5051 cati = *apval;
5052 *apval = NULL;
5053 removing_leading_and_trailing_white_space(cati);
5055 apval = APVAL(&cat_lim_var, ew);
5056 cat_lim = *apval;
5057 *apval = NULL;
5058 removing_leading_and_trailing_white_space(cat_lim);
5060 apval = APVAL(&inick_var, ew);
5061 inick = *apval;
5062 *apval = NULL;
5063 removing_leading_and_trailing_white_space(inick);
5065 apval = APVAL(&from_act_var, ew);
5066 from_act = *apval;
5067 *apval = NULL;
5068 removing_leading_and_trailing_white_space(from_act);
5070 apval = APVAL(&replyto_act_var, ew);
5071 replyto_act = *apval;
5072 *apval = NULL;
5073 removing_leading_and_trailing_white_space(replyto_act);
5075 apval = APVAL(&fcc_act_var, ew);
5076 fcc_act = *apval;
5077 *apval = NULL;
5078 removing_leading_and_trailing_white_space(fcc_act);
5080 apval = APVAL(&litsig_act_var, ew);
5081 litsig_act = *apval;
5082 *apval = NULL;
5083 removing_leading_and_trailing_white_space(litsig_act);
5085 apval = APVAL(&sort_act_var, ew);
5086 sort_act = *apval;
5087 *apval = NULL;
5088 removing_leading_and_trailing_white_space(sort_act);
5090 apval = APVAL(&iform_act_var, ew);
5091 iform_act = *apval;
5092 *apval = NULL;
5093 removing_leading_and_trailing_white_space(iform_act);
5095 apval = APVAL(&startup_var, ew);
5096 startup_act = *apval;
5097 *apval = NULL;
5098 removing_leading_and_trailing_white_space(startup_act);
5100 apval = APVAL(&sig_act_var, ew);
5101 sig_act = *apval;
5102 *apval = NULL;
5103 removing_leading_and_trailing_white_space(sig_act);
5105 apval = APVAL(&templ_act_var, ew);
5106 templ_act = *apval;
5107 *apval = NULL;
5108 removing_leading_and_trailing_white_space(templ_act);
5110 apval = APVAL(&score_act_var, ew);
5111 score_act = *apval;
5112 *apval = NULL;
5113 removing_leading_and_trailing_white_space(score_act);
5115 apval = APVAL(&hdrtok_act_var, ew);
5116 hdrtok_act = *apval;
5117 *apval = NULL;
5118 removing_leading_and_trailing_white_space(hdrtok_act);
5120 apval = APVAL(&repl_type_var, ew);
5121 repl_type = *apval;
5122 *apval = NULL;
5123 removing_leading_and_trailing_white_space(repl_type);
5125 apval = APVAL(&forw_type_var, ew);
5126 forw_type = *apval;
5127 *apval = NULL;
5128 removing_leading_and_trailing_white_space(forw_type);
5130 apval = APVAL(&comp_type_var, ew);
5131 comp_type = *apval;
5132 *apval = NULL;
5133 removing_leading_and_trailing_white_space(comp_type);
5135 apval = APVAL(&rolecolor_vars[0], ew);
5136 rc_fg = *apval;
5137 *apval = NULL;
5138 removing_leading_and_trailing_white_space(rc_fg);
5140 apval = APVAL(&rolecolor_vars[1], ew);
5141 rc_bg = *apval;
5142 *apval = NULL;
5143 removing_leading_and_trailing_white_space(rc_bg);
5145 apval = APVAL(&filter_type_var, ew);
5146 filter_type = *apval;
5147 *apval = NULL;
5148 removing_leading_and_trailing_white_space(filter_type);
5150 alval = ALVAL(&folder_act_var, ew);
5151 folder_act = *alval;
5152 *alval = NULL;
5154 alval = ALVAL(&keyword_set_var, ew);
5155 keyword_set = *alval;
5156 *alval = NULL;
5158 alval = ALVAL(&keyword_clr_var, ew);
5159 keyword_clr = *alval;
5160 *alval = NULL;
5162 apval = APVAL(&filt_imp_var, ew);
5163 filt_imp = *apval;
5164 *apval = NULL;
5165 removing_leading_and_trailing_white_space(filt_imp);
5167 apval = APVAL(&filt_del_var, ew);
5168 filt_del = *apval;
5169 *apval = NULL;
5170 removing_leading_and_trailing_white_space(filt_del);
5172 apval = APVAL(&filt_new_var, ew);
5173 filt_new = *apval;
5174 *apval = NULL;
5175 removing_leading_and_trailing_white_space(filt_new);
5177 apval = APVAL(&filt_ans_var, ew);
5178 filt_ans = *apval;
5179 *apval = NULL;
5180 removing_leading_and_trailing_white_space(filt_ans);
5183 alval = ALVAL(&cat_cmd_var, ew);
5184 cat_cmd = *alval;
5185 *alval = NULL;
5187 alval = ALVAL(&cstm_act_var, ew);
5188 cstm_act = *alval;
5189 *alval = NULL;
5191 alval = ALVAL(&smtp_act_var, ew);
5192 smtp_act = *alval;
5193 *alval = NULL;
5195 alval = ALVAL(&nntp_act_var, ew);
5196 nntp_act = *alval;
5197 *alval = NULL;
5199 if(ps->VAR_OPER_DIR && sig_act &&
5200 is_absolute_path(sig_act) &&
5201 !in_dir(ps->VAR_OPER_DIR, sig_act)){
5202 q_status_message1(SM_ORDER | SM_DING, 3, 4,
5203 _("Warning: Sig file can't be outside of %s"),
5204 ps->VAR_OPER_DIR);
5207 if(ps->VAR_OPER_DIR && templ_act &&
5208 is_absolute_path(templ_act) &&
5209 !in_dir(ps->VAR_OPER_DIR, templ_act)){
5210 q_status_message1(SM_ORDER | SM_DING, 3, 4,
5211 _("Warning: Template file can't be outside of %s"),
5212 ps->VAR_OPER_DIR);
5215 if(ps->VAR_OPER_DIR && folder_act)
5216 for(i = 0; folder_act[i]; i++){
5217 if(folder_act[i][0] && is_absolute_path(folder_act[i]) &&
5218 !in_dir(ps->VAR_OPER_DIR, folder_act[i])){
5219 q_status_message1(SM_ORDER | SM_DING, 3, 4,
5220 _("Warning: Folder can't be outside of %s"),
5221 ps->VAR_OPER_DIR);
5225 *result = (PAT_S *)fs_get(sizeof(**result));
5226 memset((void *)(*result), 0, sizeof(**result));
5228 (*result)->patgrp = (PATGRP_S *)fs_get(sizeof(*(*result)->patgrp));
5229 memset((void *)(*result)->patgrp, 0, sizeof(*(*result)->patgrp));
5231 (*result)->action = (ACTION_S *)fs_get(sizeof(*(*result)->action));
5232 memset((void *)(*result)->action, 0, sizeof(*(*result)->action));
5234 (*result)->patline = def ? def->patline : NULL;
5236 if(nick && *nick){
5237 (*result)->patgrp->nick = nick;
5238 nick = NULL;
5240 else
5241 (*result)->patgrp->nick = cpystr(nick_var.global_val.p);
5243 if(comment && *comment){
5244 (*result)->patgrp->comment = comment;
5245 comment = NULL;
5248 (*result)->action->nick = cpystr((*result)->patgrp->nick);
5250 (*result)->action->is_a_role = edit_role ? 1 : 0;
5251 (*result)->action->is_a_incol = edit_incol ? 1 : 0;
5252 (*result)->action->is_a_score = edit_score ? 1 : 0;
5253 (*result)->action->is_a_filter = edit_filter ? 1 : 0;
5254 (*result)->action->is_a_other = edit_other ? 1 : 0;
5255 (*result)->action->is_a_srch = edit_srch ? 1 : 0;
5257 (*result)->patgrp->to = editlist_to_pattern(to_pat);
5258 if((*result)->patgrp->to && !strncmp(to_pat_var.name, NOT, NOTLEN))
5259 (*result)->patgrp->to->not = 1;
5261 (*result)->patgrp->from = editlist_to_pattern(from_pat);
5262 if((*result)->patgrp->from && !strncmp(from_pat_var.name, NOT, NOTLEN))
5263 (*result)->patgrp->from->not = 1;
5265 (*result)->patgrp->sender = editlist_to_pattern(sender_pat);
5266 if((*result)->patgrp->sender &&
5267 !strncmp(sender_pat_var.name, NOT, NOTLEN))
5268 (*result)->patgrp->sender->not = 1;
5270 (*result)->patgrp->cc = editlist_to_pattern(cc_pat);
5271 if((*result)->patgrp->cc && !strncmp(cc_pat_var.name, NOT, NOTLEN))
5272 (*result)->patgrp->cc->not = 1;
5274 (*result)->patgrp->recip = editlist_to_pattern(recip_pat);
5275 if((*result)->patgrp->recip &&
5276 !strncmp(recip_pat_var.name, NOT, NOTLEN))
5277 (*result)->patgrp->recip->not = 1;
5279 (*result)->patgrp->partic = editlist_to_pattern(partic_pat);
5280 if((*result)->patgrp->partic &&
5281 !strncmp(partic_pat_var.name, NOT, NOTLEN))
5282 (*result)->patgrp->partic->not = 1;
5284 (*result)->patgrp->news = editlist_to_pattern(news_pat);
5285 if((*result)->patgrp->news && !strncmp(news_pat_var.name, NOT, NOTLEN))
5286 (*result)->patgrp->news->not = 1;
5288 (*result)->patgrp->subj = editlist_to_pattern(subj_pat);
5289 if((*result)->patgrp->subj && !strncmp(subj_pat_var.name, NOT, NOTLEN))
5290 (*result)->patgrp->subj->not = 1;
5292 (*result)->patgrp->alltext = editlist_to_pattern(alltext_pat);
5293 if((*result)->patgrp->alltext &&
5294 !strncmp(alltext_pat_var.name, NOT, NOTLEN))
5295 (*result)->patgrp->alltext->not = 1;
5297 (*result)->patgrp->bodytext = editlist_to_pattern(bodytext_pat);
5298 if((*result)->patgrp->bodytext &&
5299 !strncmp(bodytext_pat_var.name, NOT, NOTLEN))
5300 (*result)->patgrp->bodytext->not = 1;
5302 (*result)->patgrp->keyword = editlist_to_pattern(keyword_pat);
5303 if((*result)->patgrp->keyword &&
5304 !strncmp(keyword_pat_var.name, NOT, NOTLEN))
5305 (*result)->patgrp->keyword->not = 1;
5307 (*result)->patgrp->charsets = editlist_to_pattern(charset_pat);
5308 if((*result)->patgrp->charsets &&
5309 !strncmp(charset_pat_var.name, NOT, NOTLEN))
5310 (*result)->patgrp->charsets->not = 1;
5312 (*result)->patgrp->age_uses_sentdate =
5313 bitnset(FEAT_SENTDATE, feat_option_list) ? 1 : 0;
5315 if(age_pat){
5316 if(((*result)->patgrp->age = parse_intvl(age_pat)) != NULL)
5317 (*result)->patgrp->do_age = 1;
5320 if(size_pat){
5321 if(((*result)->patgrp->size = parse_intvl(size_pat)) != NULL)
5322 (*result)->patgrp->do_size = 1;
5325 if(scorei_pat){
5326 if(((*result)->patgrp->score = parse_intvl(scorei_pat)) != NULL)
5327 (*result)->patgrp->do_score = 1;
5330 (*result)->patgrp->cat_lim = -1L; /* default */
5331 if(cat_cmd){
5332 if(!cat_cmd[0])
5333 fs_give((void **) &cat_cmd);
5335 /* quick check for absolute paths */
5336 if(cat_cmd)
5337 for(j = 0; cat_cmd[j]; j++)
5338 if(!is_absolute_path(cat_cmd[j]))
5339 q_status_message1(SM_ORDER | SM_DING, 3, 4,
5340 _("Warning: command must be absolute path: \"%s\""),
5341 cat_cmd[j]);
5343 (*result)->patgrp->category_cmd = cat_cmd;
5344 cat_cmd = NULL;
5346 if(cati){
5347 if(((*result)->patgrp->cat = parse_intvl(cati)) != NULL)
5348 (*result)->patgrp->do_cat = 1;
5350 if(cat_lim && *cat_lim)
5351 (*result)->patgrp->cat_lim = atol(cat_lim);
5354 if(stat_del && *stat_del){
5355 for(j = 0; (f = role_status_types(j)); j++)
5356 if(!strucmp(stat_del, f->name)){
5357 (*result)->patgrp->stat_del = f->value;
5358 break;
5361 else
5362 (*result)->patgrp->stat_del = PAT_STAT_EITHER;
5364 if(stat_new && *stat_new){
5365 for(j = 0; (f = role_status_types(j)); j++)
5366 if(!strucmp(stat_new, f->name)){
5367 (*result)->patgrp->stat_new = f->value;
5368 break;
5371 else
5372 (*result)->patgrp->stat_new = PAT_STAT_EITHER;
5374 if(stat_rec && *stat_rec){
5375 for(j = 0; (f = role_status_types(j)); j++)
5376 if(!strucmp(stat_rec, f->name)){
5377 (*result)->patgrp->stat_rec = f->value;
5378 break;
5381 else
5382 (*result)->patgrp->stat_rec = PAT_STAT_EITHER;
5384 if(stat_imp && *stat_imp){
5385 for(j = 0; (f = role_status_types(j)); j++)
5386 if(!strucmp(stat_imp, f->name)){
5387 (*result)->patgrp->stat_imp = f->value;
5388 break;
5391 else
5392 (*result)->patgrp->stat_imp = PAT_STAT_EITHER;
5394 if(stat_ans && *stat_ans){
5395 for(j = 0; (f = role_status_types(j)); j++)
5396 if(!strucmp(stat_ans, f->name)){
5397 (*result)->patgrp->stat_ans = f->value;
5398 break;
5401 else
5402 (*result)->patgrp->stat_ans = PAT_STAT_EITHER;
5404 if(stat_8bit && *stat_8bit){
5405 for(j = 0; (f = role_status_types(j)); j++)
5406 if(!strucmp(stat_8bit, f->name)){
5407 (*result)->patgrp->stat_8bitsubj = f->value;
5408 break;
5411 else
5412 (*result)->patgrp->stat_8bitsubj = PAT_STAT_EITHER;
5414 if(stat_bom && *stat_bom){
5415 for(j = 0; (f = role_status_types(j)); j++)
5416 if(!strucmp(stat_bom, f->name)){
5417 (*result)->patgrp->stat_bom = f->value;
5418 break;
5421 else
5422 (*result)->patgrp->stat_bom = PAT_STAT_EITHER;
5424 if(stat_boy && *stat_boy){
5425 for(j = 0; (f = role_status_types(j)); j++)
5426 if(!strucmp(stat_boy, f->name)){
5427 (*result)->patgrp->stat_boy = f->value;
5428 break;
5431 else
5432 (*result)->patgrp->stat_boy = PAT_STAT_EITHER;
5434 if(sort_act){
5435 decode_sort(sort_act, &def_sort, &def_sort_rev);
5436 (*result)->action->sort_is_set = 1;
5437 (*result)->action->sortorder = def_sort;
5438 (*result)->action->revsort = (def_sort_rev ? 1 : 0);
5440 * Don't try to re-sort until next open of folder. If user
5441 * $-sorted then it probably shouldn't change anyway. Why
5442 * bother keeping track of that?
5446 (*result)->action->index_format = iform_act;
5447 iform_act = NULL;
5449 if(startup_act && *startup_act){
5450 for(j = 0; (f = startup_rules(j)); j++)
5451 if(!strucmp(startup_act, f->name)){
5452 (*result)->action->startup_rule = f->value;
5453 break;
5456 else
5457 (*result)->action->startup_rule = IS_NOTSET;
5459 aa = NULL;
5460 for(ea = earb; ea; ea = ea->next){
5461 char *xyz;
5463 if(aa){
5464 aa->next = (ARBHDR_S *)fs_get(sizeof(*aa));
5465 aa = aa->next;
5467 else{
5468 (*result)->patgrp->arbhdr =
5469 (ARBHDR_S *)fs_get(sizeof(ARBHDR_S));
5470 aa = (*result)->patgrp->arbhdr;
5473 memset(aa, 0, sizeof(*aa));
5475 aa->field = cpystr((ea->a && ea->a->field) ? ea->a->field : "");
5477 alval = ALVAL(ea->v, ew);
5478 spat = *alval;
5479 *alval = NULL;
5480 aa->p = editlist_to_pattern(spat);
5481 if(aa->p && ea->v && ea->v->name &&
5482 !strncmp(ea->v->name, NOT, NOTLEN))
5483 aa->p->not = 1;
5485 if((xyz = pattern_to_string(aa->p)) != NULL){
5486 if(!*xyz)
5487 aa->isemptyval = 1;
5489 fs_give((void **)&xyz);
5493 if(fldr_type_pat && *fldr_type_pat){
5494 for(j = 0; (f = pat_fldr_types(j)); j++)
5495 if(!strucmp(fldr_type_pat, f->name)){
5496 (*result)->patgrp->fldr_type = f->value;
5497 break;
5500 else{
5501 f = pat_fldr_types(FLDR_DEFL);
5502 if(f)
5503 (*result)->patgrp->fldr_type = f->value;
5506 (*result)->patgrp->folder = editlist_to_pattern(folder_pat);
5508 if(abook_type_pat && *abook_type_pat){
5509 for(j = 0; (f = inabook_fldr_types(j)); j++){
5510 if(!strucmp(abook_type_pat, f->name)){
5511 (*result)->patgrp->inabook = f->value;
5512 break;
5516 if(bitnset(INABOOK_FROM, inabook_type_list))
5517 (*result)->patgrp->inabook |= IAB_FROM;
5518 if(bitnset(INABOOK_REPLYTO, inabook_type_list))
5519 (*result)->patgrp->inabook |= IAB_REPLYTO;
5520 if(bitnset(INABOOK_SENDER, inabook_type_list))
5521 (*result)->patgrp->inabook |= IAB_SENDER;
5522 if(bitnset(INABOOK_TO, inabook_type_list))
5523 (*result)->patgrp->inabook |= IAB_TO;
5524 if(bitnset(INABOOK_CC, inabook_type_list))
5525 (*result)->patgrp->inabook |= IAB_CC;
5527 if(!((*result)->patgrp->inabook & IAB_TYPE_MASK))
5528 (*result)->patgrp->inabook |= (IAB_FROM | IAB_REPLYTO);
5530 else{
5531 f = inabook_fldr_types(IAB_DEFL);
5532 if(f)
5533 (*result)->patgrp->inabook = f->value;
5536 (*result)->patgrp->abooks = editlist_to_pattern(abook_pat);
5539 (*result)->action->inherit_nick = inick;
5540 inick = NULL;
5541 (*result)->action->fcc = fcc_act;
5542 fcc_act = NULL;
5543 (*result)->action->litsig = litsig_act;
5544 litsig_act = NULL;
5545 (*result)->action->sig = sig_act;
5546 sig_act = NULL;
5547 (*result)->action->template = templ_act;
5548 templ_act = NULL;
5550 if(cstm_act){
5552 * Check for From or Reply-To and eliminate them.
5554 for(i = 0; cstm_act[i]; i++){
5555 char *free_this;
5557 if((!struncmp(cstm_act[i],"from",4) &&
5558 (cstm_act[i][4] == ':' ||
5559 cstm_act[i][4] == '\0')) ||
5560 (!struncmp(cstm_act[i],"reply-to",8) &&
5561 (cstm_act[i][8] == ':' ||
5562 cstm_act[i][8] == '\0'))){
5563 free_this = cstm_act[i];
5564 /* slide the rest up */
5565 for(j = i; cstm_act[j]; j++)
5566 cstm_act[j] = cstm_act[j+1];
5568 fs_give((void **)&free_this);
5569 i--; /* recheck now that we've slid them up */
5573 /* nothing left */
5574 if(!cstm_act[0])
5575 fs_give((void **)&cstm_act);
5577 (*result)->action->cstm = cstm_act;
5578 cstm_act = NULL;
5581 if(smtp_act){
5582 if(!smtp_act[0])
5583 fs_give((void **)&smtp_act);
5585 (*result)->action->smtp = smtp_act;
5586 smtp_act = NULL;
5589 if(nntp_act){
5590 if(!nntp_act[0])
5591 fs_give((void **)&nntp_act);
5593 (*result)->action->nntp = nntp_act;
5594 nntp_act = NULL;
5597 if(filter_type && *filter_type){
5598 (*result)->action->non_terminating =
5599 bitnset(FEAT_NONTERM, feat_option_list) ? 1 : 0;
5600 for(i = 0; (f = filter_types(i)); i++){
5601 if(!strucmp(filter_type, f->name)){
5602 if(f->value == FILTER_FOLDER){
5603 (*result)->action->folder = editlist_to_pattern(folder_act);
5604 (*result)->action->move_only_if_not_deleted =
5605 bitnset(FEAT_IFNOTDEL, feat_option_list) ? 1 : 0;
5607 else if(f->value == FILTER_STATE){
5608 (*result)->action->kill = 0;
5610 else if(f->value == FILTER_KILL){
5611 (*result)->action->kill = 1;
5615 * This is indented an extra indent because we used to condition
5616 * this on !kill. We changed it so that you can set state bits
5617 * even if you're killing. This is marginally helpful if you
5618 * have another client running that doesn't know about this
5619 * filter, but you want to, for example, have the messages show
5620 * up now as deleted instead of having that deferred until we
5621 * exit. It is controlled by the user by setting the status
5622 * action bits along with the Delete.
5624 if(filt_imp && *filt_imp){
5625 for(j = 0; (f = msg_state_types(j)); j++){
5626 if(!strucmp(filt_imp, f->name)){
5627 switch(f->value){
5628 case ACT_STAT_LEAVE:
5629 break;
5630 case ACT_STAT_SET:
5631 (*result)->action->state_setting_bits |= F_FLAG;
5632 break;
5633 case ACT_STAT_CLEAR:
5634 (*result)->action->state_setting_bits |= F_UNFLAG;
5635 break;
5637 break;
5642 if(filt_del && *filt_del){
5643 for(j = 0; (f = msg_state_types(j)); j++){
5644 if(!strucmp(filt_del, f->name)){
5645 switch(f->value){
5646 case ACT_STAT_LEAVE:
5647 break;
5648 case ACT_STAT_SET:
5649 (*result)->action->state_setting_bits |= F_DEL;
5650 break;
5651 case ACT_STAT_CLEAR:
5652 (*result)->action->state_setting_bits |= F_UNDEL;
5653 break;
5655 break;
5660 if(filt_ans && *filt_ans){
5661 for(j = 0; (f = msg_state_types(j)); j++){
5662 if(!strucmp(filt_ans, f->name)){
5663 switch(f->value){
5664 case ACT_STAT_LEAVE:
5665 break;
5666 case ACT_STAT_SET:
5667 (*result)->action->state_setting_bits |= F_ANS;
5668 break;
5669 case ACT_STAT_CLEAR:
5670 (*result)->action->state_setting_bits |= F_UNANS;
5671 break;
5673 break;
5678 if(filt_new && *filt_new){
5679 for(j = 0; (f = msg_state_types(j)); j++){
5680 if(!strucmp(filt_new, f->name)){
5681 switch(f->value){
5682 case ACT_STAT_LEAVE:
5683 break;
5684 case ACT_STAT_SET:
5685 (*result)->action->state_setting_bits |= F_UNSEEN;
5686 break;
5687 case ACT_STAT_CLEAR:
5688 (*result)->action->state_setting_bits |= F_SEEN;
5689 break;
5691 break;
5696 (*result)->action->keyword_set =
5697 editlist_to_pattern(keyword_set);
5698 (*result)->action->keyword_clr =
5699 editlist_to_pattern(keyword_clr);
5701 break;
5706 if(from_act && *from_act)
5707 rfc822_parse_adrlist(&(*result)->action->from, from_act,
5708 ps->maildomain);
5710 if(replyto_act && *replyto_act)
5711 rfc822_parse_adrlist(&(*result)->action->replyto, replyto_act,
5712 ps->maildomain);
5714 if(score_act && (j = atoi(score_act)) >= SCORE_MIN && j <= SCORE_MAX)
5715 (*result)->action->scoreval = (long) j;
5717 if(hdrtok_act)
5718 (*result)->action->scorevalhdrtok = stringform_to_hdrtok(hdrtok_act);
5720 if(repl_type && *repl_type){
5721 for(j = 0; (f = role_repl_types(j)); j++)
5722 if(!strucmp(repl_type, f->name)){
5723 (*result)->action->repl_type = f->value;
5724 break;
5727 else{
5728 f = role_repl_types(ROLE_REPL_DEFL);
5729 if(f)
5730 (*result)->action->repl_type = f->value;
5733 if(forw_type && *forw_type){
5734 for(j = 0; (f = role_forw_types(j)); j++)
5735 if(!strucmp(forw_type, f->name)){
5736 (*result)->action->forw_type = f->value;
5737 break;
5740 else{
5741 f = role_forw_types(ROLE_FORW_DEFL);
5742 if(f)
5743 (*result)->action->forw_type = f->value;
5746 if(comp_type && *comp_type){
5747 for(j = 0; (f = role_comp_types(j)); j++)
5748 if(!strucmp(comp_type, f->name)){
5749 (*result)->action->comp_type = f->value;
5750 break;
5753 else{
5754 f = role_comp_types(ROLE_COMP_DEFL);
5755 if(f)
5756 (*result)->action->comp_type = f->value;
5759 if(rc_fg && *rc_fg && rc_bg && *rc_bg){
5760 if(!old_fg || !old_bg || strucmp(old_fg, rc_fg) ||
5761 strucmp(old_bg, rc_bg))
5762 clear_index_cache(ps_global->mail_stream, 0);
5765 * If same as normal color, don't set it. This may or may
5766 * not surprise the user when they change the normal color.
5767 * This color will track the normal color instead of staying
5768 * the same as the old normal color, which is probably
5769 * what they want.
5771 if(!ps_global->VAR_NORM_FORE_COLOR ||
5772 !ps_global->VAR_NORM_BACK_COLOR ||
5773 strucmp(ps_global->VAR_NORM_FORE_COLOR, rc_fg) ||
5774 strucmp(ps_global->VAR_NORM_BACK_COLOR, rc_bg))
5775 (*result)->action->incol = new_color_pair(rc_fg, rc_bg);
5779 for(j = 0; varlist[j]; j++){
5780 v = varlist[j];
5781 free_variable_values(v);
5782 if(v->name)
5783 fs_give((void **)&v->name);
5786 if(earb)
5787 free_earb(&earb);
5788 if(nick)
5789 fs_give((void **)&nick);
5790 if(comment)
5791 fs_give((void **)&comment);
5792 if(to_pat)
5793 free_list_array(&to_pat);
5794 if(from_pat)
5795 free_list_array(&from_pat);
5796 if(sender_pat)
5797 free_list_array(&sender_pat);
5798 if(cc_pat)
5799 free_list_array(&cc_pat);
5800 if(recip_pat)
5801 free_list_array(&recip_pat);
5802 if(partic_pat)
5803 free_list_array(&partic_pat);
5804 if(news_pat)
5805 free_list_array(&news_pat);
5806 if(subj_pat)
5807 free_list_array(&subj_pat);
5808 if(alltext_pat)
5809 free_list_array(&alltext_pat);
5810 if(bodytext_pat)
5811 free_list_array(&bodytext_pat);
5812 if(keyword_pat)
5813 free_list_array(&keyword_pat);
5814 if(charset_pat)
5815 free_list_array(&charset_pat);
5816 if(age_pat)
5817 fs_give((void **)&age_pat);
5818 if(size_pat)
5819 fs_give((void **)&size_pat);
5820 if(scorei_pat)
5821 fs_give((void **)&scorei_pat);
5822 if(cati)
5823 fs_give((void **)&cati);
5824 if(cat_lim)
5825 fs_give((void **)&cat_lim);
5826 if(stat_del)
5827 fs_give((void **)&stat_del);
5828 if(stat_new)
5829 fs_give((void **)&stat_new);
5830 if(stat_rec)
5831 fs_give((void **)&stat_rec);
5832 if(stat_imp)
5833 fs_give((void **)&stat_imp);
5834 if(stat_ans)
5835 fs_give((void **)&stat_ans);
5836 if(stat_8bit)
5837 fs_give((void **)&stat_8bit);
5838 if(stat_bom)
5839 fs_give((void **)&stat_bom);
5840 if(stat_boy)
5841 fs_give((void **)&stat_boy);
5842 if(fldr_type_pat)
5843 fs_give((void **)&fldr_type_pat);
5844 if(folder_pat)
5845 free_list_array(&folder_pat);
5846 if(abook_type_pat)
5847 fs_give((void **)&abook_type_pat);
5848 if(abook_pat)
5849 free_list_array(&abook_pat);
5850 if(inick)
5851 fs_give((void **)&inick);
5852 if(from_act)
5853 fs_give((void **)&from_act);
5854 if(replyto_act)
5855 fs_give((void **)&replyto_act);
5856 if(fcc_act)
5857 fs_give((void **)&fcc_act);
5858 if(litsig_act)
5859 fs_give((void **)&litsig_act);
5860 if(sort_act)
5861 fs_give((void **)&sort_act);
5862 if(iform_act)
5863 fs_give((void **)&iform_act);
5864 if(keyword_set)
5865 free_list_array(&keyword_set);
5866 if(keyword_clr)
5867 free_list_array(&keyword_clr);
5868 if(startup_act)
5869 fs_give((void **)&startup_act);
5870 if(sig_act)
5871 fs_give((void **)&sig_act);
5872 if(templ_act)
5873 fs_give((void **)&templ_act);
5874 if(score_act)
5875 fs_give((void **)&score_act);
5876 if(hdrtok_act)
5877 fs_give((void **)&hdrtok_act);
5878 if(repl_type)
5879 fs_give((void **)&repl_type);
5880 if(forw_type)
5881 fs_give((void **)&forw_type);
5882 if(comp_type)
5883 fs_give((void **)&comp_type);
5884 if(rc_fg)
5885 fs_give((void **)&rc_fg);
5886 if(rc_bg)
5887 fs_give((void **)&rc_bg);
5888 if(old_fg)
5889 fs_give((void **)&old_fg);
5890 if(old_bg)
5891 fs_give((void **)&old_bg);
5892 if(filt_del)
5893 fs_give((void **)&filt_del);
5894 if(filt_new)
5895 fs_give((void **)&filt_new);
5896 if(filt_ans)
5897 fs_give((void **)&filt_ans);
5898 if(filt_imp)
5899 fs_give((void **)&filt_imp);
5900 if(folder_act)
5901 free_list_array(&folder_act);
5902 if(filter_type)
5903 fs_give((void **)&filter_type);
5905 if(cat_cmd)
5906 free_list_array(&cat_cmd);
5908 if(cstm_act)
5909 free_list_array(&cstm_act);
5911 if(smtp_act)
5912 free_list_array(&smtp_act);
5914 if(nntp_act)
5915 free_list_array(&nntp_act);
5917 opt_screen = saved_screen;
5918 ps->mangled_screen = 1;
5919 return(rv);
5923 void
5924 setup_dummy_pattern_var(struct variable *v, char *name, PATTERN_S *defpat)
5926 char ***alval;
5928 if(!(v && name))
5929 alpine_panic("setup_dummy_pattern_var");
5931 v->name = (char *) fs_get(strlen(name)+NOTLEN+1);
5932 snprintf(v->name, strlen(name)+NOTLEN+1, "%s%s", (defpat && defpat->not) ? NOT : "", name);
5933 v->name[ strlen(name)+NOTLEN+1-1] = '\0';
5934 v->is_used = 1;
5935 v->is_user = 1;
5936 v->is_list = 1;
5937 alval = ALVAL(v, ew);
5938 *alval = pattern_to_editlist(defpat);
5939 set_current_val(v, FALSE, FALSE);
5943 void
5944 setup_role_pat(struct pine *ps, CONF_S **ctmp, struct variable *v, HelpType help,
5945 char *help_title, struct key_menu *keymenu,
5946 int (*tool)(struct pine *, int, CONF_S **, unsigned),
5947 EARB_S **earb, int indent)
5949 char tmp[MAXPATH+1];
5950 char **lval;
5951 int i;
5952 CONF_S *ctmpb;
5954 new_confline(ctmp);
5955 (*ctmp)->help_title = help_title;
5956 (*ctmp)->var = v;
5957 (*ctmp)->valoffset = indent;
5958 (*ctmp)->keymenu = keymenu;
5959 (*ctmp)->help = help;
5960 (*ctmp)->tool = tool;
5961 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", indent-3, indent-3, (v && v->name) ? v->name : "");
5962 tmp[sizeof(tmp)-1] = '\0';
5963 (*ctmp)->varname = cpystr(tmp);
5964 (*ctmp)->varnamep = *ctmp;
5965 (*ctmp)->value = pretty_value(ps, *ctmp);
5966 (*ctmp)->d.earb = earb;
5967 (*ctmp)->varmem = 0;
5968 (*ctmp)->flags = CF_STARTITEM;
5970 ctmpb = (*ctmp);
5972 lval = LVAL(v, ew);
5973 if(lval){
5974 for(i = 0; lval[i]; i++){
5975 if(i)
5976 new_confline(ctmp);
5978 (*ctmp)->var = v;
5979 (*ctmp)->varmem = i;
5980 (*ctmp)->valoffset = indent;
5981 (*ctmp)->value = pretty_value(ps, *ctmp);
5982 (*ctmp)->d.earb = earb;
5983 (*ctmp)->keymenu = keymenu;
5984 (*ctmp)->help = help;
5985 (*ctmp)->tool = tool;
5986 (*ctmp)->varnamep = ctmpb;
5993 * Watch out for polarity of nosel flag. Setting it means to turn on
5994 * the NOSELECT flag, which means to make that line unselectable.
5996 void
5997 setup_role_pat_alt(struct pine *ps, CONF_S **ctmp, struct variable *v, HelpType help,
5998 char *help_title, struct key_menu *keymenu,
5999 int (*tool)(struct pine *, int, CONF_S **, unsigned),
6000 int voff, int nosel)
6002 char tmp[MAXPATH+1];
6003 char **lval;
6004 int i, j, k;
6005 CONF_S *ctmpb;
6007 new_confline(ctmp);
6008 (*ctmp)->help_title = help_title;
6009 (*ctmp)->var = v;
6011 (*ctmp)->varoffset = voff;
6012 k = utf8_width(v->name);
6013 j = voff+k+3;
6014 (*ctmp)->valoffset = j;
6016 (*ctmp)->keymenu = keymenu;
6017 (*ctmp)->help = help;
6018 (*ctmp)->tool = tool;
6020 utf8_snprintf(tmp, sizeof(tmp), "%*.*w =", k, k, v->name);
6021 tmp[sizeof(tmp)-1] = '\0';
6022 (*ctmp)->varname = cpystr(tmp);
6024 (*ctmp)->varnamep = *ctmp;
6025 (*ctmp)->value = pretty_value(ps, *ctmp);
6026 (*ctmp)->varmem = 0;
6028 (*ctmp)->flags = (nosel ? CF_NOSELECT : 0);
6030 ctmpb = (*ctmp);
6032 lval = LVAL(v, ew);
6033 if(lval){
6034 for(i = 0; lval[i]; i++){
6035 if(i)
6036 new_confline(ctmp);
6038 (*ctmp)->var = v;
6039 (*ctmp)->varmem = i;
6040 (*ctmp)->varoffset = voff;
6041 (*ctmp)->valoffset = j;
6042 (*ctmp)->value = pretty_value(ps, *ctmp);
6043 (*ctmp)->keymenu = keymenu;
6044 (*ctmp)->help = help;
6045 (*ctmp)->tool = tool;
6046 (*ctmp)->varnamep = ctmpb;
6047 (*ctmp)->flags = (nosel ? CF_NOSELECT : 0);
6053 void
6054 free_earb(EARB_S **ea)
6056 if(ea && *ea){
6057 free_earb(&(*ea)->next);
6058 if((*ea)->v){
6059 free_variable_values((*ea)->v);
6060 if((*ea)->v->name)
6061 fs_give((void **) &(*ea)->v->name);
6063 fs_give((void **) &(*ea)->v);;
6066 free_arbhdr(&(*ea)->a);
6067 fs_give((void **) ea);
6072 void
6073 calculate_inick_stuff(struct pine *ps)
6075 ACTION_S *role, *irole;
6076 CONF_S *ctmp, *ctmpa;
6077 struct variable *v;
6078 int i;
6079 char *nick;
6081 if(inick_confs[INICK_INICK_CONF] == NULL)
6082 return;
6084 for(i = INICK_FROM_CONF; i <= INICK_NNTP_CONF; i++){
6085 v = inick_confs[i] ? inick_confs[i]->var : NULL;
6086 if(v){
6087 if(v->is_list){
6088 if(v->global_val.l)
6089 free_list_array(&v->global_val.l);
6091 else{
6092 if(v->global_val.p)
6093 fs_give((void **)&v->global_val.p);
6098 nick = PVAL(inick_confs[INICK_INICK_CONF]->var, ew);
6100 if(nick){
6102 * Use an empty role with inherit_nick set to nick and then use the
6103 * combine function to find the action values.
6105 role = (ACTION_S *)fs_get(sizeof(*role));
6106 memset((void *)role, 0, sizeof(*role));
6107 role->is_a_role = 1;
6108 role->inherit_nick = cpystr(nick);
6109 irole = combine_inherited_role(role);
6111 ctmp = inick_confs[INICK_FROM_CONF];
6112 v = ctmp ? ctmp->var : NULL;
6114 if(irole && irole->from){
6115 char *bufp;
6116 size_t len;
6118 len = est_size(irole->from);
6119 bufp = (char *) fs_get(len * sizeof(char));
6120 v->global_val.p = addr_string_mult(irole->from, bufp, len);
6123 ctmp = inick_confs[INICK_REPLYTO_CONF];
6124 v = ctmp ? ctmp->var : NULL;
6126 if(irole && irole->replyto){
6127 char *bufp;
6128 size_t len;
6130 len = est_size(irole->replyto);
6131 bufp = (char *) fs_get(len * sizeof(char));
6132 v->global_val.p = addr_string_mult(irole->replyto, bufp, len);
6135 ctmp = inick_confs[INICK_FCC_CONF];
6136 v = ctmp ? ctmp->var : NULL;
6137 v->global_val.p = (irole && irole->fcc) ? cpystr(irole->fcc) : NULL;
6139 ctmp = inick_confs[INICK_LITSIG_CONF];
6140 v = ctmp ? ctmp->var : NULL;
6141 v->global_val.p = (irole && irole->litsig) ? cpystr(irole->litsig)
6142 : NULL;
6144 ctmp = inick_confs[INICK_SIG_CONF];
6145 v = ctmp ? ctmp->var : NULL;
6146 v->global_val.p = (irole && irole->sig) ? cpystr(irole->sig) : NULL;
6148 ctmp = inick_confs[INICK_TEMPL_CONF];
6149 v = ctmp ? ctmp->var : NULL;
6150 v->global_val.p = (irole && irole->template)
6151 ? cpystr(irole->template) : NULL;
6153 ctmp = inick_confs[INICK_CSTM_CONF];
6154 v = ctmp ? ctmp->var : NULL;
6155 v->global_val.l = (irole && irole->cstm) ? copy_list_array(irole->cstm)
6156 : NULL;
6158 ctmp = inick_confs[INICK_SMTP_CONF];
6159 v = ctmp ? ctmp->var : NULL;
6160 v->global_val.l = (irole && irole->smtp) ? copy_list_array(irole->smtp)
6161 : NULL;
6163 ctmp = inick_confs[INICK_NNTP_CONF];
6164 v = ctmp ? ctmp->var : NULL;
6165 v->global_val.l = (irole && irole->nntp) ? copy_list_array(irole->nntp)
6166 : NULL;
6168 free_action(&role);
6169 free_action(&irole);
6172 for(i = INICK_INICK_CONF; i <= INICK_NNTP_CONF; i++){
6173 ctmp = inick_confs[i];
6174 v = ctmp ? ctmp->var : NULL;
6176 * If we didn't set a global_val using the nick above, then
6177 * set one here for each variable that uses one.
6179 if(v && !v->global_val.p){
6180 char *str, *astr, *lc, pdir[MAXPATH+1];
6181 ADDRESS *addr;
6182 int len = 0;
6184 switch(i){
6185 case INICK_FROM_CONF:
6186 addr = generate_from();
6187 astr = addr_list_string(addr, NULL, 1);
6188 str = (astr && astr[0]) ? astr : "?";
6189 v->global_val.p = (char *)fs_get((strlen(str) + 20) *
6190 sizeof(char));
6191 snprintf(v->global_val.p, strlen(str) + 20, "%s%s)", DSTRING, str);
6192 v->global_val.p[strlen(str) + 20 - 1] = '\0';
6193 if(astr)
6194 fs_give((void **)&astr);
6196 if(addr)
6197 mail_free_address(&addr);
6199 break;
6201 case INICK_FCC_CONF:
6202 v->global_val.p = cpystr(VSTRING);
6203 break;
6205 case INICK_LITSIG_CONF:
6207 * This default works this way because of the ordering
6208 * of the choices in the detoken routine.
6210 if(ps->VAR_LITERAL_SIG){
6211 str = ps->VAR_LITERAL_SIG;
6212 v->global_val.p = (char *)fs_get((strlen(str) + 20) *
6213 sizeof(char));
6214 snprintf(v->global_val.p, strlen(str) + 20,
6215 "%s%s)", DSTRING, str);
6216 v->global_val.p[strlen(str) + 20 - 1] = '\0';
6219 break;
6221 case INICK_SIG_CONF:
6222 pdir[0] = '\0';
6223 if(ps_global->VAR_OPER_DIR){
6224 strncpy(pdir, ps_global->VAR_OPER_DIR, MAXPATH);
6225 pdir[MAXPATH] = '\0';
6226 len = strlen(pdir) + 1;
6228 else if((lc = last_cmpnt(ps_global->pinerc)) != NULL){
6229 strncpy(pdir, ps_global->pinerc,
6230 MIN(MAXPATH,lc-ps_global->pinerc));
6231 pdir[MIN(MAXPATH, lc-ps_global->pinerc)] = '\0';
6232 len = strlen(pdir);
6235 if(pdir[0] && ps->VAR_SIGNATURE_FILE &&
6236 ps->VAR_SIGNATURE_FILE[0] &&
6237 is_absolute_path(ps->VAR_SIGNATURE_FILE) &&
6238 !strncmp(ps->VAR_SIGNATURE_FILE, pdir, len)){
6239 str = ps->VAR_SIGNATURE_FILE + len;
6241 else
6242 str = (ps->VAR_SIGNATURE_FILE && ps->VAR_SIGNATURE_FILE[0])
6243 ? ps->VAR_SIGNATURE_FILE : NULL;
6244 if(str){
6245 v->global_val.p = (char *)fs_get((strlen(str) + 20) *
6246 sizeof(char));
6247 snprintf(v->global_val.p, strlen(str) + 20, "%s%s)", DSTRING, str);
6248 v->global_val.p[strlen(str) + 20 - 1] = '\0';
6251 break;
6253 case INICK_INICK_CONF:
6254 case INICK_REPLYTO_CONF:
6255 case INICK_TEMPL_CONF:
6256 case INICK_CSTM_CONF:
6257 case INICK_SMTP_CONF:
6258 case INICK_NNTP_CONF:
6259 break;
6263 if(v)
6264 set_current_val(v, FALSE, FALSE);
6266 if(ctmp){
6267 CONF_S *ctmpsig = NULL;
6268 struct variable *vlsig;
6270 for(ctmpa = ctmp;
6271 ctmpa && ctmpa->varnamep == ctmp;
6272 ctmpa = ctmpa->next){
6273 if(ctmpa->value)
6274 fs_give((void **)&ctmpa->value);
6276 ctmpa->value = pretty_value(ps, ctmpa);
6279 if(i == INICK_SIG_CONF){
6281 * Turn off NOSELECT, but possibly turn it on again
6282 * in next line.
6284 if((ctmpsig = inick_confs[INICK_SIG_CONF]) != NULL)
6285 ctmpsig->flags &= ~CF_NOSELECT;
6287 if(inick_confs[INICK_LITSIG_CONF] &&
6288 (vlsig = inick_confs[INICK_LITSIG_CONF]->var) &&
6289 vlsig->current_val.p &&
6290 vlsig->current_val.p[0]){
6291 if(ctmp->value)
6292 fs_give((void **)&ctmp->value);
6294 ctmp->value =
6295 cpystr("<Ignored: using LiteralSig instead>");
6297 ctmp->flags |= CF_NOSELECT;
6305 /* Arguments:
6306 * lst: a list of folders
6307 * action: a 1 or 0 value which basically says that str is associated with
6308 * the filter action if true or the Current Folder type if false.
6309 * Return:
6310 * Returns 2 on success (user wants to exit) and 0 on failure.
6312 * This function cycles through a list of folders and checks whether or not each
6313 * folder exists. If they exist, return 2, if they don't exist, notify the user
6314 * or offer to create depending on whether or not it is a filter action or not.
6315 * With each of these prompts, the user can abort their desire to exit.
6318 check_role_folders(char **lst, unsigned int action)
6320 char *cur_fn, wt_res, prompt[MAX_SCREEN_COLS];
6321 int i, rv = 2;
6322 CONTEXT_S *cntxt = NULL;
6323 char nbuf1[MAX_SCREEN_COLS], nbuf2[MAX_SCREEN_COLS];
6324 int space, w1, w2, exists;
6326 if(!(lst && *lst)){
6327 if(action)
6328 q_status_message(SM_ORDER, 3, 5,
6329 _("Set a valid Filter Action before Exiting"));
6330 else
6331 q_status_message(SM_ORDER, 3, 5,
6332 _("Set a valid Specific Folder before Exiting"));
6333 rv = 0;
6334 return rv;
6337 for(i = 0; lst[i]; i++){
6338 if(action)
6339 cur_fn = detoken_src(lst[i], FOR_FILT, NULL, NULL, NULL, NULL);
6340 else
6341 cur_fn = lst[i];
6343 removing_leading_and_trailing_white_space(cur_fn);
6344 if(*cur_fn != '\0'){
6345 space = MAXPROMPT;
6346 if(is_absolute_path(cur_fn) || !context_isambig(cur_fn))
6347 cntxt = NULL;
6348 else
6349 cntxt = default_save_context(ps_global->context_list);
6351 if(!(exists=folder_exists(cntxt, cur_fn))
6352 && (action
6353 || (ps_global->context_list->use & CNTXT_INCMNG
6354 && !folder_is_nick(cur_fn,FOLDERS(ps_global->context_list), 0)))){
6355 if(cntxt && (action == 1)){
6356 space -= 37; /* for fixed part of prompt below */
6357 w1 = MAX(1,MIN(strlen(cur_fn),space/2));
6358 w2 = MIN(MAX(1,space-w1),strlen(cntxt->nickname));
6359 w1 += MAX(0,space-w1-w2);
6360 snprintf(prompt, sizeof(prompt),
6361 _("Folder \"%s\" in <%s> doesn't exist. Create"),
6362 short_str(cur_fn,nbuf1,sizeof(nbuf1),w1,MidDots),
6363 short_str(cntxt->nickname,nbuf2,sizeof(nbuf2),w2,MidDots));
6364 prompt[sizeof(prompt)-1] = '\0';
6366 else if(cntxt && (action == 0)){
6367 space -= 51; /* for fixed part of prompt below */
6368 w1 = MAX(1,MIN(strlen(cur_fn),space/2));
6369 w2 = MIN(MAX(1,space-w1),strlen(cntxt->nickname));
6370 w1 += MAX(0,space-w1-w2);
6371 snprintf(prompt, sizeof(prompt),
6372 _("Folder \"%s\" in <%s> doesn't exist. Exit and save anyway"),
6373 short_str(cur_fn,nbuf1,sizeof(nbuf1),w1,MidDots),
6374 short_str(cntxt->nickname,nbuf2,sizeof(nbuf2),w2,MidDots));
6375 prompt[sizeof(prompt)-1] = '\0';
6377 else if(!cntxt && (action == 1)){
6378 space -= 31; /* for fixed part of prompt below */
6379 w1 = MAX(1,space);
6380 snprintf(prompt, sizeof(prompt),
6381 _("Folder \"%s\" doesn't exist. Create"),
6382 short_str(cur_fn,nbuf1,sizeof(nbuf1),w1,MidDots));
6383 prompt[sizeof(prompt)-1] = '\0';
6385 else{ /*!cntxt && (action == 0) */
6386 space -= 45; /* for fixed part of prompt below */
6387 w1 = MAX(1,space);
6388 snprintf(prompt, sizeof(prompt),
6389 _("Folder \"%s\" doesn't exist. Exit and save anyway"),
6390 short_str(cur_fn,nbuf1,sizeof(nbuf1),w1,MidDots));
6391 prompt[sizeof(prompt)-1] = '\0';
6394 wt_res = want_to(prompt, 'n', 'x', NO_HELP, WT_NORM);
6395 if(wt_res == 'y'){
6396 if(action){
6397 if(context_create(cntxt, NULL, cur_fn)){
6398 q_status_message(SM_ORDER,3,5,_("Folder created"));
6399 maybe_add_to_incoming(cntxt, cur_fn);
6402 /* No message to notify of changes being saved, we can't */
6403 /* assume that the role screen isn't exited yet */
6404 rv = 2;
6406 else if(wt_res == 'n' && action){
6407 rv = 2;
6408 q_status_message(SM_ORDER,3,5,_("Folder not created"));
6410 else{
6411 q_status_message(SM_ORDER,3,5,_("Exit cancelled"));
6412 rv = 0;
6413 break;
6416 else{
6417 if(exists & FEX_ERROR){
6418 if(ps_global->mm_log_error && ps_global->c_client_error)
6419 q_status_message(SM_ORDER,3,5,ps_global->c_client_error);
6420 else
6421 q_status_message1(SM_ORDER,3,5,"\"%s\": Trouble checking for folder existence", cur_fn);
6424 rv = 2;
6427 else{ /* blank item in list of folders */
6428 if(action && lst[i+1] == NULL)
6429 q_status_message(SM_ORDER,3,5,_("Set a valid Filter Action before Exiting"));
6430 else /* !action && lst[i+1] == '\0' */
6431 q_status_message(SM_ORDER,3,5,_("Set a valid Specific Folder before Exiting"));
6432 rv = 0;
6433 break;
6436 if(cur_fn && cur_fn != lst[i])
6437 fs_give((void **) &cur_fn);
6440 return(rv);
6444 void
6445 maybe_add_to_incoming(CONTEXT_S *cntxt, char *cur_fn)
6447 char name[MAILTMPLEN], nname[32];
6448 char nbuf1[MAX_SCREEN_COLS], nbuf2[MAX_SCREEN_COLS];
6449 char prompt[MAX_SCREEN_COLS];
6450 char ***alval;
6451 int i, found, space, w1, w2;
6452 FOLDER_S *f;
6454 if(ps_global->context_list->use & CNTXT_INCMNG &&
6455 ((alval = ALVAL(&ps_global->vars[V_INCOMING_FOLDERS], Main)) != NULL)){
6456 (void)context_apply(name, cntxt, cur_fn, sizeof(name));
6458 * Since the folder didn't exist it is very unlikely that it is
6459 * in the incoming-folders list already, but we're just checking
6460 * to be sure. We should really be canonicalizing both names
6461 * before comparing, but...
6463 for(found = 0, i = 0; *alval && (*alval)[i] && !found; i++){
6464 char *nickname, *folder;
6466 get_pair((*alval)[i], &nickname, &folder, 0, 0);
6467 if(folder && !strucmp((*alval)[i], folder))
6468 found++;
6470 if(nickname)
6471 fs_give((void **)&nickname);
6472 if(folder)
6473 fs_give((void **)&folder);
6476 if(found)
6477 return;
6479 space = MAXPROMPT;
6480 space -= 15; /* for fixed part of prompt below */
6481 w2 = MAX(1,
6482 MIN(space/2,MIN(strlen(ps_global->context_list->nickname),20)));
6483 w1 = MAX(1,space - w2);
6484 snprintf(prompt, sizeof(prompt),
6485 "Add \"%s\" to %s list",
6486 short_str(name,nbuf1,sizeof(nbuf1),w1,MidDots),
6487 short_str(ps_global->context_list->nickname,nbuf2,sizeof(nbuf2),w2,MidDots));
6488 prompt[sizeof(prompt)-1] = '\0';
6489 if(want_to(prompt, 'n', 'x', NO_HELP, WT_NORM) == 'y'){
6490 char *pp;
6492 nname[0] = '\0';
6493 space = MAXPROMPT;
6494 space -= 25;
6495 w1 = MAX(1, space);
6496 snprintf(prompt, sizeof(prompt), "Nickname for folder \"%s\" : ",
6497 short_str(name,nbuf1,sizeof(nbuf1),w1,MidDots));
6498 prompt[sizeof(prompt)-1] = '\0';
6499 while(1){
6500 int rc;
6501 int flags = OE_APPEND_CURRENT;
6503 rc = optionally_enter(nname, -FOOTER_ROWS(ps_global), 0,
6504 sizeof(nname), prompt, NULL,
6505 NO_HELP, &flags);
6506 removing_leading_and_trailing_white_space(nname);
6507 if(rc == 0 && *nname){
6508 /* see if nickname already exists */
6509 found = 0;
6510 if(!strucmp(ps_global->inbox_name, nname))
6511 found++;
6513 for(i = 0;
6514 !found &&
6515 i < folder_total(FOLDERS(ps_global->context_list));
6516 i++){
6517 FOLDER_S *f;
6519 f = folder_entry(i, FOLDERS(ps_global->context_list));
6520 if(!strucmp(FLDR_NAME(f), nname))
6521 found++;
6524 if(found){
6525 q_status_message1(SM_ORDER | SM_DING, 3, 5,
6526 _("Nickname \"%s\" is already in use"),
6527 nname);
6528 continue;
6531 break;
6533 else if(rc == 3)
6534 q_status_message(SM_ORDER, 0, 3, _("No help yet."));
6535 else if(rc == 1){
6536 q_status_message1(SM_ORDER, 0, 3,
6537 _("Not adding nickname to %s list"),
6538 ps_global->context_list->nickname);
6539 return;
6543 pp = put_pair(nname, name);
6544 f = new_folder(name, line_hash(pp));
6545 f->nickname = cpystr(nname);
6546 f->name_len = strlen(nname);
6547 folder_insert(folder_total(FOLDERS(ps_global->context_list)), f,
6548 FOLDERS(ps_global->context_list));
6550 if(!*alval){
6551 i = 0;
6552 *alval = (char **)fs_get(2 * sizeof(char *));
6554 else{
6555 for(i = 0; (*alval)[i]; i++)
6558 fs_resize((void **)alval, (i + 2) * sizeof(char *));
6561 (*alval)[i] = pp;
6562 (*alval)[i+1] = NULL;
6563 set_current_val(&ps_global->vars[V_INCOMING_FOLDERS], TRUE, TRUE);
6564 write_pinerc(ps_global, ew, WRP_NONE);
6571 role_filt_exitcheck(CONF_S **cl, unsigned int flags)
6573 int rv, j, action;
6574 char **to_folder = NULL, **spec_fldr = NULL;
6575 CONF_S *ctmp;
6576 NAMEVAL_S *f;
6577 #define ACT_UNKNOWN 0
6578 #define ACT_KILL 1
6579 #define ACT_MOVE 2
6580 #define ACT_MOVE_NOFOLDER 3
6581 #define ACT_STATE 4
6584 * We have to locate the lines which define the Filter Action and
6585 * then check to see that it is set to something before allowing
6586 * user to Exit.
6588 action = ACT_UNKNOWN;
6589 if(flags & CF_CHANGES && role_filt_ptr && PVAL(role_filt_ptr,ew)){
6590 for(j = 0; (f = filter_types(j)); j++)
6591 if(!strucmp(PVAL(role_filt_ptr,ew), f->name))
6592 break;
6594 switch(f ? f->value : -1){
6595 case FILTER_KILL:
6596 action = ACT_KILL;
6597 break;
6599 case FILTER_STATE:
6600 action = ACT_STATE;
6601 break;
6603 case FILTER_FOLDER:
6605 * Check that the folder is set to something.
6608 action = ACT_MOVE_NOFOLDER;
6609 /* go to end of screen */
6610 for(ctmp = (*cl);
6611 ctmp && ctmp->next;
6612 ctmp = next_confline(ctmp))
6615 /* back up to start of Filter Action */
6616 for(;
6617 ctmp &&
6618 !(ctmp->flags & CF_STARTITEM && ctmp->var == role_filt_ptr);
6619 ctmp = prev_confline(ctmp))
6622 /* skip back past NOSELECTs */
6623 for(;
6624 ctmp && (ctmp->flags & CF_NOSELECT);
6625 ctmp = next_confline(ctmp))
6628 /* find line with new var (the Folder line) */
6629 for(;
6630 ctmp && (ctmp->var == role_filt_ptr);
6631 ctmp = next_confline(ctmp))
6634 /* ok, we're finally at the Folder line */
6635 if(ctmp && ctmp->var && LVAL(ctmp->var,ew)){
6636 to_folder = copy_list_array(LVAL(ctmp->var,ew));
6637 if(to_folder && to_folder[0])
6638 action = ACT_MOVE;
6641 break;
6643 default:
6644 dprint((1,
6645 "Can't happen, role_filt_ptr set to %s\n",
6646 PVAL(role_filt_ptr,ew) ? PVAL(role_filt_ptr,ew) : "?"));
6647 break;
6651 if(flags & CF_CHANGES){
6652 switch(want_to((action == ACT_KILL)
6653 ? _("Commit changes (\"Yes\" means matching messages will be deleted)")
6654 : EXIT_PMT, 'y', 'x', h_config_undo, WT_FLUSH_IN)){
6655 case 'y':
6656 switch(action){
6657 case ACT_KILL:
6658 if((spec_fldr = get_role_specific_folder(cl)) != NULL){
6659 rv = check_role_folders(spec_fldr, 0);
6660 free_list_array(&spec_fldr);
6661 if(rv == 2)
6662 q_status_message(SM_ORDER,0,3,_("Ok, messages matching that Pattern will be deleted"));
6664 else{
6665 q_status_message(SM_ORDER, 0, 3,
6666 _("Ok, messages matching that Pattern will be deleted"));
6667 rv = 2;
6669 break;
6671 case ACT_MOVE:
6672 if((spec_fldr = get_role_specific_folder(cl)) != NULL){
6673 rv = check_role_folders(spec_fldr, 0);
6674 free_list_array(&spec_fldr);
6675 if(to_folder && rv == 2)
6676 rv = check_role_folders(to_folder, 1);
6678 else
6679 rv = check_role_folders(to_folder, 1);
6681 break;
6683 case ACT_MOVE_NOFOLDER:
6684 rv = 0;
6685 q_status_message(SM_ORDER, 3, 5,
6686 _("Set a valid Filter Action before Exiting"));
6687 break;
6689 case ACT_STATE:
6690 if((spec_fldr = get_role_specific_folder(cl)) != NULL){
6691 rv = check_role_folders(spec_fldr, 0);
6692 free_list_array(&spec_fldr);
6694 else
6695 rv = 2;
6697 break;
6699 default:
6700 rv = 2;
6701 dprint((1,
6702 "This can't happen, role_filt_ptr or to_folder not set\n"));
6703 break;
6706 break;
6708 case 'n':
6709 q_status_message(SM_ORDER,3,5,_("No filter changes saved"));
6710 rv = 10;
6711 break;
6713 case 'x': /* ^C */
6714 default :
6715 q_status_message(SM_ORDER,3,5,_("Changes not yet saved"));
6716 rv = 0;
6717 break;
6720 else
6721 rv = 2;
6723 if(to_folder)
6724 free_list_array(&to_folder);
6726 return(rv);
6731 * Don't allow exit unless user has set the action to something.
6734 role_filt_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
6736 int rv;
6738 switch(cmd){
6739 case MC_EXIT:
6740 rv = role_filt_exitcheck(cl, flags);
6741 break;
6743 default:
6744 rv = role_text_tool(ps, cmd, cl, flags);
6745 break;
6748 return(rv);
6753 role_filt_addhdr_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
6755 int rv;
6757 switch(cmd){
6758 case MC_EXIT:
6759 rv = role_filt_exitcheck(cl, flags);
6760 break;
6762 default:
6763 rv = role_addhdr_tool(ps, cmd, cl, flags);
6764 break;
6767 return rv;
6771 role_addhdr_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
6773 int rv;
6775 switch(cmd){
6776 case MC_ADDHDR:
6777 case MC_EXIT:
6778 rv = role_text_tool(ps, cmd, cl, flags);
6779 break;
6781 default:
6782 rv = -1;
6783 break;
6786 return rv;
6790 * Don't allow exit unless user has set the action to something.
6793 role_filt_radiobutton_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
6795 int rv;
6797 switch(cmd){
6798 case MC_EXIT:
6799 rv = role_filt_exitcheck(cl, flags);
6800 break;
6802 default:
6803 rv = role_radiobutton_tool(ps, cmd, cl, flags);
6804 break;
6807 return(rv);
6812 * simple radio-button style variable handler
6815 role_radiobutton_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
6817 int rv = 0, i;
6818 CONF_S *ctmp, *spec_ctmp = NULL;
6819 NAMEVAL_S *rule;
6820 char **apval;
6822 switch(cmd){
6823 case MC_CHOICE : /* set/unset feature */
6825 /* back up to first line */
6826 for(ctmp = (*cl);
6827 ctmp && ctmp->prev && !(ctmp->prev->flags & CF_NOSELECT);
6828 ctmp = prev_confline(ctmp))
6831 for(i = 0; ctmp && (!(ctmp->flags & CF_NOSELECT)
6832 || (*cl)->var == role_fldr_ptr
6833 || (*cl)->var == role_afrom_ptr
6834 || (*cl)->var == role_filt_ptr);
6835 ctmp = next_confline(ctmp), i++){
6836 if(((*cl)->var == role_fldr_ptr) ||
6837 ((*cl)->var == role_afrom_ptr) ||
6838 ((*cl)->var == role_filt_ptr)){
6839 if((((*cl)->var == role_fldr_ptr) && !pat_fldr_types(i))
6840 || (((*cl)->var == role_afrom_ptr)
6841 && !inabook_fldr_types(i))
6842 || (((*cl)->var == role_filt_ptr) && !filter_types(i))){
6843 spec_ctmp = ctmp;
6844 break;
6848 ctmp->value[1] = ' ';
6851 /* turn on current value */
6852 (*cl)->value[1] = R_SELD;
6854 if((*cl)->var == role_fldr_ptr){
6855 for(ctmp = spec_ctmp;
6856 ctmp && ctmp->varnamep == spec_ctmp;
6857 ctmp = next_confline(ctmp))
6858 if((*cl)->varmem == FLDR_SPECIFIC)
6859 ctmp->flags &= ~CF_NOSELECT;
6860 else
6861 ctmp->flags |= CF_NOSELECT;
6863 rule = pat_fldr_types((*cl)->varmem);
6865 else if((*cl)->var == role_afrom_ptr){
6866 for(ctmp = spec_ctmp;
6867 ctmp && ctmp->varnamep == spec_ctmp;
6868 ctmp = next_confline(ctmp))
6869 if(((*cl)->varmem == IAB_SPEC_YES)
6870 || ((*cl)->varmem == IAB_SPEC_NO))
6871 ctmp->flags &= ~CF_NOSELECT;
6872 else
6873 ctmp->flags |= CF_NOSELECT;
6875 rule = inabook_fldr_types((*cl)->varmem);
6877 else if((*cl)->var == role_filt_ptr){
6878 for(ctmp = spec_ctmp;
6879 ctmp && ctmp->varnamep == spec_ctmp;
6880 ctmp = next_confline(ctmp))
6881 if((*cl)->varmem == FILTER_FOLDER)
6882 ctmp->flags &= ~CF_NOSELECT;
6883 else
6884 ctmp->flags |= CF_NOSELECT;
6886 rule = filter_types((*cl)->varmem);
6888 else if((*cl)->var == role_forw_ptr)
6889 rule = role_forw_types((*cl)->varmem);
6890 else if((*cl)->var == role_repl_ptr)
6891 rule = role_repl_types((*cl)->varmem);
6892 else if((*cl)->var == role_status1_ptr ||
6893 (*cl)->var == role_status2_ptr ||
6894 (*cl)->var == role_status3_ptr ||
6895 (*cl)->var == role_status4_ptr ||
6896 (*cl)->var == role_status5_ptr ||
6897 (*cl)->var == role_status6_ptr ||
6898 (*cl)->var == role_status7_ptr ||
6899 (*cl)->var == role_status8_ptr)
6900 rule = role_status_types((*cl)->varmem);
6901 else if((*cl)->var == msg_state1_ptr ||
6902 (*cl)->var == msg_state2_ptr ||
6903 (*cl)->var == msg_state3_ptr ||
6904 (*cl)->var == msg_state4_ptr)
6905 rule = msg_state_types((*cl)->varmem);
6906 else
6907 rule = role_comp_types((*cl)->varmem);
6909 apval = APVAL((*cl)->var, ew);
6910 if(apval && *apval)
6911 fs_give((void **)apval);
6913 if(apval)
6914 *apval = cpystr(rule->name);
6916 ps->mangled_body = 1; /* BUG: redraw it all for now? */
6917 rv = 1;
6919 break;
6921 case MC_EXIT: /* exit */
6922 rv = role_text_tool(ps, cmd, cl, flags);
6923 break;
6925 default :
6926 rv = -1;
6927 break;
6930 return(rv);
6935 role_sort_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
6937 int rv = 0, i;
6938 CONF_S *ctmp;
6939 char **apval;
6940 SortOrder def_sort;
6941 int def_sort_rev;
6943 apval = APVAL((*cl)->var, ew);
6945 switch(cmd){
6946 case MC_CHOICE : /* set/unset feature */
6948 if((*cl)->varmem >= 0){
6949 def_sort_rev = (*cl)->varmem >= (short) EndofList;
6950 def_sort = (SortOrder)((*cl)->varmem - (def_sort_rev * EndofList));
6952 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s", sort_name(def_sort),
6953 (def_sort_rev) ? "/Reverse" : "");
6954 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
6957 if(apval){
6958 if(*apval)
6959 fs_give((void **)apval);
6961 if((*cl)->varmem >= 0)
6962 *apval = cpystr(tmp_20k_buf);
6965 /* back up to first line */
6966 for(ctmp = (*cl);
6967 ctmp && ctmp->prev && !(ctmp->prev->flags & CF_NOSELECT);
6968 ctmp = prev_confline(ctmp))
6971 /* turn off all values */
6972 for(i = 0;
6973 ctmp && !(ctmp->flags & CF_NOSELECT);
6974 ctmp = next_confline(ctmp), i++)
6975 ctmp->value[1] = ' ';
6977 /* turn on current value */
6978 (*cl)->value[1] = R_SELD;
6980 ps->mangled_body = 1; /* BUG: redraw it all for now? */
6981 rv = 1;
6983 break;
6985 case MC_EXIT: /* exit */
6986 rv = role_text_tool(ps, cmd, cl, flags);
6987 break;
6989 default :
6990 rv = -1;
6991 break;
6994 return(rv);
6998 * Return an allocated list of the Specific Folder list for
6999 * roles, or NULL if Current Folder type is not set to
7000 * to Specific Folder
7002 * WARNING, the method used in obtaining the specific folder is
7003 * VERY dependent on the order in which it is presented on the
7004 * screen. If the Current Folder radio buttons were changed,
7005 * this function would probably need to be fixed accordingly.
7007 char **
7008 get_role_specific_folder(CONF_S **cl)
7010 CONF_S *ctmp;
7012 /* go to the first line */
7013 for(ctmp = *cl;
7014 ctmp && ctmp->prev;
7015 ctmp = prev_confline(ctmp))
7018 /* go to the current folder radio button list */
7019 while(ctmp && ctmp->var != role_fldr_ptr)
7020 ctmp = next_confline(ctmp);
7022 /* go to the specific folder button (caution) */
7023 while(ctmp && ctmp->varmem != FLDR_SPECIFIC)
7024 ctmp = next_confline(ctmp);
7026 /* check if selected (assumption of format "(*)" */
7027 if(ctmp && ctmp->value[1] == R_SELD){
7028 /* go to next line, the start of the list */
7029 ctmp = next_confline(ctmp);
7030 if(LVAL(ctmp->var, ew))
7031 return copy_list_array(LVAL(ctmp->var, ew));
7032 else{
7033 char **ltmp;
7036 * Need to allocate empty string so as not to confuse it
7037 * with the possibility that Specific Folder is not selected.
7039 ltmp = (char **) fs_get(2 * sizeof(char *));
7040 ltmp[0] = cpystr("");
7041 ltmp[1] = NULL;
7042 return(ltmp);
7045 else
7046 return NULL;
7053 role_litsig_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7055 int rv;
7057 switch(cmd){
7058 case MC_ADD :
7059 case MC_EDIT :
7060 rv = litsig_text_tool(ps, cmd, cl, flags);
7061 if(rv)
7062 calculate_inick_stuff(ps);
7064 break;
7066 default :
7067 rv = role_text_tool(ps, cmd, cl, flags);
7068 break;
7071 return(rv);
7078 role_cstm_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7080 int rv;
7082 switch(cmd){
7083 case MC_EXIT :
7084 rv = role_text_tool(ps, cmd, cl, flags);
7085 break;
7087 default :
7088 rv = text_tool(ps, cmd, cl, flags);
7089 if(rv == 1 && (*cl)->var){
7090 char **lval;
7092 lval = LVAL((*cl)->var, ew);
7093 if(lval && lval[(*cl)->varmem] &&
7094 ((!struncmp(lval[(*cl)->varmem],"from",4) &&
7095 (lval[(*cl)->varmem][4] == ':' ||
7096 lval[(*cl)->varmem][4] == '\0')) ||
7097 (!struncmp(lval[(*cl)->varmem],"reply-to",8) &&
7098 (lval[(*cl)->varmem][8] == ':' ||
7099 lval[(*cl)->varmem][8] == '\0'))))
7100 q_status_message1(SM_ORDER|SM_DING, 5, 7,
7101 "Use \"Set %s\" instead, Change ignored",
7102 !struncmp(lval[(*cl)->varmem],"from",4)
7103 ? "From" : "Reply-To");
7106 break;
7109 return(rv);
7116 role_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7118 OPT_SCREEN_S *saved_screen;
7119 int rv = -1, oeflags, len = 0, sig, r, i, cancel = 0;
7120 char *file, *err, title[20], *newfile, *lc, *addr, *fldr = NULL, *tmpfldr;
7121 char dir2[MAXPATH+1], pdir[MAXPATH+1], *p;
7122 char full_filename[MAXPATH+1], filename[MAXPATH+1];
7123 char tmp[MAXPATH+1], **spec_fldr, **apval;
7124 EARB_S *earb, *ea, *eaprev;
7125 CONF_S *ctmp, *ctmpb, *newcp, *ctend;
7126 HelpType help;
7128 switch(cmd){
7129 case MC_EXIT :
7130 if(flags & CF_CHANGES){
7131 switch(want_to(EXIT_PMT, 'y', 'x', h_config_role_undo, WT_FLUSH_IN)){
7132 case 'y':
7133 if((spec_fldr = get_role_specific_folder(cl)) != NULL){
7134 rv = check_role_folders(spec_fldr, 0);
7135 free_list_array(&spec_fldr);
7137 else
7138 rv = 2;
7139 break;
7141 case 'n':
7142 q_status_message(SM_ORDER,3,5,_("No changes saved"));
7143 rv = 10;
7144 break;
7146 case 'x': /* ^C */
7147 q_status_message(SM_ORDER,3,5,_("Changes not yet saved"));
7148 rv = 0;
7149 break;
7152 else
7153 rv = 2;
7155 break;
7157 case MC_NOT : /* toggle between !matching and matching */
7158 ctmp = (*cl)->varnamep;
7159 if(ctmp->varname && ctmp->var && ctmp->var->name){
7160 if(!strncmp(ctmp->varname, NOT, NOTLEN) &&
7161 !strncmp(ctmp->var->name, NOT, NOTLEN)){
7162 rplstr(ctmp->var->name, strlen(ctmp->var->name)+1, NOTLEN, "");
7163 rplstr(ctmp->varname, strlen(ctmp->varname)+1, NOTLEN, "");
7164 strncpy(ctmp->varname+strlen(ctmp->varname)-1,
7165 repeat_char(NOTLEN, ' '), NOTLEN+1);
7166 strncat(ctmp->varname, "=", NOTLEN);
7168 else{
7169 rplstr(ctmp->var->name, strlen(ctmp->var->name)+NOTLEN+1, 0, NOT);
7170 strncpy(ctmp->varname+strlen(ctmp->varname)-1-NOTLEN, "=", NOTLEN);
7171 rplstr(ctmp->varname, strlen(ctmp->varname)+NOTLEN+1, 0, NOT);
7174 rv = 1;
7177 break;
7179 case MC_CHOICE : /* Choose a file */
7181 * In signature_path we read signature files relative to the pinerc
7182 * dir, so if user selects one that is in there we'll make it
7183 * relative instead of absolute, so it looks nicer.
7185 pdir[0] = '\0';
7186 if(ps_global->VAR_OPER_DIR){
7187 strncpy(pdir, ps_global->VAR_OPER_DIR, MAXPATH);
7188 pdir[MAXPATH] = '\0';
7189 len = strlen(pdir) + 1;
7191 else if((lc = last_cmpnt(ps_global->pinerc)) != NULL){
7192 strncpy(pdir, ps_global->pinerc, MIN(MAXPATH,lc-ps_global->pinerc));
7193 pdir[MIN(MAXPATH, lc-ps_global->pinerc)] = '\0';
7194 len = strlen(pdir);
7197 strncpy(title, "CHOOSE A", 15);
7198 strncpy(dir2, pdir, MAXPATH);
7200 filename[0] = '\0';
7201 build_path(full_filename, dir2, filename, sizeof(full_filename));
7203 r = file_lister(title, dir2, sizeof(dir2), filename, sizeof(filename), TRUE, FB_READ);
7204 ps->mangled_screen = 1;
7206 if(r == 1){
7207 build_path(full_filename, dir2, filename, sizeof(full_filename));
7208 removing_leading_and_trailing_white_space(full_filename);
7209 if(!strncmp(full_filename, pdir, strlen(pdir)))
7210 newfile = cpystr(full_filename + len);
7211 else
7212 newfile = cpystr(full_filename);
7214 apval = APVAL((*cl)->var, ew);
7215 if(apval && *apval)
7216 fs_give((void **)apval);
7218 if(apval)
7219 *apval = newfile;
7221 if((*cl)->value)
7222 fs_give((void **)&((*cl)->value));
7224 (*cl)->value = pretty_value(ps, *cl);
7225 rv = 1;
7227 else
7228 rv = 0;
7230 break;
7232 case MC_CHOICEB : /* Choose Addresses, no full names */
7233 addr = addr_book_multaddr_nf();
7234 ps->mangled_screen = 1;
7235 if(addr && (*cl)->var && (*cl)->var->is_list){
7236 char **ltmp, *tmp;
7237 int i;
7239 i = 0;
7240 for(tmp = addr; *tmp; tmp++)
7241 if(*tmp == ',')
7242 i++; /* conservative count of ,'s */
7244 ltmp = parse_list(addr, i + 1, PL_COMMAQUOTE, NULL);
7245 fs_give((void **) &addr);
7247 if(ltmp && ltmp[0])
7248 config_add_list(ps, cl, ltmp, NULL, 0);
7250 if(ltmp)
7251 fs_give((void **) &ltmp);
7253 if((*cl)->value)
7254 fs_give((void **)&((*cl)->value));
7256 (*cl)->value = pretty_value(ps, *cl);
7257 rv = 1;
7259 else
7260 rv = 0;
7262 break;
7264 case MC_CHOICEC : /* Choose an Address, no full name */
7265 addr = addr_book_oneaddr();
7266 ps->mangled_screen = 1;
7267 if(addr){
7268 apval = APVAL((*cl)->var, ew);
7269 if(apval && *apval) /* replace current value */
7270 fs_give((void **)apval);
7272 if(apval)
7273 *apval = addr;
7275 if((*cl)->value)
7276 fs_give((void **)&((*cl)->value));
7278 (*cl)->value = pretty_value(ps, *cl);
7279 rv = 1;
7281 else
7282 rv = 0;
7284 break;
7286 case MC_CHOICED : /* Choose a Folder */
7287 case MC_CHOICEE :
7288 saved_screen = opt_screen;
7289 if(cmd == MC_CHOICED)
7290 tmpfldr = folder_for_config(FOR_PATTERN);
7291 else
7292 tmpfldr = folder_for_config(0);
7294 if(tmpfldr){
7295 fldr = add_comma_escapes(tmpfldr);
7296 fs_give((void**) &tmpfldr);
7299 opt_screen = saved_screen;
7301 ps->mangled_screen = 1;
7302 if(fldr && *fldr && (*cl)->var && (*cl)->var->is_list){
7303 char **ltmp;
7305 ltmp = (char **) fs_get(2 * sizeof(char *));
7306 ltmp[0] = fldr;
7307 ltmp[1] = NULL;
7308 fldr = NULL;
7310 if(ltmp && ltmp[0])
7311 config_add_list(ps, cl, ltmp, NULL, 0);
7313 if(ltmp)
7314 fs_give((void **) &ltmp);
7316 if((*cl)->value)
7317 fs_give((void **) &((*cl)->value));
7319 (*cl)->value = pretty_value(ps, *cl);
7320 rv = 1;
7322 else if(fldr && *fldr && (*cl)->var && !(*cl)->var->is_list){
7323 apval = APVAL((*cl)->var, ew);
7324 if(apval && *apval) /* replace current value */
7325 fs_give((void **)apval);
7327 if(apval){
7328 *apval = fldr;
7329 fldr = NULL;
7332 if((*cl)->value)
7333 fs_give((void **) &((*cl)->value));
7335 (*cl)->value = pretty_value(ps, *cl);
7336 rv = 1;
7338 else
7339 rv = 0;
7341 if(fldr)
7342 fs_give((void **) &fldr);
7344 break;
7346 case MC_EDITFILE :
7347 file = ((*cl)->var && PVAL((*cl)->var, ew))
7348 ? cpystr(PVAL((*cl)->var, ew)) : NULL;
7349 if(file)
7350 removing_leading_and_trailing_white_space(file);
7352 sig = (srchstr((*cl)->varname, "signature") != NULL);
7353 if(!file || !*file){
7354 err = (char *)fs_get(100 * sizeof(char));
7355 snprintf(err, 100, "No %s file defined. First define a file name.",
7356 sig ? "signature" : "template");
7357 err[100-1] = '\0';
7359 else{
7360 if(file[len=(strlen(file)-1)] == '|')
7361 file[len] = '\0';
7363 snprintf(title, sizeof(title), "%s EDITOR", sig ? "SIGNATURE" : "TEMPLATE");
7364 title[sizeof(title)-1] = '\0';
7365 err = signature_edit(file, title);
7368 fs_give((void **)&file);
7369 if(err){
7370 q_status_message1(SM_ORDER, 3, 5, "%s", err);
7371 fs_give((void **)&err);
7374 rv = 0;
7375 ps->mangled_screen = 1;
7376 break;
7378 /* Add an arbitrary header to this role */
7379 case MC_ADDHDR :
7380 rv = 0;
7381 /* make earb point to last one */
7382 for(earb = *(*cl)->d.earb; earb && earb->next; earb = earb->next)
7385 /* Add new one to end of list */
7386 ea = (EARB_S *)fs_get(sizeof(*ea));
7387 memset((void *)ea, 0, sizeof(*ea));
7388 ea->v = (struct variable *)fs_get(sizeof(struct variable));
7389 memset((void *)ea->v, 0, sizeof(struct variable));
7390 ea->a = (ARBHDR_S *)fs_get(sizeof(ARBHDR_S));
7391 memset((void *)ea->a, 0, sizeof(ARBHDR_S));
7393 /* get new header field name */
7394 help = NO_HELP;
7395 tmp[0] = '\0';
7396 while(1){
7397 i = optionally_enter(tmp, -FOOTER_ROWS(ps), 0, sizeof(tmp),
7398 _("Enter the name of the header field to be added: "),
7399 NULL, help, NULL);
7400 if(i == 0)
7401 break;
7402 else if(i == 1){
7403 cmd_cancelled("eXtraHdr");
7404 cancel = 1;
7405 break;
7407 else if(i == 3){
7408 help = help == NO_HELP ? h_config_add_pat_hdr : NO_HELP;
7409 continue;
7411 else
7412 break;
7415 ps->mangled_footer = 1;
7417 removing_leading_and_trailing_white_space(tmp);
7418 if(tmp[strlen(tmp)-1] == ':') /* remove trailing colon */
7419 tmp[strlen(tmp)-1] = '\0';
7421 removing_trailing_white_space(tmp);
7423 if(cancel || !tmp[0])
7424 break;
7426 tmp[0] = islower((unsigned char)tmp[0]) ? toupper((unsigned char)tmp[0])
7427 : tmp[0];
7428 ea->a->field = cpystr(tmp);
7430 if(earb)
7431 earb->next = ea;
7432 else
7433 *((*cl)->d.earb) = ea;
7435 /* go to first line */
7436 for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
7440 * Go to the Add Extra Headers line. We will put the
7441 * new header before this line.
7443 for(; ctmp; ctmp = next_confline(ctmp))
7444 if(ctmp->value && !strcmp(ctmp->value, ADDXHDRS))
7445 break;
7447 /* move back one */
7448 if(ctmp)
7449 ctmp = prev_confline(ctmp);
7452 * Add a new line after this point, which is after the last
7453 * extra header (if any) or after the Participant pattern, and
7454 * before the Add Extra Headers placeholder line.
7456 p = (char *) fs_get(strlen(tmp) + strlen(" pattern") + 1);
7457 snprintf(p, strlen(tmp) + strlen(" pattern") + 1, "%s pattern", tmp);
7458 p[strlen(tmp) + strlen(" pattern") + 1 - 1] = '\0';
7459 setup_dummy_pattern_var(ea->v, p, NULL);
7460 fs_give((void **) &p);
7462 /* find what indent should be */
7463 if(ctmp && ctmp->varnamep && ctmp->varnamep->varname)
7464 i = MIN(MAX(utf8_width(ctmp->varnamep->varname) + 1, 3), 200);
7465 else
7466 i = 20;
7468 setup_role_pat(ps, &ctmp, ea->v, h_config_role_arbpat,
7469 ARB_HELP, &config_role_xtrahdr_keymenu,
7470 ctmp->prev->tool, ctmp->prev->d.earb, i);
7473 * move current line to new line
7476 newcp = ctmp;
7478 /* check if new line comes before the top of the screen */
7479 ctmpb = (opt_screen && opt_screen->top_line)
7480 ? opt_screen->top_line->prev : NULL;
7481 for(; ctmpb; ctmpb = prev_confline(ctmpb))
7482 if(ctmpb == newcp)
7483 break;
7485 * Keep the right lines visible.
7486 * The if triggers if the new line is off the top of the screen, and
7487 * it makes the new line be the top line.
7488 * The else counts how many lines down the screen the new line is.
7491 i = 0;
7492 if(ctmpb == newcp)
7493 opt_screen->top_line = newcp;
7494 else{
7495 for(ctmp = opt_screen->top_line; ctmp && ctmp != newcp;
7496 i++, ctmp = next_confline(ctmp))
7500 if(i >= BODY_LINES(ps)){ /* new line is off screen */
7501 /* move top line down this far */
7502 i = i + 1 - BODY_LINES(ps);
7503 for(ctmp = opt_screen->top_line;
7504 i > 0;
7505 i--, ctmp = next_confline(ctmp))
7508 opt_screen->top_line = ctmp;
7511 *cl = newcp;
7513 ps->mangled_screen = 1;
7514 rv = 1;
7515 break;
7517 /* Delete an arbitrary header from this role */
7518 case MC_DELHDR :
7520 * Find this one in earb list. We don't have a good way to locate
7521 * it so we match the ea->v->name with ctmp->varname.
7523 rv = 0;
7524 eaprev = NULL;
7525 for(ea = *(*cl)->d.earb; ea; ea = ea->next){
7526 if((*cl)->varnamep && (*cl)->varnamep->varname
7527 && ea->v && ea->v->name
7528 && !strncmp((*cl)->varnamep->varname,
7529 ea->v->name, strlen(ea->v->name)))
7530 break;
7532 eaprev = ea;
7535 snprintf(tmp, sizeof(tmp), _("Really remove \"%s\" pattern from this rule"),
7536 (ea && ea->a && ea->a->field) ? ea->a->field : "this");
7537 tmp[sizeof(tmp)-1] = '\0';
7538 if(want_to(tmp, 'y', 'n', NO_HELP, WT_NORM) != 'y'){
7539 cmd_cancelled("RemoveHdr");
7540 return(rv);
7543 /* delete the earb element from the list */
7544 if(ea){
7545 if(eaprev)
7546 eaprev->next = ea->next;
7547 else
7548 *(*cl)->d.earb = ea->next;
7550 ea->next = NULL;
7551 free_earb(&ea);
7554 /* remember start of deleted header */
7555 ctmp = (*cl && (*cl)->varnamep) ? (*cl)->varnamep : NULL;
7557 /* and end of deleted header */
7558 for(ctend = *cl; ctend; ctend = next_confline(ctend))
7559 if(!ctend->next || ctend->next->varnamep != ctmp)
7560 break;
7562 /* check if top line is one we're deleting */
7563 for(ctmpb = ctmp; ctmpb; ctmpb = next_confline(ctmpb)){
7564 if(ctmpb == opt_screen->top_line)
7565 break;
7567 if(ctmpb == (*cl))
7568 break;
7571 if(ctmpb == opt_screen->top_line)
7572 opt_screen->top_line = ctend ? ctend->next : NULL;
7574 /* move current line after this header */
7575 *cl = ctend ? ctend->next : NULL;
7577 /* remove deleted header lines */
7578 if(ctmp && ctend){
7579 /* remove from linked list */
7580 if(ctmp->prev)
7581 ctmp->prev->next = ctend->next;
7583 if(ctend->next)
7584 ctend->next->prev = ctmp->prev;
7586 /* free memory */
7587 ctmp->prev = ctend->next = NULL;
7588 free_conflines(&ctmp);
7591 ps->mangled_body = 1;
7592 rv = 1;
7593 break;
7595 default :
7596 if(((*cl)->var == scorei_pat_global_ptr
7597 || (*cl)->var == age_pat_global_ptr
7598 || (*cl)->var == size_pat_global_ptr
7599 || (*cl)->var == cati_global_ptr)
7601 (cmd == MC_EDIT || (cmd == MC_ADD && !PVAL((*cl)->var, ew)))){
7602 char prompt[60];
7604 rv = 0;
7605 snprintf(prompt, sizeof(prompt), "%s the interval : ",
7606 PVAL((*cl)->var, ew) ? "Change" : "Enter");
7607 prompt[sizeof(prompt)-1] = '\0';
7609 ps->mangled_footer = 1;
7610 help = NO_HELP;
7611 tmp[0] = '\0';
7612 snprintf(tmp, sizeof(tmp),
7613 "%s", PVAL((*cl)->var, ew) ? PVAL((*cl)->var, ew) : "");
7614 tmp[sizeof(tmp)-1] = '\0';
7615 while(1){
7616 oeflags = OE_APPEND_CURRENT;
7617 i = optionally_enter(tmp, -FOOTER_ROWS(ps), 0, sizeof(tmp),
7618 prompt, NULL, help, &oeflags);
7619 if(i == 0){
7620 rv = ps->mangled_body = 1;
7621 apval = APVAL((*cl)->var, ew);
7622 if(apval && *apval)
7623 fs_give((void **)apval);
7625 if(apval && tmp[0])
7626 *apval = cpystr(tmp);
7628 fix_side_effects(ps, (*cl)->var, 0);
7629 if((*cl)->value)
7630 fs_give((void **)&(*cl)->value);
7632 (*cl)->value = pretty_value(ps, *cl);
7634 else if(i == 1)
7635 cmd_cancelled(cmd == MC_ADD ? "Add" : "Change");
7636 else if(i == 3){
7637 help = help == NO_HELP ? h_config_edit_scorei : NO_HELP;
7638 continue;
7640 else if(i == 4)
7641 continue;
7643 break;
7646 else{
7647 if(cmd == MC_ADD && (*cl)->var && !(*cl)->var->is_list)
7648 cmd = MC_EDIT;
7650 rv = text_toolit(ps, cmd, cl, flags, 1);
7652 /* make sure the earb pointers are set */
7653 for(ctmp = (*cl)->varnamep;
7654 ctmp->next && ctmp->next->var == ctmp->var;
7655 ctmp = next_confline(ctmp))
7656 ctmp->next->d.earb = ctmp->d.earb;
7659 break;
7663 * If the inherit nickname changed, we have to re-calculate the
7664 * global_vals and values for the action variables.
7665 * We may have to do the same if literal sig changed, too.
7667 if(rv)
7668 calculate_inick_stuff(ps);
7670 return(rv);
7677 role_text_tool_inick(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7679 int rv = -1;
7680 char **apval;
7682 switch(cmd){
7683 case MC_EXIT :
7684 rv = role_text_tool(ps, cmd, cl, flags);
7685 break;
7687 case MC_CHOICE : /* Choose a role nickname */
7688 {void (*prev_screen)(struct pine *) = ps->prev_screen,
7689 (*redraw)(void) = ps->redrawer;
7690 OPT_SCREEN_S *saved_screen;
7691 ACTION_S *role;
7693 ps->redrawer = NULL;
7694 ps->next_screen = SCREEN_FUN_NULL;
7696 saved_screen = opt_screen;
7697 if(role_select_screen(ps, &role, 0) == 0){
7698 apval = APVAL((*cl)->var, ew);
7699 if(apval && *apval)
7700 fs_give((void **)apval);
7702 if(apval)
7703 *apval = (role && role->nick) ? cpystr(role->nick) : NULL;
7705 if((*cl)->value)
7706 fs_give((void **)&((*cl)->value));
7708 (*cl)->value = pretty_value(ps, *cl);
7709 rv = 1;
7711 else{
7712 ps->next_screen = prev_screen;
7713 ps->redrawer = redraw;
7714 rv = 0;
7717 opt_screen = saved_screen;
7720 ps->mangled_screen = 1;
7721 break;
7723 case MC_EDIT :
7724 case MC_ADD :
7725 case MC_DELETE :
7726 rv = text_tool(ps, cmd, cl, flags);
7727 ps->mangled_screen = 1;
7728 break;
7730 default :
7731 rv = text_tool(ps, cmd, cl, flags);
7732 break;
7736 * If the inherit nickname changed, we have to re-calculate the
7737 * global_vals and values for the action variables.
7738 * We may have to do the same if literal sig changed, too.
7740 if(rv)
7741 calculate_inick_stuff(ps);
7743 return(rv);
7750 role_text_tool_kword(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7752 int i, j, rv = -1;
7753 char **lval;
7755 switch(cmd){
7756 case MC_CHOICE : /* Choose keywords from list and add them */
7757 {void (*prev_screen)(struct pine *) = ps->prev_screen,
7758 (*redraw)(void) = ps->redrawer;
7759 OPT_SCREEN_S *saved_screen;
7760 char *esc;
7761 char **kw;
7763 ps->redrawer = NULL;
7764 ps->next_screen = SCREEN_FUN_NULL;
7766 saved_screen = opt_screen;
7768 if((kw=choose_list_of_keywords()) != NULL){
7769 for(i = 0; kw[i]; i++){
7770 esc = add_roletake_escapes(kw[i]);
7771 fs_give((void **) &kw[i]);
7772 kw[i] = esc;
7775 /* eliminate duplicates before the add */
7776 lval = LVAL((*cl)->var, ew);
7777 if(lval && *lval){
7778 for(i = 0; kw[i]; ){
7779 /* if kw[i] is a dup, eliminate it */
7780 for(j = 0; lval[j]; j++)
7781 if(!strcmp(kw[i], lval[j]))
7782 break;
7784 if(lval[j]){ /* it is a dup */
7785 for(j = i; kw[j]; j++)
7786 kw[j] = kw[j+1];
7788 else
7789 i++;
7793 if(kw[0])
7794 config_add_list(ps, cl, kw, NULL, 0);
7796 fs_give((void **) &kw);
7798 if((*cl)->value)
7799 fs_give((void **) &((*cl)->value));
7801 (*cl)->value = pretty_value(ps, *cl);
7802 rv = 1;
7804 else{
7805 ps->next_screen = prev_screen;
7806 ps->redrawer = redraw;
7807 rv = 0;
7810 opt_screen = saved_screen;
7813 ps->mangled_screen = 1;
7814 break;
7816 case MC_EDIT :
7817 case MC_ADD :
7818 case MC_DELETE :
7819 case MC_NOT :
7820 rv = role_text_tool(ps, cmd, cl, flags);
7821 ps->mangled_screen = 1;
7822 break;
7824 case MC_EXIT :
7825 default :
7826 rv = role_text_tool(ps, cmd, cl, flags);
7827 break;
7830 return(rv);
7837 role_text_tool_charset(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7839 int i, j, rv = -1;
7840 char **lval;
7842 switch(cmd){
7843 case MC_CHOICE : /* Choose charsets from list and add them */
7844 {void (*prev_screen)(struct pine *) = ps->prev_screen,
7845 (*redraw)(void) = ps->redrawer;
7846 OPT_SCREEN_S *saved_screen;
7847 char *esc;
7848 char **kw;
7850 ps->redrawer = NULL;
7851 ps->next_screen = SCREEN_FUN_NULL;
7853 saved_screen = opt_screen;
7855 if((kw=choose_list_of_charsets()) != NULL){
7856 for(i = 0; kw[i]; i++){
7857 esc = add_roletake_escapes(kw[i]);
7858 fs_give((void **) &kw[i]);
7859 kw[i] = esc;
7862 /* eliminate duplicates before the add */
7863 lval = LVAL((*cl)->var, ew);
7864 if(lval && *lval){
7865 for(i = 0; kw[i]; ){
7866 /* if kw[i] is a dup, eliminate it */
7867 for(j = 0; lval[j]; j++)
7868 if(!strcmp(kw[i], lval[j]))
7869 break;
7871 if(lval[j]){ /* it is a dup */
7872 for(j = i; kw[j]; j++)
7873 kw[j] = kw[j+1];
7875 else
7876 i++;
7880 if(kw[0])
7881 config_add_list(ps, cl, kw, NULL, 0);
7883 fs_give((void **) &kw);
7885 if((*cl)->value)
7886 fs_give((void **) &((*cl)->value));
7888 (*cl)->value = pretty_value(ps, *cl);
7889 rv = 1;
7891 else{
7892 ps->next_screen = prev_screen;
7893 ps->redrawer = redraw;
7894 rv = 0;
7897 opt_screen = saved_screen;
7900 ps->mangled_screen = 1;
7901 break;
7903 case MC_EDIT :
7904 case MC_ADD :
7905 case MC_DELETE :
7906 case MC_NOT :
7907 rv = role_text_tool(ps, cmd, cl, flags);
7908 ps->mangled_screen = 1;
7909 break;
7911 case MC_EXIT :
7912 default :
7913 rv = role_text_tool(ps, cmd, cl, flags);
7914 break;
7917 return(rv);
7922 * Choose an address book nickname
7925 role_text_tool_afrom(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7927 int rv = -1;
7929 switch(cmd){
7930 case MC_EXIT :
7931 rv = role_text_tool(ps, cmd, cl, flags);
7932 break;
7934 case MC_CHOICE : /* Choose an addressbook */
7935 {OPT_SCREEN_S *saved_screen;
7936 char *abook = NULL, *abookesc = NULL;
7938 ps->redrawer = NULL;
7939 ps->next_screen = SCREEN_FUN_NULL;
7940 saved_screen = opt_screen;
7942 abook = abook_select_screen(ps);
7943 if(abook){
7944 abookesc = add_comma_escapes(abook);
7945 fs_give((void**) &abook);
7948 ps->mangled_screen = 1;
7949 if(abookesc && *abookesc && (*cl)->var && (*cl)->var->is_list){
7950 char **ltmp;
7952 ltmp = (char **) fs_get(2 * sizeof(char *));
7953 ltmp[0] = abookesc;
7954 ltmp[1] = NULL;
7955 abookesc = NULL;
7957 if(ltmp && ltmp[0])
7958 config_add_list(ps, cl, ltmp, NULL, 0);
7960 if(ltmp)
7961 fs_give((void **) &ltmp);
7963 if((*cl)->value)
7964 fs_give((void **) &((*cl)->value));
7966 (*cl)->value = pretty_value(ps, *cl);
7967 rv = 1;
7969 else
7970 rv = 0;
7972 if(abookesc)
7973 fs_give((void **) &abookesc);
7975 opt_screen = saved_screen;
7978 ps->mangled_screen = 1;
7979 break;
7981 default :
7982 rv = text_tool(ps, cmd, cl, flags);
7983 ps->mangled_screen = 1;
7984 break;
7987 return(rv);
7992 * Args fmt -- a printf style fmt string with a single %s
7993 * buf -- place to put result, assumed large enough (strlen(fmt)+11)
7994 * rflags -- controls what goes in buf
7996 * Returns -- pointer to buf
7998 char *
7999 role_type_print(char *buf, size_t buflen, char *fmt, long int rflags)
8001 #define CASE_MIXED 1
8002 #define CASE_UPPER 2
8003 #define CASE_LOWER 3
8004 int cas = CASE_UPPER;
8005 int prev_word_is_a = 0;
8006 char *q, *p;
8008 /* find %sRule to see what case */
8009 if((p = srchstr(fmt, "%srule")) != NULL){
8010 if(p[2] == 'R'){
8011 if(p[3] == 'U')
8012 cas = CASE_UPPER;
8013 else
8014 cas = CASE_MIXED;
8016 else
8017 cas = CASE_LOWER;
8019 if(p-3 >= fmt &&
8020 p[-1] == SPACE &&
8021 (p[-2] == 'a' || p[-2] == 'A')
8022 && p[-3] == SPACE)
8023 prev_word_is_a++;
8026 if(cas == CASE_UPPER)
8027 q = (rflags & ROLE_DO_INCOLS) ? "INDEX COLOR " :
8028 (rflags & ROLE_DO_FILTER) ? "FILTERING " :
8029 (rflags & ROLE_DO_SCORES) ? "SCORING " :
8030 (rflags & ROLE_DO_OTHER) ? "OTHER " :
8031 (rflags & ROLE_DO_SRCH) ? "SEARCH " :
8032 (rflags & ROLE_DO_ROLES) ? "ROLE " : "";
8033 else if(cas == CASE_LOWER)
8034 q = (rflags & ROLE_DO_INCOLS) ? "index color " :
8035 (rflags & ROLE_DO_FILTER) ? "filtering " :
8036 (rflags & ROLE_DO_SCORES) ? "scoring " :
8037 (rflags & ROLE_DO_OTHER) ? "other " :
8038 (rflags & ROLE_DO_OTHER) ? "search " :
8039 (rflags & ROLE_DO_ROLES) ? "role " : "";
8040 else
8041 q = (rflags & ROLE_DO_INCOLS) ? "Index Color " :
8042 (rflags & ROLE_DO_FILTER) ? "Filtering " :
8043 (rflags & ROLE_DO_SCORES) ? "Scoring " :
8044 (rflags & ROLE_DO_OTHER) ? "Other " :
8045 (rflags & ROLE_DO_OTHER) ? "Search " :
8046 (rflags & ROLE_DO_ROLES) ? "Role " : "";
8048 /* it ain't right to say "a index" */
8049 if(prev_word_is_a && !struncmp(q, "index", 5))
8050 q += 6;
8052 snprintf(buf, buflen, fmt, q);
8053 buf[buflen-1] = '\0';
8054 return(buf);
8059 * filter option list manipulation tool
8062 * returns: -1 on unrecognized cmd, 0 if no change, 1 if change
8065 feat_checkbox_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
8067 int rv = 0;
8069 switch(cmd){
8070 case MC_TOGGLE: /* mark/unmark option */
8071 rv = 1;
8072 toggle_feat_option_bit(ps, (*cl)->varmem, (*cl)->var, (*cl)->value);
8073 break;
8075 case MC_EXIT: /* exit */
8076 rv = role_filt_exitcheck(cl, flags);
8077 break;
8079 default :
8080 rv = -1;
8081 break;
8084 return(rv);
8088 void
8089 toggle_feat_option_bit(struct pine *ps, int index, struct variable *var, char *value)
8091 NAMEVAL_S *f;
8093 f = feat_feature_list(index);
8095 /* flip the bit */
8096 if(bitnset(f->value, feat_option_list))
8097 clrbitn(f->value, feat_option_list);
8098 else
8099 setbitn(f->value, feat_option_list);
8101 if(value)
8102 value[1] = bitnset(f->value, feat_option_list) ? 'X' : ' ';
8106 NAMEVAL_S *
8107 feat_feature_list(int index)
8109 static NAMEVAL_S opt_feat_list[] = {
8110 {"use-date-header-for-age", NULL, FEAT_SENTDATE},
8111 {"move-only-if-not-deleted", NULL, FEAT_IFNOTDEL},
8112 {"dont-stop-even-if-rule-matches", NULL, FEAT_NONTERM}
8115 return((index >= 0 &&
8116 index < (sizeof(opt_feat_list)/sizeof(opt_feat_list[0])))
8117 ? &opt_feat_list[index] : NULL);
8122 * address type list manipulation tool
8125 * returns: -1 on unrecognized cmd, 0 if no change, 1 if change
8128 inabook_checkbox_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
8130 int rv = 0;
8132 switch(cmd){
8133 case MC_TOGGLE: /* mark/unmark option */
8134 rv = 1;
8135 toggle_inabook_type_bit(ps, (*cl)->varmem, (*cl)->var, (*cl)->value);
8136 break;
8138 case MC_EXIT: /* exit */
8139 rv = role_filt_exitcheck(cl, flags);
8140 break;
8142 default :
8143 rv = -1;
8144 break;
8147 return(rv);
8151 void
8152 toggle_inabook_type_bit(struct pine *ps, int index, struct variable *var, char *value)
8154 NAMEVAL_S *f;
8156 f = inabook_feature_list(index);
8158 /* flip the bit */
8159 if(bitnset(f->value, inabook_type_list))
8160 clrbitn(f->value, inabook_type_list);
8161 else
8162 setbitn(f->value, inabook_type_list);
8164 if(value)
8165 value[1] = bitnset(f->value, inabook_type_list) ? 'X' : ' ';
8169 NAMEVAL_S *
8170 inabook_feature_list(int index)
8172 static NAMEVAL_S inabook_feat_list[] = {
8173 {"From", NULL, INABOOK_FROM},
8174 {"Reply-To", NULL, INABOOK_REPLYTO},
8175 {"Sender", NULL, INABOOK_SENDER},
8176 {"To", NULL, INABOOK_TO},
8177 {"Cc", NULL, INABOOK_CC}
8180 return((index >= 0 &&
8181 index < (sizeof(inabook_feat_list)/sizeof(inabook_feat_list[0])))
8182 ? &inabook_feat_list[index] : NULL);