* New version 2.21.999
[alpine.git] / alpine / roleconf.c
blob75e92565789470b667d4980b0bd775d07747a6c8
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: roleconf.c 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2006-2008 University of Washington
8 * Copyright 2013-2018 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
19 #include "headers.h"
20 #include "roleconf.h"
21 #include "colorconf.h"
22 #include "conftype.h"
23 #include "confscroll.h"
24 #include "keymenu.h"
25 #include "status.h"
26 #include "radio.h"
27 #include "reply.h"
28 #include "folder.h"
29 #include "addrbook.h"
30 #include "mailcmd.h"
31 #include "setup.h"
32 #include "../pith/state.h"
33 #include "../pith/conf.h"
34 #include "../pith/msgno.h"
35 #include "../pith/bitmap.h"
36 #include "../pith/sort.h"
37 #include "../pith/addrstring.h"
38 #include "../pith/list.h"
39 #include "../pith/flag.h"
40 #include "../pith/bldaddr.h"
41 #include "../pith/news.h"
42 #include "../pith/util.h"
43 #include "../pith/detoken.h"
44 #include "../pith/icache.h"
45 #include "../pith/ablookup.h"
46 #include "../pith/pattern.h"
47 #include "../pith/tempfile.h"
50 #define NOT "! "
51 #define NOTLEN 2
54 #define ARB_HELP _("HELP FOR ARBITRARY HEADER PATTERNS")
55 #define ADDXHDRS _("Add Extra Headers")
59 * Internal prototypes
61 int role_select_tool(struct pine *, int, CONF_S **, unsigned);
62 PATTERN_S *addrlst_to_pattern(ADDRESS *);
63 void role_config_init_disp(struct pine *, CONF_S **, long, PAT_STATE *);
64 void add_patline_to_display(struct pine *, CONF_S **, int, CONF_S **, CONF_S **, PAT_LINE_S *, long);
65 void add_role_to_display(CONF_S **, PAT_LINE_S *, PAT_S *, int, CONF_S **, int, long);
66 void add_fake_first_role(CONF_S **, int, long);
67 int role_config_tool(struct pine *, int, CONF_S **, unsigned);
68 int role_config_add(struct pine *, CONF_S **, long);
69 int role_config_replicate(struct pine *, CONF_S **, long);
70 int role_config_edit(struct pine *, CONF_S **, long);
71 int role_config_del(struct pine *, CONF_S **, long);
72 void delete_a_role(CONF_S **, long);
73 int role_config_shuffle(struct pine *, CONF_S **);
74 int role_config_addfile(struct pine *, CONF_S **, long);
75 int role_config_delfile(struct pine *, CONF_S **, long);
76 void swap_literal_roles(CONF_S *, CONF_S *);
77 void swap_file_roles(CONF_S *, CONF_S *);
78 void move_role_into_file(CONF_S **, int);
79 void move_role_outof_file(CONF_S **, int);
80 void move_role_around_file(CONF_S **, int);
81 int role_config_edit_screen(struct pine *, PAT_S *, char *, long, PAT_S **);
82 void setup_dummy_pattern_var(struct variable *, char *, PATTERN_S *);
83 void setup_role_pat(struct pine *, CONF_S **, struct variable *, HelpType, char *,
84 struct key_menu *,
85 int (*tool)(struct pine *, int, CONF_S **, unsigned),
86 EARB_S **, int);
87 void setup_role_pat_alt(struct pine *, CONF_S **, struct variable *, HelpType, char *,
88 struct key_menu *,
89 int (*tool)(struct pine *, int, CONF_S **, unsigned),
90 int, int);
91 void free_earb(EARB_S **);
92 void calculate_inick_stuff(struct pine *);
93 int check_role_folders(char **, unsigned);
94 void maybe_add_to_incoming(CONTEXT_S *, char *);
95 int role_filt_exitcheck(CONF_S **, unsigned);
96 int role_filt_text_tool(struct pine *, int, CONF_S **, unsigned);
97 int role_filt_addhdr_tool(struct pine *, int, CONF_S **, unsigned);
98 int role_addhdr_tool(struct pine *, int, CONF_S **, unsigned);
99 int role_filt_radiobutton_tool(struct pine *, int, CONF_S **, unsigned);
100 int role_sort_tool(struct pine *, int, CONF_S **, unsigned);
101 char **get_role_specific_folder(CONF_S **);
102 int role_litsig_text_tool(struct pine *, int, CONF_S **, unsigned);
103 int role_cstm_text_tool(struct pine *, int, CONF_S **, unsigned);
104 int role_text_tool(struct pine *, int, CONF_S **, unsigned);
105 int role_text_tool_inick(struct pine *, int, CONF_S **, unsigned);
106 int role_text_tool_kword(struct pine *, int, CONF_S **, unsigned);
107 int role_text_tool_charset(struct pine *, int, CONF_S **, unsigned);
108 int role_text_tool_afrom(struct pine *, int, CONF_S **, unsigned);
109 char *role_type_print(char *, size_t, char *, long);
110 int feat_checkbox_tool(struct pine *, int, CONF_S **, unsigned);
111 void toggle_feat_option_bit(struct pine *, int, struct variable *, char *);
112 NAMEVAL_S *feat_feature_list(int);
113 int inabook_checkbox_tool(struct pine *, int, CONF_S **, unsigned);
114 void toggle_inabook_type_bit(struct pine *, int, struct variable *, char *);
115 NAMEVAL_S *inabook_feature_list(int);
118 static char *set_choose = "--- --------------------";
119 static long role_global_flags;
120 static PAT_STATE *role_global_pstate;
124 role_select_screen(struct pine *ps, ACTION_S **role, int alt_compose)
126 CONF_S *ctmp = NULL, *first_line = NULL;
127 OPT_SCREEN_S screen;
128 PAT_S *pat, *sel_pat = NULL;
129 int ret = -1;
130 int change_default = 0;
131 long rflags = ROLE_DO_ROLES;
132 char *helptitle;
133 HelpType help;
134 PAT_STATE pstate;
136 if(!role)
137 return(ret);
139 *role = NULL;
141 if(!(nonempty_patterns(rflags, &pstate) &&
142 first_pattern(&pstate))){
143 q_status_message(SM_ORDER, 3, 3,
144 _("No roles available. Use Setup/Rules to add roles."));
145 return(ret);
149 if(alt_compose){
150 menu_init_binding(&role_select_km,
151 alt_compose == MC_FORWARD ? 'F' :
152 alt_compose == MC_REPLY ? 'R' :
153 alt_compose == MC_COMPOSE ? 'C' : 'B',
154 MC_CHOICE,
155 alt_compose == MC_FORWARD ? "F" :
156 alt_compose == MC_REPLY ? "R" :
157 alt_compose == MC_COMPOSE ? "C" : "B",
158 alt_compose == MC_FORWARD ? "[" N_("ForwardAs") "]" :
159 alt_compose == MC_REPLY ? "[" N_("ReplyAs") "]" :
160 alt_compose == MC_COMPOSE ? "[" N_("ComposeAs") "]" : "[" N_("BounceAs") "]",
161 DEFAULT_KEY);
162 menu_add_binding(&role_select_km, ctrl('J'), MC_CHOICE);
163 menu_add_binding(&role_select_km, ctrl('M'), MC_CHOICE);
165 else{
166 menu_init_binding(&role_select_km, 'S', MC_CHOICE, "S", "[" N_("Select") "]",
167 DEFAULT_KEY);
168 menu_add_binding(&role_select_km, ctrl('J'), MC_CHOICE);
169 menu_add_binding(&role_select_km, ctrl('M'), MC_CHOICE);
172 help = h_role_select;
173 if(alt_compose == MC_BOUNCE)
174 helptitle = _("HELP FOR SELECTING A ROLE TO BOUNCE AS");
175 else if(alt_compose)
176 helptitle = _("HELP FOR SELECTING A ROLE TO COMPOSE AS");
177 else
178 helptitle = _("HELP FOR SELECTING A ROLE");
180 menu_init_binding(&role_select_km, 'D', MC_TOGGLE, "D", "changeDef", CHANGEDEF_KEY);
182 for(pat = first_pattern(&pstate);
183 pat;
184 pat = next_pattern(&pstate)){
185 new_confline(&ctmp);
186 if(!first_line)
187 first_line = ctmp;
189 ctmp->value = cpystr((pat->patgrp && pat->patgrp->nick)
190 ? pat->patgrp->nick : "?");
191 ctmp->d.r.selected = &sel_pat;
192 ctmp->d.r.pat = pat;
193 ctmp->d.r.change_def = &change_default;
194 ctmp->keymenu = &role_select_km;
195 ctmp->help = help;
196 ctmp->help_title = helptitle;
197 ctmp->tool = role_select_tool;
198 ctmp->flags = CF_STARTITEM;
199 ctmp->valoffset = 4;
202 memset(&screen, 0, sizeof(screen));
203 /* TRANSLATORS: Print something1 using something2.
204 "roles" is something1 */
205 (void)conf_scroll_screen(ps, &screen, first_line, _("SELECT ROLE"),
206 _("roles"), 0, NULL);
208 if(sel_pat){
209 *role = sel_pat->action;
210 if(change_default == 1)
211 ps_global->default_role = *role;
212 else if(change_default == 2)
213 ps_global->default_role = NULL;
215 ret = 0;
218 ps->mangled_screen = 1;
219 return(ret);
224 role_select_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
226 int retval = 0, newval;
228 switch(cmd){
229 case MC_CHOICE :
230 *((*cl)->d.r.selected) = (*cl)->d.r.pat;
231 retval = simple_exit_cmd(flags);
232 break;
234 case MC_TOGGLE :
235 newval = (*((*cl)->d.r.change_def) + 1) % 3;
236 *((*cl)->d.r.change_def) = newval;
237 menu_init_binding((*cl)->keymenu, 'D', MC_TOGGLE, "D",
238 (newval == 0) ? "changeDef" : (newval == 1) ? "removeDef" : "leaveDef",
239 CHANGEDEF_KEY);
240 if(newval == 1){
241 if(ps_global->default_role)
242 q_status_message(SM_ORDER, 0, 3,
243 _("Default role will be changed to the role you Select"));
244 else
245 q_status_message(SM_ORDER, 0, 3,
246 _("Default role will be set to the role you Select"));
248 else if(newval == 2){
249 q_status_message(SM_ORDER, 0, 3, _("Default role will be unset"));
251 else{ /* newval == 0 */
252 if(ps_global->default_role)
253 q_status_message(SM_ORDER, 0, 3, _("Default role will remain unchanged"));
254 else
255 q_status_message(SM_ORDER, 0, 3, _("Default role will remain unset"));
258 ps->mangled_footer = 1;
259 retval = 0;
260 break;
262 case MC_EXIT :
263 retval = simple_exit_cmd(flags);
264 break;
266 default:
267 retval = -1;
268 break;
271 if(retval > 0)
272 ps->mangled_body = 1;
274 return(retval);
278 void
279 role_config_screen(struct pine *ps, long int rflags, int edit_exceptions)
281 CONF_S *first_line;
282 OPT_SCREEN_S screen;
283 char title[100];
284 int readonly_warning = 0;
285 PAT_STATE pstate;
286 struct variable *v = NULL;
288 dprint((4, "role_config_screen()\n"));
290 if(ps->fix_fixed_warning)
291 offer_to_fix_pinerc(ps);
293 ew = edit_exceptions ? ps_global->ew_for_except_vars : Main;
295 if(ps->restricted)
296 readonly_warning = 1;
297 else{
298 PINERC_S *prc = NULL;
300 switch(ew){
301 case Main:
302 prc = ps->prc;
303 rflags |= PAT_USE_MAIN;
304 break;
305 case Post:
306 prc = ps->post_prc;
307 rflags |= PAT_USE_POST;
308 break;
309 default:
310 break;
313 readonly_warning = prc ? prc->readonly : 1;
314 if(prc && prc->quit_to_edit){
315 quit_to_edit_msg(prc);
316 return;
320 if(!any_patterns(rflags, &pstate))
321 return;
323 if(rflags & ROLE_DO_ROLES)
324 v = &ps_global->vars[V_PAT_ROLES];
325 else if(rflags & ROLE_DO_INCOLS)
326 v = &ps_global->vars[V_PAT_INCOLS];
327 else if(rflags & ROLE_DO_OTHER)
328 v = &ps_global->vars[V_PAT_OTHER];
329 else if(rflags & ROLE_DO_SCORES)
330 v = &ps_global->vars[V_PAT_SCORES];
331 else if(rflags & ROLE_DO_FILTER)
332 v = &ps_global->vars[V_PAT_FILTS];
333 else if(rflags & ROLE_DO_SRCH)
334 v = &ps_global->vars[V_PAT_SRCH];
336 if((ps_global->ew_for_except_vars != Main) && (ew == Main)){
337 char **lval;
339 if((lval=LVAL(v, ps_global->ew_for_except_vars)) &&
340 lval[0] && strcmp(INHERIT, lval[0]) != 0){
341 role_type_print(title, sizeof(title), _("Warning: \"%sRules\" are overridden in your exceptions configuration"), rflags);
342 q_status_message(SM_ORDER, 7, 7, title);
346 role_type_print(title, sizeof(title), "%sRules", rflags);
347 if(fixed_var(v, "change", title))
348 return;
350 uh_oh:
351 first_line = NULL;
353 snprintf(title, sizeof(title), "SETUP%s ", edit_exceptions ? " EXCEPTIONAL" : "");
354 title[sizeof(title)-1] = '\0';
355 role_type_print(title+strlen(title), sizeof(title)-strlen(title), "%sRULES", rflags);
356 role_global_flags = rflags;
357 role_global_pstate = &pstate;
358 role_config_init_disp(ps, &first_line, rflags, &pstate);
360 if(!first_line){
361 role_global_flags = 0;
362 ps->mangled_screen = 1;
363 q_status_message(SM_ORDER,5,5,
364 _("Unexpected problem: config file modified externally?"));
365 q_status_message1(SM_ORDER,5,5,
366 _("Perhaps a newer version of pine was used to set variable \"%s\"?"),
367 v ? v->name : "?");
368 dprint((1, "Unexpected problem: config file modified externally?\nPerhaps by a newer pine? Variable \"%s\" has unexpected contents.\n",
369 (v && v->name) ? v->name : "?"));
370 return;
373 memset(&screen, 0, sizeof(screen));
374 screen.deferred_ro_warning = readonly_warning;
375 /* TRANSLATORS: Print something1 using something2.
376 "rules" is something1 */
377 switch(conf_scroll_screen(ps, &screen, first_line, title, _("rules"), 0, NULL)){
378 case 0:
379 break;
381 case 10:
382 /* flush changes and re-read orig */
383 close_patterns(rflags);
384 break;
386 case 1:
387 if(write_patterns(rflags))
388 goto uh_oh;
391 * Flush out current_vals of anything we've possibly changed.
394 if(ps_global->default_role){
395 q_status_message(SM_ORDER,0,3, "Default role is unset");
396 ps_global->default_role = NULL;
399 close_patterns((rflags & ROLE_MASK) | PAT_USE_CURRENT);
401 /* scores may have changed */
402 if(rflags & ROLE_DO_SCORES){
403 int i;
404 MAILSTREAM *m;
406 for(i = 0; i < ps_global->s_pool.nstream; i++){
407 m = ps_global->s_pool.streams[i];
408 if(m){
409 clear_folder_scores(m);
410 clear_index_cache(m, 0);
414 if(mn_get_sort(sp_msgmap(ps_global->mail_stream)) == SortScore)
415 refresh_sort(ps_global->mail_stream,
416 sp_msgmap(ps_global->mail_stream), SRT_VRB);
419 /* recalculate need for scores */
420 scores_are_used(SCOREUSE_INVALID);
422 /* we may want to fetch more or fewer headers each fetch */
423 calc_extra_hdrs();
424 if(get_extra_hdrs())
425 (void) mail_parameters(NULL, SET_IMAPEXTRAHEADERS,
426 (void *) get_extra_hdrs());
428 if(rflags & ROLE_DO_INCOLS && pico_usingcolor())
429 clear_index_cache(ps_global->mail_stream, 0);
431 if(rflags & ROLE_DO_FILTER)
432 role_process_filters();
435 * ROLE_DO_OTHER is made up of a bunch of different variables
436 * that may have changed. Assume they all changed and fix them.
438 if(rflags & ROLE_DO_OTHER){
439 reset_index_format();
440 clear_index_cache(ps_global->mail_stream, 0);
441 if(!mn_get_mansort(ps_global->msgmap))
442 reset_sort_order(SRT_VRB);
445 break;
447 default:
448 q_status_message(SM_ORDER,7,10, "conf_scroll_screen unexpected ret");
449 break;
452 role_global_flags = 0;
453 ps->mangled_screen = 1;
458 * This is called from process_cmd to add a new pattern to the end of the
459 * list of patterns. The pattern is seeded with values from the current
460 * message.
462 void
463 role_take(struct pine *ps, MSGNO_S *msgmap, int rtype)
465 PAT_S *defpat, *newpat = NULL;
466 PAT_LINE_S *new_patline, *patline;
467 ENVELOPE *env = NULL;
468 long rflags;
469 char *s, title[100], specific_fldr[MAXPATH+1];
470 PAT_STATE pstate;
471 EditWhich ew;
473 dprint((4, "role_take()\n"));
475 if(mn_get_cur(msgmap) > 0){
476 env = pine_mail_fetchstructure(ps->mail_stream,
477 mn_m2raw(msgmap, mn_get_cur(msgmap)),
478 NULL);
480 if(!env){
481 q_status_message(SM_ORDER, 3, 7,
482 _("problem getting addresses from message"));
483 return;
487 switch(rtype){
488 case 'r':
489 rflags = ROLE_DO_ROLES;
490 ew = ps_global->ew_for_role_take;
491 break;
492 case 's':
493 rflags = ROLE_DO_SCORES;
494 ew = ps_global->ew_for_score_take;
495 break;
496 case 'i':
497 rflags = ROLE_DO_INCOLS;
498 ew = ps_global->ew_for_incol_take;
499 break;
500 case 'f':
501 rflags = ROLE_DO_FILTER;
502 ew = ps_global->ew_for_filter_take;
503 break;
504 case 'o':
505 rflags = ROLE_DO_OTHER;
506 ew = ps_global->ew_for_other_take;
507 break;
508 case 'c':
509 rflags = ROLE_DO_SRCH;
510 ew = ps_global->ew_for_srch_take;
511 break;
513 default:
514 cmd_cancelled(NULL);
515 return;
518 switch(ew){
519 case Main:
520 rflags |= PAT_USE_MAIN;
521 break;
522 case Post:
523 rflags |= PAT_USE_POST;
524 break;
525 default:
526 break;
529 if(!any_patterns(rflags, &pstate)){
530 q_status_message(SM_ORDER, 3, 7, _("problem accessing rules"));
531 return;
534 /* set this so that even if we don't edit at all, we'll be asked */
535 rflags |= ROLE_CHANGES;
538 * Make a pattern out of the information in the envelope and
539 * use that as the default pattern we give to the role editor.
540 * It will have a pattern but no actions set.
542 defpat = (PAT_S *)fs_get(sizeof(*defpat));
543 memset((void *)defpat, 0, sizeof(*defpat));
545 defpat->patgrp = (PATGRP_S *)fs_get(sizeof(*defpat->patgrp));
546 memset((void *)defpat->patgrp, 0, sizeof(*defpat->patgrp));
548 if(env){
549 if(env->to)
550 defpat->patgrp->to = addrlst_to_pattern(env->to);
552 if(env->from)
553 defpat->patgrp->from = addrlst_to_pattern(env->from);
555 if(env->cc)
556 defpat->patgrp->cc = addrlst_to_pattern(env->cc);
558 if(env->sender &&
559 (!env->from || !address_is_same(env->sender, env->from)))
560 defpat->patgrp->sender = addrlst_to_pattern(env->sender);
563 * Env->newsgroups is already comma-separated and there shouldn't be
564 * any commas or backslashes in newsgroup names, so we don't add the
565 * roletake escapes.
567 if(env->newsgroups)
568 defpat->patgrp->news = string_to_pattern(env->newsgroups);
571 * Subject may have commas or backslashes, so we add escapes.
573 if(env->subject){
574 char *q, *t = NULL;
577 * Mail_strip_subject not only strips the Re's and Fwd's but
578 * it also canonicalizes to UTF-8.
580 mail_strip_subject(env->subject, &q);
581 if(q != NULL){
582 t = add_roletake_escapes(q);
583 fs_give((void **)&q);
586 if(t){
587 defpat->patgrp->subj = string_to_pattern(t);
588 fs_give((void **)&t);
593 if(IS_NEWS(ps->mail_stream))
594 defpat->patgrp->fldr_type = FLDR_NEWS;
595 else
596 defpat->patgrp->fldr_type = FLDR_EMAIL;
598 specific_fldr[0] = specific_fldr[sizeof(specific_fldr)-1] = '\0';
599 if(sp_flagged(ps->mail_stream, SP_INBOX))
600 strncpy(specific_fldr, ps_global->inbox_name, sizeof(specific_fldr)-1);
601 else if(ps->context_current
602 && ps->context_current->use & CNTXT_INCMNG &&
603 folder_is_nick(ps->cur_folder, FOLDERS(ps->context_current), 0))
604 strncpy(specific_fldr, ps->cur_folder, sizeof(specific_fldr)-1);
605 else
606 context_apply(specific_fldr, ps->context_current, ps->cur_folder,
607 sizeof(specific_fldr));
609 if(specific_fldr[0]){
610 s = add_comma_escapes(specific_fldr);
611 if(s){
612 if(rtype == 'f')
613 defpat->patgrp->fldr_type = FLDR_SPECIFIC;
615 defpat->patgrp->folder = string_to_pattern(s);
616 fs_give((void **)&s);
620 role_type_print(title, sizeof(title), "ADD NEW %sRULE", rflags);
623 * Role_config_edit_screen is sometimes called as a tool or a sub
624 * routine called from a tool within conf_scroll_screen, but here it
625 * is going to be at the top-level (we're not inside conf_scroll_screen
626 * right now). It uses opt_screen to set the ro_warning bit. We need
627 * to let it know that we're at the top, which we do by setting
628 * opt_screen to NULL. Otherwise, the thing that opt_screen is pointing
629 * to is just random stack stuff from some previous conf_scroll_screen
630 * call which has already exited.
632 opt_screen = NULL;
634 if(role_config_edit_screen(ps, defpat, title, rflags,
635 &newpat) == 1 && newpat){
637 if(ps->never_allow_changing_from && newpat->action &&
638 newpat->action->from)
639 q_status_message(SM_ORDER|SM_DING, 3, 7,
640 _("Site policy doesn't allow changing From address so From is ignored"));
642 if(rflags & ROLE_DO_ROLES && newpat->patgrp && newpat->patgrp->nick){
643 PAT_S *pat;
645 for(pat = first_pattern(&pstate);
646 pat;
647 pat = next_pattern(&pstate)){
648 if(pat->patgrp && pat->patgrp->nick &&
649 !strucmp(pat->patgrp->nick, newpat->patgrp->nick)){
650 q_status_message(SM_ORDER|SM_DING, 3, 7, _("Warning: The nickname of the new role is already in use."));
651 break;
657 set_pathandle(rflags);
659 /* need a new patline */
660 new_patline = (PAT_LINE_S *)fs_get(sizeof(*new_patline));
661 memset((void *)new_patline, 0, sizeof(*new_patline));
662 new_patline->type = Literal;
663 (*cur_pat_h)->dirtypinerc = 1;
665 /* tie together with new pattern */
666 new_patline->first = new_patline->last = newpat;
667 newpat->patline = new_patline;
669 /* find last current patline */
670 for(patline = (*cur_pat_h)->patlinehead;
671 patline && patline->next;
672 patline = patline->next)
675 /* add new patline to end of list */
676 if(patline){
677 patline->next = new_patline;
678 new_patline->prev = patline;
680 else
681 (*cur_pat_h)->patlinehead = new_patline;
683 if(write_patterns(rflags) == 0){
684 char msg[60];
687 * Flush out current_vals of anything we've possibly changed.
690 if(rflags & ROLE_DO_ROLES && ps_global->default_role){
691 q_status_message(SM_ORDER,0,3, "Default role is unset");
692 ps_global->default_role = NULL;
695 close_patterns(rflags | PAT_USE_CURRENT);
697 role_type_print(msg, sizeof(msg), "New %srule saved", rflags);
698 q_status_message(SM_ORDER, 0, 3, msg);
700 /* scores may have changed */
701 if(rflags & ROLE_DO_SCORES){
702 int i;
703 MAILSTREAM *m;
705 for(i = 0; i < ps_global->s_pool.nstream; i++){
706 m = ps_global->s_pool.streams[i];
707 if(m){
708 clear_folder_scores(m);
709 clear_index_cache(m, 0);
713 /* We've already bound msgmap to global mail_stream
714 * at the start of this function, but if we wanted to
715 * we could clean this up.
717 if(mn_get_sort(msgmap) == SortScore)
718 refresh_sort(ps_global->mail_stream, msgmap, SRT_VRB);
721 if(rflags & ROLE_DO_FILTER)
722 role_process_filters();
724 /* recalculate need for scores */
725 scores_are_used(SCOREUSE_INVALID);
727 /* we may want to fetch more or fewer headers each fetch */
728 calc_extra_hdrs();
729 if(get_extra_hdrs())
730 (void) mail_parameters(NULL, SET_IMAPEXTRAHEADERS,
731 (void *) get_extra_hdrs());
733 if(rflags & ROLE_DO_INCOLS && pico_usingcolor())
734 clear_index_cache(ps_global->mail_stream, 0);
737 * ROLE_DO_OTHER is made up of a bunch of different variables
738 * that may have changed. Assume they all changed and fix them.
740 if(rflags & ROLE_DO_OTHER){
741 reset_index_format();
742 clear_index_cache(ps_global->mail_stream, 0);
743 if(!mn_get_mansort(msgmap))
744 reset_sort_order(SRT_VRB);
748 else
749 cmd_cancelled(NULL);
751 free_pat(&defpat);
752 ps->mangled_screen = 1;
756 PATTERN_S *
757 addrlst_to_pattern(struct mail_address *addr)
759 char *s, *t, *u, *v;
760 PATTERN_S *p = NULL;
761 size_t l;
763 if(addr){
764 l = est_size(addr);
765 t = s = (char *) fs_get((l+1) * sizeof(char));
766 s[0] = '\0';
767 while(addr){
768 u = simple_addr_string(addr, tmp_20k_buf, SIZEOF_20KBUF);
769 v = add_roletake_escapes(u);
770 if(v){
771 if(*v && t != s)
772 sstrncpy(&t, ",", l-(t-s));
774 sstrncpy(&t, v, l-(t-s));
775 fs_give((void **)&v);
778 addr = addr->next;
781 s[l] = '\0';
783 if(*s)
784 p = string_to_pattern(s);
786 fs_give((void **) &s);
789 return(p);
793 void
794 role_config_init_disp(struct pine *ps, CONF_S **first_line, long int rflags, PAT_STATE *pstate)
796 PAT_LINE_S *patline;
797 CONF_S *ctmp = NULL;
798 int inherit = 0, added_fake = 0;
800 if(first_line)
801 *first_line = NULL;
804 * Set cur_pat_h and manipulate directly.
806 set_pathandle(rflags);
807 patline = *cur_pat_h ? (*cur_pat_h)->patlinehead : NULL;
808 if(patline && patline->type == Inherit){
809 add_patline_to_display(ps, &ctmp, 0, first_line, NULL, patline, rflags);
810 patline = patline->next;
813 if(!patline){
814 add_fake_first_role(&ctmp, 0, rflags);
815 added_fake++;
816 if(first_line && !*first_line)
817 (*first_line) = ctmp;
820 for(; patline; patline = patline->next)
821 add_patline_to_display(ps, &ctmp, 0, first_line, NULL, patline, rflags);
824 * If there are no actual patterns so far, we need to have an Add line
825 * for the cursor to be on. This would happen if all of the patlines
826 * were File includes and none of the files contained patterns.
828 if(!first_pattern(role_global_pstate) ||
829 ((inherit=first_pattern(role_global_pstate)->inherit) &&
830 !next_pattern(role_global_pstate))){
833 * Find the start and prepend the fake first role.
835 while(ctmp && ctmp->prev)
836 ctmp = ctmp->prev;
838 if(!added_fake){
839 add_fake_first_role(&ctmp, inherit ? 0 : 1, rflags);
840 if(first_line && !*first_line)
841 (*first_line) = ctmp;
847 void
848 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)
850 PAT_S *pat;
851 int len, firstitem, wid;
852 char *q;
853 char buf[6*MAX_SCREEN_COLS+1];
855 /* put dashed line around file contents */
856 if(patline->type == File){
858 new_confline(ctmp);
859 if(before){
861 * New_confline appends ctmp after old current instead of inserting
862 * it, so we have to adjust. We have
863 * <- a <-> b <-> p <-> c -> and want <- a <-> p <-> b <-> c ->
866 CONF_S *a, *b, *c, *p;
868 p = *ctmp;
869 b = (*ctmp)->prev;
870 c = (*ctmp)->next;
871 a = b ? b->prev : NULL;
872 if(a)
873 a->next = p;
875 if(b){
876 b->prev = p;
877 b->next = c;
880 if(c)
881 c->prev = b;
883 p->prev = a;
884 p->next = b;
887 if(top_line && *top_line == NULL)
888 *top_line = (*ctmp);
890 len = strlen(patline->filename) + 100;
892 q = (char *) fs_get((len + 1) * sizeof(char));
893 snprintf(q, len+1, "From file %s%s", patline->filename,
894 patline->readonly ? " (ReadOnly)" : "");
895 q[len-1] = '\0';
897 if((wid=utf8_width(q)) > ps->ttyo->screen_cols -2)
898 utf8_snprintf(buf, sizeof(buf), "--%.*w", ps->ttyo->screen_cols -2, q);
899 else
900 snprintf(buf, sizeof(buf), "--%s%s", q, repeat_char(ps->ttyo->screen_cols -2-wid, '-'));
902 (*ctmp)->value = cpystr(buf);
904 fs_give((void **)&q);
905 (*ctmp)->flags |= (CF_NOSELECT | CF_STARTITEM);
906 (*ctmp)->d.r.patline = patline;
907 firstitem = 0;
909 else
910 firstitem = 1;
912 for(pat = patline->first; pat; pat = pat->next){
914 /* Check that pattern has a role and is of right type */
915 if(pat->inherit ||
916 (pat->action &&
917 (((rflags & ROLE_DO_ROLES) && pat->action->is_a_role) ||
918 ((rflags & ROLE_DO_INCOLS) && pat->action->is_a_incol) ||
919 ((rflags & ROLE_DO_SRCH) && pat->action->is_a_srch) ||
920 ((rflags & ROLE_DO_OTHER) && pat->action->is_a_other) ||
921 ((rflags & ROLE_DO_SCORES) && pat->action->is_a_score) ||
922 ((rflags & ROLE_DO_FILTER) && pat->action->is_a_filter)))){
923 add_role_to_display(ctmp, patline, pat, 0,
924 (first_line && *first_line == NULL)
925 ? first_line :
926 (top_line && *top_line == NULL)
927 ? top_line : NULL,
928 firstitem, rflags);
929 firstitem = 1;
930 if(top_line && *top_line == NULL && first_line)
931 *top_line = *first_line;
936 if(patline->type == File){
937 new_confline(ctmp);
938 len = strlen(patline->filename) + 100;
940 q = (char *) fs_get((len + 1) * sizeof(char));
941 snprintf(q, len+1, "End of Rules from %s", patline->filename);
942 q[len-1] = '\0';
944 if((wid=utf8_width(q)) > ps->ttyo->screen_cols -2)
945 utf8_snprintf(buf, sizeof(buf), "--%.*w", ps->ttyo->screen_cols -2, q);
946 else
947 snprintf(buf, sizeof(buf), "--%s%s", q, repeat_char(ps->ttyo->screen_cols -2-wid, '-'));
949 (*ctmp)->value = cpystr(buf);
951 fs_give((void **)&q);
952 (*ctmp)->flags |= CF_NOSELECT;
953 (*ctmp)->d.r.patline = patline;
958 void
959 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)
961 char title[80];
963 if(!(pat && (pat->action || pat->inherit)))
964 return;
966 new_confline(ctmp);
967 if(first_line && !pat->inherit)
968 *first_line = *ctmp;
970 if(before){
972 * New_confline appends ctmp after old current instead of inserting
973 * it, so we have to adjust. We have
974 * <- a <-> b <-> p <-> c -> and want <- a <-> p <-> b <-> c ->
977 CONF_S *a, *b, *c, *p;
979 p = *ctmp;
980 b = (*ctmp)->prev;
981 c = (*ctmp)->next;
982 a = b ? b->prev : NULL;
983 if(a)
984 a->next = p;
986 if(b){
987 b->prev = p;
988 b->next = c;
991 if(c)
992 c->prev = b;
994 p->prev = a;
995 p->next = b;
998 role_type_print(title, sizeof(title), _("HELP FOR %sRULE CONFIGURATION"), rflags);
1000 if(pat->inherit){
1001 (*ctmp)->flags |= ((firstitem ? CF_STARTITEM : 0) |
1002 CF_NOSELECT | CF_INHERIT);
1004 else{
1005 (*ctmp)->flags |= (firstitem ? CF_STARTITEM : 0);
1006 (*ctmp)->value = cpystr((pat && pat->patgrp && pat->patgrp->nick)
1007 ? pat->patgrp->nick : "?");
1010 (*ctmp)->d.r.patline = patline;
1011 (*ctmp)->d.r.pat = pat;
1012 (*ctmp)->keymenu = &role_conf_km;
1013 (*ctmp)->help = (rflags & ROLE_DO_INCOLS) ? h_rules_incols :
1014 (rflags & ROLE_DO_OTHER) ? h_rules_other :
1015 (rflags & ROLE_DO_FILTER) ? h_rules_filter :
1016 (rflags & ROLE_DO_SCORES) ? h_rules_score :
1017 (rflags & ROLE_DO_ROLES) ? h_rules_roles :
1018 (rflags & ROLE_DO_SRCH) ? h_rules_srch :
1019 NO_HELP;
1020 (*ctmp)->help_title = title;
1021 (*ctmp)->tool = role_config_tool;
1022 (*ctmp)->valoffset = 4;
1026 void
1027 add_fake_first_role(CONF_S **ctmp, int before, long int rflags)
1029 char title[80];
1030 char add[80];
1032 new_confline(ctmp);
1034 if(before){
1036 * New_confline appends ctmp after old current instead of inserting
1037 * it, so we have to adjust. We have
1038 * <- a <-> b <-> p <-> c -> and want <- a <-> p <-> b <-> c ->
1041 CONF_S *a, *b, *c, *p;
1043 p = *ctmp;
1044 b = (*ctmp)->prev;
1045 c = (*ctmp)->next;
1046 a = b ? b->prev : NULL;
1047 if(a)
1048 a->next = p;
1050 if(b){
1051 b->prev = p;
1052 b->next = c;
1055 if(c)
1056 c->prev = b;
1058 p->prev = a;
1059 p->next = b;
1062 role_type_print(title, sizeof(title), _("HELP FOR %sRULE CONFIGURATION"), rflags);
1063 role_type_print(add, sizeof(add), _("Use Add to add a %sRule"), rflags);
1065 (*ctmp)->value = cpystr(add);
1066 (*ctmp)->keymenu = &role_conf_km;
1067 (*ctmp)->help = (rflags & ROLE_DO_INCOLS) ? h_rules_incols :
1068 (rflags & ROLE_DO_OTHER) ? h_rules_other :
1069 (rflags & ROLE_DO_FILTER) ? h_rules_filter :
1070 (rflags & ROLE_DO_SCORES) ? h_rules_score :
1071 (rflags & ROLE_DO_ROLES) ? h_rules_roles :
1072 (rflags & ROLE_DO_SRCH) ? h_rules_srch :
1073 NO_HELP;
1074 (*ctmp)->help_title = title;
1075 (*ctmp)->tool = role_config_tool;
1076 (*ctmp)->flags |= CF_STARTITEM;
1077 (*ctmp)->valoffset = 4;
1082 role_config_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
1084 int first_one = 0, rv = 0;
1085 char exitpmt[80];
1086 PAT_S *pat;
1088 if(!(pat = first_pattern(role_global_pstate)) ||
1089 (pat->inherit && !next_pattern(role_global_pstate)))
1090 first_one++;
1092 switch(cmd){
1093 case MC_DELETE :
1094 if(first_one)
1095 q_status_message(SM_ORDER|SM_DING, 0, 3,
1096 _("Nothing to Delete, use Add"));
1097 else
1098 rv = role_config_del(ps, cl, role_global_flags);
1100 break;
1102 case MC_ADD :
1103 rv = role_config_add(ps, cl, role_global_flags);
1104 break;
1106 case MC_EDIT :
1107 if(first_one)
1108 rv = role_config_add(ps, cl, role_global_flags);
1109 else
1110 rv = role_config_edit(ps, cl, role_global_flags);
1112 break;
1114 case MC_SHUFFLE :
1115 if(first_one)
1116 q_status_message(SM_ORDER|SM_DING, 0, 3,
1117 _("Nothing to Shuffle, use Add"));
1118 else
1119 rv = role_config_shuffle(ps, cl);
1121 break;
1123 case MC_EXIT :
1124 role_type_print(exitpmt, sizeof(exitpmt), "%sRule Setup", role_global_flags);
1125 rv = screen_exit_cmd(flags, exitpmt);
1126 break;
1128 case MC_ADDFILE :
1129 rv = role_config_addfile(ps, cl, role_global_flags);
1130 break;
1132 case MC_DELFILE :
1133 rv = role_config_delfile(ps, cl, role_global_flags);
1134 break;
1136 case MC_COPY :
1137 if(first_one)
1138 q_status_message(SM_ORDER|SM_DING, 0, 3,
1139 _("Nothing to Replicate, use Add"));
1140 else
1141 rv = role_config_replicate(ps, cl, role_global_flags);
1143 break;
1145 default:
1146 rv = -1;
1147 break;
1150 return(rv);
1155 * Add a new role.
1157 * Returns 1 -- There were changes
1158 * 0 -- No changes
1161 role_config_add(struct pine *ps, CONF_S **cl, long int rflags)
1163 int rv = 0, first_pat = 0;
1164 PAT_S *new_pat = NULL, *cur_pat;
1165 PAT_LINE_S *new_patline, *cur_patline;
1166 PAT_STATE pstate;
1167 char title[80];
1169 if((*cl)->d.r.patline &&
1170 (*cl)->d.r.patline->readonly
1171 && (*cl)->d.r.patline->type == File){
1172 q_status_message(SM_ORDER, 0, 3, _("Can't add rule to ReadOnly file"));
1173 return(rv);
1176 role_type_print(title, sizeof(title), "ADD A %sRULE", rflags);
1178 if(role_config_edit_screen(ps, NULL, title, rflags,
1179 &new_pat) == 1 && new_pat){
1180 if(ps->never_allow_changing_from &&
1181 new_pat->action &&
1182 new_pat->action->from)
1183 q_status_message(SM_ORDER|SM_DING, 0, 3,
1184 _("Site policy doesn't allow changing From address so From is ignored"));
1186 if(rflags & ROLE_DO_ROLES &&
1187 new_pat->patgrp &&
1188 new_pat->patgrp->nick &&
1189 nonempty_patterns(ROLE_DO_ROLES, &pstate)){
1190 PAT_S *pat;
1192 for(pat = first_pattern(&pstate);
1193 pat;
1194 pat = next_pattern(&pstate)){
1195 if(pat->patgrp && pat->patgrp->nick &&
1196 !strucmp(pat->patgrp->nick, new_pat->patgrp->nick)){
1197 q_status_message(SM_ORDER|SM_DING, 3, 7, _("Warning: The nickname of the new role is already in use."));
1198 break;
1203 rv = 1;
1204 cur_pat = (*cl)->d.r.pat;
1205 if(!cur_pat)
1206 first_pat++;
1208 set_pathandle(rflags);
1209 cur_patline = first_pat ? (*cur_pat_h)->patlinehead : cur_pat->patline;
1211 /* need a new pat_line */
1212 if(first_pat || (cur_patline && cur_patline->type == Literal)){
1213 new_patline = (PAT_LINE_S *)fs_get(sizeof(*new_patline));
1214 memset((void *)new_patline, 0, sizeof(*new_patline));
1215 new_patline->type = Literal;
1216 (*cur_pat_h)->dirtypinerc = 1;
1219 if(cur_patline){
1220 if(first_pat || cur_patline->type == Literal){
1221 new_patline->prev = cur_patline;
1222 new_patline->next = cur_patline->next;
1223 if(cur_patline->next)
1224 cur_patline->next->prev = new_patline;
1226 cur_patline->next = new_patline;
1228 /* tie new patline and new pat together */
1229 new_pat->patline = new_patline;
1230 new_patline->first = new_patline->last = new_pat;
1232 else if(cur_patline->type == File){ /* don't need a new pat_line */
1233 /* tie together */
1234 new_pat->patline = cur_patline;
1235 cur_patline->dirty = 1;
1237 /* Splice new_pat after cur_pat */
1238 new_pat->prev = cur_pat;
1239 new_pat->next = cur_pat->next;
1240 if(cur_pat->next)
1241 cur_pat->next->prev = new_pat;
1242 else
1243 cur_patline->last = new_pat;
1245 cur_pat->next = new_pat;
1248 else{
1249 /* tie new first patline and pat together */
1250 new_pat->patline = new_patline;
1251 new_patline->first = new_patline->last = new_pat;
1253 /* set head of list */
1254 (*cur_pat_h)->patlinehead = new_patline;
1258 * If this is the first role, we replace the "Use Add" fake role
1259 * with this real one.
1261 if(first_pat){
1262 /* Adjust conf_scroll_screen variables */
1263 (*cl)->d.r.pat = new_pat;
1264 (*cl)->d.r.patline = new_pat->patline;
1265 if((*cl)->value)
1266 fs_give((void **)&(*cl)->value);
1268 (*cl)->value = cpystr((new_pat && new_pat->patgrp &&
1269 new_pat->patgrp->nick)
1270 ? new_pat->patgrp->nick : "?");
1272 /* Else we are inserting a new role after the cur role */
1273 else
1274 add_role_to_display(cl, new_pat->patline, new_pat, 0, NULL,
1275 1, rflags);
1278 return(rv);
1283 * Replicate a role.
1285 * Returns 1 -- There were changes
1286 * 0 -- No changes
1289 role_config_replicate(struct pine *ps, CONF_S **cl, long int rflags)
1291 int rv = 0, first_pat = 0;
1292 PAT_S *new_pat = NULL, *cur_pat, *defpat = NULL;
1293 PAT_LINE_S *new_patline, *cur_patline;
1294 PAT_STATE pstate;
1295 char title[80];
1297 if((*cl)->d.r.patline &&
1298 (*cl)->d.r.patline->readonly
1299 && (*cl)->d.r.patline->type == File){
1300 q_status_message(SM_ORDER, 0, 3, _("Can't add rule to ReadOnly file"));
1301 return(rv);
1304 if((*cl)->d.r.pat && (defpat = copy_pat((*cl)->d.r.pat))){
1305 /* change nickname */
1306 if(defpat->patgrp && defpat->patgrp->nick){
1307 #define CLONEWORD " Copy"
1308 char *oldnick = defpat->patgrp->nick;
1309 size_t len;
1311 len = strlen(oldnick)+strlen(CLONEWORD);
1312 defpat->patgrp->nick = (char *)fs_get((len+1) * sizeof(char));
1313 strncpy(defpat->patgrp->nick, oldnick, len);
1314 defpat->patgrp->nick[len] = '\0';
1315 strncat(defpat->patgrp->nick, CLONEWORD,
1316 len+1-1-strlen(defpat->patgrp->nick));
1317 fs_give((void **)&oldnick);
1318 if(defpat->action){
1319 if(defpat->action->nick)
1320 fs_give((void **)&defpat->action->nick);
1322 defpat->action->nick = cpystr(defpat->patgrp->nick);
1326 /* set this so that even if we don't edit at all, we'll be asked */
1327 rflags |= ROLE_CHANGES;
1329 role_type_print(title, sizeof(title), "CHANGE THIS %sRULE", rflags);
1331 if(role_config_edit_screen(ps, defpat, title, rflags,
1332 &new_pat) == 1 && new_pat){
1334 if(ps->never_allow_changing_from &&
1335 new_pat->action &&
1336 new_pat->action->from)
1337 q_status_message(SM_ORDER|SM_DING, 0, 3,
1338 _("Site policy doesn't allow changing From address so From is ignored"));
1340 if(rflags & ROLE_DO_ROLES &&
1341 new_pat->patgrp &&
1342 new_pat->patgrp->nick &&
1343 nonempty_patterns(ROLE_DO_ROLES, &pstate)){
1344 PAT_S *pat;
1346 for(pat = first_pattern(&pstate);
1347 pat;
1348 pat = next_pattern(&pstate)){
1349 if(pat->patgrp && pat->patgrp->nick &&
1350 !strucmp(pat->patgrp->nick, new_pat->patgrp->nick)){
1351 q_status_message(SM_ORDER|SM_DING, 3, 7, _("Warning: The nickname of the new role is already in use."));
1352 break;
1357 rv = 1;
1358 cur_pat = (*cl)->d.r.pat;
1359 if(!cur_pat)
1360 first_pat++;
1362 set_pathandle(rflags);
1363 cur_patline = first_pat ? (*cur_pat_h)->patlinehead : cur_pat->patline;
1365 /* need a new pat_line */
1366 if(first_pat || (cur_patline && cur_patline->type == Literal)){
1367 new_patline = (PAT_LINE_S *)fs_get(sizeof(*new_patline));
1368 memset((void *)new_patline, 0, sizeof(*new_patline));
1369 new_patline->type = Literal;
1370 (*cur_pat_h)->dirtypinerc = 1;
1373 if(cur_patline){
1374 if(first_pat || cur_patline->type == Literal){
1375 new_patline->prev = cur_patline;
1376 new_patline->next = cur_patline->next;
1377 if(cur_patline->next)
1378 cur_patline->next->prev = new_patline;
1380 cur_patline->next = new_patline;
1382 /* tie new patline and new pat together */
1383 new_pat->patline = new_patline;
1384 new_patline->first = new_patline->last = new_pat;
1386 else if(cur_patline->type == File){ /* don't need a new pat_line */
1387 /* tie together */
1388 new_pat->patline = cur_patline;
1389 cur_patline->dirty = 1;
1391 /* Splice new_pat after cur_pat */
1392 new_pat->prev = cur_pat;
1393 new_pat->next = cur_pat->next;
1394 if(cur_pat->next)
1395 cur_pat->next->prev = new_pat;
1396 else
1397 cur_patline->last = new_pat;
1399 cur_pat->next = new_pat;
1402 else{
1403 /* tie new first patline and pat together */
1404 new_pat->patline = new_patline;
1405 new_patline->first = new_patline->last = new_pat;
1407 /* set head of list */
1408 (*cur_pat_h)->patlinehead = new_patline;
1412 * If this is the first role, we replace the "Use Add" fake role
1413 * with this real one.
1415 if(first_pat){
1416 /* Adjust conf_scroll_screen variables */
1417 (*cl)->d.r.pat = new_pat;
1418 (*cl)->d.r.patline = new_pat->patline;
1419 if((*cl)->value)
1420 fs_give((void **)&(*cl)->value);
1422 (*cl)->value = cpystr((new_pat && new_pat->patgrp &&
1423 new_pat->patgrp->nick)
1424 ? new_pat->patgrp->nick : "?");
1426 /* Else we are inserting a new role after the cur role */
1427 else
1428 add_role_to_display(cl, new_pat->patline, new_pat, 0, NULL,
1429 1, rflags);
1433 if(defpat)
1434 free_pat(&defpat);
1436 return(rv);
1441 * Change the current role.
1443 * Returns 1 -- There were changes
1444 * 0 -- No changes
1447 role_config_edit(struct pine *ps, CONF_S **cl, long int rflags)
1449 int rv = 0;
1450 PAT_S *new_pat = NULL, *cur_pat;
1451 char title[80];
1453 if((*cl)->d.r.patline->readonly){
1454 q_status_message(SM_ORDER, 0, 3, _("Can't change ReadOnly rule"));
1455 return(rv);
1458 cur_pat = (*cl)->d.r.pat;
1460 role_type_print(title, sizeof(title), "CHANGE THIS %sRULE", rflags);
1462 if(role_config_edit_screen(ps, cur_pat, title,
1463 rflags, &new_pat) == 1 && new_pat){
1465 if(ps->never_allow_changing_from &&
1466 new_pat->action &&
1467 new_pat->action->from)
1468 q_status_message(SM_ORDER|SM_DING, 0, 3,
1469 _("Site policy doesn't allow changing From address so From is ignored"));
1471 if(rflags & ROLE_DO_ROLES && new_pat->patgrp && new_pat->patgrp->nick){
1472 PAT_S *pat;
1474 for(pat = first_pattern(role_global_pstate);
1475 pat;
1476 pat = next_pattern(role_global_pstate)){
1477 if(pat->patgrp && pat->patgrp->nick && pat != cur_pat &&
1478 !strucmp(pat->patgrp->nick, new_pat->patgrp->nick)){
1479 q_status_message(SM_ORDER|SM_DING, 3, 7, _("Warning: The nickname of this role is also used for another role."));
1480 break;
1485 rv = 1;
1488 * Splice in new_pat in place of cur_pat
1491 if(cur_pat->prev)
1492 cur_pat->prev->next = new_pat;
1494 if(cur_pat->next)
1495 cur_pat->next->prev = new_pat;
1497 new_pat->prev = cur_pat->prev;
1498 new_pat->next = cur_pat->next;
1500 /* tie together patline and pat (new_pat gets patline in editor) */
1501 if(new_pat->patline->first == cur_pat)
1502 new_pat->patline->first = new_pat;
1504 if(new_pat->patline->last == cur_pat)
1505 new_pat->patline->last = new_pat;
1507 if(new_pat->patline->type == Literal){
1508 set_pathandle(rflags);
1509 if(*cur_pat_h)
1510 (*cur_pat_h)->dirtypinerc = 1;
1512 else
1513 new_pat->patline->dirty = 1;
1515 cur_pat->next = NULL;
1516 free_pat(&cur_pat);
1518 /* Adjust conf_scroll_screen variables */
1519 (*cl)->d.r.pat = new_pat;
1520 (*cl)->d.r.patline = new_pat->patline;
1521 if((*cl)->value)
1522 fs_give((void **)&(*cl)->value);
1524 (*cl)->value = cpystr((new_pat->patgrp && new_pat->patgrp->nick)
1525 ? new_pat->patgrp->nick : "?");
1528 return(rv);
1533 * Delete a role.
1535 * Returns 1 -- There were changes
1536 * 0 -- No changes
1539 role_config_del(struct pine *ps, CONF_S **cl, long int rflags)
1541 int rv = 0;
1542 char msg[80];
1543 char prompt[100];
1545 if((*cl)->d.r.patline->readonly){
1546 q_status_message(SM_ORDER, 0, 3, _("Can't delete ReadOnly rule"));
1547 return(rv);
1550 role_type_print(msg, sizeof(msg), _("Really delete %srule"), rflags);
1551 snprintf(prompt, sizeof(prompt), "%s \"%s\" ", msg, (*cl)->value);
1552 prompt[sizeof(prompt)-1] = '\0';
1554 ps->mangled_footer = 1;
1555 if(want_to(prompt,'n','n',h_config_role_del, WT_FLUSH_IN) == 'y'){
1556 rv = ps->mangled_body = 1;
1557 delete_a_role(cl, rflags);
1559 else
1560 q_status_message(SM_ORDER, 0, 3, _("Rule not deleted"));
1562 return(rv);
1566 void
1567 delete_a_role(CONF_S **cl, long int rflags)
1569 PAT_S *cur_pat;
1570 CONF_S *cp, *cq;
1571 PAT_LINE_S *cur_patline;
1572 int inherit = 0;
1574 cur_pat = (*cl)->d.r.pat;
1575 cur_patline = (*cl)->d.r.patline;
1577 if(cur_patline->type == Literal){ /* delete patline */
1578 set_pathandle(rflags);
1579 if(cur_patline->prev)
1580 cur_patline->prev->next = cur_patline->next;
1581 else{
1582 if(*cur_pat_h) /* this has to be true */
1583 (*cur_pat_h)->patlinehead = cur_patline->next;
1586 if(cur_patline->next)
1587 cur_patline->next->prev = cur_patline->prev;
1589 if(*cur_pat_h) /* this has to be true */
1590 (*cur_pat_h)->dirtypinerc = 1;
1592 cur_patline->next = NULL;
1593 free_patline(&cur_patline);
1595 else if(cur_patline->type == File){ /* or delete pat */
1596 if(cur_pat->prev)
1597 cur_pat->prev->next = cur_pat->next;
1598 else
1599 cur_patline->first = cur_pat->next;
1601 if(cur_pat->next)
1602 cur_pat->next->prev = cur_pat->prev;
1603 else
1604 cur_patline->last = cur_pat->prev;
1606 cur_patline->dirty = 1;
1608 cur_pat->next = NULL;
1609 free_pat(&cur_pat);
1612 /* delete the conf line */
1614 /* deleting last real rule */
1615 if(!first_pattern(role_global_pstate) ||
1616 ((inherit=first_pattern(role_global_pstate)->inherit) &&
1617 !next_pattern(role_global_pstate))){
1619 cq = *cl;
1622 * Find the start and prepend the fake first role.
1624 while(*cl && (*cl)->prev)
1625 *cl = (*cl)->prev;
1627 add_fake_first_role(cl, inherit ? 0 : 1, rflags);
1628 snip_confline(&cq);
1629 opt_screen->top_line = (*cl);
1630 opt_screen->current = (*cl);
1632 else{
1633 /* find next selectable line */
1634 for(cp = (*cl)->next;
1635 cp && (cp->flags & CF_NOSELECT);
1636 cp = cp->next)
1639 if(!cp){ /* no next selectable, find previous selectable */
1640 if(*cl == opt_screen->top_line)
1641 opt_screen->top_line = (*cl)->prev;
1643 for(cp = (*cl)->prev;
1644 cp && (cp->flags & CF_NOSELECT);
1645 cp = cp->prev)
1648 else if(*cl == opt_screen->top_line)
1649 opt_screen->top_line = (*cl)->next;
1651 cq = *cl;
1652 *cl = cp;
1653 snip_confline(&cq);
1659 * Shuffle the current role up or down.
1661 * Returns 1 -- There were changes
1662 * 0 -- No changes
1665 role_config_shuffle(struct pine *ps, CONF_S **cl)
1667 int rv = 0, deefault, i;
1668 int readonlyabove = 0, readonlybelow = 0;
1669 ESCKEY_S opts[5];
1670 HelpType help;
1671 char tmp[200];
1672 CONF_S *a, *b;
1673 PAT_TYPE curtype, prevtype, nexttype;
1675 if(!((*cl)->prev || (*cl)->next)){
1676 q_status_message(SM_ORDER, 0, 3,
1677 _("Shuffle only makes sense when there is more than one rule defined"));
1678 return(rv);
1681 /* Move it up or down? */
1682 i = 0;
1683 opts[i].ch = 'u';
1684 opts[i].rval = 'u';
1685 opts[i].name = "U";
1686 opts[i++].label = N_("Up");
1688 opts[i].ch = 'd';
1689 opts[i].rval = 'd';
1690 opts[i].name = "D";
1691 opts[i++].label = N_("Down");
1693 opts[i].ch = 'b';
1694 opts[i].rval = 'b';
1695 opts[i].name = "B";
1696 opts[i++].label = N_("Before File");
1698 opts[i].ch = 'a';
1699 opts[i].rval = 'a';
1700 opts[i].name = "A";
1701 opts[i++].label = N_("After File");
1703 opts[i].ch = -1;
1704 deefault = 'u';
1706 curtype = ((*cl)->d.r.patline) ? (*cl)->d.r.patline->type : TypeNotSet;
1708 prevtype = ((*cl)->prev && (*cl)->prev->d.r.patline)
1709 ? (*cl)->prev->d.r.patline->type : TypeNotSet;
1710 if(curtype == File && prevtype == File && (*cl)->prev->d.r.pat == NULL)
1711 prevtype = TypeNotSet;
1713 nexttype = ((*cl)->next && (*cl)->next->d.r.patline)
1714 ? (*cl)->next->d.r.patline->type : TypeNotSet;
1715 if(curtype == File && nexttype == File && (*cl)->next->d.r.pat == NULL)
1716 nexttype = TypeNotSet;
1719 if(curtype == Literal){
1720 if(prevtype == TypeNotSet ||
1721 prevtype == Inherit){ /* no up, at top */
1722 opts[0].ch = -2;
1723 opts[2].ch = -2;
1724 deefault = 'd';
1726 else if(prevtype == Literal){ /* regular up */
1727 opts[2].ch = -2;
1729 else if(prevtype == File){ /* file above us */
1730 if((*cl)->prev->d.r.patline->readonly)
1731 readonlyabove++;
1734 if(nexttype == TypeNotSet){ /* no down, at bottom */
1735 opts[1].ch = -2;
1736 opts[3].ch = -2;
1738 else if(nexttype == Literal){ /* regular down */
1739 opts[3].ch = -2;
1741 else if(nexttype == File){ /* file below us */
1742 if((*cl)->next->d.r.patline->readonly)
1743 readonlybelow++;
1746 else if(curtype == File){
1747 if((*cl)->d.r.patline && (*cl)->d.r.patline->readonly){
1748 q_status_message(SM_ORDER, 0, 3, _("Can't change ReadOnly file"));
1749 return(0);
1752 opts[2].ch = -2;
1753 opts[3].ch = -2;
1755 else{
1756 q_status_message(SM_ORDER, 0, 3,
1757 "Programming Error: unknown line type in role_shuffle");
1758 return(rv);
1761 snprintf(tmp, sizeof(tmp), "Shuffle \"%s\" %s%s%s%s%s%s%s ? ",
1762 (*cl)->value,
1763 (opts[0].ch != -2) ? N_("UP") : "",
1764 (opts[0].ch != -2 && opts[1].ch != -2) ? " or " : "",
1765 (opts[1].ch != -2) ? N_("DOWN") : "",
1766 ((opts[0].ch != -2 ||
1767 opts[1].ch != -2) && opts[2].ch != -2) ? " or " : "",
1768 (opts[2].ch != -2) ? N_("BEFORE") : "",
1769 ((opts[0].ch != -2 ||
1770 opts[1].ch != -2 ||
1771 opts[2].ch != -2) && opts[3].ch != -2) ? " or " : "",
1772 (opts[3].ch != -2) ? N_("AFTER") : "");
1773 tmp[sizeof(tmp)-1] = '\0';
1775 help = (opts[0].ch == -2) ? h_role_shuf_down
1776 : (opts[1].ch == -2) ? h_role_shuf_up
1777 : h_role_shuf;
1779 rv = radio_buttons(tmp, -FOOTER_ROWS(ps), opts, deefault, 'x',
1780 help, RB_NORM);
1782 if(rv == 'x'){
1783 cmd_cancelled("Shuffle");
1784 return(0);
1787 if((readonlyabove && rv == 'u' && curtype != prevtype) ||
1788 (readonlybelow && rv == 'd' && curtype != nexttype)){
1789 q_status_message(SM_ORDER, 0, 3, _("Can't shuffle into ReadOnly file"));
1790 return(0);
1793 if(rv == 'u' && curtype == Literal && prevtype == Literal){
1794 rv = 1;
1795 a = (*cl)->prev;
1796 b = (*cl);
1797 if(a == opt_screen->top_line)
1798 opt_screen->top_line = b;
1800 swap_literal_roles(a, b);
1801 ps->mangled_body = 1;
1803 else if(rv == 'd' && curtype == Literal && nexttype == Literal){
1804 rv = 1;
1805 a = (*cl);
1806 b = (*cl)->next;
1807 if(a == opt_screen->top_line)
1808 opt_screen->top_line = b;
1810 swap_literal_roles(a, b);
1811 ps->mangled_body = 1;
1813 else if(rv == 'u' && curtype == File && prevtype == File){
1814 rv = 1;
1815 a = (*cl)->prev;
1816 b = (*cl);
1817 if(a == opt_screen->top_line)
1818 opt_screen->top_line = b;
1820 swap_file_roles(a, b);
1821 ps->mangled_body = 1;
1823 else if(rv == 'u' && curtype == File){
1824 rv = 1;
1825 move_role_outof_file(cl, 1);
1826 ps->mangled_body = 1;
1828 else if(rv == 'd' && curtype == File && nexttype == File){
1829 rv = 1;
1830 a = (*cl);
1831 b = (*cl)->next;
1832 if(a == opt_screen->top_line)
1833 opt_screen->top_line = b;
1835 swap_file_roles(a, b);
1836 ps->mangled_body = 1;
1838 else if(rv == 'd' && curtype == File){
1839 rv = 1;
1840 if(*cl == opt_screen->top_line)
1841 opt_screen->top_line = (*cl)->next;
1843 move_role_outof_file(cl, 0);
1844 ps->mangled_body = 1;
1846 else if(rv == 'u' && curtype == Literal && prevtype == File){
1847 rv = 1;
1848 move_role_into_file(cl, 1);
1849 ps->mangled_body = 1;
1851 else if(rv == 'd' && curtype == Literal && nexttype == File){
1852 rv = 1;
1853 if(*cl == opt_screen->top_line)
1854 opt_screen->top_line = (*cl)->next;
1856 move_role_into_file(cl, 0);
1857 ps->mangled_body = 1;
1859 else if(rv == 'b'){
1860 rv = 1;
1861 move_role_around_file(cl, 1);
1862 ps->mangled_body = 1;
1864 else if(rv == 'a'){
1865 rv = 1;
1866 if(*cl == opt_screen->top_line)
1867 opt_screen->top_line = (*cl)->next;
1869 move_role_around_file(cl, 0);
1870 ps->mangled_body = 1;
1873 return(rv);
1878 role_config_addfile(struct pine *ps, CONF_S **cl, long int rflags)
1880 char filename[MAXPATH+1], full_filename[MAXPATH+1];
1881 char dir2[MAXPATH+1], pdir[MAXPATH+1];
1882 char *lc, *newfile = NULL;
1883 PAT_LINE_S *file_patline;
1884 int rv = 0, len;
1885 int r = 1, flags;
1886 HelpType help = NO_HELP;
1887 PAT_TYPE curtype;
1888 CONF_S *first_line = NULL, *add_line, *save_current;
1889 struct variable *vars = ps->vars;
1891 if(ps->restricted){
1892 q_status_message(SM_ORDER, 0, 3, "Alpine demo can't read files");
1893 return(rv);
1896 curtype = ((*cl)->d.r.patline && (*cl)->d.r.patline)
1897 ? (*cl)->d.r.patline->type : TypeNotSet;
1899 if(curtype == File){
1900 q_status_message(SM_ORDER, 0, 3, _("Current rule is already part of a file. Move outside any files first."));
1901 return(rv);
1905 * Parse_pattern_file uses signature_path to figure out where to look
1906 * for the file. In signature_path we read signature files relative
1907 * to the pinerc dir, so if user selects one that is in there we'll
1908 * use relative instead of absolute, so it looks nicer.
1910 pdir[0] = '\0';
1911 if(VAR_OPER_DIR){
1912 strncpy(pdir, VAR_OPER_DIR, sizeof(pdir)-1);
1913 pdir[sizeof(pdir)-1] = '\0';
1914 len = strlen(pdir) + 1;
1916 else if((lc = last_cmpnt(ps->pinerc)) != NULL){
1917 strncpy(pdir, ps->pinerc, MIN(sizeof(pdir)-1,lc-ps->pinerc));
1918 pdir[MIN(sizeof(pdir)-1, lc-ps->pinerc)] = '\0';
1919 len = strlen(pdir);
1922 strncpy(dir2, pdir, sizeof(dir2)-1);
1923 dir2[sizeof(dir2)-1] = '\0';
1924 filename[0] = '\0';
1925 full_filename[0] = '\0';
1926 ps->mangled_footer = 1;
1928 while(1){
1929 flags = OE_APPEND_CURRENT;
1930 r = optionally_enter(filename, -FOOTER_ROWS(ps), 0, sizeof(filename),
1931 "Name of file to be added to rules: ",
1932 NULL, help, &flags);
1934 if(r == 3){
1935 help = (help == NO_HELP) ? h_config_role_addfile : NO_HELP;
1936 continue;
1938 else if(r == 10 || r == 11){ /* Browser or File Completion */
1939 continue;
1941 else if(r == 1 || (r == 0 && filename[0] == '\0')){
1942 cmd_cancelled("IncludeFile");
1943 return(rv);
1945 else if(r == 4){
1946 continue;
1948 else if(r != 0){
1949 Writechar(BELL, 0);
1950 continue;
1953 removing_leading_and_trailing_white_space(filename);
1954 if(is_absolute_path(filename))
1955 newfile = cpystr(filename);
1956 else{
1957 build_path(full_filename, dir2, filename, sizeof(full_filename));
1958 removing_leading_and_trailing_white_space(full_filename);
1959 if(!strncmp(full_filename, pdir, strlen(pdir)))
1960 newfile = cpystr(full_filename + len);
1961 else
1962 newfile = cpystr(full_filename);
1965 if(newfile && *newfile)
1966 break;
1969 if(!newfile)
1970 return(rv);
1972 set_pathandle(rflags);
1974 if((file_patline = parse_pat_file(newfile)) != NULL){
1976 * Insert the file after the current line.
1978 PAT_LINE_S *cur_patline;
1979 int first_pat;
1981 rv = ps->mangled_screen = 1;
1982 first_pat = !(*cl)->d.r.pat;
1983 cur_patline = (*cl)->d.r.patline ? (*cl)->d.r.patline :
1984 (*cur_pat_h) ? (*cur_pat_h)->patlinehead : NULL;
1986 if(*cur_pat_h)
1987 (*cur_pat_h)->dirtypinerc = 1;
1989 file_patline->dirty = 1;
1991 if(cur_patline){
1992 file_patline->prev = cur_patline;
1993 file_patline->next = cur_patline->next;
1994 if(cur_patline->next)
1995 cur_patline->next->prev = file_patline;
1997 cur_patline->next = file_patline;
1999 else{
2000 /* set head of list */
2001 if(*cur_pat_h)
2002 (*cur_pat_h)->patlinehead = file_patline;
2005 if(first_pat){
2006 if(file_patline->first){
2007 /* get rid of Fake Add line */
2008 add_line = *cl;
2009 opt_screen->top_line = NULL;
2010 add_patline_to_display(ps, cl, 0, &first_line,
2011 &opt_screen->top_line, file_patline,
2012 rflags);
2013 opt_screen->current = first_line;
2014 snip_confline(&add_line);
2016 else{
2017 /* we're _appending_ to the Fake Add line */
2018 save_current = opt_screen->current;
2019 add_patline_to_display(ps, cl, 0, NULL, NULL, file_patline,
2020 rflags);
2021 opt_screen->current = save_current;
2024 else{
2025 opt_screen->top_line = NULL;
2026 save_current = opt_screen->current;
2027 add_patline_to_display(ps, cl, 0, &first_line,
2028 &opt_screen->top_line, file_patline,
2029 rflags);
2030 if(first_line)
2031 opt_screen->current = first_line;
2032 else
2033 opt_screen->current = save_current;
2037 if(newfile)
2038 fs_give((void **)&newfile);
2040 return(rv);
2045 role_config_delfile(struct pine *ps, CONF_S **cl, long int rflags)
2047 int rv = 0;
2048 PAT_LINE_S *cur_patline;
2049 char prompt[100];
2051 if(!(cur_patline = (*cl)->d.r.patline)){
2052 q_status_message(SM_ORDER, 0, 3,
2053 "Unknown problem in role_config_delfile");
2054 return(rv);
2057 if(cur_patline->type != File){
2058 q_status_message(SM_ORDER, 0, 3, _("Current rule is not part of a file. Use Delete to remove current rule"));
2059 return(rv);
2062 snprintf(prompt, sizeof(prompt), _("Really remove rule file \"%s\" from rules config "),
2063 cur_patline->filename);
2064 prompt[sizeof(prompt)-1] = '\0';
2066 ps->mangled_footer = 1;
2067 if(want_to(prompt,'n','n',h_config_role_delfile, WT_FLUSH_IN) == 'y'){
2068 CONF_S *ctmp, *cp;
2070 set_pathandle(rflags);
2071 rv = ps->mangled_screen = 1;
2072 if(*cur_pat_h)
2073 (*cur_pat_h)->dirtypinerc = 1;
2075 if(cur_patline->prev)
2076 cur_patline->prev->next = cur_patline->next;
2077 else{
2078 if(*cur_pat_h)
2079 (*cur_pat_h)->patlinehead = cur_patline->next;
2082 if(cur_patline->next)
2083 cur_patline->next->prev = cur_patline->prev;
2085 /* delete the conf lines */
2087 /* find the first one associated with this file */
2088 for(ctmp = *cl;
2089 ctmp && ctmp->prev && ctmp->prev->d.r.patline == cur_patline;
2090 ctmp = ctmp->prev)
2093 if(ctmp->prev) /* this file wasn't the first thing in config */
2094 *cl = ctmp->prev;
2095 else{ /* this file was first in config */
2096 for(cp = ctmp; cp && cp->next; cp = cp->next)
2099 if(cp->d.r.patline == cur_patline)
2100 *cl = NULL;
2101 else
2102 *cl = cp;
2105 /* delete lines from the file */
2106 while(ctmp && ctmp->d.r.patline == cur_patline){
2107 cp = ctmp;
2108 ctmp = ctmp->next;
2109 snip_confline(&cp);
2112 /* deleting last real rule */
2113 if(!first_pattern(role_global_pstate)){
2115 * Find the start and prepend the fake first role
2116 * in there.
2118 while(*cl && (*cl)->prev)
2119 *cl = (*cl)->prev;
2121 add_fake_first_role(cl, 1, rflags);
2123 else if(first_pattern(role_global_pstate)->inherit &&
2124 !next_pattern(role_global_pstate)){
2125 while(*cl && (*cl)->prev)
2126 *cl = (*cl)->prev;
2128 /* append fake first after inherit */
2129 add_fake_first_role(cl, 0, rflags);
2132 opt_screen->top_line = first_confline(*cl);
2133 opt_screen->current = first_sel_confline(opt_screen->top_line);
2135 cur_patline->next = NULL;
2136 free_patline(&cur_patline);
2138 else
2139 q_status_message(SM_ORDER, 0, 3, _("Rule file not removed"));
2141 return(rv);
2146 * Swap from a, b to b, a.
2148 void
2149 swap_literal_roles(CONF_S *a, CONF_S *b)
2151 PAT_LINE_S *patline_a, *patline_b;
2153 patline_a = a->d.r.patline;
2154 patline_b = b->d.r.patline;
2156 set_pathandle(role_global_flags);
2157 if(*cur_pat_h)
2158 (*cur_pat_h)->dirtypinerc = 1;
2160 /* first swap the patlines */
2161 if(patline_a->next == patline_b){
2162 patline_b->prev = patline_a->prev;
2163 if(patline_a->prev)
2164 patline_a->prev->next = patline_b;
2166 patline_a->next = patline_b->next;
2167 if(patline_b->next)
2168 patline_b->next->prev = patline_a;
2170 patline_b->next = patline_a;
2171 patline_a->prev = patline_b;
2173 else{
2174 PAT_LINE_S *new_a_prev, *new_a_next;
2176 new_a_prev = patline_b->prev;
2177 new_a_next = patline_b->next;
2179 patline_b->prev = patline_a->prev;
2180 patline_b->next = patline_a->next;
2181 if(patline_b->prev)
2182 patline_b->prev->next = patline_b;
2183 if(patline_b->next)
2184 patline_b->next->prev = patline_b;
2186 patline_a->prev = new_a_prev;
2187 patline_a->next = new_a_next;
2188 if(patline_a->prev)
2189 patline_a->prev->next = patline_a;
2190 if(patline_a->next)
2191 patline_a->next->prev = patline_a;
2195 * If patline_b is now the first one in the list, we need to fix the
2196 * head of the list to point to this new role.
2198 if(patline_b->prev == NULL && *cur_pat_h)
2199 (*cur_pat_h)->patlinehead = patline_b;
2202 /* and then swap the conf lines */
2204 b->prev = a->prev;
2205 if(a->prev)
2206 a->prev->next = b;
2208 a->next = b->next;
2209 if(b->next)
2210 b->next->prev = a;
2212 b->next = a;
2213 a->prev = b;
2218 * Swap from a, b to b, a.
2220 void
2221 swap_file_roles(CONF_S *a, CONF_S *b)
2223 PAT_S *pat_a, *pat_b;
2224 PAT_LINE_S *patline;
2226 pat_a = a->d.r.pat;
2227 pat_b = b->d.r.pat;
2228 patline = pat_a->patline;
2230 patline->dirty = 1;
2232 /* first swap the pats */
2233 if(pat_a->next == pat_b){
2234 pat_b->prev = pat_a->prev;
2235 if(pat_a->prev)
2236 pat_a->prev->next = pat_b;
2238 pat_a->next = pat_b->next;
2239 if(pat_b->next)
2240 pat_b->next->prev = pat_a;
2242 pat_b->next = pat_a;
2243 pat_a->prev = pat_b;
2245 else{
2246 PAT_S *new_a_prev, *new_a_next;
2248 new_a_prev = pat_b->prev;
2249 new_a_next = pat_b->next;
2251 pat_b->prev = pat_a->prev;
2252 pat_b->next = pat_a->next;
2253 if(pat_b->prev)
2254 pat_b->prev->next = pat_b;
2255 if(pat_b->next)
2256 pat_b->next->prev = pat_b;
2258 pat_a->prev = new_a_prev;
2259 pat_a->next = new_a_next;
2260 if(pat_a->prev)
2261 pat_a->prev->next = pat_a;
2262 if(pat_a->next)
2263 pat_a->next->prev = pat_a;
2267 * Fix the first and last pointers.
2269 if(patline->first == pat_a)
2270 patline->first = pat_b;
2271 if(patline->last == pat_b)
2272 patline->last = pat_a;
2274 /* and then swap the conf lines */
2276 b->prev = a->prev;
2277 if(a->prev)
2278 a->prev->next = b;
2280 a->next = b->next;
2281 if(b->next)
2282 b->next->prev = a;
2284 b->next = a;
2285 a->prev = b;
2291 void
2292 move_role_into_file(CONF_S **cl, int up)
2294 PAT_LINE_S *cur_patline, *file_patline;
2295 PAT_S *pat;
2296 CONF_S *a, *b;
2298 cur_patline = (*cl)->d.r.patline;
2300 if(up){
2301 file_patline = (*cl)->prev->d.r.patline;
2302 a = (*cl)->prev;
2303 b = (*cl);
2304 b->d.r.patline = file_patline;
2306 else{
2307 file_patline = (*cl)->next->d.r.patline;
2308 a = (*cl);
2309 b = (*cl)->next;
2310 a->d.r.patline = file_patline;
2313 set_pathandle(role_global_flags);
2314 if(*cur_pat_h)
2315 (*cur_pat_h)->dirtypinerc = 1;
2317 file_patline->dirty = 1;
2319 pat = cur_patline->first;
2321 if(!up && *cur_pat_h && cur_patline == (*cur_pat_h)->patlinehead)
2322 (*cur_pat_h)->patlinehead = (*cur_pat_h)->patlinehead->next;
2324 if(file_patline->first){
2325 if(up){
2326 file_patline->last->next = pat;
2327 pat->prev = file_patline->last;
2328 file_patline->last = pat;
2330 else{
2331 file_patline->first->prev = pat;
2332 pat->next = file_patline->first;
2333 file_patline->first = pat;
2336 else /* will be only role in file */
2337 file_patline->first = file_patline->last = pat;
2339 pat->patline = file_patline;
2341 /* delete the now unused cur_patline */
2342 cur_patline->first = cur_patline->last = NULL;
2343 if(cur_patline->prev)
2344 cur_patline->prev->next = cur_patline->next;
2345 if(cur_patline->next)
2346 cur_patline->next->prev = cur_patline->prev;
2348 cur_patline->next = NULL;
2349 free_patline(&cur_patline);
2351 /* and then swap the conf lines */
2353 b->prev = a->prev;
2354 if(a->prev)
2355 a->prev->next = b;
2357 a->next = b->next;
2358 if(b->next)
2359 b->next->prev = a;
2361 b->next = a;
2362 a->prev = b;
2368 void
2369 move_role_outof_file(CONF_S **cl, int up)
2371 PAT_LINE_S *file_patline, *new_patline;
2372 PAT_S *pat;
2373 CONF_S *a, *b;
2375 new_patline = (PAT_LINE_S *)fs_get(sizeof(*new_patline));
2376 memset((void *)new_patline, 0, sizeof(*new_patline));
2377 new_patline->type = Literal;
2379 file_patline = (*cl)->d.r.patline;
2380 pat = (*cl)->d.r.pat;
2382 if(up){
2383 a = (*cl)->prev;
2384 b = (*cl);
2386 if(pat->prev)
2387 pat->prev->next = pat->next;
2388 else
2389 file_patline->first = pat->next;
2391 if(pat->next)
2392 pat->next->prev = pat->prev;
2393 else
2394 file_patline->last = pat->prev;
2396 if(file_patline->first)
2397 file_patline->first->prev = NULL;
2399 if(file_patline->last)
2400 file_patline->last->next = NULL;
2402 if(file_patline->prev)
2403 file_patline->prev->next = new_patline;
2405 new_patline->prev = file_patline->prev;
2406 new_patline->next = file_patline;
2407 file_patline->prev = new_patline;
2408 b->d.r.patline = new_patline;
2410 else{
2411 a = (*cl);
2412 b = (*cl)->next;
2414 if(pat->prev)
2415 pat->prev->next = pat->next;
2416 else
2417 file_patline->first = pat->next;
2419 if(pat->next)
2420 pat->next->prev = pat->prev;
2421 else
2422 file_patline->last = pat->prev;
2424 if(file_patline->first)
2425 file_patline->first->prev = NULL;
2427 if(file_patline->last)
2428 file_patline->last->next = NULL;
2430 if(file_patline->next)
2431 file_patline->next->prev = new_patline;
2433 new_patline->next = file_patline->next;
2434 new_patline->prev = file_patline;
2435 file_patline->next = new_patline;
2436 a->d.r.patline = new_patline;
2439 set_pathandle(role_global_flags);
2440 if(*cur_pat_h)
2441 (*cur_pat_h)->dirtypinerc = 1;
2443 file_patline->dirty = 1;
2445 new_patline->first = new_patline->last = pat;
2446 pat->patline = new_patline;
2447 pat->prev = pat->next = NULL;
2449 if(up && *cur_pat_h && file_patline == (*cur_pat_h)->patlinehead)
2450 (*cur_pat_h)->patlinehead = new_patline;
2452 /* and then swap the conf lines */
2454 b->prev = a->prev;
2455 if(a->prev)
2456 a->prev->next = b;
2458 a->next = b->next;
2459 if(b->next)
2460 b->next->prev = a;
2462 b->next = a;
2463 a->prev = b;
2468 * This is a move of a literal role from before a file to after a file,
2469 * or vice versa.
2471 void
2472 move_role_around_file(CONF_S **cl, int up)
2474 PAT_LINE_S *file_patline, *lit_patline;
2475 CONF_S *cp;
2477 set_pathandle(role_global_flags);
2478 lit_patline = (*cl)->d.r.patline;
2479 if(up)
2480 file_patline = (*cl)->prev->d.r.patline;
2481 else{
2482 if(*cur_pat_h && lit_patline == (*cur_pat_h)->patlinehead)
2483 (*cur_pat_h)->patlinehead = (*cur_pat_h)->patlinehead->next;
2485 file_patline = (*cl)->next->d.r.patline;
2488 if(*cur_pat_h)
2489 (*cur_pat_h)->dirtypinerc = 1;
2491 /* remove the lit_patline from the list */
2492 if(lit_patline->prev)
2493 lit_patline->prev->next = lit_patline->next;
2494 if(lit_patline->next)
2495 lit_patline->next->prev = lit_patline->prev;
2497 /* and reinsert it on the other side of the file */
2498 if(up){
2499 if(*cur_pat_h && file_patline == (*cur_pat_h)->patlinehead)
2500 (*cur_pat_h)->patlinehead = lit_patline;
2502 lit_patline->prev = file_patline->prev;
2503 lit_patline->next = file_patline;
2505 if(file_patline->prev)
2506 file_patline->prev->next = lit_patline;
2508 file_patline->prev = lit_patline;
2510 else{
2511 lit_patline->next = file_patline->next;
2512 lit_patline->prev = file_patline;
2514 if(file_patline->next)
2515 file_patline->next->prev = lit_patline;
2517 file_patline->next = lit_patline;
2521 * And then move the conf line around the file conf lines.
2524 /* find it's new home */
2525 if(up)
2526 for(cp = (*cl);
2527 cp && cp->prev && cp->prev->d.r.patline == file_patline;
2528 cp = prev_confline(cp))
2530 else
2531 for(cp = (*cl);
2532 cp && cp->next && cp->next->d.r.patline == file_patline;
2533 cp = next_confline(cp))
2536 /* remove it from where it is */
2537 if((*cl)->prev)
2538 (*cl)->prev->next = (*cl)->next;
2539 if((*cl)->next)
2540 (*cl)->next->prev = (*cl)->prev;
2542 /* cp points to top or bottom of the file lines */
2543 if(up){
2544 (*cl)->prev = cp->prev;
2545 if(cp->prev)
2546 cp->prev->next = (*cl);
2548 cp->prev = (*cl);
2549 (*cl)->next = cp;
2551 else{
2552 (*cl)->next = cp->next;
2553 if(cp->next)
2554 cp->next->prev = (*cl);
2556 cp->next = (*cl);
2557 (*cl)->prev = cp;
2562 #define SETUP_PAT_STATUS(ctmp,svar,val,htitle,hval) \
2563 {char tmp[MAXPATH+1]; \
2564 int i, j, lv; \
2565 NAMEVAL_S *f; \
2567 /* Blank line */ \
2568 new_confline(&ctmp); \
2569 ctmp->flags |= CF_NOSELECT | CF_B_LINE; \
2571 new_confline(&ctmp); \
2572 ctmp->var = &svar; \
2573 ctmp->keymenu = &config_radiobutton_keymenu; \
2574 ctmp->help = NO_HELP; \
2575 ctmp->tool = NULL; \
2576 snprintf(tmp, sizeof(tmp), "%-s =", svar.name); \
2577 tmp[sizeof(tmp)-1] = '\0'; \
2578 ctmp->varname = cpystr(tmp); \
2579 ctmp->varnamep = ctmpb = ctmp; \
2580 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM); \
2582 new_confline(&ctmp); \
2583 ctmp->var = NULL; \
2584 ctmp->valoffset = rindent; \
2585 ctmp->keymenu = &config_radiobutton_keymenu; \
2586 ctmp->help = NO_HELP; \
2587 ctmp->tool = NULL; \
2588 ctmp->varnamep = ctmpb; \
2589 ctmp->flags |= CF_NOSELECT; \
2590 ctmp->value = cpystr("Set Choose One"); \
2592 new_confline(&ctmp); \
2593 ctmp->var = NULL; \
2594 ctmp->valoffset = rindent; \
2595 ctmp->keymenu = &config_radiobutton_keymenu; \
2596 ctmp->help = NO_HELP; \
2597 ctmp->tool = radio_tool; \
2598 ctmp->varnamep = ctmpb; \
2599 ctmp->flags |= CF_NOSELECT; \
2600 ctmp->value = cpystr(set_choose); \
2602 /* find longest value's name */ \
2603 for(lv = 0, i = 0; (f = role_status_types(i)); i++) \
2604 if(lv < (j = utf8_width(f->name))) \
2605 lv = j; \
2607 lv = MIN(lv, 100); \
2609 for(i = 0; (f = role_status_types(i)); i++){ \
2610 new_confline(&ctmp); \
2611 ctmp->help_title= htitle; \
2612 ctmp->var = &svar; \
2613 ctmp->valoffset = rindent; \
2614 ctmp->keymenu = &config_radiobutton_keymenu; \
2615 ctmp->help = hval; \
2616 ctmp->varmem = i; \
2617 ctmp->tool = radio_tool; \
2618 ctmp->varnamep = ctmpb; \
2619 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", (((!(def && def->patgrp) || \
2620 val == -1) && \
2621 f->value == PAT_STAT_EITHER) || \
2622 (def && def->patgrp && \
2623 f->value == val)) \
2624 ? R_SELD : ' ', \
2625 lv, lv, f->name); \
2626 tmp[sizeof(tmp)-1] = '\0'; \
2627 ctmp->value = cpystr(tmp); \
2631 #define SETUP_MSG_STATE(ctmp,svar,val,htitle,hval) \
2632 {char tmp[MAXPATH+1]; \
2633 int i, j, lv; \
2634 NAMEVAL_S *f; \
2636 /* Blank line */ \
2637 new_confline(&ctmp); \
2638 ctmp->flags |= CF_NOSELECT | CF_B_LINE; \
2640 new_confline(&ctmp); \
2641 ctmp->var = &svar; \
2642 ctmp->keymenu = &config_radiobutton_keymenu; \
2643 ctmp->help = NO_HELP; \
2644 ctmp->tool = NULL; \
2645 snprintf(tmp, sizeof(tmp), "%-s =", svar.name); \
2646 tmp[sizeof(tmp)-1] = '\0'; \
2647 ctmp->varname = cpystr(tmp); \
2648 ctmp->varnamep = ctmpb = ctmp; \
2649 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM); \
2651 new_confline(&ctmp); \
2652 ctmp->var = NULL; \
2653 ctmp->valoffset = rindent; \
2654 ctmp->keymenu = &config_radiobutton_keymenu; \
2655 ctmp->help = NO_HELP; \
2656 ctmp->tool = NULL; \
2657 ctmp->varnamep = ctmpb; \
2658 ctmp->flags |= CF_NOSELECT; \
2659 ctmp->value = cpystr("Set Choose One"); \
2661 new_confline(&ctmp); \
2662 ctmp->var = NULL; \
2663 ctmp->valoffset = rindent; \
2664 ctmp->keymenu = &config_radiobutton_keymenu; \
2665 ctmp->help = NO_HELP; \
2666 ctmp->tool = radio_tool; \
2667 ctmp->varnamep = ctmpb; \
2668 ctmp->flags |= CF_NOSELECT; \
2669 ctmp->value = cpystr(set_choose); \
2671 /* find longest value's name */ \
2672 for(lv = 0, i = 0; (f = msg_state_types(i)); i++) \
2673 if(lv < (j = utf8_width(f->name))) \
2674 lv = j; \
2676 lv = MIN(lv, 100); \
2678 for(i = 0; (f = msg_state_types(i)); i++){ \
2679 new_confline(&ctmp); \
2680 ctmp->help_title= htitle; \
2681 ctmp->var = &svar; \
2682 ctmp->valoffset = rindent; \
2683 ctmp->keymenu = &config_radiobutton_keymenu; \
2684 ctmp->help = hval; \
2685 ctmp->varmem = i; \
2686 ctmp->tool = radio_tool; \
2687 ctmp->varnamep = ctmpb; \
2688 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", (f->value == val) \
2689 ? R_SELD : ' ', \
2690 lv, lv, f->name); \
2691 tmp[sizeof(tmp)-1] = '\0'; \
2692 ctmp->value = cpystr(tmp); \
2697 #define FEAT_SENTDATE 0
2698 #define FEAT_IFNOTDEL 1
2699 #define FEAT_NONTERM 2
2700 bitmap_t feat_option_list;
2702 #define INABOOK_FROM 0
2703 #define INABOOK_REPLYTO 1
2704 #define INABOOK_SENDER 2
2705 #define INABOOK_TO 3
2706 #define INABOOK_CC 4
2707 bitmap_t inabook_type_list;
2710 #define INICK_INICK_CONF 0
2711 #define INICK_FROM_CONF 1
2712 #define INICK_REPLYTO_CONF 2
2713 #define INICK_FCC_CONF 3
2714 #define INICK_LITSIG_CONF 4 /* this needs to come before SIG_CONF */
2715 #define INICK_SIG_CONF 5
2716 #define INICK_TEMPL_CONF 6
2717 #define INICK_CSTM_CONF 7
2718 #define INICK_SMTP_CONF 8
2719 #define INICK_NNTP_CONF 9
2720 CONF_S *inick_confs[INICK_NNTP_CONF+1];
2724 * Screen for editing configuration of a role.
2726 * Args ps -- pine struct
2727 * def -- default role values to start with
2728 * title -- part of title at top of screen
2729 * rflags -- which parts of role to edit
2730 * result -- This is the returned PAT_S, freed by caller.
2732 * Returns: 0 if no change
2733 * 1 if user requested a change
2734 * (change is stored in raw_server and hasn't been acted upon yet)
2735 * 10 user says abort
2738 role_config_edit_screen(struct pine *ps, PAT_S *def, char *title, long int rflags, PAT_S **result)
2740 OPT_SCREEN_S screen, *saved_screen;
2741 CONF_S *ctmp = NULL, *ctmpb, *first_line = NULL;
2742 struct variable nick_var, to_pat_var, from_pat_var,
2743 comment_var,
2744 sender_pat_var, cc_pat_var, recip_pat_var, news_pat_var,
2745 subj_pat_var, inick_var, fldr_type_var, folder_pat_var,
2746 abook_type_var, abook_pat_var,
2747 alltext_pat_var, scorei_pat_var, partic_pat_var,
2748 bodytext_pat_var, age_pat_var, size_pat_var,
2749 keyword_pat_var, charset_pat_var,
2750 stat_new_var, stat_del_var, stat_imp_var, stat_ans_var,
2751 stat_rec_var, stat_8bit_var,
2752 stat_bom_var, stat_boy_var,
2753 cat_cmd_var, cati_var, cat_lim_var,
2754 from_act_var, replyto_act_var, fcc_act_var,
2755 sig_act_var, litsig_act_var, templ_act_var,
2756 cstm_act_var, smtp_act_var, nntp_act_var,
2757 sort_act_var, iform_act_var, startup_var,
2758 repl_type_var, forw_type_var, comp_type_var, score_act_var,
2759 hdrtok_act_var,
2760 rolecolor_vars[2], filter_type_var, folder_act_var,
2761 keyword_set_var, keyword_clr_var,
2762 filt_new_var, filt_del_var, filt_imp_var, filt_ans_var;
2763 struct variable *v, *varlist[65], opt_var, inabook_type_var;
2764 char *nick = NULL, *inick = NULL, *fldr_type_pat = NULL,
2765 *comment = NULL,
2766 *scorei_pat = NULL, *age_pat = NULL, *size_pat = NULL,
2767 *abook_type_pat = NULL,
2768 *stat_new = NULL, *stat_del = NULL, *stat_imp = NULL,
2769 *stat_rec = NULL, *stat_ans = NULL, *stat_8bit = NULL,
2770 *stat_bom = NULL, *stat_boy = NULL,
2771 *filt_new = NULL, *filt_del = NULL, *filt_imp = NULL,
2772 *filt_ans = NULL, *cati = NULL, *cat_lim = NULL,
2773 *from_act = NULL, *replyto_act = NULL, *fcc_act = NULL,
2774 *sig_act = NULL, *litsig_act = NULL, *sort_act = NULL,
2775 *templ_act = NULL, *repl_type = NULL, *forw_type = NULL,
2776 *comp_type = NULL, *rc_fg = NULL, *rc_bg = NULL,
2777 *score_act = NULL, *filter_type = NULL,
2778 *hdrtok_act = NULL,
2779 *iform_act = NULL, *startup_act = NULL,
2780 *old_fg = NULL, *old_bg = NULL;
2781 char **to_pat = NULL, **from_pat = NULL, **sender_pat = NULL,
2782 **cc_pat = NULL, **news_pat = NULL, **recip_pat = NULL,
2783 **partic_pat = NULL, **subj_pat = NULL,
2784 **alltext_pat = NULL, **bodytext_pat = NULL,
2785 **keyword_pat = NULL, **folder_pat = NULL,
2786 **charset_pat = NULL,
2787 **abook_pat = NULL, **folder_act = NULL,
2788 **keyword_set = NULL, **keyword_clr = NULL,
2789 **cat_cmd = NULL, **cstm_act = NULL, **smtp_act = NULL,
2790 **nntp_act = NULL, **spat;
2791 char tmp[MAXPATH+1], **apval, **lval, ***alval, *p;
2792 /* TRANSLATORS: These next 4 are subheading for sections of a configuration screen. */
2793 char *fstr = _(" CURRENT FOLDER CONDITIONS BEGIN HERE ");
2794 char mstr[50];
2795 char *astr = _(" ACTIONS BEGIN HERE ");
2796 char *ustr = _(" USES BEGIN HERE ");
2797 char *ostr = _(" OPTIONS BEGIN HERE ");
2798 char *s_p_v_n = _("Subject pattern"); /* longest one of these */
2799 char *u_s_s = _("Use SMTP Server"); /* ditto */
2800 char *c_v_n = _("Exit Status Interval"); /* ditto */
2801 SortOrder def_sort;
2802 int def_sort_rev;
2803 ARBHDR_S *aa, *a;
2804 EARB_S *earb = NULL, *ea;
2805 int rv, i, j, lv, pindent, maxpindent, rindent,
2806 scoreval = 0, edit_role, wid,
2807 edit_incol, edit_score, edit_filter, edit_other, edit_srch,
2808 dval, ival, nval, aval, fval,
2809 per_folder_only, need_uses, need_options;
2810 int (*radio_tool)(struct pine *, int, CONF_S **, unsigned);
2811 int (*addhdr_tool)(struct pine *, int, CONF_S **, unsigned);
2812 int (*t_tool)(struct pine *, int, CONF_S **, unsigned);
2813 NAMEVAL_S *f;
2815 dprint((4, "role_config_edit_screen()\n"));
2816 edit_role = rflags & ROLE_DO_ROLES;
2817 edit_incol = rflags & ROLE_DO_INCOLS;
2818 edit_score = rflags & ROLE_DO_SCORES;
2819 edit_filter = rflags & ROLE_DO_FILTER;
2820 edit_other = rflags & ROLE_DO_OTHER;
2821 edit_srch = rflags & ROLE_DO_SRCH;
2823 per_folder_only = (edit_other &&
2824 !(edit_role || edit_incol || edit_score || edit_filter || edit_srch));
2825 need_uses = edit_role;
2826 need_options = !per_folder_only;
2828 radio_tool = edit_filter ? role_filt_radiobutton_tool
2829 : role_radiobutton_tool;
2830 t_tool = edit_filter ? role_filt_text_tool : role_text_tool;
2831 addhdr_tool = edit_filter ? role_filt_addhdr_tool : role_addhdr_tool;
2833 rindent = 12; /* radio indent */
2836 * We edit by making a nested call to conf_scroll_screen.
2837 * We use some fake struct variables to get back the results in, and
2838 * so we can use the existing tools from the config screen.
2840 varlist[j = 0] = &nick_var;
2841 varlist[++j] = &comment_var;
2842 varlist[++j] = &to_pat_var;
2843 varlist[++j] = &from_pat_var;
2844 varlist[++j] = &sender_pat_var;
2845 varlist[++j] = &cc_pat_var;
2846 varlist[++j] = &recip_pat_var;
2847 varlist[++j] = &partic_pat_var;
2848 varlist[++j] = &news_pat_var;
2849 varlist[++j] = &subj_pat_var;
2850 varlist[++j] = &alltext_pat_var;
2851 varlist[++j] = &bodytext_pat_var;
2852 varlist[++j] = &keyword_pat_var;
2853 varlist[++j] = &charset_pat_var;
2854 varlist[++j] = &age_pat_var;
2855 varlist[++j] = &size_pat_var;
2856 varlist[++j] = &scorei_pat_var;
2857 varlist[++j] = &stat_new_var;
2858 varlist[++j] = &stat_rec_var;
2859 varlist[++j] = &stat_del_var;
2860 varlist[++j] = &stat_imp_var;
2861 varlist[++j] = &stat_ans_var;
2862 varlist[++j] = &stat_8bit_var;
2863 varlist[++j] = &stat_bom_var;
2864 varlist[++j] = &stat_boy_var;
2865 varlist[++j] = &cat_cmd_var;
2866 varlist[++j] = &cati_var;
2867 varlist[++j] = &cat_lim_var;
2868 varlist[++j] = &inick_var;
2869 varlist[++j] = &fldr_type_var;
2870 varlist[++j] = &folder_pat_var;
2871 varlist[++j] = &abook_type_var;
2872 varlist[++j] = &abook_pat_var;
2873 varlist[++j] = &from_act_var;
2874 varlist[++j] = &replyto_act_var;
2875 varlist[++j] = &fcc_act_var;
2876 varlist[++j] = &sig_act_var;
2877 varlist[++j] = &litsig_act_var;
2878 varlist[++j] = &sort_act_var;
2879 varlist[++j] = &iform_act_var;
2880 varlist[++j] = &startup_var;
2881 varlist[++j] = &templ_act_var;
2882 varlist[++j] = &cstm_act_var;
2883 varlist[++j] = &smtp_act_var;
2884 varlist[++j] = &nntp_act_var;
2885 varlist[++j] = &score_act_var;
2886 varlist[++j] = &hdrtok_act_var;
2887 varlist[++j] = &repl_type_var;
2888 varlist[++j] = &forw_type_var;
2889 varlist[++j] = &comp_type_var;
2890 varlist[++j] = &rolecolor_vars[0];
2891 varlist[++j] = &rolecolor_vars[1];
2892 varlist[++j] = &filter_type_var;
2893 varlist[++j] = &folder_act_var;
2894 varlist[++j] = &keyword_set_var;
2895 varlist[++j] = &keyword_clr_var;
2896 varlist[++j] = &filt_new_var;
2897 varlist[++j] = &filt_del_var;
2898 varlist[++j] = &filt_imp_var;
2899 varlist[++j] = &filt_ans_var;
2900 varlist[++j] = &opt_var;
2901 varlist[++j] = &inabook_type_var;
2902 varlist[++j] = NULL;
2903 for(j = 0; varlist[j]; j++)
2904 memset(varlist[j], 0, sizeof(struct variable));
2906 if(def && ((def->patgrp && def->patgrp->bogus) || (def->action && def->action->bogus))){
2907 char msg[MAX_SCREEN_COLS+1];
2909 snprintf(msg, sizeof(msg),
2910 _("Rule contains unknown %s element, possibly from newer Alpine"),
2911 (def->patgrp && def->patgrp->bogus) ? "pattern" : "action");
2912 msg[sizeof(msg)-1] = '\0';
2913 q_status_message(SM_ORDER | SM_DING, 7, 7, msg);
2914 q_status_message(SM_ORDER | SM_DING, 7, 7,
2915 _("Editing with this version of Alpine will destroy information"));
2916 flush_status_messages(0);
2919 role_forw_ptr = role_repl_ptr = role_fldr_ptr = role_filt_ptr = NULL;
2920 role_status1_ptr = role_status2_ptr = role_status3_ptr = NULL;
2921 role_status4_ptr = role_status5_ptr = role_status6_ptr = NULL;
2922 role_status7_ptr = NULL; role_status8_ptr = NULL;
2923 msg_state1_ptr = msg_state2_ptr = NULL;
2924 msg_state3_ptr = msg_state4_ptr = NULL;
2925 role_afrom_ptr = startup_ptr = NULL;
2926 role_comment_ptr = NULL;
2928 nick_var.name = cpystr(_("Nickname"));
2929 nick_var.is_used = 1;
2930 nick_var.is_user = 1;
2931 apval = APVAL(&nick_var, ew);
2932 *apval = (def && def->patgrp && def->patgrp->nick)
2933 ? cpystr(def->patgrp->nick) : NULL;
2935 nick_var.global_val.p = cpystr(edit_role
2936 ? "Alternate Role"
2937 : (edit_other
2938 ? "Other Rule"
2939 : (edit_incol
2940 ? "Index Color Rule"
2941 : (edit_score
2942 ? "Score Rule"
2943 : "Filter Rule"))));
2944 set_current_val(&nick_var, FALSE, FALSE);
2946 role_comment_ptr = &comment_var; /* so radiobuttons can tell */
2947 comment_var.name = cpystr(_("Comment"));
2948 comment_var.is_used = 1;
2949 comment_var.is_user = 1;
2950 apval = APVAL(&comment_var, ew);
2951 *apval = (def && def->patgrp && def->patgrp->comment)
2952 ? cpystr(def->patgrp->comment) : NULL;
2953 set_current_val(&comment_var, FALSE, FALSE);
2955 /* TRANSLATORS: Quite a few of the translations to follow are from the
2956 rules editing screens. These are mostly headings of individual categories
2957 of criteria which can be set in a rule. */
2958 setup_dummy_pattern_var(&to_pat_var, _("To pattern"),
2959 (def && def->patgrp) ? def->patgrp->to : NULL);
2960 setup_dummy_pattern_var(&from_pat_var, _("From pattern"),
2961 (def && def->patgrp) ? def->patgrp->from : NULL);
2962 setup_dummy_pattern_var(&sender_pat_var, _("Sender pattern"),
2963 (def && def->patgrp) ? def->patgrp->sender : NULL);
2964 setup_dummy_pattern_var(&cc_pat_var, _("Cc pattern"),
2965 (def && def->patgrp) ? def->patgrp->cc : NULL);
2966 setup_dummy_pattern_var(&news_pat_var, _("News pattern"),
2967 (def && def->patgrp) ? def->patgrp->news : NULL);
2968 setup_dummy_pattern_var(&subj_pat_var, s_p_v_n,
2969 (def && def->patgrp) ? def->patgrp->subj : NULL);
2970 /* TRANSLATORS: Recip is an abbreviation for Recipients which stands for
2971 all of the recipients of a message. */
2972 setup_dummy_pattern_var(&recip_pat_var, _("Recip pattern"),
2973 (def && def->patgrp) ? def->patgrp->recip : NULL);
2974 /* TRANSLATORS: Partic is an abbreviation for Participants which stands for
2975 all of the recipients plus the sender of a message. */
2976 setup_dummy_pattern_var(&partic_pat_var, _("Partic pattern"),
2977 (def && def->patgrp) ? def->patgrp->partic : NULL);
2978 /* TRANSLATORS: AllText means all of the text of a message */
2979 setup_dummy_pattern_var(&alltext_pat_var, _("AllText pattern"),
2980 (def && def->patgrp) ? def->patgrp->alltext : NULL);
2981 /* TRANSLATORS: BdyText means the text of a message but not the text in the headers */
2982 setup_dummy_pattern_var(&bodytext_pat_var, _("BdyText pattern"),
2983 (def && def->patgrp) ? def->patgrp->bodytext : NULL);
2985 setup_dummy_pattern_var(&keyword_pat_var, _("Keyword pattern"),
2986 (def && def->patgrp) ? def->patgrp->keyword : NULL);
2987 setup_dummy_pattern_var(&charset_pat_var, _("Charset pattern"),
2988 (def && def->patgrp) ? def->patgrp->charsets : NULL);
2990 age_pat_global_ptr = &age_pat_var;
2991 /* TRANSLATORS: Age interval is a setting for how old the message is. */
2992 age_pat_var.name = cpystr(_("Age interval"));
2993 age_pat_var.is_used = 1;
2994 age_pat_var.is_user = 1;
2995 if(def && def->patgrp && def->patgrp->do_age){
2996 apval = APVAL(&age_pat_var, ew);
2997 *apval = stringform_of_intvl(def->patgrp->age);
3000 set_current_val(&age_pat_var, FALSE, FALSE);
3002 size_pat_global_ptr = &size_pat_var;
3003 size_pat_var.name = cpystr(_("Size interval"));
3004 size_pat_var.is_used = 1;
3005 size_pat_var.is_user = 1;
3006 if(def && def->patgrp && def->patgrp->do_size){
3007 apval = APVAL(&size_pat_var, ew);
3008 *apval = stringform_of_intvl(def->patgrp->size);
3011 set_current_val(&size_pat_var, FALSE, FALSE);
3013 scorei_pat_global_ptr = &scorei_pat_var;
3014 /* TRANSLATORS: Score is an alpine concept where the score can be kept for a
3015 message to see if it is a message you want to look at. */
3016 scorei_pat_var.name = cpystr(_("Score interval"));
3017 scorei_pat_var.is_used = 1;
3018 scorei_pat_var.is_user = 1;
3019 if(def && def->patgrp && def->patgrp->do_score){
3020 apval = APVAL(&scorei_pat_var, ew);
3021 *apval = stringform_of_intvl(def->patgrp->score);
3024 set_current_val(&scorei_pat_var, FALSE, FALSE);
3026 role_status1_ptr = &stat_del_var; /* so radiobuttons can tell */
3027 stat_del_var.name = cpystr(_("Message is Deleted?"));
3028 stat_del_var.is_used = 1;
3029 stat_del_var.is_user = 1;
3030 apval = APVAL(&stat_del_var, ew);
3031 *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_del : -1)) ? cpystr(f->name) : NULL;
3032 set_current_val(&stat_del_var, FALSE, FALSE);
3034 role_status2_ptr = &stat_new_var; /* so radiobuttons can tell */
3035 stat_new_var.name = cpystr(_("Message is New (Unseen)?"));
3036 stat_new_var.is_used = 1;
3037 stat_new_var.is_user = 1;
3038 apval = APVAL(&stat_new_var, ew);
3039 *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_new : -1)) ? cpystr(f->name) : NULL;
3040 set_current_val(&stat_new_var, FALSE, FALSE);
3042 role_status3_ptr = &stat_imp_var; /* so radiobuttons can tell */
3043 stat_imp_var.name = cpystr(_("Message is Important?"));
3044 stat_imp_var.is_used = 1;
3045 stat_imp_var.is_user = 1;
3046 apval = APVAL(&stat_imp_var, ew);
3047 *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_imp : -1)) ? cpystr(f->name) : NULL;
3048 set_current_val(&stat_imp_var, FALSE, FALSE);
3050 role_status4_ptr = &stat_ans_var; /* so radiobuttons can tell */
3051 stat_ans_var.name = cpystr(_("Message is Answered?"));
3052 stat_ans_var.is_used = 1;
3053 stat_ans_var.is_user = 1;
3054 apval = APVAL(&stat_ans_var, ew);
3055 *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_ans : -1)) ? cpystr(f->name) : NULL;
3056 set_current_val(&stat_ans_var, FALSE, FALSE);
3058 role_status5_ptr = &stat_8bit_var; /* so radiobuttons can tell */
3059 stat_8bit_var.name = cpystr(_("Subject contains raw 8-bit?"));
3060 stat_8bit_var.is_used = 1;
3061 stat_8bit_var.is_user = 1;
3062 apval = APVAL(&stat_8bit_var, ew);
3063 *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_8bitsubj : -1)) ? cpystr(f->name) : NULL;
3064 set_current_val(&stat_8bit_var, FALSE, FALSE);
3066 role_status6_ptr = &stat_rec_var; /* so radiobuttons can tell */
3067 stat_rec_var.name = cpystr(_("Message is Recent?"));
3068 stat_rec_var.is_used = 1;
3069 stat_rec_var.is_user = 1;
3070 apval = APVAL(&stat_rec_var, ew);
3071 *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_rec : -1)) ? cpystr(f->name) : NULL;
3072 set_current_val(&stat_rec_var, FALSE, FALSE);
3074 role_status7_ptr = &stat_bom_var; /* so radiobuttons can tell */
3075 stat_bom_var.name = cpystr(_("Beginning of Month?"));
3076 stat_bom_var.is_used = 1;
3077 stat_bom_var.is_user = 1;
3078 apval = APVAL(&stat_bom_var, ew);
3079 *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_bom : -1)) ? cpystr(f->name) : NULL;
3080 set_current_val(&stat_bom_var, FALSE, FALSE);
3082 role_status8_ptr = &stat_boy_var; /* so radiobuttons can tell */
3083 stat_boy_var.name = cpystr(_("Beginning of Year?"));
3084 stat_boy_var.is_used = 1;
3085 stat_boy_var.is_user = 1;
3086 apval = APVAL(&stat_boy_var, ew);
3087 *apval = (f=role_status_types((def && def->patgrp) ? def->patgrp->stat_boy : -1)) ? cpystr(f->name) : NULL;
3088 set_current_val(&stat_boy_var, FALSE, FALSE);
3092 convert_statebits_to_vals((def && def->action) ? def->action->state_setting_bits : 0L, &dval, &aval, &ival, &nval);
3093 msg_state1_ptr = &filt_del_var; /* so radiobuttons can tell */
3094 /* TRANSLATORS: these are actions that might be taken by the rule */
3095 filt_del_var.name = cpystr(_("Set Deleted Status"));
3096 filt_del_var.is_used = 1;
3097 filt_del_var.is_user = 1;
3098 apval = APVAL(&filt_del_var, ew);
3099 *apval = (f=msg_state_types(dval)) ? cpystr(f->name) : NULL;
3100 set_current_val(&filt_del_var, FALSE, FALSE);
3102 msg_state2_ptr = &filt_new_var; /* so radiobuttons can tell */
3103 filt_new_var.name = cpystr(_("Set New Status"));
3104 filt_new_var.is_used = 1;
3105 filt_new_var.is_user = 1;
3106 apval = APVAL(&filt_new_var, ew);
3107 *apval = (f=msg_state_types(nval)) ? cpystr(f->name) : NULL;
3108 set_current_val(&filt_new_var, FALSE, FALSE);
3110 msg_state3_ptr = &filt_imp_var; /* so radiobuttons can tell */
3111 filt_imp_var.name = cpystr(_("Set Important Status"));
3112 filt_imp_var.is_used = 1;
3113 filt_imp_var.is_user = 1;
3114 apval = APVAL(&filt_imp_var, ew);
3115 *apval = (f=msg_state_types(ival)) ? cpystr(f->name) : NULL;
3116 set_current_val(&filt_imp_var, FALSE, FALSE);
3118 msg_state4_ptr = &filt_ans_var; /* so radiobuttons can tell */
3119 filt_ans_var.name = cpystr(_("Set Answered Status"));
3120 filt_ans_var.is_used = 1;
3121 filt_ans_var.is_user = 1;
3122 apval = APVAL(&filt_ans_var, ew);
3123 *apval = (f=msg_state_types(aval)) ? cpystr(f->name) : NULL;
3124 set_current_val(&filt_ans_var, FALSE, FALSE);
3126 inick_var.name = cpystr(_("Initialize settings using role"));
3127 inick_var.is_used = 1;
3128 inick_var.is_user = 1;
3129 apval = APVAL(&inick_var, ew);
3130 *apval = (def && def->action && def->action->inherit_nick &&
3131 def->action->inherit_nick[0])
3132 ? cpystr(def->action->inherit_nick) : NULL;
3134 role_fldr_ptr = &fldr_type_var; /* so radiobuttons can tell */
3135 fldr_type_var.name = cpystr(_("Current Folder Type"));
3136 fldr_type_var.is_used = 1;
3137 fldr_type_var.is_user = 1;
3138 apval = APVAL(&fldr_type_var, ew);
3139 *apval = (f=pat_fldr_types((def && def->patgrp) ? def->patgrp->fldr_type : (!def && edit_filter) ? FLDR_SPECIFIC : FLDR_DEFL)) ? cpystr(f->name) : NULL;
3140 set_current_val(&fldr_type_var, FALSE, FALSE);
3142 setup_dummy_pattern_var(&folder_pat_var, _("Folder List"),
3143 (def && def->patgrp) ? def->patgrp->folder : NULL);
3144 /* special default for folder_pat */
3145 alval = ALVAL(&folder_pat_var, ew);
3146 if(alval && !*alval && !def && edit_filter){
3147 char **ltmp;
3149 ltmp = (char **) fs_get(2 * sizeof(*ltmp));
3150 ltmp[0] = cpystr(ps_global->inbox_name);
3151 ltmp[1] = NULL;
3152 *alval = ltmp;
3153 set_current_val(&folder_pat_var, FALSE, FALSE);
3156 role_afrom_ptr = &abook_type_var; /* so radiobuttons can tell */
3157 abook_type_var.name = cpystr(_("Address in address book?"));
3158 abook_type_var.is_used = 1;
3159 abook_type_var.is_user = 1;
3160 apval = APVAL(&abook_type_var, ew);
3161 *apval = (f=inabook_fldr_types((def && def->patgrp) ? def->patgrp->inabook : IAB_EITHER)) ? cpystr(f->name) : NULL;
3162 set_current_val(&abook_type_var, FALSE, FALSE);
3164 /* TRANSLATORS: Abook is an abbreviation for Address Book */
3165 setup_dummy_pattern_var(&abook_pat_var, _("Abook List"),
3166 (def && def->patgrp) ? def->patgrp->abooks : NULL);
3169 * This is a little different from some of the other patterns. Tt is
3170 * actually a char ** in the struct instead of a PATTERN_S.
3172 cat_cmd_global_ptr = &cat_cmd_var;
3173 cat_cmd_var.name = cpystr(_("External Categorizer Commands"));
3174 cat_cmd_var.is_used = 1;
3175 cat_cmd_var.is_user = 1;
3176 cat_cmd_var.is_list = 1;
3177 alval = ALVAL(&cat_cmd_var, ew);
3178 *alval = (def && def->patgrp && def->patgrp->category_cmd &&
3179 def->patgrp->category_cmd[0])
3180 ? copy_list_array(def->patgrp->category_cmd) : NULL;
3181 set_current_val(&cat_cmd_var, FALSE, FALSE);
3183 cati_global_ptr = &cati_var;
3184 cati_var.name = cpystr(c_v_n);
3185 cati_var.is_used = 1;
3186 cati_var.is_user = 1;
3187 if(def && def->patgrp && def->patgrp->do_cat && def->patgrp->category_cmd &&
3188 def->patgrp->category_cmd[0]){
3189 apval = APVAL(&cati_var, ew);
3190 *apval = stringform_of_intvl(def->patgrp->cat);
3193 set_current_val(&cati_var, FALSE, FALSE);
3195 cat_lim_global_ptr = &cat_lim_var;
3196 cat_lim_var.name = cpystr(_("Character Limit"));
3197 cat_lim_var.is_used = 1;
3198 cat_lim_var.is_user = 1;
3199 cat_lim_var.global_val.p = cpystr("-1");
3200 apval = APVAL(&cat_lim_var, ew);
3201 if(def && def->patgrp && def->patgrp->category_cmd &&
3202 def->patgrp->category_cmd[0] && def->patgrp->cat_lim != -1){
3203 *apval = (char *) fs_get(20 * sizeof(char));
3204 snprintf(*apval, 20, "%ld", def->patgrp->cat_lim);
3205 (*apval)[20-1] = '\0';
3208 set_current_val(&cat_lim_var, FALSE, FALSE);
3210 from_act_var.name = cpystr(_("Set From"));
3211 from_act_var.is_used = 1;
3212 from_act_var.is_user = 1;
3213 if(def && def->action && def->action->from){
3214 char *bufp;
3215 size_t len;
3217 len = est_size(def->action->from);
3218 bufp = (char *) fs_get(len * sizeof(char));
3219 apval = APVAL(&from_act_var, ew);
3220 *apval = addr_string_mult(def->action->from, bufp, len);
3222 else{
3223 apval = APVAL(&from_act_var, ew);
3224 *apval = NULL;
3227 replyto_act_var.name = cpystr(_("Set Reply-To"));
3228 replyto_act_var.is_used = 1;
3229 replyto_act_var.is_user = 1;
3230 if(def && def->action && def->action->replyto){
3231 char *bufp;
3232 size_t len;
3234 len = est_size(def->action->replyto);
3235 bufp = (char *) fs_get(len * sizeof(char));
3236 apval = APVAL(&replyto_act_var, ew);
3237 *apval = addr_string_mult(def->action->replyto, bufp, len);
3239 else{
3240 apval = APVAL(&replyto_act_var, ew);
3241 *apval = NULL;
3244 fcc_act_var.name = cpystr(_("Set Fcc"));
3245 fcc_act_var.is_used = 1;
3246 fcc_act_var.is_user = 1;
3247 apval = APVAL(&fcc_act_var, ew);
3248 *apval = (def && def->action && def->action->fcc)
3249 ? cpystr(def->action->fcc) : NULL;
3251 sort_act_var.name = cpystr(_("Set Sort Order"));
3252 sort_act_var.is_used = 1;
3253 sort_act_var.is_user = 1;
3254 apval = APVAL(&sort_act_var, ew);
3255 if(def && def->action && def->action->is_a_other &&
3256 def->action->sort_is_set){
3257 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s", sort_name(def->action->sortorder),
3258 (def->action->revsort) ? "/Reverse" : "");
3259 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
3260 *apval = cpystr(tmp_20k_buf);
3262 else
3263 *apval = NULL;
3265 iform_act_var.name = cpystr(_("Set Index Format"));
3266 iform_act_var.is_used = 1;
3267 iform_act_var.is_user = 1;
3268 apval = APVAL(&iform_act_var, ew);
3269 *apval = (def && def->action && def->action->is_a_other &&
3270 def->action->index_format)
3271 ? cpystr(def->action->index_format) : NULL;
3272 if(ps_global->VAR_INDEX_FORMAT){
3273 iform_act_var.global_val.p = cpystr(ps_global->VAR_INDEX_FORMAT);
3274 set_current_val(&iform_act_var, FALSE, FALSE);
3277 startup_ptr = &startup_var;
3278 startup_var.name = cpystr(_("Set Startup Rule"));
3279 startup_var.is_used = 1;
3280 startup_var.is_user = 1;
3281 apval = APVAL(&startup_var, ew);
3282 *apval = NULL;
3283 if(def && def->action && def->action->is_a_other){
3284 *apval = (f=startup_rules(def->action->startup_rule))
3285 ? cpystr(f->name) : NULL;
3286 set_current_val(&startup_var, FALSE, FALSE);
3288 if(!*apval){
3289 *apval = (f=startup_rules(IS_NOTSET)) ? cpystr(f->name) : NULL;
3290 set_current_val(&startup_var, FALSE, FALSE);
3293 /* TRANSLATORS: LiteralSig is a way to keep the signature in the configuration
3294 file instead of in a separate Signature file. */
3295 litsig_act_var.name = cpystr(_("Set LiteralSig"));
3296 litsig_act_var.is_used = 1;
3297 litsig_act_var.is_user = 1;
3298 apval = APVAL(&litsig_act_var, ew);
3299 *apval = (def && def->action && def->action->litsig)
3300 ? cpystr(def->action->litsig) : NULL;
3302 sig_act_var.name = cpystr(_("Set Signature"));
3303 sig_act_var.is_used = 1;
3304 sig_act_var.is_user = 1;
3305 apval = APVAL(&sig_act_var, ew);
3306 *apval = (def && def->action && def->action->sig)
3307 ? cpystr(def->action->sig) : NULL;
3309 /* TRANSLATORS: A template is a skeleton of a message to be used
3310 for composing a new message */
3311 templ_act_var.name = cpystr(_("Set Template"));
3312 templ_act_var.is_used = 1;
3313 templ_act_var.is_user = 1;
3314 apval = APVAL(&templ_act_var, ew);
3315 *apval = (def && def->action && def->action->template)
3316 ? cpystr(def->action->template) : NULL;
3318 /* TRANSLATORS: Hdrs is an abbreviation for Headers */
3319 cstm_act_var.name = cpystr(_("Set Other Hdrs"));
3320 cstm_act_var.is_used = 1;
3321 cstm_act_var.is_user = 1;
3322 cstm_act_var.is_list = 1;
3323 alval = ALVAL(&cstm_act_var, ew);
3324 *alval = (def && def->action && def->action->cstm)
3325 ? copy_list_array(def->action->cstm) : NULL;
3327 smtp_act_var.name = cpystr(u_s_s);
3328 smtp_act_var.is_used = 1;
3329 smtp_act_var.is_user = 1;
3330 smtp_act_var.is_list = 1;
3331 alval = ALVAL(&smtp_act_var, ew);
3332 *alval = (def && def->action && def->action->smtp)
3333 ? copy_list_array(def->action->smtp) : NULL;
3335 nntp_act_var.name = cpystr(_("Use NNTP Server"));
3336 nntp_act_var.is_used = 1;
3337 nntp_act_var.is_user = 1;
3338 nntp_act_var.is_list = 1;
3339 alval = ALVAL(&nntp_act_var, ew);
3340 *alval = (def && def->action && def->action->nntp)
3341 ? copy_list_array(def->action->nntp) : NULL;
3343 score_act_global_ptr = &score_act_var;
3344 score_act_var.name = cpystr(_("Score Value"));
3345 score_act_var.is_used = 1;
3346 score_act_var.is_user = 1;
3347 if(def && def->action && def->action->scoreval >= SCORE_MIN &&
3348 def->action->scoreval <= SCORE_MAX)
3349 scoreval = def->action->scoreval;
3351 score_act_var.global_val.p = cpystr("0");
3352 if(scoreval != 0){
3353 apval = APVAL(&score_act_var, ew);
3354 *apval = (char *)fs_get(20 * sizeof(char));
3355 snprintf(*apval, 20, "%d", scoreval);
3356 (*apval)[20-1] = '\0';
3359 set_current_val(&score_act_var, FALSE, FALSE);
3361 hdrtok_act_var.name = cpystr(_("Score From Header"));
3362 hdrtok_act_var.is_used = 1;
3363 hdrtok_act_var.is_user = 1;
3364 if(def && def->action && def->action->scorevalhdrtok){
3365 apval = APVAL(&hdrtok_act_var, ew);
3366 *apval = hdrtok_to_stringform(def->action->scorevalhdrtok);
3369 set_current_val(&hdrtok_act_var, FALSE, FALSE);
3371 role_repl_ptr = &repl_type_var; /* so radiobuttons can tell */
3372 /* TRANSLATORS: For these, Use is a now. This part of the rule describes how
3373 it will be used when Replying so it is the Reply Use */
3374 repl_type_var.name = cpystr(_("Reply Use"));
3375 repl_type_var.is_used = 1;
3376 repl_type_var.is_user = 1;
3377 apval = APVAL(&repl_type_var, ew);
3378 *apval = (f=role_repl_types((def && def->action) ? def->action->repl_type : -1)) ? cpystr(f->name) : NULL;
3379 set_current_val(&repl_type_var, FALSE, FALSE);
3381 role_forw_ptr = &forw_type_var; /* so radiobuttons can tell */
3382 forw_type_var.name = cpystr(_("Forward Use"));
3383 forw_type_var.is_used = 1;
3384 forw_type_var.is_user = 1;
3385 apval = APVAL(&forw_type_var, ew);
3386 *apval = (f=role_forw_types((def && def->action) ? def->action->forw_type : -1)) ? cpystr(f->name) : NULL;
3387 set_current_val(&forw_type_var, FALSE, FALSE);
3389 comp_type_var.name = cpystr(_("Compose Use"));
3390 comp_type_var.is_used = 1;
3391 comp_type_var.is_user = 1;
3392 apval = APVAL(&comp_type_var, ew);
3393 *apval = (f=role_comp_types((def && def->action) ? def->action->comp_type : -1)) ? cpystr(f->name) : NULL;
3394 set_current_val(&comp_type_var, FALSE, FALSE);
3396 rolecolor_vars[0].is_used = 1;
3397 rolecolor_vars[0].is_user = 1;
3398 apval = APVAL(&rolecolor_vars[0], ew);
3399 *apval = (def && def->action && def->action->incol &&
3400 def->action->incol->fg[0])
3401 ? cpystr(def->action->incol->fg) : NULL;
3402 rolecolor_vars[1].is_used = 1;
3403 rolecolor_vars[1].is_user = 1;
3404 rolecolor_vars[0].name = cpystr("ic-foreground-color");
3405 rolecolor_vars[1].name = cpystr(rolecolor_vars[0].name);
3406 strncpy(rolecolor_vars[1].name + 3, "back", 4);
3407 apval = APVAL(&rolecolor_vars[1], ew);
3408 *apval = (def && def->action && def->action->incol &&
3409 def->action->incol->bg[0])
3410 ? cpystr(def->action->incol->bg) : NULL;
3411 set_current_val(&rolecolor_vars[0], FALSE, FALSE);
3412 set_current_val(&rolecolor_vars[1], FALSE, FALSE);
3413 old_fg = PVAL(&rolecolor_vars[0], ew) ? cpystr(PVAL(&rolecolor_vars[0], ew))
3414 : NULL;
3415 old_bg = PVAL(&rolecolor_vars[1], ew) ? cpystr(PVAL(&rolecolor_vars[1], ew))
3416 : NULL;
3419 /* save the old opt_screen before calling scroll screen again */
3420 saved_screen = opt_screen;
3422 pindent = utf8_width(s_p_v_n); /* the longest one */
3423 maxpindent = pindent + 6;
3424 for(a = (def && def->patgrp) ? def->patgrp->arbhdr : NULL; a; a = a->next)
3425 if((lv=utf8_width(a->field ? a->field : "")+utf8_width(" pattern")) > pindent)
3426 pindent = lv;
3428 pindent = MIN(pindent, maxpindent);
3430 pindent += NOTLEN; /* width of `! ' */
3432 pindent += 3; /* width of ` = ' */
3434 /* Nickname */
3435 new_confline(&ctmp);
3436 ctmp->help_title= _("HELP FOR NICKNAME");
3437 ctmp->var = &nick_var;
3438 ctmp->valoffset = pindent;
3439 ctmp->keymenu = &config_role_keymenu;
3440 ctmp->help = edit_role ? h_config_role_nick :
3441 edit_incol ? h_config_incol_nick :
3442 edit_score ? h_config_score_nick :
3443 edit_other ? h_config_other_nick
3444 : h_config_filt_nick;
3445 ctmp->tool = t_tool;
3446 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, nick_var.name);
3447 tmp[sizeof(tmp)-1] = '\0';
3448 ctmp->varname = cpystr(tmp);
3449 ctmp->varnamep = ctmp;
3450 ctmp->value = pretty_value(ps, ctmp);
3451 ctmp->varmem = -1;
3453 first_line = ctmp;
3454 if(rflags & ROLE_CHANGES)
3455 first_line->flags |= CF_CHANGES;
3457 /* Comment */
3458 new_confline(&ctmp);
3459 ctmp->help_title= _("HELP FOR COMMENT");
3460 ctmp->var = &comment_var;
3461 ctmp->valoffset = pindent;
3462 ctmp->keymenu = &config_role_keymenu;
3463 ctmp->help = h_config_role_comment;
3464 ctmp->tool = role_litsig_text_tool;
3465 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, comment_var.name);
3466 tmp[sizeof(tmp)-1] = '\0';
3467 ctmp->varname = cpystr(tmp);
3468 ctmp->varnamep = ctmp;
3469 ctmp->value = pretty_value(ps, ctmp);
3470 ctmp->varmem = -1;
3472 /* Blank line */
3473 new_confline(&ctmp);
3474 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
3476 new_confline(&ctmp);
3477 ctmp->flags |= CF_NOSELECT;
3478 if(ps->ttyo->screen_cols >= (wid=utf8_width(fstr)) + 4){
3479 int dashes;
3481 dashes = (ps->ttyo->screen_cols - wid)/2;
3482 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='),
3483 fstr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '='));
3484 ctmp->value = cpystr(tmp_20k_buf);
3486 else
3487 ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '='));
3489 /* Blank line */
3490 new_confline(&ctmp);
3491 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
3493 /* Folder Type */
3494 new_confline(&ctmp);
3495 ctmp->var = &fldr_type_var;
3496 ctmp->keymenu = &config_radiobutton_keymenu;
3497 ctmp->help = NO_HELP;
3498 ctmp->tool = NULL;
3499 snprintf(tmp, sizeof(tmp), "%s =", fldr_type_var.name);
3500 tmp[sizeof(tmp)-1] = '\0';
3501 ctmp->varname = cpystr(tmp);
3502 ctmp->varnamep = ctmpb = ctmp;
3503 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM);
3505 new_confline(&ctmp);
3506 ctmp->var = NULL;
3507 ctmp->valoffset = rindent;
3508 ctmp->keymenu = &config_radiobutton_keymenu;
3509 ctmp->help = NO_HELP;
3510 ctmp->tool = NULL;
3511 ctmp->varnamep = ctmpb;
3512 ctmp->flags |= CF_NOSELECT;
3513 ctmp->value = cpystr("Set Choose One");
3515 new_confline(&ctmp);
3516 ctmp->var = NULL;
3517 ctmp->valoffset = rindent;
3518 ctmp->keymenu = &config_radiobutton_keymenu;
3519 ctmp->help = NO_HELP;
3520 ctmp->tool = radio_tool;
3521 ctmp->varnamep = ctmpb;
3522 ctmp->flags |= CF_NOSELECT;
3523 ctmp->value = cpystr(set_choose); \
3525 /* find longest value's name */
3526 for(lv = 0, i = 0; (f = pat_fldr_types(i)); i++)
3527 if(lv < (j = utf8_width(f->name)))
3528 lv = j;
3530 lv = MIN(lv, 100);
3532 fval = -1;
3533 for(i = 0; (f = pat_fldr_types(i)); i++){
3534 new_confline(&ctmp);
3535 ctmp->help_title= _("HELP FOR CURRENT FOLDER TYPE");
3536 ctmp->var = &fldr_type_var;
3537 ctmp->valoffset = rindent;
3538 ctmp->keymenu = &config_radiobutton_keymenu;
3539 ctmp->help = edit_role ? h_config_role_fldr_type :
3540 edit_incol ? h_config_incol_fldr_type :
3541 edit_score ? h_config_score_fldr_type :
3542 edit_other ? h_config_other_fldr_type
3543 : h_config_filt_fldr_type;
3544 ctmp->varmem = i;
3545 ctmp->tool = radio_tool;
3546 ctmp->varnamep = ctmpb;
3548 if((PVAL(&fldr_type_var, ew) &&
3549 !strucmp(PVAL(&fldr_type_var, ew), f->name))
3550 || (!PVAL(&fldr_type_var, ew) && f->value == FLDR_DEFL))
3551 fval = f->value;
3553 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w",
3554 (fval == f->value) ? R_SELD : ' ',
3555 lv, lv, f->name);
3556 tmp[sizeof(tmp)-1] = '\0';
3557 ctmp->value = cpystr(tmp);
3560 /* Folder */
3561 /* 5 is the width of `(*) ' */
3562 setup_role_pat_alt(ps, &ctmp, &folder_pat_var,
3563 edit_role ? h_config_role_fldr_type :
3564 edit_incol ? h_config_incol_fldr_type :
3565 edit_score ? h_config_score_fldr_type :
3566 edit_other ? h_config_other_fldr_type
3567 : h_config_filt_fldr_type,
3568 _("HELP FOR FOLDER LIST"),
3569 &config_role_patfolder_keymenu, t_tool, rindent+5,
3570 !(fval == FLDR_SPECIFIC));
3572 if(!per_folder_only){ /* sorry about that indent */
3574 /* Blank line */
3575 new_confline(&ctmp);
3576 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
3578 new_confline(&ctmp);
3579 ctmp->flags |= CF_NOSELECT;
3581 /* TRANSLATORS: The %s is replaced with one of the 4 or 5 words below, CURRENT,
3582 SCORED, and so on. */
3583 snprintf(mstr, sizeof(mstr), _(" %s MESSAGE CONDITIONS BEGIN HERE "),
3584 edit_role ? _("CURRENT") :
3585 edit_score ? _("SCORED") :
3586 edit_incol ? _("COLORED") :
3587 edit_filter ? _("FILTERED") : _("CURRENT"));
3588 mstr[sizeof(mstr)-1] = '\0';
3590 if(ps->ttyo->screen_cols >= (wid=utf8_width(mstr)) + 4){
3591 int dashes;
3593 dashes = (ps->ttyo->screen_cols - wid)/2;
3594 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='),
3595 mstr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '='));
3596 ctmp->value = cpystr(tmp_20k_buf);
3598 else
3599 ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '='));
3601 /* Blank line */
3602 new_confline(&ctmp);
3603 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
3605 setup_role_pat(ps, &ctmp, &to_pat_var,
3606 edit_role ? h_config_role_topat :
3607 edit_incol ? h_config_incol_topat :
3608 edit_score ? h_config_score_topat :
3609 edit_other ? h_config_other_topat
3610 : h_config_filt_topat,
3611 _("HELP FOR TO PATTERN"),
3612 &config_role_addr_pat_keymenu, t_tool, &earb, pindent);
3614 setup_role_pat(ps, &ctmp, &from_pat_var, h_config_role_frompat,
3615 _("HELP FOR FROM PATTERN"),
3616 &config_role_addr_pat_keymenu, t_tool, &earb, pindent);
3618 setup_role_pat(ps, &ctmp, &sender_pat_var, h_config_role_senderpat,
3619 _("HELP FOR SENDER PATTERN"),
3620 &config_role_addr_pat_keymenu, t_tool, &earb, pindent);
3622 setup_role_pat(ps, &ctmp, &cc_pat_var, h_config_role_ccpat,
3623 _("HELP FOR CC PATTERN"),
3624 &config_role_addr_pat_keymenu, t_tool, &earb, pindent);
3626 setup_role_pat(ps, &ctmp, &news_pat_var, h_config_role_newspat,
3627 _("HELP FOR NEWS PATTERN"),
3628 &config_role_keymenu_not, t_tool, &earb, pindent);
3630 setup_role_pat(ps, &ctmp, &subj_pat_var, h_config_role_subjpat,
3631 _("HELP FOR SUBJECT PATTERN"),
3632 &config_role_keymenu_not, t_tool, &earb, pindent);
3634 setup_role_pat(ps, &ctmp, &recip_pat_var, h_config_role_recippat,
3635 _("HELP FOR RECIPIENT PATTERN"),
3636 &config_role_addr_pat_keymenu, t_tool, &earb, pindent);
3638 setup_role_pat(ps, &ctmp, &partic_pat_var, h_config_role_particpat,
3639 _("HELP FOR PARTICIPANT PATTERN"),
3640 &config_role_addr_pat_keymenu, t_tool, &earb, pindent);
3642 /* Arbitrary Patterns */
3643 ea = NULL;
3644 for(j = 0, a = (def && def->patgrp) ? def->patgrp->arbhdr : NULL;
3646 j++, a = a->next){
3647 char *fn = (a->field) ? a->field : "";
3649 if(ea){
3650 ea->next = (EARB_S *)fs_get(sizeof(*ea));
3651 ea = ea->next;
3653 else{
3654 earb = (EARB_S *)fs_get(sizeof(*ea));
3655 ea = earb;
3658 memset((void *)ea, 0, sizeof(*ea));
3659 ea->v = (struct variable *)fs_get(sizeof(struct variable));
3660 memset((void *)ea->v, 0, sizeof(struct variable));
3661 ea->a = (ARBHDR_S *)fs_get(sizeof(ARBHDR_S));
3662 memset((void *)ea->a, 0, sizeof(ARBHDR_S));
3664 ea->a->field = cpystr(fn);
3666 p = (char *) fs_get(strlen(fn) + strlen(" pattern") + 1);
3667 snprintf(p, strlen(fn) + strlen(" pattern") + 1, "%s pattern", fn);
3668 p[strlen(fn) + strlen(" pattern") + 1 - 1] = '\0';
3669 setup_dummy_pattern_var(ea->v, p, a->p);
3670 fs_give((void **) &p);
3671 setup_role_pat(ps, &ctmp, ea->v, h_config_role_arbpat,
3672 ARB_HELP, &config_role_xtrahdr_keymenu,
3673 t_tool, &earb, pindent);
3676 new_confline(&ctmp);
3677 ctmp->help_title = _("HELP FOR EXTRA HEADERS");
3678 ctmp->value = cpystr(ADDXHDRS);
3679 ctmp->keymenu = &config_role_keymenu_extra;
3680 ctmp->help = h_config_role_arbpat;
3681 ctmp->tool = addhdr_tool;
3682 ctmp->d.earb = &earb;
3683 ctmp->varmem = -1;
3685 setup_role_pat(ps, &ctmp, &alltext_pat_var, h_config_role_alltextpat,
3686 _("HELP FOR ALL TEXT PATTERN"),
3687 &config_role_keymenu_not, t_tool, &earb, pindent);
3689 setup_role_pat(ps, &ctmp, &bodytext_pat_var, h_config_role_bodytextpat,
3690 _("HELP FOR BODY TEXT PATTERN"),
3691 &config_role_keymenu_not, t_tool, &earb, pindent);
3693 /* Age Interval */
3694 new_confline(&ctmp);
3695 ctmp->help_title= _("HELP FOR AGE INTERVAL");
3696 ctmp->var = &age_pat_var;
3697 ctmp->valoffset = pindent;
3698 ctmp->keymenu = &config_text_keymenu;
3699 ctmp->help = h_config_role_age;
3700 ctmp->tool = t_tool;
3701 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, age_pat_var.name);
3702 tmp[sizeof(tmp)-1] = '\0';
3703 ctmp->varname = cpystr(tmp);
3704 ctmp->varnamep = ctmp;
3705 ctmp->value = pretty_value(ps, ctmp);
3707 /* Size Interval */
3708 new_confline(&ctmp);
3709 ctmp->help_title= _("HELP FOR SIZE INTERVAL");
3710 ctmp->var = &size_pat_var;
3711 ctmp->valoffset = pindent;
3712 ctmp->keymenu = &config_text_keymenu;
3713 ctmp->help = h_config_role_size;
3714 ctmp->tool = t_tool;
3715 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, size_pat_var.name);
3716 tmp[sizeof(tmp)-1] = '\0';
3717 ctmp->varname = cpystr(tmp);
3718 ctmp->varnamep = ctmp;
3719 ctmp->value = pretty_value(ps, ctmp);
3721 if(!edit_score){
3722 /* Score Interval */
3723 new_confline(&ctmp);
3724 ctmp->help_title= _("HELP FOR SCORE INTERVAL");
3725 ctmp->var = &scorei_pat_var;
3726 ctmp->valoffset = pindent;
3727 ctmp->keymenu = &config_text_keymenu;
3728 ctmp->help = h_config_role_scorei;
3729 ctmp->tool = t_tool;
3730 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, scorei_pat_var.name);
3731 tmp[sizeof(tmp)-1] = '\0';
3732 ctmp->varname = cpystr(tmp);
3733 ctmp->varnamep = ctmp;
3734 ctmp->value = pretty_value(ps, ctmp);
3737 /* Keyword Pattern */
3738 setup_role_pat(ps, &ctmp, &keyword_pat_var, h_config_role_keywordpat,
3739 _("HELP FOR KEYWORD PATTERN"),
3740 &config_role_keyword_keymenu_not, role_text_tool_kword,
3741 NULL, pindent);
3743 /* Charset Pattern */
3744 setup_role_pat(ps, &ctmp, &charset_pat_var, h_config_role_charsetpat,
3745 _("HELP FOR CHARACTER SET PATTERN"),
3746 &config_role_charset_keymenu_not, role_text_tool_charset,
3747 NULL, pindent);
3749 /* Important Status */
3750 SETUP_PAT_STATUS(ctmp, stat_imp_var, def->patgrp->stat_imp,
3751 _("HELP FOR IMPORTANT STATUS"), h_config_role_stat_imp);
3752 /* New Status */
3753 SETUP_PAT_STATUS(ctmp, stat_new_var, def->patgrp->stat_new,
3754 _("HELP FOR NEW STATUS"), h_config_role_stat_new);
3755 /* Recent Status */
3756 SETUP_PAT_STATUS(ctmp, stat_rec_var, def->patgrp->stat_rec,
3757 _("HELP FOR RECENT STATUS"), h_config_role_stat_recent);
3758 /* Deleted Status */
3759 SETUP_PAT_STATUS(ctmp, stat_del_var, def->patgrp->stat_del,
3760 _("HELP FOR DELETED STATUS"), h_config_role_stat_del);
3761 /* Answered Status */
3762 SETUP_PAT_STATUS(ctmp, stat_ans_var, def->patgrp->stat_ans,
3763 _("HELP FOR ANSWERED STATUS"), h_config_role_stat_ans);
3764 /* 8-bit Subject */
3765 SETUP_PAT_STATUS(ctmp, stat_8bit_var, def->patgrp->stat_8bitsubj,
3766 _("HELP FOR 8-BIT SUBJECT"), h_config_role_stat_8bitsubj);
3767 /* Beginning of month */
3768 SETUP_PAT_STATUS(ctmp, stat_bom_var, def->patgrp->stat_bom,
3769 _("HELP FOR BEGINNING OF MONTH"), h_config_role_bom);
3770 /* Beginning of year */
3771 SETUP_PAT_STATUS(ctmp, stat_boy_var, def->patgrp->stat_boy,
3772 _("HELP FOR BEGINNING OF YEAR"), h_config_role_boy);
3774 /* Blank line */
3775 new_confline(&ctmp);
3776 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
3778 /* From in Addrbook */
3779 new_confline(&ctmp);
3780 ctmp->var = &abook_type_var;
3781 ctmp->keymenu = &config_radiobutton_keymenu;
3782 ctmp->help = NO_HELP;
3783 ctmp->tool = NULL;
3784 snprintf(tmp, sizeof(tmp), "%s =", abook_type_var.name);
3785 tmp[sizeof(tmp)-1] = '\0';
3786 ctmp->varname = cpystr(tmp);
3787 ctmp->varnamep = ctmpb = ctmp;
3788 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM);
3790 new_confline(&ctmp);
3791 ctmp->var = NULL;
3792 ctmp->valoffset = rindent;
3793 ctmp->keymenu = &config_radiobutton_keymenu;
3794 ctmp->help = NO_HELP;
3795 ctmp->tool = NULL;
3796 ctmp->varnamep = ctmpb;
3797 ctmp->flags |= CF_NOSELECT;
3798 ctmp->value = cpystr("Set Choose One");
3800 new_confline(&ctmp);
3801 ctmp->var = NULL;
3802 ctmp->valoffset = rindent;
3803 ctmp->keymenu = &config_radiobutton_keymenu;
3804 ctmp->help = NO_HELP;
3805 ctmp->tool = radio_tool;
3806 ctmp->varnamep = ctmpb;
3807 ctmp->flags |= CF_NOSELECT;
3808 ctmp->value = cpystr(set_choose); \
3810 /* find longest value's name */
3811 for(lv = 0, i = 0; (f = inabook_fldr_types(i)); i++)
3812 if(lv < (j = utf8_width(f->name)))
3813 lv = j;
3815 lv = MIN(lv, 100);
3817 fval = -1;
3818 for(i = 0; (f = inabook_fldr_types(i)); i++){
3819 new_confline(&ctmp);
3820 ctmp->help_title= _("HELP FOR ADDRESS IN ADDRESS BOOK");
3821 ctmp->var = &abook_type_var;
3822 ctmp->valoffset = rindent;
3823 ctmp->keymenu = &config_radiobutton_keymenu;
3824 ctmp->help = h_config_role_abookfrom;
3825 ctmp->varmem = i;
3826 ctmp->tool = radio_tool;
3827 ctmp->varnamep = ctmpb;
3829 if((PVAL(&abook_type_var, ew) &&
3830 !strucmp(PVAL(&abook_type_var, ew), f->name))
3831 || (!PVAL(&abook_type_var, ew) && f->value == IAB_DEFL))
3832 fval = f->value;
3834 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w",
3835 (fval == f->value) ? R_SELD : ' ',
3836 lv, lv, f->name);
3837 tmp[sizeof(tmp)-1] = '\0';
3838 ctmp->value = cpystr(tmp);
3841 /* Specific list of abooks */
3842 /* 5 is the width of `(*) ' */
3843 setup_role_pat_alt(ps, &ctmp, &abook_pat_var, h_config_role_abookfrom,
3844 _("HELP FOR ABOOK LIST"),
3845 &config_role_afrom_keymenu, role_text_tool_afrom, rindent+5,
3846 !(fval == IAB_SPEC_YES || fval == IAB_SPEC_NO));
3848 /* Which addresses to check for */
3849 inabook_type_var.name = cpystr(_("Types of addresses to check for in address book"));
3850 inabook_type_var.is_used = 1;
3851 inabook_type_var.is_user = 1;
3852 inabook_type_var.is_list = 1;
3853 clrbitmap(inabook_type_list);
3854 if(def && def->patgrp && def->patgrp->inabook & IAB_FROM)
3855 setbitn(INABOOK_FROM, inabook_type_list);
3856 if(def && def->patgrp && def->patgrp->inabook & IAB_REPLYTO)
3857 setbitn(INABOOK_REPLYTO, inabook_type_list);
3858 if(def && def->patgrp && def->patgrp->inabook & IAB_SENDER)
3859 setbitn(INABOOK_SENDER, inabook_type_list);
3860 if(def && def->patgrp && def->patgrp->inabook & IAB_TO)
3861 setbitn(INABOOK_TO, inabook_type_list);
3862 if(def && def->patgrp && def->patgrp->inabook & IAB_CC)
3863 setbitn(INABOOK_CC, inabook_type_list);
3865 /* default setting */
3866 if(!(bitnset(INABOOK_FROM, inabook_type_list)
3867 || bitnset(INABOOK_REPLYTO, inabook_type_list)
3868 || bitnset(INABOOK_SENDER, inabook_type_list)
3869 || bitnset(INABOOK_TO, inabook_type_list)
3870 || bitnset(INABOOK_CC, inabook_type_list))){
3871 setbitn(INABOOK_FROM, inabook_type_list);
3872 setbitn(INABOOK_REPLYTO, inabook_type_list);
3875 new_confline(&ctmp);
3876 ctmp->var = &inabook_type_var;
3877 ctmp->varoffset = 4;
3878 ctmp->valoffset = 23;
3879 ctmp->keymenu = &config_checkbox_keymenu;
3880 ctmp->help = NO_HELP;
3881 ctmp->tool = NULL;
3882 snprintf(tmp, sizeof(tmp), "%-20s =", inabook_type_var.name);
3883 tmp[sizeof(tmp)-1] = '\0';
3884 ctmp->varname = cpystr(tmp);
3885 ctmp->varnamep = ctmpb = ctmp;
3886 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM);
3888 new_confline(&ctmp);
3889 ctmp->var = NULL;
3890 ctmp->valoffset = rindent;
3891 ctmp->keymenu = &config_checkbox_keymenu;
3892 ctmp->help = NO_HELP;
3893 ctmp->tool = inabook_checkbox_tool;
3894 ctmp->varnamep = ctmpb;
3895 ctmp->flags |= CF_NOSELECT;
3896 ctmp->value = cpystr("Set Address types");
3898 new_confline(&ctmp);
3899 ctmp->var = NULL;
3900 ctmp->valoffset = rindent;
3901 ctmp->keymenu = &config_checkbox_keymenu;
3902 ctmp->help = NO_HELP;
3903 ctmp->tool = inabook_checkbox_tool;
3904 ctmp->varnamep = ctmpb;
3905 ctmp->flags |= CF_NOSELECT;
3906 ctmp->value = cpystr(set_choose);
3908 /* find longest value's name */
3909 for(lv = 0, i = 0; (f = inabook_feature_list(i)); i++){
3910 if(lv < (j = utf8_width(f->name)))
3911 lv = j;
3914 lv = MIN(lv, 100);
3916 for(i = 0; (f = inabook_feature_list(i)); i++){
3917 new_confline(&ctmp);
3918 ctmp->var = &opt_var;
3919 ctmp->help_title= _("HELP FOR ADDRESS TYPES");
3920 ctmp->varnamep = ctmpb;
3921 ctmp->keymenu = &config_checkbox_keymenu;
3922 switch(i){
3923 case INABOOK_FROM:
3924 ctmp->help = h_config_inabook_from;
3925 break;
3926 case INABOOK_REPLYTO:
3927 ctmp->help = h_config_inabook_replyto;
3928 break;
3929 case INABOOK_SENDER:
3930 ctmp->help = h_config_inabook_sender;
3931 break;
3932 case INABOOK_TO:
3933 ctmp->help = h_config_inabook_to;
3934 break;
3935 case INABOOK_CC:
3936 ctmp->help = h_config_inabook_cc;
3937 break;
3940 ctmp->tool = inabook_checkbox_tool;
3941 ctmp->valoffset = rindent;
3942 ctmp->varmem = i;
3943 utf8_snprintf(tmp, sizeof(tmp), "[%c] %-*.*w",
3944 bitnset(f->value, inabook_type_list) ? 'X' : ' ',
3945 lv, lv, f->name);
3946 tmp[sizeof(tmp)-1] = '\0';
3947 ctmp->value = cpystr(tmp);
3950 /* Blank line */
3951 new_confline(&ctmp);
3952 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
3954 /* 4 is indent of "Command", c_v_n is longest of these three, 3 is ` = ' */
3955 i = 4 + utf8_width(c_v_n) + 3;
3957 /* External Command Categorizer */
3958 new_confline(&ctmp);
3959 ctmp->var = &cat_cmd_var;
3960 ctmp->keymenu = &config_text_keymenu;
3961 ctmp->help = NO_HELP;
3962 ctmp->tool = NULL;
3963 snprintf(tmp, sizeof(tmp), "%s =", cat_cmd_var.name);
3964 tmp[sizeof(tmp)-1] = '\0';
3965 ctmp->varname = cpystr(tmp);
3966 ctmp->varnamep = ctmpb = ctmp;
3967 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM);
3969 /* Commands */
3970 new_confline(&ctmp);
3971 ctmp->help_title= _("HELP FOR CATEGORIZER COMMAND");
3972 ctmp->var = &cat_cmd_var;
3973 ctmp->varoffset = 4;
3974 ctmp->valoffset = i;
3975 ctmp->keymenu = &config_text_wshuf_keymenu;
3976 ctmp->help = h_config_role_cat_cmd;
3977 ctmp->tool = t_tool;
3978 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", i-4-3, i-4-3, "Command");
3979 tmp[sizeof(tmp)-1] = '\0';
3980 ctmp->varname = cpystr(tmp);
3981 ctmp->varnamep = ctmpb = ctmp;
3982 ctmp->flags = CF_STARTITEM;
3984 if((lval = LVAL(&cat_cmd_var, ew)) != NULL && lval[0]){
3985 for(j = 0; lval[j]; j++){
3986 if(j)
3987 (void) new_confline(&ctmp);
3989 ctmp->var = &cat_cmd_var;
3990 ctmp->varmem = j;
3991 ctmp->valoffset = i;
3992 ctmp->keymenu = &config_text_wshuf_keymenu;
3993 ctmp->help = h_config_role_cat_cmd;
3994 ctmp->tool = t_tool;
3995 ctmp->varnamep = ctmp;
3996 ctmp->value = pretty_value(ps, ctmp);
3999 else
4000 ctmp->value = pretty_value(ps, ctmp);
4002 /* Exit status interval */
4003 new_confline(&ctmp);
4004 ctmp->help_title= _("HELP FOR CATEGORIZER EXIT STATUS");
4005 ctmp->var = &cati_var;
4006 ctmp->varoffset = 4;
4007 ctmp->valoffset = i;
4008 ctmp->keymenu = &config_text_keymenu;
4009 ctmp->help = h_config_role_cat_status;
4010 ctmp->tool = t_tool;
4011 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", i-4-3, i-4-3, cati_var.name);
4012 tmp[sizeof(tmp)-1] = '\0';
4013 ctmp->varname = cpystr(tmp);
4014 ctmp->varnamep = ctmp;
4015 ctmp->value = pretty_value(ps, ctmp);
4017 /* Character Limit */
4018 new_confline(&ctmp);
4019 ctmp->help_title= _("HELP FOR CHARACTER LIMIT");
4020 ctmp->var = &cat_lim_var;
4021 ctmp->varoffset = 4;
4022 ctmp->valoffset = i;
4023 ctmp->keymenu = &config_text_keymenu;
4024 ctmp->help = h_config_role_cat_limit;
4025 ctmp->tool = t_tool;
4026 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", i-4-3, i-4-3, cat_lim_var.name);
4027 tmp[sizeof(tmp)-1] = '\0';
4028 ctmp->varname = cpystr(tmp);
4029 ctmp->varnamep = ctmp;
4030 ctmp->value = pretty_value(ps, ctmp);
4031 ctmp->flags |= CF_NUMBER;
4034 if(!edit_srch){ /* sorry about that indent */
4035 /* Actions */
4037 /* Blank line */
4038 new_confline(&ctmp);
4039 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4041 new_confline(&ctmp);
4042 ctmp->flags |= CF_NOSELECT;
4043 if(ps->ttyo->screen_cols >= (wid=utf8_width(astr)) + 4){
4044 int dashes;
4046 dashes = (ps->ttyo->screen_cols - wid)/2;
4047 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='),
4048 astr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '='));
4049 ctmp->value = cpystr(tmp_20k_buf);
4051 else
4052 ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '='));
4054 if(edit_role){
4055 int roindent;
4057 roindent = utf8_width(u_s_s); /* the longest one */
4058 roindent += 3; /* width of ` = ' */
4060 /* Blank line */
4061 new_confline(&ctmp);
4062 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4064 /* Inherit Nickname */
4065 new_confline(&ctmp);
4066 inick_confs[INICK_INICK_CONF] = ctmp;
4067 ctmp->help_title= _("HELP FOR INITIAL SET NICKNAME");
4068 ctmp->var = &inick_var;
4069 ctmp->keymenu = &config_role_inick_keymenu;
4070 ctmp->help = h_config_role_inick;
4071 ctmp->tool = role_text_tool_inick;
4072 snprintf(tmp, sizeof(tmp), "%s :", inick_var.name);
4073 tmp[sizeof(tmp)-1] = '\0';
4074 ctmp->valoffset = utf8_width(tmp)+1;
4075 ctmp->varname = cpystr(tmp);
4076 ctmp->varnamep = ctmp;
4078 /* From Action */
4079 new_confline(&ctmp);
4080 inick_confs[INICK_FROM_CONF] = ctmp;
4081 ctmp->help_title= _("HELP FOR SET FROM ACTION");
4082 ctmp->var = &from_act_var;
4083 ctmp->valoffset = roindent;
4084 ctmp->keymenu = &config_role_addr_act_keymenu;
4085 ctmp->help = h_config_role_setfrom;
4086 ctmp->tool = role_text_tool;
4087 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, from_act_var.name);
4088 tmp[sizeof(tmp)-1] = '\0';
4089 ctmp->varname = cpystr(tmp);
4090 ctmp->varnamep = ctmp;
4092 /* Reply-To Action */
4093 new_confline(&ctmp);
4094 inick_confs[INICK_REPLYTO_CONF] = ctmp;
4095 ctmp->help_title= _("HELP FOR SET REPLY-TO ACTION");
4096 ctmp->var = &replyto_act_var;
4097 ctmp->valoffset = roindent;
4098 ctmp->keymenu = &config_role_addr_act_keymenu;
4099 ctmp->help = h_config_role_setreplyto;
4100 ctmp->tool = role_text_tool;
4101 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, replyto_act_var.name);
4102 tmp[sizeof(tmp)-1] = '\0';
4103 ctmp->varname = cpystr(tmp);
4104 ctmp->varnamep = ctmp;
4106 /* Fcc Action */
4107 new_confline(&ctmp);
4108 inick_confs[INICK_FCC_CONF] = ctmp;
4109 ctmp->help_title= _("HELP FOR SET FCC ACTION");
4110 ctmp->var = &fcc_act_var;
4111 ctmp->valoffset = roindent;
4112 ctmp->keymenu = &config_role_actionfolder_keymenu;
4113 ctmp->help = h_config_role_setfcc;
4114 ctmp->tool = role_text_tool;
4115 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, fcc_act_var.name);
4116 tmp[sizeof(tmp)-1] = '\0';
4117 ctmp->varname = cpystr(tmp);
4118 ctmp->varnamep = ctmp;
4120 /* LitSig Action */
4121 new_confline(&ctmp);
4122 inick_confs[INICK_LITSIG_CONF] = ctmp;
4123 ctmp->help_title= _("HELP FOR SET LITERAL SIGNATURE ACTION");
4124 ctmp->var = &litsig_act_var;
4125 ctmp->valoffset = roindent;
4126 ctmp->keymenu = &config_text_keymenu;
4127 ctmp->help = h_config_role_setlitsig;
4128 ctmp->tool = role_litsig_text_tool;
4129 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, litsig_act_var.name);
4130 tmp[sizeof(tmp)-1] = '\0';
4131 ctmp->varname = cpystr(tmp);
4132 ctmp->varnamep = ctmp;
4134 /* Sig Action */
4135 new_confline(&ctmp);
4136 inick_confs[INICK_SIG_CONF] = ctmp;
4137 ctmp->help_title= _("HELP FOR SET SIGNATURE ACTION");
4138 ctmp->var = &sig_act_var;
4139 ctmp->valoffset = roindent;
4140 if(F_ON(F_DISABLE_ROLES_SIGEDIT, ps_global))
4141 ctmp->keymenu = &config_role_file_res_keymenu;
4142 else
4143 ctmp->keymenu = &config_role_file_keymenu;
4145 ctmp->help = h_config_role_setsig;
4146 ctmp->tool = role_text_tool;
4147 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, sig_act_var.name);
4148 tmp[sizeof(tmp)-1] = '\0';
4149 ctmp->varname = cpystr(tmp);
4150 ctmp->varnamep = ctmp;
4152 /* Template Action */
4153 new_confline(&ctmp);
4154 inick_confs[INICK_TEMPL_CONF] = ctmp;
4155 ctmp->help_title= _("HELP FOR SET TEMPLATE ACTION");
4156 ctmp->var = &templ_act_var;
4157 ctmp->valoffset = roindent;
4158 if(F_ON(F_DISABLE_ROLES_TEMPLEDIT, ps_global))
4159 ctmp->keymenu = &config_role_file_res_keymenu;
4160 else
4161 ctmp->keymenu = &config_role_file_keymenu;
4163 ctmp->help = h_config_role_settempl;
4164 ctmp->tool = role_text_tool;
4165 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, templ_act_var.name);
4166 tmp[sizeof(tmp)-1] = '\0';
4167 ctmp->varname = cpystr(tmp);
4168 ctmp->varnamep = ctmp;
4170 /* Other Headers Action */
4171 new_confline(&ctmp);
4172 inick_confs[INICK_CSTM_CONF] = ctmp;
4173 ctmp->help_title= _("HELP FOR SET OTHER HEADERS ACTION");
4174 ctmp->var = &cstm_act_var;
4175 ctmp->valoffset = roindent;
4176 ctmp->keymenu = &config_text_wshuf_keymenu;
4177 ctmp->help = h_config_role_setotherhdr;
4178 ctmp->tool = role_cstm_text_tool;
4179 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, cstm_act_var.name);
4180 tmp[sizeof(tmp)-1] = '\0';
4181 ctmp->varname = cpystr(tmp);
4182 ctmp->varnamep = ctmpb = ctmp;
4183 ctmp->flags = CF_STARTITEM;
4185 if((lval = LVAL(&cstm_act_var, ew)) != NULL){
4186 for(i = 0; lval[i]; i++){
4187 if(i)
4188 (void)new_confline(&ctmp);
4190 ctmp->var = &cstm_act_var;
4191 ctmp->varmem = i;
4192 ctmp->valoffset = roindent;
4193 ctmp->keymenu = &config_text_wshuf_keymenu;
4194 ctmp->help = h_config_role_setotherhdr;
4195 ctmp->tool = role_cstm_text_tool;
4196 ctmp->varnamep = ctmpb;
4199 else
4200 ctmp->varmem = 0;
4202 /* SMTP Server Action */
4203 new_confline(&ctmp);
4204 inick_confs[INICK_SMTP_CONF] = ctmp;
4205 ctmp->help_title= _("HELP FOR SMTP SERVER ACTION");
4206 ctmp->var = &smtp_act_var;
4207 ctmp->valoffset = roindent;
4208 ctmp->keymenu = &config_text_wshuf_keymenu;
4209 ctmp->help = h_config_role_usesmtp;
4210 ctmp->tool = t_tool;
4211 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, smtp_act_var.name);
4212 tmp[sizeof(tmp)-1] = '\0';
4213 ctmp->varname = cpystr(tmp);
4214 ctmp->varnamep = ctmpb = ctmp;
4215 ctmp->flags = CF_STARTITEM;
4217 if((lval = LVAL(&smtp_act_var, ew)) != NULL){
4218 for(i = 0; lval[i]; i++){
4219 if(i)
4220 (void)new_confline(&ctmp);
4222 ctmp->var = &smtp_act_var;
4223 ctmp->varmem = i;
4224 ctmp->valoffset = roindent;
4225 ctmp->keymenu = &config_text_wshuf_keymenu;
4226 ctmp->help = h_config_role_usesmtp;
4227 ctmp->tool = t_tool;
4228 ctmp->varnamep = ctmpb;
4231 else
4232 ctmp->varmem = 0;
4234 /* NNTP Server Action */
4235 new_confline(&ctmp);
4236 inick_confs[INICK_NNTP_CONF] = ctmp;
4237 ctmp->help_title= _("HELP FOR NNTP SERVER ACTION");
4238 ctmp->var = &nntp_act_var;
4239 ctmp->valoffset = roindent;
4240 ctmp->keymenu = &config_text_wshuf_keymenu;
4241 ctmp->help = h_config_role_usenntp;
4242 ctmp->tool = t_tool;
4243 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, nntp_act_var.name);
4244 tmp[sizeof(tmp)-1] = '\0';
4245 ctmp->varname = cpystr(tmp);
4246 ctmp->varnamep = ctmpb = ctmp;
4247 ctmp->flags = CF_STARTITEM;
4249 if((lval = LVAL(&nntp_act_var, ew)) != NULL){
4250 for(i = 0; lval[i]; i++){
4251 if(i)
4252 (void)new_confline(&ctmp);
4254 ctmp->var = &nntp_act_var;
4255 ctmp->varmem = i;
4256 ctmp->valoffset = roindent;
4257 ctmp->keymenu = &config_text_wshuf_keymenu;
4258 ctmp->help = h_config_role_usenntp;
4259 ctmp->tool = t_tool;
4260 ctmp->varnamep = ctmpb;
4263 else
4264 ctmp->varmem = 0;
4266 calculate_inick_stuff(ps);
4268 else
4269 inick_confs[INICK_INICK_CONF] = NULL;
4271 if(edit_score){
4272 int sindent;
4274 sindent = MAX(utf8_width(score_act_var.name),utf8_width(hdrtok_act_var.name)) + 3;
4276 /* Blank line */
4277 new_confline(&ctmp);
4278 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4280 /* Score Value -- This doesn't inherit from inick */
4281 new_confline(&ctmp);
4282 ctmp->help_title= _("HELP FOR SCORE VALUE ACTION");
4283 ctmp->var = &score_act_var;
4284 ctmp->valoffset = sindent;
4285 ctmp->keymenu = &config_text_keymenu;
4286 ctmp->help = h_config_role_scoreval;
4287 ctmp->tool = text_tool;
4288 ctmp->flags |= CF_NUMBER;
4289 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", sindent-3, sindent-3, score_act_var.name);
4290 tmp[sizeof(tmp)-1] = '\0';
4291 ctmp->varname = cpystr(tmp);
4292 ctmp->varnamep = ctmp;
4293 ctmp->value = pretty_value(ps, ctmp);
4295 new_confline(&ctmp);
4296 ctmp->flags |= CF_NOSELECT;
4297 ctmp->value = cpystr(" OR");
4299 /* Score From Header */
4300 new_confline(&ctmp);
4301 ctmp->help_title= _("HELP FOR SCORE VALUE FROM HEADER ACTION");
4302 ctmp->var = &hdrtok_act_var;
4303 ctmp->valoffset = sindent;
4304 ctmp->keymenu = &config_text_keymenu;
4305 ctmp->help = h_config_role_scorehdrtok;
4306 ctmp->tool = text_tool;
4307 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", sindent-3, sindent-3, hdrtok_act_var.name);
4308 tmp[sizeof(tmp)-1] = '\0';
4309 ctmp->varname = cpystr(tmp);
4310 ctmp->varnamep = ctmp;
4311 ctmp->value = pretty_value(ps, ctmp);
4314 if(edit_filter){
4316 * Filtering got added in stages, so instead of simply having a
4317 * variable in action which is set to one of the three possible
4318 * values (FILTER_KILL, FILTER_STATE, FILTER_FOLDER) we infer
4319 * the value from other variables. (Perhaps it would still make
4320 * sense to change this.)
4321 * Action->kill is set iff the user checks Delete.
4322 * If the user checks the box that says Just Set State, then kill
4323 * is not set and action->folder is not set (and vice versa).
4324 * And finally, FILTER_FOLDER is set if !kill and action->folder is set.
4325 * (And it is set here as the default if there is no default
4326 * action and the user is required to fill in the Folder.)
4328 if(def && def->action && def->action->kill)
4329 fval = FILTER_KILL;
4330 else if(def && def->action && !def->action->kill &&
4331 !def->action->folder)
4332 fval = FILTER_STATE;
4333 else
4334 fval = FILTER_FOLDER;
4336 role_filt_ptr = &filter_type_var; /* so radiobuttons can tell */
4337 filter_type_var.name = cpystr(_("Filter Action"));
4338 filter_type_var.is_used = 1;
4339 filter_type_var.is_user = 1;
4340 apval = APVAL(&filter_type_var, ew);
4341 *apval = (f=filter_types(fval)) ? cpystr(f->name) : NULL;
4342 set_current_val(&filter_type_var, FALSE, FALSE);
4344 /* Blank line */
4345 new_confline(&ctmp);
4346 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4348 /* Filter Type */
4349 new_confline(&ctmp);
4350 ctmp->var = &filter_type_var;
4351 ctmp->keymenu = &config_radiobutton_keymenu;
4352 ctmp->help = NO_HELP;
4353 ctmp->tool = NULL;
4354 snprintf(tmp, sizeof(tmp), "%s =", filter_type_var.name);
4355 tmp[sizeof(tmp)-1] = '\0';
4356 ctmp->varname = cpystr(tmp);
4357 ctmp->varnamep = ctmpb = ctmp;
4358 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM);
4360 new_confline(&ctmp);
4361 ctmp->var = NULL;
4362 ctmp->valoffset = rindent;
4363 ctmp->keymenu = &config_radiobutton_keymenu;
4364 ctmp->help = NO_HELP;
4365 ctmp->tool = NULL;
4366 ctmp->varnamep = ctmpb;
4367 ctmp->flags |= CF_NOSELECT;
4368 ctmp->value = cpystr("Set Choose One");
4370 new_confline(&ctmp);
4371 ctmp->var = NULL;
4372 ctmp->valoffset = rindent;
4373 ctmp->keymenu = &config_radiobutton_keymenu;
4374 ctmp->help = NO_HELP;
4375 ctmp->tool = radio_tool;
4376 ctmp->varnamep = ctmpb;
4377 ctmp->flags |= CF_NOSELECT;
4378 ctmp->value = cpystr(set_choose); \
4380 /* find longest value's name */
4381 for(lv = 0, i = 0; (f = filter_types(i)); i++)
4382 if(lv < (j = utf8_width(f->name)))
4383 lv = j;
4385 lv = MIN(lv, 100);
4387 for(i = 0; (f = filter_types(i)); i++){
4388 new_confline(&ctmp);
4389 ctmp->help_title= _("HELP FOR FILTER ACTION");
4390 ctmp->var = &filter_type_var;
4391 ctmp->valoffset = rindent;
4392 ctmp->keymenu = &config_radiobutton_keymenu;
4393 ctmp->help = h_config_filt_rule_type;
4394 ctmp->varmem = i;
4395 ctmp->tool = radio_tool;
4396 ctmp->varnamep = ctmpb;
4397 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", (f->value == fval) ? R_SELD : ' ',
4398 lv, lv, f->name);
4399 tmp[sizeof(tmp)-1] = '\0';
4400 ctmp->value = cpystr(tmp);
4403 /* Specific list of folders to copy to */
4404 setup_dummy_pattern_var(&folder_act_var, _("Folder List"),
4405 (def && def->action)
4406 ? def->action->folder : NULL);
4408 /* 5 is the width of `(*) ' */
4409 setup_role_pat_alt(ps, &ctmp, &folder_act_var, h_config_filter_folder,
4410 _("HELP FOR FILTER FOLDER NAME"),
4411 &config_role_actionfolder_keymenu, t_tool, rindent+5,
4412 !(fval == FILTER_FOLDER));
4414 SETUP_MSG_STATE(ctmp, filt_imp_var, ival,
4415 _("HELP FOR SET IMPORTANT STATUS"), h_config_filt_stat_imp);
4416 SETUP_MSG_STATE(ctmp, filt_new_var, nval,
4417 _("HELP FOR SET NEW STATUS"), h_config_filt_stat_new);
4418 SETUP_MSG_STATE(ctmp, filt_del_var, dval,
4419 _("HELP FOR SET DELETED STATUS"), h_config_filt_stat_del);
4420 SETUP_MSG_STATE(ctmp, filt_ans_var, aval,
4421 _("HELP FOR SET ANSWERED STATUS"), h_config_filt_stat_ans);
4423 /* Blank line */
4424 new_confline(&ctmp);
4425 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4427 /* Keywords to be Set */
4428 setup_dummy_pattern_var(&keyword_set_var, _("Set These Keywords"),
4429 (def && def->action)
4430 ? def->action->keyword_set : NULL);
4431 setup_role_pat(ps, &ctmp, &keyword_set_var, h_config_filter_kw_set,
4432 _("HELP FOR KEYWORDS TO BE SET"),
4433 &config_role_keyword_keymenu, role_text_tool_kword,
4434 NULL, 23);
4436 /* Keywords to be Cleared */
4437 setup_dummy_pattern_var(&keyword_clr_var, _("Clear These Keywords"),
4438 (def && def->action)
4439 ? def->action->keyword_clr : NULL);
4440 setup_role_pat(ps, &ctmp, &keyword_clr_var, h_config_filter_kw_clr,
4441 _("HELP FOR KEYWORDS TO BE CLEARED"),
4442 &config_role_keyword_keymenu, role_text_tool_kword,
4443 NULL, 23);
4446 if(edit_other){
4447 char *pval;
4448 int oindent;
4450 /* Blank line */
4451 new_confline(&ctmp);
4452 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4454 new_confline(&ctmp)->var = NULL;
4455 snprintf(tmp, sizeof(tmp), "%s =", sort_act_var.name);
4456 tmp[sizeof(tmp)-1] = '\0';
4457 ctmp->varname = cpystr(tmp);
4458 ctmp->varnamep = ctmpb = ctmp;
4459 ctmp->keymenu = &config_radiobutton_keymenu;
4460 ctmp->help = NO_HELP;
4461 ctmp->tool = role_sort_tool;
4462 ctmp->valoffset = rindent;
4463 ctmp->flags |= CF_NOSELECT;
4465 new_confline(&ctmp)->var = NULL;
4466 ctmp->varnamep = ctmpb;
4467 ctmp->keymenu = &config_radiobutton_keymenu;
4468 ctmp->help = NO_HELP;
4469 ctmp->tool = role_sort_tool;
4470 ctmp->valoffset = rindent;
4471 ctmp->flags |= CF_NOSELECT;
4472 ctmp->value = cpystr("Set Sort Options");
4474 new_confline(&ctmp)->var = NULL;
4475 ctmp->varnamep = ctmpb;
4476 ctmp->keymenu = &config_radiobutton_keymenu;
4477 ctmp->help = NO_HELP;
4478 ctmp->tool = role_sort_tool;
4479 ctmp->valoffset = rindent;
4480 ctmp->flags |= CF_NOSELECT;
4481 ctmp->value = cpystr(set_choose); \
4483 pval = PVAL(&sort_act_var, ew);
4484 if(pval)
4485 decode_sort(pval, &def_sort, &def_sort_rev);
4487 /* allow user to set their default sort order */
4488 new_confline(&ctmp)->var = &sort_act_var;
4489 ctmp->varnamep = ctmpb;
4490 ctmp->keymenu = &config_radiobutton_keymenu;
4491 ctmp->help = h_config_perfolder_sort;
4492 ctmp->tool = role_sort_tool;
4493 ctmp->valoffset = rindent;
4494 ctmp->varmem = -1;
4495 ctmp->value = generalized_sort_pretty_value(ps, ctmp, 0);
4497 for(j = 0; j < 2; j++){
4498 for(i = 0; ps->sort_types[i] != EndofList; i++){
4499 new_confline(&ctmp)->var = &sort_act_var;
4500 ctmp->varnamep = ctmpb;
4501 ctmp->keymenu = &config_radiobutton_keymenu;
4502 ctmp->help = h_config_perfolder_sort;
4503 ctmp->tool = role_sort_tool;
4504 ctmp->valoffset = rindent;
4505 ctmp->varmem = i + (j * EndofList);
4506 ctmp->value = generalized_sort_pretty_value(ps, ctmp,
4512 /* Blank line */
4513 new_confline(&ctmp);
4514 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4516 oindent = utf8_width(iform_act_var.name) + 3;
4518 /* Index Format Action */
4519 new_confline(&ctmp);
4520 ctmp->help_title= _("HELP FOR SET INDEX FORMAT ACTION");
4521 ctmp->var = &iform_act_var;
4522 ctmp->valoffset = oindent;
4523 ctmp->keymenu = &config_text_keymenu;
4524 ctmp->help = h_config_set_index_format;
4525 ctmp->tool = text_tool;
4526 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", oindent-3, oindent-3, iform_act_var.name);
4527 tmp[sizeof(tmp)-1] = '\0';
4528 ctmp->varname = cpystr(tmp);
4529 ctmp->varnamep = ctmp;
4530 ctmp->value = pretty_value(ps, ctmp);
4532 /* Blank line */
4533 new_confline(&ctmp);
4534 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4536 new_confline(&ctmp);
4537 ctmp->flags |= CF_STARTITEM;
4538 utf8_snprintf(tmp, sizeof(tmp), "%s =", startup_var.name);
4539 tmp[sizeof(tmp)-1] = '\0';
4540 ctmp->varname = cpystr(tmp);
4541 standard_radio_setup(ps, &ctmp, &startup_var, NULL);
4544 if(edit_incol && pico_usingcolor()){
4545 char *pval0, *pval1;
4546 int def;
4548 /* Blank line */
4549 new_confline(&ctmp);
4550 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4552 new_confline(&ctmp);
4553 ctmp->var = &rolecolor_vars[0]; /* foreground */
4554 ctmp->varname = cpystr(_("Index Line Color ="));
4555 ctmp->varnamep = ctmpb = ctmp;
4556 ctmp->flags |= (CF_STARTITEM | CF_NOSELECT);
4557 ctmp->keymenu = &role_color_setting_keymenu;
4559 pval0 = PVAL(&rolecolor_vars[0], ew);
4560 pval1 = PVAL(&rolecolor_vars[1], ew);
4561 if(pval0 && pval1)
4562 def = !(pval0[0] && pval1[1]);
4563 else
4564 def = 1;
4566 add_color_setting_disp(ps, &ctmp, &rolecolor_vars[0], ctmpb,
4567 &role_color_setting_keymenu,
4568 &config_checkbox_keymenu,
4569 h_config_incol,
4570 rindent, 0,
4571 def ? ps->VAR_NORM_FORE_COLOR
4572 : PVAL(&rolecolor_vars[0], ew),
4573 def ? ps->VAR_NORM_BACK_COLOR
4574 : PVAL(&rolecolor_vars[1], ew),
4575 def);
4579 if(need_options){
4580 /* Options */
4582 /* Blank line */
4583 new_confline(&ctmp);
4584 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4586 new_confline(&ctmp);
4587 ctmp->flags |= CF_NOSELECT;
4588 if(ps->ttyo->screen_cols >= (wid=utf8_width(ostr)) + 4){
4589 int dashes;
4591 dashes = (ps->ttyo->screen_cols - wid)/2;
4592 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='),
4593 ostr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '='));
4594 ctmp->value = cpystr(tmp_20k_buf);
4596 else
4597 ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '='));
4599 /* Blank line */
4600 new_confline(&ctmp);
4601 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4603 opt_var.name = cpystr(_("Features"));
4604 opt_var.is_used = 1;
4605 opt_var.is_user = 1;
4606 opt_var.is_list = 1;
4607 clrbitmap(feat_option_list);
4608 if(def && def->patgrp && def->patgrp->age_uses_sentdate)
4609 setbitn(FEAT_SENTDATE, feat_option_list);
4611 if(edit_filter){
4612 if(def && def->action && def->action->move_only_if_not_deleted)
4613 setbitn(FEAT_IFNOTDEL, feat_option_list);
4614 if(def && def->action && def->action->non_terminating)
4615 setbitn(FEAT_NONTERM, feat_option_list);
4618 /* Options */
4619 new_confline(&ctmp);
4620 ctmp->var = &opt_var;
4621 ctmp->valoffset = 23;
4622 ctmp->keymenu = &config_checkbox_keymenu;
4623 ctmp->help = NO_HELP;
4624 ctmp->tool = NULL;
4625 snprintf(tmp, sizeof(tmp), "%-20s =", opt_var.name);
4626 tmp[sizeof(tmp)-1] = '\0';
4627 ctmp->varname = cpystr(tmp);
4628 ctmp->varnamep = ctmpb = ctmp;
4629 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM);
4631 new_confline(&ctmp);
4632 ctmp->var = NULL;
4633 ctmp->valoffset = rindent;
4634 ctmp->keymenu = &config_checkbox_keymenu;
4635 ctmp->help = NO_HELP;
4636 ctmp->tool = feat_checkbox_tool;
4637 ctmp->varnamep = ctmpb;
4638 ctmp->flags |= CF_NOSELECT;
4639 ctmp->value = cpystr("Set Feature Name");
4641 new_confline(&ctmp);
4642 ctmp->var = NULL;
4643 ctmp->valoffset = rindent;
4644 ctmp->keymenu = &config_checkbox_keymenu;
4645 ctmp->help = NO_HELP;
4646 ctmp->tool = feat_checkbox_tool;
4647 ctmp->varnamep = ctmpb;
4648 ctmp->flags |= CF_NOSELECT;
4649 ctmp->value = cpystr(set_choose); \
4651 /* find longest value's name */
4652 for(lv = 0, i = 0; (f = feat_feature_list(i)); i++){
4653 if(!edit_filter && (i == FEAT_IFNOTDEL || i == FEAT_NONTERM))
4654 continue;
4656 if(lv < (j = utf8_width(f->name)))
4657 lv = j;
4660 lv = MIN(lv, 100);
4662 for(i = 0; (f = feat_feature_list(i)); i++){
4663 if(!edit_filter && (i == FEAT_IFNOTDEL || i == FEAT_NONTERM))
4664 continue;
4666 new_confline(&ctmp);
4667 ctmp->var = &opt_var;
4668 ctmp->help_title= _("HELP FOR FILTER FEATURES");
4669 ctmp->varnamep = ctmpb;
4670 ctmp->keymenu = &config_checkbox_keymenu;
4671 switch(i){
4672 case FEAT_SENTDATE:
4673 ctmp->help = h_config_filt_opts_sentdate;
4674 break;
4675 case FEAT_IFNOTDEL:
4676 ctmp->help = h_config_filt_opts_notdel;
4677 break;
4678 case FEAT_NONTERM:
4679 ctmp->help = h_config_filt_opts_nonterm;
4680 break;
4683 ctmp->tool = feat_checkbox_tool;
4684 ctmp->valoffset = rindent;
4685 ctmp->varmem = i;
4686 utf8_snprintf(tmp, sizeof(tmp), "[%c] %-*.*w",
4687 bitnset(f->value, feat_option_list) ? 'X' : ' ',
4688 lv, lv, f->name);
4689 tmp[sizeof(tmp)-1] = '\0';
4690 ctmp->value = cpystr(tmp);
4694 if(need_uses){
4695 /* Uses */
4697 /* Blank line */
4698 new_confline(&ctmp);
4699 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4701 new_confline(&ctmp);
4702 ctmp->flags |= CF_NOSELECT;
4703 if(ps->ttyo->screen_cols >= (wid=utf8_width(ustr)) + 4){
4704 int dashes;
4706 dashes = (ps->ttyo->screen_cols - wid)/2;
4707 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='),
4708 ustr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '='));
4709 ctmp->value = cpystr(tmp_20k_buf);
4711 else
4712 ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '='));
4714 /* Blank line */
4715 new_confline(&ctmp);
4716 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4718 /* Reply Type */
4719 new_confline(&ctmp);
4720 ctmp->var = &repl_type_var;
4721 ctmp->keymenu = &config_radiobutton_keymenu;
4722 ctmp->help = NO_HELP;
4723 ctmp->tool = NULL;
4724 snprintf(tmp, sizeof(tmp), "%s =", repl_type_var.name);
4725 tmp[sizeof(tmp)-1] = '\0';
4726 ctmp->varname = cpystr(tmp);
4727 ctmp->varnamep = ctmpb = ctmp;
4728 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM);
4730 new_confline(&ctmp);
4731 ctmp->var = NULL;
4732 ctmp->valoffset = rindent;
4733 ctmp->keymenu = &config_radiobutton_keymenu;
4734 ctmp->help = NO_HELP;
4735 ctmp->tool = NULL;
4736 ctmp->varnamep = ctmpb;
4737 ctmp->flags |= CF_NOSELECT;
4738 ctmp->value = cpystr("Set Choose One");
4740 new_confline(&ctmp);
4741 ctmp->var = NULL;
4742 ctmp->valoffset = rindent;
4743 ctmp->keymenu = &config_radiobutton_keymenu;
4744 ctmp->help = NO_HELP;
4745 ctmp->tool = radio_tool;
4746 ctmp->varnamep = ctmpb;
4747 ctmp->flags |= CF_NOSELECT;
4748 ctmp->value = cpystr(set_choose); \
4750 /* find longest value's name */
4751 for(lv = 0, i = 0; (f = role_repl_types(i)); i++)
4752 if(lv < (j = utf8_width(f->name)))
4753 lv = j;
4755 lv = MIN(lv, 100);
4757 for(i = 0; (f = role_repl_types(i)); i++){
4758 new_confline(&ctmp);
4759 ctmp->help_title= _("HELP FOR ROLE REPLY USE");
4760 ctmp->var = &repl_type_var;
4761 ctmp->valoffset = rindent;
4762 ctmp->keymenu = &config_radiobutton_keymenu;
4763 ctmp->help = h_config_role_replyuse;
4764 ctmp->varmem = i;
4765 ctmp->tool = radio_tool;
4766 ctmp->varnamep = ctmpb;
4767 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", (((!(def && def->action) ||
4768 def->action->repl_type == -1) &&
4769 f->value == ROLE_REPL_DEFL) ||
4770 (def && def->action &&
4771 f->value == def->action->repl_type))
4772 ? R_SELD : ' ',
4773 lv, lv, f->name);
4774 tmp[sizeof(tmp)-1] = '\0';
4775 ctmp->value = cpystr(tmp);
4778 /* Blank line */
4779 new_confline(&ctmp);
4780 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4782 /* Forward Type */
4783 new_confline(&ctmp);
4784 ctmp->var = &forw_type_var;
4785 ctmp->keymenu = &config_radiobutton_keymenu;
4786 ctmp->help = NO_HELP;
4787 ctmp->tool = NULL;
4788 snprintf(tmp, sizeof(tmp), "%s =", forw_type_var.name);
4789 tmp[sizeof(tmp)-1] = '\0';
4790 ctmp->varname = cpystr(tmp);
4791 ctmp->varnamep = ctmpb = ctmp;
4792 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM);
4794 new_confline(&ctmp);
4795 ctmp->var = NULL;
4796 ctmp->valoffset = rindent;
4797 ctmp->keymenu = &config_radiobutton_keymenu;
4798 ctmp->help = NO_HELP;
4799 ctmp->tool = NULL;
4800 ctmp->varnamep = ctmpb;
4801 ctmp->flags |= CF_NOSELECT;
4802 ctmp->value = cpystr("Set Choose One");
4804 new_confline(&ctmp);
4805 ctmp->var = NULL;
4806 ctmp->valoffset = rindent;
4807 ctmp->keymenu = &config_radiobutton_keymenu;
4808 ctmp->help = NO_HELP;
4809 ctmp->tool = radio_tool;
4810 ctmp->varnamep = ctmpb;
4811 ctmp->flags |= CF_NOSELECT;
4812 ctmp->value = cpystr(set_choose); \
4814 /* find longest value's name */
4815 for(lv = 0, i = 0; (f = role_forw_types(i)); i++)
4816 if(lv < (j = utf8_width(f->name)))
4817 lv = j;
4819 lv = MIN(lv, 100);
4821 for(i = 0; (f = role_forw_types(i)); i++){
4822 new_confline(&ctmp);
4823 ctmp->help_title= _("HELP FOR ROLE FORWARD USE");
4824 ctmp->var = &forw_type_var;
4825 ctmp->valoffset = rindent;
4826 ctmp->keymenu = &config_radiobutton_keymenu;
4827 ctmp->help = h_config_role_forwarduse;
4828 ctmp->varmem = i;
4829 ctmp->tool = radio_tool;
4830 ctmp->varnamep = ctmpb;
4831 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", (((!(def && def->action) ||
4832 def->action->forw_type == -1) &&
4833 f->value == ROLE_FORW_DEFL) ||
4834 (def && def->action &&
4835 f->value == def->action->forw_type))
4836 ? R_SELD : ' ',
4837 lv, lv, f->name);
4838 tmp[sizeof(tmp)-1] = '\0';
4839 ctmp->value = cpystr(tmp);
4842 /* Blank line */
4843 new_confline(&ctmp);
4844 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
4846 /* Compose Type */
4847 new_confline(&ctmp);
4848 ctmp->var = &comp_type_var;
4849 ctmp->keymenu = &config_radiobutton_keymenu;
4850 ctmp->help = NO_HELP;
4851 ctmp->tool = NULL;
4852 snprintf(tmp, sizeof(tmp), "%s =", comp_type_var.name);
4853 tmp[sizeof(tmp)-1] = '\0';
4854 ctmp->varname = cpystr(tmp);
4855 ctmp->varnamep = ctmpb = ctmp;
4856 ctmp->flags |= (CF_NOSELECT | CF_STARTITEM);
4858 new_confline(&ctmp);
4859 ctmp->var = NULL;
4860 ctmp->valoffset = rindent;
4861 ctmp->keymenu = &config_radiobutton_keymenu;
4862 ctmp->help = NO_HELP;
4863 ctmp->tool = NULL;
4864 ctmp->varnamep = ctmpb;
4865 ctmp->flags |= CF_NOSELECT;
4866 ctmp->value = cpystr("Set Choose One");
4868 new_confline(&ctmp);
4869 ctmp->var = NULL;
4870 ctmp->valoffset = rindent;
4871 ctmp->keymenu = &config_radiobutton_keymenu;
4872 ctmp->help = NO_HELP;
4873 ctmp->tool = radio_tool;
4874 ctmp->varnamep = ctmpb;
4875 ctmp->flags |= CF_NOSELECT;
4876 ctmp->value = cpystr(set_choose); \
4878 /* find longest value's name */
4879 for(lv = 0, i = 0; (f = role_comp_types(i)); i++)
4880 if(lv < (j = utf8_width(f->name)))
4881 lv = j;
4883 lv = MIN(lv, 100);
4885 for(i = 0; (f = role_comp_types(i)); i++){
4886 new_confline(&ctmp);
4887 ctmp->help_title= _("HELP FOR ROLE COMPOSE USE");
4888 ctmp->var = &comp_type_var;
4889 ctmp->valoffset = rindent;
4890 ctmp->keymenu = &config_radiobutton_keymenu;
4891 ctmp->help = h_config_role_composeuse;
4892 ctmp->varmem = i;
4893 ctmp->tool = radio_tool;
4894 ctmp->varnamep = ctmpb;
4895 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w", (((!(def && def->action) ||
4896 def->action->comp_type == -1) &&
4897 f->value == ROLE_COMP_DEFL) ||
4898 (def && def->action &&
4899 f->value == def->action->comp_type))
4900 ? R_SELD : ' ',
4901 lv, lv, f->name);
4902 tmp[sizeof(tmp)-1] = '\0';
4903 ctmp->value = cpystr(tmp);
4907 memset(&screen, 0, sizeof(screen));
4908 screen.ro_warning = saved_screen ? saved_screen->deferred_ro_warning : 0;
4909 /* TRANSLATORS: Print something1 using something2.
4910 "roles" is something1 */
4911 rv = conf_scroll_screen(ps, &screen, first_line, title, _("roles"),
4912 (edit_incol && pico_usingcolor()) ? 1 : 0, NULL);
4915 * Now look at the fake variables and extract the information we
4916 * want from them.
4919 if(rv == 1 && result){
4921 * We know these variables exist, so we don't have to check that
4922 * apval is nonnull before evaluating *apval.
4924 apval = APVAL(&nick_var, ew);
4925 nick = *apval;
4926 *apval = NULL;
4927 removing_leading_and_trailing_white_space(nick);
4929 apval = APVAL(&comment_var, ew);
4930 comment = *apval;
4931 *apval = NULL;
4932 removing_leading_and_trailing_white_space(comment);
4934 alval = ALVAL(&to_pat_var, ew);
4935 to_pat = *alval;
4936 *alval = NULL;
4938 alval = ALVAL(&from_pat_var, ew);
4939 from_pat = *alval;
4940 *alval = NULL;
4942 alval = ALVAL(&sender_pat_var, ew);
4943 sender_pat = *alval;
4944 *alval = NULL;
4946 alval = ALVAL(&cc_pat_var, ew);
4947 cc_pat = *alval;
4948 *alval = NULL;
4950 alval = ALVAL(&recip_pat_var, ew);
4951 recip_pat = *alval;
4952 *alval = NULL;
4954 alval = ALVAL(&partic_pat_var, ew);
4955 partic_pat = *alval;
4956 *alval = NULL;
4958 alval = ALVAL(&news_pat_var, ew);
4959 news_pat = *alval;
4960 *alval = NULL;
4962 alval = ALVAL(&subj_pat_var, ew);
4963 subj_pat = *alval;
4964 *alval = NULL;
4966 alval = ALVAL(&alltext_pat_var, ew);
4967 alltext_pat = *alval;
4968 *alval = NULL;
4970 alval = ALVAL(&bodytext_pat_var, ew);
4971 bodytext_pat = *alval;
4972 *alval = NULL;
4974 alval = ALVAL(&keyword_pat_var, ew);
4975 keyword_pat = *alval;
4976 *alval = NULL;
4978 alval = ALVAL(&charset_pat_var, ew);
4979 charset_pat = *alval;
4980 *alval = NULL;
4982 apval = APVAL(&age_pat_var, ew);
4983 age_pat = *apval;
4984 *apval = NULL;
4985 removing_leading_and_trailing_white_space(age_pat);
4987 apval = APVAL(&size_pat_var, ew);
4988 size_pat = *apval;
4989 *apval = NULL;
4990 removing_leading_and_trailing_white_space(size_pat);
4992 apval = APVAL(&scorei_pat_var, ew);
4993 scorei_pat = *apval;
4994 *apval = NULL;
4995 removing_leading_and_trailing_white_space(scorei_pat);
4997 apval = APVAL(&stat_del_var, ew);
4998 stat_del = *apval;
4999 *apval = NULL;
5000 removing_leading_and_trailing_white_space(stat_del);
5002 apval = APVAL(&stat_new_var, ew);
5003 stat_new = *apval;
5004 *apval = NULL;
5005 removing_leading_and_trailing_white_space(stat_new);
5007 apval = APVAL(&stat_rec_var, ew);
5008 stat_rec = *apval;
5009 *apval = NULL;
5010 removing_leading_and_trailing_white_space(stat_rec);
5012 apval = APVAL(&stat_imp_var, ew);
5013 stat_imp = *apval;
5014 *apval = NULL;
5015 removing_leading_and_trailing_white_space(stat_imp);
5017 apval = APVAL(&stat_ans_var, ew);
5018 stat_ans = *apval;
5019 *apval = NULL;
5020 removing_leading_and_trailing_white_space(stat_ans);
5022 apval = APVAL(&stat_8bit_var, ew);
5023 stat_8bit = *apval;
5024 *apval = NULL;
5025 removing_leading_and_trailing_white_space(stat_8bit);
5027 apval = APVAL(&stat_bom_var, ew);
5028 stat_bom = *apval;
5029 *apval = NULL;
5030 removing_leading_and_trailing_white_space(stat_bom);
5032 apval = APVAL(&stat_boy_var, ew);
5033 stat_boy = *apval;
5034 *apval = NULL;
5035 removing_leading_and_trailing_white_space(stat_boy);
5037 apval = APVAL(&fldr_type_var, ew);
5038 fldr_type_pat = *apval;
5039 *apval = NULL;
5040 removing_leading_and_trailing_white_space(fldr_type_pat);
5042 alval = ALVAL(&folder_pat_var, ew);
5043 folder_pat = *alval;
5044 *alval = NULL;
5046 apval = APVAL(&abook_type_var, ew);
5047 abook_type_pat = *apval;
5048 *apval = NULL;
5049 removing_leading_and_trailing_white_space(abook_type_pat);
5051 alval = ALVAL(&abook_pat_var, ew);
5052 abook_pat = *alval;
5053 *alval = NULL;
5055 apval = APVAL(&cati_var, ew);
5056 cati = *apval;
5057 *apval = NULL;
5058 removing_leading_and_trailing_white_space(cati);
5060 apval = APVAL(&cat_lim_var, ew);
5061 cat_lim = *apval;
5062 *apval = NULL;
5063 removing_leading_and_trailing_white_space(cat_lim);
5065 apval = APVAL(&inick_var, ew);
5066 inick = *apval;
5067 *apval = NULL;
5068 removing_leading_and_trailing_white_space(inick);
5070 apval = APVAL(&from_act_var, ew);
5071 from_act = *apval;
5072 *apval = NULL;
5073 removing_leading_and_trailing_white_space(from_act);
5075 apval = APVAL(&replyto_act_var, ew);
5076 replyto_act = *apval;
5077 *apval = NULL;
5078 removing_leading_and_trailing_white_space(replyto_act);
5080 apval = APVAL(&fcc_act_var, ew);
5081 fcc_act = *apval;
5082 *apval = NULL;
5083 removing_leading_and_trailing_white_space(fcc_act);
5085 apval = APVAL(&litsig_act_var, ew);
5086 litsig_act = *apval;
5087 *apval = NULL;
5088 removing_leading_and_trailing_white_space(litsig_act);
5090 apval = APVAL(&sort_act_var, ew);
5091 sort_act = *apval;
5092 *apval = NULL;
5093 removing_leading_and_trailing_white_space(sort_act);
5095 apval = APVAL(&iform_act_var, ew);
5096 iform_act = *apval;
5097 *apval = NULL;
5098 removing_leading_and_trailing_white_space(iform_act);
5100 apval = APVAL(&startup_var, ew);
5101 startup_act = *apval;
5102 *apval = NULL;
5103 removing_leading_and_trailing_white_space(startup_act);
5105 apval = APVAL(&sig_act_var, ew);
5106 sig_act = *apval;
5107 *apval = NULL;
5108 removing_leading_and_trailing_white_space(sig_act);
5110 apval = APVAL(&templ_act_var, ew);
5111 templ_act = *apval;
5112 *apval = NULL;
5113 removing_leading_and_trailing_white_space(templ_act);
5115 apval = APVAL(&score_act_var, ew);
5116 score_act = *apval;
5117 *apval = NULL;
5118 removing_leading_and_trailing_white_space(score_act);
5120 apval = APVAL(&hdrtok_act_var, ew);
5121 hdrtok_act = *apval;
5122 *apval = NULL;
5123 removing_leading_and_trailing_white_space(hdrtok_act);
5125 apval = APVAL(&repl_type_var, ew);
5126 repl_type = *apval;
5127 *apval = NULL;
5128 removing_leading_and_trailing_white_space(repl_type);
5130 apval = APVAL(&forw_type_var, ew);
5131 forw_type = *apval;
5132 *apval = NULL;
5133 removing_leading_and_trailing_white_space(forw_type);
5135 apval = APVAL(&comp_type_var, ew);
5136 comp_type = *apval;
5137 *apval = NULL;
5138 removing_leading_and_trailing_white_space(comp_type);
5140 apval = APVAL(&rolecolor_vars[0], ew);
5141 rc_fg = *apval;
5142 *apval = NULL;
5143 removing_leading_and_trailing_white_space(rc_fg);
5145 apval = APVAL(&rolecolor_vars[1], ew);
5146 rc_bg = *apval;
5147 *apval = NULL;
5148 removing_leading_and_trailing_white_space(rc_bg);
5150 apval = APVAL(&filter_type_var, ew);
5151 filter_type = *apval;
5152 *apval = NULL;
5153 removing_leading_and_trailing_white_space(filter_type);
5155 alval = ALVAL(&folder_act_var, ew);
5156 folder_act = *alval;
5157 *alval = NULL;
5159 alval = ALVAL(&keyword_set_var, ew);
5160 keyword_set = *alval;
5161 *alval = NULL;
5163 alval = ALVAL(&keyword_clr_var, ew);
5164 keyword_clr = *alval;
5165 *alval = NULL;
5167 apval = APVAL(&filt_imp_var, ew);
5168 filt_imp = *apval;
5169 *apval = NULL;
5170 removing_leading_and_trailing_white_space(filt_imp);
5172 apval = APVAL(&filt_del_var, ew);
5173 filt_del = *apval;
5174 *apval = NULL;
5175 removing_leading_and_trailing_white_space(filt_del);
5177 apval = APVAL(&filt_new_var, ew);
5178 filt_new = *apval;
5179 *apval = NULL;
5180 removing_leading_and_trailing_white_space(filt_new);
5182 apval = APVAL(&filt_ans_var, ew);
5183 filt_ans = *apval;
5184 *apval = NULL;
5185 removing_leading_and_trailing_white_space(filt_ans);
5188 alval = ALVAL(&cat_cmd_var, ew);
5189 cat_cmd = *alval;
5190 *alval = NULL;
5192 alval = ALVAL(&cstm_act_var, ew);
5193 cstm_act = *alval;
5194 *alval = NULL;
5196 alval = ALVAL(&smtp_act_var, ew);
5197 smtp_act = *alval;
5198 *alval = NULL;
5200 alval = ALVAL(&nntp_act_var, ew);
5201 nntp_act = *alval;
5202 *alval = NULL;
5204 if(ps->VAR_OPER_DIR && sig_act &&
5205 is_absolute_path(sig_act) &&
5206 !in_dir(ps->VAR_OPER_DIR, sig_act)){
5207 q_status_message1(SM_ORDER | SM_DING, 3, 4,
5208 _("Warning: Sig file can't be outside of %s"),
5209 ps->VAR_OPER_DIR);
5212 if(ps->VAR_OPER_DIR && templ_act &&
5213 is_absolute_path(templ_act) &&
5214 !in_dir(ps->VAR_OPER_DIR, templ_act)){
5215 q_status_message1(SM_ORDER | SM_DING, 3, 4,
5216 _("Warning: Template file can't be outside of %s"),
5217 ps->VAR_OPER_DIR);
5220 if(ps->VAR_OPER_DIR && folder_act)
5221 for(i = 0; folder_act[i]; i++){
5222 if(folder_act[i][0] && is_absolute_path(folder_act[i]) &&
5223 !in_dir(ps->VAR_OPER_DIR, folder_act[i])){
5224 q_status_message1(SM_ORDER | SM_DING, 3, 4,
5225 _("Warning: Folder can't be outside of %s"),
5226 ps->VAR_OPER_DIR);
5230 *result = (PAT_S *)fs_get(sizeof(**result));
5231 memset((void *)(*result), 0, sizeof(**result));
5233 (*result)->patgrp = (PATGRP_S *)fs_get(sizeof(*(*result)->patgrp));
5234 memset((void *)(*result)->patgrp, 0, sizeof(*(*result)->patgrp));
5236 (*result)->action = (ACTION_S *)fs_get(sizeof(*(*result)->action));
5237 memset((void *)(*result)->action, 0, sizeof(*(*result)->action));
5239 (*result)->patline = def ? def->patline : NULL;
5241 if(nick && *nick){
5242 (*result)->patgrp->nick = nick;
5243 nick = NULL;
5245 else
5246 (*result)->patgrp->nick = cpystr(nick_var.global_val.p);
5248 if(comment && *comment){
5249 (*result)->patgrp->comment = comment;
5250 comment = NULL;
5253 (*result)->action->nick = cpystr((*result)->patgrp->nick);
5255 (*result)->action->is_a_role = edit_role ? 1 : 0;
5256 (*result)->action->is_a_incol = edit_incol ? 1 : 0;
5257 (*result)->action->is_a_score = edit_score ? 1 : 0;
5258 (*result)->action->is_a_filter = edit_filter ? 1 : 0;
5259 (*result)->action->is_a_other = edit_other ? 1 : 0;
5260 (*result)->action->is_a_srch = edit_srch ? 1 : 0;
5262 (*result)->patgrp->to = editlist_to_pattern(to_pat);
5263 if((*result)->patgrp->to && !strncmp(to_pat_var.name, NOT, NOTLEN))
5264 (*result)->patgrp->to->not = 1;
5266 (*result)->patgrp->from = editlist_to_pattern(from_pat);
5267 if((*result)->patgrp->from && !strncmp(from_pat_var.name, NOT, NOTLEN))
5268 (*result)->patgrp->from->not = 1;
5270 (*result)->patgrp->sender = editlist_to_pattern(sender_pat);
5271 if((*result)->patgrp->sender &&
5272 !strncmp(sender_pat_var.name, NOT, NOTLEN))
5273 (*result)->patgrp->sender->not = 1;
5275 (*result)->patgrp->cc = editlist_to_pattern(cc_pat);
5276 if((*result)->patgrp->cc && !strncmp(cc_pat_var.name, NOT, NOTLEN))
5277 (*result)->patgrp->cc->not = 1;
5279 (*result)->patgrp->recip = editlist_to_pattern(recip_pat);
5280 if((*result)->patgrp->recip &&
5281 !strncmp(recip_pat_var.name, NOT, NOTLEN))
5282 (*result)->patgrp->recip->not = 1;
5284 (*result)->patgrp->partic = editlist_to_pattern(partic_pat);
5285 if((*result)->patgrp->partic &&
5286 !strncmp(partic_pat_var.name, NOT, NOTLEN))
5287 (*result)->patgrp->partic->not = 1;
5289 (*result)->patgrp->news = editlist_to_pattern(news_pat);
5290 if((*result)->patgrp->news && !strncmp(news_pat_var.name, NOT, NOTLEN))
5291 (*result)->patgrp->news->not = 1;
5293 (*result)->patgrp->subj = editlist_to_pattern(subj_pat);
5294 if((*result)->patgrp->subj && !strncmp(subj_pat_var.name, NOT, NOTLEN))
5295 (*result)->patgrp->subj->not = 1;
5297 (*result)->patgrp->alltext = editlist_to_pattern(alltext_pat);
5298 if((*result)->patgrp->alltext &&
5299 !strncmp(alltext_pat_var.name, NOT, NOTLEN))
5300 (*result)->patgrp->alltext->not = 1;
5302 (*result)->patgrp->bodytext = editlist_to_pattern(bodytext_pat);
5303 if((*result)->patgrp->bodytext &&
5304 !strncmp(bodytext_pat_var.name, NOT, NOTLEN))
5305 (*result)->patgrp->bodytext->not = 1;
5307 (*result)->patgrp->keyword = editlist_to_pattern(keyword_pat);
5308 if((*result)->patgrp->keyword &&
5309 !strncmp(keyword_pat_var.name, NOT, NOTLEN))
5310 (*result)->patgrp->keyword->not = 1;
5312 (*result)->patgrp->charsets = editlist_to_pattern(charset_pat);
5313 if((*result)->patgrp->charsets &&
5314 !strncmp(charset_pat_var.name, NOT, NOTLEN))
5315 (*result)->patgrp->charsets->not = 1;
5317 (*result)->patgrp->age_uses_sentdate =
5318 bitnset(FEAT_SENTDATE, feat_option_list) ? 1 : 0;
5320 if(age_pat){
5321 if(((*result)->patgrp->age = parse_intvl(age_pat)) != NULL)
5322 (*result)->patgrp->do_age = 1;
5325 if(size_pat){
5326 if(((*result)->patgrp->size = parse_intvl(size_pat)) != NULL)
5327 (*result)->patgrp->do_size = 1;
5330 if(scorei_pat){
5331 if(((*result)->patgrp->score = parse_intvl(scorei_pat)) != NULL)
5332 (*result)->patgrp->do_score = 1;
5335 (*result)->patgrp->cat_lim = -1L; /* default */
5336 if(cat_cmd){
5337 if(!cat_cmd[0])
5338 fs_give((void **) &cat_cmd);
5340 /* quick check for absolute paths */
5341 if(cat_cmd)
5342 for(j = 0; cat_cmd[j]; j++)
5343 if(!is_absolute_path(cat_cmd[j]))
5344 q_status_message1(SM_ORDER | SM_DING, 3, 4,
5345 _("Warning: command must be absolute path: \"%s\""),
5346 cat_cmd[j]);
5348 (*result)->patgrp->category_cmd = cat_cmd;
5349 cat_cmd = NULL;
5351 if(cati){
5352 if(((*result)->patgrp->cat = parse_intvl(cati)) != NULL)
5353 (*result)->patgrp->do_cat = 1;
5355 if(cat_lim && *cat_lim)
5356 (*result)->patgrp->cat_lim = atol(cat_lim);
5359 if(stat_del && *stat_del){
5360 for(j = 0; (f = role_status_types(j)); j++)
5361 if(!strucmp(stat_del, f->name)){
5362 (*result)->patgrp->stat_del = f->value;
5363 break;
5366 else
5367 (*result)->patgrp->stat_del = PAT_STAT_EITHER;
5369 if(stat_new && *stat_new){
5370 for(j = 0; (f = role_status_types(j)); j++)
5371 if(!strucmp(stat_new, f->name)){
5372 (*result)->patgrp->stat_new = f->value;
5373 break;
5376 else
5377 (*result)->patgrp->stat_new = PAT_STAT_EITHER;
5379 if(stat_rec && *stat_rec){
5380 for(j = 0; (f = role_status_types(j)); j++)
5381 if(!strucmp(stat_rec, f->name)){
5382 (*result)->patgrp->stat_rec = f->value;
5383 break;
5386 else
5387 (*result)->patgrp->stat_rec = PAT_STAT_EITHER;
5389 if(stat_imp && *stat_imp){
5390 for(j = 0; (f = role_status_types(j)); j++)
5391 if(!strucmp(stat_imp, f->name)){
5392 (*result)->patgrp->stat_imp = f->value;
5393 break;
5396 else
5397 (*result)->patgrp->stat_imp = PAT_STAT_EITHER;
5399 if(stat_ans && *stat_ans){
5400 for(j = 0; (f = role_status_types(j)); j++)
5401 if(!strucmp(stat_ans, f->name)){
5402 (*result)->patgrp->stat_ans = f->value;
5403 break;
5406 else
5407 (*result)->patgrp->stat_ans = PAT_STAT_EITHER;
5409 if(stat_8bit && *stat_8bit){
5410 for(j = 0; (f = role_status_types(j)); j++)
5411 if(!strucmp(stat_8bit, f->name)){
5412 (*result)->patgrp->stat_8bitsubj = f->value;
5413 break;
5416 else
5417 (*result)->patgrp->stat_8bitsubj = PAT_STAT_EITHER;
5419 if(stat_bom && *stat_bom){
5420 for(j = 0; (f = role_status_types(j)); j++)
5421 if(!strucmp(stat_bom, f->name)){
5422 (*result)->patgrp->stat_bom = f->value;
5423 break;
5426 else
5427 (*result)->patgrp->stat_bom = PAT_STAT_EITHER;
5429 if(stat_boy && *stat_boy){
5430 for(j = 0; (f = role_status_types(j)); j++)
5431 if(!strucmp(stat_boy, f->name)){
5432 (*result)->patgrp->stat_boy = f->value;
5433 break;
5436 else
5437 (*result)->patgrp->stat_boy = PAT_STAT_EITHER;
5439 if(sort_act){
5440 decode_sort(sort_act, &def_sort, &def_sort_rev);
5441 (*result)->action->sort_is_set = 1;
5442 (*result)->action->sortorder = def_sort;
5443 (*result)->action->revsort = (def_sort_rev ? 1 : 0);
5445 * Don't try to re-sort until next open of folder. If user
5446 * $-sorted then it probably shouldn't change anyway. Why
5447 * bother keeping track of that?
5451 (*result)->action->index_format = iform_act;
5452 iform_act = NULL;
5454 if(startup_act && *startup_act){
5455 for(j = 0; (f = startup_rules(j)); j++)
5456 if(!strucmp(startup_act, f->name)){
5457 (*result)->action->startup_rule = f->value;
5458 break;
5461 else
5462 (*result)->action->startup_rule = IS_NOTSET;
5464 aa = NULL;
5465 for(ea = earb; ea; ea = ea->next){
5466 char *xyz;
5468 if(aa){
5469 aa->next = (ARBHDR_S *)fs_get(sizeof(*aa));
5470 aa = aa->next;
5472 else{
5473 (*result)->patgrp->arbhdr =
5474 (ARBHDR_S *)fs_get(sizeof(ARBHDR_S));
5475 aa = (*result)->patgrp->arbhdr;
5478 memset(aa, 0, sizeof(*aa));
5480 aa->field = cpystr((ea->a && ea->a->field) ? ea->a->field : "");
5482 alval = ALVAL(ea->v, ew);
5483 spat = *alval;
5484 *alval = NULL;
5485 aa->p = editlist_to_pattern(spat);
5486 if(aa->p && ea->v && ea->v->name &&
5487 !strncmp(ea->v->name, NOT, NOTLEN))
5488 aa->p->not = 1;
5490 if((xyz = pattern_to_string(aa->p)) != NULL){
5491 if(!*xyz)
5492 aa->isemptyval = 1;
5494 fs_give((void **)&xyz);
5498 if(fldr_type_pat && *fldr_type_pat){
5499 for(j = 0; (f = pat_fldr_types(j)); j++)
5500 if(!strucmp(fldr_type_pat, f->name)){
5501 (*result)->patgrp->fldr_type = f->value;
5502 break;
5505 else{
5506 f = pat_fldr_types(FLDR_DEFL);
5507 if(f)
5508 (*result)->patgrp->fldr_type = f->value;
5511 (*result)->patgrp->folder = editlist_to_pattern(folder_pat);
5513 if(abook_type_pat && *abook_type_pat){
5514 for(j = 0; (f = inabook_fldr_types(j)); j++)
5515 if(!strucmp(abook_type_pat, f->name)){
5516 (*result)->patgrp->inabook = f->value;
5517 break;
5520 if(bitnset(INABOOK_FROM, inabook_type_list))
5521 (*result)->patgrp->inabook |= IAB_FROM;
5522 if(bitnset(INABOOK_REPLYTO, inabook_type_list))
5523 (*result)->patgrp->inabook |= IAB_REPLYTO;
5524 if(bitnset(INABOOK_SENDER, inabook_type_list))
5525 (*result)->patgrp->inabook |= IAB_SENDER;
5526 if(bitnset(INABOOK_TO, inabook_type_list))
5527 (*result)->patgrp->inabook |= IAB_TO;
5528 if(bitnset(INABOOK_CC, inabook_type_list))
5529 (*result)->patgrp->inabook |= IAB_CC;
5531 if(!((*result)->patgrp->inabook & IAB_TYPE_MASK))
5532 (*result)->patgrp->inabook |= (IAB_FROM | IAB_REPLYTO);
5534 else{
5535 f = inabook_fldr_types(IAB_DEFL);
5536 if(f)
5537 (*result)->patgrp->inabook = f->value;
5540 (*result)->patgrp->abooks = editlist_to_pattern(abook_pat);
5543 (*result)->action->inherit_nick = inick;
5544 inick = NULL;
5545 (*result)->action->fcc = fcc_act;
5546 fcc_act = NULL;
5547 (*result)->action->litsig = litsig_act;
5548 litsig_act = NULL;
5549 (*result)->action->sig = sig_act;
5550 sig_act = NULL;
5551 (*result)->action->template = templ_act;
5552 templ_act = NULL;
5554 if(cstm_act){
5556 * Check for From or Reply-To and eliminate them.
5558 for(i = 0; cstm_act[i]; i++){
5559 char *free_this;
5561 if((!struncmp(cstm_act[i],"from",4) &&
5562 (cstm_act[i][4] == ':' ||
5563 cstm_act[i][4] == '\0')) ||
5564 (!struncmp(cstm_act[i],"reply-to",8) &&
5565 (cstm_act[i][8] == ':' ||
5566 cstm_act[i][8] == '\0'))){
5567 free_this = cstm_act[i];
5568 /* slide the rest up */
5569 for(j = i; cstm_act[j]; j++)
5570 cstm_act[j] = cstm_act[j+1];
5572 fs_give((void **)&free_this);
5573 i--; /* recheck now that we've slid them up */
5577 /* nothing left */
5578 if(!cstm_act[0])
5579 fs_give((void **)&cstm_act);
5581 (*result)->action->cstm = cstm_act;
5582 cstm_act = NULL;
5585 if(smtp_act){
5586 if(!smtp_act[0])
5587 fs_give((void **)&smtp_act);
5589 (*result)->action->smtp = smtp_act;
5590 smtp_act = NULL;
5593 if(nntp_act){
5594 if(!nntp_act[0])
5595 fs_give((void **)&nntp_act);
5597 (*result)->action->nntp = nntp_act;
5598 nntp_act = NULL;
5601 if(filter_type && *filter_type){
5602 (*result)->action->non_terminating =
5603 bitnset(FEAT_NONTERM, feat_option_list) ? 1 : 0;
5604 for(i = 0; (f = filter_types(i)); i++){
5605 if(!strucmp(filter_type, f->name)){
5606 if(f->value == FILTER_FOLDER){
5607 (*result)->action->folder = editlist_to_pattern(folder_act);
5608 (*result)->action->move_only_if_not_deleted =
5609 bitnset(FEAT_IFNOTDEL, feat_option_list) ? 1 : 0;
5611 else if(f->value == FILTER_STATE){
5612 (*result)->action->kill = 0;
5614 else if(f->value == FILTER_KILL){
5615 (*result)->action->kill = 1;
5619 * This is indented an extra indent because we used to condition
5620 * this on !kill. We changed it so that you can set state bits
5621 * even if you're killing. This is marginally helpful if you
5622 * have another client running that doesn't know about this
5623 * filter, but you want to, for example, have the messages show
5624 * up now as deleted instead of having that deferred until we
5625 * exit. It is controlled by the user by setting the status
5626 * action bits along with the Delete.
5628 if(filt_imp && *filt_imp){
5629 for(j = 0; (f = msg_state_types(j)); j++){
5630 if(!strucmp(filt_imp, f->name)){
5631 switch(f->value){
5632 case ACT_STAT_LEAVE:
5633 break;
5634 case ACT_STAT_SET:
5635 (*result)->action->state_setting_bits |= F_FLAG;
5636 break;
5637 case ACT_STAT_CLEAR:
5638 (*result)->action->state_setting_bits |= F_UNFLAG;
5639 break;
5641 break;
5646 if(filt_del && *filt_del){
5647 for(j = 0; (f = msg_state_types(j)); j++){
5648 if(!strucmp(filt_del, f->name)){
5649 switch(f->value){
5650 case ACT_STAT_LEAVE:
5651 break;
5652 case ACT_STAT_SET:
5653 (*result)->action->state_setting_bits |= F_DEL;
5654 break;
5655 case ACT_STAT_CLEAR:
5656 (*result)->action->state_setting_bits |= F_UNDEL;
5657 break;
5659 break;
5664 if(filt_ans && *filt_ans){
5665 for(j = 0; (f = msg_state_types(j)); j++){
5666 if(!strucmp(filt_ans, f->name)){
5667 switch(f->value){
5668 case ACT_STAT_LEAVE:
5669 break;
5670 case ACT_STAT_SET:
5671 (*result)->action->state_setting_bits |= F_ANS;
5672 break;
5673 case ACT_STAT_CLEAR:
5674 (*result)->action->state_setting_bits |= F_UNANS;
5675 break;
5677 break;
5682 if(filt_new && *filt_new){
5683 for(j = 0; (f = msg_state_types(j)); j++){
5684 if(!strucmp(filt_new, f->name)){
5685 switch(f->value){
5686 case ACT_STAT_LEAVE:
5687 break;
5688 case ACT_STAT_SET:
5689 (*result)->action->state_setting_bits |= F_UNSEEN;
5690 break;
5691 case ACT_STAT_CLEAR:
5692 (*result)->action->state_setting_bits |= F_SEEN;
5693 break;
5695 break;
5700 (*result)->action->keyword_set =
5701 editlist_to_pattern(keyword_set);
5702 (*result)->action->keyword_clr =
5703 editlist_to_pattern(keyword_clr);
5705 break;
5710 if(from_act && *from_act)
5711 rfc822_parse_adrlist(&(*result)->action->from, from_act,
5712 ps->maildomain);
5714 if(replyto_act && *replyto_act)
5715 rfc822_parse_adrlist(&(*result)->action->replyto, replyto_act,
5716 ps->maildomain);
5718 if(score_act && (j = atoi(score_act)) >= SCORE_MIN && j <= SCORE_MAX)
5719 (*result)->action->scoreval = (long) j;
5721 if(hdrtok_act)
5722 (*result)->action->scorevalhdrtok = stringform_to_hdrtok(hdrtok_act);
5724 if(repl_type && *repl_type){
5725 for(j = 0; (f = role_repl_types(j)); j++)
5726 if(!strucmp(repl_type, f->name)){
5727 (*result)->action->repl_type = f->value;
5728 break;
5731 else{
5732 f = role_repl_types(ROLE_REPL_DEFL);
5733 if(f)
5734 (*result)->action->repl_type = f->value;
5737 if(forw_type && *forw_type){
5738 for(j = 0; (f = role_forw_types(j)); j++)
5739 if(!strucmp(forw_type, f->name)){
5740 (*result)->action->forw_type = f->value;
5741 break;
5744 else{
5745 f = role_forw_types(ROLE_FORW_DEFL);
5746 if(f)
5747 (*result)->action->forw_type = f->value;
5750 if(comp_type && *comp_type){
5751 for(j = 0; (f = role_comp_types(j)); j++)
5752 if(!strucmp(comp_type, f->name)){
5753 (*result)->action->comp_type = f->value;
5754 break;
5757 else{
5758 f = role_comp_types(ROLE_COMP_DEFL);
5759 if(f)
5760 (*result)->action->comp_type = f->value;
5763 if(rc_fg && *rc_fg && rc_bg && *rc_bg){
5764 if(!old_fg || !old_bg || strucmp(old_fg, rc_fg) ||
5765 strucmp(old_bg, rc_bg))
5766 clear_index_cache(ps_global->mail_stream, 0);
5769 * If same as normal color, don't set it. This may or may
5770 * not surprise the user when they change the normal color.
5771 * This color will track the normal color instead of staying
5772 * the same as the old normal color, which is probably
5773 * what they want.
5775 if(!ps_global->VAR_NORM_FORE_COLOR ||
5776 !ps_global->VAR_NORM_BACK_COLOR ||
5777 strucmp(ps_global->VAR_NORM_FORE_COLOR, rc_fg) ||
5778 strucmp(ps_global->VAR_NORM_BACK_COLOR, rc_bg))
5779 (*result)->action->incol = new_color_pair(rc_fg, rc_bg);
5783 for(j = 0; varlist[j]; j++){
5784 v = varlist[j];
5785 free_variable_values(v);
5786 if(v->name)
5787 fs_give((void **)&v->name);
5790 if(earb)
5791 free_earb(&earb);
5792 if(nick)
5793 fs_give((void **)&nick);
5794 if(comment)
5795 fs_give((void **)&comment);
5796 if(to_pat)
5797 free_list_array(&to_pat);
5798 if(from_pat)
5799 free_list_array(&from_pat);
5800 if(sender_pat)
5801 free_list_array(&sender_pat);
5802 if(cc_pat)
5803 free_list_array(&cc_pat);
5804 if(recip_pat)
5805 free_list_array(&recip_pat);
5806 if(partic_pat)
5807 free_list_array(&partic_pat);
5808 if(news_pat)
5809 free_list_array(&news_pat);
5810 if(subj_pat)
5811 free_list_array(&subj_pat);
5812 if(alltext_pat)
5813 free_list_array(&alltext_pat);
5814 if(bodytext_pat)
5815 free_list_array(&bodytext_pat);
5816 if(keyword_pat)
5817 free_list_array(&keyword_pat);
5818 if(charset_pat)
5819 free_list_array(&charset_pat);
5820 if(age_pat)
5821 fs_give((void **)&age_pat);
5822 if(size_pat)
5823 fs_give((void **)&size_pat);
5824 if(scorei_pat)
5825 fs_give((void **)&scorei_pat);
5826 if(cati)
5827 fs_give((void **)&cati);
5828 if(cat_lim)
5829 fs_give((void **)&cat_lim);
5830 if(stat_del)
5831 fs_give((void **)&stat_del);
5832 if(stat_new)
5833 fs_give((void **)&stat_new);
5834 if(stat_rec)
5835 fs_give((void **)&stat_rec);
5836 if(stat_imp)
5837 fs_give((void **)&stat_imp);
5838 if(stat_ans)
5839 fs_give((void **)&stat_ans);
5840 if(stat_8bit)
5841 fs_give((void **)&stat_8bit);
5842 if(stat_bom)
5843 fs_give((void **)&stat_bom);
5844 if(stat_boy)
5845 fs_give((void **)&stat_boy);
5846 if(fldr_type_pat)
5847 fs_give((void **)&fldr_type_pat);
5848 if(folder_pat)
5849 free_list_array(&folder_pat);
5850 if(abook_type_pat)
5851 fs_give((void **)&abook_type_pat);
5852 if(abook_pat)
5853 free_list_array(&abook_pat);
5854 if(inick)
5855 fs_give((void **)&inick);
5856 if(from_act)
5857 fs_give((void **)&from_act);
5858 if(replyto_act)
5859 fs_give((void **)&replyto_act);
5860 if(fcc_act)
5861 fs_give((void **)&fcc_act);
5862 if(litsig_act)
5863 fs_give((void **)&litsig_act);
5864 if(sort_act)
5865 fs_give((void **)&sort_act);
5866 if(iform_act)
5867 fs_give((void **)&iform_act);
5868 if(keyword_set)
5869 free_list_array(&keyword_set);
5870 if(keyword_clr)
5871 free_list_array(&keyword_clr);
5872 if(startup_act)
5873 fs_give((void **)&startup_act);
5874 if(sig_act)
5875 fs_give((void **)&sig_act);
5876 if(templ_act)
5877 fs_give((void **)&templ_act);
5878 if(score_act)
5879 fs_give((void **)&score_act);
5880 if(hdrtok_act)
5881 fs_give((void **)&hdrtok_act);
5882 if(repl_type)
5883 fs_give((void **)&repl_type);
5884 if(forw_type)
5885 fs_give((void **)&forw_type);
5886 if(comp_type)
5887 fs_give((void **)&comp_type);
5888 if(rc_fg)
5889 fs_give((void **)&rc_fg);
5890 if(rc_bg)
5891 fs_give((void **)&rc_bg);
5892 if(old_fg)
5893 fs_give((void **)&old_fg);
5894 if(old_bg)
5895 fs_give((void **)&old_bg);
5896 if(filt_del)
5897 fs_give((void **)&filt_del);
5898 if(filt_new)
5899 fs_give((void **)&filt_new);
5900 if(filt_ans)
5901 fs_give((void **)&filt_ans);
5902 if(filt_imp)
5903 fs_give((void **)&filt_imp);
5904 if(folder_act)
5905 free_list_array(&folder_act);
5906 if(filter_type)
5907 fs_give((void **)&filter_type);
5909 if(cat_cmd)
5910 free_list_array(&cat_cmd);
5912 if(cstm_act)
5913 free_list_array(&cstm_act);
5915 if(smtp_act)
5916 free_list_array(&smtp_act);
5918 if(nntp_act)
5919 free_list_array(&nntp_act);
5921 opt_screen = saved_screen;
5922 ps->mangled_screen = 1;
5923 return(rv);
5927 void
5928 setup_dummy_pattern_var(struct variable *v, char *name, PATTERN_S *defpat)
5930 char ***alval;
5932 if(!(v && name))
5933 alpine_panic("setup_dummy_pattern_var");
5935 v->name = (char *) fs_get(strlen(name)+NOTLEN+1);
5936 snprintf(v->name, strlen(name)+NOTLEN+1, "%s%s", (defpat && defpat->not) ? NOT : "", name);
5937 v->name[ strlen(name)+NOTLEN+1-1] = '\0';
5938 v->is_used = 1;
5939 v->is_user = 1;
5940 v->is_list = 1;
5941 alval = ALVAL(v, ew);
5942 *alval = pattern_to_editlist(defpat);
5943 set_current_val(v, FALSE, FALSE);
5947 void
5948 setup_role_pat(struct pine *ps, CONF_S **ctmp, struct variable *v, HelpType help,
5949 char *help_title, struct key_menu *keymenu,
5950 int (*tool)(struct pine *, int, CONF_S **, unsigned),
5951 EARB_S **earb, int indent)
5953 char tmp[MAXPATH+1];
5954 char **lval;
5955 int i;
5956 CONF_S *ctmpb;
5958 new_confline(ctmp);
5959 (*ctmp)->help_title = help_title;
5960 (*ctmp)->var = v;
5961 (*ctmp)->valoffset = indent;
5962 (*ctmp)->keymenu = keymenu;
5963 (*ctmp)->help = help;
5964 (*ctmp)->tool = tool;
5965 utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", indent-3, indent-3, (v && v->name) ? v->name : "");
5966 tmp[sizeof(tmp)-1] = '\0';
5967 (*ctmp)->varname = cpystr(tmp);
5968 (*ctmp)->varnamep = *ctmp;
5969 (*ctmp)->value = pretty_value(ps, *ctmp);
5970 (*ctmp)->d.earb = earb;
5971 (*ctmp)->varmem = 0;
5972 (*ctmp)->flags = CF_STARTITEM;
5974 ctmpb = (*ctmp);
5976 lval = LVAL(v, ew);
5977 if(lval){
5978 for(i = 0; lval[i]; i++){
5979 if(i)
5980 new_confline(ctmp);
5982 (*ctmp)->var = v;
5983 (*ctmp)->varmem = i;
5984 (*ctmp)->valoffset = indent;
5985 (*ctmp)->value = pretty_value(ps, *ctmp);
5986 (*ctmp)->d.earb = earb;
5987 (*ctmp)->keymenu = keymenu;
5988 (*ctmp)->help = help;
5989 (*ctmp)->tool = tool;
5990 (*ctmp)->varnamep = ctmpb;
5997 * Watch out for polarity of nosel flag. Setting it means to turn on
5998 * the NOSELECT flag, which means to make that line unselectable.
6000 void
6001 setup_role_pat_alt(struct pine *ps, CONF_S **ctmp, struct variable *v, HelpType help,
6002 char *help_title, struct key_menu *keymenu,
6003 int (*tool)(struct pine *, int, CONF_S **, unsigned),
6004 int voff, int nosel)
6006 char tmp[MAXPATH+1];
6007 char **lval;
6008 int i, j, k;
6009 CONF_S *ctmpb;
6011 new_confline(ctmp);
6012 (*ctmp)->help_title = help_title;
6013 (*ctmp)->var = v;
6015 (*ctmp)->varoffset = voff;
6016 k = utf8_width(v->name);
6017 j = voff+k+3;
6018 (*ctmp)->valoffset = j;
6020 (*ctmp)->keymenu = keymenu;
6021 (*ctmp)->help = help;
6022 (*ctmp)->tool = tool;
6024 utf8_snprintf(tmp, sizeof(tmp), "%*.*w =", k, k, v->name);
6025 tmp[sizeof(tmp)-1] = '\0';
6026 (*ctmp)->varname = cpystr(tmp);
6028 (*ctmp)->varnamep = *ctmp;
6029 (*ctmp)->value = pretty_value(ps, *ctmp);
6030 (*ctmp)->varmem = 0;
6032 (*ctmp)->flags = (nosel ? CF_NOSELECT : 0);
6034 ctmpb = (*ctmp);
6036 lval = LVAL(v, ew);
6037 if(lval){
6038 for(i = 0; lval[i]; i++){
6039 if(i)
6040 new_confline(ctmp);
6042 (*ctmp)->var = v;
6043 (*ctmp)->varmem = i;
6044 (*ctmp)->varoffset = voff;
6045 (*ctmp)->valoffset = j;
6046 (*ctmp)->value = pretty_value(ps, *ctmp);
6047 (*ctmp)->keymenu = keymenu;
6048 (*ctmp)->help = help;
6049 (*ctmp)->tool = tool;
6050 (*ctmp)->varnamep = ctmpb;
6051 (*ctmp)->flags = (nosel ? CF_NOSELECT : 0);
6057 void
6058 free_earb(EARB_S **ea)
6060 if(ea && *ea){
6061 free_earb(&(*ea)->next);
6062 if((*ea)->v){
6063 free_variable_values((*ea)->v);
6064 if((*ea)->v->name)
6065 fs_give((void **) &(*ea)->v->name);
6067 fs_give((void **) &(*ea)->v);;
6070 free_arbhdr(&(*ea)->a);
6071 fs_give((void **) ea);
6076 void
6077 calculate_inick_stuff(struct pine *ps)
6079 ACTION_S *role, *irole;
6080 CONF_S *ctmp, *ctmpa;
6081 struct variable *v;
6082 int i;
6083 char *nick;
6085 if(inick_confs[INICK_INICK_CONF] == NULL)
6086 return;
6088 for(i = INICK_FROM_CONF; i <= INICK_NNTP_CONF; i++){
6089 v = inick_confs[i] ? inick_confs[i]->var : NULL;
6090 if(v){
6091 if(v->is_list){
6092 if(v->global_val.l)
6093 free_list_array(&v->global_val.l);
6095 else{
6096 if(v->global_val.p)
6097 fs_give((void **)&v->global_val.p);
6102 nick = PVAL(inick_confs[INICK_INICK_CONF]->var, ew);
6104 if(nick){
6106 * Use an empty role with inherit_nick set to nick and then use the
6107 * combine function to find the action values.
6109 role = (ACTION_S *)fs_get(sizeof(*role));
6110 memset((void *)role, 0, sizeof(*role));
6111 role->is_a_role = 1;
6112 role->inherit_nick = cpystr(nick);
6113 irole = combine_inherited_role(role);
6115 ctmp = inick_confs[INICK_FROM_CONF];
6116 v = ctmp ? ctmp->var : NULL;
6118 if(irole && irole->from){
6119 char *bufp;
6120 size_t len;
6122 len = est_size(irole->from);
6123 bufp = (char *) fs_get(len * sizeof(char));
6124 v->global_val.p = addr_string_mult(irole->from, bufp, len);
6127 ctmp = inick_confs[INICK_REPLYTO_CONF];
6128 v = ctmp ? ctmp->var : NULL;
6130 if(irole && irole->replyto){
6131 char *bufp;
6132 size_t len;
6134 len = est_size(irole->replyto);
6135 bufp = (char *) fs_get(len * sizeof(char));
6136 v->global_val.p = addr_string_mult(irole->replyto, bufp, len);
6139 ctmp = inick_confs[INICK_FCC_CONF];
6140 v = ctmp ? ctmp->var : NULL;
6141 v->global_val.p = (irole && irole->fcc) ? cpystr(irole->fcc) : NULL;
6143 ctmp = inick_confs[INICK_LITSIG_CONF];
6144 v = ctmp ? ctmp->var : NULL;
6145 v->global_val.p = (irole && irole->litsig) ? cpystr(irole->litsig)
6146 : NULL;
6148 ctmp = inick_confs[INICK_SIG_CONF];
6149 v = ctmp ? ctmp->var : NULL;
6150 v->global_val.p = (irole && irole->sig) ? cpystr(irole->sig) : NULL;
6152 ctmp = inick_confs[INICK_TEMPL_CONF];
6153 v = ctmp ? ctmp->var : NULL;
6154 v->global_val.p = (irole && irole->template)
6155 ? cpystr(irole->template) : NULL;
6157 ctmp = inick_confs[INICK_CSTM_CONF];
6158 v = ctmp ? ctmp->var : NULL;
6159 v->global_val.l = (irole && irole->cstm) ? copy_list_array(irole->cstm)
6160 : NULL;
6162 ctmp = inick_confs[INICK_SMTP_CONF];
6163 v = ctmp ? ctmp->var : NULL;
6164 v->global_val.l = (irole && irole->smtp) ? copy_list_array(irole->smtp)
6165 : NULL;
6167 ctmp = inick_confs[INICK_NNTP_CONF];
6168 v = ctmp ? ctmp->var : NULL;
6169 v->global_val.l = (irole && irole->nntp) ? copy_list_array(irole->nntp)
6170 : NULL;
6172 free_action(&role);
6173 free_action(&irole);
6176 for(i = INICK_INICK_CONF; i <= INICK_NNTP_CONF; i++){
6177 ctmp = inick_confs[i];
6178 v = ctmp ? ctmp->var : NULL;
6180 * If we didn't set a global_val using the nick above, then
6181 * set one here for each variable that uses one.
6183 if(v && !v->global_val.p){
6184 char *str, *astr, *lc, pdir[MAXPATH+1];
6185 ADDRESS *addr;
6186 int len;
6188 switch(i){
6189 case INICK_FROM_CONF:
6190 addr = generate_from();
6191 astr = addr_list_string(addr, NULL, 1);
6192 str = (astr && astr[0]) ? astr : "?";
6193 v->global_val.p = (char *)fs_get((strlen(str) + 20) *
6194 sizeof(char));
6195 snprintf(v->global_val.p, strlen(str) + 20, "%s%s)", DSTRING, str);
6196 v->global_val.p[strlen(str) + 20 - 1] = '\0';
6197 if(astr)
6198 fs_give((void **)&astr);
6200 if(addr)
6201 mail_free_address(&addr);
6203 break;
6205 case INICK_FCC_CONF:
6206 v->global_val.p = cpystr(VSTRING);
6207 break;
6209 case INICK_LITSIG_CONF:
6211 * This default works this way because of the ordering
6212 * of the choices in the detoken routine.
6214 if(ps->VAR_LITERAL_SIG){
6215 str = ps->VAR_LITERAL_SIG;
6216 v->global_val.p = (char *)fs_get((strlen(str) + 20) *
6217 sizeof(char));
6218 snprintf(v->global_val.p, strlen(str) + 20,
6219 "%s%s)", DSTRING, str);
6220 v->global_val.p[strlen(str) + 20 - 1] = '\0';
6223 break;
6225 case INICK_SIG_CONF:
6226 pdir[0] = '\0';
6227 if(ps_global->VAR_OPER_DIR){
6228 strncpy(pdir, ps_global->VAR_OPER_DIR, MAXPATH);
6229 pdir[MAXPATH] = '\0';
6230 len = strlen(pdir) + 1;
6232 else if((lc = last_cmpnt(ps_global->pinerc)) != NULL){
6233 strncpy(pdir, ps_global->pinerc,
6234 MIN(MAXPATH,lc-ps_global->pinerc));
6235 pdir[MIN(MAXPATH, lc-ps_global->pinerc)] = '\0';
6236 len = strlen(pdir);
6239 if(pdir[0] && ps->VAR_SIGNATURE_FILE &&
6240 ps->VAR_SIGNATURE_FILE[0] &&
6241 is_absolute_path(ps->VAR_SIGNATURE_FILE) &&
6242 !strncmp(ps->VAR_SIGNATURE_FILE, pdir, len)){
6243 str = ps->VAR_SIGNATURE_FILE + len;
6245 else
6246 str = (ps->VAR_SIGNATURE_FILE && ps->VAR_SIGNATURE_FILE[0])
6247 ? ps->VAR_SIGNATURE_FILE : NULL;
6248 if(str){
6249 v->global_val.p = (char *)fs_get((strlen(str) + 20) *
6250 sizeof(char));
6251 snprintf(v->global_val.p, strlen(str) + 20, "%s%s)", DSTRING, str);
6252 v->global_val.p[strlen(str) + 20 - 1] = '\0';
6255 break;
6257 case INICK_INICK_CONF:
6258 case INICK_REPLYTO_CONF:
6259 case INICK_TEMPL_CONF:
6260 case INICK_CSTM_CONF:
6261 case INICK_SMTP_CONF:
6262 case INICK_NNTP_CONF:
6263 break;
6267 if(v)
6268 set_current_val(v, FALSE, FALSE);
6270 if(ctmp){
6271 CONF_S *ctmpsig = NULL;
6272 struct variable *vlsig;
6274 for(ctmpa = ctmp;
6275 ctmpa && ctmpa->varnamep == ctmp;
6276 ctmpa = ctmpa->next){
6277 if(ctmpa->value)
6278 fs_give((void **)&ctmpa->value);
6280 ctmpa->value = pretty_value(ps, ctmpa);
6283 if(i == INICK_SIG_CONF){
6285 * Turn off NOSELECT, but possibly turn it on again
6286 * in next line.
6288 if((ctmpsig = inick_confs[INICK_SIG_CONF]) != NULL)
6289 ctmpsig->flags &= ~CF_NOSELECT;
6291 if(inick_confs[INICK_LITSIG_CONF] &&
6292 (vlsig = inick_confs[INICK_LITSIG_CONF]->var) &&
6293 vlsig->current_val.p &&
6294 vlsig->current_val.p[0]){
6295 if(ctmp->value)
6296 fs_give((void **)&ctmp->value);
6298 ctmp->value =
6299 cpystr("<Ignored: using LiteralSig instead>");
6301 ctmp->flags |= CF_NOSELECT;
6309 /* Arguments:
6310 * lst: a list of folders
6311 * action: a 1 or 0 value which basically says that str is associated with
6312 * the filter action if true or the Current Folder type if false.
6313 * Return:
6314 * Returns 2 on success (user wants to exit) and 0 on failure.
6316 * This function cycles through a list of folders and checks whether or not each
6317 * folder exists. If they exist, return 2, if they don't exist, notify the user
6318 * or offer to create depending on whether or not it is a filter action or not.
6319 * With each of these prompts, the user can abort their desire to exit.
6322 check_role_folders(char **lst, unsigned int action)
6324 char *cur_fn, wt_res, prompt[MAX_SCREEN_COLS];
6325 int i, rv = 2;
6326 CONTEXT_S *cntxt = NULL;
6327 char nbuf1[MAX_SCREEN_COLS], nbuf2[MAX_SCREEN_COLS];
6328 int space, w1, w2, exists;
6330 if(!(lst && *lst)){
6331 if(action)
6332 q_status_message(SM_ORDER, 3, 5,
6333 _("Set a valid Filter Action before Exiting"));
6334 else
6335 q_status_message(SM_ORDER, 3, 5,
6336 _("Set a valid Specific Folder before Exiting"));
6337 rv = 0;
6338 return rv;
6341 for(i = 0; lst[i]; i++){
6342 if(action)
6343 cur_fn = detoken_src(lst[i], FOR_FILT, NULL, NULL, NULL, NULL);
6344 else
6345 cur_fn = lst[i];
6347 removing_leading_and_trailing_white_space(cur_fn);
6348 if(*cur_fn != '\0'){
6349 space = MAXPROMPT;
6350 if(is_absolute_path(cur_fn) || !context_isambig(cur_fn))
6351 cntxt = NULL;
6352 else
6353 cntxt = default_save_context(ps_global->context_list);
6355 if(!(exists=folder_exists(cntxt, cur_fn))
6356 && (action
6357 || (ps_global->context_list->use & CNTXT_INCMNG
6358 && !folder_is_nick(cur_fn,FOLDERS(ps_global->context_list), 0)))){
6359 if(cntxt && (action == 1)){
6360 space -= 37; /* for fixed part of prompt below */
6361 w1 = MAX(1,MIN(strlen(cur_fn),space/2));
6362 w2 = MIN(MAX(1,space-w1),strlen(cntxt->nickname));
6363 w1 += MAX(0,space-w1-w2);
6364 snprintf(prompt, sizeof(prompt),
6365 _("Folder \"%s\" in <%s> doesn't exist. Create"),
6366 short_str(cur_fn,nbuf1,sizeof(nbuf1),w1,MidDots),
6367 short_str(cntxt->nickname,nbuf2,sizeof(nbuf2),w2,MidDots));
6368 prompt[sizeof(prompt)-1] = '\0';
6370 else if(cntxt && (action == 0)){
6371 space -= 51; /* for fixed part of prompt below */
6372 w1 = MAX(1,MIN(strlen(cur_fn),space/2));
6373 w2 = MIN(MAX(1,space-w1),strlen(cntxt->nickname));
6374 w1 += MAX(0,space-w1-w2);
6375 snprintf(prompt, sizeof(prompt),
6376 _("Folder \"%s\" in <%s> doesn't exist. Exit and save anyway"),
6377 short_str(cur_fn,nbuf1,sizeof(nbuf1),w1,MidDots),
6378 short_str(cntxt->nickname,nbuf2,sizeof(nbuf2),w2,MidDots));
6379 prompt[sizeof(prompt)-1] = '\0';
6381 else if(!cntxt && (action == 1)){
6382 space -= 31; /* for fixed part of prompt below */
6383 w1 = MAX(1,space);
6384 snprintf(prompt, sizeof(prompt),
6385 _("Folder \"%s\" doesn't exist. Create"),
6386 short_str(cur_fn,nbuf1,sizeof(nbuf1),w1,MidDots));
6387 prompt[sizeof(prompt)-1] = '\0';
6389 else{ /*!cntxt && (action == 0) */
6390 space -= 45; /* for fixed part of prompt below */
6391 w1 = MAX(1,space);
6392 snprintf(prompt, sizeof(prompt),
6393 _("Folder \"%s\" doesn't exist. Exit and save anyway"),
6394 short_str(cur_fn,nbuf1,sizeof(nbuf1),w1,MidDots));
6395 prompt[sizeof(prompt)-1] = '\0';
6398 wt_res = want_to(prompt, 'n', 'x', NO_HELP, WT_NORM);
6399 if(wt_res == 'y'){
6400 if(action){
6401 if(context_create(cntxt, NULL, cur_fn)){
6402 q_status_message(SM_ORDER,3,5,_("Folder created"));
6403 maybe_add_to_incoming(cntxt, cur_fn);
6406 /* No message to notify of changes being saved, we can't */
6407 /* assume that the role screen isn't exited yet */
6408 rv = 2;
6410 else if(wt_res == 'n' && action){
6411 rv = 2;
6412 q_status_message(SM_ORDER,3,5,_("Folder not created"));
6414 else{
6415 q_status_message(SM_ORDER,3,5,_("Exit cancelled"));
6416 rv = 0;
6417 break;
6420 else{
6421 if(exists & FEX_ERROR){
6422 if(ps_global->mm_log_error && ps_global->c_client_error)
6423 q_status_message(SM_ORDER,3,5,ps_global->c_client_error);
6424 else
6425 q_status_message1(SM_ORDER,3,5,"\"%s\": Trouble checking for folder existence", cur_fn);
6428 rv = 2;
6431 else{ /* blank item in list of folders */
6432 if(action && lst[i+1] == NULL)
6433 q_status_message(SM_ORDER,3,5,_("Set a valid Filter Action before Exiting"));
6434 else /* !action && lst[i+1] == '\0' */
6435 q_status_message(SM_ORDER,3,5,_("Set a valid Specific Folder before Exiting"));
6436 rv = 0;
6437 break;
6440 if(cur_fn && cur_fn != lst[i])
6441 fs_give((void **) &cur_fn);
6444 return(rv);
6448 void
6449 maybe_add_to_incoming(CONTEXT_S *cntxt, char *cur_fn)
6451 char name[MAILTMPLEN], nname[32];
6452 char nbuf1[MAX_SCREEN_COLS], nbuf2[MAX_SCREEN_COLS];
6453 char prompt[MAX_SCREEN_COLS];
6454 char ***alval;
6455 int i, found, space, w1, w2;
6456 FOLDER_S *f;
6458 if(ps_global->context_list->use & CNTXT_INCMNG &&
6459 ((alval = ALVAL(&ps_global->vars[V_INCOMING_FOLDERS], Main)) != NULL)){
6460 (void)context_apply(name, cntxt, cur_fn, sizeof(name));
6462 * Since the folder didn't exist it is very unlikely that it is
6463 * in the incoming-folders list already, but we're just checking
6464 * to be sure. We should really be canonicalizing both names
6465 * before comparing, but...
6467 for(found = 0, i = 0; *alval && (*alval)[i] && !found; i++){
6468 char *nickname, *folder;
6470 get_pair((*alval)[i], &nickname, &folder, 0, 0);
6471 if(folder && !strucmp((*alval)[i], folder))
6472 found++;
6474 if(nickname)
6475 fs_give((void **)&nickname);
6476 if(folder)
6477 fs_give((void **)&folder);
6480 if(found)
6481 return;
6483 space = MAXPROMPT;
6484 space -= 15; /* for fixed part of prompt below */
6485 w2 = MAX(1,
6486 MIN(space/2,MIN(strlen(ps_global->context_list->nickname),20)));
6487 w1 = MAX(1,space - w2);
6488 snprintf(prompt, sizeof(prompt),
6489 "Add \"%s\" to %s list",
6490 short_str(name,nbuf1,sizeof(nbuf1),w1,MidDots),
6491 short_str(ps_global->context_list->nickname,nbuf2,sizeof(nbuf2),w2,MidDots));
6492 prompt[sizeof(prompt)-1] = '\0';
6493 if(want_to(prompt, 'n', 'x', NO_HELP, WT_NORM) == 'y'){
6494 char *pp;
6496 nname[0] = '\0';
6497 space = MAXPROMPT;
6498 space -= 25;
6499 w1 = MAX(1, space);
6500 snprintf(prompt, sizeof(prompt), "Nickname for folder \"%s\" : ",
6501 short_str(name,nbuf1,sizeof(nbuf1),w1,MidDots));
6502 prompt[sizeof(prompt)-1] = '\0';
6503 while(1){
6504 int rc;
6505 int flags = OE_APPEND_CURRENT;
6507 rc = optionally_enter(nname, -FOOTER_ROWS(ps_global), 0,
6508 sizeof(nname), prompt, NULL,
6509 NO_HELP, &flags);
6510 removing_leading_and_trailing_white_space(nname);
6511 if(rc == 0 && *nname){
6512 /* see if nickname already exists */
6513 found = 0;
6514 if(!strucmp(ps_global->inbox_name, nname))
6515 found++;
6517 for(i = 0;
6518 !found &&
6519 i < folder_total(FOLDERS(ps_global->context_list));
6520 i++){
6521 FOLDER_S *f;
6523 f = folder_entry(i, FOLDERS(ps_global->context_list));
6524 if(!strucmp(FLDR_NAME(f), nname))
6525 found++;
6528 if(found){
6529 q_status_message1(SM_ORDER | SM_DING, 3, 5,
6530 _("Nickname \"%s\" is already in use"),
6531 nname);
6532 continue;
6535 break;
6537 else if(rc == 3)
6538 q_status_message(SM_ORDER, 0, 3, _("No help yet."));
6539 else if(rc == 1){
6540 q_status_message1(SM_ORDER, 0, 3,
6541 _("Not adding nickname to %s list"),
6542 ps_global->context_list->nickname);
6543 return;
6547 pp = put_pair(nname, name);
6548 f = new_folder(name, line_hash(pp));
6549 f->nickname = cpystr(nname);
6550 f->name_len = strlen(nname);
6551 folder_insert(folder_total(FOLDERS(ps_global->context_list)), f,
6552 FOLDERS(ps_global->context_list));
6554 if(!*alval){
6555 i = 0;
6556 *alval = (char **)fs_get(2 * sizeof(char *));
6558 else{
6559 for(i = 0; (*alval)[i]; i++)
6562 fs_resize((void **)alval, (i + 2) * sizeof(char *));
6565 (*alval)[i] = pp;
6566 (*alval)[i+1] = NULL;
6567 set_current_val(&ps_global->vars[V_INCOMING_FOLDERS], TRUE, TRUE);
6568 write_pinerc(ps_global, ew, WRP_NONE);
6575 role_filt_exitcheck(CONF_S **cl, unsigned int flags)
6577 int rv, j, action;
6578 char **to_folder = NULL, **spec_fldr = NULL;
6579 CONF_S *ctmp;
6580 NAMEVAL_S *f;
6581 #define ACT_UNKNOWN 0
6582 #define ACT_KILL 1
6583 #define ACT_MOVE 2
6584 #define ACT_MOVE_NOFOLDER 3
6585 #define ACT_STATE 4
6588 * We have to locate the lines which define the Filter Action and
6589 * then check to see that it is set to something before allowing
6590 * user to Exit.
6592 action = ACT_UNKNOWN;
6593 if(flags & CF_CHANGES && role_filt_ptr && PVAL(role_filt_ptr,ew)){
6594 for(j = 0; (f = filter_types(j)); j++)
6595 if(!strucmp(PVAL(role_filt_ptr,ew), f->name))
6596 break;
6598 switch(f ? f->value : -1){
6599 case FILTER_KILL:
6600 action = ACT_KILL;
6601 break;
6603 case FILTER_STATE:
6604 action = ACT_STATE;
6605 break;
6607 case FILTER_FOLDER:
6609 * Check that the folder is set to something.
6612 action = ACT_MOVE_NOFOLDER;
6613 /* go to end of screen */
6614 for(ctmp = (*cl);
6615 ctmp && ctmp->next;
6616 ctmp = next_confline(ctmp))
6619 /* back up to start of Filter Action */
6620 for(;
6621 ctmp &&
6622 !(ctmp->flags & CF_STARTITEM && ctmp->var == role_filt_ptr);
6623 ctmp = prev_confline(ctmp))
6626 /* skip back past NOSELECTs */
6627 for(;
6628 ctmp && (ctmp->flags & CF_NOSELECT);
6629 ctmp = next_confline(ctmp))
6632 /* find line with new var (the Folder line) */
6633 for(;
6634 ctmp && (ctmp->var == role_filt_ptr);
6635 ctmp = next_confline(ctmp))
6638 /* ok, we're finally at the Folder line */
6639 if(ctmp && ctmp->var && LVAL(ctmp->var,ew)){
6640 to_folder = copy_list_array(LVAL(ctmp->var,ew));
6641 if(to_folder && to_folder[0])
6642 action = ACT_MOVE;
6645 break;
6647 default:
6648 dprint((1,
6649 "Can't happen, role_filt_ptr set to %s\n",
6650 PVAL(role_filt_ptr,ew) ? PVAL(role_filt_ptr,ew) : "?"));
6651 break;
6655 if(flags & CF_CHANGES){
6656 switch(want_to((action == ACT_KILL)
6657 ? _("Commit changes (\"Yes\" means matching messages will be deleted)")
6658 : EXIT_PMT, 'y', 'x', h_config_undo, WT_FLUSH_IN)){
6659 case 'y':
6660 switch(action){
6661 case ACT_KILL:
6662 if((spec_fldr = get_role_specific_folder(cl)) != NULL){
6663 rv = check_role_folders(spec_fldr, 0);
6664 free_list_array(&spec_fldr);
6665 if(rv == 2)
6666 q_status_message(SM_ORDER,0,3,_("Ok, messages matching that Pattern will be deleted"));
6668 else{
6669 q_status_message(SM_ORDER, 0, 3,
6670 _("Ok, messages matching that Pattern will be deleted"));
6671 rv = 2;
6673 break;
6675 case ACT_MOVE:
6676 if((spec_fldr = get_role_specific_folder(cl)) != NULL){
6677 rv = check_role_folders(spec_fldr, 0);
6678 free_list_array(&spec_fldr);
6679 if(to_folder && rv == 2)
6680 rv = check_role_folders(to_folder, 1);
6682 else
6683 rv = check_role_folders(to_folder, 1);
6685 break;
6687 case ACT_MOVE_NOFOLDER:
6688 rv = 0;
6689 q_status_message(SM_ORDER, 3, 5,
6690 _("Set a valid Filter Action before Exiting"));
6691 break;
6693 case ACT_STATE:
6694 if((spec_fldr = get_role_specific_folder(cl)) != NULL){
6695 rv = check_role_folders(spec_fldr, 0);
6696 free_list_array(&spec_fldr);
6698 else
6699 rv = 2;
6701 break;
6703 default:
6704 rv = 2;
6705 dprint((1,
6706 "This can't happen, role_filt_ptr or to_folder not set\n"));
6707 break;
6710 break;
6712 case 'n':
6713 q_status_message(SM_ORDER,3,5,_("No filter changes saved"));
6714 rv = 10;
6715 break;
6717 case 'x': /* ^C */
6718 default :
6719 q_status_message(SM_ORDER,3,5,_("Changes not yet saved"));
6720 rv = 0;
6721 break;
6724 else
6725 rv = 2;
6727 if(to_folder)
6728 free_list_array(&to_folder);
6730 return(rv);
6735 * Don't allow exit unless user has set the action to something.
6738 role_filt_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
6740 int rv;
6742 switch(cmd){
6743 case MC_EXIT:
6744 rv = role_filt_exitcheck(cl, flags);
6745 break;
6747 default:
6748 rv = role_text_tool(ps, cmd, cl, flags);
6749 break;
6752 return(rv);
6757 role_filt_addhdr_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
6759 int rv;
6761 switch(cmd){
6762 case MC_EXIT:
6763 rv = role_filt_exitcheck(cl, flags);
6764 break;
6766 default:
6767 rv = role_addhdr_tool(ps, cmd, cl, flags);
6768 break;
6771 return rv;
6775 role_addhdr_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
6777 int rv;
6779 switch(cmd){
6780 case MC_ADDHDR:
6781 case MC_EXIT:
6782 rv = role_text_tool(ps, cmd, cl, flags);
6783 break;
6785 default:
6786 rv = -1;
6787 break;
6790 return rv;
6794 * Don't allow exit unless user has set the action to something.
6797 role_filt_radiobutton_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
6799 int rv;
6801 switch(cmd){
6802 case MC_EXIT:
6803 rv = role_filt_exitcheck(cl, flags);
6804 break;
6806 default:
6807 rv = role_radiobutton_tool(ps, cmd, cl, flags);
6808 break;
6811 return(rv);
6816 * simple radio-button style variable handler
6819 role_radiobutton_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
6821 int rv = 0, i;
6822 CONF_S *ctmp, *spec_ctmp = NULL;
6823 NAMEVAL_S *rule;
6824 char **apval;
6826 switch(cmd){
6827 case MC_CHOICE : /* set/unset feature */
6829 /* back up to first line */
6830 for(ctmp = (*cl);
6831 ctmp && ctmp->prev && !(ctmp->prev->flags & CF_NOSELECT);
6832 ctmp = prev_confline(ctmp))
6835 for(i = 0; ctmp && (!(ctmp->flags & CF_NOSELECT)
6836 || (*cl)->var == role_fldr_ptr
6837 || (*cl)->var == role_afrom_ptr
6838 || (*cl)->var == role_filt_ptr);
6839 ctmp = next_confline(ctmp), i++){
6840 if(((*cl)->var == role_fldr_ptr) ||
6841 ((*cl)->var == role_afrom_ptr) ||
6842 ((*cl)->var == role_filt_ptr)){
6843 if((((*cl)->var == role_fldr_ptr) && !pat_fldr_types(i))
6844 || (((*cl)->var == role_afrom_ptr)
6845 && !inabook_fldr_types(i))
6846 || (((*cl)->var == role_filt_ptr) && !filter_types(i))){
6847 spec_ctmp = ctmp;
6848 break;
6852 ctmp->value[1] = ' ';
6855 /* turn on current value */
6856 (*cl)->value[1] = R_SELD;
6858 if((*cl)->var == role_fldr_ptr){
6859 for(ctmp = spec_ctmp;
6860 ctmp && ctmp->varnamep == spec_ctmp;
6861 ctmp = next_confline(ctmp))
6862 if((*cl)->varmem == FLDR_SPECIFIC)
6863 ctmp->flags &= ~CF_NOSELECT;
6864 else
6865 ctmp->flags |= CF_NOSELECT;
6867 rule = pat_fldr_types((*cl)->varmem);
6869 else if((*cl)->var == role_afrom_ptr){
6870 for(ctmp = spec_ctmp;
6871 ctmp && ctmp->varnamep == spec_ctmp;
6872 ctmp = next_confline(ctmp))
6873 if(((*cl)->varmem == IAB_SPEC_YES)
6874 || ((*cl)->varmem == IAB_SPEC_NO))
6875 ctmp->flags &= ~CF_NOSELECT;
6876 else
6877 ctmp->flags |= CF_NOSELECT;
6879 rule = inabook_fldr_types((*cl)->varmem);
6881 else if((*cl)->var == role_filt_ptr){
6882 for(ctmp = spec_ctmp;
6883 ctmp && ctmp->varnamep == spec_ctmp;
6884 ctmp = next_confline(ctmp))
6885 if((*cl)->varmem == FILTER_FOLDER)
6886 ctmp->flags &= ~CF_NOSELECT;
6887 else
6888 ctmp->flags |= CF_NOSELECT;
6890 rule = filter_types((*cl)->varmem);
6892 else if((*cl)->var == role_forw_ptr)
6893 rule = role_forw_types((*cl)->varmem);
6894 else if((*cl)->var == role_repl_ptr)
6895 rule = role_repl_types((*cl)->varmem);
6896 else if((*cl)->var == role_status1_ptr ||
6897 (*cl)->var == role_status2_ptr ||
6898 (*cl)->var == role_status3_ptr ||
6899 (*cl)->var == role_status4_ptr ||
6900 (*cl)->var == role_status5_ptr ||
6901 (*cl)->var == role_status6_ptr ||
6902 (*cl)->var == role_status7_ptr ||
6903 (*cl)->var == role_status8_ptr)
6904 rule = role_status_types((*cl)->varmem);
6905 else if((*cl)->var == msg_state1_ptr ||
6906 (*cl)->var == msg_state2_ptr ||
6907 (*cl)->var == msg_state3_ptr ||
6908 (*cl)->var == msg_state4_ptr)
6909 rule = msg_state_types((*cl)->varmem);
6910 else
6911 rule = role_comp_types((*cl)->varmem);
6913 apval = APVAL((*cl)->var, ew);
6914 if(apval && *apval)
6915 fs_give((void **)apval);
6917 if(apval)
6918 *apval = cpystr(rule->name);
6920 ps->mangled_body = 1; /* BUG: redraw it all for now? */
6921 rv = 1;
6923 break;
6925 case MC_EXIT: /* exit */
6926 rv = role_text_tool(ps, cmd, cl, flags);
6927 break;
6929 default :
6930 rv = -1;
6931 break;
6934 return(rv);
6939 role_sort_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
6941 int rv = 0, i;
6942 CONF_S *ctmp;
6943 char **apval;
6944 SortOrder def_sort;
6945 int def_sort_rev;
6947 apval = APVAL((*cl)->var, ew);
6949 switch(cmd){
6950 case MC_CHOICE : /* set/unset feature */
6952 if((*cl)->varmem >= 0){
6953 def_sort_rev = (*cl)->varmem >= (short) EndofList;
6954 def_sort = (SortOrder)((*cl)->varmem - (def_sort_rev * EndofList));
6956 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s", sort_name(def_sort),
6957 (def_sort_rev) ? "/Reverse" : "");
6958 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
6961 if(apval){
6962 if(*apval)
6963 fs_give((void **)apval);
6965 if((*cl)->varmem >= 0)
6966 *apval = cpystr(tmp_20k_buf);
6969 /* back up to first line */
6970 for(ctmp = (*cl);
6971 ctmp && ctmp->prev && !(ctmp->prev->flags & CF_NOSELECT);
6972 ctmp = prev_confline(ctmp))
6975 /* turn off all values */
6976 for(i = 0;
6977 ctmp && !(ctmp->flags & CF_NOSELECT);
6978 ctmp = next_confline(ctmp), i++)
6979 ctmp->value[1] = ' ';
6981 /* turn on current value */
6982 (*cl)->value[1] = R_SELD;
6984 ps->mangled_body = 1; /* BUG: redraw it all for now? */
6985 rv = 1;
6987 break;
6989 case MC_EXIT: /* exit */
6990 rv = role_text_tool(ps, cmd, cl, flags);
6991 break;
6993 default :
6994 rv = -1;
6995 break;
6998 return(rv);
7002 * Return an allocated list of the Specific Folder list for
7003 * roles, or NULL if Current Folder type is not set to
7004 * to Specific Folder
7006 * WARNING, the method used in obtaining the specific folder is
7007 * VERY dependent on the order in which it is presented on the
7008 * screen. If the Current Folder radio buttons were changed,
7009 * this function would probably need to be fixed accordingly.
7011 char **
7012 get_role_specific_folder(CONF_S **cl)
7014 CONF_S *ctmp;
7016 /* go to the first line */
7017 for(ctmp = *cl;
7018 ctmp && ctmp->prev;
7019 ctmp = prev_confline(ctmp))
7022 /* go to the current folder radio button list */
7023 while(ctmp && ctmp->var != role_fldr_ptr)
7024 ctmp = next_confline(ctmp);
7026 /* go to the specific folder button (caution) */
7027 while(ctmp && ctmp->varmem != FLDR_SPECIFIC)
7028 ctmp = next_confline(ctmp);
7030 /* check if selected (assumption of format "(*)" */
7031 if(ctmp && ctmp->value[1] == R_SELD){
7032 /* go to next line, the start of the list */
7033 ctmp = next_confline(ctmp);
7034 if(LVAL(ctmp->var, ew))
7035 return copy_list_array(LVAL(ctmp->var, ew));
7036 else{
7037 char **ltmp;
7040 * Need to allocate empty string so as not to confuse it
7041 * with the possibility that Specific Folder is not selected.
7043 ltmp = (char **) fs_get(2 * sizeof(char *));
7044 ltmp[0] = cpystr("");
7045 ltmp[1] = NULL;
7046 return(ltmp);
7049 else
7050 return NULL;
7057 role_litsig_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7059 int rv;
7061 switch(cmd){
7062 case MC_ADD :
7063 case MC_EDIT :
7064 rv = litsig_text_tool(ps, cmd, cl, flags);
7065 if(rv)
7066 calculate_inick_stuff(ps);
7068 break;
7070 default :
7071 rv = role_text_tool(ps, cmd, cl, flags);
7072 break;
7075 return(rv);
7082 role_cstm_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7084 int rv;
7086 switch(cmd){
7087 case MC_EXIT :
7088 rv = role_text_tool(ps, cmd, cl, flags);
7089 break;
7091 default :
7092 rv = text_tool(ps, cmd, cl, flags);
7093 if(rv == 1 && (*cl)->var){
7094 char **lval;
7096 lval = LVAL((*cl)->var, ew);
7097 if(lval && lval[(*cl)->varmem] &&
7098 ((!struncmp(lval[(*cl)->varmem],"from",4) &&
7099 (lval[(*cl)->varmem][4] == ':' ||
7100 lval[(*cl)->varmem][4] == '\0')) ||
7101 (!struncmp(lval[(*cl)->varmem],"reply-to",8) &&
7102 (lval[(*cl)->varmem][8] == ':' ||
7103 lval[(*cl)->varmem][8] == '\0'))))
7104 q_status_message1(SM_ORDER|SM_DING, 5, 7,
7105 "Use \"Set %s\" instead, Change ignored",
7106 !struncmp(lval[(*cl)->varmem],"from",4)
7107 ? "From" : "Reply-To");
7110 break;
7113 return(rv);
7120 role_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7122 OPT_SCREEN_S *saved_screen;
7123 int rv = -1, oeflags, len, sig, r, i, cancel = 0;
7124 char *file, *err, title[20], *newfile, *lc, *addr, *fldr = NULL, *tmpfldr;
7125 char dir2[MAXPATH+1], pdir[MAXPATH+1], *p;
7126 char full_filename[MAXPATH+1], filename[MAXPATH+1];
7127 char tmp[MAXPATH+1], **spec_fldr, **apval;
7128 EARB_S *earb, *ea, *eaprev;
7129 CONF_S *ctmp, *ctmpb, *newcp, *ctend;
7130 HelpType help;
7132 switch(cmd){
7133 case MC_EXIT :
7134 if(flags & CF_CHANGES){
7135 switch(want_to(EXIT_PMT, 'y', 'x', h_config_role_undo, WT_FLUSH_IN)){
7136 case 'y':
7137 if((spec_fldr = get_role_specific_folder(cl)) != NULL){
7138 rv = check_role_folders(spec_fldr, 0);
7139 free_list_array(&spec_fldr);
7141 else
7142 rv = 2;
7143 break;
7145 case 'n':
7146 q_status_message(SM_ORDER,3,5,_("No changes saved"));
7147 rv = 10;
7148 break;
7150 case 'x': /* ^C */
7151 q_status_message(SM_ORDER,3,5,_("Changes not yet saved"));
7152 rv = 0;
7153 break;
7156 else
7157 rv = 2;
7159 break;
7161 case MC_NOT : /* toggle between !matching and matching */
7162 ctmp = (*cl)->varnamep;
7163 if(ctmp->varname && ctmp->var && ctmp->var->name){
7164 if(!strncmp(ctmp->varname, NOT, NOTLEN) &&
7165 !strncmp(ctmp->var->name, NOT, NOTLEN)){
7166 rplstr(ctmp->var->name, strlen(ctmp->var->name)+1, NOTLEN, "");
7167 rplstr(ctmp->varname, strlen(ctmp->varname)+1, NOTLEN, "");
7168 strncpy(ctmp->varname+strlen(ctmp->varname)-1,
7169 repeat_char(NOTLEN, ' '), NOTLEN+1);
7170 strncat(ctmp->varname, "=", NOTLEN);
7172 else{
7173 rplstr(ctmp->var->name, strlen(ctmp->var->name)+NOTLEN+1, 0, NOT);
7174 strncpy(ctmp->varname+strlen(ctmp->varname)-1-NOTLEN, "=", NOTLEN);
7175 rplstr(ctmp->varname, strlen(ctmp->varname)+NOTLEN+1, 0, NOT);
7178 rv = 1;
7181 break;
7183 case MC_CHOICE : /* Choose a file */
7185 * In signature_path we read signature files relative to the pinerc
7186 * dir, so if user selects one that is in there we'll make it
7187 * relative instead of absolute, so it looks nicer.
7189 pdir[0] = '\0';
7190 if(ps_global->VAR_OPER_DIR){
7191 strncpy(pdir, ps_global->VAR_OPER_DIR, MAXPATH);
7192 pdir[MAXPATH] = '\0';
7193 len = strlen(pdir) + 1;
7195 else if((lc = last_cmpnt(ps_global->pinerc)) != NULL){
7196 strncpy(pdir, ps_global->pinerc, MIN(MAXPATH,lc-ps_global->pinerc));
7197 pdir[MIN(MAXPATH, lc-ps_global->pinerc)] = '\0';
7198 len = strlen(pdir);
7201 strncpy(title, "CHOOSE A", 15);
7202 strncpy(dir2, pdir, MAXPATH);
7204 filename[0] = '\0';
7205 build_path(full_filename, dir2, filename, sizeof(full_filename));
7207 r = file_lister(title, dir2, sizeof(dir2), filename, sizeof(filename), TRUE, FB_READ);
7208 ps->mangled_screen = 1;
7210 if(r == 1){
7211 build_path(full_filename, dir2, filename, sizeof(full_filename));
7212 removing_leading_and_trailing_white_space(full_filename);
7213 if(!strncmp(full_filename, pdir, strlen(pdir)))
7214 newfile = cpystr(full_filename + len);
7215 else
7216 newfile = cpystr(full_filename);
7218 apval = APVAL((*cl)->var, ew);
7219 if(apval && *apval)
7220 fs_give((void **)apval);
7222 if(apval)
7223 *apval = newfile;
7225 if((*cl)->value)
7226 fs_give((void **)&((*cl)->value));
7228 (*cl)->value = pretty_value(ps, *cl);
7229 rv = 1;
7231 else
7232 rv = 0;
7234 break;
7236 case MC_CHOICEB : /* Choose Addresses, no full names */
7237 addr = addr_book_multaddr_nf();
7238 ps->mangled_screen = 1;
7239 if(addr && (*cl)->var && (*cl)->var->is_list){
7240 char **ltmp, *tmp;
7241 int i;
7243 i = 0;
7244 for(tmp = addr; *tmp; tmp++)
7245 if(*tmp == ',')
7246 i++; /* conservative count of ,'s */
7248 ltmp = parse_list(addr, i + 1, PL_COMMAQUOTE, NULL);
7249 fs_give((void **) &addr);
7251 if(ltmp && ltmp[0])
7252 config_add_list(ps, cl, ltmp, NULL, 0);
7254 if(ltmp)
7255 fs_give((void **) &ltmp);
7257 if((*cl)->value)
7258 fs_give((void **)&((*cl)->value));
7260 (*cl)->value = pretty_value(ps, *cl);
7261 rv = 1;
7263 else
7264 rv = 0;
7266 break;
7268 case MC_CHOICEC : /* Choose an Address, no full name */
7269 addr = addr_book_oneaddr();
7270 ps->mangled_screen = 1;
7271 if(addr){
7272 apval = APVAL((*cl)->var, ew);
7273 if(apval && *apval) /* replace current value */
7274 fs_give((void **)apval);
7276 if(apval)
7277 *apval = addr;
7279 if((*cl)->value)
7280 fs_give((void **)&((*cl)->value));
7282 (*cl)->value = pretty_value(ps, *cl);
7283 rv = 1;
7285 else
7286 rv = 0;
7288 break;
7290 case MC_CHOICED : /* Choose a Folder */
7291 case MC_CHOICEE :
7292 saved_screen = opt_screen;
7293 if(cmd == MC_CHOICED)
7294 tmpfldr = folder_for_config(FOR_PATTERN);
7295 else
7296 tmpfldr = folder_for_config(0);
7298 if(tmpfldr){
7299 fldr = add_comma_escapes(tmpfldr);
7300 fs_give((void**) &tmpfldr);
7303 opt_screen = saved_screen;
7305 ps->mangled_screen = 1;
7306 if(fldr && *fldr && (*cl)->var && (*cl)->var->is_list){
7307 char **ltmp;
7309 ltmp = (char **) fs_get(2 * sizeof(char *));
7310 ltmp[0] = fldr;
7311 ltmp[1] = NULL;
7312 fldr = NULL;
7314 if(ltmp && ltmp[0])
7315 config_add_list(ps, cl, ltmp, NULL, 0);
7317 if(ltmp)
7318 fs_give((void **) &ltmp);
7320 if((*cl)->value)
7321 fs_give((void **) &((*cl)->value));
7323 (*cl)->value = pretty_value(ps, *cl);
7324 rv = 1;
7326 else if(fldr && *fldr && (*cl)->var && !(*cl)->var->is_list){
7327 apval = APVAL((*cl)->var, ew);
7328 if(apval && *apval) /* replace current value */
7329 fs_give((void **)apval);
7331 if(apval){
7332 *apval = fldr;
7333 fldr = NULL;
7336 if((*cl)->value)
7337 fs_give((void **) &((*cl)->value));
7339 (*cl)->value = pretty_value(ps, *cl);
7340 rv = 1;
7342 else
7343 rv = 0;
7345 if(fldr)
7346 fs_give((void **) &fldr);
7348 break;
7350 case MC_EDITFILE :
7351 file = ((*cl)->var && PVAL((*cl)->var, ew))
7352 ? cpystr(PVAL((*cl)->var, ew)) : NULL;
7353 if(file)
7354 removing_leading_and_trailing_white_space(file);
7356 sig = (srchstr((*cl)->varname, "signature") != NULL);
7357 if(!file || !*file){
7358 err = (char *)fs_get(100 * sizeof(char));
7359 snprintf(err, 100, "No %s file defined. First define a file name.",
7360 sig ? "signature" : "template");
7361 err[100-1] = '\0';
7363 else{
7364 if(file[len=(strlen(file)-1)] == '|')
7365 file[len] = '\0';
7367 snprintf(title, sizeof(title), "%s EDITOR", sig ? "SIGNATURE" : "TEMPLATE");
7368 title[sizeof(title)-1] = '\0';
7369 err = signature_edit(file, title);
7372 fs_give((void **)&file);
7373 if(err){
7374 q_status_message1(SM_ORDER, 3, 5, "%s", err);
7375 fs_give((void **)&err);
7378 rv = 0;
7379 ps->mangled_screen = 1;
7380 break;
7382 /* Add an arbitrary header to this role */
7383 case MC_ADDHDR :
7384 rv = 0;
7385 /* make earb point to last one */
7386 for(earb = *(*cl)->d.earb; earb && earb->next; earb = earb->next)
7389 /* Add new one to end of list */
7390 ea = (EARB_S *)fs_get(sizeof(*ea));
7391 memset((void *)ea, 0, sizeof(*ea));
7392 ea->v = (struct variable *)fs_get(sizeof(struct variable));
7393 memset((void *)ea->v, 0, sizeof(struct variable));
7394 ea->a = (ARBHDR_S *)fs_get(sizeof(ARBHDR_S));
7395 memset((void *)ea->a, 0, sizeof(ARBHDR_S));
7397 /* get new header field name */
7398 help = NO_HELP;
7399 tmp[0] = '\0';
7400 while(1){
7401 i = optionally_enter(tmp, -FOOTER_ROWS(ps), 0, sizeof(tmp),
7402 _("Enter the name of the header field to be added: "),
7403 NULL, help, NULL);
7404 if(i == 0)
7405 break;
7406 else if(i == 1){
7407 cmd_cancelled("eXtraHdr");
7408 cancel = 1;
7409 break;
7411 else if(i == 3){
7412 help = help == NO_HELP ? h_config_add_pat_hdr : NO_HELP;
7413 continue;
7415 else
7416 break;
7419 ps->mangled_footer = 1;
7421 removing_leading_and_trailing_white_space(tmp);
7422 if(tmp[strlen(tmp)-1] == ':') /* remove trailing colon */
7423 tmp[strlen(tmp)-1] = '\0';
7425 removing_trailing_white_space(tmp);
7427 if(cancel || !tmp[0])
7428 break;
7430 tmp[0] = islower((unsigned char)tmp[0]) ? toupper((unsigned char)tmp[0])
7431 : tmp[0];
7432 ea->a->field = cpystr(tmp);
7434 if(earb)
7435 earb->next = ea;
7436 else
7437 *((*cl)->d.earb) = ea;
7439 /* go to first line */
7440 for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
7444 * Go to the Add Extra Headers line. We will put the
7445 * new header before this line.
7447 for(; ctmp; ctmp = next_confline(ctmp))
7448 if(ctmp->value && !strcmp(ctmp->value, ADDXHDRS))
7449 break;
7451 /* move back one */
7452 if(ctmp)
7453 ctmp = prev_confline(ctmp);
7456 * Add a new line after this point, which is after the last
7457 * extra header (if any) or after the Participant pattern, and
7458 * before the Add Extra Headers placeholder line.
7460 p = (char *) fs_get(strlen(tmp) + strlen(" pattern") + 1);
7461 snprintf(p, strlen(tmp) + strlen(" pattern") + 1, "%s pattern", tmp);
7462 p[strlen(tmp) + strlen(" pattern") + 1 - 1] = '\0';
7463 setup_dummy_pattern_var(ea->v, p, NULL);
7464 fs_give((void **) &p);
7466 /* find what indent should be */
7467 if(ctmp && ctmp->varnamep && ctmp->varnamep->varname)
7468 i = MIN(MAX(utf8_width(ctmp->varnamep->varname) + 1, 3), 200);
7469 else
7470 i = 20;
7472 setup_role_pat(ps, &ctmp, ea->v, h_config_role_arbpat,
7473 ARB_HELP, &config_role_xtrahdr_keymenu,
7474 ctmp->prev->tool, ctmp->prev->d.earb, i);
7477 * move current line to new line
7480 newcp = ctmp;
7482 /* check if new line comes before the top of the screen */
7483 ctmpb = (opt_screen && opt_screen->top_line)
7484 ? opt_screen->top_line->prev : NULL;
7485 for(; ctmpb; ctmpb = prev_confline(ctmpb))
7486 if(ctmpb == newcp)
7487 break;
7489 * Keep the right lines visible.
7490 * The if triggers if the new line is off the top of the screen, and
7491 * it makes the new line be the top line.
7492 * The else counts how many lines down the screen the new line is.
7495 i = 0;
7496 if(ctmpb == newcp)
7497 opt_screen->top_line = newcp;
7498 else{
7499 for(ctmp = opt_screen->top_line; ctmp && ctmp != newcp;
7500 i++, ctmp = next_confline(ctmp))
7504 if(i >= BODY_LINES(ps)){ /* new line is off screen */
7505 /* move top line down this far */
7506 i = i + 1 - BODY_LINES(ps);
7507 for(ctmp = opt_screen->top_line;
7508 i > 0;
7509 i--, ctmp = next_confline(ctmp))
7512 opt_screen->top_line = ctmp;
7515 *cl = newcp;
7517 ps->mangled_screen = 1;
7518 rv = 1;
7519 break;
7521 /* Delete an arbitrary header from this role */
7522 case MC_DELHDR :
7524 * Find this one in earb list. We don't have a good way to locate
7525 * it so we match the ea->v->name with ctmp->varname.
7527 rv = 0;
7528 eaprev = NULL;
7529 for(ea = *(*cl)->d.earb; ea; ea = ea->next){
7530 if((*cl)->varnamep && (*cl)->varnamep->varname
7531 && ea->v && ea->v->name
7532 && !strncmp((*cl)->varnamep->varname,
7533 ea->v->name, strlen(ea->v->name)))
7534 break;
7536 eaprev = ea;
7539 snprintf(tmp, sizeof(tmp), _("Really remove \"%s\" pattern from this rule"),
7540 (ea && ea->a && ea->a->field) ? ea->a->field : "this");
7541 tmp[sizeof(tmp)-1] = '\0';
7542 if(want_to(tmp, 'y', 'n', NO_HELP, WT_NORM) != 'y'){
7543 cmd_cancelled("RemoveHdr");
7544 return(rv);
7547 /* delete the earb element from the list */
7548 if(ea){
7549 if(eaprev)
7550 eaprev->next = ea->next;
7551 else
7552 *(*cl)->d.earb = ea->next;
7554 ea->next = NULL;
7555 free_earb(&ea);
7558 /* remember start of deleted header */
7559 ctmp = (*cl && (*cl)->varnamep) ? (*cl)->varnamep : NULL;
7561 /* and end of deleted header */
7562 for(ctend = *cl; ctend; ctend = next_confline(ctend))
7563 if(!ctend->next || ctend->next->varnamep != ctmp)
7564 break;
7566 /* check if top line is one we're deleting */
7567 for(ctmpb = ctmp; ctmpb; ctmpb = next_confline(ctmpb)){
7568 if(ctmpb == opt_screen->top_line)
7569 break;
7571 if(ctmpb == (*cl))
7572 break;
7575 if(ctmpb == opt_screen->top_line)
7576 opt_screen->top_line = ctend ? ctend->next : NULL;
7578 /* move current line after this header */
7579 *cl = ctend ? ctend->next : NULL;
7581 /* remove deleted header lines */
7582 if(ctmp && ctend){
7583 /* remove from linked list */
7584 if(ctmp->prev)
7585 ctmp->prev->next = ctend->next;
7587 if(ctend->next)
7588 ctend->next->prev = ctmp->prev;
7590 /* free memory */
7591 ctmp->prev = ctend->next = NULL;
7592 free_conflines(&ctmp);
7595 ps->mangled_body = 1;
7596 rv = 1;
7597 break;
7599 default :
7600 if(((*cl)->var == scorei_pat_global_ptr
7601 || (*cl)->var == age_pat_global_ptr
7602 || (*cl)->var == size_pat_global_ptr
7603 || (*cl)->var == cati_global_ptr)
7605 (cmd == MC_EDIT || (cmd == MC_ADD && !PVAL((*cl)->var, ew)))){
7606 char prompt[60];
7608 rv = 0;
7609 snprintf(prompt, sizeof(prompt), "%s the interval : ",
7610 PVAL((*cl)->var, ew) ? "Change" : "Enter");
7611 prompt[sizeof(prompt)-1] = '\0';
7613 ps->mangled_footer = 1;
7614 help = NO_HELP;
7615 tmp[0] = '\0';
7616 snprintf(tmp, sizeof(tmp),
7617 "%s", PVAL((*cl)->var, ew) ? PVAL((*cl)->var, ew) : "");
7618 tmp[sizeof(tmp)-1] = '\0';
7619 while(1){
7620 oeflags = OE_APPEND_CURRENT;
7621 i = optionally_enter(tmp, -FOOTER_ROWS(ps), 0, sizeof(tmp),
7622 prompt, NULL, help, &oeflags);
7623 if(i == 0){
7624 rv = ps->mangled_body = 1;
7625 apval = APVAL((*cl)->var, ew);
7626 if(apval && *apval)
7627 fs_give((void **)apval);
7629 if(apval && tmp[0])
7630 *apval = cpystr(tmp);
7632 fix_side_effects(ps, (*cl)->var, 0);
7633 if((*cl)->value)
7634 fs_give((void **)&(*cl)->value);
7636 (*cl)->value = pretty_value(ps, *cl);
7638 else if(i == 1)
7639 cmd_cancelled(cmd == MC_ADD ? "Add" : "Change");
7640 else if(i == 3){
7641 help = help == NO_HELP ? h_config_edit_scorei : NO_HELP;
7642 continue;
7644 else if(i == 4)
7645 continue;
7647 break;
7650 else{
7651 if(cmd == MC_ADD && (*cl)->var && !(*cl)->var->is_list)
7652 cmd = MC_EDIT;
7654 rv = text_toolit(ps, cmd, cl, flags, 1);
7656 /* make sure the earb pointers are set */
7657 for(ctmp = (*cl)->varnamep;
7658 ctmp->next && ctmp->next->var == ctmp->var;
7659 ctmp = next_confline(ctmp))
7660 ctmp->next->d.earb = ctmp->d.earb;
7663 break;
7667 * If the inherit nickname changed, we have to re-calculate the
7668 * global_vals and values for the action variables.
7669 * We may have to do the same if literal sig changed, too.
7671 if(rv)
7672 calculate_inick_stuff(ps);
7674 return(rv);
7681 role_text_tool_inick(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7683 int rv = -1;
7684 char **apval;
7686 switch(cmd){
7687 case MC_EXIT :
7688 rv = role_text_tool(ps, cmd, cl, flags);
7689 break;
7691 case MC_CHOICE : /* Choose a role nickname */
7692 {void (*prev_screen)(struct pine *) = ps->prev_screen,
7693 (*redraw)(void) = ps->redrawer;
7694 OPT_SCREEN_S *saved_screen;
7695 ACTION_S *role;
7697 ps->redrawer = NULL;
7698 ps->next_screen = SCREEN_FUN_NULL;
7700 saved_screen = opt_screen;
7701 if(role_select_screen(ps, &role, 0) == 0){
7702 apval = APVAL((*cl)->var, ew);
7703 if(apval && *apval)
7704 fs_give((void **)apval);
7706 if(apval)
7707 *apval = (role && role->nick) ? cpystr(role->nick) : NULL;
7709 if((*cl)->value)
7710 fs_give((void **)&((*cl)->value));
7712 (*cl)->value = pretty_value(ps, *cl);
7713 rv = 1;
7715 else{
7716 ps->next_screen = prev_screen;
7717 ps->redrawer = redraw;
7718 rv = 0;
7721 opt_screen = saved_screen;
7724 ps->mangled_screen = 1;
7725 break;
7727 case MC_EDIT :
7728 case MC_ADD :
7729 case MC_DELETE :
7730 rv = text_tool(ps, cmd, cl, flags);
7731 ps->mangled_screen = 1;
7732 break;
7734 default :
7735 rv = text_tool(ps, cmd, cl, flags);
7736 break;
7740 * If the inherit nickname changed, we have to re-calculate the
7741 * global_vals and values for the action variables.
7742 * We may have to do the same if literal sig changed, too.
7744 if(rv)
7745 calculate_inick_stuff(ps);
7747 return(rv);
7754 role_text_tool_kword(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7756 int i, j, rv = -1;
7757 char **lval;
7759 switch(cmd){
7760 case MC_CHOICE : /* Choose keywords from list and add them */
7761 {void (*prev_screen)(struct pine *) = ps->prev_screen,
7762 (*redraw)(void) = ps->redrawer;
7763 OPT_SCREEN_S *saved_screen;
7764 char *esc;
7765 char **kw;
7767 ps->redrawer = NULL;
7768 ps->next_screen = SCREEN_FUN_NULL;
7770 saved_screen = opt_screen;
7772 if((kw=choose_list_of_keywords()) != NULL){
7773 for(i = 0; kw[i]; i++){
7774 esc = add_roletake_escapes(kw[i]);
7775 fs_give((void **) &kw[i]);
7776 kw[i] = esc;
7779 /* eliminate duplicates before the add */
7780 lval = LVAL((*cl)->var, ew);
7781 if(lval && *lval){
7782 for(i = 0; kw[i]; ){
7783 /* if kw[i] is a dup, eliminate it */
7784 for(j = 0; lval[j]; j++)
7785 if(!strcmp(kw[i], lval[j]))
7786 break;
7788 if(lval[j]){ /* it is a dup */
7789 for(j = i; kw[j]; j++)
7790 kw[j] = kw[j+1];
7792 else
7793 i++;
7797 if(kw[0])
7798 config_add_list(ps, cl, kw, NULL, 0);
7800 fs_give((void **) &kw);
7802 if((*cl)->value)
7803 fs_give((void **) &((*cl)->value));
7805 (*cl)->value = pretty_value(ps, *cl);
7806 rv = 1;
7808 else{
7809 ps->next_screen = prev_screen;
7810 ps->redrawer = redraw;
7811 rv = 0;
7814 opt_screen = saved_screen;
7817 ps->mangled_screen = 1;
7818 break;
7820 case MC_EDIT :
7821 case MC_ADD :
7822 case MC_DELETE :
7823 case MC_NOT :
7824 rv = role_text_tool(ps, cmd, cl, flags);
7825 ps->mangled_screen = 1;
7826 break;
7828 case MC_EXIT :
7829 default :
7830 rv = role_text_tool(ps, cmd, cl, flags);
7831 break;
7834 return(rv);
7841 role_text_tool_charset(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7843 int i, j, rv = -1;
7844 char **lval;
7846 switch(cmd){
7847 case MC_CHOICE : /* Choose charsets from list and add them */
7848 {void (*prev_screen)(struct pine *) = ps->prev_screen,
7849 (*redraw)(void) = ps->redrawer;
7850 OPT_SCREEN_S *saved_screen;
7851 char *esc;
7852 char **kw;
7854 ps->redrawer = NULL;
7855 ps->next_screen = SCREEN_FUN_NULL;
7857 saved_screen = opt_screen;
7859 if((kw=choose_list_of_charsets()) != NULL){
7860 for(i = 0; kw[i]; i++){
7861 esc = add_roletake_escapes(kw[i]);
7862 fs_give((void **) &kw[i]);
7863 kw[i] = esc;
7866 /* eliminate duplicates before the add */
7867 lval = LVAL((*cl)->var, ew);
7868 if(lval && *lval){
7869 for(i = 0; kw[i]; ){
7870 /* if kw[i] is a dup, eliminate it */
7871 for(j = 0; lval[j]; j++)
7872 if(!strcmp(kw[i], lval[j]))
7873 break;
7875 if(lval[j]){ /* it is a dup */
7876 for(j = i; kw[j]; j++)
7877 kw[j] = kw[j+1];
7879 else
7880 i++;
7884 if(kw[0])
7885 config_add_list(ps, cl, kw, NULL, 0);
7887 fs_give((void **) &kw);
7889 if((*cl)->value)
7890 fs_give((void **) &((*cl)->value));
7892 (*cl)->value = pretty_value(ps, *cl);
7893 rv = 1;
7895 else{
7896 ps->next_screen = prev_screen;
7897 ps->redrawer = redraw;
7898 rv = 0;
7901 opt_screen = saved_screen;
7904 ps->mangled_screen = 1;
7905 break;
7907 case MC_EDIT :
7908 case MC_ADD :
7909 case MC_DELETE :
7910 case MC_NOT :
7911 rv = role_text_tool(ps, cmd, cl, flags);
7912 ps->mangled_screen = 1;
7913 break;
7915 case MC_EXIT :
7916 default :
7917 rv = role_text_tool(ps, cmd, cl, flags);
7918 break;
7921 return(rv);
7926 * Choose an address book nickname
7929 role_text_tool_afrom(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7931 int rv = -1;
7933 switch(cmd){
7934 case MC_EXIT :
7935 rv = role_text_tool(ps, cmd, cl, flags);
7936 break;
7938 case MC_CHOICE : /* Choose an addressbook */
7939 {OPT_SCREEN_S *saved_screen;
7940 char *abook = NULL, *abookesc = NULL;
7942 ps->redrawer = NULL;
7943 ps->next_screen = SCREEN_FUN_NULL;
7944 saved_screen = opt_screen;
7946 abook = abook_select_screen(ps);
7947 if(abook){
7948 abookesc = add_comma_escapes(abook);
7949 fs_give((void**) &abook);
7952 ps->mangled_screen = 1;
7953 if(abookesc && *abookesc && (*cl)->var && (*cl)->var->is_list){
7954 char **ltmp;
7956 ltmp = (char **) fs_get(2 * sizeof(char *));
7957 ltmp[0] = abookesc;
7958 ltmp[1] = NULL;
7959 abookesc = NULL;
7961 if(ltmp && ltmp[0])
7962 config_add_list(ps, cl, ltmp, NULL, 0);
7964 if(ltmp)
7965 fs_give((void **) &ltmp);
7967 if((*cl)->value)
7968 fs_give((void **) &((*cl)->value));
7970 (*cl)->value = pretty_value(ps, *cl);
7971 rv = 1;
7973 else
7974 rv = 0;
7976 if(abookesc)
7977 fs_give((void **) &abookesc);
7979 opt_screen = saved_screen;
7982 ps->mangled_screen = 1;
7983 break;
7985 default :
7986 rv = text_tool(ps, cmd, cl, flags);
7987 ps->mangled_screen = 1;
7988 break;
7991 return(rv);
7996 * Args fmt -- a printf style fmt string with a single %s
7997 * buf -- place to put result, assumed large enough (strlen(fmt)+11)
7998 * rflags -- controls what goes in buf
8000 * Returns -- pointer to buf
8002 char *
8003 role_type_print(char *buf, size_t buflen, char *fmt, long int rflags)
8005 #define CASE_MIXED 1
8006 #define CASE_UPPER 2
8007 #define CASE_LOWER 3
8008 int cas = CASE_UPPER;
8009 int prev_word_is_a = 0;
8010 char *q, *p;
8012 /* find %sRule to see what case */
8013 if((p = srchstr(fmt, "%srule")) != NULL){
8014 if(p[2] == 'R'){
8015 if(p[3] == 'U')
8016 cas = CASE_UPPER;
8017 else
8018 cas = CASE_MIXED;
8020 else
8021 cas = CASE_LOWER;
8023 if(p-3 >= fmt &&
8024 p[-1] == SPACE &&
8025 (p[-2] == 'a' || p[-2] == 'A')
8026 && p[-3] == SPACE)
8027 prev_word_is_a++;
8030 if(cas == CASE_UPPER)
8031 q = (rflags & ROLE_DO_INCOLS) ? "INDEX COLOR " :
8032 (rflags & ROLE_DO_FILTER) ? "FILTERING " :
8033 (rflags & ROLE_DO_SCORES) ? "SCORING " :
8034 (rflags & ROLE_DO_OTHER) ? "OTHER " :
8035 (rflags & ROLE_DO_SRCH) ? "SEARCH " :
8036 (rflags & ROLE_DO_ROLES) ? "ROLE " : "";
8037 else if(cas == CASE_LOWER)
8038 q = (rflags & ROLE_DO_INCOLS) ? "index color " :
8039 (rflags & ROLE_DO_FILTER) ? "filtering " :
8040 (rflags & ROLE_DO_SCORES) ? "scoring " :
8041 (rflags & ROLE_DO_OTHER) ? "other " :
8042 (rflags & ROLE_DO_OTHER) ? "search " :
8043 (rflags & ROLE_DO_ROLES) ? "role " : "";
8044 else
8045 q = (rflags & ROLE_DO_INCOLS) ? "Index Color " :
8046 (rflags & ROLE_DO_FILTER) ? "Filtering " :
8047 (rflags & ROLE_DO_SCORES) ? "Scoring " :
8048 (rflags & ROLE_DO_OTHER) ? "Other " :
8049 (rflags & ROLE_DO_OTHER) ? "Search " :
8050 (rflags & ROLE_DO_ROLES) ? "Role " : "";
8052 /* it ain't right to say "a index" */
8053 if(prev_word_is_a && !struncmp(q, "index", 5))
8054 q += 6;
8056 snprintf(buf, buflen, fmt, q);
8057 buf[buflen-1] = '\0';
8058 return(buf);
8063 * filter option list manipulation tool
8066 * returns: -1 on unrecognized cmd, 0 if no change, 1 if change
8069 feat_checkbox_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
8071 int rv = 0;
8073 switch(cmd){
8074 case MC_TOGGLE: /* mark/unmark option */
8075 rv = 1;
8076 toggle_feat_option_bit(ps, (*cl)->varmem, (*cl)->var, (*cl)->value);
8077 break;
8079 case MC_EXIT: /* exit */
8080 rv = role_filt_exitcheck(cl, flags);
8081 break;
8083 default :
8084 rv = -1;
8085 break;
8088 return(rv);
8092 void
8093 toggle_feat_option_bit(struct pine *ps, int index, struct variable *var, char *value)
8095 NAMEVAL_S *f;
8097 f = feat_feature_list(index);
8099 /* flip the bit */
8100 if(bitnset(f->value, feat_option_list))
8101 clrbitn(f->value, feat_option_list);
8102 else
8103 setbitn(f->value, feat_option_list);
8105 if(value)
8106 value[1] = bitnset(f->value, feat_option_list) ? 'X' : ' ';
8110 NAMEVAL_S *
8111 feat_feature_list(int index)
8113 static NAMEVAL_S opt_feat_list[] = {
8114 {"use-date-header-for-age", NULL, FEAT_SENTDATE},
8115 {"move-only-if-not-deleted", NULL, FEAT_IFNOTDEL},
8116 {"dont-stop-even-if-rule-matches", NULL, FEAT_NONTERM}
8119 return((index >= 0 &&
8120 index < (sizeof(opt_feat_list)/sizeof(opt_feat_list[0])))
8121 ? &opt_feat_list[index] : NULL);
8126 * address type list manipulation tool
8129 * returns: -1 on unrecognized cmd, 0 if no change, 1 if change
8132 inabook_checkbox_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
8134 int rv = 0;
8136 switch(cmd){
8137 case MC_TOGGLE: /* mark/unmark option */
8138 rv = 1;
8139 toggle_inabook_type_bit(ps, (*cl)->varmem, (*cl)->var, (*cl)->value);
8140 break;
8142 case MC_EXIT: /* exit */
8143 rv = role_filt_exitcheck(cl, flags);
8144 break;
8146 default :
8147 rv = -1;
8148 break;
8151 return(rv);
8155 void
8156 toggle_inabook_type_bit(struct pine *ps, int index, struct variable *var, char *value)
8158 NAMEVAL_S *f;
8160 f = inabook_feature_list(index);
8162 /* flip the bit */
8163 if(bitnset(f->value, inabook_type_list))
8164 clrbitn(f->value, inabook_type_list);
8165 else
8166 setbitn(f->value, inabook_type_list);
8168 if(value)
8169 value[1] = bitnset(f->value, inabook_type_list) ? 'X' : ' ';
8173 NAMEVAL_S *
8174 inabook_feature_list(int index)
8176 static NAMEVAL_S inabook_feat_list[] = {
8177 {"From", NULL, INABOOK_FROM},
8178 {"Reply-To", NULL, INABOOK_REPLYTO},
8179 {"Sender", NULL, INABOOK_SENDER},
8180 {"To", NULL, INABOOK_TO},
8181 {"Cc", NULL, INABOOK_CC}
8184 return((index >= 0 &&
8185 index < (sizeof(inabook_feat_list)/sizeof(inabook_feat_list[0])))
8186 ? &inabook_feat_list[index] : NULL);