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 **) <mp);
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 **) <mp);
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 **) <mp);
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