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
4 
5 /*
6  * ========================================================================
7  * Copyright 2006-2008 University of Washington
8  * Copyright 2013-2021 Eduardo Chappa
9  *
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
13  *
14  *     http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * ========================================================================
17  */
18 
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"
48 
49 
50 #define NOT		"! "
51 #define NOTLEN		2
52 
53 
54 #define ARB_HELP _("HELP FOR ARBITRARY HEADER PATTERNS")
55 #define ADDXHDRS _("Add Extra Headers")
56 
57 
58 /*
59  * Internal prototypes
60  */
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);
116 
117 
118 static char *set_choose = "---  --------------------";
119 static long role_global_flags;
120 static PAT_STATE *role_global_pstate;
121 
122 
123 int
role_select_screen(struct pine * ps,ACTION_S ** role,int alt_compose)124 role_select_screen(struct pine *ps, ACTION_S **role, int alt_compose)
125 {
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;
135 
136     if(!role)
137       return(ret);
138 
139     *role = NULL;
140 
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);
146     }
147 
148 
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);
164     }
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);
170     }
171 
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");
179 
180     menu_init_binding(&role_select_km, 'D', MC_TOGGLE, "D", "changeDef", CHANGEDEF_KEY);
181 
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;
188 
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;
200     }
201 
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);
207 
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;
214 
215 	ret = 0;
216     }
217 
218     ps->mangled_screen = 1;
219     return(ret);
220 }
221 
222 
223 int
role_select_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)224 role_select_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
225 {
226     int retval = 0, newval;
227 
228     switch(cmd){
229       case MC_CHOICE :
230 	*((*cl)->d.r.selected) = (*cl)->d.r.pat;
231 	retval = simple_exit_cmd(flags);
232 	break;
233 
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"));
247 	}
248 	else if(newval == 2){
249 	    q_status_message(SM_ORDER, 0, 3, _("Default role will be unset"));
250 	}
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"));
256 	}
257 
258 	ps->mangled_footer = 1;
259 	retval = 0;
260 	break;
261 
262       case MC_EXIT :
263         retval = simple_exit_cmd(flags);
264 	break;
265 
266       default:
267 	retval = -1;
268 	break;
269     }
270 
271     if(retval > 0)
272       ps->mangled_body = 1;
273 
274     return(retval);
275 }
276 
277 
278 void
role_config_screen(struct pine * ps,long int rflags,int edit_exceptions)279 role_config_screen(struct pine *ps, long int rflags, int edit_exceptions)
280 {
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;
287 
288     dprint((4, "role_config_screen()\n"));
289 
290     if(ps->fix_fixed_warning)
291       offer_to_fix_pinerc(ps);
292 
293     ew = edit_exceptions ? ps_global->ew_for_except_vars : Main;
294 
295     if(ps->restricted)
296       readonly_warning = 1;
297     else{
298 	PINERC_S *prc = NULL;
299 
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;
311 	}
312 
313 	readonly_warning = prc ? prc->readonly : 1;
314 	if(prc && prc->quit_to_edit){
315 	    quit_to_edit_msg(prc);
316 	    return;
317 	}
318     }
319 
320     if(!any_patterns(rflags, &pstate))
321       return;
322 
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];
335 
336     if((ps_global->ew_for_except_vars != Main) && (ew == Main)){
337 	char           **lval;
338 
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);
343 	}
344     }
345 
346     role_type_print(title, sizeof(title), "%sRules", rflags);
347     if(fixed_var(v, "change", title))
348       return;
349 
350 uh_oh:
351     first_line = NULL;
352 
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);
359 
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;
371     }
372 
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;
380 
381 	case 10:
382 	  /* flush changes and re-read orig */
383 	  close_patterns(rflags);
384 	  break;
385 
386 	case 1:
387 	  if(write_patterns(rflags))
388 	    goto uh_oh;
389 
390 	  /*
391 	   * Flush out current_vals of anything we've possibly changed.
392 	   */
393 
394 	  if(ps_global->default_role){
395 	      q_status_message(SM_ORDER,0,3, "Default role is unset");
396 	      ps_global->default_role = NULL;
397 	  }
398 
399 	  close_patterns((rflags & ROLE_MASK) | PAT_USE_CURRENT);
400 
401 	  /* scores may have changed */
402 	  if(rflags & ROLE_DO_SCORES){
403 	      int         i;
404 	      MAILSTREAM *m;
405 
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);
411 		  }
412 	      }
413 
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);
417 	  }
418 
419 	  /* recalculate need for scores */
420 	  scores_are_used(SCOREUSE_INVALID);
421 
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());
427 
428 	  if(rflags & ROLE_DO_INCOLS && pico_usingcolor())
429 	    clear_index_cache(ps_global->mail_stream, 0);
430 
431 	  if(rflags & ROLE_DO_FILTER)
432 	    role_process_filters();
433 
434 	  /*
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.
437 	   */
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);
443 	  }
444 
445 	  break;
446 
447 	default:
448 	  q_status_message(SM_ORDER,7,10, "conf_scroll_screen unexpected ret");
449 	  break;
450     }
451 
452     role_global_flags = 0;
453     ps->mangled_screen = 1;
454 }
455 
456 
457 /*
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.
461  */
462 void
role_take(struct pine * ps,MSGNO_S * msgmap,int rtype)463 role_take(struct pine *ps, MSGNO_S *msgmap, int rtype)
464 {
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;
472 
473     dprint((4, "role_take()\n"));
474 
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);
479 
480 	if(!env){
481 	    q_status_message(SM_ORDER, 3, 7,
482 			     _("problem getting addresses from message"));
483 	    return;
484 	}
485     }
486 
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;
512 
513       default:
514 	cmd_cancelled(NULL);
515 	return;
516     }
517 
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;
527     }
528 
529     if(!any_patterns(rflags, &pstate)){
530 	q_status_message(SM_ORDER, 3, 7, _("problem accessing rules"));
531 	return;
532     }
533 
534     /* set this so that even if we don't edit at all, we'll be asked */
535     rflags |= ROLE_CHANGES;
536 
537     /*
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.
541      */
542     defpat = (PAT_S *)fs_get(sizeof(*defpat));
543     memset((void *)defpat, 0, sizeof(*defpat));
544 
545     defpat->patgrp = (PATGRP_S *)fs_get(sizeof(*defpat->patgrp));
546     memset((void *)defpat->patgrp, 0, sizeof(*defpat->patgrp));
547 
548     if(env){
549 	if(env->to)
550 	  defpat->patgrp->to = addrlst_to_pattern(env->to);
551 
552 	if(env->from)
553 	  defpat->patgrp->from = addrlst_to_pattern(env->from);
554 
555 	if(env->cc)
556 	  defpat->patgrp->cc = addrlst_to_pattern(env->cc);
557 
558 	if(env->sender &&
559 	   (!env->from || !address_is_same(env->sender, env->from)))
560 	  defpat->patgrp->sender = addrlst_to_pattern(env->sender);
561 
562 	/*
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.
566 	 */
567 	if(env->newsgroups)
568 	  defpat->patgrp->news = string_to_pattern(env->newsgroups);
569 
570 	/*
571 	 * Subject may have commas or backslashes, so we add escapes.
572 	 */
573 	if(env->subject){
574 	    char *q, *t = NULL;
575 
576 	    /*
577 	     * Mail_strip_subject not only strips the Re's and Fwd's but
578 	     * it also canonicalizes to UTF-8.
579 	     */
580 	    mail_strip_subject(env->subject, &q);
581 	    if(q != NULL){
582 		t = add_roletake_escapes(q);
583 		fs_give((void **)&q);
584 	    }
585 
586 	    if(t){
587 		defpat->patgrp->subj = string_to_pattern(t);
588 		fs_give((void **)&t);
589 	    }
590 	}
591     }
592 
593     if(IS_NEWS(ps->mail_stream))
594       defpat->patgrp->fldr_type = FLDR_NEWS;
595     else
596       defpat->patgrp->fldr_type = FLDR_EMAIL;
597 
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));
608 
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;
614 
615 	    defpat->patgrp->folder = string_to_pattern(s);
616 	    fs_give((void **)&s);
617 	}
618     }
619 
620     role_type_print(title, sizeof(title), "ADD NEW %sRULE", rflags);
621 
622     /*
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.
631      */
632     opt_screen = NULL;
633 
634     if(role_config_edit_screen(ps, defpat, title, rflags,
635 			       &newpat) == 1 && newpat){
636 
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"));
641 
642 	if(rflags & ROLE_DO_ROLES && newpat->patgrp && newpat->patgrp->nick){
643 	    PAT_S *pat;
644 
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;
652 		}
653 	    }
654 	}
655 
656 
657 	set_pathandle(rflags);
658 
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;
664 
665 	/* tie together with new pattern */
666 	new_patline->first = new_patline->last = newpat;
667 	newpat->patline = new_patline;
668 
669 	/* find last current patline */
670 	for(patline = (*cur_pat_h)->patlinehead;
671 	    patline && patline->next;
672 	    patline = patline->next)
673 	  ;
674 
675 	/* add new patline to end of list */
676 	if(patline){
677 	    patline->next = new_patline;
678 	    new_patline->prev = patline;
679 	}
680 	else
681 	  (*cur_pat_h)->patlinehead = new_patline;
682 
683 	if(write_patterns(rflags) == 0){
684 	    char msg[60];
685 
686 	    /*
687 	     * Flush out current_vals of anything we've possibly changed.
688 	     */
689 
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;
693 	    }
694 
695 	    close_patterns(rflags | PAT_USE_CURRENT);
696 
697 	    role_type_print(msg, sizeof(msg), "New %srule saved", rflags);
698 	    q_status_message(SM_ORDER, 0, 3, msg);
699 
700 	    /* scores may have changed */
701 	    if(rflags & ROLE_DO_SCORES){
702 		int         i;
703 		MAILSTREAM *m;
704 
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);
710 		    }
711 		}
712 
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.
716 		 */
717 		if(mn_get_sort(msgmap) == SortScore)
718 	          refresh_sort(ps_global->mail_stream, msgmap, SRT_VRB);
719 	    }
720 
721 	    if(rflags & ROLE_DO_FILTER)
722 	      role_process_filters();
723 
724 	    /* recalculate need for scores */
725 	    scores_are_used(SCOREUSE_INVALID);
726 
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());
732 
733 	    if(rflags & ROLE_DO_INCOLS && pico_usingcolor())
734 	      clear_index_cache(ps_global->mail_stream, 0);
735 
736 	    /*
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.
739 	     */
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);
745 	    }
746 	}
747     }
748     else
749       cmd_cancelled(NULL);
750 
751     free_pat(&defpat);
752     ps->mangled_screen = 1;
753 }
754 
755 
756 PATTERN_S *
addrlst_to_pattern(struct mail_address * addr)757 addrlst_to_pattern(struct mail_address *addr)
758 {
759     char      *s, *t, *u, *v;
760     PATTERN_S *p = NULL;
761     size_t l;
762 
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));
773 
774 		sstrncpy(&t, v, l-(t-s));
775 		fs_give((void **)&v);
776 	    }
777 
778 	    addr = addr->next;
779 	}
780 
781 	s[l] = '\0';
782 
783 	if(*s)
784 	  p = string_to_pattern(s);
785 
786 	fs_give((void **) &s);
787     }
788 
789     return(p);
790 }
791 
792 
793 void
role_config_init_disp(struct pine * ps,CONF_S ** first_line,long int rflags,PAT_STATE * pstate)794 role_config_init_disp(struct pine *ps, CONF_S **first_line, long int rflags, PAT_STATE *pstate)
795 {
796     PAT_LINE_S    *patline;
797     CONF_S        *ctmp = NULL;
798     int            inherit = 0, added_fake = 0;
799 
800     if(first_line)
801       *first_line = NULL;
802 
803     /*
804      * Set cur_pat_h and manipulate directly.
805      */
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;
811     }
812 
813     if(!patline){
814 	add_fake_first_role(&ctmp, 0, rflags);
815 	added_fake++;
816 	if(first_line && !*first_line)
817 	  (*first_line) = ctmp;
818     }
819 
820     for(; patline; patline = patline->next)
821       add_patline_to_display(ps, &ctmp, 0, first_line, NULL, patline, rflags);
822 
823     /*
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.
827      */
828     if(!first_pattern(role_global_pstate) ||
829        ((inherit=first_pattern(role_global_pstate)->inherit) &&
830 	 !next_pattern(role_global_pstate))){
831 
832 	/*
833 	 * Find the start and prepend the fake first role.
834 	 */
835 	while(ctmp && ctmp->prev)
836 	  ctmp = ctmp->prev;
837 
838 	if(!added_fake){
839 	    add_fake_first_role(&ctmp, inherit ? 0 : 1, rflags);
840 	    if(first_line && !*first_line)
841 	      (*first_line) = ctmp;
842 	}
843     }
844 }
845 
846 
847 void
add_patline_to_display(struct pine * ps,CONF_S ** ctmp,int before,CONF_S ** first_line,CONF_S ** top_line,PAT_LINE_S * patline,long int rflags)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)
849 {
850     PAT_S *pat;
851     int    len, firstitem, wid;
852     char  *q;
853     char   buf[6*MAX_SCREEN_COLS+1];
854 
855     /* put dashed line around file contents */
856     if(patline->type == File){
857 
858 	new_confline(ctmp);
859 	if(before){
860 	    /*
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 ->
864 	     */
865 
866 	    CONF_S *a, *b, *c, *p;
867 
868 	    p = *ctmp;
869 	    b = (*ctmp)->prev;
870 	    c = (*ctmp)->next;
871 	    a = b ? b->prev : NULL;
872 	    if(a)
873 	      a->next = p;
874 
875 	    if(b){
876 		b->prev = p;
877 		b->next = c;
878 	    }
879 
880 	    if(c)
881 	      c->prev = b;
882 
883 	    p->prev = a;
884 	    p->next = b;
885 	}
886 
887 	if(top_line && *top_line == NULL)
888 	  *top_line = (*ctmp);
889 
890 	len = strlen(patline->filename) + 100;
891 
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';
896 
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, '-'));
901 
902 	(*ctmp)->value = cpystr(buf);
903 
904 	fs_give((void **)&q);
905 	(*ctmp)->flags     |= (CF_NOSELECT | CF_STARTITEM);
906 	(*ctmp)->d.r.patline = patline;
907 	firstitem = 0;
908     }
909     else
910       firstitem = 1;
911 
912     for(pat = patline->first; pat; pat = pat->next){
913 
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;
932 	}
933 
934     }
935 
936     if(patline->type == File){
937 	new_confline(ctmp);
938 	len = strlen(patline->filename) + 100;
939 
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';
943 
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, '-'));
948 
949 	(*ctmp)->value = cpystr(buf);
950 
951 	fs_give((void **)&q);
952 	(*ctmp)->flags     |= CF_NOSELECT;
953 	(*ctmp)->d.r.patline = patline;
954     }
955 }
956 
957 
958 void
add_role_to_display(CONF_S ** ctmp,PAT_LINE_S * patline,PAT_S * pat,int before,CONF_S ** first_line,int firstitem,long int rflags)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)
960 {
961     char      title[80];
962 
963     if(!(pat && (pat->action || pat->inherit)))
964       return;
965 
966     new_confline(ctmp);
967     if(first_line && !pat->inherit)
968       *first_line = *ctmp;
969 
970     if(before){
971 	/*
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 ->
975 	 */
976 
977 	CONF_S *a, *b, *c, *p;
978 
979 	p = *ctmp;
980 	b = (*ctmp)->prev;
981 	c = (*ctmp)->next;
982 	a = b ? b->prev : NULL;
983 	if(a)
984 	  a->next = p;
985 
986 	if(b){
987 	    b->prev = p;
988 	    b->next = c;
989 	}
990 
991 	if(c)
992 	  c->prev = b;
993 
994 	p->prev = a;
995 	p->next = b;
996     }
997 
998     role_type_print(title, sizeof(title), _("HELP FOR %sRULE CONFIGURATION"), rflags);
999 
1000     if(pat->inherit){
1001 	(*ctmp)->flags    |= ((firstitem ? CF_STARTITEM : 0) |
1002 			      CF_NOSELECT | CF_INHERIT);
1003     }
1004     else{
1005 	(*ctmp)->flags    |= (firstitem ? CF_STARTITEM : 0);
1006 	(*ctmp)->value     = cpystr((pat && pat->patgrp && pat->patgrp->nick)
1007 				    ? pat->patgrp->nick : "?");
1008     }
1009 
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;
1023 }
1024 
1025 
1026 void
add_fake_first_role(CONF_S ** ctmp,int before,long int rflags)1027 add_fake_first_role(CONF_S **ctmp, int before, long int rflags)
1028 {
1029     char title[80];
1030     char add[80];
1031 
1032     new_confline(ctmp);
1033 
1034     if(before){
1035 	/*
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 ->
1039 	 */
1040 
1041 	CONF_S *a, *b, *c, *p;
1042 
1043 	p = *ctmp;
1044 	b = (*ctmp)->prev;
1045 	c = (*ctmp)->next;
1046 	a = b ? b->prev : NULL;
1047 	if(a)
1048 	  a->next = p;
1049 
1050 	if(b){
1051 	    b->prev = p;
1052 	    b->next = c;
1053 	}
1054 
1055 	if(c)
1056 	  c->prev = b;
1057 
1058 	p->prev = a;
1059 	p->next = b;
1060     }
1061 
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);
1064 
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;
1078 }
1079 
1080 
1081 int
role_config_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)1082 role_config_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
1083 {
1084     int       first_one = 0, rv = 0;
1085     char      exitpmt[80];
1086     PAT_S    *pat;
1087 
1088     if(!(pat = first_pattern(role_global_pstate)) ||
1089        (pat->inherit && !next_pattern(role_global_pstate)))
1090       first_one++;
1091 
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);
1099 
1100 	break;
1101 
1102       case MC_ADD :
1103 	rv = role_config_add(ps, cl, role_global_flags);
1104 	break;
1105 
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);
1111 
1112 	break;
1113 
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);
1120 
1121 	break;
1122 
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;
1127 
1128       case MC_ADDFILE :
1129 	rv = role_config_addfile(ps, cl, role_global_flags);
1130 	break;
1131 
1132       case MC_DELFILE :
1133 	rv = role_config_delfile(ps, cl, role_global_flags);
1134 	break;
1135 
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);
1142 
1143 	break;
1144 
1145       default:
1146 	rv = -1;
1147 	break;
1148     }
1149 
1150     return(rv);
1151 }
1152 
1153 
1154 /*
1155  * Add a new role.
1156  *
1157  * Returns  1 -- There were changes
1158  *          0 -- No changes
1159  */
1160 int
role_config_add(struct pine * ps,CONF_S ** cl,long int rflags)1161 role_config_add(struct pine *ps, CONF_S **cl, long int rflags)
1162 {
1163     int         rv = 0, first_pat = 0;
1164     PAT_S      *new_pat = NULL, *cur_pat;
1165     PAT_LINE_S *new_patline = NULL, *cur_patline;
1166     PAT_STATE   pstate;
1167     char        title[80];
1168 
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);
1174     }
1175 
1176     role_type_print(title, sizeof(title), "ADD A %sRULE", rflags);
1177 
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"));
1185 
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;
1191 
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;
1199 		}
1200 	    }
1201 	}
1202 
1203 	rv = 1;
1204 	cur_pat = (*cl)->d.r.pat;
1205 	if(!cur_pat)
1206 	  first_pat++;
1207 
1208 	set_pathandle(rflags);
1209 	cur_patline = first_pat ? (*cur_pat_h)->patlinehead : cur_pat->patline;
1210 
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;
1217 	}
1218 
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;
1225 
1226 		cur_patline->next = new_patline;
1227 
1228 		/* tie new patline and new pat together */
1229 		new_pat->patline   = new_patline;
1230 		new_patline->first = new_patline->last = new_pat;
1231 	    }
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;
1236 
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;
1244 
1245 		cur_pat->next = new_pat;
1246 	    }
1247 	}
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;
1252 
1253 	    /* set head of list */
1254 	    (*cur_pat_h)->patlinehead = new_patline;
1255 	}
1256 
1257 	/*
1258 	 * If this is the first role, we replace the "Use Add" fake role
1259 	 * with this real one.
1260 	 */
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);
1267 
1268 	    (*cl)->value = cpystr((new_pat && new_pat->patgrp &&
1269 				   new_pat->patgrp->nick)
1270 					 ? new_pat->patgrp->nick : "?");
1271 	}
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);
1276     }
1277 
1278     return(rv);
1279 }
1280 
1281 
1282 /*
1283  * Replicate a role.
1284  *
1285  * Returns  1 -- There were changes
1286  *          0 -- No changes
1287  */
1288 int
role_config_replicate(struct pine * ps,CONF_S ** cl,long int rflags)1289 role_config_replicate(struct pine *ps, CONF_S **cl, long int rflags)
1290 {
1291     int         rv = 0, first_pat = 0;
1292     PAT_S      *new_pat = NULL, *cur_pat, *defpat = NULL;
1293     PAT_LINE_S *new_patline = NULL, *cur_patline;
1294     PAT_STATE   pstate;
1295     char        title[80];
1296 
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);
1302     }
1303 
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;
1310 
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);
1321 
1322 		defpat->action->nick = cpystr(defpat->patgrp->nick);
1323 	    }
1324 	}
1325 
1326 	/* set this so that even if we don't edit at all, we'll be asked */
1327 	rflags |= ROLE_CHANGES;
1328 
1329 	role_type_print(title, sizeof(title), "CHANGE THIS %sRULE", rflags);
1330 
1331 	if(role_config_edit_screen(ps, defpat, title, rflags,
1332 				   &new_pat) == 1 && new_pat){
1333 
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"));
1339 
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;
1345 
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;
1353 		}
1354 	    }
1355 	}
1356 
1357 	rv = 1;
1358 	cur_pat = (*cl)->d.r.pat;
1359 	if(!cur_pat)
1360 	  first_pat++;
1361 
1362 	set_pathandle(rflags);
1363 	cur_patline = first_pat ? (*cur_pat_h)->patlinehead : cur_pat->patline;
1364 
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;
1371 	}
1372 
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;
1379 
1380 		cur_patline->next = new_patline;
1381 
1382 		/* tie new patline and new pat together */
1383 		new_pat->patline   = new_patline;
1384 		new_patline->first = new_patline->last = new_pat;
1385 	    }
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;
1390 
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;
1398 
1399 		cur_pat->next = new_pat;
1400 	    }
1401 	}
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;
1406 
1407 	    /* set head of list */
1408 	    (*cur_pat_h)->patlinehead = new_patline;
1409 	}
1410 
1411 	/*
1412 	 * If this is the first role, we replace the "Use Add" fake role
1413 	 * with this real one.
1414 	 */
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);
1421 
1422 	    (*cl)->value = cpystr((new_pat && new_pat->patgrp &&
1423 				   new_pat->patgrp->nick)
1424 					 ? new_pat->patgrp->nick : "?");
1425 	}
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);
1430 	}
1431     }
1432 
1433     if(defpat)
1434       free_pat(&defpat);
1435 
1436     return(rv);
1437 }
1438 
1439 
1440 /*
1441  * Change the current role.
1442  *
1443  * Returns  1 -- There were changes
1444  *          0 -- No changes
1445  */
1446 int
role_config_edit(struct pine * ps,CONF_S ** cl,long int rflags)1447 role_config_edit(struct pine *ps, CONF_S **cl, long int rflags)
1448 {
1449     int         rv = 0;
1450     PAT_S      *new_pat = NULL, *cur_pat;
1451     char        title[80];
1452 
1453     if((*cl)->d.r.patline->readonly){
1454 	q_status_message(SM_ORDER, 0, 3, _("Can't change ReadOnly rule"));
1455 	return(rv);
1456     }
1457 
1458     cur_pat = (*cl)->d.r.pat;
1459 
1460     role_type_print(title, sizeof(title), "CHANGE THIS %sRULE", rflags);
1461 
1462     if(role_config_edit_screen(ps, cur_pat, title,
1463 			       rflags, &new_pat) == 1 && new_pat){
1464 
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"));
1470 
1471 	if(rflags & ROLE_DO_ROLES && new_pat->patgrp && new_pat->patgrp->nick){
1472 	    PAT_S *pat;
1473 
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;
1481 		}
1482 	    }
1483 	}
1484 
1485 	rv = 1;
1486 
1487 	/*
1488 	 * Splice in new_pat in place of cur_pat
1489 	 */
1490 
1491 	if(cur_pat->prev)
1492 	  cur_pat->prev->next = new_pat;
1493 
1494 	if(cur_pat->next)
1495 	  cur_pat->next->prev = new_pat;
1496 
1497 	new_pat->prev = cur_pat->prev;
1498 	new_pat->next = cur_pat->next;
1499 
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;
1503 
1504 	if(new_pat->patline->last == cur_pat)
1505 	  new_pat->patline->last = new_pat;
1506 
1507 	if(new_pat->patline->type == Literal){
1508 	    set_pathandle(rflags);
1509 	    if(*cur_pat_h)
1510 	      (*cur_pat_h)->dirtypinerc = 1;
1511 	}
1512 	else
1513 	  new_pat->patline->dirty = 1;
1514 
1515 	cur_pat->next = NULL;
1516 	free_pat(&cur_pat);
1517 
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);
1523 
1524 	(*cl)->value = cpystr((new_pat->patgrp && new_pat->patgrp->nick)
1525 				? new_pat->patgrp->nick : "?");
1526     }
1527 
1528     return(rv);
1529 }
1530 
1531 
1532 /*
1533  * Delete a role.
1534  *
1535  * Returns  1 -- There were changes
1536  *          0 -- No changes
1537  */
1538 int
role_config_del(struct pine * ps,CONF_S ** cl,long int rflags)1539 role_config_del(struct pine *ps, CONF_S **cl, long int rflags)
1540 {
1541     int  rv = 0;
1542     char msg[80];
1543     char prompt[100];
1544 
1545     if((*cl)->d.r.patline->readonly){
1546 	q_status_message(SM_ORDER, 0, 3, _("Can't delete ReadOnly rule"));
1547 	return(rv);
1548     }
1549 
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';
1553 
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);
1558     }
1559     else
1560       q_status_message(SM_ORDER, 0, 3, _("Rule not deleted"));
1561 
1562     return(rv);
1563 }
1564 
1565 
1566 void
delete_a_role(CONF_S ** cl,long int rflags)1567 delete_a_role(CONF_S **cl, long int rflags)
1568 {
1569     PAT_S      *cur_pat;
1570     CONF_S     *cp, *cq;
1571     PAT_LINE_S *cur_patline;
1572     int         inherit = 0;
1573 
1574     cur_pat     = (*cl)->d.r.pat;
1575     cur_patline = (*cl)->d.r.patline;
1576 
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;
1584 	}
1585 
1586 	if(cur_patline->next)
1587 	  cur_patline->next->prev = cur_patline->prev;
1588 
1589 	if(*cur_pat_h)		/* this has to be true */
1590 	  (*cur_pat_h)->dirtypinerc = 1;
1591 
1592 	cur_patline->next = NULL;
1593 	free_patline(&cur_patline);
1594     }
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;
1600 
1601 	if(cur_pat->next)
1602 	  cur_pat->next->prev = cur_pat->prev;
1603 	else
1604 	  cur_patline->last = cur_pat->prev;
1605 
1606 	cur_patline->dirty = 1;
1607 
1608 	cur_pat->next = NULL;
1609 	free_pat(&cur_pat);
1610     }
1611 
1612     /* delete the conf line */
1613 
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))){
1618 
1619 	cq = *cl;
1620 
1621 	/*
1622 	 * Find the start and prepend the fake first role.
1623 	 */
1624 	while(*cl && (*cl)->prev)
1625 	  *cl = (*cl)->prev;
1626 
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);
1631     }
1632     else{
1633 	/* find next selectable line */
1634 	for(cp = (*cl)->next;
1635 	    cp && (cp->flags & CF_NOSELECT);
1636 	    cp = cp->next)
1637 	  ;
1638 
1639 	if(!cp){	/* no next selectable, find previous selectable */
1640 	    if(*cl == opt_screen->top_line)
1641 	      opt_screen->top_line = (*cl)->prev;
1642 
1643 	    for(cp = (*cl)->prev;
1644 		cp && (cp->flags & CF_NOSELECT);
1645 		cp = cp->prev)
1646 	      ;
1647 	}
1648 	else if(*cl == opt_screen->top_line)
1649 	  opt_screen->top_line = (*cl)->next;
1650 
1651 	cq = *cl;
1652 	*cl = cp;
1653 	snip_confline(&cq);
1654     }
1655 }
1656 
1657 
1658 /*
1659  * Shuffle the current role up or down.
1660  *
1661  * Returns  1 -- There were changes
1662  *          0 -- No changes
1663  */
1664 int
role_config_shuffle(struct pine * ps,CONF_S ** cl)1665 role_config_shuffle(struct pine *ps, CONF_S **cl)
1666 {
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;
1674 
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);
1679     }
1680 
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");
1687 
1688     opts[i].ch      = 'd';
1689     opts[i].rval    = 'd';
1690     opts[i].name    = "D";
1691     opts[i++].label = N_("Down");
1692 
1693     opts[i].ch      = 'b';
1694     opts[i].rval    = 'b';
1695     opts[i].name    = "B";
1696     opts[i++].label = N_("Before File");
1697 
1698     opts[i].ch      = 'a';
1699     opts[i].rval    = 'a';
1700     opts[i].name    = "A";
1701     opts[i++].label = N_("After File");
1702 
1703     opts[i].ch = -1;
1704     deefault = 'u';
1705 
1706     curtype = ((*cl)->d.r.patline) ? (*cl)->d.r.patline->type : TypeNotSet;
1707 
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;
1712 
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;
1717 
1718 
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';
1725 	}
1726 	else if(prevtype == Literal){	/* regular up		*/
1727 	    opts[2].ch = -2;
1728 	}
1729 	else if(prevtype == File){	/* file above us	*/
1730 	    if((*cl)->prev->d.r.patline->readonly)
1731 	      readonlyabove++;
1732 	}
1733 
1734 	if(nexttype == TypeNotSet){	/* no down, at bottom	*/
1735 	    opts[1].ch = -2;
1736 	    opts[3].ch = -2;
1737 	}
1738 	else if(nexttype == Literal){	/* regular down		*/
1739 	    opts[3].ch = -2;
1740 	}
1741 	else if(nexttype == File){	/* file below us	*/
1742 	    if((*cl)->next->d.r.patline->readonly)
1743 	      readonlybelow++;
1744 	}
1745     }
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);
1750 	}
1751 
1752 	opts[2].ch = -2;
1753 	opts[3].ch = -2;
1754     }
1755     else{
1756 	q_status_message(SM_ORDER, 0, 3,
1757 	"Programming Error: unknown line type in role_shuffle");
1758 	return(rv);
1759     }
1760 
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';
1774 
1775     help = (opts[0].ch == -2) ? h_role_shuf_down
1776 			      : (opts[1].ch == -2) ? h_role_shuf_up
1777 						   : h_role_shuf;
1778 
1779     rv = radio_buttons(tmp, -FOOTER_ROWS(ps), opts, deefault, 'x',
1780 		       help, RB_NORM);
1781 
1782     if(rv == 'x'){
1783 	cmd_cancelled("Shuffle");
1784 	return(0);
1785     }
1786 
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);
1791     }
1792 
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;
1799 
1800 	swap_literal_roles(a, b);
1801 	ps->mangled_body = 1;
1802     }
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;
1809 
1810 	swap_literal_roles(a, b);
1811 	ps->mangled_body = 1;
1812     }
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;
1819 
1820 	swap_file_roles(a, b);
1821 	ps->mangled_body = 1;
1822     }
1823     else if(rv == 'u' && curtype == File){
1824 	rv = 1;
1825 	move_role_outof_file(cl, 1);
1826 	ps->mangled_body = 1;
1827     }
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;
1834 
1835 	swap_file_roles(a, b);
1836 	ps->mangled_body = 1;
1837     }
1838     else if(rv == 'd' && curtype == File){
1839 	rv = 1;
1840 	if(*cl == opt_screen->top_line)
1841 	  opt_screen->top_line = (*cl)->next;
1842 
1843 	move_role_outof_file(cl, 0);
1844 	ps->mangled_body = 1;
1845     }
1846     else if(rv == 'u' && curtype == Literal && prevtype == File){
1847 	rv = 1;
1848 	move_role_into_file(cl, 1);
1849 	ps->mangled_body = 1;
1850     }
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;
1855 
1856 	move_role_into_file(cl, 0);
1857 	ps->mangled_body = 1;
1858     }
1859     else if(rv == 'b'){
1860 	rv = 1;
1861 	move_role_around_file(cl, 1);
1862 	ps->mangled_body = 1;
1863     }
1864     else if(rv == 'a'){
1865 	rv = 1;
1866 	if(*cl == opt_screen->top_line)
1867 	  opt_screen->top_line = (*cl)->next;
1868 
1869 	move_role_around_file(cl, 0);
1870 	ps->mangled_body = 1;
1871     }
1872 
1873     return(rv);
1874 }
1875 
1876 
1877 int
role_config_addfile(struct pine * ps,CONF_S ** cl,long int rflags)1878 role_config_addfile(struct pine *ps, CONF_S **cl, long int rflags)
1879 {
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 = 0;
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;
1890 
1891     if(ps->restricted){
1892 	q_status_message(SM_ORDER, 0, 3, "Alpine demo can't read files");
1893 	return(rv);
1894     }
1895 
1896     curtype = ((*cl)->d.r.patline && (*cl)->d.r.patline)
1897 	        ? (*cl)->d.r.patline->type : TypeNotSet;
1898 
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);
1902     }
1903 
1904     /*
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.
1909      */
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;
1915     }
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);
1920     }
1921 
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;
1927 
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);
1933 
1934 	if(r == 3){
1935 	    help = (help == NO_HELP) ? h_config_role_addfile : NO_HELP;
1936 	    continue;
1937 	}
1938 	else if(r == 10 || r == 11){    /* Browser or File Completion */
1939 	    continue;
1940 	}
1941 	else if(r == 1 || (r == 0 && filename[0] == '\0')){
1942 	    cmd_cancelled("IncludeFile");
1943 	    return(rv);
1944 	}
1945 	else if(r == 4){
1946 	    continue;
1947 	}
1948 	else if(r != 0){
1949 	    Writechar(BELL, 0);
1950 	    continue;
1951 	}
1952 
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);
1963 	}
1964 
1965 	if(newfile && *newfile)
1966 	  break;
1967     }
1968 
1969     if(!newfile)
1970       return(rv);
1971 
1972     set_pathandle(rflags);
1973 
1974     if((file_patline = parse_pat_file(newfile)) != NULL){
1975 	/*
1976 	 * Insert the file after the current line.
1977 	 */
1978 	PAT_LINE_S *cur_patline;
1979 	int         first_pat;
1980 
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;
1985 
1986 	if(*cur_pat_h)
1987 	  (*cur_pat_h)->dirtypinerc = 1;
1988 
1989 	file_patline->dirty = 1;
1990 
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;
1996 
1997 	    cur_patline->next = file_patline;
1998 	}
1999 	else{
2000 	    /* set head of list */
2001 	    if(*cur_pat_h)
2002 	      (*cur_pat_h)->patlinehead = file_patline;
2003 	}
2004 
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);
2015 	    }
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;
2022 	    }
2023 	}
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;
2034 	}
2035     }
2036 
2037     if(newfile)
2038       fs_give((void **)&newfile);
2039 
2040     return(rv);
2041 }
2042 
2043 
2044 int
role_config_delfile(struct pine * ps,CONF_S ** cl,long int rflags)2045 role_config_delfile(struct pine *ps, CONF_S **cl, long int rflags)
2046 {
2047     int         rv = 0;
2048     PAT_LINE_S *cur_patline;
2049     char        prompt[100];
2050 
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);
2055     }
2056 
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);
2060     }
2061 
2062     snprintf(prompt, sizeof(prompt), _("Really remove rule file \"%s\" from rules config "),
2063 	    cur_patline->filename);
2064     prompt[sizeof(prompt)-1] = '\0';
2065 
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;
2069 
2070 	set_pathandle(rflags);
2071 	rv = ps->mangled_screen = 1;
2072 	if(*cur_pat_h)
2073 	  (*cur_pat_h)->dirtypinerc = 1;
2074 
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;
2080 	}
2081 
2082 	if(cur_patline->next)
2083 	  cur_patline->next->prev = cur_patline->prev;
2084 
2085 	/* delete the conf lines */
2086 
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)
2091 	  ;
2092 
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)
2097 	      ;
2098 
2099 	    if(cp->d.r.patline == cur_patline)
2100 	      *cl = NULL;
2101 	    else
2102 	      *cl = cp;
2103 	}
2104 
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);
2110 	}
2111 
2112 	/* deleting last real rule */
2113 	if(!first_pattern(role_global_pstate)){
2114 	    /*
2115 	     * Find the start and prepend the fake first role
2116 	     * in there.
2117 	     */
2118 	    while(*cl && (*cl)->prev)
2119 	      *cl = (*cl)->prev;
2120 
2121 	    add_fake_first_role(cl, 1, rflags);
2122 	}
2123 	else if(first_pattern(role_global_pstate)->inherit &&
2124 	       !next_pattern(role_global_pstate)){
2125 	    while(*cl && (*cl)->prev)
2126 	      *cl = (*cl)->prev;
2127 
2128 	    /* append fake first after inherit */
2129 	    add_fake_first_role(cl, 0, rflags);
2130 	}
2131 
2132 	opt_screen->top_line = first_confline(*cl);
2133 	opt_screen->current  = first_sel_confline(opt_screen->top_line);
2134 
2135 	cur_patline->next = NULL;
2136 	free_patline(&cur_patline);
2137     }
2138     else
2139       q_status_message(SM_ORDER, 0, 3, _("Rule file not removed"));
2140 
2141     return(rv);
2142 }
2143 
2144 
2145 /*
2146  * Swap from a, b to b, a.
2147  */
2148 void
swap_literal_roles(CONF_S * a,CONF_S * b)2149 swap_literal_roles(CONF_S *a, CONF_S *b)
2150 {
2151     PAT_LINE_S *patline_a, *patline_b;
2152 
2153     patline_a = a->d.r.patline;
2154     patline_b = b->d.r.patline;
2155 
2156     set_pathandle(role_global_flags);
2157     if(*cur_pat_h)
2158       (*cur_pat_h)->dirtypinerc = 1;
2159 
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;
2165 
2166 	patline_a->next = patline_b->next;
2167 	if(patline_b->next)
2168 	  patline_b->next->prev = patline_a;
2169 
2170 	patline_b->next = patline_a;
2171 	patline_a->prev = patline_b;
2172     }
2173     else{
2174 	PAT_LINE_S *new_a_prev, *new_a_next;
2175 
2176 	new_a_prev = patline_b->prev;
2177 	new_a_next = patline_b->next;
2178 
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;
2185 
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;
2192     }
2193 
2194     /*
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.
2197      */
2198     if(patline_b->prev == NULL && *cur_pat_h)
2199       (*cur_pat_h)->patlinehead = patline_b;
2200 
2201 
2202     /* and then swap the conf lines */
2203 
2204     b->prev = a->prev;
2205     if(a->prev)
2206       a->prev->next = b;
2207 
2208     a->next = b->next;
2209     if(b->next)
2210       b->next->prev = a;
2211 
2212     b->next = a;
2213     a->prev = b;
2214 }
2215 
2216 
2217 /*
2218  * Swap from a, b to b, a.
2219  */
2220 void
swap_file_roles(CONF_S * a,CONF_S * b)2221 swap_file_roles(CONF_S *a, CONF_S *b)
2222 {
2223     PAT_S      *pat_a, *pat_b;
2224     PAT_LINE_S *patline;
2225 
2226     pat_a = a->d.r.pat;
2227     pat_b = b->d.r.pat;
2228     patline = pat_a->patline;
2229 
2230     patline->dirty = 1;
2231 
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;
2237 
2238 	pat_a->next = pat_b->next;
2239 	if(pat_b->next)
2240 	  pat_b->next->prev = pat_a;
2241 
2242 	pat_b->next = pat_a;
2243 	pat_a->prev = pat_b;
2244     }
2245     else{
2246 	PAT_S *new_a_prev, *new_a_next;
2247 
2248 	new_a_prev = pat_b->prev;
2249 	new_a_next = pat_b->next;
2250 
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;
2257 
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;
2264     }
2265 
2266     /*
2267      * Fix the first and last pointers.
2268      */
2269     if(patline->first == pat_a)
2270       patline->first = pat_b;
2271     if(patline->last == pat_b)
2272       patline->last = pat_a;
2273 
2274     /* and then swap the conf lines */
2275 
2276     b->prev = a->prev;
2277     if(a->prev)
2278       a->prev->next = b;
2279 
2280     a->next = b->next;
2281     if(b->next)
2282       b->next->prev = a;
2283 
2284     b->next = a;
2285     a->prev = b;
2286 }
2287 
2288 
2289 /*
2290  */
2291 void
move_role_into_file(CONF_S ** cl,int up)2292 move_role_into_file(CONF_S **cl, int up)
2293 {
2294     PAT_LINE_S *cur_patline, *file_patline;
2295     PAT_S      *pat;
2296     CONF_S     *a, *b;
2297 
2298     cur_patline = (*cl)->d.r.patline;
2299 
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;
2305     }
2306     else{
2307 	file_patline = (*cl)->next->d.r.patline;
2308 	a = (*cl);
2309 	b = (*cl)->next;
2310 	a->d.r.patline = file_patline;
2311     }
2312 
2313     set_pathandle(role_global_flags);
2314     if(*cur_pat_h)
2315       (*cur_pat_h)->dirtypinerc = 1;
2316 
2317     file_patline->dirty = 1;
2318 
2319     pat = cur_patline->first;
2320 
2321     if(!up && *cur_pat_h && cur_patline == (*cur_pat_h)->patlinehead)
2322       (*cur_pat_h)->patlinehead = (*cur_pat_h)->patlinehead->next;
2323 
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;
2329 	}
2330 	else{
2331 	    file_patline->first->prev = pat;
2332 	    pat->next = file_patline->first;
2333 	    file_patline->first = pat;
2334 	}
2335     }
2336     else		/* will be only role in file */
2337       file_patline->first = file_patline->last = pat;
2338 
2339     pat->patline = file_patline;
2340 
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;
2347 
2348     cur_patline->next = NULL;
2349     free_patline(&cur_patline);
2350 
2351     /* and then swap the conf lines */
2352 
2353     b->prev = a->prev;
2354     if(a->prev)
2355       a->prev->next = b;
2356 
2357     a->next = b->next;
2358     if(b->next)
2359       b->next->prev = a;
2360 
2361     b->next = a;
2362     a->prev = b;
2363 }
2364 
2365 
2366 /*
2367  */
2368 void
move_role_outof_file(CONF_S ** cl,int up)2369 move_role_outof_file(CONF_S **cl, int up)
2370 {
2371     PAT_LINE_S *file_patline, *new_patline;
2372     PAT_S      *pat;
2373     CONF_S     *a, *b;
2374 
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;
2378 
2379     file_patline = (*cl)->d.r.patline;
2380     pat = (*cl)->d.r.pat;
2381 
2382     if(up){
2383 	a = (*cl)->prev;
2384 	b = (*cl);
2385 
2386 	if(pat->prev)
2387 	  pat->prev->next = pat->next;
2388 	else
2389 	  file_patline->first = pat->next;
2390 
2391 	if(pat->next)
2392 	  pat->next->prev = pat->prev;
2393 	else
2394 	  file_patline->last = pat->prev;
2395 
2396 	if(file_patline->first)
2397 	  file_patline->first->prev = NULL;
2398 
2399 	if(file_patline->last)
2400 	  file_patline->last->next = NULL;
2401 
2402 	if(file_patline->prev)
2403 	  file_patline->prev->next = new_patline;
2404 
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;
2409     }
2410     else{
2411 	a = (*cl);
2412 	b = (*cl)->next;
2413 
2414 	if(pat->prev)
2415 	  pat->prev->next = pat->next;
2416 	else
2417 	  file_patline->first = pat->next;
2418 
2419 	if(pat->next)
2420 	  pat->next->prev = pat->prev;
2421 	else
2422 	  file_patline->last = pat->prev;
2423 
2424 	if(file_patline->first)
2425 	  file_patline->first->prev = NULL;
2426 
2427 	if(file_patline->last)
2428 	  file_patline->last->next = NULL;
2429 
2430 	if(file_patline->next)
2431 	  file_patline->next->prev = new_patline;
2432 
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;
2437     }
2438 
2439     set_pathandle(role_global_flags);
2440     if(*cur_pat_h)
2441       (*cur_pat_h)->dirtypinerc = 1;
2442 
2443     file_patline->dirty = 1;
2444 
2445     new_patline->first = new_patline->last = pat;
2446     pat->patline = new_patline;
2447     pat->prev = pat->next = NULL;
2448 
2449     if(up && *cur_pat_h && file_patline == (*cur_pat_h)->patlinehead)
2450       (*cur_pat_h)->patlinehead = new_patline;
2451 
2452     /* and then swap the conf lines */
2453 
2454     b->prev = a->prev;
2455     if(a->prev)
2456       a->prev->next = b;
2457 
2458     a->next = b->next;
2459     if(b->next)
2460       b->next->prev = a;
2461 
2462     b->next = a;
2463     a->prev = b;
2464 }
2465 
2466 
2467 /*
2468  * This is a move of a literal role from before a file to after a file,
2469  * or vice versa.
2470  */
2471 void
move_role_around_file(CONF_S ** cl,int up)2472 move_role_around_file(CONF_S **cl, int up)
2473 {
2474     PAT_LINE_S *file_patline, *lit_patline;
2475     CONF_S     *cp;
2476 
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;
2484 
2485 	file_patline = (*cl)->next->d.r.patline;
2486     }
2487 
2488     if(*cur_pat_h)
2489       (*cur_pat_h)->dirtypinerc = 1;
2490 
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;
2496 
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;
2501 
2502 	lit_patline->prev = file_patline->prev;
2503 	lit_patline->next = file_patline;
2504 
2505 	if(file_patline->prev)
2506 	  file_patline->prev->next = lit_patline;
2507 
2508 	file_patline->prev = lit_patline;
2509     }
2510     else{
2511 	lit_patline->next = file_patline->next;
2512 	lit_patline->prev = file_patline;
2513 
2514 	if(file_patline->next)
2515 	  file_patline->next->prev = lit_patline;
2516 
2517 	file_patline->next = lit_patline;
2518     }
2519 
2520     /*
2521      * And then move the conf line around the file conf lines.
2522      */
2523 
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))
2529 	;
2530     else
2531       for(cp = (*cl);
2532 	  cp && cp->next && cp->next->d.r.patline == file_patline;
2533 	  cp = next_confline(cp))
2534 	;
2535 
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;
2541 
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);
2547 
2548 	cp->prev = (*cl);
2549 	(*cl)->next = cp;
2550     }
2551     else{
2552 	(*cl)->next = cp->next;
2553 	if(cp->next)
2554 	  cp->next->prev = (*cl);
2555 
2556 	cp->next = (*cl);
2557 	(*cl)->prev = cp;
2558     }
2559 }
2560 
2561 
2562 #define SETUP_PAT_STATUS(ctmp,svar,val,htitle,hval)			\
2563    {char tmp[MAXPATH+1];						\
2564     int i, j, lv;							\
2565     NAMEVAL_S *f;							\
2566 									\
2567     /* Blank line */							\
2568     new_confline(&ctmp);						\
2569     ctmp->flags    |= CF_NOSELECT | CF_B_LINE;				\
2570 									\
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);			\
2581 									\
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");			\
2591 									\
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);				\
2601 									\
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;								\
2606     									\
2607     lv = MIN(lv, 100);							\
2608     									\
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);					\
2628     }									\
2629    }
2630 
2631 #define SETUP_MSG_STATE(ctmp,svar,val,htitle,hval)			\
2632    {char tmp[MAXPATH+1];						\
2633     int i, j, lv;							\
2634     NAMEVAL_S *f;							\
2635 									\
2636     /* Blank line */							\
2637     new_confline(&ctmp);						\
2638     ctmp->flags    |= CF_NOSELECT | CF_B_LINE;				\
2639 									\
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);			\
2650 									\
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");			\
2660 									\
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);				\
2670 									\
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;								\
2675     									\
2676     lv = MIN(lv, 100);							\
2677     									\
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);					\
2693     }									\
2694    }
2695 
2696 
2697 #define  FEAT_SENTDATE   0
2698 #define  FEAT_IFNOTDEL   1
2699 #define  FEAT_NONTERM    2
2700 bitmap_t feat_option_list;
2701 
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;
2708 
2709 
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];
2721 
2722 
2723 /*
2724  * Screen for editing configuration of a role.
2725  *
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.
2731  *
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
2736  */
2737 int
role_config_edit_screen(struct pine * ps,PAT_S * def,char * title,long int rflags,PAT_S ** result)2738 role_config_edit_screen(struct pine *ps, PAT_S *def, char *title, long int rflags, PAT_S **result)
2739 {
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;
2814 
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;
2822 
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;
2827 
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;
2832 
2833     rindent = 12;	/* radio indent */
2834 
2835     /*
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.
2839      */
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));
2905 
2906     if(def && ((def->patgrp && def->patgrp->bogus) || (def->action && def->action->bogus))){
2907 	char msg[MAX_SCREEN_COLS+1];
2908 
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);
2917     }
2918 
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;
2927 
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;
2934 
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);
2945 
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);
2954 
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);
2984 
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);
2989 
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);
2998     }
2999 
3000     set_current_val(&age_pat_var, FALSE, FALSE);
3001 
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);
3009     }
3010 
3011     set_current_val(&size_pat_var, FALSE, FALSE);
3012 
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);
3022     }
3023 
3024     set_current_val(&scorei_pat_var, FALSE, FALSE);
3025 
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);
3033 
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);
3041 
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);
3049 
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);
3057 
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);
3065 
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);
3073 
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);
3081 
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);
3089 
3090 
3091 
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);
3101 
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);
3109 
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);
3117 
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);
3125 
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;
3133 
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);
3141 
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;
3148 
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);
3154     }
3155 
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);
3163 
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);
3167 
3168     /*
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.
3171      */
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);
3182 
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);
3191     }
3192 
3193     set_current_val(&cati_var, FALSE, FALSE);
3194 
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';
3206     }
3207 
3208     set_current_val(&cat_lim_var, FALSE, FALSE);
3209 
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;
3216 
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);
3221     }
3222     else{
3223 	apval = APVAL(&from_act_var, ew);
3224 	*apval = NULL;
3225     }
3226 
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;
3233 
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);
3238     }
3239     else{
3240 	apval = APVAL(&replyto_act_var, ew);
3241 	*apval = NULL;
3242     }
3243 
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;
3250 
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);
3261     }
3262     else
3263       *apval = NULL;
3264 
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);
3275     }
3276 
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);
3287     }
3288     if(!*apval){
3289 	*apval = (f=startup_rules(IS_NOTSET)) ? cpystr(f->name) : NULL;
3290 	set_current_val(&startup_var, FALSE, FALSE);
3291     }
3292 
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;
3301 
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;
3308 
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;
3317 
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;
3326 
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;
3334 
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;
3342 
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;
3350 
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';
3357     }
3358 
3359     set_current_val(&score_act_var, FALSE, FALSE);
3360 
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);
3367     }
3368 
3369     set_current_val(&hdrtok_act_var, FALSE, FALSE);
3370 
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);
3380 
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);
3388 
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);
3395 
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("ic-background-color");
3406     apval = APVAL(&rolecolor_vars[1], ew);
3407     *apval = (def && def->action && def->action->incol &&
3408 	      def->action->incol->bg[0])
3409 	         ? cpystr(def->action->incol->bg) : NULL;
3410     set_current_val(&rolecolor_vars[0], FALSE, FALSE);
3411     set_current_val(&rolecolor_vars[1], FALSE, FALSE);
3412     old_fg = PVAL(&rolecolor_vars[0], ew) ? cpystr(PVAL(&rolecolor_vars[0], ew))
3413 					  : NULL;
3414     old_bg = PVAL(&rolecolor_vars[1], ew) ? cpystr(PVAL(&rolecolor_vars[1], ew))
3415 					  : NULL;
3416 
3417 
3418     /* save the old opt_screen before calling scroll screen again */
3419     saved_screen = opt_screen;
3420 
3421     pindent = utf8_width(s_p_v_n);	/* the longest one */
3422     maxpindent = pindent + 6;
3423     for(a = (def && def->patgrp) ? def->patgrp->arbhdr : NULL; a; a = a->next)
3424       if((lv=utf8_width(a->field ? a->field : "")+utf8_width(" pattern")) > pindent)
3425 	pindent = lv;
3426 
3427     pindent = MIN(pindent, maxpindent);
3428 
3429     pindent += NOTLEN;	/* width of `! ' */
3430 
3431     pindent += 3;	/* width of ` = ' */
3432 
3433     /* Nickname */
3434     new_confline(&ctmp);
3435     ctmp->help_title= _("HELP FOR NICKNAME");
3436     ctmp->var       = &nick_var;
3437     ctmp->valoffset = pindent;
3438     ctmp->keymenu   = &config_role_keymenu;
3439     ctmp->help      = edit_role ? h_config_role_nick :
3440 		       edit_incol ? h_config_incol_nick :
3441 			edit_score ? h_config_score_nick :
3442 			 edit_other ? h_config_other_nick
3443 			            : h_config_filt_nick;
3444     ctmp->tool      = t_tool;
3445     utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, nick_var.name);
3446     tmp[sizeof(tmp)-1] = '\0';
3447     ctmp->varname   = cpystr(tmp);
3448     ctmp->varnamep  = ctmp;
3449     ctmp->value     = pretty_value(ps, ctmp);
3450     ctmp->varmem    = -1;
3451 
3452     first_line = ctmp;
3453     if(rflags & ROLE_CHANGES)
3454       first_line->flags |= CF_CHANGES;
3455 
3456     /* Comment */
3457     new_confline(&ctmp);
3458     ctmp->help_title= _("HELP FOR COMMENT");
3459     ctmp->var       = &comment_var;
3460     ctmp->valoffset = pindent;
3461     ctmp->keymenu   = &config_role_keymenu;
3462     ctmp->help      = h_config_role_comment;
3463     ctmp->tool      = role_litsig_text_tool;
3464     utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, comment_var.name);
3465     tmp[sizeof(tmp)-1] = '\0';
3466     ctmp->varname   = cpystr(tmp);
3467     ctmp->varnamep  = ctmp;
3468     ctmp->value     = pretty_value(ps, ctmp);
3469     ctmp->varmem    = -1;
3470 
3471     /* Blank line */
3472     new_confline(&ctmp);
3473     ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
3474 
3475     new_confline(&ctmp);
3476     ctmp->flags    |= CF_NOSELECT;
3477     if(ps->ttyo->screen_cols >= (wid=utf8_width(fstr)) + 4){
3478 	int dashes;
3479 
3480 	dashes = (ps->ttyo->screen_cols - wid)/2;
3481 	snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='),
3482 		 fstr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '='));
3483 	ctmp->value = cpystr(tmp_20k_buf);
3484     }
3485     else
3486       ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '='));
3487 
3488     /* Blank line */
3489     new_confline(&ctmp);
3490     ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
3491 
3492     /* Folder Type */
3493     new_confline(&ctmp);
3494     ctmp->var       = &fldr_type_var;
3495     ctmp->keymenu   = &config_radiobutton_keymenu;
3496     ctmp->help      = NO_HELP;
3497     ctmp->tool      = NULL;
3498     snprintf(tmp, sizeof(tmp), "%s =", fldr_type_var.name);
3499     tmp[sizeof(tmp)-1] = '\0';
3500     ctmp->varname   = cpystr(tmp);
3501     ctmp->varnamep  = ctmpb = ctmp;
3502     ctmp->flags    |= (CF_NOSELECT | CF_STARTITEM);
3503 
3504     new_confline(&ctmp);
3505     ctmp->var       = NULL;
3506     ctmp->valoffset = rindent;
3507     ctmp->keymenu   = &config_radiobutton_keymenu;
3508     ctmp->help      = NO_HELP;
3509     ctmp->tool      = NULL;
3510     ctmp->varnamep  = ctmpb;
3511     ctmp->flags    |= CF_NOSELECT;
3512     ctmp->value     = cpystr("Set    Choose One");
3513 
3514     new_confline(&ctmp);
3515     ctmp->var       = NULL;
3516     ctmp->valoffset = rindent;
3517     ctmp->keymenu   = &config_radiobutton_keymenu;
3518     ctmp->help      = NO_HELP;
3519     ctmp->tool      = radio_tool;
3520     ctmp->varnamep  = ctmpb;
3521     ctmp->flags    |= CF_NOSELECT;
3522     ctmp->value     = cpystr(set_choose);				\
3523 
3524     /* find longest value's name */
3525     for(lv = 0, i = 0; (f = pat_fldr_types(i)); i++)
3526       if(lv < (j = utf8_width(f->name)))
3527 	lv = j;
3528 
3529     lv = MIN(lv, 100);
3530 
3531     fval = -1;
3532     for(i = 0; (f = pat_fldr_types(i)); i++){
3533 	new_confline(&ctmp);
3534 	ctmp->help_title= _("HELP FOR CURRENT FOLDER TYPE");
3535 	ctmp->var       = &fldr_type_var;
3536 	ctmp->valoffset = rindent;
3537 	ctmp->keymenu   = &config_radiobutton_keymenu;
3538 	ctmp->help      = edit_role ? h_config_role_fldr_type :
3539 			   edit_incol ? h_config_incol_fldr_type :
3540 			    edit_score ? h_config_score_fldr_type :
3541 			     edit_other ? h_config_other_fldr_type
3542 				        : h_config_filt_fldr_type;
3543 	ctmp->varmem    = i;
3544 	ctmp->tool      = radio_tool;
3545 	ctmp->varnamep  = ctmpb;
3546 
3547 	if((PVAL(&fldr_type_var, ew) &&
3548 	    !strucmp(PVAL(&fldr_type_var, ew), f->name))
3549 	   || (!PVAL(&fldr_type_var, ew) && f->value == FLDR_DEFL))
3550 	  fval = f->value;
3551 
3552 	utf8_snprintf(tmp, sizeof(tmp), "(%c)  %-*.*w",
3553 		(fval == f->value) ? R_SELD : ' ',
3554 		lv, lv, f->name);
3555 	tmp[sizeof(tmp)-1] = '\0';
3556 	ctmp->value     = cpystr(tmp);
3557     }
3558 
3559     /* Folder */
3560     /* 5 is the width of `(*)  ' */
3561     setup_role_pat_alt(ps, &ctmp, &folder_pat_var,
3562 		       edit_role ? h_config_role_fldr_type :
3563 			edit_incol ? h_config_incol_fldr_type :
3564 			 edit_score ? h_config_score_fldr_type :
3565 			  edit_other ? h_config_other_fldr_type
3566 				     : h_config_filt_fldr_type,
3567 		       _("HELP FOR FOLDER LIST"),
3568 		       &config_role_patfolder_keymenu, t_tool, rindent+5,
3569 		       !(fval == FLDR_SPECIFIC));
3570 
3571   if(!per_folder_only){		/* sorry about that indent */
3572 
3573     /* Blank line */
3574     new_confline(&ctmp);
3575     ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
3576 
3577     new_confline(&ctmp);
3578     ctmp->flags    |= CF_NOSELECT;
3579 
3580     /* TRANSLATORS: The %s is replaced with one of the 4 or 5 words below, CURRENT,
3581        SCORED, and so on. */
3582     snprintf(mstr, sizeof(mstr), _(" %s MESSAGE CONDITIONS BEGIN HERE "),
3583 	    edit_role ? _("CURRENT") :
3584 	     edit_score ? _("SCORED") :
3585 	      edit_incol ? _("COLORED") :
3586 	       edit_filter ? _("FILTERED") : _("CURRENT"));
3587     mstr[sizeof(mstr)-1] = '\0';
3588 
3589     if(ps->ttyo->screen_cols >= (wid=utf8_width(mstr)) + 4){
3590 	int dashes;
3591 
3592 	dashes = (ps->ttyo->screen_cols - wid)/2;
3593 	snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='),
3594 		 mstr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '='));
3595 	ctmp->value = cpystr(tmp_20k_buf);
3596     }
3597     else
3598       ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '='));
3599 
3600     /* Blank line */
3601     new_confline(&ctmp);
3602     ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
3603 
3604     setup_role_pat(ps, &ctmp, &to_pat_var,
3605 		   edit_role ? h_config_role_topat :
3606 		    edit_incol ? h_config_incol_topat :
3607 		     edit_score ? h_config_score_topat :
3608 		      edit_other ? h_config_other_topat
3609 			         : h_config_filt_topat,
3610 		   _("HELP FOR TO PATTERN"),
3611 		   &config_role_addr_pat_keymenu, t_tool, &earb, pindent);
3612 
3613     setup_role_pat(ps, &ctmp, &from_pat_var, h_config_role_frompat,
3614 		   _("HELP FOR FROM PATTERN"),
3615 		   &config_role_addr_pat_keymenu, t_tool, &earb, pindent);
3616 
3617     setup_role_pat(ps, &ctmp, &sender_pat_var, h_config_role_senderpat,
3618 		   _("HELP FOR SENDER PATTERN"),
3619 		   &config_role_addr_pat_keymenu, t_tool, &earb, pindent);
3620 
3621     setup_role_pat(ps, &ctmp, &cc_pat_var, h_config_role_ccpat,
3622 		   _("HELP FOR CC PATTERN"),
3623 		   &config_role_addr_pat_keymenu, t_tool, &earb, pindent);
3624 
3625     setup_role_pat(ps, &ctmp, &news_pat_var, h_config_role_newspat,
3626 		   _("HELP FOR NEWS PATTERN"),
3627 		   &config_role_keymenu_not, t_tool, &earb, pindent);
3628 
3629     setup_role_pat(ps, &ctmp, &subj_pat_var, h_config_role_subjpat,
3630 		   _("HELP FOR SUBJECT PATTERN"),
3631 		   &config_role_keymenu_not, t_tool, &earb, pindent);
3632 
3633     setup_role_pat(ps, &ctmp, &recip_pat_var, h_config_role_recippat,
3634 		   _("HELP FOR RECIPIENT PATTERN"),
3635 		   &config_role_addr_pat_keymenu, t_tool, &earb, pindent);
3636 
3637     setup_role_pat(ps, &ctmp, &partic_pat_var, h_config_role_particpat,
3638 		   _("HELP FOR PARTICIPANT PATTERN"),
3639 		   &config_role_addr_pat_keymenu, t_tool, &earb, pindent);
3640 
3641     /* Arbitrary Patterns */
3642     ea = NULL;
3643     for(j = 0, a = (def && def->patgrp) ? def->patgrp->arbhdr : NULL;
3644 	a;
3645 	j++, a = a->next){
3646 	char *fn = (a->field) ? a->field : "";
3647 
3648 	if(ea){
3649 	    ea->next = (EARB_S *)fs_get(sizeof(*ea));
3650 	    ea = ea->next;
3651 	}
3652 	else{
3653 	    earb = (EARB_S *)fs_get(sizeof(*ea));
3654 	    ea = earb;
3655 	}
3656 
3657 	memset((void *)ea, 0, sizeof(*ea));
3658 	ea->v = (struct variable *)fs_get(sizeof(struct variable));
3659 	memset((void *)ea->v, 0, sizeof(struct variable));
3660 	ea->a = (ARBHDR_S *)fs_get(sizeof(ARBHDR_S));
3661 	memset((void *)ea->a, 0, sizeof(ARBHDR_S));
3662 
3663 	ea->a->field = cpystr(fn);
3664 
3665 	p = (char *) fs_get(strlen(fn) + strlen(" pattern") + 1);
3666 	snprintf(p, strlen(fn) + strlen(" pattern") + 1, "%s pattern", fn);
3667 	p[strlen(fn) + strlen(" pattern") + 1 - 1] = '\0';
3668 	setup_dummy_pattern_var(ea->v, p, a->p);
3669 	fs_give((void **) &p);
3670 	setup_role_pat(ps, &ctmp, ea->v, h_config_role_arbpat,
3671 		       ARB_HELP, &config_role_xtrahdr_keymenu,
3672 		       t_tool, &earb, pindent);
3673     }
3674 
3675     new_confline(&ctmp);
3676     ctmp->help_title = _("HELP FOR EXTRA HEADERS");
3677     ctmp->value = cpystr(ADDXHDRS);
3678     ctmp->keymenu = &config_role_keymenu_extra;
3679     ctmp->help      = h_config_role_arbpat;
3680     ctmp->tool      = addhdr_tool;
3681     ctmp->d.earb    = &earb;
3682     ctmp->varmem    = -1;
3683 
3684     setup_role_pat(ps, &ctmp, &alltext_pat_var, h_config_role_alltextpat,
3685 		   _("HELP FOR ALL TEXT PATTERN"),
3686 		   &config_role_keymenu_not, t_tool, &earb, pindent);
3687 
3688     setup_role_pat(ps, &ctmp, &bodytext_pat_var, h_config_role_bodytextpat,
3689 		   _("HELP FOR BODY TEXT PATTERN"),
3690 		   &config_role_keymenu_not, t_tool, &earb, pindent);
3691 
3692     /* Age Interval */
3693     new_confline(&ctmp);
3694     ctmp->help_title= _("HELP FOR AGE INTERVAL");
3695     ctmp->var       = &age_pat_var;
3696     ctmp->valoffset = pindent;
3697     ctmp->keymenu   = &config_text_keymenu;
3698     ctmp->help      = h_config_role_age;
3699     ctmp->tool      = t_tool;
3700     utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, age_pat_var.name);
3701     tmp[sizeof(tmp)-1] = '\0';
3702     ctmp->varname   = cpystr(tmp);
3703     ctmp->varnamep  = ctmp;
3704     ctmp->value     = pretty_value(ps, ctmp);
3705 
3706     /* Size Interval */
3707     new_confline(&ctmp);
3708     ctmp->help_title= _("HELP FOR SIZE INTERVAL");
3709     ctmp->var       = &size_pat_var;
3710     ctmp->valoffset = pindent;
3711     ctmp->keymenu   = &config_text_keymenu;
3712     ctmp->help      = h_config_role_size;
3713     ctmp->tool      = t_tool;
3714     utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, size_pat_var.name);
3715     tmp[sizeof(tmp)-1] = '\0';
3716     ctmp->varname   = cpystr(tmp);
3717     ctmp->varnamep  = ctmp;
3718     ctmp->value     = pretty_value(ps, ctmp);
3719 
3720     if(!edit_score){
3721 	/* Score Interval */
3722 	new_confline(&ctmp);
3723 	ctmp->help_title= _("HELP FOR SCORE INTERVAL");
3724 	ctmp->var       = &scorei_pat_var;
3725 	ctmp->valoffset = pindent;
3726 	ctmp->keymenu   = &config_text_keymenu;
3727 	ctmp->help      = h_config_role_scorei;
3728 	ctmp->tool      = t_tool;
3729 	utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", pindent-3, pindent-3, scorei_pat_var.name);
3730 	tmp[sizeof(tmp)-1] = '\0';
3731 	ctmp->varname   = cpystr(tmp);
3732 	ctmp->varnamep  = ctmp;
3733 	ctmp->value     = pretty_value(ps, ctmp);
3734     }
3735 
3736     /* Keyword Pattern */
3737     setup_role_pat(ps, &ctmp, &keyword_pat_var, h_config_role_keywordpat,
3738 		   _("HELP FOR KEYWORD PATTERN"),
3739 		   &config_role_keyword_keymenu_not, role_text_tool_kword,
3740 		   NULL, pindent);
3741 
3742     /* Charset Pattern */
3743     setup_role_pat(ps, &ctmp, &charset_pat_var, h_config_role_charsetpat,
3744 		   _("HELP FOR CHARACTER SET PATTERN"),
3745 		   &config_role_charset_keymenu_not, role_text_tool_charset,
3746 		   NULL, pindent);
3747 
3748     /* Important Status */
3749     SETUP_PAT_STATUS(ctmp, stat_imp_var, def->patgrp->stat_imp,
3750 		     _("HELP FOR IMPORTANT STATUS"), h_config_role_stat_imp);
3751     /* New Status */
3752     SETUP_PAT_STATUS(ctmp, stat_new_var, def->patgrp->stat_new,
3753 		     _("HELP FOR NEW STATUS"), h_config_role_stat_new);
3754     /* Recent Status */
3755     SETUP_PAT_STATUS(ctmp, stat_rec_var, def->patgrp->stat_rec,
3756 		     _("HELP FOR RECENT STATUS"), h_config_role_stat_recent);
3757     /* Deleted Status */
3758     SETUP_PAT_STATUS(ctmp, stat_del_var, def->patgrp->stat_del,
3759 		     _("HELP FOR DELETED STATUS"), h_config_role_stat_del);
3760     /* Answered Status */
3761     SETUP_PAT_STATUS(ctmp, stat_ans_var, def->patgrp->stat_ans,
3762 		     _("HELP FOR ANSWERED STATUS"), h_config_role_stat_ans);
3763     /* 8-bit Subject */
3764     SETUP_PAT_STATUS(ctmp, stat_8bit_var, def->patgrp->stat_8bitsubj,
3765 		     _("HELP FOR 8-BIT SUBJECT"), h_config_role_stat_8bitsubj);
3766     /* Beginning of month */
3767     SETUP_PAT_STATUS(ctmp, stat_bom_var, def->patgrp->stat_bom,
3768 		     _("HELP FOR BEGINNING OF MONTH"), h_config_role_bom);
3769     /* Beginning of year */
3770     SETUP_PAT_STATUS(ctmp, stat_boy_var, def->patgrp->stat_boy,
3771 		     _("HELP FOR BEGINNING OF YEAR"), h_config_role_boy);
3772 
3773     /* Blank line */
3774     new_confline(&ctmp);
3775     ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
3776 
3777     /* From in Addrbook */
3778     new_confline(&ctmp);
3779     ctmp->var       = &abook_type_var;
3780     ctmp->keymenu   = &config_radiobutton_keymenu;
3781     ctmp->help      = NO_HELP;
3782     ctmp->tool      = NULL;
3783     snprintf(tmp, sizeof(tmp), "%s =", abook_type_var.name);
3784     tmp[sizeof(tmp)-1] = '\0';
3785     ctmp->varname   = cpystr(tmp);
3786     ctmp->varnamep  = ctmpb = ctmp;
3787     ctmp->flags    |= (CF_NOSELECT | CF_STARTITEM);
3788 
3789     new_confline(&ctmp);
3790     ctmp->var       = NULL;
3791     ctmp->valoffset = rindent;
3792     ctmp->keymenu   = &config_radiobutton_keymenu;
3793     ctmp->help      = NO_HELP;
3794     ctmp->tool      = NULL;
3795     ctmp->varnamep  = ctmpb;
3796     ctmp->flags    |= CF_NOSELECT;
3797     ctmp->value     = cpystr("Set    Choose One");
3798 
3799     new_confline(&ctmp);
3800     ctmp->var       = NULL;
3801     ctmp->valoffset = rindent;
3802     ctmp->keymenu   = &config_radiobutton_keymenu;
3803     ctmp->help      = NO_HELP;
3804     ctmp->tool      = radio_tool;
3805     ctmp->varnamep  = ctmpb;
3806     ctmp->flags    |= CF_NOSELECT;
3807     ctmp->value     = cpystr(set_choose);				\
3808 
3809     /* find longest value's name */
3810     for(lv = 0, i = 0; (f = inabook_fldr_types(i)); i++)
3811       if(lv < (j = utf8_width(f->name)))
3812 	lv = j;
3813 
3814     lv = MIN(lv, 100);
3815 
3816     fval = -1;
3817     for(i = 0; (f = inabook_fldr_types(i)); i++){
3818 	new_confline(&ctmp);
3819 	ctmp->help_title= _("HELP FOR ADDRESS IN ADDRESS BOOK");
3820 	ctmp->var       = &abook_type_var;
3821 	ctmp->valoffset = rindent;
3822 	ctmp->keymenu   = &config_radiobutton_keymenu;
3823 	ctmp->help      = h_config_role_abookfrom;
3824 	ctmp->varmem    = i;
3825 	ctmp->tool      = radio_tool;
3826 	ctmp->varnamep  = ctmpb;
3827 
3828 	if((PVAL(&abook_type_var, ew) &&
3829 	    !strucmp(PVAL(&abook_type_var, ew), f->name))
3830 	   || (!PVAL(&abook_type_var, ew) && f->value == IAB_DEFL))
3831 	  fval = f->value;
3832 
3833 	utf8_snprintf(tmp, sizeof(tmp), "(%c)  %-*.*w",
3834 		(fval == f->value) ? R_SELD : ' ',
3835 		lv, lv, f->name);
3836 	tmp[sizeof(tmp)-1] = '\0';
3837 	ctmp->value     = cpystr(tmp);
3838     }
3839 
3840     /* Specific list of abooks */
3841     /* 5 is the width of `(*)  ' */
3842     setup_role_pat_alt(ps, &ctmp, &abook_pat_var, h_config_role_abookfrom,
3843 		       _("HELP FOR ABOOK LIST"),
3844 		       &config_role_afrom_keymenu, role_text_tool_afrom, rindent+5,
3845 		       !(fval == IAB_SPEC_YES || fval == IAB_SPEC_NO));
3846 
3847     /* Which addresses to check for */
3848     inabook_type_var.name      = cpystr(_("Types of addresses to check for in address book"));
3849     inabook_type_var.is_used   = 1;
3850     inabook_type_var.is_user   = 1;
3851     inabook_type_var.is_list   = 1;
3852     clrbitmap(inabook_type_list);
3853     if(def && def->patgrp && def->patgrp->inabook & IAB_FROM)
3854       setbitn(INABOOK_FROM, inabook_type_list);
3855     if(def && def->patgrp && def->patgrp->inabook & IAB_REPLYTO)
3856       setbitn(INABOOK_REPLYTO, inabook_type_list);
3857     if(def && def->patgrp && def->patgrp->inabook & IAB_SENDER)
3858       setbitn(INABOOK_SENDER, inabook_type_list);
3859     if(def && def->patgrp && def->patgrp->inabook & IAB_TO)
3860       setbitn(INABOOK_TO, inabook_type_list);
3861     if(def && def->patgrp && def->patgrp->inabook & IAB_CC)
3862       setbitn(INABOOK_CC, inabook_type_list);
3863 
3864     /* default setting */
3865     if(!(bitnset(INABOOK_FROM, inabook_type_list)
3866 	 || bitnset(INABOOK_REPLYTO, inabook_type_list)
3867 	 || bitnset(INABOOK_SENDER, inabook_type_list)
3868 	 || bitnset(INABOOK_TO, inabook_type_list)
3869 	 || bitnset(INABOOK_CC, inabook_type_list))){
3870 	setbitn(INABOOK_FROM, inabook_type_list);
3871 	setbitn(INABOOK_REPLYTO, inabook_type_list);
3872     }
3873 
3874     new_confline(&ctmp);
3875     ctmp->var       = &inabook_type_var;
3876     ctmp->varoffset = 4;
3877     ctmp->valoffset = 23;
3878     ctmp->keymenu   = &config_checkbox_keymenu;
3879     ctmp->help      = NO_HELP;
3880     ctmp->tool      = NULL;
3881     snprintf(tmp, sizeof(tmp), "%-20s =", inabook_type_var.name);
3882     tmp[sizeof(tmp)-1] = '\0';
3883     ctmp->varname   = cpystr(tmp);
3884     ctmp->varnamep  = ctmpb = ctmp;
3885     ctmp->flags    |= (CF_NOSELECT | CF_STARTITEM);
3886 
3887     new_confline(&ctmp);
3888     ctmp->var       = NULL;
3889     ctmp->valoffset = rindent;
3890     ctmp->keymenu   = &config_checkbox_keymenu;
3891     ctmp->help      = NO_HELP;
3892     ctmp->tool      = inabook_checkbox_tool;
3893     ctmp->varnamep  = ctmpb;
3894     ctmp->flags    |= CF_NOSELECT;
3895     ctmp->value     = cpystr("Set   Address types");
3896 
3897     new_confline(&ctmp);
3898     ctmp->var       = NULL;
3899     ctmp->valoffset = rindent;
3900     ctmp->keymenu   = &config_checkbox_keymenu;
3901     ctmp->help      = NO_HELP;
3902     ctmp->tool      = inabook_checkbox_tool;
3903     ctmp->varnamep  = ctmpb;
3904     ctmp->flags    |= CF_NOSELECT;
3905     ctmp->value     = cpystr(set_choose);
3906 
3907     /*  find longest value's name */
3908     for(lv = 0, i = 0; (f = inabook_feature_list(i)); i++){
3909 	if(lv < (j = utf8_width(f->name)))
3910 	  lv = j;
3911     }
3912 
3913     lv = MIN(lv, 100);
3914 
3915     for(i = 0; (f = inabook_feature_list(i)); i++){
3916 	new_confline(&ctmp);
3917 	ctmp->var       = &opt_var;
3918 	ctmp->help_title= _("HELP FOR ADDRESS TYPES");
3919 	ctmp->varnamep  = ctmpb;
3920 	ctmp->keymenu   = &config_checkbox_keymenu;
3921 	switch(i){
3922 	  case INABOOK_FROM:
3923 	    ctmp->help      = h_config_inabook_from;
3924 	    break;
3925 	  case INABOOK_REPLYTO:
3926 	    ctmp->help      = h_config_inabook_replyto;
3927 	    break;
3928 	  case INABOOK_SENDER:
3929 	    ctmp->help      = h_config_inabook_sender;
3930 	    break;
3931 	  case INABOOK_TO:
3932 	    ctmp->help      = h_config_inabook_to;
3933 	    break;
3934 	  case INABOOK_CC:
3935 	    ctmp->help      = h_config_inabook_cc;
3936 	    break;
3937 	}
3938 
3939 	ctmp->tool      = inabook_checkbox_tool;
3940 	ctmp->valoffset = rindent;
3941 	ctmp->varmem    = i;
3942 	utf8_snprintf(tmp, sizeof(tmp), "[%c]  %-*.*w",
3943 		bitnset(f->value, inabook_type_list) ? 'X' : ' ',
3944 		lv, lv, f->name);
3945 	tmp[sizeof(tmp)-1] = '\0';
3946 	ctmp->value     = cpystr(tmp);
3947     }
3948 
3949     /* Blank line */
3950     new_confline(&ctmp);
3951     ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
3952 
3953     /* 4 is indent of "Command", c_v_n is longest of these three, 3 is ` = ' */
3954     i = 4 + utf8_width(c_v_n) + 3;
3955 
3956     /* External Command Categorizer */
3957     new_confline(&ctmp);
3958     ctmp->var       = &cat_cmd_var;
3959     ctmp->keymenu   = &config_text_keymenu;
3960     ctmp->help      = NO_HELP;
3961     ctmp->tool      = NULL;
3962     snprintf(tmp, sizeof(tmp), "%s =", cat_cmd_var.name);
3963     tmp[sizeof(tmp)-1] = '\0';
3964     ctmp->varname   = cpystr(tmp);
3965     ctmp->varnamep  = ctmpb = ctmp;
3966     ctmp->flags    |= (CF_NOSELECT | CF_STARTITEM);
3967 
3968     /* Commands */
3969     new_confline(&ctmp);
3970     ctmp->help_title= _("HELP FOR CATEGORIZER COMMAND");
3971     ctmp->var       = &cat_cmd_var;
3972     ctmp->varoffset = 4;
3973     ctmp->valoffset = i;
3974     ctmp->keymenu   = &config_text_wshuf_keymenu;
3975     ctmp->help      = h_config_role_cat_cmd;
3976     ctmp->tool      = t_tool;
3977     utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", i-4-3, i-4-3, "Command");
3978     tmp[sizeof(tmp)-1] = '\0';
3979     ctmp->varname   = cpystr(tmp);
3980     ctmp->varnamep  = ctmpb = ctmp;
3981     ctmp->flags     = CF_STARTITEM;
3982 
3983     if((lval = LVAL(&cat_cmd_var, ew)) != NULL && lval[0]){
3984 	for(j = 0; lval[j]; j++){
3985 	    if(j)
3986 	      (void) new_confline(&ctmp);
3987 
3988 	    ctmp->var       = &cat_cmd_var;
3989 	    ctmp->varmem    = j;
3990 	    ctmp->valoffset = i;
3991 	    ctmp->keymenu   = &config_text_wshuf_keymenu;
3992 	    ctmp->help      = h_config_role_cat_cmd;
3993 	    ctmp->tool      = t_tool;
3994 	    ctmp->varnamep  = ctmp;
3995 	    ctmp->value     = pretty_value(ps, ctmp);
3996 	}
3997     }
3998     else
3999       ctmp->value = pretty_value(ps, ctmp);
4000 
4001     /* Exit status interval */
4002     new_confline(&ctmp);
4003     ctmp->help_title= _("HELP FOR CATEGORIZER EXIT STATUS");
4004     ctmp->var       = &cati_var;
4005     ctmp->varoffset = 4;
4006     ctmp->valoffset = i;
4007     ctmp->keymenu   = &config_text_keymenu;
4008     ctmp->help      = h_config_role_cat_status;
4009     ctmp->tool      = t_tool;
4010     utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", i-4-3, i-4-3, cati_var.name);
4011     tmp[sizeof(tmp)-1] = '\0';
4012     ctmp->varname   = cpystr(tmp);
4013     ctmp->varnamep  = ctmp;
4014     ctmp->value     = pretty_value(ps, ctmp);
4015 
4016     /* Character Limit */
4017     new_confline(&ctmp);
4018     ctmp->help_title= _("HELP FOR CHARACTER LIMIT");
4019     ctmp->var       = &cat_lim_var;
4020     ctmp->varoffset = 4;
4021     ctmp->valoffset = i;
4022     ctmp->keymenu   = &config_text_keymenu;
4023     ctmp->help      = h_config_role_cat_limit;
4024     ctmp->tool      = t_tool;
4025     utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", i-4-3, i-4-3, cat_lim_var.name);
4026     tmp[sizeof(tmp)-1] = '\0';
4027     ctmp->varname   = cpystr(tmp);
4028     ctmp->varnamep  = ctmp;
4029     ctmp->value     = pretty_value(ps, ctmp);
4030     ctmp->flags    |= CF_NUMBER;
4031   }
4032 
4033   if(!edit_srch){		/* sorry about that indent */
4034     /* Actions */
4035 
4036     /* Blank line */
4037     new_confline(&ctmp);
4038     ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
4039 
4040     new_confline(&ctmp);
4041     ctmp->flags    |= CF_NOSELECT;
4042     if(ps->ttyo->screen_cols >= (wid=utf8_width(astr)) + 4){
4043 	int dashes;
4044 
4045 	dashes = (ps->ttyo->screen_cols - wid)/2;
4046 	snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='),
4047 		 astr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '='));
4048 	ctmp->value = cpystr(tmp_20k_buf);
4049     }
4050     else
4051       ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '='));
4052 
4053     if(edit_role){
4054 	int roindent;
4055 
4056 	roindent = utf8_width(u_s_s);	/* the longest one */
4057 	roindent += 3;	/* width of ` = ' */
4058 
4059 	/* Blank line */
4060 	new_confline(&ctmp);
4061 	ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
4062 
4063 	/* Inherit Nickname */
4064 	new_confline(&ctmp);
4065 	inick_confs[INICK_INICK_CONF] = ctmp;
4066 	ctmp->help_title= _("HELP FOR INITIAL SET NICKNAME");
4067 	ctmp->var       = &inick_var;
4068 	ctmp->keymenu   = &config_role_inick_keymenu;
4069 	ctmp->help      = h_config_role_inick;
4070 	ctmp->tool      = role_text_tool_inick;
4071 	snprintf(tmp, sizeof(tmp), "%s :", inick_var.name);
4072 	tmp[sizeof(tmp)-1] = '\0';
4073 	ctmp->valoffset = utf8_width(tmp)+1;
4074 	ctmp->varname   = cpystr(tmp);
4075 	ctmp->varnamep  = ctmp;
4076 
4077 	/* From Action */
4078 	new_confline(&ctmp);
4079 	inick_confs[INICK_FROM_CONF] = ctmp;
4080 	ctmp->help_title= _("HELP FOR SET FROM ACTION");
4081 	ctmp->var       = &from_act_var;
4082 	ctmp->valoffset = roindent;
4083 	ctmp->keymenu   = &config_role_addr_act_keymenu;
4084 	ctmp->help      = h_config_role_setfrom;
4085 	ctmp->tool      = role_text_tool;
4086 	utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, from_act_var.name);
4087 	tmp[sizeof(tmp)-1] = '\0';
4088 	ctmp->varname   = cpystr(tmp);
4089 	ctmp->varnamep  = ctmp;
4090 
4091 	/* Reply-To Action */
4092 	new_confline(&ctmp);
4093 	inick_confs[INICK_REPLYTO_CONF] = ctmp;
4094 	ctmp->help_title= _("HELP FOR SET REPLY-TO ACTION");
4095 	ctmp->var       = &replyto_act_var;
4096 	ctmp->valoffset = roindent;
4097 	ctmp->keymenu   = &config_role_addr_act_keymenu;
4098 	ctmp->help      = h_config_role_setreplyto;
4099 	ctmp->tool      = role_text_tool;
4100 	utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, replyto_act_var.name);
4101 	tmp[sizeof(tmp)-1] = '\0';
4102 	ctmp->varname   = cpystr(tmp);
4103 	ctmp->varnamep  = ctmp;
4104 
4105 	/* Fcc Action */
4106 	new_confline(&ctmp);
4107 	inick_confs[INICK_FCC_CONF] = ctmp;
4108 	ctmp->help_title= _("HELP FOR SET FCC ACTION");
4109 	ctmp->var       = &fcc_act_var;
4110 	ctmp->valoffset = roindent;
4111 	ctmp->keymenu   = &config_role_actionfolder_keymenu;
4112 	ctmp->help      = h_config_role_setfcc;
4113 	ctmp->tool      = role_text_tool;
4114 	utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, fcc_act_var.name);
4115 	tmp[sizeof(tmp)-1] = '\0';
4116 	ctmp->varname   = cpystr(tmp);
4117 	ctmp->varnamep  = ctmp;
4118 
4119 	/* LitSig Action */
4120 	new_confline(&ctmp);
4121 	inick_confs[INICK_LITSIG_CONF] = ctmp;
4122 	ctmp->help_title= _("HELP FOR SET LITERAL SIGNATURE ACTION");
4123 	ctmp->var       = &litsig_act_var;
4124 	ctmp->valoffset = roindent;
4125 	ctmp->keymenu   = &config_text_keymenu;
4126 	ctmp->help      = h_config_role_setlitsig;
4127 	ctmp->tool      = role_litsig_text_tool;
4128 	utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, litsig_act_var.name);
4129 	tmp[sizeof(tmp)-1] = '\0';
4130 	ctmp->varname   = cpystr(tmp);
4131 	ctmp->varnamep  = ctmp;
4132 
4133 	/* Sig Action */
4134 	new_confline(&ctmp);
4135 	inick_confs[INICK_SIG_CONF] = ctmp;
4136 	ctmp->help_title= _("HELP FOR SET SIGNATURE ACTION");
4137 	ctmp->var       = &sig_act_var;
4138 	ctmp->valoffset = roindent;
4139 	if(F_ON(F_DISABLE_ROLES_SIGEDIT, ps_global))
4140 	  ctmp->keymenu   = &config_role_file_res_keymenu;
4141 	else
4142 	  ctmp->keymenu   = &config_role_file_keymenu;
4143 
4144 	ctmp->help      = h_config_role_setsig;
4145 	ctmp->tool      = role_text_tool;
4146 	utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, sig_act_var.name);
4147 	tmp[sizeof(tmp)-1] = '\0';
4148 	ctmp->varname   = cpystr(tmp);
4149 	ctmp->varnamep  = ctmp;
4150 
4151 	/* Template Action */
4152 	new_confline(&ctmp);
4153 	inick_confs[INICK_TEMPL_CONF] = ctmp;
4154 	ctmp->help_title= _("HELP FOR SET TEMPLATE ACTION");
4155 	ctmp->var       = &templ_act_var;
4156 	ctmp->valoffset = roindent;
4157 	if(F_ON(F_DISABLE_ROLES_TEMPLEDIT, ps_global))
4158 	  ctmp->keymenu   = &config_role_file_res_keymenu;
4159 	else
4160 	  ctmp->keymenu   = &config_role_file_keymenu;
4161 
4162 	ctmp->help      = h_config_role_settempl;
4163 	ctmp->tool      = role_text_tool;
4164 	utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, templ_act_var.name);
4165 	tmp[sizeof(tmp)-1] = '\0';
4166 	ctmp->varname   = cpystr(tmp);
4167 	ctmp->varnamep  = ctmp;
4168 
4169 	/* Other Headers Action */
4170 	new_confline(&ctmp);
4171 	inick_confs[INICK_CSTM_CONF] = ctmp;
4172 	ctmp->help_title= _("HELP FOR SET OTHER HEADERS ACTION");
4173 	ctmp->var       = &cstm_act_var;
4174 	ctmp->valoffset = roindent;
4175 	ctmp->keymenu   = &config_text_wshuf_keymenu;
4176 	ctmp->help      = h_config_role_setotherhdr;
4177 	ctmp->tool      = role_cstm_text_tool;
4178 	utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, cstm_act_var.name);
4179 	tmp[sizeof(tmp)-1] = '\0';
4180 	ctmp->varname   = cpystr(tmp);
4181 	ctmp->varnamep  = ctmpb = ctmp;
4182 	ctmp->flags     = CF_STARTITEM;
4183 
4184 	if((lval = LVAL(&cstm_act_var, ew)) != NULL){
4185 	    for(i = 0; lval[i]; i++){
4186 		if(i)
4187 		  (void)new_confline(&ctmp);
4188 
4189 		ctmp->var       = &cstm_act_var;
4190 		ctmp->varmem    = i;
4191 		ctmp->valoffset = roindent;
4192 		ctmp->keymenu   = &config_text_wshuf_keymenu;
4193 		ctmp->help      = h_config_role_setotherhdr;
4194 		ctmp->tool      = role_cstm_text_tool;
4195 		ctmp->varnamep  = ctmpb;
4196 	    }
4197 	}
4198 	else
4199 	  ctmp->varmem = 0;
4200 
4201 	/* SMTP Server Action */
4202 	new_confline(&ctmp);
4203 	inick_confs[INICK_SMTP_CONF] = ctmp;
4204 	ctmp->help_title= _("HELP FOR SMTP SERVER ACTION");
4205 	ctmp->var       = &smtp_act_var;
4206 	ctmp->valoffset = roindent;
4207 	ctmp->keymenu   = &config_text_wshuf_keymenu;
4208 	ctmp->help      = h_config_role_usesmtp;
4209 	ctmp->tool      = t_tool;
4210 	utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, smtp_act_var.name);
4211 	tmp[sizeof(tmp)-1] = '\0';
4212 	ctmp->varname   = cpystr(tmp);
4213 	ctmp->varnamep  = ctmpb = ctmp;
4214 	ctmp->flags     = CF_STARTITEM;
4215 
4216 	if((lval = LVAL(&smtp_act_var, ew)) != NULL){
4217 	    for(i = 0; lval[i]; i++){
4218 		if(i)
4219 		  (void)new_confline(&ctmp);
4220 
4221 		ctmp->var       = &smtp_act_var;
4222 		ctmp->varmem    = i;
4223 		ctmp->valoffset = roindent;
4224 		ctmp->keymenu   = &config_text_wshuf_keymenu;
4225 		ctmp->help      = h_config_role_usesmtp;
4226 		ctmp->tool      = t_tool;
4227 		ctmp->varnamep  = ctmpb;
4228 	    }
4229 	}
4230 	else
4231 	  ctmp->varmem = 0;
4232 
4233 	/* NNTP Server Action */
4234 	new_confline(&ctmp);
4235 	inick_confs[INICK_NNTP_CONF] = ctmp;
4236 	ctmp->help_title= _("HELP FOR NNTP SERVER ACTION");
4237 	ctmp->var       = &nntp_act_var;
4238 	ctmp->valoffset = roindent;
4239 	ctmp->keymenu   = &config_text_wshuf_keymenu;
4240 	ctmp->help      = h_config_role_usenntp;
4241 	ctmp->tool      = t_tool;
4242 	utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", roindent-3, roindent-3, nntp_act_var.name);
4243 	tmp[sizeof(tmp)-1] = '\0';
4244 	ctmp->varname   = cpystr(tmp);
4245 	ctmp->varnamep  = ctmpb = ctmp;
4246 	ctmp->flags     = CF_STARTITEM;
4247 
4248 	if((lval = LVAL(&nntp_act_var, ew)) != NULL){
4249 	    for(i = 0; lval[i]; i++){
4250 		if(i)
4251 		  (void)new_confline(&ctmp);
4252 
4253 		ctmp->var       = &nntp_act_var;
4254 		ctmp->varmem    = i;
4255 		ctmp->valoffset = roindent;
4256 		ctmp->keymenu   = &config_text_wshuf_keymenu;
4257 		ctmp->help      = h_config_role_usenntp;
4258 		ctmp->tool      = t_tool;
4259 		ctmp->varnamep  = ctmpb;
4260 	    }
4261 	}
4262 	else
4263 	  ctmp->varmem = 0;
4264 
4265 	calculate_inick_stuff(ps);
4266     }
4267     else
4268       inick_confs[INICK_INICK_CONF] = NULL;
4269 
4270     if(edit_score){
4271 	int sindent;
4272 
4273 	sindent = MAX(utf8_width(score_act_var.name),utf8_width(hdrtok_act_var.name)) + 3;
4274 
4275 	/* Blank line */
4276 	new_confline(&ctmp);
4277 	ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
4278 
4279 	/* Score Value -- This doesn't inherit from inick */
4280 	new_confline(&ctmp);
4281 	ctmp->help_title= _("HELP FOR SCORE VALUE ACTION");
4282 	ctmp->var       = &score_act_var;
4283 	ctmp->valoffset = sindent;
4284 	ctmp->keymenu   = &config_text_keymenu;
4285 	ctmp->help      = h_config_role_scoreval;
4286 	ctmp->tool      = text_tool;
4287 	ctmp->flags    |= CF_NUMBER;
4288 	utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", sindent-3, sindent-3, score_act_var.name);
4289 	tmp[sizeof(tmp)-1] = '\0';
4290 	ctmp->varname   = cpystr(tmp);
4291 	ctmp->varnamep  = ctmp;
4292 	ctmp->value     = pretty_value(ps, ctmp);
4293 
4294 	new_confline(&ctmp);
4295 	ctmp->flags    |= CF_NOSELECT;
4296 	ctmp->value     = cpystr("   OR");
4297 
4298 	/* Score From Header */
4299 	new_confline(&ctmp);
4300 	ctmp->help_title= _("HELP FOR SCORE VALUE FROM HEADER ACTION");
4301 	ctmp->var       = &hdrtok_act_var;
4302 	ctmp->valoffset = sindent;
4303 	ctmp->keymenu   = &config_text_keymenu;
4304 	ctmp->help      = h_config_role_scorehdrtok;
4305 	ctmp->tool      = text_tool;
4306 	utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", sindent-3, sindent-3, hdrtok_act_var.name);
4307 	tmp[sizeof(tmp)-1] = '\0';
4308 	ctmp->varname   = cpystr(tmp);
4309 	ctmp->varnamep  = ctmp;
4310 	ctmp->value     = pretty_value(ps, ctmp);
4311     }
4312 
4313     if(edit_filter){
4314 	/*
4315 	 * Filtering got added in stages, so instead of simply having a
4316 	 * variable in action which is set to one of the three possible
4317 	 * values (FILTER_KILL, FILTER_STATE, FILTER_FOLDER) we infer
4318 	 * the value from other variables. (Perhaps it would still make
4319 	 * sense to change this.)
4320 	 * Action->kill is set iff the user checks Delete.
4321 	 * If the user checks the box that says Just Set State, then kill
4322 	 * is not set and action->folder is not set (and vice versa).
4323 	 * And finally, FILTER_FOLDER is set if !kill and action->folder is set.
4324 	 * (And it is set here as the default if there is no default
4325 	 * action and the user is required to fill in the Folder.)
4326 	 */
4327 	if(def && def->action && def->action->kill)
4328 	  fval = FILTER_KILL;
4329 	else if(def && def->action && !def->action->kill &&
4330 		!def->action->folder)
4331 	  fval = FILTER_STATE;
4332 	else
4333 	  fval = FILTER_FOLDER;
4334 
4335 	role_filt_ptr = &filter_type_var;	/* so radiobuttons can tell */
4336 	filter_type_var.name       = cpystr(_("Filter Action"));
4337 	filter_type_var.is_used    = 1;
4338 	filter_type_var.is_user    = 1;
4339 	apval = APVAL(&filter_type_var, ew);
4340 	*apval = (f=filter_types(fval)) ? cpystr(f->name) : NULL;
4341 	set_current_val(&filter_type_var, FALSE, FALSE);
4342 
4343 	/* Blank line */
4344 	new_confline(&ctmp);
4345 	ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
4346 
4347 	/* Filter Type */
4348 	new_confline(&ctmp);
4349 	ctmp->var       = &filter_type_var;
4350 	ctmp->keymenu   = &config_radiobutton_keymenu;
4351 	ctmp->help      = NO_HELP;
4352 	ctmp->tool      = NULL;
4353 	snprintf(tmp, sizeof(tmp), "%s =", filter_type_var.name);
4354 	tmp[sizeof(tmp)-1] = '\0';
4355 	ctmp->varname   = cpystr(tmp);
4356 	ctmp->varnamep  = ctmpb = ctmp;
4357 	ctmp->flags    |= (CF_NOSELECT | CF_STARTITEM);
4358 
4359 	new_confline(&ctmp);
4360 	ctmp->var       = NULL;
4361 	ctmp->valoffset = rindent;
4362 	ctmp->keymenu   = &config_radiobutton_keymenu;
4363 	ctmp->help      = NO_HELP;
4364 	ctmp->tool      = NULL;
4365 	ctmp->varnamep  = ctmpb;
4366 	ctmp->flags    |= CF_NOSELECT;
4367 	ctmp->value     = cpystr("Set    Choose One");
4368 
4369 	new_confline(&ctmp);
4370 	ctmp->var       = NULL;
4371 	ctmp->valoffset = rindent;
4372 	ctmp->keymenu   = &config_radiobutton_keymenu;
4373 	ctmp->help      = NO_HELP;
4374 	ctmp->tool      = radio_tool;
4375 	ctmp->varnamep  = ctmpb;
4376 	ctmp->flags    |= CF_NOSELECT;
4377 	ctmp->value     = cpystr(set_choose);				\
4378 
4379 	/* find longest value's name */
4380 	for(lv = 0, i = 0; (f = filter_types(i)); i++)
4381 	  if(lv < (j = utf8_width(f->name)))
4382 	    lv = j;
4383 
4384 	lv = MIN(lv, 100);
4385 
4386 	for(i = 0; (f = filter_types(i)); i++){
4387 	    new_confline(&ctmp);
4388 	    ctmp->help_title= _("HELP FOR FILTER ACTION");
4389 	    ctmp->var       = &filter_type_var;
4390 	    ctmp->valoffset = rindent;
4391 	    ctmp->keymenu   = &config_radiobutton_keymenu;
4392 	    ctmp->help      = h_config_filt_rule_type;
4393 	    ctmp->varmem    = i;
4394 	    ctmp->tool      = radio_tool;
4395 	    ctmp->varnamep  = ctmpb;
4396 	    utf8_snprintf(tmp, sizeof(tmp), "(%c)  %-*.*w", (f->value == fval) ? R_SELD : ' ',
4397 		    lv, lv, f->name);
4398 	    tmp[sizeof(tmp)-1] = '\0';
4399 	    ctmp->value     = cpystr(tmp);
4400 	}
4401 
4402 	/* Specific list of folders to copy to */
4403 	setup_dummy_pattern_var(&folder_act_var, _("Folder List"),
4404 			        (def && def->action)
4405 				   ? def->action->folder : NULL);
4406 
4407 	/* 5 is the width of `(*)  ' */
4408 	setup_role_pat_alt(ps, &ctmp, &folder_act_var, h_config_filter_folder,
4409 			   _("HELP FOR FILTER FOLDER NAME"),
4410 			   &config_role_actionfolder_keymenu, t_tool, rindent+5,
4411 			   !(fval == FILTER_FOLDER));
4412 
4413 	SETUP_MSG_STATE(ctmp, filt_imp_var, ival,
4414 		      _("HELP FOR SET IMPORTANT STATUS"), h_config_filt_stat_imp);
4415 	SETUP_MSG_STATE(ctmp, filt_new_var, nval,
4416 			_("HELP FOR SET NEW STATUS"), h_config_filt_stat_new);
4417 	SETUP_MSG_STATE(ctmp, filt_del_var, dval,
4418 			_("HELP FOR SET DELETED STATUS"), h_config_filt_stat_del);
4419 	SETUP_MSG_STATE(ctmp, filt_ans_var, aval,
4420 			_("HELP FOR SET ANSWERED STATUS"), h_config_filt_stat_ans);
4421 
4422 	/* Blank line */
4423 	new_confline(&ctmp);
4424 	ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
4425 
4426 	/* Keywords to be Set */
4427 	setup_dummy_pattern_var(&keyword_set_var, _("Set These Keywords"),
4428 			        (def && def->action)
4429 				  ? def->action->keyword_set : NULL);
4430 	setup_role_pat(ps, &ctmp, &keyword_set_var, h_config_filter_kw_set,
4431 		       _("HELP FOR KEYWORDS TO BE SET"),
4432 		       &config_role_keyword_keymenu, role_text_tool_kword,
4433 		       NULL, 23);
4434 
4435 	/* Keywords to be Cleared */
4436 	setup_dummy_pattern_var(&keyword_clr_var, _("Clear These Keywords"),
4437 			        (def && def->action)
4438 				  ? def->action->keyword_clr : NULL);
4439 	setup_role_pat(ps, &ctmp, &keyword_clr_var, h_config_filter_kw_clr,
4440 		       _("HELP FOR KEYWORDS TO BE CLEARED"),
4441 		       &config_role_keyword_keymenu, role_text_tool_kword,
4442 		       NULL, 23);
4443     }
4444 
4445     if(edit_other){
4446 	char     *pval;
4447 	int       oindent;
4448 
4449 	/* Blank line */
4450 	new_confline(&ctmp);
4451 	ctmp->flags		|= CF_NOSELECT | CF_B_LINE;
4452 
4453 	new_confline(&ctmp)->var  = NULL;
4454 	snprintf(tmp, sizeof(tmp), "%s =", sort_act_var.name);
4455 	tmp[sizeof(tmp)-1] = '\0';
4456 	ctmp->varname		  = cpystr(tmp);
4457 	ctmp->varnamep		  = ctmpb = ctmp;
4458 	ctmp->keymenu		  = &config_radiobutton_keymenu;
4459 	ctmp->help		  = NO_HELP;
4460 	ctmp->tool		  = role_sort_tool;
4461 	ctmp->valoffset		  = rindent;
4462 	ctmp->flags		 |= CF_NOSELECT;
4463 
4464 	new_confline(&ctmp)->var  = NULL;
4465 	ctmp->varnamep		  = ctmpb;
4466 	ctmp->keymenu		  = &config_radiobutton_keymenu;
4467 	ctmp->help		  = NO_HELP;
4468 	ctmp->tool		  = role_sort_tool;
4469 	ctmp->valoffset		  = rindent;
4470 	ctmp->flags		 |= CF_NOSELECT;
4471 	ctmp->value = cpystr("Set    Sort Options");
4472 
4473 	new_confline(&ctmp)->var = NULL;
4474 	ctmp->varnamep		  = ctmpb;
4475 	ctmp->keymenu		  = &config_radiobutton_keymenu;
4476 	ctmp->help		  = NO_HELP;
4477 	ctmp->tool		  = role_sort_tool;
4478 	ctmp->valoffset	    	  = rindent;
4479 	ctmp->flags              |= CF_NOSELECT;
4480 	ctmp->value     = cpystr(set_choose);				\
4481 
4482 	pval = PVAL(&sort_act_var, ew);
4483 	if(pval)
4484 	  decode_sort(pval, &def_sort, &def_sort_rev);
4485 
4486 	/* allow user to set their default sort order */
4487 	new_confline(&ctmp)->var = &sort_act_var;
4488 	ctmp->varnamep	      = ctmpb;
4489 	ctmp->keymenu	      = &config_radiobutton_keymenu;
4490 	ctmp->help	      = h_config_perfolder_sort;
4491 	ctmp->tool	      = role_sort_tool;
4492 	ctmp->valoffset	      = rindent;
4493 	ctmp->varmem	      = -1;
4494 	ctmp->value	      = generalized_sort_pretty_value(ps, ctmp, 0);
4495 
4496 	for(j = 0; j < 2; j++){
4497 	    for(i = 0; ps->sort_types[i] != EndofList; i++){
4498 		new_confline(&ctmp)->var = &sort_act_var;
4499 		ctmp->varnamep	      = ctmpb;
4500 		ctmp->keymenu	      = &config_radiobutton_keymenu;
4501 		ctmp->help	      = h_config_perfolder_sort;
4502 		ctmp->tool	      = role_sort_tool;
4503 		ctmp->valoffset	      = rindent;
4504 		ctmp->varmem	      = i + (j * EndofList);
4505 		ctmp->value	      = generalized_sort_pretty_value(ps, ctmp,
4506 								      0);
4507 	    }
4508 	}
4509 
4510 
4511 	/* Blank line */
4512 	new_confline(&ctmp);
4513 	ctmp->flags		|= CF_NOSELECT | CF_B_LINE;
4514 
4515 	oindent = utf8_width(iform_act_var.name) + 3;
4516 
4517 	/* Index Format Action */
4518 	new_confline(&ctmp);
4519 	ctmp->help_title= _("HELP FOR SET INDEX FORMAT ACTION");
4520 	ctmp->var       = &iform_act_var;
4521 	ctmp->valoffset = oindent;
4522 	ctmp->keymenu   = &config_text_keymenu;
4523 	ctmp->help      = h_config_set_index_format;
4524 	ctmp->tool      = text_tool;
4525 	utf8_snprintf(tmp, sizeof(tmp), "%-*.*w =", oindent-3, oindent-3, iform_act_var.name);
4526 	tmp[sizeof(tmp)-1] = '\0';
4527 	ctmp->varname   = cpystr(tmp);
4528 	ctmp->varnamep  = ctmp;
4529 	ctmp->value     = pretty_value(ps, ctmp);
4530 
4531 	/* Blank line */
4532 	new_confline(&ctmp);
4533 	ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
4534 
4535 	new_confline(&ctmp);
4536 	ctmp->flags    |= CF_STARTITEM;
4537 	utf8_snprintf(tmp, sizeof(tmp), "%s =", startup_var.name);
4538 	tmp[sizeof(tmp)-1] = '\0';
4539 	ctmp->varname		  = cpystr(tmp);
4540 	standard_radio_setup(ps, &ctmp, &startup_var, NULL);
4541     }
4542 
4543     if(edit_incol && pico_usingcolor()){
4544 	char *pval0, *pval1;
4545 	int def;
4546 
4547 	/* Blank line */
4548 	new_confline(&ctmp);
4549 	ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
4550 
4551 	new_confline(&ctmp);
4552 	ctmp->var		 = &rolecolor_vars[0];	/* foreground */
4553 	ctmp->varname		 = cpystr(_("Index Line Color ="));
4554 	ctmp->varnamep		 = ctmpb = ctmp;
4555 	ctmp->flags		|= (CF_STARTITEM | CF_NOSELECT);
4556 	ctmp->keymenu		 = &role_color_setting_keymenu;
4557 
4558 	pval0 = PVAL(&rolecolor_vars[0], ew);
4559 	pval1 = PVAL(&rolecolor_vars[1], ew);
4560 	if(pval0 && pval1)
4561 	  def = !(pval0[0] && pval1[1]);
4562 	else
4563 	  def = 1;
4564 
4565 	add_color_setting_disp(ps, &ctmp, &rolecolor_vars[0], ctmpb,
4566 			       &role_color_setting_keymenu,
4567 			       &config_checkbox_keymenu,
4568 			       h_config_incol,
4569 			       rindent, 0,
4570 			       def ? ps->VAR_NORM_FORE_COLOR
4571 				   : PVAL(&rolecolor_vars[0], ew),
4572 			       def ? ps->VAR_NORM_BACK_COLOR
4573 				   : PVAL(&rolecolor_vars[1], ew),
4574 			       def);
4575     }
4576   }
4577 
4578     if(need_options){
4579 	/* Options */
4580 
4581 	/* Blank line */
4582 	new_confline(&ctmp);
4583 	ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
4584 
4585 	new_confline(&ctmp);
4586 	ctmp->flags    |= CF_NOSELECT;
4587 	if(ps->ttyo->screen_cols >= (wid=utf8_width(ostr)) + 4){
4588 	    int dashes;
4589 
4590 	    dashes = (ps->ttyo->screen_cols - wid)/2;
4591 	    snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='),
4592 		     ostr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '='));
4593 	    ctmp->value = cpystr(tmp_20k_buf);
4594 	}
4595 	else
4596 	  ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '='));
4597 
4598 	/* Blank line */
4599 	new_confline(&ctmp);
4600 	ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
4601 
4602 	opt_var.name      = cpystr(_("Features"));
4603 	opt_var.is_used   = 1;
4604 	opt_var.is_user   = 1;
4605 	opt_var.is_list   = 1;
4606 	clrbitmap(feat_option_list);
4607 	if(def && def->patgrp && def->patgrp->age_uses_sentdate)
4608 	  setbitn(FEAT_SENTDATE, feat_option_list);
4609 
4610 	if(edit_filter){
4611 	    if(def && def->action && def->action->move_only_if_not_deleted)
4612 	      setbitn(FEAT_IFNOTDEL, feat_option_list);
4613 	    if(def && def->action && def->action->non_terminating)
4614 	      setbitn(FEAT_NONTERM, feat_option_list);
4615 	}
4616 
4617 	/* Options */
4618 	new_confline(&ctmp);
4619 	ctmp->var       = &opt_var;
4620 	ctmp->valoffset = 23;
4621 	ctmp->keymenu   = &config_checkbox_keymenu;
4622 	ctmp->help      = NO_HELP;
4623 	ctmp->tool      = NULL;
4624 	snprintf(tmp, sizeof(tmp), "%-20s =", opt_var.name);
4625 	tmp[sizeof(tmp)-1] = '\0';
4626 	ctmp->varname   = cpystr(tmp);
4627 	ctmp->varnamep  = ctmpb = ctmp;
4628 	ctmp->flags    |= (CF_NOSELECT | CF_STARTITEM);
4629 
4630 	new_confline(&ctmp);
4631 	ctmp->var       = NULL;
4632 	ctmp->valoffset = rindent;
4633 	ctmp->keymenu   = &config_checkbox_keymenu;
4634 	ctmp->help      = NO_HELP;
4635 	ctmp->tool      = feat_checkbox_tool;
4636 	ctmp->varnamep  = ctmpb;
4637 	ctmp->flags    |= CF_NOSELECT;
4638 	ctmp->value     = cpystr("Set    Feature Name");
4639 
4640 	new_confline(&ctmp);
4641 	ctmp->var       = NULL;
4642 	ctmp->valoffset = rindent;
4643 	ctmp->keymenu   = &config_checkbox_keymenu;
4644 	ctmp->help      = NO_HELP;
4645 	ctmp->tool      = feat_checkbox_tool;
4646 	ctmp->varnamep  = ctmpb;
4647 	ctmp->flags    |= CF_NOSELECT;
4648 	ctmp->value     = cpystr(set_choose);				\
4649 
4650 	/*  find longest value's name */
4651 	for(lv = 0, i = 0; (f = feat_feature_list(i)); i++){
4652 	    if(!edit_filter && (i == FEAT_IFNOTDEL || i == FEAT_NONTERM))
4653 	      continue;
4654 
4655 	    if(lv < (j = utf8_width(f->name)))
4656 	      lv = j;
4657 	}
4658 
4659 	lv = MIN(lv, 100);
4660 
4661 	for(i = 0; (f = feat_feature_list(i)); i++){
4662 	    if(!edit_filter && (i == FEAT_IFNOTDEL || i == FEAT_NONTERM))
4663 	      continue;
4664 
4665 	    new_confline(&ctmp);
4666 	    ctmp->var       = &opt_var;
4667 	    ctmp->help_title= _("HELP FOR FILTER FEATURES");
4668 	    ctmp->varnamep  = ctmpb;
4669 	    ctmp->keymenu   = &config_checkbox_keymenu;
4670 	    switch(i){
4671 	      case FEAT_SENTDATE:
4672 		ctmp->help      = h_config_filt_opts_sentdate;
4673 		break;
4674 	      case FEAT_IFNOTDEL:
4675 		ctmp->help      = h_config_filt_opts_notdel;
4676 		break;
4677 	      case FEAT_NONTERM:
4678 		ctmp->help      = h_config_filt_opts_nonterm;
4679 		break;
4680 	    }
4681 
4682 	    ctmp->tool      = feat_checkbox_tool;
4683 	    ctmp->valoffset = rindent;
4684 	    ctmp->varmem    = i;
4685 	    utf8_snprintf(tmp, sizeof(tmp), "[%c]  %-*.*w",
4686 		    bitnset(f->value, feat_option_list) ? 'X' : ' ',
4687 		    lv, lv, f->name);
4688 	    tmp[sizeof(tmp)-1] = '\0';
4689 	    ctmp->value     = cpystr(tmp);
4690 	}
4691     }
4692 
4693     if(need_uses){
4694 	/* Uses */
4695 
4696 	/* Blank line */
4697 	new_confline(&ctmp);
4698 	ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
4699 
4700 	new_confline(&ctmp);
4701 	ctmp->flags    |= CF_NOSELECT;
4702 	if(ps->ttyo->screen_cols >= (wid=utf8_width(ustr)) + 4){
4703 	    int dashes;
4704 
4705 	    dashes = (ps->ttyo->screen_cols - wid)/2;
4706 	    snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", repeat_char(dashes, '='),
4707 		     ustr, repeat_char(ps->ttyo->screen_cols-wid-dashes, '='));
4708 	    ctmp->value = cpystr(tmp_20k_buf);
4709 	}
4710 	else
4711 	  ctmp->value = cpystr(repeat_char(ps->ttyo->screen_cols, '='));
4712 
4713 	/* Blank line */
4714 	new_confline(&ctmp);
4715 	ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
4716 
4717 	/* Reply Type */
4718 	new_confline(&ctmp);
4719 	ctmp->var       = &repl_type_var;
4720 	ctmp->keymenu   = &config_radiobutton_keymenu;
4721 	ctmp->help      = NO_HELP;
4722 	ctmp->tool      = NULL;
4723 	snprintf(tmp, sizeof(tmp), "%s =", repl_type_var.name);
4724 	tmp[sizeof(tmp)-1] = '\0';
4725 	ctmp->varname   = cpystr(tmp);
4726 	ctmp->varnamep  = ctmpb = ctmp;
4727 	ctmp->flags    |= (CF_NOSELECT | CF_STARTITEM);
4728 
4729 	new_confline(&ctmp);
4730 	ctmp->var       = NULL;
4731 	ctmp->valoffset = rindent;
4732 	ctmp->keymenu   = &config_radiobutton_keymenu;
4733 	ctmp->help      = NO_HELP;
4734 	ctmp->tool      = NULL;
4735 	ctmp->varnamep  = ctmpb;
4736 	ctmp->flags    |= CF_NOSELECT;
4737 	ctmp->value     = cpystr("Set    Choose One");
4738 
4739 	new_confline(&ctmp);
4740 	ctmp->var       = NULL;
4741 	ctmp->valoffset = rindent;
4742 	ctmp->keymenu   = &config_radiobutton_keymenu;
4743 	ctmp->help      = NO_HELP;
4744 	ctmp->tool      = radio_tool;
4745 	ctmp->varnamep  = ctmpb;
4746 	ctmp->flags    |= CF_NOSELECT;
4747 	ctmp->value     = cpystr(set_choose);				\
4748 
4749 	/* find longest value's name */
4750 	for(lv = 0, i = 0; (f = role_repl_types(i)); i++)
4751 	  if(lv < (j = utf8_width(f->name)))
4752 	    lv = j;
4753 
4754 	lv = MIN(lv, 100);
4755 
4756 	for(i = 0; (f = role_repl_types(i)); i++){
4757 	    new_confline(&ctmp);
4758 	    ctmp->help_title= _("HELP FOR ROLE REPLY USE");
4759 	    ctmp->var       = &repl_type_var;
4760 	    ctmp->valoffset = rindent;
4761 	    ctmp->keymenu   = &config_radiobutton_keymenu;
4762 	    ctmp->help      = h_config_role_replyuse;
4763 	    ctmp->varmem    = i;
4764 	    ctmp->tool      = radio_tool;
4765 	    ctmp->varnamep  = ctmpb;
4766 	    utf8_snprintf(tmp, sizeof(tmp), "(%c)  %-*.*w", (((!(def && def->action) ||
4767 					     def->action->repl_type == -1) &&
4768 					    f->value == ROLE_REPL_DEFL) ||
4769 					  (def && def->action &&
4770 					  f->value == def->action->repl_type))
4771 					     ? R_SELD : ' ',
4772 		    lv, lv, f->name);
4773 	    tmp[sizeof(tmp)-1] = '\0';
4774 	    ctmp->value     = cpystr(tmp);
4775 	}
4776 
4777 	/* Blank line */
4778 	new_confline(&ctmp);
4779 	ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
4780 
4781 	/* Forward Type */
4782 	new_confline(&ctmp);
4783 	ctmp->var       = &forw_type_var;
4784 	ctmp->keymenu   = &config_radiobutton_keymenu;
4785 	ctmp->help      = NO_HELP;
4786 	ctmp->tool      = NULL;
4787 	snprintf(tmp, sizeof(tmp), "%s =", forw_type_var.name);
4788 	tmp[sizeof(tmp)-1] = '\0';
4789 	ctmp->varname   = cpystr(tmp);
4790 	ctmp->varnamep  = ctmpb = ctmp;
4791 	ctmp->flags    |= (CF_NOSELECT | CF_STARTITEM);
4792 
4793 	new_confline(&ctmp);
4794 	ctmp->var       = NULL;
4795 	ctmp->valoffset = rindent;
4796 	ctmp->keymenu   = &config_radiobutton_keymenu;
4797 	ctmp->help      = NO_HELP;
4798 	ctmp->tool      = NULL;
4799 	ctmp->varnamep  = ctmpb;
4800 	ctmp->flags    |= CF_NOSELECT;
4801 	ctmp->value     = cpystr("Set    Choose One");
4802 
4803 	new_confline(&ctmp);
4804 	ctmp->var       = NULL;
4805 	ctmp->valoffset = rindent;
4806 	ctmp->keymenu   = &config_radiobutton_keymenu;
4807 	ctmp->help      = NO_HELP;
4808 	ctmp->tool      = radio_tool;
4809 	ctmp->varnamep  = ctmpb;
4810 	ctmp->flags    |= CF_NOSELECT;
4811 	ctmp->value     = cpystr(set_choose);				\
4812 
4813 	/* find longest value's name */
4814 	for(lv = 0, i = 0; (f = role_forw_types(i)); i++)
4815 	  if(lv < (j = utf8_width(f->name)))
4816 	    lv = j;
4817 
4818 	lv = MIN(lv, 100);
4819 
4820 	for(i = 0; (f = role_forw_types(i)); i++){
4821 	    new_confline(&ctmp);
4822 	    ctmp->help_title= _("HELP FOR ROLE FORWARD USE");
4823 	    ctmp->var       = &forw_type_var;
4824 	    ctmp->valoffset = rindent;
4825 	    ctmp->keymenu   = &config_radiobutton_keymenu;
4826 	    ctmp->help      = h_config_role_forwarduse;
4827 	    ctmp->varmem    = i;
4828 	    ctmp->tool      = radio_tool;
4829 	    ctmp->varnamep  = ctmpb;
4830 	    utf8_snprintf(tmp, sizeof(tmp), "(%c)  %-*.*w", (((!(def && def->action) ||
4831 					     def->action->forw_type == -1) &&
4832 					    f->value == ROLE_FORW_DEFL) ||
4833 					  (def && def->action &&
4834 					  f->value == def->action->forw_type))
4835 					     ? R_SELD : ' ',
4836 		    lv, lv, f->name);
4837 	    tmp[sizeof(tmp)-1] = '\0';
4838 	    ctmp->value     = cpystr(tmp);
4839 	}
4840 
4841 	/* Blank line */
4842 	new_confline(&ctmp);
4843 	ctmp->flags    |= CF_NOSELECT | CF_B_LINE;
4844 
4845 	/* Compose Type */
4846 	new_confline(&ctmp);
4847 	ctmp->var       = &comp_type_var;
4848 	ctmp->keymenu   = &config_radiobutton_keymenu;
4849 	ctmp->help      = NO_HELP;
4850 	ctmp->tool      = NULL;
4851 	snprintf(tmp, sizeof(tmp), "%s =", comp_type_var.name);
4852 	tmp[sizeof(tmp)-1] = '\0';
4853 	ctmp->varname   = cpystr(tmp);
4854 	ctmp->varnamep  = ctmpb = ctmp;
4855 	ctmp->flags    |= (CF_NOSELECT | CF_STARTITEM);
4856 
4857 	new_confline(&ctmp);
4858 	ctmp->var       = NULL;
4859 	ctmp->valoffset = rindent;
4860 	ctmp->keymenu   = &config_radiobutton_keymenu;
4861 	ctmp->help      = NO_HELP;
4862 	ctmp->tool      = NULL;
4863 	ctmp->varnamep  = ctmpb;
4864 	ctmp->flags    |= CF_NOSELECT;
4865 	ctmp->value     = cpystr("Set    Choose One");
4866 
4867 	new_confline(&ctmp);
4868 	ctmp->var       = NULL;
4869 	ctmp->valoffset = rindent;
4870 	ctmp->keymenu   = &config_radiobutton_keymenu;
4871 	ctmp->help      = NO_HELP;
4872 	ctmp->tool      = radio_tool;
4873 	ctmp->varnamep  = ctmpb;
4874 	ctmp->flags    |= CF_NOSELECT;
4875 	ctmp->value     = cpystr(set_choose);				\
4876 
4877 	/* find longest value's name */
4878 	for(lv = 0, i = 0; (f = role_comp_types(i)); i++)
4879 	  if(lv < (j = utf8_width(f->name)))
4880 	    lv = j;
4881 
4882 	lv = MIN(lv, 100);
4883 
4884 	for(i = 0; (f = role_comp_types(i)); i++){
4885 	    new_confline(&ctmp);
4886 	    ctmp->help_title= _("HELP FOR ROLE COMPOSE USE");
4887 	    ctmp->var       = &comp_type_var;
4888 	    ctmp->valoffset = rindent;
4889 	    ctmp->keymenu   = &config_radiobutton_keymenu;
4890 	    ctmp->help      = h_config_role_composeuse;
4891 	    ctmp->varmem    = i;
4892 	    ctmp->tool      = radio_tool;
4893 	    ctmp->varnamep  = ctmpb;
4894 	    utf8_snprintf(tmp, sizeof(tmp), "(%c)  %-*.*w", (((!(def && def->action) ||
4895 					     def->action->comp_type == -1) &&
4896 					    f->value == ROLE_COMP_DEFL) ||
4897 					  (def && def->action &&
4898 					  f->value == def->action->comp_type))
4899 					     ? R_SELD : ' ',
4900 		    lv, lv, f->name);
4901 	    tmp[sizeof(tmp)-1] = '\0';
4902 	    ctmp->value     = cpystr(tmp);
4903 	}
4904     }
4905 
4906     memset(&screen, 0, sizeof(screen));
4907     screen.ro_warning = saved_screen ? saved_screen->deferred_ro_warning : 0;
4908     /* TRANSLATORS: Print something1 using something2.
4909        "roles" is something1 */
4910     rv = conf_scroll_screen(ps, &screen, first_line, title, _("roles"),
4911 			    (edit_incol && pico_usingcolor()) ? 1 : 0, NULL);
4912 
4913     /*
4914      * Now look at the fake variables and extract the information we
4915      * want from them.
4916      */
4917 
4918     if(rv == 1 && result){
4919 	/*
4920 	 * We know these variables exist, so we don't have to check that
4921 	 * apval is nonnull before evaluating *apval.
4922 	 */
4923 	apval = APVAL(&nick_var, ew);
4924 	nick = *apval;
4925 	*apval = NULL;
4926 	removing_leading_and_trailing_white_space(nick);
4927 
4928 	apval = APVAL(&comment_var, ew);
4929 	comment = *apval;
4930 	*apval = NULL;
4931 	removing_leading_and_trailing_white_space(comment);
4932 
4933 	alval = ALVAL(&to_pat_var, ew);
4934 	to_pat = *alval;
4935 	*alval = NULL;
4936 
4937 	alval = ALVAL(&from_pat_var, ew);
4938 	from_pat = *alval;
4939 	*alval = NULL;
4940 
4941 	alval = ALVAL(&sender_pat_var, ew);
4942 	sender_pat = *alval;
4943 	*alval = NULL;
4944 
4945 	alval = ALVAL(&cc_pat_var, ew);
4946 	cc_pat = *alval;
4947 	*alval = NULL;
4948 
4949 	alval = ALVAL(&recip_pat_var, ew);
4950 	recip_pat = *alval;
4951 	*alval = NULL;
4952 
4953 	alval = ALVAL(&partic_pat_var, ew);
4954 	partic_pat = *alval;
4955 	*alval = NULL;
4956 
4957 	alval = ALVAL(&news_pat_var, ew);
4958 	news_pat = *alval;
4959 	*alval = NULL;
4960 
4961 	alval = ALVAL(&subj_pat_var, ew);
4962 	subj_pat = *alval;
4963 	*alval = NULL;
4964 
4965 	alval = ALVAL(&alltext_pat_var, ew);
4966 	alltext_pat = *alval;
4967 	*alval = NULL;
4968 
4969 	alval = ALVAL(&bodytext_pat_var, ew);
4970 	bodytext_pat = *alval;
4971 	*alval = NULL;
4972 
4973 	alval = ALVAL(&keyword_pat_var, ew);
4974 	keyword_pat = *alval;
4975 	*alval = NULL;
4976 
4977 	alval = ALVAL(&charset_pat_var, ew);
4978 	charset_pat = *alval;
4979 	*alval = NULL;
4980 
4981 	apval = APVAL(&age_pat_var, ew);
4982 	age_pat = *apval;
4983 	*apval = NULL;
4984 	removing_leading_and_trailing_white_space(age_pat);
4985 
4986 	apval = APVAL(&size_pat_var, ew);
4987 	size_pat = *apval;
4988 	*apval = NULL;
4989 	removing_leading_and_trailing_white_space(size_pat);
4990 
4991 	apval = APVAL(&scorei_pat_var, ew);
4992 	scorei_pat = *apval;
4993 	*apval = NULL;
4994 	removing_leading_and_trailing_white_space(scorei_pat);
4995 
4996 	apval = APVAL(&stat_del_var, ew);
4997 	stat_del = *apval;
4998 	*apval = NULL;
4999 	removing_leading_and_trailing_white_space(stat_del);
5000 
5001 	apval = APVAL(&stat_new_var, ew);
5002 	stat_new = *apval;
5003 	*apval = NULL;
5004 	removing_leading_and_trailing_white_space(stat_new);
5005 
5006 	apval = APVAL(&stat_rec_var, ew);
5007 	stat_rec = *apval;
5008 	*apval = NULL;
5009 	removing_leading_and_trailing_white_space(stat_rec);
5010 
5011 	apval = APVAL(&stat_imp_var, ew);
5012 	stat_imp = *apval;
5013 	*apval = NULL;
5014 	removing_leading_and_trailing_white_space(stat_imp);
5015 
5016 	apval = APVAL(&stat_ans_var, ew);
5017 	stat_ans = *apval;
5018 	*apval = NULL;
5019 	removing_leading_and_trailing_white_space(stat_ans);
5020 
5021 	apval = APVAL(&stat_8bit_var, ew);
5022 	stat_8bit = *apval;
5023 	*apval = NULL;
5024 	removing_leading_and_trailing_white_space(stat_8bit);
5025 
5026 	apval = APVAL(&stat_bom_var, ew);
5027 	stat_bom = *apval;
5028 	*apval = NULL;
5029 	removing_leading_and_trailing_white_space(stat_bom);
5030 
5031 	apval = APVAL(&stat_boy_var, ew);
5032 	stat_boy = *apval;
5033 	*apval = NULL;
5034 	removing_leading_and_trailing_white_space(stat_boy);
5035 
5036 	apval = APVAL(&fldr_type_var, ew);
5037 	fldr_type_pat = *apval;
5038 	*apval = NULL;
5039 	removing_leading_and_trailing_white_space(fldr_type_pat);
5040 
5041 	alval = ALVAL(&folder_pat_var, ew);
5042 	folder_pat = *alval;
5043 	*alval = NULL;
5044 
5045 	apval = APVAL(&abook_type_var, ew);
5046 	abook_type_pat = *apval;
5047 	*apval = NULL;
5048 	removing_leading_and_trailing_white_space(abook_type_pat);
5049 
5050 	alval = ALVAL(&abook_pat_var, ew);
5051 	abook_pat = *alval;
5052 	*alval = NULL;
5053 
5054 	apval = APVAL(&cati_var, ew);
5055 	cati = *apval;
5056 	*apval = NULL;
5057 	removing_leading_and_trailing_white_space(cati);
5058 
5059 	apval = APVAL(&cat_lim_var, ew);
5060 	cat_lim = *apval;
5061 	*apval = NULL;
5062 	removing_leading_and_trailing_white_space(cat_lim);
5063 
5064 	apval = APVAL(&inick_var, ew);
5065 	inick = *apval;
5066 	*apval = NULL;
5067 	removing_leading_and_trailing_white_space(inick);
5068 
5069 	apval = APVAL(&from_act_var, ew);
5070 	from_act = *apval;
5071 	*apval = NULL;
5072 	removing_leading_and_trailing_white_space(from_act);
5073 
5074 	apval = APVAL(&replyto_act_var, ew);
5075 	replyto_act = *apval;
5076 	*apval = NULL;
5077 	removing_leading_and_trailing_white_space(replyto_act);
5078 
5079 	apval = APVAL(&fcc_act_var, ew);
5080 	fcc_act = *apval;
5081 	*apval = NULL;
5082 	removing_leading_and_trailing_white_space(fcc_act);
5083 
5084 	apval = APVAL(&litsig_act_var, ew);
5085 	litsig_act = *apval;
5086 	*apval = NULL;
5087 	removing_leading_and_trailing_white_space(litsig_act);
5088 
5089 	apval = APVAL(&sort_act_var, ew);
5090 	sort_act = *apval;
5091 	*apval = NULL;
5092 	removing_leading_and_trailing_white_space(sort_act);
5093 
5094 	apval = APVAL(&iform_act_var, ew);
5095 	iform_act = *apval;
5096 	*apval = NULL;
5097 	removing_leading_and_trailing_white_space(iform_act);
5098 
5099 	apval = APVAL(&startup_var, ew);
5100 	startup_act = *apval;
5101 	*apval = NULL;
5102 	removing_leading_and_trailing_white_space(startup_act);
5103 
5104 	apval = APVAL(&sig_act_var, ew);
5105 	sig_act = *apval;
5106 	*apval = NULL;
5107 	removing_leading_and_trailing_white_space(sig_act);
5108 
5109 	apval = APVAL(&templ_act_var, ew);
5110 	templ_act = *apval;
5111 	*apval = NULL;
5112 	removing_leading_and_trailing_white_space(templ_act);
5113 
5114 	apval = APVAL(&score_act_var, ew);
5115 	score_act = *apval;
5116 	*apval = NULL;
5117 	removing_leading_and_trailing_white_space(score_act);
5118 
5119 	apval = APVAL(&hdrtok_act_var, ew);
5120 	hdrtok_act = *apval;
5121 	*apval = NULL;
5122 	removing_leading_and_trailing_white_space(hdrtok_act);
5123 
5124 	apval = APVAL(&repl_type_var, ew);
5125 	repl_type = *apval;
5126 	*apval = NULL;
5127 	removing_leading_and_trailing_white_space(repl_type);
5128 
5129 	apval = APVAL(&forw_type_var, ew);
5130 	forw_type = *apval;
5131 	*apval = NULL;
5132 	removing_leading_and_trailing_white_space(forw_type);
5133 
5134 	apval = APVAL(&comp_type_var, ew);
5135 	comp_type = *apval;
5136 	*apval = NULL;
5137 	removing_leading_and_trailing_white_space(comp_type);
5138 
5139 	apval = APVAL(&rolecolor_vars[0], ew);
5140 	rc_fg = *apval;
5141 	*apval = NULL;
5142 	removing_leading_and_trailing_white_space(rc_fg);
5143 
5144 	apval = APVAL(&rolecolor_vars[1], ew);
5145 	rc_bg = *apval;
5146 	*apval = NULL;
5147 	removing_leading_and_trailing_white_space(rc_bg);
5148 
5149 	apval = APVAL(&filter_type_var, ew);
5150 	filter_type = *apval;
5151 	*apval = NULL;
5152 	removing_leading_and_trailing_white_space(filter_type);
5153 
5154 	alval = ALVAL(&folder_act_var, ew);
5155 	folder_act = *alval;
5156 	*alval = NULL;
5157 
5158 	alval = ALVAL(&keyword_set_var, ew);
5159 	keyword_set = *alval;
5160 	*alval = NULL;
5161 
5162 	alval = ALVAL(&keyword_clr_var, ew);
5163 	keyword_clr = *alval;
5164 	*alval = NULL;
5165 
5166 	apval = APVAL(&filt_imp_var, ew);
5167 	filt_imp = *apval;
5168 	*apval = NULL;
5169 	removing_leading_and_trailing_white_space(filt_imp);
5170 
5171 	apval = APVAL(&filt_del_var, ew);
5172 	filt_del = *apval;
5173 	*apval = NULL;
5174 	removing_leading_and_trailing_white_space(filt_del);
5175 
5176 	apval = APVAL(&filt_new_var, ew);
5177 	filt_new = *apval;
5178 	*apval = NULL;
5179 	removing_leading_and_trailing_white_space(filt_new);
5180 
5181 	apval = APVAL(&filt_ans_var, ew);
5182 	filt_ans = *apval;
5183 	*apval = NULL;
5184 	removing_leading_and_trailing_white_space(filt_ans);
5185 
5186 
5187 	alval = ALVAL(&cat_cmd_var, ew);
5188 	cat_cmd = *alval;
5189 	*alval = NULL;
5190 
5191 	alval = ALVAL(&cstm_act_var, ew);
5192 	cstm_act = *alval;
5193 	*alval = NULL;
5194 
5195 	alval = ALVAL(&smtp_act_var, ew);
5196 	smtp_act = *alval;
5197 	*alval = NULL;
5198 
5199 	alval = ALVAL(&nntp_act_var, ew);
5200 	nntp_act = *alval;
5201 	*alval = NULL;
5202 
5203 	if(ps->VAR_OPER_DIR && sig_act &&
5204 	   is_absolute_path(sig_act) &&
5205 	   !in_dir(ps->VAR_OPER_DIR, sig_act)){
5206 	    q_status_message1(SM_ORDER | SM_DING, 3, 4,
5207 			      _("Warning: Sig file can't be outside of %s"),
5208 			      ps->VAR_OPER_DIR);
5209 	}
5210 
5211 	if(ps->VAR_OPER_DIR && templ_act &&
5212 	   is_absolute_path(templ_act) &&
5213 	   !in_dir(ps->VAR_OPER_DIR, templ_act)){
5214 	    q_status_message1(SM_ORDER | SM_DING, 3, 4,
5215 			    _("Warning: Template file can't be outside of %s"),
5216 			    ps->VAR_OPER_DIR);
5217 	}
5218 
5219 	if(ps->VAR_OPER_DIR && folder_act)
5220 	  for(i = 0; folder_act[i]; i++){
5221 	    if(folder_act[i][0] && is_absolute_path(folder_act[i]) &&
5222 	       !in_dir(ps->VAR_OPER_DIR, folder_act[i])){
5223 		q_status_message1(SM_ORDER | SM_DING, 3, 4,
5224 				  _("Warning: Folder can't be outside of %s"),
5225 				  ps->VAR_OPER_DIR);
5226 	    }
5227 	  }
5228 
5229 	*result = (PAT_S *)fs_get(sizeof(**result));
5230 	memset((void *)(*result), 0, sizeof(**result));
5231 
5232 	(*result)->patgrp = (PATGRP_S *)fs_get(sizeof(*(*result)->patgrp));
5233 	memset((void *)(*result)->patgrp, 0, sizeof(*(*result)->patgrp));
5234 
5235 	(*result)->action = (ACTION_S *)fs_get(sizeof(*(*result)->action));
5236 	memset((void *)(*result)->action, 0, sizeof(*(*result)->action));
5237 
5238 	(*result)->patline = def ? def->patline : NULL;
5239 
5240 	if(nick && *nick){
5241 	    (*result)->patgrp->nick = nick;
5242 	    nick = NULL;
5243 	}
5244 	else
5245 	  (*result)->patgrp->nick = cpystr(nick_var.global_val.p);
5246 
5247 	if(comment && *comment){
5248 	    (*result)->patgrp->comment = comment;
5249 	    comment = NULL;
5250 	}
5251 
5252 	(*result)->action->nick = cpystr((*result)->patgrp->nick);
5253 
5254 	(*result)->action->is_a_role   = edit_role   ? 1 : 0;
5255 	(*result)->action->is_a_incol  = edit_incol  ? 1 : 0;
5256 	(*result)->action->is_a_score  = edit_score  ? 1 : 0;
5257 	(*result)->action->is_a_filter = edit_filter ? 1 : 0;
5258 	(*result)->action->is_a_other  = edit_other  ? 1 : 0;
5259 	(*result)->action->is_a_srch   = edit_srch   ? 1 : 0;
5260 
5261 	(*result)->patgrp->to      = editlist_to_pattern(to_pat);
5262 	if((*result)->patgrp->to && !strncmp(to_pat_var.name, NOT, NOTLEN))
5263 	  (*result)->patgrp->to->not = 1;
5264 
5265 	(*result)->patgrp->from    = editlist_to_pattern(from_pat);
5266 	if((*result)->patgrp->from && !strncmp(from_pat_var.name, NOT, NOTLEN))
5267 	  (*result)->patgrp->from->not = 1;
5268 
5269 	(*result)->patgrp->sender  = editlist_to_pattern(sender_pat);
5270 	if((*result)->patgrp->sender &&
5271 	   !strncmp(sender_pat_var.name, NOT, NOTLEN))
5272 	  (*result)->patgrp->sender->not = 1;
5273 
5274 	(*result)->patgrp->cc      = editlist_to_pattern(cc_pat);
5275 	if((*result)->patgrp->cc && !strncmp(cc_pat_var.name, NOT, NOTLEN))
5276 	  (*result)->patgrp->cc->not = 1;
5277 
5278 	(*result)->patgrp->recip   = editlist_to_pattern(recip_pat);
5279 	if((*result)->patgrp->recip &&
5280 	   !strncmp(recip_pat_var.name, NOT, NOTLEN))
5281 	  (*result)->patgrp->recip->not = 1;
5282 
5283 	(*result)->patgrp->partic  = editlist_to_pattern(partic_pat);
5284 	if((*result)->patgrp->partic &&
5285 	   !strncmp(partic_pat_var.name, NOT, NOTLEN))
5286 	  (*result)->patgrp->partic->not = 1;
5287 
5288 	(*result)->patgrp->news    = editlist_to_pattern(news_pat);
5289 	if((*result)->patgrp->news && !strncmp(news_pat_var.name, NOT, NOTLEN))
5290 	  (*result)->patgrp->news->not = 1;
5291 
5292 	(*result)->patgrp->subj    = editlist_to_pattern(subj_pat);
5293 	if((*result)->patgrp->subj && !strncmp(subj_pat_var.name, NOT, NOTLEN))
5294 	  (*result)->patgrp->subj->not = 1;
5295 
5296 	(*result)->patgrp->alltext = editlist_to_pattern(alltext_pat);
5297 	if((*result)->patgrp->alltext &&
5298 	   !strncmp(alltext_pat_var.name, NOT, NOTLEN))
5299 	  (*result)->patgrp->alltext->not = 1;
5300 
5301 	(*result)->patgrp->bodytext = editlist_to_pattern(bodytext_pat);
5302 	if((*result)->patgrp->bodytext &&
5303 	   !strncmp(bodytext_pat_var.name, NOT, NOTLEN))
5304 	  (*result)->patgrp->bodytext->not = 1;
5305 
5306 	(*result)->patgrp->keyword = editlist_to_pattern(keyword_pat);
5307 	if((*result)->patgrp->keyword &&
5308 	   !strncmp(keyword_pat_var.name, NOT, NOTLEN))
5309 	  (*result)->patgrp->keyword->not = 1;
5310 
5311 	(*result)->patgrp->charsets = editlist_to_pattern(charset_pat);
5312 	if((*result)->patgrp->charsets &&
5313 	   !strncmp(charset_pat_var.name, NOT, NOTLEN))
5314 	  (*result)->patgrp->charsets->not = 1;
5315 
5316 	(*result)->patgrp->age_uses_sentdate =
5317 		bitnset(FEAT_SENTDATE, feat_option_list) ? 1 : 0;
5318 
5319 	if(age_pat){
5320 	    if(((*result)->patgrp->age  = parse_intvl(age_pat)) != NULL)
5321 	      (*result)->patgrp->do_age = 1;
5322 	}
5323 
5324 	if(size_pat){
5325 	    if(((*result)->patgrp->size  = parse_intvl(size_pat)) != NULL)
5326 	      (*result)->patgrp->do_size = 1;
5327 	}
5328 
5329 	if(scorei_pat){
5330 	    if(((*result)->patgrp->score = parse_intvl(scorei_pat)) != NULL)
5331 	      (*result)->patgrp->do_score  = 1;
5332 	}
5333 
5334 	(*result)->patgrp->cat_lim = -1L; /* default */
5335 	if(cat_cmd){
5336 	    if(!cat_cmd[0])
5337 	      fs_give((void **) &cat_cmd);
5338 
5339 	    /* quick check for absolute paths */
5340 	    if(cat_cmd)
5341 	      for(j = 0; cat_cmd[j]; j++)
5342 		if(!is_absolute_path(cat_cmd[j]))
5343 		  q_status_message1(SM_ORDER | SM_DING, 3, 4,
5344 			_("Warning: command must be absolute path: \"%s\""),
5345 			cat_cmd[j]);
5346 
5347 	    (*result)->patgrp->category_cmd = cat_cmd;
5348 	    cat_cmd = NULL;
5349 
5350 	    if(cati){
5351 		if(((*result)->patgrp->cat = parse_intvl(cati)) != NULL)
5352 		  (*result)->patgrp->do_cat  = 1;
5353 	    }
5354 	    if(cat_lim && *cat_lim)
5355 	      (*result)->patgrp->cat_lim = atol(cat_lim);
5356 	}
5357 
5358 	if(stat_del && *stat_del){
5359 	    for(j = 0; (f = role_status_types(j)); j++)
5360 	      if(!strucmp(stat_del, f->name)){
5361 		  (*result)->patgrp->stat_del = f->value;
5362 		  break;
5363 	      }
5364 	}
5365 	else
5366 	  (*result)->patgrp->stat_del = PAT_STAT_EITHER;
5367 
5368 	if(stat_new && *stat_new){
5369 	    for(j = 0; (f = role_status_types(j)); j++)
5370 	      if(!strucmp(stat_new, f->name)){
5371 		  (*result)->patgrp->stat_new = f->value;
5372 		  break;
5373 	      }
5374 	}
5375 	else
5376 	  (*result)->patgrp->stat_new = PAT_STAT_EITHER;
5377 
5378 	if(stat_rec && *stat_rec){
5379 	    for(j = 0; (f = role_status_types(j)); j++)
5380 	      if(!strucmp(stat_rec, f->name)){
5381 		  (*result)->patgrp->stat_rec = f->value;
5382 		  break;
5383 	      }
5384 	}
5385 	else
5386 	  (*result)->patgrp->stat_rec = PAT_STAT_EITHER;
5387 
5388 	if(stat_imp && *stat_imp){
5389 	    for(j = 0; (f = role_status_types(j)); j++)
5390 	      if(!strucmp(stat_imp, f->name)){
5391 		  (*result)->patgrp->stat_imp = f->value;
5392 		  break;
5393 	      }
5394 	}
5395 	else
5396 	  (*result)->patgrp->stat_imp = PAT_STAT_EITHER;
5397 
5398 	if(stat_ans && *stat_ans){
5399 	    for(j = 0; (f = role_status_types(j)); j++)
5400 	      if(!strucmp(stat_ans, f->name)){
5401 		  (*result)->patgrp->stat_ans = f->value;
5402 		  break;
5403 	      }
5404 	}
5405 	else
5406 	  (*result)->patgrp->stat_ans = PAT_STAT_EITHER;
5407 
5408 	if(stat_8bit && *stat_8bit){
5409 	    for(j = 0; (f = role_status_types(j)); j++)
5410 	      if(!strucmp(stat_8bit, f->name)){
5411 		  (*result)->patgrp->stat_8bitsubj = f->value;
5412 		  break;
5413 	      }
5414 	}
5415 	else
5416 	  (*result)->patgrp->stat_8bitsubj = PAT_STAT_EITHER;
5417 
5418 	if(stat_bom && *stat_bom){
5419 	    for(j = 0; (f = role_status_types(j)); j++)
5420 	      if(!strucmp(stat_bom, f->name)){
5421 		  (*result)->patgrp->stat_bom = f->value;
5422 		  break;
5423 	      }
5424 	}
5425 	else
5426 	  (*result)->patgrp->stat_bom = PAT_STAT_EITHER;
5427 
5428 	if(stat_boy && *stat_boy){
5429 	    for(j = 0; (f = role_status_types(j)); j++)
5430 	      if(!strucmp(stat_boy, f->name)){
5431 		  (*result)->patgrp->stat_boy = f->value;
5432 		  break;
5433 	      }
5434 	}
5435 	else
5436 	  (*result)->patgrp->stat_boy = PAT_STAT_EITHER;
5437 
5438 	if(sort_act){
5439 	    decode_sort(sort_act, &def_sort, &def_sort_rev);
5440 	    (*result)->action->sort_is_set = 1;
5441 	    (*result)->action->sortorder = def_sort;
5442 	    (*result)->action->revsort = (def_sort_rev ? 1 : 0);
5443 	    /*
5444 	     * Don't try to re-sort until next open of folder. If user
5445 	     * $-sorted then it probably shouldn't change anyway. Why
5446 	     * bother keeping track of that?
5447 	     */
5448 	}
5449 
5450 	(*result)->action->index_format = iform_act;
5451 	iform_act = NULL;
5452 
5453 	if(startup_act && *startup_act){
5454 	    for(j = 0; (f = startup_rules(j)); j++)
5455 	      if(!strucmp(startup_act, f->name)){
5456 		  (*result)->action->startup_rule = f->value;
5457 		  break;
5458 	      }
5459 	}
5460 	else
5461 	  (*result)->action->startup_rule = IS_NOTSET;
5462 
5463 	aa = NULL;
5464 	for(ea = earb; ea; ea = ea->next){
5465 	    char *xyz;
5466 
5467 	    if(aa){
5468 		aa->next = (ARBHDR_S *)fs_get(sizeof(*aa));
5469 		aa = aa->next;
5470 	    }
5471 	    else{
5472 		(*result)->patgrp->arbhdr =
5473 				      (ARBHDR_S *)fs_get(sizeof(ARBHDR_S));
5474 		aa = (*result)->patgrp->arbhdr;
5475 	    }
5476 
5477 	    memset(aa, 0, sizeof(*aa));
5478 
5479 	    aa->field = cpystr((ea->a && ea->a->field) ? ea->a->field : "");
5480 
5481 	    alval = ALVAL(ea->v, ew);
5482 	    spat = *alval;
5483 	    *alval = NULL;
5484 	    aa->p = editlist_to_pattern(spat);
5485 	    if(aa->p && ea->v && ea->v->name &&
5486 	       !strncmp(ea->v->name, NOT, NOTLEN))
5487 	      aa->p->not = 1;
5488 
5489 	    if((xyz = pattern_to_string(aa->p)) != NULL){
5490 		if(!*xyz)
5491 		  aa->isemptyval = 1;
5492 
5493 		fs_give((void **)&xyz);
5494 	    }
5495 	}
5496 
5497 	if(fldr_type_pat && *fldr_type_pat){
5498 	    for(j = 0; (f = pat_fldr_types(j)); j++)
5499 	      if(!strucmp(fldr_type_pat, f->name)){
5500 		  (*result)->patgrp->fldr_type = f->value;
5501 		  break;
5502 	      }
5503 	}
5504 	else{
5505 	    f = pat_fldr_types(FLDR_DEFL);
5506 	    if(f)
5507 	      (*result)->patgrp->fldr_type = f->value;
5508 	}
5509 
5510 	(*result)->patgrp->folder = editlist_to_pattern(folder_pat);
5511 
5512 	if(abook_type_pat && *abook_type_pat){
5513 	    for(j = 0; (f = inabook_fldr_types(j)); j++){
5514 	      if(!strucmp(abook_type_pat, f->name)){
5515 		  (*result)->patgrp->inabook = f->value;
5516 		  break;
5517 	      }
5518 	    }
5519 
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;
5530 
5531 	      if(!((*result)->patgrp->inabook & IAB_TYPE_MASK))
5532 		(*result)->patgrp->inabook |= (IAB_FROM | IAB_REPLYTO);
5533 	}
5534 	else{
5535 	    f = inabook_fldr_types(IAB_DEFL);
5536 	    if(f)
5537 	      (*result)->patgrp->inabook = f->value;
5538 	}
5539 
5540 	(*result)->patgrp->abooks = editlist_to_pattern(abook_pat);
5541 
5542 
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;
5553 
5554 	if(cstm_act){
5555 	    /*
5556 	     * Check for From or Reply-To and eliminate them.
5557 	     */
5558 	    for(i = 0; cstm_act[i]; i++){
5559 		char *free_this;
5560 
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];
5571 
5572 		    fs_give((void **)&free_this);
5573 		    i--;	/* recheck now that we've slid them up */
5574 		}
5575 	    }
5576 
5577 	    /* nothing left */
5578 	    if(!cstm_act[0])
5579 	      fs_give((void **)&cstm_act);
5580 
5581 	    (*result)->action->cstm = cstm_act;
5582 	    cstm_act = NULL;
5583 	}
5584 
5585 	if(smtp_act){
5586 	    if(!smtp_act[0])
5587 	      fs_give((void **)&smtp_act);
5588 
5589 	    (*result)->action->smtp = smtp_act;
5590 	    smtp_act = NULL;
5591 	}
5592 
5593 	if(nntp_act){
5594 	    if(!nntp_act[0])
5595 	      fs_give((void **)&nntp_act);
5596 
5597 	    (*result)->action->nntp = nntp_act;
5598 	    nntp_act = NULL;
5599 	}
5600 
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;
5610 	      }
5611 	      else if(f->value == FILTER_STATE){
5612 		(*result)->action->kill = 0;
5613 	      }
5614 	      else if(f->value == FILTER_KILL){
5615 	        (*result)->action->kill = 1;
5616 	      }
5617 
5618 	      /*
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.
5627 	       */
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;
5640 		      }
5641 		      break;
5642 		    }
5643 		  }
5644 		}
5645 
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;
5658 		      }
5659 		      break;
5660 		    }
5661 		  }
5662 		}
5663 
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;
5676 		      }
5677 		      break;
5678 		    }
5679 		  }
5680 		}
5681 
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;
5694 		      }
5695 		      break;
5696 		    }
5697 		  }
5698 		}
5699 
5700 		(*result)->action->keyword_set =
5701 					editlist_to_pattern(keyword_set);
5702 		(*result)->action->keyword_clr =
5703 					editlist_to_pattern(keyword_clr);
5704 
5705 	      break;
5706 	    }
5707 	  }
5708 	}
5709 
5710 	if(from_act && *from_act)
5711 	  rfc822_parse_adrlist(&(*result)->action->from, from_act,
5712 			       ps->maildomain);
5713 
5714 	if(replyto_act && *replyto_act)
5715 	  rfc822_parse_adrlist(&(*result)->action->replyto, replyto_act,
5716 			       ps->maildomain);
5717 
5718 	if(score_act && (j = atoi(score_act)) >= SCORE_MIN && j <= SCORE_MAX)
5719 	  (*result)->action->scoreval = (long) j;
5720 
5721 	if(hdrtok_act)
5722 	  (*result)->action->scorevalhdrtok = stringform_to_hdrtok(hdrtok_act);
5723 
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;
5729 	      }
5730 	}
5731 	else{
5732 	    f = role_repl_types(ROLE_REPL_DEFL);
5733 	    if(f)
5734 	      (*result)->action->repl_type = f->value;
5735 	}
5736 
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;
5742 	      }
5743 	}
5744 	else{
5745 	    f = role_forw_types(ROLE_FORW_DEFL);
5746 	    if(f)
5747 	      (*result)->action->forw_type = f->value;
5748 	}
5749 
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;
5755 	      }
5756 	}
5757 	else{
5758 	    f = role_comp_types(ROLE_COMP_DEFL);
5759 	    if(f)
5760 	      (*result)->action->comp_type = f->value;
5761 	}
5762 
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);
5767 
5768 	    /*
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.
5774 	     */
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);
5780 	}
5781     }
5782 
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);
5788     }
5789 
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);
5908 
5909     if(cat_cmd)
5910       free_list_array(&cat_cmd);
5911 
5912     if(cstm_act)
5913       free_list_array(&cstm_act);
5914 
5915     if(smtp_act)
5916       free_list_array(&smtp_act);
5917 
5918     if(nntp_act)
5919       free_list_array(&nntp_act);
5920 
5921     opt_screen = saved_screen;
5922     ps->mangled_screen = 1;
5923     return(rv);
5924 }
5925 
5926 
5927 void
setup_dummy_pattern_var(struct variable * v,char * name,PATTERN_S * defpat)5928 setup_dummy_pattern_var(struct variable *v, char *name, PATTERN_S *defpat)
5929 {
5930     char ***alval;
5931 
5932     if(!(v && name))
5933       alpine_panic("setup_dummy_pattern_var");
5934 
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);
5944 }
5945 
5946 
5947 void
setup_role_pat(struct pine * ps,CONF_S ** ctmp,struct variable * v,HelpType help,char * help_title,struct key_menu * keymenu,int (* tool)(struct pine *,int,CONF_S **,unsigned),EARB_S ** earb,int indent)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)
5952 {
5953     char    tmp[MAXPATH+1];
5954     char  **lval;
5955     int     i;
5956     CONF_S *ctmpb;
5957 
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;
5973 
5974     ctmpb = (*ctmp);
5975 
5976     lval = LVAL(v, ew);
5977     if(lval){
5978 	for(i = 0; lval[i]; i++){
5979 	    if(i)
5980 	      new_confline(ctmp);
5981 
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;
5991 	}
5992     }
5993 }
5994 
5995 
5996 /*
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.
5999  */
6000 void
setup_role_pat_alt(struct pine * ps,CONF_S ** ctmp,struct variable * v,HelpType help,char * help_title,struct key_menu * keymenu,int (* tool)(struct pine *,int,CONF_S **,unsigned),int voff,int nosel)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)
6005 {
6006     char    tmp[MAXPATH+1];
6007     char  **lval;
6008     int     i, j, k;
6009     CONF_S *ctmpb;
6010 
6011     new_confline(ctmp);
6012     (*ctmp)->help_title = help_title;
6013     (*ctmp)->var        = v;
6014 
6015     (*ctmp)->varoffset  = voff;
6016     k                   = utf8_width(v->name);
6017     j                   = voff+k+3;
6018     (*ctmp)->valoffset  = j;
6019 
6020     (*ctmp)->keymenu    = keymenu;
6021     (*ctmp)->help       = help;
6022     (*ctmp)->tool       = tool;
6023 
6024     utf8_snprintf(tmp, sizeof(tmp), "%*.*w =", k, k, v->name);
6025     tmp[sizeof(tmp)-1] = '\0';
6026     (*ctmp)->varname    = cpystr(tmp);
6027 
6028     (*ctmp)->varnamep   = *ctmp;
6029     (*ctmp)->value      = pretty_value(ps, *ctmp);
6030     (*ctmp)->varmem     = 0;
6031 
6032     (*ctmp)->flags      = (nosel ? CF_NOSELECT : 0);
6033 
6034     ctmpb = (*ctmp);
6035 
6036     lval = LVAL(v, ew);
6037     if(lval){
6038 	for(i = 0; lval[i]; i++){
6039 	    if(i)
6040 	      new_confline(ctmp);
6041 
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);
6052 	}
6053     }
6054 }
6055 
6056 
6057 void
free_earb(EARB_S ** ea)6058 free_earb(EARB_S **ea)
6059 {
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);
6066 
6067 	    fs_give((void **) &(*ea)->v);;
6068 	}
6069 
6070 	free_arbhdr(&(*ea)->a);
6071 	fs_give((void **) ea);
6072     }
6073 }
6074 
6075 
6076 void
calculate_inick_stuff(struct pine * ps)6077 calculate_inick_stuff(struct pine *ps)
6078 {
6079     ACTION_S        *role, *irole;
6080     CONF_S          *ctmp, *ctmpa;
6081     struct variable *v;
6082     int              i;
6083     char            *nick;
6084 
6085     if(inick_confs[INICK_INICK_CONF] == NULL)
6086       return;
6087 
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);
6094 	  }
6095 	  else{
6096 	      if(v->global_val.p)
6097 		fs_give((void **)&v->global_val.p);
6098 	  }
6099 	}
6100     }
6101 
6102     nick = PVAL(inick_confs[INICK_INICK_CONF]->var, ew);
6103 
6104     if(nick){
6105 	/*
6106 	 * Use an empty role with inherit_nick set to nick and then use the
6107 	 * combine function to find the action values.
6108 	 */
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);
6114 
6115 	ctmp = inick_confs[INICK_FROM_CONF];
6116 	v = ctmp ? ctmp->var : NULL;
6117 
6118 	if(irole && irole->from){
6119 	    char *bufp;
6120 	    size_t len;
6121 
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);
6125 	}
6126 
6127 	ctmp = inick_confs[INICK_REPLYTO_CONF];
6128 	v = ctmp ? ctmp->var : NULL;
6129 
6130 	if(irole && irole->replyto){
6131 	    char *bufp;
6132 	    size_t len;
6133 
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);
6137 	}
6138 
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;
6142 
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;
6147 
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;
6151 
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;
6156 
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;
6161 
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;
6166 
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;
6171 
6172 	free_action(&role);
6173 	free_action(&irole);
6174     }
6175 
6176     for(i = INICK_INICK_CONF; i <= INICK_NNTP_CONF; i++){
6177 	ctmp = inick_confs[i];
6178 	v = ctmp ? ctmp->var : NULL;
6179 	/*
6180 	 * If we didn't set a global_val using the nick above, then
6181 	 * set one here for each variable that uses one.
6182 	 */
6183 	if(v && !v->global_val.p){
6184 	    char    *str, *astr, *lc, pdir[MAXPATH+1];
6185 	    ADDRESS *addr;
6186 	    int      len = 0;
6187 
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);
6199 
6200 		if(addr)
6201 		  mail_free_address(&addr);
6202 
6203 		break;
6204 
6205 	      case INICK_FCC_CONF:
6206 		v->global_val.p = cpystr(VSTRING);
6207 		break;
6208 
6209 	      case INICK_LITSIG_CONF:
6210 		/*
6211 		 * This default works this way because of the ordering
6212 		 * of the choices in the detoken routine.
6213 		 */
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';
6221 		}
6222 
6223 		break;
6224 
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;
6231 		}
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);
6237 		}
6238 
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;
6244 		}
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';
6253 		}
6254 
6255 		break;
6256 
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;
6264 	    }
6265 	}
6266 
6267 	if(v)
6268 	  set_current_val(v, FALSE, FALSE);
6269 
6270 	if(ctmp){
6271 	    CONF_S          *ctmpsig = NULL;
6272 	    struct variable *vlsig;
6273 
6274 	    for(ctmpa = ctmp;
6275 		ctmpa && ctmpa->varnamep == ctmp;
6276 		ctmpa = ctmpa->next){
6277 		if(ctmpa->value)
6278 		  fs_give((void **)&ctmpa->value);
6279 
6280 		ctmpa->value = pretty_value(ps, ctmpa);
6281 	    }
6282 
6283 	    if(i == INICK_SIG_CONF){
6284 		/*
6285 		 * Turn off NOSELECT, but possibly turn it on again
6286 		 * in next line.
6287 		 */
6288 		if((ctmpsig = inick_confs[INICK_SIG_CONF]) != NULL)
6289 		  ctmpsig->flags &= ~CF_NOSELECT;
6290 
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);
6297 
6298 		    ctmp->value =
6299 				cpystr("<Ignored: using LiteralSig instead>");
6300 
6301 		    ctmp->flags |= CF_NOSELECT;
6302 		}
6303 	    }
6304 	}
6305     }
6306 }
6307 
6308 
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.
6315  *
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.
6320  */
6321 int
check_role_folders(char ** lst,unsigned int action)6322 check_role_folders(char **lst, unsigned int action)
6323 {
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;
6329 
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;
6339     }
6340 
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];
6346 
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);
6354 
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';
6369 	    }
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';
6380 	    }
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';
6388 	    }
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';
6396 	    }
6397 
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);
6404 		}
6405 	      }
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;
6409 	    }
6410 	    else if(wt_res == 'n' && action){
6411 	      rv = 2;
6412 	      q_status_message(SM_ORDER,3,5,_("Folder not created"));
6413 	    }
6414 	    else{
6415 	      q_status_message(SM_ORDER,3,5,_("Exit cancelled"));
6416 	      rv = 0;
6417 	      break;
6418 	    }
6419 	  }
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);
6426 	      }
6427 
6428 	      rv = 2;
6429 	  }
6430 	}
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;
6438 	}
6439 
6440 	if(cur_fn && cur_fn != lst[i])
6441 	  fs_give((void **) &cur_fn);
6442     }
6443 
6444     return(rv);
6445 }
6446 
6447 
6448 void
maybe_add_to_incoming(CONTEXT_S * cntxt,char * cur_fn)6449 maybe_add_to_incoming(CONTEXT_S *cntxt, char *cur_fn)
6450 {
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;
6457 
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));
6461 	/*
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...
6466 	 */
6467 	for(found = 0, i = 0; *alval && (*alval)[i] && !found; i++){
6468 	    char *nickname, *folder;
6469 
6470 	    get_pair((*alval)[i], &nickname, &folder, 0, 0);
6471 	    if(folder && !strucmp((*alval)[i], folder))
6472 	      found++;
6473 
6474 	    if(nickname)
6475 	      fs_give((void **)&nickname);
6476 	    if(folder)
6477 	      fs_give((void **)&folder);
6478 	}
6479 
6480 	if(found)
6481 	  return;
6482 
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;
6495 
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;
6506 
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++;
6516 
6517 		    for(i = 0;
6518 			!found &&
6519 			  i < folder_total(FOLDERS(ps_global->context_list));
6520 			i++){
6521 			FOLDER_S *f;
6522 
6523 			f = folder_entry(i, FOLDERS(ps_global->context_list));
6524 			if(!strucmp(FLDR_NAME(f), nname))
6525 			  found++;
6526 		    }
6527 
6528 		    if(found){
6529 			q_status_message1(SM_ORDER | SM_DING, 3, 5,
6530 				      _("Nickname \"%s\" is already in use"),
6531 					  nname);
6532 			continue;
6533 		    }
6534 
6535 		    break;
6536 		}
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;
6544 		}
6545 	    }
6546 
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));
6553 
6554 	    if(!*alval){
6555 		i = 0;
6556 		*alval = (char **)fs_get(2 * sizeof(char *));
6557 	    }
6558 	    else{
6559 		for(i = 0; (*alval)[i]; i++)
6560 		  ;
6561 
6562 		fs_resize((void **)alval, (i + 2) * sizeof(char *));
6563 	    }
6564 
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);
6569 	}
6570     }
6571 }
6572 
6573 
6574 int
role_filt_exitcheck(CONF_S ** cl,unsigned int flags)6575 role_filt_exitcheck(CONF_S **cl, unsigned int flags)
6576 {
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
6586 
6587     /*
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.
6591      */
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;
6597 
6598 	switch(f ? f->value : -1){
6599 	  case FILTER_KILL:
6600 	    action = ACT_KILL;
6601 	    break;
6602 
6603 	  case FILTER_STATE:
6604 	    action = ACT_STATE;
6605 	    break;
6606 
6607 	  case FILTER_FOLDER:
6608 	    /*
6609 	     * Check that the folder is set to something.
6610 	     */
6611 
6612 	    action = ACT_MOVE_NOFOLDER;
6613 	    /* go to end of screen */
6614 	    for(ctmp = (*cl);
6615 		ctmp && ctmp->next;
6616 		ctmp = next_confline(ctmp))
6617 	      ;
6618 
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))
6624 	      ;
6625 
6626 	    /* skip back past NOSELECTs */
6627 	    for(;
6628 		ctmp && (ctmp->flags & CF_NOSELECT);
6629 		ctmp = next_confline(ctmp))
6630 	      ;
6631 
6632 	    /* find line with new var (the Folder line) */
6633 	    for(;
6634 		ctmp && (ctmp->var == role_filt_ptr);
6635 		ctmp = next_confline(ctmp))
6636 	      ;
6637 
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;
6643 	    }
6644 
6645 	    break;
6646 
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;
6652 	}
6653     }
6654 
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"));
6667 		}
6668 		else{
6669 		  q_status_message(SM_ORDER, 0, 3,
6670 				   _("Ok, messages matching that Pattern will be deleted"));
6671 		  rv = 2;
6672 		}
6673 		break;
6674 
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);
6681 		}
6682 		else
6683 		  rv = check_role_folders(to_folder, 1);
6684 
6685 		break;
6686 
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;
6692 
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);
6697 		}
6698 		else
6699 		  rv = 2;
6700 
6701 		break;
6702 
6703 	      default:
6704 		rv = 2;
6705 		dprint((1,
6706 		    "This can't happen, role_filt_ptr or to_folder not set\n"));
6707 		break;
6708 	    }
6709 
6710 	    break;
6711 
6712 	  case 'n':
6713 	    q_status_message(SM_ORDER,3,5,_("No filter changes saved"));
6714 	    rv = 10;
6715 	    break;
6716 
6717 	  case 'x':  /* ^C */
6718 	  default :
6719 	    q_status_message(SM_ORDER,3,5,_("Changes not yet saved"));
6720 	    rv = 0;
6721 	    break;
6722 	}
6723     }
6724     else
6725       rv = 2;
6726 
6727     if(to_folder)
6728       free_list_array(&to_folder);
6729 
6730     return(rv);
6731 }
6732 
6733 
6734 /*
6735  * Don't allow exit unless user has set the action to something.
6736  */
6737 int
role_filt_text_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)6738 role_filt_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
6739 {
6740     int             rv;
6741 
6742     switch(cmd){
6743       case MC_EXIT:
6744 	rv = role_filt_exitcheck(cl, flags);
6745 	break;
6746 
6747       default:
6748 	rv = role_text_tool(ps, cmd, cl, flags);
6749 	break;
6750     }
6751 
6752     return(rv);
6753 }
6754 
6755 
6756 int
role_filt_addhdr_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)6757 role_filt_addhdr_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
6758 {
6759     int rv;
6760 
6761     switch(cmd){
6762       case MC_EXIT:
6763 	rv = role_filt_exitcheck(cl, flags);
6764 	break;
6765 
6766       default:
6767 	rv = role_addhdr_tool(ps, cmd, cl, flags);
6768 	break;
6769     }
6770 
6771     return rv;
6772 }
6773 
6774 int
role_addhdr_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)6775 role_addhdr_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
6776 {
6777     int rv;
6778 
6779     switch(cmd){
6780       case MC_ADDHDR:
6781       case MC_EXIT:
6782 	rv = role_text_tool(ps, cmd, cl, flags);
6783 	break;
6784 
6785       default:
6786 	rv = -1;
6787 	break;
6788     }
6789 
6790     return rv;
6791 }
6792 
6793 /*
6794  * Don't allow exit unless user has set the action to something.
6795  */
6796 int
role_filt_radiobutton_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)6797 role_filt_radiobutton_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
6798 {
6799     int             rv;
6800 
6801     switch(cmd){
6802       case MC_EXIT:
6803 	rv = role_filt_exitcheck(cl, flags);
6804 	break;
6805 
6806       default:
6807 	rv = role_radiobutton_tool(ps, cmd, cl, flags);
6808 	break;
6809     }
6810 
6811     return(rv);
6812 }
6813 
6814 
6815 /*
6816  * simple radio-button style variable handler
6817  */
6818 int
role_radiobutton_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)6819 role_radiobutton_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
6820 {
6821     int	       rv = 0, i;
6822     CONF_S    *ctmp, *spec_ctmp = NULL;
6823     NAMEVAL_S *rule;
6824     char     **apval;
6825 
6826     switch(cmd){
6827       case MC_CHOICE :				/* set/unset feature */
6828 
6829 	/* back up to first line */
6830 	for(ctmp = (*cl);
6831 	    ctmp && ctmp->prev && !(ctmp->prev->flags & CF_NOSELECT);
6832 	    ctmp = prev_confline(ctmp))
6833 	  ;
6834 
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;
6849 		}
6850 	    }
6851 
6852 	    ctmp->value[1] = ' ';
6853 	}
6854 
6855 	/* turn on current value */
6856 	(*cl)->value[1] = R_SELD;
6857 
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;
6866 
6867 	    rule = pat_fldr_types((*cl)->varmem);
6868 	}
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;
6878 
6879 	    rule = inabook_fldr_types((*cl)->varmem);
6880 	}
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;
6889 
6890 	    rule = filter_types((*cl)->varmem);
6891 	}
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);
6912 
6913 	apval = APVAL((*cl)->var, ew);
6914 	if(apval && *apval)
6915 	  fs_give((void **)apval);
6916 
6917 	if(apval)
6918 	  *apval = cpystr(rule->name);
6919 
6920 	ps->mangled_body = 1;	/* BUG: redraw it all for now? */
6921 	rv = 1;
6922 
6923 	break;
6924 
6925       case MC_EXIT:				/* exit */
6926 	rv = role_text_tool(ps, cmd, cl, flags);
6927 	break;
6928 
6929       default :
6930 	rv = -1;
6931 	break;
6932     }
6933 
6934     return(rv);
6935 }
6936 
6937 
6938 int
role_sort_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)6939 role_sort_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
6940 {
6941     int	       rv = 0, i;
6942     CONF_S    *ctmp;
6943     char     **apval;
6944     SortOrder  def_sort;
6945     int        def_sort_rev;
6946 
6947     apval = APVAL((*cl)->var, ew);
6948 
6949     switch(cmd){
6950       case MC_CHOICE :				/* set/unset feature */
6951 
6952 	if((*cl)->varmem >= 0){
6953 	    def_sort_rev = (*cl)->varmem >= (short) EndofList;
6954 	    def_sort = (SortOrder)((*cl)->varmem - (def_sort_rev * EndofList));
6955 
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';
6959 	}
6960 
6961 	if(apval){
6962 	    if(*apval)
6963 	      fs_give((void **)apval);
6964 
6965 	    if((*cl)->varmem >= 0)
6966 	      *apval = cpystr(tmp_20k_buf);
6967 	}
6968 
6969 	/* back up to first line */
6970 	for(ctmp = (*cl);
6971 	    ctmp && ctmp->prev && !(ctmp->prev->flags & CF_NOSELECT);
6972 	    ctmp = prev_confline(ctmp))
6973 	  ;
6974 
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] = ' ';
6980 
6981 	/* turn on current value */
6982 	(*cl)->value[1] = R_SELD;
6983 
6984 	ps->mangled_body = 1;	/* BUG: redraw it all for now? */
6985 	rv = 1;
6986 
6987 	break;
6988 
6989       case MC_EXIT:				/* exit */
6990 	rv = role_text_tool(ps, cmd, cl, flags);
6991 	break;
6992 
6993       default :
6994 	rv = -1;
6995 	break;
6996     }
6997 
6998     return(rv);
6999 }
7000 
7001 /*
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
7005  *
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.
7010  */
7011 char **
get_role_specific_folder(CONF_S ** cl)7012 get_role_specific_folder(CONF_S **cl)
7013 {
7014     CONF_S   *ctmp;
7015 
7016     /* go to the first line */
7017     for(ctmp = *cl;
7018 	ctmp && ctmp->prev;
7019 	ctmp = prev_confline(ctmp))
7020       ;
7021 
7022     /* go to the current folder radio button list */
7023     while(ctmp && ctmp->var != role_fldr_ptr)
7024       ctmp = next_confline(ctmp);
7025 
7026     /* go to the specific folder button (caution) */
7027     while(ctmp && ctmp->varmem != FLDR_SPECIFIC)
7028       ctmp = next_confline(ctmp);
7029 
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;
7038 
7039 	    /*
7040 	     * Need to allocate empty string so as not to confuse it
7041 	     * with the possibility that Specific Folder is not selected.
7042 	     */
7043 	    ltmp    = (char **) fs_get(2 * sizeof(char *));
7044 	    ltmp[0] = cpystr("");
7045 	    ltmp[1] = NULL;
7046 	    return(ltmp);
7047 	}
7048     }
7049     else
7050       return NULL;
7051 }
7052 
7053 
7054 /*
7055  */
7056 int
role_litsig_text_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)7057 role_litsig_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7058 {
7059     int   rv;
7060 
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);
7067 
7068 	break;
7069 
7070       default :
7071 	rv = role_text_tool(ps, cmd, cl, flags);
7072 	break;
7073     }
7074 
7075     return(rv);
7076 }
7077 
7078 
7079 /*
7080  */
7081 int
role_cstm_text_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)7082 role_cstm_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7083 {
7084     int   rv;
7085 
7086     switch(cmd){
7087       case MC_EXIT :
7088 	rv = role_text_tool(ps, cmd, cl, flags);
7089 	break;
7090 
7091       default :
7092 	rv = text_tool(ps, cmd, cl, flags);
7093 	if(rv == 1 && (*cl)->var){
7094 	    char **lval;
7095 
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");
7108 	}
7109 
7110 	break;
7111     }
7112 
7113     return(rv);
7114 }
7115 
7116 
7117 /*
7118  */
7119 int
role_text_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)7120 role_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7121 {
7122     OPT_SCREEN_S *saved_screen;
7123     int   rv = -1, oeflags, len = 0, 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;
7131 
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);
7140 	      }
7141 	      else
7142 		rv = 2;
7143 	      break;
7144 
7145 	    case 'n':
7146 	      q_status_message(SM_ORDER,3,5,_("No changes saved"));
7147 	      rv = 10;
7148 	      break;
7149 
7150 	    case 'x':  /* ^C */
7151 	      q_status_message(SM_ORDER,3,5,_("Changes not yet saved"));
7152 	      rv = 0;
7153 	      break;
7154 	  }
7155 	}
7156 	else
7157 	  rv = 2;
7158 
7159 	break;
7160 
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);
7171 	    }
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);
7176 	    }
7177 
7178 	    rv = 1;
7179 	}
7180 
7181 	break;
7182 
7183       case MC_CHOICE :				/* Choose a file */
7184 	/*
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.
7188 	 */
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;
7194 	}
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);
7199 	}
7200 
7201 	strncpy(title, "CHOOSE A", 15);
7202 	strncpy(dir2, pdir, MAXPATH);
7203 
7204 	filename[0] = '\0';
7205 	build_path(full_filename, dir2, filename, sizeof(full_filename));
7206 
7207 	r = file_lister(title, dir2, sizeof(dir2), filename, sizeof(filename), TRUE, FB_READ);
7208 	ps->mangled_screen = 1;
7209 
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);
7217 
7218 	    apval = APVAL((*cl)->var, ew);
7219 	    if(apval && *apval)
7220 	      fs_give((void **)apval);
7221 
7222 	    if(apval)
7223 	      *apval = newfile;
7224 
7225 	    if((*cl)->value)
7226 	      fs_give((void **)&((*cl)->value));
7227 
7228 	    (*cl)->value = pretty_value(ps, *cl);
7229 	    rv = 1;
7230 	}
7231 	else
7232 	  rv = 0;
7233 
7234 	break;
7235 
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;
7242 
7243 	    i = 0;
7244 	    for(tmp = addr; *tmp; tmp++)
7245 	      if(*tmp == ',')
7246 		i++;	/* conservative count of ,'s */
7247 
7248 	    ltmp = parse_list(addr, i + 1, PL_COMMAQUOTE, NULL);
7249 	    fs_give((void **) &addr);
7250 
7251 	    if(ltmp && ltmp[0])
7252 	      config_add_list(ps, cl, ltmp, NULL, 0);
7253 
7254 	    if(ltmp)
7255 	      fs_give((void **) &ltmp);
7256 
7257 	    if((*cl)->value)
7258 	      fs_give((void **)&((*cl)->value));
7259 
7260 	    (*cl)->value = pretty_value(ps, *cl);
7261 	    rv = 1;
7262 	}
7263 	else
7264 	  rv = 0;
7265 
7266 	break;
7267 
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);
7275 
7276 	    if(apval)
7277 	      *apval = addr;
7278 
7279 	    if((*cl)->value)
7280 	      fs_give((void **)&((*cl)->value));
7281 
7282 	    (*cl)->value = pretty_value(ps, *cl);
7283 	    rv = 1;
7284 	}
7285 	else
7286 	  rv = 0;
7287 
7288 	break;
7289 
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);
7297 
7298 	if(tmpfldr){
7299 	    fldr = add_comma_escapes(tmpfldr);
7300 	    fs_give((void**) &tmpfldr);
7301 	}
7302 
7303 	opt_screen = saved_screen;
7304 
7305 	ps->mangled_screen = 1;
7306 	if(fldr && *fldr && (*cl)->var && (*cl)->var->is_list){
7307 	    char **ltmp;
7308 
7309 	    ltmp    = (char **) fs_get(2 * sizeof(char *));
7310 	    ltmp[0] = fldr;
7311 	    ltmp[1] = NULL;
7312 	    fldr    = NULL;
7313 
7314 	    if(ltmp && ltmp[0])
7315 	      config_add_list(ps, cl, ltmp, NULL, 0);
7316 
7317 	    if(ltmp)
7318 	      fs_give((void **) &ltmp);
7319 
7320 	    if((*cl)->value)
7321 	      fs_give((void **) &((*cl)->value));
7322 
7323 	    (*cl)->value = pretty_value(ps, *cl);
7324 	    rv = 1;
7325 	}
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);
7330 
7331 	    if(apval){
7332 		*apval = fldr;
7333 		fldr   = NULL;
7334 	    }
7335 
7336 	    if((*cl)->value)
7337 	      fs_give((void **) &((*cl)->value));
7338 
7339 	    (*cl)->value = pretty_value(ps, *cl);
7340 	    rv = 1;
7341 	}
7342 	else
7343 	  rv = 0;
7344 
7345 	if(fldr)
7346 	  fs_give((void **) &fldr);
7347 
7348 	break;
7349 
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);
7355 
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';
7362 	}
7363 	else{
7364 	    if(file[len=(strlen(file)-1)] == '|')
7365 	      file[len] = '\0';
7366 
7367 	    snprintf(title, sizeof(title), "%s EDITOR", sig ? "SIGNATURE" : "TEMPLATE");
7368 	    title[sizeof(title)-1] = '\0';
7369 	    err = signature_edit(file, title);
7370 	}
7371 
7372 	fs_give((void **)&file);
7373 	if(err){
7374 	    q_status_message1(SM_ORDER, 3, 5, "%s", err);
7375 	    fs_give((void **)&err);
7376 	}
7377 
7378 	rv = 0;
7379 	ps->mangled_screen = 1;
7380 	break;
7381 
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)
7387 	  ;
7388 
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));
7396 
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;
7410 	    }
7411 	    else if(i == 3){
7412 		help = help == NO_HELP ? h_config_add_pat_hdr : NO_HELP;
7413 		continue;
7414 	    }
7415 	    else
7416 	      break;
7417 	}
7418 
7419 	ps->mangled_footer = 1;
7420 
7421 	removing_leading_and_trailing_white_space(tmp);
7422 	if(tmp[strlen(tmp)-1] == ':')  /* remove trailing colon */
7423 	  tmp[strlen(tmp)-1] = '\0';
7424 
7425 	removing_trailing_white_space(tmp);
7426 
7427 	if(cancel || !tmp[0])
7428 	  break;
7429 
7430 	tmp[0] = islower((unsigned char)tmp[0]) ? toupper((unsigned char)tmp[0])
7431 						: tmp[0];
7432 	ea->a->field = cpystr(tmp);
7433 
7434 	if(earb)
7435 	  earb->next = ea;
7436 	else
7437 	  *((*cl)->d.earb) = ea;
7438 
7439 	/* go to first line */
7440 	for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
7441 	  ;
7442 
7443 	/*
7444 	 * Go to the Add Extra Headers line. We will put the
7445 	 * new header before this line.
7446 	 */
7447 	for(; ctmp; ctmp = next_confline(ctmp))
7448 	  if(ctmp->value && !strcmp(ctmp->value, ADDXHDRS))
7449 	    break;
7450 
7451 	/* move back one */
7452 	if(ctmp)
7453 	  ctmp = prev_confline(ctmp);
7454 
7455 	/*
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.
7459 	 */
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);
7465 
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;
7471 
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);
7475 
7476 	/*
7477 	 * move current line to new line
7478 	 */
7479 
7480 	newcp = ctmp;
7481 
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;
7488 	/*
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.
7493 	 */
7494 
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))
7501 	      ;
7502 	}
7503 
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))
7510 	      ;
7511 
7512 	    opt_screen->top_line = ctmp;
7513 	}
7514 
7515 	*cl = newcp;
7516 
7517 	ps->mangled_screen = 1;
7518 	rv = 1;
7519 	break;
7520 
7521       /* Delete an arbitrary header from this role */
7522       case MC_DELHDR :
7523 	/*
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.
7526 	 */
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;
7535 
7536 	    eaprev = ea;
7537 	}
7538 
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);
7545 	}
7546 
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;
7553 
7554 	    ea->next = NULL;
7555 	    free_earb(&ea);
7556 	}
7557 
7558 	/* remember start of deleted header */
7559 	ctmp = (*cl && (*cl)->varnamep) ? (*cl)->varnamep : NULL;
7560 
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;
7565 
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;
7570 
7571 	    if(ctmpb == (*cl))
7572 	      break;
7573 	}
7574 
7575 	if(ctmpb == opt_screen->top_line)
7576 	  opt_screen->top_line = ctend ? ctend->next : NULL;
7577 
7578 	/* move current line after this header */
7579 	*cl = ctend ? ctend->next : NULL;
7580 
7581 	/* remove deleted header lines */
7582 	if(ctmp && ctend){
7583 	    /* remove from linked list */
7584 	    if(ctmp->prev)
7585 	      ctmp->prev->next = ctend->next;
7586 
7587 	    if(ctend->next)
7588 	      ctend->next->prev = ctmp->prev;
7589 
7590 	    /* free memory */
7591 	    ctmp->prev = ctend->next = NULL;
7592 	    free_conflines(&ctmp);
7593 	}
7594 
7595 	ps->mangled_body = 1;
7596 	rv = 1;
7597 	break;
7598 
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)
7604 	   &&
7605 	   (cmd == MC_EDIT || (cmd == MC_ADD && !PVAL((*cl)->var, ew)))){
7606 	    char prompt[60];
7607 
7608 	    rv = 0;
7609 	    snprintf(prompt, sizeof(prompt), "%s the interval : ",
7610 		    PVAL((*cl)->var, ew) ? "Change" : "Enter");
7611 	    prompt[sizeof(prompt)-1] = '\0';
7612 
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);
7628 
7629 		    if(apval && tmp[0])
7630 		      *apval = cpystr(tmp);
7631 
7632 		    fix_side_effects(ps, (*cl)->var, 0);
7633 		    if((*cl)->value)
7634 		      fs_give((void **)&(*cl)->value);
7635 
7636 		    (*cl)->value = pretty_value(ps, *cl);
7637 		}
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;
7643 		}
7644 		else if(i == 4)
7645 		  continue;
7646 
7647 		break;
7648 	    }
7649 	}
7650 	else{
7651 	    if(cmd == MC_ADD && (*cl)->var && !(*cl)->var->is_list)
7652 	      cmd = MC_EDIT;
7653 
7654 	    rv = text_toolit(ps, cmd, cl, flags, 1);
7655 
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;
7661 	}
7662 
7663 	break;
7664     }
7665 
7666     /*
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.
7670      */
7671     if(rv)
7672       calculate_inick_stuff(ps);
7673 
7674     return(rv);
7675 }
7676 
7677 
7678 /*
7679  */
7680 int
role_text_tool_inick(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)7681 role_text_tool_inick(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7682 {
7683     int   rv = -1;
7684     char **apval;
7685 
7686     switch(cmd){
7687       case MC_EXIT :
7688 	rv = role_text_tool(ps, cmd, cl, flags);
7689 	break;
7690 
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;
7696 
7697 	ps->redrawer = NULL;
7698 	ps->next_screen = SCREEN_FUN_NULL;
7699 
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);
7705 
7706 	    if(apval)
7707 	      *apval = (role && role->nick) ? cpystr(role->nick) : NULL;
7708 
7709 	    if((*cl)->value)
7710 	      fs_give((void **)&((*cl)->value));
7711 
7712 	    (*cl)->value = pretty_value(ps, *cl);
7713 	    rv = 1;
7714 	}
7715 	else{
7716 	    ps->next_screen = prev_screen;
7717 	    ps->redrawer = redraw;
7718 	    rv = 0;
7719 	}
7720 
7721 	opt_screen = saved_screen;
7722 	}
7723 
7724 	ps->mangled_screen = 1;
7725 	break;
7726 
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;
7733 
7734       default :
7735 	rv = text_tool(ps, cmd, cl, flags);
7736 	break;
7737     }
7738 
7739     /*
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.
7743      */
7744     if(rv)
7745       calculate_inick_stuff(ps);
7746 
7747     return(rv);
7748 }
7749 
7750 
7751 /*
7752  */
7753 int
role_text_tool_kword(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)7754 role_text_tool_kword(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7755 {
7756     int    i, j, rv = -1;
7757     char **lval;
7758 
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;
7766 
7767 	ps->redrawer = NULL;
7768 	ps->next_screen = SCREEN_FUN_NULL;
7769 
7770 	saved_screen = opt_screen;
7771 
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;
7777 	    }
7778 
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;
7787 
7788 		    if(lval[j]){		/* it is a dup */
7789 			for(j = i; kw[j]; j++)
7790 			  kw[j] = kw[j+1];
7791 		    }
7792 		    else
7793 		      i++;
7794 		}
7795 	    }
7796 
7797 	    if(kw[0])
7798 	      config_add_list(ps, cl, kw, NULL, 0);
7799 
7800 	    fs_give((void **) &kw);
7801 
7802 	    if((*cl)->value)
7803 	      fs_give((void **) &((*cl)->value));
7804 
7805 	    (*cl)->value = pretty_value(ps, *cl);
7806 	    rv = 1;
7807 	}
7808 	else{
7809 	    ps->next_screen = prev_screen;
7810 	    ps->redrawer = redraw;
7811 	    rv = 0;
7812 	}
7813 
7814 	opt_screen = saved_screen;
7815 	}
7816 
7817 	ps->mangled_screen = 1;
7818 	break;
7819 
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;
7827 
7828       case MC_EXIT :
7829       default :
7830 	rv = role_text_tool(ps, cmd, cl, flags);
7831 	break;
7832     }
7833 
7834     return(rv);
7835 }
7836 
7837 
7838 /*
7839  */
7840 int
role_text_tool_charset(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)7841 role_text_tool_charset(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7842 {
7843     int    i, j, rv = -1;
7844     char **lval;
7845 
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;
7853 
7854 	ps->redrawer = NULL;
7855 	ps->next_screen = SCREEN_FUN_NULL;
7856 
7857 	saved_screen = opt_screen;
7858 
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;
7864 	    }
7865 
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;
7874 
7875 		    if(lval[j]){		/* it is a dup */
7876 			for(j = i; kw[j]; j++)
7877 			  kw[j] = kw[j+1];
7878 		    }
7879 		    else
7880 		      i++;
7881 		}
7882 	    }
7883 
7884 	    if(kw[0])
7885 	      config_add_list(ps, cl, kw, NULL, 0);
7886 
7887 	    fs_give((void **) &kw);
7888 
7889 	    if((*cl)->value)
7890 	      fs_give((void **) &((*cl)->value));
7891 
7892 	    (*cl)->value = pretty_value(ps, *cl);
7893 	    rv = 1;
7894 	}
7895 	else{
7896 	    ps->next_screen = prev_screen;
7897 	    ps->redrawer = redraw;
7898 	    rv = 0;
7899 	}
7900 
7901 	opt_screen = saved_screen;
7902 	}
7903 
7904 	ps->mangled_screen = 1;
7905 	break;
7906 
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;
7914 
7915       case MC_EXIT :
7916       default :
7917 	rv = role_text_tool(ps, cmd, cl, flags);
7918 	break;
7919     }
7920 
7921     return(rv);
7922 }
7923 
7924 
7925 /*
7926  * Choose an address book nickname
7927  */
7928 int
role_text_tool_afrom(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)7929 role_text_tool_afrom(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
7930 {
7931     int   rv = -1;
7932 
7933     switch(cmd){
7934       case MC_EXIT :
7935 	rv = role_text_tool(ps, cmd, cl, flags);
7936 	break;
7937 
7938       case MC_CHOICE :		/* Choose an addressbook */
7939 	{OPT_SCREEN_S *saved_screen;
7940 	 char *abook = NULL, *abookesc = NULL;
7941 
7942 	ps->redrawer = NULL;
7943 	ps->next_screen = SCREEN_FUN_NULL;
7944 	saved_screen = opt_screen;
7945 
7946 	abook = abook_select_screen(ps);
7947 	if(abook){
7948 	    abookesc = add_comma_escapes(abook);
7949 	    fs_give((void**) &abook);
7950 	}
7951 
7952 	ps->mangled_screen = 1;
7953 	if(abookesc && *abookesc && (*cl)->var && (*cl)->var->is_list){
7954 	    char **ltmp;
7955 
7956 	    ltmp     = (char **) fs_get(2 * sizeof(char *));
7957 	    ltmp[0]  = abookesc;
7958 	    ltmp[1]  = NULL;
7959 	    abookesc = NULL;
7960 
7961 	    if(ltmp && ltmp[0])
7962 	      config_add_list(ps, cl, ltmp, NULL, 0);
7963 
7964 	    if(ltmp)
7965 	      fs_give((void **) &ltmp);
7966 
7967 	    if((*cl)->value)
7968 	      fs_give((void **) &((*cl)->value));
7969 
7970 	    (*cl)->value = pretty_value(ps, *cl);
7971 	    rv = 1;
7972 	}
7973 	else
7974 	  rv = 0;
7975 
7976 	if(abookesc)
7977 	  fs_give((void **) &abookesc);
7978 
7979 	opt_screen = saved_screen;
7980 	}
7981 
7982 	ps->mangled_screen = 1;
7983 	break;
7984 
7985       default :
7986 	rv = text_tool(ps, cmd, cl, flags);
7987 	ps->mangled_screen = 1;
7988 	break;
7989     }
7990 
7991     return(rv);
7992 }
7993 
7994 
7995 /*
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
7999  *
8000  * Returns -- pointer to buf
8001  */
8002 char *
role_type_print(char * buf,size_t buflen,char * fmt,long int rflags)8003 role_type_print(char *buf, size_t buflen, char *fmt, long int rflags)
8004 {
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;
8011 
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;
8019 	}
8020 	else
8021 	  cas = CASE_LOWER;
8022 
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++;
8028     }
8029 
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 " : "";
8051 
8052     /* it ain't right to say "a index" */
8053     if(prev_word_is_a && !struncmp(q, "index", 5))
8054       q += 6;
8055 
8056     snprintf(buf, buflen, fmt, q);
8057     buf[buflen-1] = '\0';
8058     return(buf);
8059 }
8060 
8061 
8062 /*
8063  * filter option list manipulation tool
8064  *
8065  *
8066  * returns:  -1 on unrecognized cmd, 0 if no change, 1 if change
8067  */
8068 int
feat_checkbox_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)8069 feat_checkbox_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
8070 {
8071     int  rv = 0;
8072 
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;
8078 
8079       case MC_EXIT:				 /* exit */
8080         rv = role_filt_exitcheck(cl, flags);
8081 	break;
8082 
8083       default :
8084 	rv = -1;
8085 	break;
8086     }
8087 
8088     return(rv);
8089 }
8090 
8091 
8092 void
toggle_feat_option_bit(struct pine * ps,int index,struct variable * var,char * value)8093 toggle_feat_option_bit(struct pine *ps, int index, struct variable *var, char *value)
8094 {
8095     NAMEVAL_S  *f;
8096 
8097     f  = feat_feature_list(index);
8098 
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);
8104 
8105     if(value)
8106       value[1] = bitnset(f->value, feat_option_list) ? 'X' : ' ';
8107 }
8108 
8109 
8110 NAMEVAL_S *
feat_feature_list(int index)8111 feat_feature_list(int index)
8112 {
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}
8117     };
8118 
8119     return((index >= 0 &&
8120 	    index < (sizeof(opt_feat_list)/sizeof(opt_feat_list[0])))
8121 		   ? &opt_feat_list[index] : NULL);
8122 }
8123 
8124 
8125 /*
8126  * address type list manipulation tool
8127  *
8128  *
8129  * returns:  -1 on unrecognized cmd, 0 if no change, 1 if change
8130  */
8131 int
inabook_checkbox_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)8132 inabook_checkbox_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
8133 {
8134     int  rv = 0;
8135 
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;
8141 
8142       case MC_EXIT:				 /* exit */
8143         rv = role_filt_exitcheck(cl, flags);
8144 	break;
8145 
8146       default :
8147 	rv = -1;
8148 	break;
8149     }
8150 
8151     return(rv);
8152 }
8153 
8154 
8155 void
toggle_inabook_type_bit(struct pine * ps,int index,struct variable * var,char * value)8156 toggle_inabook_type_bit(struct pine *ps, int index, struct variable *var, char *value)
8157 {
8158     NAMEVAL_S  *f;
8159 
8160     f  = inabook_feature_list(index);
8161 
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);
8167 
8168     if(value)
8169       value[1] = bitnset(f->value, inabook_type_list) ? 'X' : ' ';
8170 }
8171 
8172 
8173 NAMEVAL_S *
inabook_feature_list(int index)8174 inabook_feature_list(int index)
8175 {
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}
8182     };
8183 
8184     return((index >= 0 &&
8185 	    index < (sizeof(inabook_feat_list)/sizeof(inabook_feat_list[0])))
8186 		   ? &inabook_feat_list[index] : NULL);
8187 }
8188