* New version 2.19.999
[alpine.git] / alpine / confscroll.c
blob7164820291cb17f2575f911679333e54b893c5ae
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: confscroll.c 1169 2008-08-27 06:42:06Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2006-2008 University of Washington
8 * Copyright 2013-2014 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
19 #include "headers.h"
20 #include "confscroll.h"
21 #include "keymenu.h"
22 #include "status.h"
23 #include "titlebar.h"
24 #include "help.h"
25 #include "radio.h"
26 #include "print.h"
27 #include "ldapconf.h"
28 #include "roleconf.h"
29 #include "colorconf.h"
30 #include "mailview.h"
31 #include "mailcmd.h"
32 #include "mailindx.h"
33 #include "talk.h"
34 #include "setup.h"
35 #include "smime.h"
36 #include "../pith/state.h"
37 #include "../pith/flag.h"
38 #include "../pith/list.h"
39 #include "../pith/conf.h"
40 #include "../pith/util.h"
41 #include "../pith/newmail.h"
42 #include "../pith/sort.h"
43 #include "../pith/thread.h"
44 #include "../pith/color.h"
45 #include "../pith/hist.h"
46 #include "../pith/icache.h"
47 #include "../pith/conf.h"
48 #include "../pith/init.h"
49 #include "../pith/folder.h"
50 #include "../pith/busy.h"
51 #include "../pith/tempfile.h"
52 #include "../pith/pattern.h"
53 #include "../pith/charconv/utf8.h"
56 #define CONFIG_SCREEN_HELP_TITLE _("HELP FOR SETUP CONFIGURATION")
58 /* TRANSLATORS: Empty Value is what is shown in the configuration
59 screen when the user not only does not set an option but also
60 wants to explicitly not use the default value. Empty value means
61 an option with no value. */
62 char *empty_val = N_("Empty Value");
63 char *empty_val2 = N_("<Empty Value>");
64 /* TRANSLATORS: No Value set is similar to Empty Value, but the
65 user has not explicitly decided to not use the default. It is
66 just an option which the user has left at the default value. */
67 char *no_val = N_("No Value Set");
68 /* TRANSLATORS: Value is Fixed is what is displayed in the config
69 screen when the system managers have set an option to a specific
70 value and they don't allow the user to change it. The value
71 is fixed to a certain value. This isn't the same word as
72 Repaired, it means Unchanging. */
73 char *fixed_val = N_("Value is Fixed");
74 char yesstr[] = "Yes";
75 char nostr[] = "No";
78 EditWhich ew = Main;
81 OPT_SCREEN_S *opt_screen;
85 * This is pretty ugly. Some of the routines operate differently depending
86 * on which variable they are operating on. Sometimes those variables are
87 * global (real alpine.h V_ style variables) and sometimes they are just
88 * local variables (as in role_config_edit_screen). These pointers are here
89 * so that the routines can figure out which variable they are operating
90 * on and do the right thing.
92 struct variable *score_act_global_ptr,
93 *scorei_pat_global_ptr,
94 *age_pat_global_ptr,
95 *size_pat_global_ptr,
96 *cati_global_ptr,
97 *cat_cmd_global_ptr,
98 *cat_lim_global_ptr,
99 *startup_ptr,
100 *role_comment_ptr,
101 *role_forw_ptr,
102 *role_repl_ptr,
103 *role_fldr_ptr,
104 *role_afrom_ptr,
105 *role_filt_ptr,
106 *role_status1_ptr,
107 *role_status2_ptr,
108 *role_status3_ptr,
109 *role_status4_ptr,
110 *role_status5_ptr,
111 *role_status6_ptr,
112 *role_status7_ptr,
113 *role_status8_ptr,
114 *msg_state1_ptr,
115 *msg_state2_ptr,
116 *msg_state3_ptr,
117 *msg_state4_ptr;
120 typedef NAMEVAL_S *(*PTR_TO_RULEFUNC)(int);
124 * Internal prototypes
126 PTR_TO_RULEFUNC rulefunc_from_var(struct pine *, struct variable *);
127 void set_radio_pretty_vals(struct pine *, CONF_S **);
128 int save_include(struct pine *, struct variable *, int);
129 void config_scroll_up(long);
130 void config_scroll_down(long);
131 void config_scroll_to_pos(long);
132 CONF_S *config_top_scroll(struct pine *, CONF_S *);
133 void update_option_screen(struct pine *, OPT_SCREEN_S *, Pos *);
134 void print_option_screen(OPT_SCREEN_S *, char *);
135 void option_screen_redrawer(void);
136 char *text_pretty_value(struct pine *, CONF_S *);
137 char *checkbox_pretty_value(struct pine *, CONF_S *);
138 char *yesno_pretty_value(struct pine *, CONF_S *);
139 char *radio_pretty_value(struct pine *, CONF_S *);
140 char *sigfile_pretty_value(struct pine *, CONF_S *);
141 char *color_pretty_value(struct pine *, CONF_S *);
142 char *sort_pretty_value(struct pine *, CONF_S *);
143 int longest_feature_name(void);
144 COLOR_PAIR *sample_color(struct pine *, struct variable *);
145 COLOR_PAIR *sampleexc_color(struct pine *, struct variable *);
146 void clear_feature(char ***, char *);
147 CONF_S *last_confline(CONF_S *);
148 #ifdef _WINDOWS
149 int config_scroll_callback(int, long);
150 #endif
154 * We test for this same set of vars in a few places.
157 standard_radio_var(struct pine *ps, struct variable *v)
159 return(v == &ps->vars[V_SAVED_MSG_NAME_RULE] ||
160 v == &ps->vars[V_FCC_RULE] ||
161 v == &ps->vars[V_GOTO_DEFAULT_RULE] ||
162 v == &ps->vars[V_INCOMING_STARTUP] ||
163 v == &ps->vars[V_PRUNING_RULE] ||
164 v == &ps->vars[V_REOPEN_RULE] ||
165 v == &ps->vars[V_THREAD_DISP_STYLE] ||
166 v == &ps->vars[V_THREAD_INDEX_STYLE] ||
167 v == &ps->vars[V_FLD_SORT_RULE] ||
168 #ifndef _WINDOWS
169 v == &ps->vars[V_COLOR_STYLE] ||
170 #endif
171 v == &ps->vars[V_INDEX_COLOR_STYLE] ||
172 v == &ps->vars[V_TITLEBAR_COLOR_STYLE] ||
173 v == &ps->vars[V_AB_SORT_RULE]);
177 PTR_TO_RULEFUNC
178 rulefunc_from_var(struct pine *ps, struct variable *v)
180 PTR_TO_RULEFUNC rulefunc = NULL;
182 if(v == &ps->vars[V_SAVED_MSG_NAME_RULE])
183 rulefunc = save_msg_rules;
184 else if(v == &ps->vars[V_FCC_RULE])
185 rulefunc = fcc_rules;
186 else if(v == &ps->vars[V_GOTO_DEFAULT_RULE])
187 rulefunc = goto_rules;
188 else if(v == &ps->vars[V_INCOMING_STARTUP])
189 rulefunc = incoming_startup_rules;
190 else if(v == startup_ptr)
191 rulefunc = startup_rules;
192 else if(v == &ps->vars[V_PRUNING_RULE])
193 rulefunc = pruning_rules;
194 else if(v == &ps->vars[V_REOPEN_RULE])
195 rulefunc = reopen_rules;
196 else if(v == &ps->vars[V_THREAD_DISP_STYLE])
197 rulefunc = thread_disp_styles;
198 else if(v == &ps->vars[V_THREAD_INDEX_STYLE])
199 rulefunc = thread_index_styles;
200 else if(v == &ps->vars[V_FLD_SORT_RULE])
201 rulefunc = fld_sort_rules;
202 else if(v == &ps->vars[V_AB_SORT_RULE])
203 rulefunc = ab_sort_rules;
204 else if(v == &ps->vars[V_INDEX_COLOR_STYLE])
205 rulefunc = index_col_style;
206 else if(v == &ps->vars[V_TITLEBAR_COLOR_STYLE])
207 rulefunc = titlebar_col_style;
208 #ifndef _WINDOWS
209 else if(v == &ps->vars[V_COLOR_STYLE])
210 rulefunc = col_style;
211 #endif
213 return(rulefunc);
217 void
218 standard_radio_setup(struct pine *ps, CONF_S **cl, struct variable *v, CONF_S **first_line)
220 int i, rindent = 12;
221 CONF_S *ctmpb;
222 PTR_TO_RULEFUNC rulefunc;
223 NAMEVAL_S *f;
224 char b[100];
226 if(!(cl && *cl))
227 return;
229 rulefunc = rulefunc_from_var(ps, v);
230 ctmpb = (*cl);
232 (*cl)->flags |= CF_NOSELECT;
233 (*cl)->keymenu = &config_radiobutton_keymenu;
234 (*cl)->tool = NULL;
236 /* put a nice delimiter before list */
237 new_confline(cl)->var = NULL;
238 (*cl)->varnamep = ctmpb;
239 (*cl)->keymenu = &config_radiobutton_keymenu;
240 (*cl)->help = NO_HELP;
241 (*cl)->tool = radiobutton_tool;
242 (*cl)->valoffset = rindent;
243 (*cl)->flags |= CF_NOSELECT;
244 /* TRANSLATORS: Set and Rule Values are the headings for an option
245 that can take one of several values. Underneath the Set heading
246 will be a column where one possibility is turned on (is Set).
247 The other column will be very short descriptions of what
248 the possibilities are (the Rule Values). */
249 utf8_snprintf(b, sizeof(b), "%-5.5w %s", _("Set"), _("Rule Values"));
250 (*cl)->value = cpystr(b);
252 new_confline(cl)->var = NULL;
253 (*cl)->varnamep = ctmpb;
254 (*cl)->keymenu = &config_radiobutton_keymenu;
255 (*cl)->help = NO_HELP;
256 (*cl)->tool = radiobutton_tool;
257 (*cl)->valoffset = rindent;
258 (*cl)->flags |= CF_NOSELECT;
259 (*cl)->value = cpystr("--- ----------------------");
261 if(rulefunc)
262 for(i = 0; (f = (*rulefunc)(i)); i++){
263 new_confline(cl)->var = v;
264 if(first_line && !*first_line && !pico_usingcolor())
265 *first_line = (*cl);
267 (*cl)->varnamep = ctmpb;
268 (*cl)->keymenu = &config_radiobutton_keymenu;
269 (*cl)->help = (v == startup_ptr)
270 ? h_config_other_startup
271 : config_help(v - ps->vars,0);
272 (*cl)->tool = radiobutton_tool;
273 (*cl)->valoffset = rindent;
274 (*cl)->varmem = i;
275 (*cl)->value = pretty_value(ps, *cl);
281 * Reset the displayed values for all of the lines for this
282 * variable because others besides this line may change.
284 void
285 set_radio_pretty_vals(struct pine *ps, CONF_S **cl)
287 CONF_S *ctmp;
289 if(!(cl && *cl &&
290 ((*cl)->var == &ps->vars[V_SORT_KEY] ||
291 standard_radio_var(ps, (*cl)->var) ||
292 (*cl)->var == startup_ptr)))
293 return;
295 /* hunt backwards */
296 for(ctmp = *cl;
297 ctmp && !(ctmp->flags & CF_NOSELECT) && !ctmp->varname;
298 ctmp = prev_confline(ctmp)){
299 if(ctmp->value)
300 fs_give((void **)&ctmp->value);
302 ctmp->value = pretty_value(ps, ctmp);
305 /* hunt forwards */
306 for(ctmp = *cl;
307 ctmp && !ctmp->varname && !(ctmp->flags & CF_NOSELECT);
308 ctmp = next_confline(ctmp)){
309 if(ctmp->value)
310 fs_give((void **)&ctmp->value);
312 ctmp->value = pretty_value(ps, ctmp);
318 * test whether or not a var is
320 * returns: 1 if it should be excluded, 0 otw
323 exclude_config_var(struct pine *ps, struct variable *var, int allow_hard_to_config_remotely)
325 if((ew != Main && (var->is_onlymain)) ||
326 (ew != ps_global->ew_for_except_vars && var->is_outermost))
327 return(1);
329 if(allow_hard_to_config_remotely)
330 return(!(var->is_user && var->is_used && !var->is_obsolete));
332 switch(var - ps->vars){
333 case V_MAIL_DIRECTORY :
334 case V_INCOMING_FOLDERS :
335 case V_FOLDER_SPEC :
336 case V_NEWS_SPEC :
337 case V_STANDARD_PRINTER :
338 case V_LAST_TIME_PRUNE_QUESTION :
339 case V_LAST_VERS_USED :
340 case V_ADDRESSBOOK :
341 case V_GLOB_ADDRBOOK :
342 case V_DISABLE_DRIVERS :
343 case V_DISABLE_AUTHS :
344 case V_REMOTE_ABOOK_METADATA :
345 case V_REMOTE_ABOOK_HISTORY :
346 case V_REMOTE_ABOOK_VALIDITY :
347 case V_OPER_DIR :
348 case V_USERINPUTTIMEO :
349 case V_TCPOPENTIMEO :
350 case V_TCPREADWARNTIMEO :
351 case V_TCPWRITEWARNTIMEO :
352 case V_TCPQUERYTIMEO :
353 case V_RSHCMD :
354 case V_RSHPATH :
355 case V_RSHOPENTIMEO :
356 case V_SSHCMD :
357 case V_SSHPATH :
358 case V_SSHOPENTIMEO :
359 case V_SENDMAIL_PATH :
360 case V_NEW_VER_QUELL :
361 case V_PATTERNS :
362 case V_PAT_ROLES :
363 case V_PAT_FILTS :
364 case V_PAT_SCORES :
365 case V_PAT_INCOLS :
366 case V_PAT_OTHER :
367 case V_PAT_SRCH :
368 case V_PRINTER :
369 case V_PERSONAL_PRINT_COMMAND :
370 case V_PERSONAL_PRINT_CATEGORY :
371 case V_RSS_NEWS :
372 case V_RSS_WEATHER :
373 case V_WP_INDEXHEIGHT :
374 case V_WP_INDEXLINES :
375 case V_WP_AGGSTATE :
376 case V_WP_STATE :
377 case V_WP_COLUMNS :
378 #ifndef _WINDOWS
379 case V_OLD_CHAR_SET :
380 #endif /* ! _WINDOWS */
381 #if defined(DOS) || defined(OS2)
382 case V_UPLOAD_CMD :
383 case V_UPLOAD_CMD_PREFIX :
384 case V_DOWNLOAD_CMD :
385 case V_DOWNLOAD_CMD_PREFIX :
386 #ifdef _WINDOWS
387 case V_FONT_NAME :
388 case V_FONT_SIZE :
389 case V_FONT_STYLE :
390 case V_FONT_CHAR_SET :
391 case V_PRINT_FONT_NAME :
392 case V_PRINT_FONT_SIZE :
393 case V_PRINT_FONT_STYLE :
394 case V_PRINT_FONT_CHAR_SET :
395 case V_WINDOW_POSITION :
396 case V_CURSOR_STYLE :
397 #endif /* _WINDOWS */
398 #endif /* DOS */
399 #ifdef ENABLE_LDAP
400 case V_LDAP_SERVERS :
401 #endif /* ENABLE_LDAP */
402 return(1);
404 default:
405 break;
408 return(!(var->is_user && var->is_used && !var->is_obsolete &&
409 #ifdef SMIME
410 !smime_related_var(ps, var) &&
411 #endif /* SMIME */
412 !color_related_var(ps, var)));
417 * Test to indicate what should be saved in case user wants to abandon
418 * changes.
421 save_include(struct pine *ps, struct variable *v, int allow_hard_to_config_remotely)
423 return(!exclude_config_var(ps, v, allow_hard_to_config_remotely)
424 || (v->is_user
425 && v->is_used
426 && !v->is_obsolete
427 && (v == &ps->vars[V_PERSONAL_PRINT_COMMAND]
428 #ifdef ENABLE_LDAP
429 || v == &ps->vars[V_LDAP_SERVERS]
430 #endif
431 )));
436 * Handles screen painting and motion. Passes other commands to
437 * custom tools.
439 * Tool return values: Tools should return the following:
440 * 0 nothing changed
441 * -1 unrecognized command
442 * 1 something changed, conf_scroll_screen should remember that
443 * 2 tells conf_scroll_screen to return with value 1 or 0 depending
444 * on whether or not it has previously gotten a 1 from some tool.
445 * 3 tells conf_scroll_screen to return 1 (like 1 and 2 combined)
446 * ? Other tool-specific values can be used. They will cause
447 * conf_scroll_screen to return that value.
449 * Return values:
450 * 0 if nothing happened. That is, a tool returned 2 and we hadn't
451 * previously noted a return of 1
452 * 1 if something happened. That is, a tool returned 2 and we had
453 * previously noted a return of 1
454 * ? Tool-returned value different from -1, 0, 1, 2, or 3. This is it.
456 * Special proviso: If first_line->flags has CF_CHANGES set on entry, then
457 * that will cause things to behave like a change was made since entering
458 * this function.
461 conf_scroll_screen(struct pine *ps, OPT_SCREEN_S *screen, CONF_S *start_line, char *title, char *pdesc, int multicol)
463 char tmp[MAXPATH+1];
464 char *utf8str;
465 UCS ch = 'x';
466 int cmd, i, j, done = 0, changes = 0;
467 int retval = 0;
468 int km_popped = 0, stay_in_col = 0;
469 struct key_menu *km = NULL;
470 CONF_S *ctmpa = NULL, *ctmpb = NULL;
471 Pos cursor_pos;
472 OtherMenu what_keymenu = FirstMenu;
473 void (*prev_redrawer)(void);
475 dprint((7, "conf_scroll_screen()\n"));
477 if(BODY_LINES(ps) < 1){
478 q_status_message(SM_ORDER | SM_DING, 3, 3, _("Screen too small"));
479 return(0);
482 if(screen && screen->ro_warning)
483 q_status_message1(SM_ORDER, 1, 3,
484 /* TRANSLATORS: "Config file not changeable," is what replaces the %s */
485 _("%s can't change options or settings"),
486 ps_global->restricted ? "Alpine demo"
487 : _("Config file not changeable,"));
489 screen->current = start_line;
490 if(start_line && start_line->flags & CF_CHANGES)
491 changes++;
493 opt_screen = screen;
494 ps->mangled_screen = 1;
495 ps->redrawer = option_screen_redrawer;
497 while(!done){
498 ps->user_says_cancel = 0;
499 if(km_popped){
500 km_popped--;
501 if(km_popped == 0){
502 clearfooter(ps);
503 ps->mangled_body = 1;
507 if(ps->mangled_screen){
508 ps->mangled_header = 1;
509 ps->mangled_footer = 1;
510 ps->mangled_body = 1;
511 ps->mangled_screen = 0;
514 /*----------- Check for new mail -----------*/
515 if(new_mail(0, NM_TIMING(ch), NM_STATUS_MSG | NM_DEFER_SORT) >= 0)
516 ps->mangled_header = 1;
518 if(ps->mangled_header){
519 set_titlebar(title, ps->mail_stream,
520 ps->context_current,
521 ps->cur_folder, ps->msgmap, 1, FolderName, 0, 0, NULL);
522 ps->mangled_header = 0;
525 update_option_screen(ps, screen, &cursor_pos);
527 if(F_OFF(F_SHOW_CURSOR, ps)){
528 cursor_pos.row = ps->ttyo->screen_rows - FOOTER_ROWS(ps);
529 cursor_pos.col = 0;
532 /*---- This displays new mail notification, or errors ---*/
533 if(km_popped){
534 FOOTER_ROWS(ps) = 3;
535 mark_status_unknown();
538 display_message(ch);
539 if(km_popped){
540 FOOTER_ROWS(ps) = 1;
541 mark_status_unknown();
544 if(ps->mangled_footer || km != screen->current->keymenu){
545 bitmap_t bitmap;
547 setbitmap(bitmap);
549 ps->mangled_footer = 0;
550 km = screen->current->keymenu;
552 if(multicol &&
553 (F_OFF(F_ARROW_NAV, ps_global) ||
554 F_ON(F_RELAXED_ARROW_NAV, ps_global))){
555 menu_clear_binding(km, KEY_LEFT);
556 menu_clear_binding(km, KEY_RIGHT);
557 menu_clear_binding(km, KEY_UP);
558 menu_clear_binding(km, KEY_DOWN);
559 menu_add_binding(km, KEY_UP, MC_CHARUP);
560 menu_add_binding(km, KEY_DOWN, MC_CHARDOWN);
561 menu_add_binding(km, KEY_LEFT, MC_PREVITEM);
562 menu_add_binding(km, ctrl('B'), MC_PREVITEM);
563 menu_add_binding(km, KEY_RIGHT, MC_NEXTITEM);
564 menu_add_binding(km, ctrl('F'), MC_NEXTITEM);
566 else{
567 menu_clear_binding(km, KEY_LEFT);
568 menu_clear_binding(km, KEY_RIGHT);
569 menu_clear_binding(km, KEY_UP);
570 menu_clear_binding(km, KEY_DOWN);
573 * Fix up arrow nav mode if necessary...
575 if(F_ON(F_ARROW_NAV, ps_global)){
576 int cmd;
578 if((cmd = menu_clear_binding(km, '<')) != MC_UNKNOWN){
579 menu_add_binding(km, '<', cmd);
580 menu_add_binding(km, KEY_LEFT, cmd);
583 if((cmd = menu_clear_binding(km, '>')) != MC_UNKNOWN){
584 menu_add_binding(km, '>', cmd);
585 menu_add_binding(km, KEY_RIGHT, cmd);
588 if((cmd = menu_clear_binding(km, 'p')) != MC_UNKNOWN){
589 menu_add_binding(km, 'p', cmd);
590 menu_add_binding(km, KEY_UP, cmd);
593 if((cmd = menu_clear_binding(km, 'n')) != MC_UNKNOWN){
594 menu_add_binding(km, 'n', cmd);
595 menu_add_binding(km, KEY_DOWN, cmd);
600 if(km_popped){
601 FOOTER_ROWS(ps) = 3;
602 clearfooter(ps);
605 draw_keymenu(km, bitmap, ps->ttyo->screen_cols,
606 1-FOOTER_ROWS(ps), 0, what_keymenu);
607 what_keymenu = SameMenu;
609 if(km_popped){
610 FOOTER_ROWS(ps) = 1;
611 mark_keymenu_dirty();
615 MoveCursor(cursor_pos.row, cursor_pos.col);
616 #ifdef MOUSE
617 mouse_in_content(KEY_MOUSE, -1, -1, 0, 0); /* prime the handler */
618 register_mfunc(mouse_in_content, HEADER_ROWS(ps_global), 0,
619 ps_global->ttyo->screen_rows -(FOOTER_ROWS(ps_global)+1),
620 ps_global->ttyo->screen_cols);
621 #endif
622 #ifdef _WINDOWS
623 mswin_setscrollcallback(config_scroll_callback);
624 #endif
625 /*------ Read the command from the keyboard ----*/
626 ch = READ_COMMAND(&utf8str);
627 #ifdef MOUSE
628 clear_mfunc(mouse_in_content);
629 #endif
630 #ifdef _WINDOWS
631 mswin_setscrollcallback(NULL);
632 #endif
634 cmd = menu_command(ch, km);
636 if(km_popped)
637 switch(cmd){
638 case MC_NONE:
639 case MC_OTHER:
640 case MC_RESIZE:
641 case MC_REPAINT:
642 km_popped++;
643 break;
645 default:
646 clearfooter(ps);
647 break;
650 switch(cmd){
651 case MC_OTHER :
652 what_keymenu = NextMenu;
653 ps->mangled_footer = 1;
654 break;
656 case MC_HELP: /* help! */
657 if(FOOTER_ROWS(ps) == 1 && km_popped == 0){
658 km_popped = 2;
659 ps->mangled_footer = 1;
660 break;
663 if(screen->current->help != NO_HELP){
664 prev_redrawer = ps_global->redrawer;
665 helper(screen->current->help,
666 (screen->current->help_title)
667 ? screen->current->help_title
668 : CONFIG_SCREEN_HELP_TITLE,
669 HLPD_SIMPLE);
670 ps_global->redrawer = prev_redrawer;
671 ps->mangled_screen = 1;
673 else
674 q_status_message(SM_ORDER,0,3,_("No help yet."));
676 break;
679 case MC_NEXTITEM: /* next list element */
680 case MC_CHARDOWN:
681 stay_in_col = 0;
682 if(screen->current->flags & CF_DOUBLEVAR){
683 /* if going from col1 to col2, it's simple */
684 if(!(screen->current->flags & CF_VAR2) && cmd == MC_NEXTITEM){
685 screen->current->flags |= CF_VAR2;
686 break;
689 /* otherwise we fall through to normal next */
690 stay_in_col = (screen->current->flags & CF_VAR2 &&
691 cmd == MC_CHARDOWN);
692 screen->current->flags &= ~CF_VAR2;
695 for(ctmpa = next_confline(screen->current), i = 1;
696 ctmpa && (ctmpa->flags & CF_NOSELECT);
697 ctmpa = next_confline(ctmpa), i++)
700 if(ctmpa){
701 screen->current = ctmpa;
702 if(screen->current->flags & CF_DOUBLEVAR && stay_in_col)
703 screen->current->flags |= CF_VAR2;
705 if(cmd == MC_CHARDOWN){
706 for(ctmpa = screen->top_line,
707 j = BODY_LINES(ps) - 1 - HS_MARGIN(ps);
708 j > 0 && ctmpa && ctmpa != screen->current;
709 ctmpa = next_confline(ctmpa), j--)
712 if(!j && ctmpa){
713 for(i = 0;
714 ctmpa && ctmpa != screen->current;
715 ctmpa = next_confline(ctmpa), i++)
718 if(i)
719 config_scroll_up(i);
723 else{
725 * Scroll screen a bit so we show the non-selectable
726 * lines at the bottom.
729 /* set ctmpa to the bottom line on the screen */
730 for(ctmpa = screen->top_line, j = BODY_LINES(ps) - 1;
731 j > 0 && ctmpa;
732 ctmpa = next_confline(ctmpa), j--)
735 i = 0;
736 if(ctmpa){
737 for(ctmpa = next_confline(ctmpa);
738 ctmpa &&
739 (ctmpa->flags & (CF_NOSELECT | CF_B_LINE)) ==
740 CF_NOSELECT;
741 ctmpa = next_confline(ctmpa), i++)
745 if(i)
746 config_scroll_up(i);
747 else
748 q_status_message(SM_ORDER,0,1, _("Already at end of screen"));
751 break;
753 case MC_PREVITEM: /* prev list element */
754 case MC_CHARUP:
755 stay_in_col = 0;
756 if(screen->current->flags & CF_DOUBLEVAR){
757 if(screen->current->flags & CF_VAR2 && cmd == MC_PREVITEM){
758 screen->current->flags &= ~CF_VAR2;
759 break;
762 /* otherwise we fall through to normal prev */
763 stay_in_col = (!(screen->current->flags & CF_VAR2) &&
764 cmd == MC_CHARUP);
765 screen->current->flags &= ~CF_VAR2;
767 else if(cmd == MC_CHARUP)
768 stay_in_col = 1;
770 ctmpa = screen->current;
771 i = 0;
773 if(ctmpa == config_top_scroll(ps, screen->top_line))
774 i = 1;
775 else if(i)
776 i++;
777 while((ctmpa = prev_confline(ctmpa))
778 && (ctmpa->flags&CF_NOSELECT));
780 if(ctmpa){
781 screen->current = ctmpa;
782 if(screen->current->flags & CF_DOUBLEVAR && !stay_in_col)
783 screen->current->flags |= CF_VAR2;
785 if((cmd == MC_CHARUP) && i)
786 config_scroll_down(i);
788 else
789 q_status_message(SM_ORDER, 0, 1,
790 _("Already at start of screen"));
792 break;
794 case MC_PAGEDN: /* page forward */
795 screen->current->flags &= ~CF_VAR2;
796 for(ctmpa = screen->top_line, i = BODY_LINES(ps);
797 i > 0 && ctmpa;
798 ctmpb = ctmpa, ctmpa = next_confline(ctmpa), i--)
801 if(ctmpa){ /* first line off bottom of screen */
802 ctmpb = ctmpa;
803 ps->mangled_body = 1;
804 /* find first selectable line on next page */
805 for(screen->top_line = ctmpa;
806 ctmpa && (ctmpa->flags & CF_NOSELECT);
807 ctmpa = next_confline(ctmpa))
811 * No selectable lines on next page. Slide up to first
812 * selectable.
814 if(!ctmpa){
815 for(ctmpa = prev_confline(ctmpb);
816 ctmpa && (ctmpa->flags & CF_NOSELECT);
817 ctmpa = prev_confline(ctmpa))
820 if(ctmpa)
821 screen->top_line = ctmpa;
824 else{ /* on last screen */
825 /* just move current down to last entry on screen */
826 if(ctmpb){ /* last line of data */
827 for(ctmpa = ctmpb, i = BODY_LINES(ps);
828 i > 0 && ctmpa && (ctmpa->flags & CF_NOSELECT);
829 ctmpa = prev_confline(ctmpa), i--)
832 if(ctmpa == screen->current){
833 q_status_message(SM_ORDER,0,1,
834 _("Already at end of screen"));
835 goto no_down;
838 ps->mangled_body = 1;
842 if(ctmpa)
843 screen->current = ctmpa;
844 no_down:
845 break;
847 case MC_PAGEUP: /* page backward */
848 ps->mangled_body = 1;
849 screen->current->flags &= ~CF_VAR2;
850 if(!(ctmpa=prev_confline(screen->top_line)))
851 ctmpa = screen->current;
853 for(i = BODY_LINES(ps) - 1;
854 i > 0 && prev_confline(ctmpa);
855 i--, ctmpa = prev_confline(ctmpa))
858 for(screen->top_line = ctmpa;
859 ctmpa && (ctmpa->flags & CF_NOSELECT);
860 ctmpa = next_confline(ctmpa))
863 if(ctmpa){
864 if(ctmpa == screen->current){
866 * We get to here if there was nothing selectable on
867 * the previous page. There still may be something
868 * selectable further back than the previous page,
869 * so look for that.
871 for(ctmpa = prev_confline(screen->top_line);
872 ctmpa && (ctmpa->flags & CF_NOSELECT);
873 ctmpa = prev_confline(ctmpa))
876 if(!ctmpa){
877 ctmpa = screen->current;
878 q_status_message(SM_ORDER, 0, 1,
879 _("Already at start of screen"));
883 screen->current = ctmpa;
886 break;
888 #ifdef MOUSE
889 case MC_MOUSE:
891 MOUSEPRESS mp;
893 mouse_get_last (NULL, &mp);
894 mp.row -= HEADER_ROWS(ps);
895 ctmpa = screen->top_line;
897 while (mp.row && ctmpa != NULL) {
898 --mp.row;
899 ctmpa = ctmpa->next;
902 if (ctmpa != NULL && !(ctmpa->flags & CF_NOSELECT)){
903 if(screen->current->flags & CF_DOUBLEVAR)
904 screen->current->flags &= ~CF_VAR2;
906 screen->current = ctmpa;
908 if(screen->current->flags & CF_DOUBLEVAR &&
909 mp.col >= screen->current->val2offset)
910 screen->current->flags |= CF_VAR2;
912 update_option_screen(ps, screen, &cursor_pos);
914 if(mp.button == M_BUTTON_LEFT && mp.doubleclick){
916 if(screen->current->tool){
917 unsigned flags;
918 int default_cmd;
920 flags = screen->current->flags;
921 flags |= (changes ? CF_CHANGES : 0);
923 default_cmd = menu_command(ctrl('M'), km);
924 switch(i=(*screen->current->tool)(ps, default_cmd,
925 &screen->current, flags)){
926 case -1:
927 case 0:
928 break;
930 case 1:
931 changes = 1;
932 break;
934 case 2:
935 retval = changes;
936 done++;
937 break;
939 case 3:
940 retval = 1;
941 done++;
942 break;
944 default:
945 retval = i;
946 done++;
947 break;
951 #ifdef _WINDOWS
952 else if(mp.button == M_BUTTON_RIGHT) {
953 MPopup other_popup[20];
954 int n = -1, cmd, i;
955 struct key_menu *sckm = screen->current->keymenu; /* only for popup */
957 if((cmd = menu_command(ctrl('M'), sckm)) != MC_UNKNOWN){
958 i = menu_binding_index(sckm, cmd);
959 other_popup[++n].type = tQueue;
960 other_popup[n].label.style = lNormal;
961 other_popup[n].label.string = sckm->keys[i].label;
962 other_popup[n].data.val = ctrl('M');
964 else if((cmd = menu_command('>', sckm)) != MC_UNKNOWN){
965 i = menu_binding_index(sckm, cmd);
966 other_popup[++n].type = tQueue;
967 other_popup[n].label.style = lNormal;
968 other_popup[n].label.string = sckm->keys[i].label;
969 other_popup[n].data.val = '>';
972 if(((i = menu_binding_index(sckm, MC_RGB1)) >= 0) ||
973 ((i = menu_binding_index(sckm, MC_RGB2)) >= 0)){
974 other_popup[++n].type = tQueue;
975 other_popup[n].label.style = lNormal;
976 other_popup[n].label.string = sckm->keys[i].label;
977 other_popup[n].data.val =
978 sckm->keys[i].bind.ch[0];
981 if((cmd = menu_command('<', sckm)) != MC_UNKNOWN){
982 i = menu_binding_index(sckm, cmd);
983 other_popup[++n].type = tQueue;
984 other_popup[n].label.style = lNormal;
985 other_popup[n].label.string = sckm->keys[i].label;
986 other_popup[n].data.val = '<';
988 else if((i = menu_binding_index(sckm, MC_EXIT)) >= 0){
989 other_popup[++n].type = tQueue;
990 other_popup[n].label.style = lNormal;
991 other_popup[n].label.string = sckm->keys[i].label;
992 other_popup[n].data.val =
993 sckm->keys[i].bind.ch[0];
996 if((i = menu_binding_index(sckm, MC_HELP)) >= 0){
997 if(n > 0)
998 other_popup[++n].type = tSeparator;
1000 other_popup[++n].type = tQueue;
1001 other_popup[n].label.style = lNormal;
1002 other_popup[n].label.string = sckm->keys[i].label;
1003 other_popup[n].data.val = sckm->keys[i].bind.ch[0];
1006 if(n > 0){
1007 other_popup[++n].type = tTail;
1008 mswin_popup(other_popup);
1012 else if(mp.button == M_BUTTON_RIGHT) {
1013 MPopup other_popup[20];
1014 int n = -1, cmd, i;
1015 struct key_menu *sckm = screen->current->keymenu; /* only for popup */
1017 if((cmd = menu_command('<', sckm)) != MC_UNKNOWN){
1018 i = menu_binding_index(sckm, cmd);
1019 other_popup[++n].type = tQueue;
1020 other_popup[n].label.style = lNormal;
1021 other_popup[n].label.string = sckm->keys[i].label;
1022 other_popup[n].data.val = '<';
1024 else if((i = menu_binding_index(sckm, MC_EXIT)) >= 0){
1025 other_popup[++n].type = tQueue;
1026 other_popup[n].label.style = lNormal;
1027 other_popup[n].label.string = sckm->keys[i].label;
1028 other_popup[n].data.val = sckm->keys[i].bind.ch[0];
1031 other_popup[++n].type = tTail;
1033 if(n > 0)
1034 mswin_popup(other_popup);
1035 #endif
1038 break;
1039 #endif
1041 case MC_PRINTTXT: /* print screen */
1042 print_option_screen(screen, pdesc ? pdesc : "");
1043 break;
1045 case MC_WHEREIS: /* whereis */
1046 /*--- get string ---*/
1047 {int rc, found = 0;
1048 #define FOUND_IT 0x01
1049 #define FOUND_CURRENT 0x02
1050 #define FOUND_WRAPPED 0x04
1051 #define FOUND_NOSELECT 0x08
1052 #define FOUND_ABOVE 0x10
1053 char *result = NULL, buf[64];
1054 char *p, last[64];
1055 static HISTORY_S *history = NULL;
1056 HelpType help;
1057 static ESCKEY_S ekey[] = {
1058 {0, 0, "", ""},
1059 /* TRANSLATORS: go to Top of screen */
1060 {ctrl('Y'), 10, "^Y", N_("Top")},
1061 {ctrl('V'), 11, "^V", N_("Bottom")},
1062 {KEY_UP, 30, "", ""},
1063 {KEY_DOWN, 31, "", ""},
1064 {-1, 0, NULL, NULL}};
1065 #define KU_WI (3) /* index of KEY_UP */
1067 init_hist(&history, HISTSIZE);
1068 last[0] = '\0';
1069 if((p = get_prev_hist(history, "", 0, NULL)) != NULL){
1070 strncpy(last, p, sizeof(last));
1071 last[sizeof(last)-1] = '\0';
1074 ps->mangled_footer = 1;
1075 buf[0] = '\0';
1076 snprintf(tmp, sizeof(tmp), "Word to find %s%s%s: ",
1077 (last[0]) ? "[" : "",
1078 (last[0]) ? last : "",
1079 (last[0]) ? "]" : "");
1080 tmp[sizeof(tmp)-1] = '\0';
1081 help = NO_HELP;
1082 while(1){
1083 int flags = OE_APPEND_CURRENT;
1086 * 2 is really 1 because there will be one real entry and
1087 * one entry of "" because of the get_prev_hist above.
1089 if(items_in_hist(history) > 2){
1090 ekey[KU_WI].name = HISTORY_UP_KEYNAME;
1091 ekey[KU_WI].label = HISTORY_KEYLABEL;
1092 ekey[KU_WI+1].name = HISTORY_DOWN_KEYNAME;
1093 ekey[KU_WI+1].label = HISTORY_KEYLABEL;
1095 else{
1096 ekey[KU_WI].name = "";
1097 ekey[KU_WI].label = "";
1098 ekey[KU_WI+1].name = "";
1099 ekey[KU_WI+1].label = "";
1102 rc = optionally_enter(buf,-FOOTER_ROWS(ps),0,sizeof(buf),
1103 tmp,ekey,help,&flags);
1104 if(rc == 3)
1105 help = help == NO_HELP ? h_config_whereis : NO_HELP;
1106 else if(rc == 30){
1107 if((p = get_prev_hist(history, buf, 0, NULL)) != NULL){
1108 strncpy(buf, p, sizeof(buf));
1109 buf[sizeof(buf)-1] = '\0';
1111 else
1112 Writechar(BELL, 0);
1114 continue;
1116 else if(rc == 31){
1117 if((p = get_next_hist(history, buf, 0, NULL)) != NULL){
1118 strncpy(buf, p, sizeof(buf));
1119 buf[sizeof(buf)-1] = '\0';
1121 else
1122 Writechar(BELL, 0);
1124 continue;
1126 else if(rc == 0 || rc == 1 || rc == 10 || rc == 11 || !buf[0]){
1127 if(rc == 0 && !buf[0] && last[0])
1128 strncpy(buf, last, 64);
1130 break;
1134 screen->current->flags &= ~CF_VAR2;
1135 if(rc == 0 && buf[0]){
1136 CONF_S *started_here;
1138 save_hist(history, buf, 0, NULL);
1140 ch = KEY_DOWN;
1141 ctmpa = screen->current;
1143 * Skip over the unselectable lines of this "item"
1144 * before starting search so that we don't find the
1145 * same one again.
1147 while((ctmpb = next_confline(ctmpa)) &&
1148 (ctmpb->flags & CF_NOSELECT) &&
1149 !(ctmpb->flags & CF_STARTITEM))
1150 ctmpa = ctmpb;
1152 started_here = next_confline(ctmpa);
1153 while((ctmpa = next_confline(ctmpa)) != NULL)
1154 if(srchstr(ctmpa->varname, buf)
1155 || srchstr(ctmpa->value, buf)){
1157 found = FOUND_IT;
1159 * If this line is not selectable, back up to the
1160 * previous selectable line, but not past the
1161 * start of this "entry".
1163 if(ctmpa->flags & CF_NOSELECT)
1164 found |= FOUND_NOSELECT;
1166 while((ctmpa->flags & CF_NOSELECT) &&
1167 !(ctmpa->flags & CF_STARTITEM) &&
1168 (ctmpb = prev_confline(ctmpa)))
1169 ctmpa = ctmpb;
1172 * If that isn't selectable, better search forward
1173 * for something that is.
1175 while((ctmpa->flags & CF_NOSELECT) &&
1176 (ctmpb = next_confline(ctmpa))){
1177 ctmpa = ctmpb;
1178 found |= FOUND_ABOVE;
1182 * If that still isn't selectable, better search
1183 * backwards for something that is.
1185 while((ctmpa->flags & CF_NOSELECT) &&
1186 (ctmpb = prev_confline(ctmpa))){
1187 ctmpa = ctmpb;
1188 found &= ~FOUND_ABOVE;
1191 break;
1194 if(!found){
1195 found = FOUND_WRAPPED;
1196 ctmpa = first_confline(screen->current);
1198 while(ctmpa != started_here)
1199 if(srchstr(ctmpa->varname, buf)
1200 || srchstr(ctmpa->value, buf)){
1202 found |= FOUND_IT;
1203 if(ctmpa->flags & CF_NOSELECT)
1204 found |= FOUND_NOSELECT;
1206 while((ctmpa->flags & CF_NOSELECT) &&
1207 !(ctmpa->flags & CF_STARTITEM) &&
1208 (ctmpb = prev_confline(ctmpa)))
1209 ctmpa = ctmpb;
1211 while((ctmpa->flags & CF_NOSELECT) &&
1212 (ctmpb = next_confline(ctmpa))){
1213 ctmpa = ctmpb;
1214 found |= FOUND_ABOVE;
1217 if(ctmpa == screen->current)
1218 found |= FOUND_CURRENT;
1220 break;
1222 else
1223 ctmpa = next_confline(ctmpa);
1226 else if(rc == 10){
1227 screen->current = first_confline(screen->current);
1228 if(screen->current && screen->current->flags & CF_NOSELECT){
1229 for(ctmpa = next_confline(screen->current);
1230 ctmpa && (ctmpa->flags & CF_NOSELECT);
1231 ctmpa = next_confline(ctmpa))
1234 if(ctmpa)
1235 screen->current = ctmpa;
1238 /* TRANSLATORS: Searched to ... is the result of the search, searched
1239 to top means the search went past the bottom of the screen and
1240 wrapped back around to the top. */
1241 result = _("Searched to top");
1243 else if(rc == 11){
1244 screen->current = last_confline(screen->current);
1245 if(screen->current && screen->current->flags & CF_NOSELECT){
1246 for(ctmpa = prev_confline(screen->current);
1247 ctmpa && (ctmpa->flags & CF_NOSELECT);
1248 ctmpa = prev_confline(ctmpa))
1251 if(ctmpa)
1252 screen->current = ctmpa;
1255 result = _("Searched to bottom");
1257 else
1258 result = _("WhereIs cancelled");
1260 if((found & FOUND_IT) && ctmpa){
1261 strncpy(last, buf, 64);
1262 result =
1263 (found & FOUND_CURRENT && found & FOUND_WRAPPED && found & FOUND_NOSELECT)
1264 ? _("Current item contains the only match")
1265 : (found & FOUND_CURRENT && found & FOUND_WRAPPED)
1266 ? _("Current line contains the only match")
1267 : (found & FOUND_NOSELECT && found & FOUND_WRAPPED)
1268 ? ((found & FOUND_ABOVE)
1269 ? _("Search wrapped: word found in text above current line")
1270 : _("Search wrapped: word found in text below current line"))
1271 : (found & FOUND_WRAPPED)
1272 ? _("Search wrapped to beginning: word found")
1273 : (found & FOUND_NOSELECT)
1274 ? ((found & FOUND_ABOVE)
1275 ? _("Word found in text above current line")
1276 : _("Word found in text below current line"))
1277 : _("Word found");
1278 screen->current = ctmpa;
1281 q_status_message(SM_ORDER,0,3,result ? result : _("Word not found"));
1284 break;
1286 case MC_HOMEKEY:
1287 screen->current = first_confline(screen->current);
1288 if(screen->current && screen->current->flags & CF_NOSELECT){
1289 for(ctmpa = next_confline(screen->current);
1290 ctmpa && (ctmpa->flags & CF_NOSELECT);
1291 ctmpa = next_confline(ctmpa))
1294 if(ctmpa)
1295 screen->current = ctmpa;
1298 q_status_message(SM_ORDER,0,3, _("Moved to top"));
1299 break;
1301 case MC_ENDKEY:
1302 screen->current = last_confline(screen->current);
1303 if(screen->current && screen->current->flags & CF_NOSELECT){
1304 for(ctmpa = prev_confline(screen->current);
1305 ctmpa && (ctmpa->flags & CF_NOSELECT);
1306 ctmpa = prev_confline(ctmpa))
1309 if(ctmpa)
1310 screen->current = ctmpa;
1313 q_status_message(SM_ORDER,0,3, _("Moved to bottom"));
1314 break;
1316 case MC_REPAINT: /* redraw the display */
1317 case MC_RESIZE:
1318 ClearScreen();
1319 ps->mangled_screen = 1;
1320 break;
1322 default:
1323 if(screen && screen->ro_warning){
1324 if(cmd == MC_EXIT){
1325 retval = 0;
1326 done++;
1328 else
1329 q_status_message1(SM_ORDER|SM_DING, 1, 3,
1330 _("%s can't change options or settings"),
1331 ps_global->restricted ? "Alpine demo"
1332 : _("Config file not changeable,"));
1334 else if(screen->current->tool){
1335 unsigned flags;
1337 flags = screen->current->flags;
1338 flags |= (changes ? CF_CHANGES : 0);
1340 switch(i=(*screen->current->tool)(ps, cmd,
1341 &screen->current, flags)){
1342 case -1:
1343 q_status_message2(SM_ORDER, 0, 2,
1344 /* TRANSLATORS: Command <command letter> not defined here.
1345 Leave the trailing %s which might be a parenthetical
1346 remark. */
1347 _("Command \"%s\" not defined here.%s"),
1348 pretty_command(ch),
1349 F_ON(F_BLANK_KEYMENU,ps) ? "" : " See key menu below.");
1350 break;
1352 case 0:
1353 break;
1355 case 1:
1356 changes = 1;
1357 break;
1359 case 2:
1360 retval = changes;
1361 done++;
1362 break;
1364 case 3:
1365 retval = 1;
1366 done++;
1367 break;
1369 default:
1370 retval = i;
1371 done++;
1372 break;
1376 break;
1378 case MC_UTF8:
1379 bogus_utf8_command(utf8str, "?");
1380 break;
1382 case MC_NONE: /* simple timeout */
1383 break;
1387 screen->current = first_confline(screen->current);
1388 free_conflines(&screen->current);
1389 return(retval);
1396 void
1397 config_scroll_up(long int n)
1399 CONF_S *ctmp = opt_screen->top_line;
1400 int cur_found = 0;
1402 if(n < 0)
1403 config_scroll_down(-n);
1404 else if(n){
1405 for(; n>0 && ctmp->next; n--){
1406 ctmp = next_confline(ctmp);
1407 if(prev_confline(ctmp) == opt_screen->current)
1408 cur_found++;
1411 opt_screen->top_line = ctmp;
1412 ps_global->mangled_body = 1;
1413 if(cur_found){
1414 for(ctmp = opt_screen->top_line;
1415 ctmp && (ctmp->flags & CF_NOSELECT);
1416 ctmp = next_confline(ctmp))
1419 if(ctmp)
1420 opt_screen->current = opt_screen->prev = ctmp;
1421 else {
1422 while(opt_screen->top_line->flags & CF_NOSELECT)
1423 opt_screen->top_line = prev_confline(opt_screen->top_line);
1424 opt_screen->current = opt_screen->prev = opt_screen->top_line;
1432 * config_scroll_down -
1434 void
1435 config_scroll_down(long int n)
1437 CONF_S *ctmp = opt_screen->top_line, *last_sel = NULL;
1438 int i;
1440 if(n < 0)
1441 config_scroll_up(-n);
1442 else if(n){
1443 for(; n>0 && ctmp->prev; n--)
1444 ctmp = prev_confline(ctmp);
1446 opt_screen->top_line = ctmp;
1447 ps_global->mangled_body = 1;
1448 for(ctmp = opt_screen->top_line, i = BODY_LINES(ps_global);
1449 i > 0 && ctmp && ctmp != opt_screen->current;
1450 ctmp = next_confline(ctmp), i--)
1451 if(!(ctmp->flags & CF_NOSELECT))
1452 last_sel = ctmp;
1454 if(!i && last_sel)
1455 opt_screen->current = opt_screen->prev = last_sel;
1461 * config_scroll_to_pos -
1463 void
1464 config_scroll_to_pos(long int n)
1466 CONF_S *ctmp;
1468 for(ctmp = first_confline(opt_screen->current);
1469 n && ctmp && ctmp != opt_screen->top_line;
1470 ctmp = next_confline(ctmp), n--)
1473 if(n == 0)
1474 while(ctmp && ctmp != opt_screen->top_line)
1475 if((ctmp = next_confline(ctmp)) != NULL)
1476 n--;
1478 config_scroll_up(n);
1483 * config_top_scroll - return pointer to the
1485 CONF_S *
1486 config_top_scroll(struct pine *ps, CONF_S *topline)
1488 int i;
1489 CONF_S *ctmp;
1491 for(ctmp = topline, i = HS_MARGIN(ps);
1492 ctmp && i;
1493 ctmp = next_confline(ctmp), i--)
1496 return(ctmp ? ctmp : topline);
1501 text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
1503 return(text_toolit(ps, cmd, cl, flags, 0));
1508 * simple text variable handler
1510 * note, things get a little involved due to the
1511 * screen struct <--> variable mapping. (but, once its
1512 * running it shouldn't need changing ;).
1514 * look_for_backslash == 1 means that backslash is an escape character.
1515 * In particular, \, can be used to put a literal comma
1516 * into a value. The value will still have the backslash
1517 * in it, but the comma after the backslash won't be treated
1518 * as an item separator.
1520 * returns: -1 on unrecognized cmd, 0 if no change, 1 if change
1521 * returns what conf_exit_cmd returns for exit command.
1524 text_toolit(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags, int look_for_backslash)
1526 char prompt[81], *sval, *tmp, *swap_val, **newval = NULL;
1527 char *pval, **apval, **lval, ***alval;
1528 char *olddefval = NULL;
1529 int rv = 0, skip_to_next = 0, after = 0, i = 4, j, k;
1530 int lowrange, hirange, incr, oeflags, oebufsize;
1531 int numval, repeat_key = 0;
1532 int curindex, previndex, nextindex, deefault;
1533 HelpType help;
1534 ESCKEY_S ekey[6];
1536 if((*cl)->var->is_list){
1537 lval = LVAL((*cl)->var, ew);
1538 alval = ALVAL((*cl)->var, ew);
1540 else{
1541 pval = PVAL((*cl)->var, ew);
1542 apval = APVAL((*cl)->var, ew);
1545 oebufsize = 6*MAXPATH;
1546 sval = (char *) fs_get(oebufsize*sizeof(char));
1547 sval[0] = '\0';
1549 if(flags&CF_NUMBER){ /* only happens if !is_list */
1550 incr = 1;
1551 if((*cl)->var == &ps->vars[V_FILLCOL]){
1552 lowrange = 1;
1553 hirange = MAX_FILLCOL;
1555 else if((*cl)->var == &ps->vars[V_SLEEP]){
1556 lowrange = 60;
1557 hirange = 600;
1559 else if((*cl)->var == &ps->vars[V_OVERLAP]
1560 || (*cl)->var == &ps->vars[V_MARGIN]){
1561 lowrange = 0;
1562 hirange = 20;
1564 else if((*cl)->var == &ps->vars[V_QUOTE_SUPPRESSION]){
1565 lowrange = -(Q_SUPP_LIMIT-1);
1566 hirange = 1000;
1568 else if((*cl)->var == &ps->vars[V_MAXREMSTREAM]){
1569 lowrange = 0;
1570 hirange = 15;
1572 else if((*cl)->var == &ps->vars[V_STATUS_MSG_DELAY]){
1573 lowrange = -10;
1574 hirange = 30;
1576 else if((*cl)->var == &ps->vars[V_ACTIVE_MSG_INTERVAL]){
1577 lowrange = 0;
1578 hirange = 20;
1580 else if((*cl)->var == &ps->vars[V_MAILCHECK] ||
1581 (*cl)->var == &ps->vars[V_INCCHECKINTERVAL] ||
1582 (*cl)->var == &ps->vars[V_INC2NDCHECKINTERVAL] ||
1583 (*cl)->var == &ps->vars[V_MAILCHECKNONCURR]){
1584 lowrange = 0;
1585 hirange = 25000;
1586 incr = 15;
1588 else if((*cl)->var == &ps->vars[V_DEADLETS]){
1589 lowrange = 0;
1590 hirange = 9;
1592 else if((*cl)->var == &ps->vars[V_NMW_WIDTH]){
1593 lowrange = 20;
1594 hirange = MAX_SCREEN_COLS;
1596 else if((*cl)->var == score_act_global_ptr){
1597 lowrange = -100;
1598 hirange = 100;
1600 else if((*cl)->var == &ps->vars[V_TCPOPENTIMEO] ||
1601 (*cl)->var == &ps->vars[V_TCPREADWARNTIMEO] ||
1602 (*cl)->var == &ps->vars[V_TCPQUERYTIMEO]){
1603 lowrange = 5;
1604 hirange = 1000;
1606 else if((*cl)->var == &ps->vars[V_TCPWRITEWARNTIMEO] ||
1607 (*cl)->var == &ps->vars[V_RSHOPENTIMEO] ||
1608 (*cl)->var == &ps->vars[V_SSHOPENTIMEO] ||
1609 (*cl)->var == &ps->vars[V_USERINPUTTIMEO]){
1610 lowrange = 0;
1611 hirange = 1000;
1613 else if((*cl)->var == &ps->vars[V_INCCHECKTIMEO]){
1614 lowrange = 1;
1615 hirange = 1000;
1617 else if((*cl)->var == &ps->vars[V_MAILDROPCHECK]){
1618 lowrange = 0;
1619 hirange = 1000000;
1620 incr = 60;
1622 else if((*cl)->var == &ps->vars[V_NNTPRANGE]){
1623 lowrange = 0;
1624 hirange = 1000000;
1625 incr = 100;
1627 else if((*cl)->var == &ps->vars[V_REMOTE_ABOOK_VALIDITY]){
1628 lowrange = -1;
1629 hirange = 25000;
1631 else if((*cl)->var == &ps->vars[V_REMOTE_ABOOK_HISTORY]){
1632 lowrange = 0;
1633 hirange = 100;
1635 else if((*cl)->var == cat_lim_global_ptr){
1636 lowrange = -1;
1637 hirange = 10000000;
1639 else{
1640 lowrange = 0;
1641 hirange = 25000;
1644 ekey[0].ch = -2;
1645 ekey[0].rval = 'x';
1646 ekey[0].name = "";
1647 ekey[0].label = "";
1648 ekey[1].ch = ctrl('P');
1649 ekey[1].rval = ctrl('P');
1650 ekey[1].name = "^P";
1651 ekey[1].label = N_("Decrease");
1652 ekey[2].ch = ctrl('N');
1653 ekey[2].rval = ctrl('N');
1654 ekey[2].name = "^N";
1655 ekey[2].label = N_("Increase");
1656 ekey[3].ch = KEY_DOWN;
1657 ekey[3].rval = ctrl('P');
1658 ekey[3].name = "";
1659 ekey[3].label = "";
1660 ekey[4].ch = KEY_UP;
1661 ekey[4].rval = ctrl('N');
1662 ekey[4].name = "";
1663 ekey[4].label = "";
1664 ekey[5].ch = -1;
1667 switch(cmd){
1668 case MC_ADD: /* add to list */
1669 if(fixed_var((*cl)->var, "add to", NULL)){
1670 break;
1672 else if(!(*cl)->var->is_list && pval){
1673 q_status_message(SM_ORDER, 3, 3,
1674 _("Only single value allowed. Use \"Change\"."));
1676 else{
1677 int maxwidth;
1678 char *p;
1680 if((*cl)->var->is_list
1681 && lval && lval[0] && lval[0][0]
1682 && (*cl)->value){
1683 char tmpval[101];
1684 /* regular add to an existing list */
1686 strncpy(tmpval, (*cl)->value, sizeof(tmpval));
1687 tmpval[sizeof(tmpval)-1] = '\0';
1688 removing_trailing_white_space(tmpval);
1690 /* 33 is the number of chars other than the value */
1691 maxwidth = MIN(80, ps->ttyo->screen_cols) - 15;
1692 k = MIN(18, MAX(maxwidth-33,0));
1693 if(utf8_width(tmpval) > k && k >= 3){
1694 (void) utf8_truncate(tmpval, k-3);
1695 strncat(tmpval, "...", sizeof(tmpval)-strlen(tmpval)-1);
1696 tmpval[sizeof(tmpval)-1] = '\0';
1699 utf8_snprintf(prompt, sizeof(prompt),
1700 _("Enter text to insert before \"%.*w\": "), k, tmpval);
1701 prompt[sizeof(prompt)-1] = '\0';
1703 else if((*cl)->var->is_list
1704 && !lval
1705 && (*cl)->var->current_val.l){
1706 /* Add to list which doesn't exist, but default does exist */
1707 ekey[0].ch = 'r';
1708 ekey[0].rval = 'r';
1709 ekey[0].name = "R";
1710 ekey[0].label = N_("Replace");
1711 ekey[1].ch = 'a';
1712 ekey[1].rval = 'a';
1713 ekey[1].name = "A";
1714 ekey[1].label = N_("Add To");
1715 ekey[2].ch = -1;
1716 strncpy(prompt, _("Replace or Add To default value ? "), sizeof(prompt));
1717 prompt[sizeof(prompt)-1] = '\0';
1718 switch(radio_buttons(prompt, -FOOTER_ROWS(ps), ekey, 'a', 'x',
1719 h_config_replace_add, RB_NORM)){
1720 case 'a':
1721 p = sval;
1722 for(j = 0; (*cl)->var->current_val.l[j]; j++){
1723 sstrncpy(&p, (*cl)->var->current_val.l[j], oebufsize-(p-sval));
1724 if(oebufsize-(p-sval) > 2){
1725 *p++ = ',';
1726 *p++ = ' ';
1729 if(oebufsize-(p-sval) > 0)
1730 *p = '\0';
1733 sval[oebufsize-1] = '\0';
1735 add_text:
1736 if(flags & CF_NUMBER)
1737 snprintf(prompt, sizeof(prompt), _("Enter the numeric text to be added : "));
1738 else
1739 snprintf(prompt, sizeof(prompt), _("Enter the text to be added : "));
1741 break;
1743 case 'r':
1744 replace_text:
1745 if(olddefval){
1746 strncpy(sval, olddefval, oebufsize);
1747 sval[oebufsize-1] = '\0';
1750 if(flags & CF_NUMBER)
1751 snprintf(prompt, sizeof(prompt), _("Enter the numeric replacement text : "));
1752 else
1753 snprintf(prompt, sizeof(prompt), _("Enter the replacement text : "));
1755 break;
1757 case 'x':
1758 i = 1;
1759 cmd_cancelled("Add");
1760 break;
1763 else{
1764 if(flags & CF_NUMBER)
1765 snprintf(prompt, sizeof(prompt), _("Enter the numeric text to be added : "));
1766 else
1767 snprintf(prompt, sizeof(prompt), _("Enter the text to be added : "));
1770 prompt[sizeof(prompt)-1] = '\0';
1772 ps->mangled_footer = 1;
1774 if(i == 1)
1775 break;
1777 help = NO_HELP;
1778 while(1){
1779 if((*cl)->var->is_list
1780 && lval && lval[0] && lval[0][0]
1781 && (*cl)->value){
1782 ekey[0].ch = ctrl('W');
1783 ekey[0].rval = 5;
1784 ekey[0].name = "^W";
1785 /* TRANSLATORS: Insert new item before current item */
1786 ekey[0].label = after ? N_("InsertBefore") : N_("InsertAfter");
1787 ekey[1].ch = -1;
1789 else if(!(flags&CF_NUMBER))
1790 ekey[0].ch = -1;
1792 oeflags = OE_APPEND_CURRENT;
1793 i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, oebufsize,
1794 prompt,
1795 (ekey[0].ch != -1) ? ekey : NULL,
1796 help, &oeflags);
1797 if(i == 0){
1798 rv = 1;
1799 if((*cl)->var->is_list)
1800 ps->mangled_body = 1;
1801 else
1802 ps->mangled_footer = 1;
1804 removing_leading_and_trailing_white_space(sval);
1806 * Coerce "" and <Empty Value> to empty string input.
1807 * Catch <No Value Set> as a substitute for deleting.
1809 if((*sval == '\"' && *(sval+1) == '\"' && *(sval+2) == '\0')
1810 || !struncmp(sval, _(empty_val), strlen(_(empty_val)))
1811 || (*sval == '<'
1812 && !struncmp(sval+1, _(empty_val), strlen(_(empty_val)))))
1813 *sval = '\0';
1814 else if(!struncmp(sval, _(no_val), strlen(_(no_val)))
1815 || (*sval == '<'
1816 && !struncmp(sval+1, _(no_val), strlen(_(no_val)))))
1817 goto delete;
1819 if((*cl)->var->is_list){
1820 if(*sval || !lval){
1821 char **ltmp;
1822 int i;
1824 i = 0;
1825 for(tmp = sval; *tmp; tmp++)
1826 if(*tmp == ',')
1827 i++; /* conservative count of ,'s */
1829 if(!i){
1830 ltmp = (char **)fs_get(2 * sizeof(char *));
1831 ltmp[0] = cpystr(sval);
1832 ltmp[1] = NULL;
1834 else
1835 ltmp = parse_list(sval, i + 1,
1836 look_for_backslash
1837 ? PL_COMMAQUOTE : 0,
1838 NULL);
1840 if(ltmp[0]){
1841 config_add_list(ps, cl, ltmp, &newval, after);
1842 if(after)
1843 skip_to_next = 1;
1845 else{
1846 q_status_message1(SM_ORDER, 0, 3,
1847 _("Can't add %s to list"), _(empty_val));
1848 rv = ps->mangled_body = 0;
1851 fs_give((void **)&ltmp);
1853 else{
1854 q_status_message1(SM_ORDER, 0, 3,
1855 _("Can't add %s to list"), _(empty_val));
1858 else{
1859 if(flags&CF_NUMBER && sval[0]
1860 && !(isdigit((unsigned char)sval[0])
1861 || sval[0] == '-' || sval[0] == '+')){
1862 q_status_message(SM_ORDER,3,3,
1863 _("Entry must be numeric"));
1864 i = 3; /* to keep loop going */
1865 continue;
1868 if(apval && *apval)
1869 fs_give((void **)apval);
1871 if(!(olddefval && !strcmp(sval, olddefval))
1872 || ((*cl)->var == &ps->vars[V_POST_CHAR_SET])
1873 || want_to(_("Leave unset and use default "),
1874 'y', 'y', NO_HELP, WT_FLUSH_IN) == 'n')
1875 *apval = cpystr(sval);
1877 newval = &(*cl)->value;
1880 else if(i == 1){
1881 cmd_cancelled("Add");
1883 else if(i == 3){
1884 help = help == NO_HELP ? h_config_add : NO_HELP;
1885 continue;
1887 else if(i == 4){ /* no redraw, yet */
1888 continue;
1890 else if(i == 5){ /* change from/to prepend to/from append */
1891 char tmpval[101];
1893 after = after ? 0 : 1;
1894 strncpy(tmpval, (*cl)->value, sizeof(tmpval));
1895 tmpval[sizeof(tmpval)-1] = '\0';
1896 removing_trailing_white_space(tmpval);
1897 /* 33 is the number of chars other than the value */
1898 maxwidth = MIN(80, ps->ttyo->screen_cols) - 15;
1899 k = MIN(18, MAX(maxwidth-33,0));
1900 if(utf8_width(tmpval) > k && k >= 3){
1901 (void) utf8_truncate(tmpval, k-3);
1902 strncat(tmpval, "...", sizeof(tmpval)-strlen(tmpval)-1);
1903 tmpval[sizeof(tmpval)-1] = '\0';
1906 if(after)
1907 snprintf(prompt, sizeof(prompt), _("Enter text to insert after \"%.*s\": "), k, tmpval);
1908 else
1909 snprintf(prompt, sizeof(prompt), _("Enter text to insert before \"%.*s\": "), k, tmpval);
1911 continue;
1913 else if(i == ctrl('P')){
1914 if(sval[0])
1915 numval = atoi(sval);
1916 else{
1917 if(pval)
1918 numval = atoi(pval);
1919 else
1920 numval = lowrange + 1;
1923 if(numval == lowrange){
1925 * Protect user from repeating arrow key that
1926 * causes message to appear over and over.
1928 if(++repeat_key > 0){
1929 q_status_message1(SM_ORDER,3,3,
1930 _("Minimum value is %s"), comatose(lowrange));
1931 repeat_key = -5;
1934 else
1935 repeat_key = 0;
1937 numval = MAX(numval - incr, lowrange);
1938 snprintf(sval, oebufsize, "%d", numval);
1939 sval[oebufsize-1] = '\0';
1940 continue;
1942 else if(i == ctrl('N')){
1943 if(sval[0])
1944 numval = atoi(sval);
1945 else{
1946 if(pval)
1947 numval = atoi(pval);
1948 else
1949 numval = lowrange + 1;
1952 if(numval == hirange){
1953 if(++repeat_key > 0){
1954 q_status_message1(SM_ORDER,3,3,
1955 _("Maximum value is %s"), comatose(hirange));
1956 repeat_key = -5;
1959 else
1960 repeat_key = 0;
1962 numval = MIN(numval + incr, hirange);
1963 snprintf(sval, oebufsize, "%d", numval);
1964 sval[oebufsize-1] = '\0';
1965 continue;
1968 break;
1972 break;
1974 case MC_DELETE: /* delete */
1975 delete:
1976 if(!(*cl)->var->is_list
1977 && apval && !*apval
1978 && (*cl)->var->current_val.p){
1979 char pmt[80];
1981 snprintf(pmt, sizeof(pmt), _("Override default with %s"), _(empty_val2));
1982 pmt[sizeof(pmt)-1] = '\0';
1983 if(want_to(pmt, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
1984 sval[0] = '\0';
1985 *apval = cpystr(sval);
1986 newval = &(*cl)->value;
1987 rv = ps->mangled_footer = 1;
1990 else if((*cl)->var->is_list
1991 && alval && !lval
1992 && (*cl)->var->current_val.l){
1993 char pmt[80];
1995 snprintf(pmt, sizeof(pmt), _("Override default with %s"), _(empty_val2));
1996 pmt[sizeof(pmt)-1] = '\0';
1997 if(want_to(pmt, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
1998 char **ltmp;
2000 sval[0] = '\0';
2001 ltmp = (char **)fs_get(2 * sizeof(char *));
2002 ltmp[0] = cpystr(sval);
2003 ltmp[1] = NULL;
2004 config_add_list(ps, cl, ltmp, &newval, 0);
2005 fs_give((void **)&ltmp);
2006 rv = ps->mangled_body = 1;
2009 else if(((*cl)->var->is_list && !lval)
2010 || (!(*cl)->var->is_list && !pval)){
2011 q_status_message(SM_ORDER, 0, 3, _("No set value to delete"));
2013 else{
2014 if((*cl)->var->is_fixed)
2015 snprintf(prompt, sizeof(prompt), _("Delete (unused) %s from %s "),
2016 (*cl)->var->is_list
2017 ? (!*lval[(*cl)->varmem])
2018 ? _(empty_val2)
2019 : lval[(*cl)->varmem]
2020 : (pval)
2021 ? (!*pval)
2022 ? _(empty_val2)
2023 : pval
2024 : "<NULL VALUE>",
2025 (*cl)->var->name);
2026 else
2027 snprintf(prompt, sizeof(prompt), _("Really delete %s%s from %s "),
2028 (*cl)->var->is_list ? "item " : "",
2029 (*cl)->var->is_list
2030 ? int2string((*cl)->varmem + 1)
2031 : (pval)
2032 ? (!*pval)
2033 ? _(empty_val2)
2034 : pval
2035 : "<NULL VALUE>",
2036 (*cl)->var->name);
2038 prompt[sizeof(prompt)-1] = '\0';
2041 ps->mangled_footer = 1;
2042 if(want_to(prompt, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
2043 rv = 1;
2044 if((*cl)->var->is_list)
2045 ps->mangled_body = 1;
2046 else
2047 ps->mangled_footer = 1;
2049 if((*cl)->var->is_list){
2050 if(lval[(*cl)->varmem])
2051 fs_give((void **)&lval[(*cl)->varmem]);
2053 config_del_list_item(cl, &newval);
2055 else{
2056 if(apval && *apval)
2057 fs_give((void **)apval);
2059 newval = &(*cl)->value;
2062 else
2063 q_status_message(SM_ORDER, 0, 3, _("Value not deleted"));
2066 break;
2068 case MC_EDIT: /* edit/change list option */
2069 if(fixed_var((*cl)->var, NULL, NULL)){
2070 break;
2072 else if(((*cl)->var->is_list
2073 && !lval
2074 && (*cl)->var->current_val.l)
2076 (!(*cl)->var->is_list
2077 && !pval
2078 && (*cl)->var->current_val.p)){
2081 * In non-list case, offer default value for editing.
2083 if(!(*cl)->var->is_list
2084 && (*cl)->var != &ps->vars[V_REPLY_INTRO]
2085 && (*cl)->var->current_val.p[0]
2086 && strcmp(VSTRING,(*cl)->var->current_val.p)){
2087 int quote_it;
2088 size_t len;
2090 olddefval = (char *) fs_get(strlen((*cl)->var->current_val.p)+3);
2092 if(!strncmp((*cl)->var->current_val.p,
2093 DSTRING,
2094 (len=strlen(DSTRING)))){
2095 /* strip DSTRING and trailing paren */
2096 strncpy(olddefval, (*cl)->var->current_val.p+len,
2097 strlen((*cl)->var->current_val.p)-len-1);
2098 olddefval[strlen((*cl)->var->current_val.p)-len-1] = '\0';
2100 else{
2101 /* quote it if there are trailing spaces */
2102 quote_it = ((*cl)->var->current_val.p[strlen((*cl)->var->current_val.p)-1] == SPACE);
2103 snprintf(olddefval, strlen((*cl)->var->current_val.p)+3, "%s%s%s", quote_it ? "\"" : "", (*cl)->var->current_val.p, quote_it ? "\"" : "");
2106 olddefval[strlen((*cl)->var->current_val.p)+3-1] = '\0';
2109 goto replace_text;
2111 else if(((*cl)->var->is_list
2112 && !lval
2113 && !(*cl)->var->current_val.l)
2115 (!(*cl)->var->is_list
2116 && !pval
2117 && !(*cl)->var->current_val.p)){
2118 goto add_text;
2120 else{
2121 HelpType help;
2122 char *clptr;
2124 if(sval)
2125 fs_give((void **)&sval);
2126 if((*cl)->var->is_list){
2127 snprintf(prompt, sizeof(prompt), _("Change field %s list entry : "),
2128 (*cl)->var->name);
2129 prompt[sizeof(prompt)-1] = '\0';
2130 clptr = lval[(*cl)->varmem] ? lval[(*cl)->varmem] : NULL;
2132 else{
2133 if(flags & CF_NUMBER)
2134 snprintf(prompt, sizeof(prompt), _("Change numeric field %s value : "), (*cl)->var->name);
2135 else
2136 snprintf(prompt, sizeof(prompt), _("Change field %s value : "), (*cl)->var->name);
2138 clptr = pval ? pval : NULL;
2141 oebufsize = clptr ? (int) MAX(MAXPATH, 50+strlen(clptr)) : MAXPATH;
2142 sval = (char *) fs_get(oebufsize * sizeof(char));
2143 snprintf(sval, oebufsize, "%s", clptr ? clptr : "");
2144 sval[oebufsize-1] = '\0';
2146 ps->mangled_footer = 1;
2147 help = NO_HELP;
2148 while(1){
2149 if(!(flags&CF_NUMBER))
2150 ekey[0].ch = -1;
2152 oeflags = OE_APPEND_CURRENT;
2153 i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, oebufsize,
2154 prompt,
2155 (ekey[0].ch != -1) ? ekey : NULL,
2156 help, &oeflags);
2157 if(i == 0){
2158 removing_leading_and_trailing_white_space(sval);
2160 * Coerce "" and <Empty Value> to empty string input.
2161 * Catch <No Value Set> as a substitute for deleting.
2163 if((*sval == '\"' && *(sval+1) == '\"' && *(sval+2) == '\0')
2164 || !struncmp(sval, _(empty_val), strlen(_(empty_val)))
2165 || (*sval == '<'
2166 && !struncmp(sval+1, _(empty_val), strlen(_(empty_val)))))
2167 *sval = '\0';
2168 else if(!struncmp(sval, _(no_val), strlen(_(no_val)))
2169 || (*sval == '<'
2170 && !struncmp(sval+1, _(no_val), strlen(_(no_val)))))
2171 goto delete;
2173 rv = 1;
2174 if((*cl)->var->is_list)
2175 ps->mangled_body = 1;
2176 else
2177 ps->mangled_footer = 1;
2179 if((*cl)->var->is_list){
2180 char **ltmp = NULL;
2181 int i;
2183 if(lval[(*cl)->varmem])
2184 fs_give((void **)&lval[(*cl)->varmem]);
2186 i = 0;
2187 for(tmp = sval; *tmp; tmp++)
2188 if(*tmp == ',')
2189 i++; /* conservative count of ,'s */
2191 if(i)
2192 ltmp = parse_list(sval, i + 1,
2193 look_for_backslash
2194 ? PL_COMMAQUOTE : 0,
2195 NULL);
2197 if(ltmp && !ltmp[0]) /* only commas */
2198 goto delete;
2199 else if(!i || (ltmp && !ltmp[1])){ /* only one item */
2200 lval[(*cl)->varmem] = cpystr(sval);
2201 newval = &(*cl)->value;
2203 if(ltmp && ltmp[0])
2204 fs_give((void **)&ltmp[0]);
2206 else if(ltmp){
2208 * Looks like the value was changed to a
2209 * list, so delete old value, and insert
2210 * new list...
2212 * If more than one item in existing list and
2213 * current is end of existing list, then we
2214 * have to delete and append instead of
2215 * deleting and prepending.
2217 if(((*cl)->varmem > 0 || lval[1])
2218 && !(lval[(*cl)->varmem+1])){
2219 after = 1;
2220 skip_to_next = 1;
2223 config_del_list_item(cl, &newval);
2224 config_add_list(ps, cl, ltmp, &newval, after);
2227 if(ltmp)
2228 fs_give((void **)&ltmp);
2230 else{
2231 if(flags&CF_NUMBER && sval[0]
2232 && !(isdigit((unsigned char)sval[0])
2233 || sval[0] == '-' || sval[0] == '+')){
2234 q_status_message(SM_ORDER,3,3,
2235 _("Entry must be numeric"));
2236 continue;
2239 if(apval && *apval)
2240 fs_give((void **)apval);
2242 if(sval[0] && apval)
2243 *apval = cpystr(sval);
2245 newval = &(*cl)->value;
2248 else if(i == 1){
2249 cmd_cancelled("Change");
2251 else if(i == 3){
2252 help = help == NO_HELP ? h_config_change : NO_HELP;
2253 continue;
2255 else if(i == 4){ /* no redraw, yet */
2256 continue;
2258 else if(i == ctrl('P')){
2259 numval = atoi(sval);
2260 if(numval == lowrange){
2262 * Protect user from repeating arrow key that
2263 * causes message to appear over and over.
2265 if(++repeat_key > 0){
2266 q_status_message1(SM_ORDER,3,3,
2267 _("Minimum value is %s"), comatose(lowrange));
2268 repeat_key = -5;
2271 else
2272 repeat_key = 0;
2274 numval = MAX(numval - incr, lowrange);
2275 snprintf(sval, oebufsize, "%d", numval);
2276 sval[oebufsize-1] = '\0';
2277 continue;
2279 else if(i == ctrl('N')){
2280 numval = atoi(sval);
2281 if(numval == hirange){
2282 if(++repeat_key > 0){
2283 q_status_message1(SM_ORDER,3,3,
2284 _("Maximum value is %s"), comatose(hirange));
2285 repeat_key = -5;
2288 else
2289 repeat_key = 0;
2291 numval = MIN(numval + incr, hirange);
2292 snprintf(sval, oebufsize, "%d", numval);
2293 sval[oebufsize-1] = '\0';
2294 continue;
2297 break;
2301 break;
2303 case MC_SHUFFLE:
2304 if(!((*cl)->var && (*cl)->var->is_list)){
2305 q_status_message(SM_ORDER, 0, 2,
2306 _("Can't shuffle single-valued setting"));
2307 break;
2310 if(!alval)
2311 break;
2313 curindex = (*cl)->varmem;
2314 previndex = curindex-1;
2315 nextindex = curindex+1;
2316 if(!*alval || !(*alval)[nextindex])
2317 nextindex = -1;
2319 if((previndex < 0 && nextindex < 0) || !*alval){
2320 q_status_message(SM_ORDER, 0, 3,
2321 _("Shuffle only makes sense when there is more than one value defined"));
2322 break;
2325 /* Move it up or down? */
2326 i = 0;
2327 ekey[i].ch = 'u';
2328 ekey[i].rval = 'u';
2329 ekey[i].name = "U";
2330 ekey[i++].label = N_("Up");
2332 ekey[i].ch = 'd';
2333 ekey[i].rval = 'd';
2334 ekey[i].name = "D";
2335 ekey[i++].label = N_("Down");
2337 ekey[i].ch = -1;
2338 deefault = 'u';
2340 if(previndex < 0){ /* no up */
2341 ekey[0].ch = -2;
2342 deefault = 'd';
2344 else if(nextindex < 0)
2345 ekey[1].ch = -2; /* no down */
2347 snprintf(prompt, sizeof(prompt), "Shuffle %s%s%s ? ",
2348 (ekey[0].ch != -2) ? "UP" : "",
2349 (ekey[0].ch != -2 && ekey[1].ch != -2) ? " or " : "",
2350 (ekey[1].ch != -2) ? "DOWN" : "");
2351 help = (ekey[0].ch == -2) ? h_hdrcolor_shuf_down
2352 : (ekey[1].ch == -2) ? h_hdrcolor_shuf_up
2353 : h_hdrcolor_shuf;
2354 prompt[sizeof(prompt)-1] = '\0';
2356 i = radio_buttons(prompt, -FOOTER_ROWS(ps), ekey, deefault, 'x',
2357 help, RB_NORM);
2359 switch(i){
2360 case 'x':
2361 cmd_cancelled("Shuffle");
2362 return(rv);
2364 case 'u':
2365 case 'd':
2366 break;
2369 /* swap order */
2370 if(i == 'd'){
2371 swap_val = (*alval)[curindex];
2372 (*alval)[curindex] = (*alval)[nextindex];
2373 (*alval)[nextindex] = swap_val;
2375 else if(i == 'u'){
2376 swap_val = (*alval)[curindex];
2377 (*alval)[curindex] = (*alval)[previndex];
2378 (*alval)[previndex] = swap_val;
2380 else /* can't happen */
2381 break;
2384 * Fix the conf line values.
2387 if((*cl)->value)
2388 fs_give((void **)&(*cl)->value);
2390 (*cl)->value = pretty_value(ps, *cl);
2392 if(i == 'd'){
2393 if((*cl)->next->value)
2394 fs_give((void **)&(*cl)->next->value);
2396 (*cl)->next->value = pretty_value(ps, (*cl)->next);
2397 *cl = next_confline(*cl);
2399 else{
2400 if((*cl)->prev->value)
2401 fs_give((void **)&(*cl)->prev->value);
2403 (*cl)->prev->value = pretty_value(ps, (*cl)->prev);
2404 *cl = prev_confline(*cl);
2407 rv = ps->mangled_body = 1;
2408 break;
2410 case MC_EXIT: /* exit */
2411 rv = config_exit_cmd(flags);
2412 break;
2414 default:
2415 rv = -1;
2416 break;
2419 if(skip_to_next)
2420 *cl = next_confline(*cl);
2423 * At this point, if changes occurred, var->user_val.X is set.
2424 * So, fix the current_val, and handle special cases...
2426 * NOTE: we don't worry about the "fixed variable" case here, because
2427 * editing such vars should have been prevented above...
2429 if(rv == 1){
2431 * Now go and set the current_val based on user_val changes
2432 * above. Turn off command line settings...
2434 set_current_val((*cl)->var, TRUE, FALSE);
2435 fix_side_effects(ps, (*cl)->var, 0);
2438 * Delay setting the displayed value until "var.current_val" is set
2439 * in case current val get's changed due to a special case above.
2441 if(newval){
2442 if(*newval)
2443 fs_give((void **) newval);
2445 *newval = pretty_value(ps, *cl);
2448 exception_override_warning((*cl)->var);
2451 if(sval)
2452 fs_give((void **) &sval);
2454 if(olddefval)
2455 fs_give((void **) &olddefval);
2457 return(rv);
2462 config_exit_cmd(unsigned int flags)
2464 return(screen_exit_cmd(flags, "Configuration"));
2469 simple_exit_cmd(unsigned int flags)
2471 return(2);
2476 * screen_exit_cmd - basic config/flag screen exit logic
2479 screen_exit_cmd(unsigned int flags, char *cmd)
2481 if(flags & CF_CHANGES){
2482 switch(want_to(EXIT_PMT, 'y', 'x', h_config_undo, WT_FLUSH_IN)){
2483 case 'y':
2484 q_status_message1(SM_ORDER,0,3,"%s changes saved", cmd);
2485 return(2);
2487 case 'n':
2488 q_status_message1(SM_ORDER,3,5,"No %s changes saved", cmd);
2489 return(10);
2491 case 'x': /* ^C */
2492 default :
2493 q_status_message(SM_ORDER,3,5,"Changes not yet saved");
2494 return(0);
2497 else
2498 return(2);
2505 void
2506 config_add_list(struct pine *ps, CONF_S **cl, char **ltmp, char ***newval, int after)
2508 int items, i;
2509 char *tmp, ***alval;
2510 CONF_S *ctmp;
2512 for(items = 0, i = 0; ltmp[i]; i++) /* count list items */
2513 items++;
2515 alval = ALVAL((*cl)->var, ew);
2517 if(alval && (*alval)){
2518 if((*alval)[0] && (*alval)[0][0]){
2520 * Since we were already a list, make room
2521 * for the new member[s] and fall thru to
2522 * actually fill them in below...
2524 for(i = 0; (*alval)[i]; i++)
2527 fs_resize((void **)alval, (i + items + 1) * sizeof(char *));
2530 * move the ones that will be bumped down to the bottom of the list
2532 for(; i >= (*cl)->varmem + (after?1:0); i--)
2533 (*alval)[i+items] = (*alval)[i];
2535 i = 0;
2537 else if(alval){
2538 (*cl)->varmem = 0;
2539 if(*alval)
2540 free_list_array(alval);
2542 *alval = (char **)fs_get((items+1)*sizeof(char *));
2543 memset((void *)(*alval), 0, (items+1)*sizeof(char *));
2544 (*alval)[0] = ltmp[0];
2545 if(newval)
2546 *newval = &(*cl)->value;
2548 if((*cl)->value)
2549 fs_give((void **)&(*cl)->value);
2551 i = 1;
2554 else if(alval){
2556 * since we were previously empty, we want
2557 * to replace the first CONF_S's value with
2558 * the first new value, and fill the other
2559 * in below if there's a list...
2561 * first, make sure we're at the beginning of this config
2562 * section and dump the config lines for the default list,
2563 * except for the first one, which we will over-write.
2565 *cl = (*cl)->varnamep;
2566 while((*cl)->next && (*cl)->next->varnamep == (*cl)->varnamep)
2567 snip_confline(&(*cl)->next);
2570 * now allocate the new user_val array and fill in the first entry.
2572 *alval = (char **)fs_get((items+1)*sizeof(char *));
2573 memset((void *)(*alval), 0, (items+1) * sizeof(char *));
2574 (*alval)[(*cl)->varmem=0] = ltmp[0];
2575 if(newval)
2576 *newval = &(*cl)->value;
2578 if((*cl)->value)
2579 fs_give((void **)&(*cl)->value);
2581 i = 1;
2585 * Make new cl's to fit in the new space. Move the value from the current
2586 * line if inserting before it, else leave it where it is.
2588 for(; i < items ; i++){
2589 (*alval)[i+(*cl)->varmem + (after?1:0)] = ltmp[i];
2590 tmp = (*cl)->value;
2591 new_confline(cl);
2592 if(after)
2593 (*cl)->value = NULL;
2594 else
2595 (*cl)->value = tmp;
2597 (*cl)->var = (*cl)->prev->var;
2598 (*cl)->valoffset = (*cl)->prev->valoffset;
2599 (*cl)->varoffset = (*cl)->prev->varoffset;
2600 (*cl)->headingp = (*cl)->prev->headingp;
2601 (*cl)->keymenu = (*cl)->prev->keymenu;
2602 (*cl)->help = (*cl)->prev->help;
2603 (*cl)->tool = (*cl)->prev->tool;
2604 (*cl)->varnamep = (*cl)->prev->varnamep;
2605 *cl = (*cl)->prev;
2606 if(!after)
2607 (*cl)->value = NULL;
2609 if(newval){
2610 if(after)
2611 *newval = &(*cl)->next->value;
2612 else
2613 *newval = &(*cl)->value;
2618 * now fix up varmem values and fill in new values that have been
2619 * left NULL
2621 for(ctmp = (*cl)->varnamep, i = 0;
2622 (*alval)[i];
2623 ctmp = ctmp->next, i++){
2624 ctmp->varmem = i;
2625 if(!ctmp->value){
2626 /* BUG: We should be able to do this without the temp
2627 * copy...
2629 char *ptmp = pretty_value(ps, ctmp);
2630 ctmp->value = (ctmp->varnamep->flags & CF_PRINTER) ? printer_name(ptmp) : cpystr(ptmp);
2631 fs_give((void **)&ptmp);
2640 void
2641 config_del_list_item(CONF_S **cl, char ***newval)
2643 char **bufp, ***alval;
2644 int i;
2645 CONF_S *ctmp;
2647 alval = ALVAL((*cl)->var, ew);
2649 if((*alval)[(*cl)->varmem + 1]){
2650 for(bufp = &(*alval)[(*cl)->varmem];
2651 (*bufp = *(bufp+1)) != NULL; bufp++)
2654 if(*cl == (*cl)->varnamep){ /* leading value */
2655 if((*cl)->value)
2656 fs_give((void **)&(*cl)->value);
2658 ctmp = (*cl)->next;
2659 (*cl)->value = ctmp->value;
2660 ctmp->value = NULL;
2662 else{
2663 ctmp = *cl; /* blast the confline */
2664 *cl = (*cl)->next;
2665 if(ctmp == opt_screen->top_line)
2666 opt_screen->top_line = *cl;
2669 snip_confline(&ctmp);
2671 for(ctmp = (*cl)->varnamep, i = 0; /* now fix up varmem values */
2672 (*alval)[i];
2673 ctmp = ctmp->next, i++)
2674 ctmp->varmem = i;
2676 else if((*cl)->varmem){ /* blasted last in list */
2677 ctmp = *cl;
2678 *cl = (*cl)->prev;
2679 if(ctmp == opt_screen->top_line)
2680 opt_screen->top_line = *cl;
2682 snip_confline(&ctmp);
2684 else{ /* blasted last remaining */
2685 if(alval && *alval)
2686 fs_give((void **)alval);
2688 *newval = &(*cl)->value;
2694 * feature list manipulation tool
2697 * returns: -1 on unrecognized cmd, 0 if no change, 1 if change
2700 checkbox_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
2702 int rv = 0;
2704 switch(cmd){
2705 case MC_TOGGLE: /* mark/unmark feature */
2706 if((*cl)->var == &ps->vars[V_FEATURE_LIST]){
2707 rv = 1;
2708 toggle_feature_bit(ps, (*cl)->varmem, (*cl)->var, *cl, 0);
2710 else
2711 q_status_message(SM_ORDER | SM_DING, 3, 6,
2712 "Programmer botch! Unknown checkbox type.");
2714 break;
2716 case MC_EXIT: /* exit */
2717 rv = config_exit_cmd(flags);
2718 break;
2720 default :
2721 rv = -1;
2722 break;
2725 return(rv);
2730 * simple radio-button style variable handler
2733 radiobutton_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
2735 char **apval;
2736 int rv = 0;
2737 NAMEVAL_S *rule = NULL;
2738 #ifndef _WINDOWS
2739 int old_uc, old_cs;
2740 CONF_S *ctmp;
2741 #endif
2743 apval = APVAL((*cl)->var, ew);
2745 switch(cmd){
2746 case MC_CHOICE : /* set/unset feature */
2748 if(fixed_var((*cl)->var, NULL, NULL)){
2749 if(((*cl)->var->post_user_val.p || (*cl)->var->main_user_val.p)
2750 && want_to(_("Delete old unused personal option setting"),
2751 'y', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
2752 delete_user_vals((*cl)->var);
2753 q_status_message(SM_ORDER, 0, 3, _("Deleted"));
2754 rv = 1;
2757 return(rv);
2760 if(standard_radio_var(ps, (*cl)->var) || (*cl)->var == startup_ptr){
2761 PTR_TO_RULEFUNC rulefunc;
2763 #ifndef _WINDOWS
2764 if((*cl)->var == &ps->vars[V_COLOR_STYLE]){
2765 old_uc = pico_usingcolor();
2766 old_cs = ps->color_style;
2768 #endif
2770 if((*cl)->var->cmdline_val.p)
2771 fs_give((void **)&(*cl)->var->cmdline_val.p);
2773 if(apval && *apval)
2774 fs_give((void **)apval);
2776 rulefunc = rulefunc_from_var(ps, (*cl)->var);
2777 if(rulefunc)
2778 rule = (*rulefunc)((*cl)->varmem);
2780 if(apval && rule)
2781 *apval = cpystr(S_OR_L(rule));
2783 cur_rule_value((*cl)->var, TRUE, TRUE);
2784 set_radio_pretty_vals(ps, cl);
2786 if((*cl)->var == &ps->vars[V_AB_SORT_RULE])
2787 addrbook_redo_sorts();
2788 else if((*cl)->var == &ps->vars[V_THREAD_DISP_STYLE]){
2789 clear_index_cache(ps->mail_stream, 0);
2791 else if((*cl)->var == &ps->vars[V_THREAD_INDEX_STYLE]){
2792 MAILSTREAM *m;
2793 int i;
2795 clear_index_cache(ps->mail_stream, 0);
2796 /* clear all hidden and collapsed flags */
2797 set_lflags(ps->mail_stream, ps->msgmap, MN_COLL | MN_CHID, 0);
2799 if(SEP_THRDINDX()
2800 && SORT_IS_THREADED(ps->msgmap)
2801 && unview_thread(ps, ps->mail_stream, ps->msgmap)){
2802 ps->next_screen = mail_index_screen;
2803 ps->view_skipped_index = 0;
2804 ps->mangled_screen = 1;
2807 if(SORT_IS_THREADED(ps->msgmap)
2808 && (SEP_THRDINDX() || COLL_THRDS()))
2809 collapse_threads(ps->mail_stream, ps->msgmap, NULL);
2811 for(i = 0; i < ps_global->s_pool.nstream; i++){
2812 m = ps_global->s_pool.streams[i];
2813 if(m)
2814 sp_set_viewing_a_thread(m, 0);
2817 adjust_cur_to_visible(ps->mail_stream, ps->msgmap);
2819 #ifndef _WINDOWS
2820 else if((*cl)->var == &ps->vars[V_COLOR_STYLE]){
2821 if(old_cs != ps->color_style){
2822 pico_toggle_color(0);
2823 switch(ps->color_style){
2824 case COL_NONE:
2825 case COL_TERMDEF:
2826 pico_set_color_options(pico_trans_color() ? COLOR_TRANS_OPT : 0);
2827 break;
2828 case COL_ANSI8:
2829 pico_set_color_options(COLOR_ANSI8_OPT|COLOR_TRANS_OPT);
2830 break;
2831 case COL_ANSI16:
2832 pico_set_color_options(COLOR_ANSI16_OPT|COLOR_TRANS_OPT);
2833 break;
2834 case COL_ANSI256:
2835 pico_set_color_options(COLOR_ANSI256_OPT|COLOR_TRANS_OPT);
2836 break;
2839 if(ps->color_style != COL_NONE)
2840 pico_toggle_color(1);
2843 if(pico_usingcolor())
2844 pico_set_normal_color();
2846 if(!old_uc && pico_usingcolor()){
2849 * remove the explanatory warning line and a blank line
2852 /* first find the first blank line */
2853 for(ctmp = *cl; ctmp; ctmp = next_confline(ctmp))
2854 if(ctmp->flags & CF_NOSELECT)
2855 break;
2857 if(ctmp && ctmp->flags & CF_NOSELECT &&
2858 ctmp->prev && !(ctmp->prev->flags & CF_NOSELECT) &&
2859 ctmp->next && ctmp->next->flags & CF_NOSELECT &&
2860 ctmp->next->next &&
2861 ctmp->next->next->flags & CF_NOSELECT){
2862 ctmp->prev->next = ctmp->next->next;
2863 ctmp->next->next->prev = ctmp->prev;
2864 ctmp->next->next = NULL;
2865 free_conflines(&ctmp);
2868 /* make all the colors selectable */
2869 for(ctmp = *cl; ctmp; ctmp = next_confline(ctmp))
2870 if(ctmp->flags & CF_POT_SLCTBL)
2871 ctmp->flags &= ~CF_NOSELECT;
2873 else if(old_uc && !pico_usingcolor()){
2876 * add the explanatory warning line and a blank line
2879 /* first find the existing blank line */
2880 for(ctmp = *cl; ctmp; ctmp = next_confline(ctmp))
2881 if(ctmp->flags & CF_NOSELECT)
2882 break;
2884 /* add the explanatory warning line */
2885 new_confline(&ctmp);
2886 ctmp->help = NO_HELP;
2887 ctmp->flags |= CF_NOSELECT;
2888 ctmp->value = cpystr(COLORNOSET);
2890 /* and add another blank line */
2891 new_confline(&ctmp);
2892 ctmp->flags |= (CF_NOSELECT | CF_B_LINE);
2894 /* make all the colors non-selectable */
2895 for(ctmp = *cl; ctmp; ctmp = next_confline(ctmp))
2896 if(ctmp->flags & CF_POT_SLCTBL)
2897 ctmp->flags |= CF_NOSELECT;
2900 clear_index_cache(ps->mail_stream, 0);
2901 ClearScreen();
2902 ps->mangled_screen = 1;
2904 #endif
2906 ps->mangled_body = 1; /* BUG: redraw it all for now? */
2907 rv = 1;
2909 else if((*cl)->var == &ps->vars[V_SORT_KEY]){
2910 SortOrder def_sort;
2911 int def_sort_rev;
2913 def_sort_rev = (*cl)->varmem >= (short) EndofList;
2914 def_sort = (SortOrder) ((*cl)->varmem - (def_sort_rev
2915 * EndofList));
2916 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s", sort_name(def_sort),
2917 (def_sort_rev) ? "/Reverse" : "");
2919 if((*cl)->var->cmdline_val.p)
2920 fs_give((void **)&(*cl)->var->cmdline_val.p);
2922 if(apval){
2923 if(*apval)
2924 fs_give((void **)apval);
2926 *apval = cpystr(tmp_20k_buf);
2929 set_current_val((*cl)->var, TRUE, TRUE);
2930 if(decode_sort(ps->VAR_SORT_KEY, &def_sort, &def_sort_rev) != -1){
2931 ps->def_sort = def_sort;
2932 ps->def_sort_rev = def_sort_rev;
2935 set_radio_pretty_vals(ps, cl);
2936 ps->mangled_body = 1; /* BUG: redraw it all for now? */
2937 rv = 1;
2939 else
2940 q_status_message(SM_ORDER | SM_DING, 3, 6,
2941 "Programmer botch! Unknown radiobutton type.");
2943 break;
2945 case MC_EXIT: /* exit */
2946 rv = config_exit_cmd(flags);
2947 break;
2949 default :
2950 rv = -1;
2951 break;
2954 if(rv == 1)
2955 exception_override_warning((*cl)->var);
2957 return(rv);
2962 * simple yes/no style variable handler
2965 yesno_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
2967 int rv = 0, yes = 0;
2968 char *pval, **apval;
2970 pval = PVAL((*cl)->var, ew);
2971 apval = APVAL((*cl)->var, ew);
2973 switch(cmd){
2974 case MC_TOGGLE: /* toggle yes to no and back */
2975 if(fixed_var((*cl)->var, NULL, NULL)){
2976 if(((*cl)->var->post_user_val.p || (*cl)->var->main_user_val.p)
2977 && want_to(_("Delete old unused personal option setting"),
2978 'y', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
2979 delete_user_vals((*cl)->var);
2980 q_status_message(SM_ORDER, 0, 3, _("Deleted"));
2981 rv = 1;
2984 return(rv);
2987 rv = 1;
2988 yes = ((pval && !strucmp(pval, yesstr)) ||
2989 (!pval && (*cl)->var->current_val.p &&
2990 !strucmp((*cl)->var->current_val.p, yesstr)));
2991 fs_give((void **)&(*cl)->value);
2993 if(apval){
2994 if(*apval)
2995 fs_give((void **)apval);
2997 if(yes)
2998 *apval = cpystr(nostr);
2999 else
3000 *apval = cpystr(yesstr);
3003 set_current_val((*cl)->var, FALSE, FALSE);
3004 if((*cl)->value)
3005 fs_give((void **)&(*cl)->value);
3007 (*cl)->value = pretty_value(ps, *cl);
3008 fix_side_effects(ps, (*cl)->var, 0);
3010 break;
3012 case MC_EXIT: /* exit */
3013 rv = config_exit_cmd(flags);
3014 break;
3016 default :
3017 rv = -1;
3018 break;
3021 return(rv);
3026 * Manage display of the config/options menu body.
3028 void
3029 update_option_screen(struct pine *ps, OPT_SCREEN_S *screen, Pos *cursor_pos)
3031 int dline, w, save = '\0';
3032 CONF_S *top_line, *ctmp;
3033 char *value;
3034 unsigned got_width;
3035 int want_width, first_width;
3036 char *saveptr = NULL;
3038 #ifdef _WINDOWS
3039 int last_selectable;
3040 mswin_beginupdate();
3041 #endif
3042 if(screen == NULL || BODY_LINES(ps) < 1)
3043 return;
3045 if(cursor_pos){
3046 cursor_pos->col = 0;
3047 cursor_pos->row = -1; /* to tell us if we've set it yet */
3051 * calculate top line of display for reframing if the current field
3052 * is off the display defined by screen->top_line...
3054 if((ctmp = screen->top_line) != NULL)
3055 for(dline = BODY_LINES(ps);
3056 dline && ctmp && ctmp != screen->current;
3057 ctmp = next_confline(ctmp), dline--)
3060 if(!ctmp || !dline){ /* force reframing */
3061 dline = 0;
3062 ctmp = top_line = first_confline(screen->current);
3064 if(((dline++)%BODY_LINES(ps)) == 0)
3065 top_line = ctmp;
3066 while(ctmp != screen->current && (ctmp = next_confline(ctmp)));
3068 else
3069 top_line = screen->top_line;
3071 #ifdef _WINDOWS
3073 * Figure out how far down the top line is from the top and how many
3074 * total lines there are. Dumb to loop every time thru, but
3075 * there aren't that many lines, and it's cheaper than rewriting things
3076 * to maintain a line count in each structure...
3078 for(dline = 0, ctmp = prev_confline(top_line); ctmp; ctmp = prev_confline(ctmp))
3079 dline++;
3081 scroll_setpos(dline);
3082 last_selectable = dline;
3083 for(ctmp = next_confline(top_line); ctmp ; ctmp = next_confline(ctmp)){
3084 dline++;
3085 if (!(ctmp->flags & CF_NOSELECT))
3086 last_selectable = dline;
3088 dline = last_selectable;
3089 scroll_setrange(BODY_LINES(ps), dline);
3090 #endif
3092 /* mangled body or new page, force redraw */
3093 if(ps->mangled_body || screen->top_line != top_line)
3094 screen->prev = NULL;
3096 /* loop thru painting what's needed */
3097 for(dline = 0, ctmp = top_line;
3098 dline < BODY_LINES(ps);
3099 dline++, ctmp = next_confline(ctmp)){
3102 * only fall thru painting if something needs painting...
3104 if(!(!screen->prev || ctmp == screen->prev || ctmp == screen->current
3105 || ctmp == screen->prev->varnamep
3106 || ctmp == screen->current->varnamep
3107 || ctmp == screen->prev->headingp
3108 || ctmp == screen->current->headingp))
3109 continue;
3111 ClearLine(dline + HEADER_ROWS(ps));
3113 if(ctmp){
3114 if(ctmp->flags & CF_B_LINE)
3115 continue;
3117 if(ctmp->varname && !(ctmp->flags & CF_INVISIBLEVAR)){
3118 if(ctmp == screen->current && cursor_pos)
3119 cursor_pos->row = dline + HEADER_ROWS(ps);
3121 if((ctmp == screen->current
3122 || ctmp == screen->current->varnamep
3123 || ctmp == screen->current->headingp)
3124 && !(ctmp->flags & CF_NOHILITE))
3125 StartInverse();
3127 if(ctmp->flags & CF_H_LINE){
3128 MoveCursor(dline + HEADER_ROWS(ps), 0);
3129 Write_to_screen(repeat_char(ps->ttyo->screen_cols, '-'));
3132 if(ctmp->flags & CF_CENTERED){
3133 int offset = ps->ttyo->screen_cols/2
3134 - (utf8_width(ctmp->varname)/2);
3135 MoveCursor(dline + HEADER_ROWS(ps),
3136 (offset > 0) ? offset : 0);
3138 else if(ctmp->varoffset)
3139 MoveCursor(dline+HEADER_ROWS(ps), ctmp->varoffset);
3141 Write_to_screen(ctmp->varname);
3142 if((ctmp == screen->current
3143 || ctmp == screen->current->varnamep
3144 || ctmp == screen->current->headingp)
3145 && !(ctmp->flags & CF_NOHILITE))
3146 EndInverse();
3149 value = (ctmp->flags & CF_INHERIT) ? INHERIT : ctmp->value;
3151 if(value){
3152 char *p;
3153 int i, j;
3155 memset(tmp_20k_buf, '\0',
3156 (6*ps->ttyo->screen_cols + 1) * sizeof(char));
3157 if(ctmp == screen->current){
3158 if(!(ctmp->flags & CF_DOUBLEVAR && ctmp->flags & CF_VAR2))
3159 StartInverse();
3161 if(cursor_pos)
3162 cursor_pos->row = dline + HEADER_ROWS(ps);
3165 if(ctmp->flags & CF_H_LINE)
3166 memset(tmp_20k_buf, '-',
3167 ps->ttyo->screen_cols * sizeof(char));
3169 if(ctmp->flags & CF_CENTERED){
3170 int offset = ps->ttyo->screen_cols/2
3171 - (utf8_width(value)/2);
3172 /* BUG: tabs screw us figuring length above */
3173 if(offset > 0){
3174 char *q;
3176 p = tmp_20k_buf + offset;
3177 if(!*(q = tmp_20k_buf))
3178 while(q < p)
3179 *q++ = ' ';
3182 else
3183 p = tmp_20k_buf;
3186 * Copy the value to a temp buffer expanding tabs, and
3187 * making sure not to write beyond screen right...
3189 for(i = 0, j = ctmp->valoffset; value[i]; i++){
3190 if(value[i] == ctrl('I')){
3192 *p++ = ' ';
3193 while((++j) & 0x07);
3195 else{
3196 *p++ = value[i];
3197 j++;
3201 if(ctmp == screen->current && cursor_pos){
3202 if(ctmp->flags & CF_DOUBLEVAR && ctmp->flags & CF_VAR2)
3203 cursor_pos->col = ctmp->val2offset;
3204 else
3205 cursor_pos->col = ctmp->valoffset;
3207 if(ctmp->tool == radiobutton_tool
3208 #ifdef ENABLE_LDAP
3209 || ctmp->tool==ldap_radiobutton_tool
3210 #endif
3211 || ctmp->tool==role_radiobutton_tool
3212 || ctmp->tool==checkbox_tool
3213 || (ctmp->tool==color_setting_tool &&
3214 ctmp->valoffset != COLOR_INDENT))
3215 cursor_pos->col++;
3218 if(ctmp->flags & CF_DOUBLEVAR){
3219 long l;
3221 p = tmp_20k_buf;
3222 first_width = ctmp->val2offset - ctmp->valoffset - SPACE_BETWEEN_DOUBLEVARS;
3223 if((l=utf8_width(p)) > first_width && first_width >= 0){
3224 saveptr = utf8_count_forw_width(p, first_width, &got_width);
3226 * got_width != first_width indicates there's a problem
3227 * that should not happen. Ignore it.
3229 if(saveptr){
3230 save = *saveptr;
3231 *saveptr = '\0';
3234 else
3235 save = '\0';
3238 * If this is a COLOR_BLOB line we do special coloring.
3239 * The current object inverse hilite is only on the
3240 * checkbox part, the exact format comes from the
3241 * new_color_line function. If we change that we'll have
3242 * to change this to get the coloring right.
3244 if(p[0] == '(' && p[2] == ')' &&
3245 p[3] == ' ' && p[4] == ' ' &&
3246 (!strncmp(p+5, COLOR_BLOB, COLOR_BLOB_LEN)
3247 || !strncmp(p+5, COLOR_BLOB_TRAN, COLOR_BLOB_LEN)
3248 || !strncmp(p+5, COLOR_BLOB_NORM, COLOR_BLOB_LEN))){
3249 COLOR_PAIR *lastc = NULL, *newc = NULL;
3251 MoveCursor(dline+HEADER_ROWS(ps), ctmp->valoffset);
3252 Write_to_screen_n(p, 3);
3253 if(!(ctmp->flags & CF_VAR2) && ctmp == screen->current)
3254 EndInverse();
3256 Write_to_screen_n(p+3, 3);
3257 newc = new_color_pair(colorx(CFC_ICOLOR(ctmp)),
3258 colorx(CFC_ICOLOR(ctmp)));
3259 if(newc){
3260 lastc = pico_get_cur_color();
3261 (void)pico_set_colorp(newc, PSC_NONE);
3262 free_color_pair(&newc);
3265 Write_to_screen_n(p+6, COLOR_BLOB_LEN-2);
3267 if(lastc){
3268 (void)pico_set_colorp(lastc, PSC_NONE);
3269 free_color_pair(&lastc);
3272 Write_to_screen(p+6+COLOR_BLOB_LEN-2);
3274 else{
3275 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset, p);
3276 if(!(ctmp->flags & CF_VAR2) && ctmp == screen->current)
3277 EndInverse();
3280 if(saveptr)
3281 *saveptr = save;
3283 PutLine0(dline+HEADER_ROWS(ps),
3284 ctmp->val2offset - SPACE_BETWEEN_DOUBLEVARS,
3285 repeat_char(SPACE_BETWEEN_DOUBLEVARS, SPACE));
3287 if(l > ctmp->val2offset - ctmp->valoffset && ctmp->val2offset - ctmp->valoffset >= 0)
3288 p = saveptr + SPACE_BETWEEN_DOUBLEVARS;
3290 if(p > tmp_20k_buf){
3291 if(ctmp->flags & CF_VAR2 && ctmp == screen->current)
3292 StartInverse();
3294 if(p[0] == '(' && p[2] == ')' &&
3295 p[3] == ' ' && p[4] == ' ' &&
3296 (!strncmp(p+5, COLOR_BLOB, COLOR_BLOB_LEN)
3297 || !strncmp(p+5, COLOR_BLOB_TRAN, COLOR_BLOB_LEN)
3298 || !strncmp(p+5, COLOR_BLOB_NORM, COLOR_BLOB_LEN))){
3299 COLOR_PAIR *lastc = NULL, *newc = NULL;
3301 MoveCursor(dline+HEADER_ROWS(ps), ctmp->val2offset);
3302 Write_to_screen_n(p, 3);
3303 if(ctmp->flags & CF_VAR2 && ctmp == screen->current)
3304 EndInverse();
3306 Write_to_screen_n(p+3, 3);
3307 newc = new_color_pair(colorx(CFC_ICOLOR(ctmp)),
3308 colorx(CFC_ICOLOR(ctmp)));
3309 if(newc){
3310 lastc = pico_get_cur_color();
3311 (void)pico_set_colorp(newc, PSC_NONE);
3312 free_color_pair(&newc);
3315 Write_to_screen_n(p+6, COLOR_BLOB_LEN-2);
3317 if(lastc){
3318 (void)pico_set_colorp(lastc, PSC_NONE);
3319 free_color_pair(&lastc);
3322 Write_to_screen(p+6+COLOR_BLOB_LEN-2);
3324 else{
3325 PutLine0(dline+HEADER_ROWS(ps),ctmp->val2offset,p);
3326 if(ctmp->flags & CF_VAR2 && ctmp == screen->current)
3327 EndInverse();
3331 else{
3332 char *q, *first_space, *sample, *ptr;
3333 COLOR_PAIR *lastc, *newc;
3334 int invert;
3337 if(ctmp->flags & CF_COLORSAMPLE &&
3338 pico_usingcolor() &&
3339 ((q = strstr(tmp_20k_buf, SAMPLE_LEADER)) ||
3340 (q = strstr(tmp_20k_buf, "Color"))) &&
3341 (first_space = strindex(q, SPACE)) &&
3342 (strstr(value, SAMP1) ||
3343 strstr(value, SAMP2))){
3345 ptr = tmp_20k_buf;
3347 /* write out first part */
3348 *first_space = '\0';
3349 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset,
3350 ptr);
3351 *first_space = SPACE;
3352 ptr = first_space;
3354 if(ctmp == screen->current)
3355 EndInverse();
3357 sample = skip_white_space(ptr);
3358 /* if there's enough room to put some sample up */
3359 save = *sample;
3360 *sample = '\0';
3361 w = utf8_width(tmp_20k_buf);
3362 *sample = save;
3363 if(ctmp->valoffset + w < ps->ttyo->screen_cols){
3365 sample++; /* for `[' at edge of sample */
3367 save = *ptr;
3368 *ptr = '\0';
3369 w = utf8_width(tmp_20k_buf);
3370 *ptr = save;
3372 save = *sample;
3373 *sample = '\0';
3374 /* spaces and bracket before sample1 */
3375 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset+w, ptr);
3376 *sample = save;
3378 ptr = sample;
3380 /* then the color sample */
3381 if(ctmp->var == &ps->vars[V_VIEW_HDR_COLORS]
3382 || ctmp->var == &ps->vars[V_INDEX_TOKEN_COLORS]){
3383 SPEC_COLOR_S *hc, *hcolors;
3385 lastc = newc = NULL;
3387 hcolors =
3388 spec_colors_from_varlist(LVAL(ctmp->var, ew),
3390 for(hc = hcolors, i=0; hc; hc = hc->next, i++)
3391 if(CFC_ICUST(ctmp) == i)
3392 break;
3394 if(hc && hc->fg && hc->fg[0] && hc->bg &&
3395 hc->bg[0])
3396 newc = new_color_pair(hc->fg, hc->bg);
3398 if(newc){
3399 lastc = pico_get_cur_color();
3400 (void)pico_set_colorp(newc, PSC_NONE);
3401 free_color_pair(&newc);
3404 if(hcolors)
3405 free_spec_colors(&hcolors);
3408 /* print out sample1 */
3410 save = *ptr;
3411 *ptr = '\0';
3412 w = utf8_width(tmp_20k_buf);
3413 *ptr = save;
3415 want_width = MIN(utf8_width(SAMP1)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3416 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3417 if(saveptr){
3418 save = *saveptr;
3419 *saveptr = '\0';
3422 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3423 if(saveptr)
3424 *saveptr = save;
3426 ptr = strindex(ptr, ']');
3428 if(lastc){
3429 (void)pico_set_colorp(lastc, PSC_NONE);
3430 free_color_pair(&lastc);
3433 else if(ctmp->var == &ps->vars[V_KW_COLORS]){
3434 KEYWORD_S *kw;
3435 SPEC_COLOR_S *kw_col = NULL;
3437 lastc = newc = NULL;
3439 /* find keyword associated with this line */
3440 for(kw=ps->keywords, i=0; kw; kw=kw->next, i++)
3441 if(CFC_ICUST(ctmp) == i)
3442 break;
3444 if(kw)
3445 kw_col =
3446 spec_colors_from_varlist(LVAL(ctmp->var,ew),
3449 /* color for this keyword */
3450 if(kw && kw_col
3451 && ((kw->nick && kw->nick[0]
3452 && (newc=hdr_color(kw->nick, NULL,
3453 kw_col)))
3455 (kw->kw && kw->kw[0]
3456 && (newc=hdr_color(kw->kw, NULL,
3457 kw_col))))){
3458 lastc = pico_get_cur_color();
3459 (void)pico_set_colorp(newc, PSC_NONE);
3460 free_color_pair(&newc);
3463 if(kw_col)
3464 free_spec_colors(&kw_col);
3466 /* print out sample1 */
3468 save = *ptr;
3469 *ptr = '\0';
3470 w = utf8_width(tmp_20k_buf);
3471 *ptr = save;
3473 want_width = MIN(utf8_width(SAMP1)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3474 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3475 if(saveptr){
3476 save = *saveptr;
3477 *saveptr = '\0';
3480 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3481 if(saveptr)
3482 *saveptr = save;
3484 ptr = strindex(ptr, ']');
3486 if(lastc){
3487 (void)pico_set_colorp(lastc, PSC_NONE);
3488 free_color_pair(&lastc);
3491 else{
3492 lastc = NULL;
3493 invert = 0;
3494 newc = sample_color(ps, ctmp->var);
3495 if(newc){
3496 if((lastc = pico_get_cur_color()) != NULL)
3497 (void)pico_set_colorp(newc, PSC_NONE);
3499 free_color_pair(&newc);
3501 else if(var_defaults_to_rev(ctmp->var)){
3502 if((newc = pico_get_rev_color()) != NULL){
3504 * Note, don't have to free newc.
3506 if((lastc = pico_get_cur_color()) != NULL)
3507 (void)pico_set_colorp(newc, PSC_NONE);
3509 else{
3510 StartInverse();
3511 invert = 1;
3515 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3517 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3518 !(PVAL(ctmp->var,ew) &&
3519 PVAL(ctmp->var+1,ew))))
3520 StartBold();
3522 /* print out sample1 */
3524 save = *ptr;
3525 *ptr = '\0';
3526 w = utf8_width(tmp_20k_buf);
3527 *ptr = save;
3529 want_width = MIN(utf8_width(SAMP1)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3530 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3531 if(saveptr){
3532 save = *saveptr;
3533 *saveptr = '\0';
3536 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3537 if(saveptr)
3538 *saveptr = save;
3540 ptr = strindex(ptr, ']');
3542 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3544 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3545 !(PVAL(ctmp->var,ew) &&
3546 PVAL(ctmp->var+1,ew))))
3547 EndBold();
3549 if(lastc){
3550 (void)pico_set_colorp(lastc, PSC_NONE);
3551 free_color_pair(&lastc);
3553 else if(invert)
3554 EndInverse();
3558 * Finish sample1 with the right bracket.
3560 save = *ptr;
3561 *ptr = '\0';
3562 w = utf8_width(tmp_20k_buf);
3563 *ptr = save;
3564 if(ctmp->valoffset + w < ps->ttyo->screen_cols){
3565 save = *(ptr+1);
3566 *(ptr+1) = '\0';
3567 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3568 *(ptr+1) = save;
3569 ptr++;
3570 w++;
3574 * Now check for an exception sample and paint it.
3576 if(ctmp->valoffset + w + SBS + 1 < ps->ttyo->screen_cols && (q = strstr(ptr, SAMPEXC))){
3577 /* spaces + `[' */
3578 save = ptr[SBS+1];
3579 ptr[SBS+1] = '\0';
3580 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3581 ptr[SBS+1] = save;
3582 ptr += (SBS+1);
3585 * Figure out what color to paint it.
3586 * This only happens with normal variables,
3587 * not with V_VIEW_HDR_COLORS.
3589 lastc = NULL;
3590 invert = 0;
3591 newc = sampleexc_color(ps, ctmp->var);
3592 if(newc){
3593 if((lastc = pico_get_cur_color()) != NULL)
3594 (void)pico_set_colorp(newc, PSC_NONE);
3596 free_color_pair(&newc);
3598 else if(var_defaults_to_rev(ctmp->var)){
3599 if((newc = pico_get_rev_color()) != NULL){
3601 * Note, don't have to free newc.
3603 if((lastc = pico_get_cur_color()) != NULL)
3604 (void)pico_set_colorp(newc, PSC_NONE);
3606 else{
3607 StartInverse();
3608 invert = 1;
3612 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3614 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3615 !(PVAL(ctmp->var,Post) &&
3616 PVAL(ctmp->var+1,Post))))
3617 StartBold();
3619 /* sample2 */
3620 save = *ptr;
3621 *ptr = '\0';
3622 w = utf8_width(tmp_20k_buf);
3623 *ptr = save;
3625 want_width = MIN(utf8_width(SAMPEXC)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3626 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3627 if(saveptr){
3628 save = *saveptr;
3629 *saveptr = '\0';
3632 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3633 if(saveptr)
3634 *saveptr = save;
3636 ptr = strindex(ptr, ']');
3638 /* turn off bold and color */
3639 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3641 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3642 !(PVAL(ctmp->var,Post) &&
3643 PVAL(ctmp->var+1,Post))))
3644 EndBold();
3646 if(lastc){
3647 (void)pico_set_colorp(lastc, PSC_NONE);
3648 free_color_pair(&lastc);
3650 else if(invert)
3651 EndInverse();
3654 * Finish sample2 with the right bracket.
3656 save = *ptr;
3657 *ptr = '\0';
3658 w = utf8_width(tmp_20k_buf);
3659 *ptr = save;
3660 if(ctmp->valoffset + w < ps->ttyo->screen_cols){
3661 save = *(ptr+1);
3662 *(ptr+1) = '\0';
3663 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3664 *(ptr+1) = save;
3665 ptr++;
3666 w++;
3670 /* paint rest of the line if there is any left */
3671 if(ctmp->valoffset + w < ps->ttyo->screen_cols && *ptr){
3672 want_width = ps->ttyo->screen_cols - w - ctmp->valoffset;
3673 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3674 if(saveptr){
3675 save = *saveptr;
3676 *saveptr = '\0';
3679 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3680 if(saveptr)
3681 *saveptr = save;
3685 else{
3686 w = utf8_width(tmp_20k_buf);
3687 want_width = ps->ttyo->screen_cols - ctmp->valoffset;
3688 if(w > want_width){
3689 saveptr = utf8_count_forw_width(tmp_20k_buf, want_width, &got_width);
3690 if(saveptr)
3691 *saveptr = '\0';
3694 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset, tmp_20k_buf);
3695 if(ctmp == screen->current)
3696 EndInverse();
3703 ps->mangled_body = 0;
3704 screen->top_line = top_line;
3705 screen->prev = screen->current;
3706 #ifdef _WINDOWS
3707 mswin_endupdate();
3708 #endif
3716 void
3717 print_option_screen(OPT_SCREEN_S *screen, char *prompt)
3719 CONF_S *ctmp;
3720 int so_far;
3721 char line[500];
3723 if(open_printer(prompt) == 0){
3724 for(ctmp = first_confline(screen->current);
3725 ctmp;
3726 ctmp = next_confline(ctmp)){
3728 so_far = 0;
3729 if(ctmp->varname && !(ctmp->flags & CF_INVISIBLEVAR)){
3731 snprintf(line, sizeof(line), "%*s%s", ctmp->varoffset, "",
3732 ctmp->varname);
3733 line[sizeof(line)-1] = '\0';
3734 print_text(line);
3735 so_far = ctmp->varoffset + utf8_width(ctmp->varname);
3738 if(ctmp && ctmp->value){
3739 char *p = tmp_20k_buf;
3740 int i, j, spaces;
3742 /* Copy the value to a temp buffer expanding tabs. */
3743 for(i = 0, j = ctmp->valoffset; ctmp->value[i]; i++){
3744 if(ctmp->value[i] == ctrl('I')){
3746 *p++ = ' ';
3747 while((++j) & 0x07);
3750 else{
3751 *p++ = ctmp->value[i];
3752 j++;
3756 *p = '\0';
3757 removing_trailing_white_space(tmp_20k_buf);
3759 spaces = MAX(ctmp->valoffset - so_far, 0);
3760 snprintf(line, sizeof(line), "%*s%s\n", spaces, "", tmp_20k_buf);
3761 line[sizeof(line)-1] = '\0';
3762 print_text(line);
3766 close_printer();
3775 void
3776 option_screen_redrawer(void)
3778 ps_global->mangled_body = 1;
3779 update_option_screen(ps_global, opt_screen, (Pos *)NULL);
3785 * pretty_value - given the line, return an
3786 * alloc'd string for line's value...
3788 char *
3789 pretty_value(struct pine *ps, CONF_S *cl)
3791 struct variable *v;
3793 v = cl->var;
3795 if(v == &ps->vars[V_FEATURE_LIST])
3796 return(checkbox_pretty_value(ps, cl));
3797 else if(standard_radio_var(ps, v) || v == startup_ptr)
3798 return(radio_pretty_value(ps, cl));
3799 else if(v == &ps->vars[V_SORT_KEY])
3800 return(sort_pretty_value(ps, cl));
3801 else if(v == &ps->vars[V_SIGNATURE_FILE])
3802 return(sigfile_pretty_value(ps, cl));
3803 else if(v == &ps->vars[V_USE_ONLY_DOMAIN_NAME])
3804 return(yesno_pretty_value(ps, cl));
3805 else if(color_holding_var(ps, v))
3806 return(color_pretty_value(ps, cl));
3807 else
3808 return(text_pretty_value(ps, cl));
3812 char *
3813 text_pretty_value(struct pine *ps, CONF_S *cl)
3815 char tmp[6*MAX_SCREEN_COLS+20], *pvalnorm, **lvalnorm, *pvalexc, **lvalexc;
3816 char *p, *pval, **lval, lastchar = '\0';
3817 int editing_except, fixed, uvalset, uvalposlen;
3818 unsigned got_width;
3819 int comments, except_set, avail_width;
3820 int norm_with_except = 0, norm_with_except_inherit = 0;
3821 int inherit_line = 0;
3823 editing_except = (ew == ps_global->ew_for_except_vars);
3824 fixed = cl->var->is_fixed;
3825 if((ps_global->ew_for_except_vars != Main) && (ew == Main))
3826 norm_with_except++; /* editing normal and except config exists */
3828 if(cl->var->is_list){
3829 lvalnorm = LVAL(cl->var, Main);
3830 lvalexc = LVAL(cl->var, ps_global->ew_for_except_vars);
3831 if(editing_except){
3832 uvalset = lvalexc != NULL;
3833 uvalposlen = uvalset && lvalexc[0] && lvalexc[0][0];
3834 lval = lvalexc;
3836 else{
3837 uvalset = lvalnorm != NULL;
3838 uvalposlen = uvalset && lvalnorm[0] && lvalnorm[0][0];
3839 lval = lvalnorm;
3842 except_set = lvalexc != NULL;
3843 comments = cl->var->current_val.l != NULL;
3844 if(norm_with_except && except_set && lvalexc[0] &&
3845 !strcmp(lvalexc[0],INHERIT))
3846 norm_with_except_inherit++;
3848 if(uvalset && !strcmp(lval[0], INHERIT)){
3849 if(cl->varmem == 0){
3850 inherit_line++;
3851 comments = 0;
3855 /* only add extra comments on last member of list */
3856 if(uvalset && !inherit_line && lval && lval[cl->varmem] &&
3857 lval[cl->varmem + 1])
3858 comments = 0;
3860 else{
3861 pvalnorm = PVAL(cl->var, Main);
3862 pvalexc = PVAL(cl->var, ps_global->ew_for_except_vars);
3863 if(editing_except){
3864 uvalset = pvalexc != NULL;
3865 uvalposlen = uvalset && *pvalexc;
3866 pval = pvalexc;
3868 else{
3869 uvalset = pvalnorm != NULL;
3870 uvalposlen = uvalset && *pvalnorm;
3871 pval = pvalnorm;
3874 except_set = pvalexc != NULL;
3875 comments = cl->var->current_val.p != NULL;
3878 memset(tmp, 0, sizeof(tmp));
3879 p = tmp;
3880 *p = '\0';
3882 avail_width = ps->ttyo->screen_cols - cl->valoffset;
3884 if(fixed || !uvalset || !uvalposlen){
3885 p += utf8_to_width(p, "<", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3886 avail_width -= got_width;
3889 if(fixed){
3890 p += utf8_to_width(p, _(fixed_val), sizeof(tmp)-(p-tmp), avail_width, &got_width);
3891 avail_width -= got_width;
3893 else if(!uvalset){
3894 p += utf8_to_width(p, _(no_val), sizeof(tmp)-(p-tmp), avail_width, &got_width);
3895 avail_width -= got_width;
3897 else if(!uvalposlen){
3898 p += utf8_to_width(p, _(empty_val), sizeof(tmp)-(p-tmp), avail_width, &got_width);
3899 avail_width -= got_width;
3901 else if(inherit_line){
3902 p += utf8_to_width(p, INHERIT, sizeof(tmp)-(p-tmp), avail_width, &got_width);
3903 avail_width -= got_width;
3905 else{
3906 if(cl->var->is_list){
3907 p += utf8_to_width(p, lval[cl->varmem], sizeof(tmp)-(p-tmp), avail_width, &got_width);
3908 avail_width -= got_width;
3910 else{
3911 p += utf8_to_width(p, pval, sizeof(tmp)-(p-tmp), avail_width, &got_width);
3912 avail_width -= got_width;
3916 if(comments && (fixed || !uvalset || (norm_with_except && except_set))){
3917 if(fixed || !uvalset){
3918 p += utf8_to_width(p, ": using ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3919 avail_width -= got_width;
3922 if(norm_with_except && except_set){
3923 if(!uvalset){
3924 p += utf8_to_width(p, "exception ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3925 avail_width -= got_width;
3927 else if(!fixed){
3928 if(!uvalposlen){
3929 p += utf8_to_width(p, ": ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3930 avail_width -= got_width;
3932 else{
3933 p += utf8_to_width(p, " (", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3934 avail_width -= got_width;
3937 if(norm_with_except_inherit){
3938 p += utf8_to_width(p, "added to by exception ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3939 avail_width -= got_width;
3941 else{
3942 p += utf8_to_width(p, "overridden by exception ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3943 avail_width -= got_width;
3948 if(avail_width >= 7){
3949 if(cl->var == &ps_global->vars[V_POST_CHAR_SET]){
3950 p += utf8_to_width(p, "most specific (see help)", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3951 avail_width -= got_width;
3953 else{
3954 sstrncpy(&p, "\"", sizeof(tmp)-(p-tmp));
3955 avail_width--;
3956 if(cl->var->is_list){
3957 char **the_list;
3959 the_list = cl->var->current_val.l;
3961 if(norm_with_except && except_set)
3962 the_list = lvalexc;
3964 if(the_list && the_list[0] && !strcmp(the_list[0], INHERIT))
3965 the_list++;
3967 for(lval = the_list; avail_width-(p-tmp) > 0 && *lval; lval++){
3968 if(lval != the_list){
3969 p += utf8_to_width(p, ",", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3970 avail_width -= got_width;
3973 p += utf8_to_width(p, *lval, sizeof(tmp)-(p-tmp), avail_width, &got_width);
3974 avail_width -= got_width;
3977 else{
3978 p += utf8_to_width(p, cl->var->current_val.p, sizeof(tmp)-(p-tmp), avail_width, &got_width);
3979 avail_width -= got_width;
3982 if(p-tmp+2 < sizeof(tmp)){
3983 *p++ = '\"';
3984 *p = '\0';
3988 else if(*(p-1) == SPACE)
3989 *--p = '\0';
3992 tmp[sizeof(tmp)-1] = '\0';
3994 if(fixed || !uvalset || !uvalposlen)
3995 lastchar = '>';
3996 else if(comments && norm_with_except && except_set)
3997 lastchar = ')';
3999 if(lastchar){
4000 if(p-tmp+2 < sizeof(tmp)){
4001 *p++ = lastchar;
4002 *p = '\0';
4006 tmp[sizeof(tmp)-1] = '\0';
4007 avail_width = ps->ttyo->screen_cols - cl->valoffset;
4009 if(utf8_width(tmp) < avail_width)
4010 snprintf(tmp+strlen(tmp), sizeof(tmp)-strlen(tmp), "%*s", avail_width-utf8_width(tmp), "");
4012 tmp[sizeof(tmp)-1] = '\0';
4014 return(cpystr(tmp));
4018 char *
4019 checkbox_pretty_value(struct pine *ps, CONF_S *cl)
4021 char tmp[6*MAXPATH];
4022 char *comment = NULL;
4023 int indent, x, screen_width, need;
4024 int longest_featname, longest_comment;
4025 int nwidcomm; /* name width with comment */
4026 int nwidnocomm; /* and without comment */
4027 FEATURE_S *feature;
4029 screen_width = (ps && ps->ttyo) ? ps->ttyo->screen_cols : 80;
4030 tmp[0] = '\0';
4032 longest_featname = longest_feature_name();
4033 longest_comment = longest_feature_comment(ps, ew);
4034 indent = feature_indent();
4036 nwidcomm = longest_featname;
4037 nwidnocomm = longest_featname + 2 + longest_comment;
4039 if((need = (indent + 5 + longest_featname + 2 + longest_comment) - screen_width) > 0){
4040 if(need < 10){
4041 nwidcomm -= need;
4042 nwidnocomm -= need;
4044 else{
4045 longest_comment = 0;
4046 nwidnocomm = longest_featname;
4050 feature = feature_list(cl->varmem);
4052 x = feature_gets_an_x(ps, cl->var, feature, &comment, ew);
4054 if(longest_comment && comment && *comment){
4055 utf8_snprintf(tmp, sizeof(tmp), "[%c] %-*.*w %-*.*w", x ? 'X' : ' ',
4056 nwidcomm, nwidcomm,
4057 pretty_feature_name(feature->name, nwidcomm),
4058 longest_comment, longest_comment, comment ? comment : "");
4060 else{
4061 utf8_snprintf(tmp, sizeof(tmp), "[%c] %-*.*w", x ? 'X' : ' ',
4062 nwidnocomm, nwidnocomm,
4063 pretty_feature_name(feature->name, nwidnocomm));
4066 return(cpystr(tmp));
4071 longest_feature_name(void)
4073 static int lv = -1;
4074 int i, j;
4075 FEATURE_S *feature;
4077 if(lv < 0){
4078 for(lv = 0, i = 0; (feature = feature_list(i)); i++)
4079 if(feature_list_section(feature)
4080 && lv < (j = utf8_width(pretty_feature_name(feature->name, -1))))
4081 lv = j;
4083 lv = MIN(lv, 100);
4086 return(lv);
4091 feature_indent(void)
4093 return(6);
4097 char *
4098 yesno_pretty_value(struct pine *ps, CONF_S *cl)
4100 char tmp[6*MAXPATH], *pvalnorm, *pvalexc;
4101 char *p, *pval, lastchar = '\0';
4102 int editing_except, fixed, norm_with_except, uvalset;
4103 int curval, except_set;
4105 editing_except = (ew == ps_global->ew_for_except_vars);
4106 fixed = cl->var->is_fixed;
4107 if((ps_global->ew_for_except_vars == Main) ||
4108 (ew == ps_global->ew_for_except_vars))
4109 norm_with_except = 0;
4110 else
4111 norm_with_except = 1; /* editing normal and except config exists */
4113 pvalnorm = PVAL(cl->var, Main);
4114 pvalexc = PVAL(cl->var, ps_global->ew_for_except_vars);
4115 if(editing_except){
4116 uvalset = (pvalexc != NULL &&
4117 (!strucmp(pvalexc,yesstr) || !strucmp(pvalexc,nostr)));
4118 pval = pvalexc;
4120 else{
4121 uvalset = (pvalnorm != NULL &&
4122 (!strucmp(pvalnorm,yesstr) || !strucmp(pvalnorm,nostr)));
4123 pval = pvalnorm;
4126 except_set = (pvalexc != NULL &&
4127 (!strucmp(pvalexc,yesstr) || !strucmp(pvalexc,nostr)));
4128 curval = (cl->var->current_val.p != NULL &&
4129 (!strucmp(cl->var->current_val.p,yesstr) ||
4130 !strucmp(cl->var->current_val.p,nostr)));
4132 p = tmp;
4133 *p = '\0';
4135 if(fixed || !uvalset)
4136 sstrncpy(&p, "<", sizeof(tmp)-(p-tmp));
4138 if(fixed)
4139 sstrncpy(&p, _(fixed_val), sizeof(tmp)-(p-tmp));
4140 else if(!uvalset)
4141 sstrncpy(&p, _(no_val), sizeof(tmp)-(p-tmp));
4142 else if(!strucmp(pval, yesstr))
4143 sstrncpy(&p, yesstr, sizeof(tmp)-(p-tmp));
4144 else
4145 sstrncpy(&p, nostr, sizeof(tmp)-(p-tmp));
4147 if(curval && (fixed || !uvalset || (norm_with_except && except_set))){
4148 if(fixed || !uvalset)
4149 sstrncpy(&p, ": using ", sizeof(tmp)-(p-tmp));
4151 if(norm_with_except && except_set){
4152 if(!uvalset)
4153 sstrncpy(&p, "exception ", sizeof(tmp)-(p-tmp));
4154 else if(!fixed){
4155 sstrncpy(&p, " (", sizeof(tmp)-(p-tmp));
4156 sstrncpy(&p, "overridden by exception ", sizeof(tmp)-(p-tmp));
4160 sstrncpy(&p, "\"", sizeof(tmp)-(p-tmp));
4161 sstrncpy(&p, !strucmp(cl->var->current_val.p,yesstr) ? yesstr : nostr, sizeof(tmp)-(p-tmp));
4162 sstrncpy(&p, "\"", sizeof(tmp)-(p-tmp));
4165 if(fixed || !uvalset)
4166 lastchar = '>';
4167 else if(curval && norm_with_except && except_set)
4168 lastchar = ')';
4170 if(lastchar && sizeof(tmp)-(p-tmp) > 1){
4171 *p++ = lastchar;
4172 *p = '\0';
4175 tmp[sizeof(tmp)-1] = '\0';
4177 if(utf8_width(tmp) < ps->ttyo->screen_cols - cl->valoffset)
4178 snprintf(tmp+strlen(tmp), sizeof(tmp)-strlen(tmp),
4179 "%*s", ps->ttyo->screen_cols - cl->valoffset - utf8_width(tmp), "");
4181 tmp[sizeof(tmp)-1] = '\0';
4183 return(cpystr(tmp));
4187 char *
4188 radio_pretty_value(struct pine *ps, CONF_S *cl)
4190 char tmp[6*MAXPATH];
4191 char *pvalnorm, *pvalexc, *pval;
4192 int editing_except_which_isnt_normal, editing_normal_which_isnt_except;
4193 int fixed, is_set_for_this_level = 0, is_the_one, the_exc_one;
4194 int i, j, lv = 0;
4195 NAMEVAL_S *rule = NULL, *f;
4196 PTR_TO_RULEFUNC rulefunc;
4197 struct variable *v;
4199 tmp[0] = '\0';
4200 v = cl->var;
4202 editing_except_which_isnt_normal = (ew == ps_global->ew_for_except_vars &&
4203 ew != Main);
4204 editing_normal_which_isnt_except = (ew == Main &&
4205 ew != ps_global->ew_for_except_vars);
4206 fixed = cl->var->is_fixed;
4207 pvalnorm = PVAL(v, Main);
4208 pvalexc = PVAL(v, ps_global->ew_for_except_vars);
4210 rulefunc = rulefunc_from_var(ps, v);
4211 rule = rulefunc ? (*rulefunc)(cl->varmem) : NULL;
4213 /* find longest name */
4214 if(rulefunc)
4215 for(lv = 0, i = 0; (f = (*rulefunc)(i)); i++)
4216 if(lv < (j = utf8_width(f->name)))
4217 lv = j;
4219 lv = MIN(lv, 100);
4221 if(editing_except_which_isnt_normal)
4222 pval = pvalexc;
4223 else
4224 pval = pvalnorm;
4226 if(pval)
4227 is_set_for_this_level++;
4229 if(fixed){
4230 pval = v->fixed_val.p;
4231 is_the_one = (pval && !strucmp(pval, S_OR_L(rule)));
4233 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4234 is_the_one ? R_SELD : ' ',
4235 lv, lv, rule->name, is_the_one ? " (value is fixed)" : "");
4237 else if(is_set_for_this_level){
4238 is_the_one = (pval && !strucmp(pval, S_OR_L(rule)));
4239 the_exc_one = (editing_normal_which_isnt_except && pvalexc &&
4240 !strucmp(pvalexc, S_OR_L(rule)));
4241 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4242 is_the_one ? R_SELD : ' ',
4243 lv, lv, rule->name,
4244 (!is_the_one && the_exc_one) ? " (value set in exceptions)" :
4245 (is_the_one && the_exc_one) ? " (also set in exceptions)" :
4246 (is_the_one &&
4247 editing_normal_which_isnt_except &&
4248 pvalexc &&
4249 !the_exc_one) ? " (overridden by exceptions)" :
4250 "");
4252 else{
4253 if(pvalexc){
4254 is_the_one = !strucmp(pvalexc, S_OR_L(rule));
4255 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4256 is_the_one ? R_SELD : ' ',
4257 lv, lv, rule->name,
4258 is_the_one ? " (value set in exceptions)" : "");
4260 else{
4261 pval = v->current_val.p;
4262 is_the_one = (pval && !strucmp(pval, S_OR_L(rule)));
4263 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4264 is_the_one ? R_SELD : ' ',
4265 lv, lv, rule->name,
4266 is_the_one ? ((editing_except_which_isnt_normal && pvalnorm) ? " (default from regular config)" : " (default)") : "");
4270 tmp[sizeof(tmp)-1] = '\0';
4272 return(cpystr(tmp));
4276 char *
4277 sigfile_pretty_value(struct pine *ps, CONF_S *cl)
4279 if(cl && cl->var == &ps->vars[V_SIGNATURE_FILE] &&
4280 cl->prev && cl->prev->var == &ps->vars[V_LITERAL_SIG]){
4281 if(cl->prev->var->current_val.p){
4282 cl->flags |= CF_NOSELECT; /* side effect */
4283 return(cpystr(_("<Ignored: using Literal-Signature instead>")));
4285 else{
4286 cl->flags &= ~CF_NOSELECT;
4287 return(text_pretty_value(ps, cl));
4290 else
4291 return(cpystr(""));
4295 char *
4296 color_pretty_value(struct pine *ps, CONF_S *cl)
4298 char tmp[6*MAXPATH];
4299 char *p, *q;
4300 struct variable *v;
4301 int is_index;
4303 tmp[0] = '\0';
4304 v = cl->var;
4306 if(v && color_holding_var(ps, v) &&
4307 (p=srchstr(v->name, "-foreground-color"))){
4309 is_index = !struncmp(v->name, "index-", 6);
4311 q = sampleexc_text(ps, v);
4312 utf8_snprintf(tmp, sizeof(tmp), "%c%.*s %sColor%*.50s %.20w%*s%.20w%.20w",
4313 islower((unsigned char)v->name[0])
4314 ? toupper((unsigned char)v->name[0])
4315 : v->name[0],
4316 MIN(p-v->name-1,30), v->name+1,
4317 is_index ? "Symbol " : "",
4318 MAX(EQ_COL - COLOR_INDENT -1 - MIN(p-v->name-1,30)
4319 - 6 - (is_index ? 7 : 0) - 1,0), "",
4320 sample_text(ps,v), *q ? SBS : 0, "", q,
4321 color_parenthetical(v));
4324 tmp[sizeof(tmp)-1] = '\0';
4326 return(cpystr(tmp));
4330 char *
4331 sort_pretty_value(struct pine *ps, CONF_S *cl)
4333 return(generalized_sort_pretty_value(ps, cl, 1));
4337 char *
4338 generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok)
4340 char tmp[6*MAXPATH];
4341 char *pvalnorm, *pvalexc, *pval;
4342 int editing_except_which_isnt_normal, editing_normal_which_isnt_except;
4343 int fixed, is_set_for_this_level = 0, is_the_one, the_exc_one;
4344 int i, j, lv = 0;
4345 struct variable *v;
4346 SortOrder line_sort, var_sort, exc_sort;
4347 int line_sort_rev, var_sort_rev, exc_sort_rev;
4349 tmp[0] = '\0';
4350 v = cl->var;
4352 editing_except_which_isnt_normal = (ew == ps_global->ew_for_except_vars &&
4353 ew != Main);
4354 editing_normal_which_isnt_except = (ew == Main &&
4355 ew != ps_global->ew_for_except_vars);
4356 fixed = cl->var->is_fixed;
4357 pvalnorm = PVAL(v, Main);
4358 pvalexc = PVAL(v, ps_global->ew_for_except_vars);
4360 /* find longest value's name */
4361 for(lv = 0, i = 0; ps->sort_types[i] != EndofList; i++)
4362 if(lv < (j = utf8_width(sort_name(ps->sort_types[i]))))
4363 lv = j;
4365 lv = MIN(lv, 100);
4367 if(editing_except_which_isnt_normal)
4368 pval = pvalexc;
4369 else
4370 pval = pvalnorm;
4372 if(pval)
4373 is_set_for_this_level++;
4375 /* the config line we're talking about */
4376 if(cl->varmem >= 0){
4377 line_sort_rev = cl->varmem >= (short)EndofList;
4378 line_sort = (SortOrder)(cl->varmem - (line_sort_rev * EndofList));
4381 if(cl->varmem < 0){
4382 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*w",
4383 (pval == NULL) ? R_SELD : ' ',
4384 lv, "Default");
4386 else if(fixed){
4387 pval = v->fixed_val.p;
4388 decode_sort(pval, &var_sort, &var_sort_rev);
4389 is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
4391 utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s",
4392 is_the_one ? R_SELD : ' ',
4393 line_sort_rev ? "Reverse " : "",
4394 lv, sort_name(line_sort),
4395 line_sort_rev ? 0 : 8, "",
4396 is_the_one ? " (value is fixed)" : "");
4398 else if(is_set_for_this_level){
4399 decode_sort(pval, &var_sort, &var_sort_rev);
4400 is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
4401 decode_sort(pvalexc, &exc_sort, &exc_sort_rev);
4402 the_exc_one = (editing_normal_which_isnt_except && pvalexc &&
4403 exc_sort_rev == line_sort_rev && exc_sort == line_sort);
4404 utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s",
4405 is_the_one ? R_SELD : ' ',
4406 line_sort_rev ? "Reverse " : "",
4407 lv, sort_name(line_sort),
4408 line_sort_rev ? 0 : 8, "",
4409 (!is_the_one && the_exc_one) ? " (value set in exceptions)" :
4410 (is_the_one && the_exc_one) ? " (also set in exceptions)" :
4411 (is_the_one &&
4412 editing_normal_which_isnt_except &&
4413 pvalexc &&
4414 !the_exc_one) ? " (overridden by exceptions)" :
4415 "");
4417 else{
4418 if(pvalexc){
4419 decode_sort(pvalexc, &exc_sort, &exc_sort_rev);
4420 is_the_one = (exc_sort_rev == line_sort_rev &&
4421 exc_sort == line_sort);
4422 utf8_snprintf(tmp, sizeof(tmp), "( ) %s%-*w%*s%s",
4423 line_sort_rev ? "Reverse " : "",
4424 lv, sort_name(line_sort),
4425 line_sort_rev ? 0 : 8, "",
4426 is_the_one ? " (value set in exceptions)" : "");
4428 else{
4429 pval = v->current_val.p;
4430 decode_sort(pval, &var_sort, &var_sort_rev);
4431 is_the_one = ((pval || default_ok) &&
4432 var_sort_rev == line_sort_rev &&
4433 var_sort == line_sort);
4434 utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s",
4435 is_the_one ? R_SELD : ' ',
4436 line_sort_rev ? "Reverse " : "",
4437 lv, sort_name(line_sort),
4438 line_sort_rev ? 0 : 8, "",
4439 is_the_one ? ((editing_except_which_isnt_normal && pvalnorm) ? " (default from regular config)" : " (default)") : "");
4443 return(cpystr(tmp));
4447 COLOR_PAIR *
4448 sample_color(struct pine *ps, struct variable *v)
4450 COLOR_PAIR *cp = NULL;
4451 char *pvalefg, *pvalebg;
4452 char *pvalmfg, *pvalmbg;
4454 pvalefg = PVAL(v, ew);
4455 pvalebg = PVAL(v+1, ew);
4456 pvalmfg = PVAL(v, Main);
4457 pvalmbg = PVAL(v+1, Main);
4458 if(v && color_holding_var(ps, v) &&
4459 srchstr(v->name, "-foreground-color")){
4460 if(pvalefg && pvalefg[0] && pvalebg && pvalebg[0])
4461 cp = new_color_pair(pvalefg, pvalebg);
4462 else if(ew == Post && pvalmfg && pvalmfg[0] && pvalmbg && pvalmbg[0])
4463 cp = new_color_pair(pvalmfg, pvalmbg);
4464 else if(v->global_val.p && v->global_val.p[0] &&
4465 (v+1)->global_val.p && (v+1)->global_val.p[0])
4466 cp = new_color_pair(v->global_val.p, (v+1)->global_val.p);
4469 return(cp);
4473 COLOR_PAIR *
4474 sampleexc_color(struct pine *ps, struct variable *v)
4476 COLOR_PAIR *cp = NULL;
4477 char *pvalfg, *pvalbg;
4479 pvalfg = PVAL(v, Post);
4480 pvalbg = PVAL(v+1, Post);
4481 if(v && color_holding_var(ps, v) &&
4482 srchstr(v->name, "-foreground-color") &&
4483 pvalfg && pvalfg[0] && pvalbg && pvalbg[0])
4484 cp = new_color_pair(pvalfg, pvalbg);
4486 return(cp);
4490 void
4491 clear_feature(char ***l, char *f)
4493 char **list = l ? *l : NULL;
4494 int count = 0;
4496 for(; list && *list; list++, count++){
4497 if(f && !strucmp(((!struncmp(*list,"no-",3)) ? *list + 3 : *list), f)){
4498 fs_give((void **)list);
4499 f = NULL;
4502 if(!f) /* shift */
4503 *list = *(list + 1);
4507 * this is helpful to keep the array from growing if a feature
4508 * get's set and unset repeatedly
4510 if(!f)
4511 fs_resize((void **)l, count * sizeof(char *));
4518 void
4519 toggle_feature_bit(struct pine *ps, int index, struct variable *var, CONF_S *cl, int just_flip_value)
4521 FEATURE_S *f;
4522 int og, on_before;
4523 char *p, **vp;
4525 f = feature_list(index);
4527 og = test_old_growth_bits(ps, f->id);
4530 * if this feature is in the fixed set, or old-growth is in the fixed
4531 * set and this feature is in the old-growth set, don't alter it...
4533 for(vp = var->fixed_val.l; vp && *vp; vp++){
4534 p = (struncmp(*vp, "no-", 3)) ? *vp : *vp + 3;
4535 if(!strucmp(p, f->name) || (og && !strucmp(p, "old-growth"))){
4536 q_status_message(SM_ORDER, 3, 3,
4537 _("Can't change value fixed by sys-admin."));
4538 return;
4542 on_before = F_ON(f->id, ps);
4544 toggle_feature(ps, var, f, just_flip_value, ew);
4547 * Handle any alpine-specific features that need attention here. Features
4548 * that aren't alpine-specific should be handled in toggle_feature instead.
4550 if(on_before != F_ON(f->id, ps))
4551 switch(f->id){
4552 case F_CMBND_ABOOK_DISP :
4553 addrbook_reset();
4554 break;
4556 case F_PRESERVE_START_STOP :
4557 /* toggle raw mode settings to make tty driver aware of new setting */
4558 PineRaw(0);
4559 PineRaw(1);
4560 break;
4562 case F_USE_FK :
4563 ps->orig_use_fkeys = F_ON(F_USE_FK, ps);
4564 ps->mangled_footer = 1;
4565 mark_keymenu_dirty();
4566 break;
4568 case F_SHOW_SORT :
4569 ps->mangled_header = 1;
4570 break;
4572 case F_BLANK_KEYMENU :
4573 if(F_ON(f->id, ps)){
4574 FOOTER_ROWS(ps) = 1;
4575 ps->mangled_body = 1;
4577 else{
4578 FOOTER_ROWS(ps) = 3;
4579 ps->mangled_footer = 1;
4582 clearfooter(ps);
4583 break;
4585 case F_ENABLE_INCOMING :
4586 q_status_message(SM_ORDER | SM_DING, 3, 4,
4587 "Folder List changes will take effect your next Alpine session.");
4588 break;
4590 #ifdef _WINDOWS
4591 case F_SHOW_CURSOR :
4592 mswin_showcaret(F_ON(f->id,ps));
4593 break;
4595 case F_ENABLE_TRAYICON :
4596 mswin_trayicon(F_ON(f->id,ps));
4597 break;
4598 #endif
4600 #if !defined(DOS) && !defined(OS2)
4601 case F_ALLOW_TALK :
4602 if(F_ON(f->id, ps))
4603 allow_talk(ps);
4604 else
4605 disallow_talk(ps);
4607 break;
4608 #endif
4610 case F_PASS_CONTROL_CHARS :
4611 ps->pass_ctrl_chars = F_ON(F_PASS_CONTROL_CHARS,ps_global) ? 1 : 0;
4612 break;
4614 case F_USE_CERT_STORE_ONLY:
4615 if(F_OFF(F_USE_CERT_STORE_ONLY, ps))
4616 q_status_message(SM_ORDER | SM_DING, 3, 4,
4617 "Disabling this feature should only be done for testing. Press \"?\" for help");
4618 break;
4620 case F_PASS_C1_CONTROL_CHARS :
4621 ps->pass_c1_ctrl_chars = F_ON(F_PASS_C1_CONTROL_CHARS,ps_global) ? 1 : 0;
4622 break;
4624 #ifdef MOUSE
4625 case F_ENABLE_MOUSE :
4626 if(F_ON(f->id, ps)){
4627 init_mouse();
4628 if(!mouseexist())
4629 q_status_message(SM_ORDER | SM_DING, 3, 4,
4630 "Mouse tracking still off ($DISPLAY variable set?)");
4632 else
4633 end_mouse();
4635 break;
4636 #endif
4639 if(just_flip_value){
4640 if(cl->value && cl->value[0])
4641 cl->value[1] = (cl->value[1] == ' ') ? 'X' : ' ';
4643 else{
4645 * This fork is only called from the checkbox_tool, which has
4646 * varmem set to index correctly and cl->var set correctly.
4648 if(cl->value)
4649 fs_give((void **)&cl->value);
4651 cl->value = pretty_value(ps, cl);
4657 * new_confline - create new CONF_S zero it out, and insert it after current.
4658 * NOTE current gets set to the new CONF_S too!
4660 CONF_S *
4661 new_confline(CONF_S **current)
4663 CONF_S *p;
4665 p = (CONF_S *)fs_get(sizeof(CONF_S));
4666 memset((void *)p, 0, sizeof(CONF_S));
4667 if(current){
4668 if(*current){
4669 p->next = (*current)->next;
4670 (*current)->next = p;
4671 p->prev = *current;
4672 if(p->next)
4673 p->next->prev = p;
4676 *current = p;
4679 return(p);
4686 void
4687 snip_confline(CONF_S **p)
4689 CONF_S *q;
4692 * Be careful. We need this line because the
4693 * q->prev->next = ...
4694 * may change q itself if &q == &q->prev->next.
4695 * Then the use of q in the next line is wrong.
4696 * That's what happens if we pass in the address of
4697 * some ->next and use *p directly instead of q.
4699 q = *p;
4701 if(q){
4702 /* Yank it from the linked list */
4703 if(q->prev)
4704 q->prev->next = q->next;
4706 if(q->next)
4707 q->next->prev = q->prev;
4709 /* Then free up it's memory */
4710 q->prev = q->next = NULL;
4711 free_conflines(&q);
4719 void
4720 free_conflines(CONF_S **p)
4722 if(*p){
4723 free_conflines(&(*p)->next);
4725 if((*p)->varname)
4726 fs_give((void **) &(*p)->varname);
4728 if((*p)->value)
4729 fs_give((void **) &(*p)->value);
4731 fs_give((void **) p);
4739 CONF_S *
4740 first_confline(CONF_S *p)
4742 while(p && p->prev)
4743 p = p->prev;
4745 return(p);
4750 * First selectable confline.
4752 CONF_S *
4753 first_sel_confline(CONF_S *p)
4755 for(p = first_confline(p); p && (p->flags&CF_NOSELECT); p=next_confline(p))
4756 ;/* do nothing */
4758 return(p);
4765 CONF_S *
4766 last_confline(CONF_S *p)
4768 while(p && p->next)
4769 p = p->next;
4771 return(p);
4779 fixed_var(struct variable *v, char *action, char *name)
4781 char **lval;
4783 if(v && v->is_fixed
4784 && (!v->is_list
4785 || ((lval=v->fixed_val.l) && lval[0]
4786 && strcmp(INHERIT, lval[0]) != 0))){
4787 q_status_message2(SM_ORDER, 3, 3,
4788 "Can't %s sys-admin defined %s.",
4789 action ? action : "change", name ? name : "value");
4790 return(1);
4793 return(0);
4797 void
4798 exception_override_warning(struct variable *v)
4800 char **lval;
4802 /* if exceptions config file exists and we're not editing it */
4803 if(v && (ps_global->ew_for_except_vars != Main) && (ew == Main)){
4804 if((!v->is_list && PVAL(v, ps_global->ew_for_except_vars)) ||
4805 (v->is_list && (lval=LVAL(v, ps_global->ew_for_except_vars)) &&
4806 lval[0] && strcmp(INHERIT, lval[0]) != 0))
4807 q_status_message1(SM_ORDER, 3, 3,
4808 _("Warning: \"%s\" is overridden in your exceptions configuration"),
4809 v->name);
4814 void
4815 offer_to_fix_pinerc(struct pine *ps)
4817 struct variable *v;
4818 char prompt[300];
4819 char *p, *q;
4820 char **list;
4821 char **list_fixed;
4822 int rv = 0, write_main = 0, write_post = 0;
4823 int i, k, j, need, exc;
4824 char *clear = ": delete it";
4825 char ***plist;
4827 dprint((4, "offer_to_fix_pinerc()\n"));
4829 ps->fix_fixed_warning = 0; /* so we only ask first time */
4831 if(ps->readonly_pinerc)
4832 return;
4834 set_titlebar(_("FIXING PINERC"), ps->mail_stream,
4835 ps->context_current,
4836 ps->cur_folder, ps->msgmap, 1, FolderName, 0, 0, NULL);
4838 if(want_to(_("Some of your options conflict with site policy. Investigate"),
4839 'y', 'n', NO_HELP, WT_FLUSH_IN) != 'y')
4840 return;
4842 /* space want_to requires in addition to the string you pass in */
4843 #define WANTTO_SPACE 6
4844 need = WANTTO_SPACE + utf8_width(clear);
4846 for(v = ps->vars; v->name; v++){
4847 if(!v->is_fixed ||
4848 !v->is_user ||
4849 v->is_obsolete ||
4850 v == &ps->vars[V_FEATURE_LIST]) /* handle feature-list below */
4851 continue;
4853 prompt[0] = '\0';
4855 if(v->is_list &&
4856 (v->post_user_val.l || v->main_user_val.l)){
4857 char **active_list;
4859 active_list = v->post_user_val.l ? v->post_user_val.l
4860 : v->main_user_val.l;
4861 if(*active_list){
4862 snprintf(prompt, sizeof(prompt), _("Your setting for %s is "), v->name);
4863 prompt[sizeof(prompt)-1] = '\0';
4864 p = prompt + strlen(prompt);
4865 for(i = 0; active_list[i]; i++){
4866 if(utf8_width(prompt) > ps->ttyo->screen_cols - need)
4867 break;
4868 if(i && sizeof(prompt)-(p-prompt) > 0)
4869 *p++ = ',';
4871 sstrncpy(&p, active_list[i], sizeof(prompt)-(p-prompt));
4872 if(sizeof(prompt)-(p-prompt) > 0)
4873 *p = '\0';
4875 prompt[sizeof(prompt)-1] = '\0';
4878 if(sizeof(prompt)-(p-prompt) > 0)
4879 *p = '\0';
4881 else
4882 snprintf(prompt, sizeof(prompt), _("Your setting for %s is %s"), v->name, _(empty_val2));
4884 else{
4885 if(v->post_user_val.p || v->main_user_val.p){
4886 char *active_var;
4888 active_var = v->post_user_val.p ? v->post_user_val.p
4889 : v->main_user_val.p;
4890 if(*active_var){
4891 snprintf(prompt, sizeof(prompt), _("Your setting for %s is %s"),
4892 v->name, active_var);
4894 else{
4895 snprintf(prompt, sizeof(prompt), _("Your setting for %s is %s"),
4896 v->name, _(empty_val2));
4901 prompt[sizeof(prompt)-1] = '\0';
4903 if(*prompt){
4904 if(utf8_width(prompt) > ps->ttyo->screen_cols - need)
4905 (void) utf8_truncate(prompt, ps->ttyo->screen_cols - need);
4907 (void) strncat(prompt, clear, sizeof(prompt)-strlen(prompt)-1);
4908 prompt[sizeof(prompt)-1] = '\0';
4909 if(want_to(prompt, 'y', 'n', NO_HELP, WT_NORM) == 'y'){
4910 if(v->is_list){
4911 if(v->main_user_val.l)
4912 write_main++;
4913 if(v->post_user_val.l)
4914 write_post++;
4916 else{
4917 if(v->main_user_val.p)
4918 write_main++;
4919 if(v->post_user_val.p)
4920 write_post++;
4923 if(delete_user_vals(v))
4924 rv++;
4931 * As always, feature-list has to be handled separately.
4933 exc = (ps->ew_for_except_vars != Main);
4934 v = &ps->vars[V_FEATURE_LIST];
4935 list_fixed = v->fixed_val.l;
4937 for(j = 0; j < 2; j++){
4938 plist = (j==0) ? &v->main_user_val.l : &v->post_user_val.l;
4939 list = *plist;
4940 if(list){
4941 for(i = 0; list[i]; i++){
4942 p = list[i];
4943 if(!struncmp(p, "no-", 3))
4944 p += 3;
4945 for(k = 0; list_fixed && list_fixed[k]; k++){
4946 q = list_fixed[k];
4947 if(!struncmp(q, "no-", 3))
4948 q += 3;
4949 if(!strucmp(q, p) && strucmp(list[i], list_fixed[k])){
4950 snprintf(prompt, sizeof(prompt), "Your %s is %s%s, fixed value is %s",
4951 p, p == list[i] ? _("ON") : _("OFF"),
4952 exc ? ((plist == &v->main_user_val.l) ? ""
4953 : " in postload-config")
4954 : "",
4955 q == list_fixed[k] ? _("ON") : _("OFF"));
4957 prompt[sizeof(prompt)-1] = '\0';
4958 if(utf8_width(prompt) > ps->ttyo->screen_cols - need)
4959 (void) utf8_truncate(prompt, ps->ttyo->screen_cols - need);
4961 (void) strncat(prompt, clear, sizeof(prompt)-strlen(prompt)-1);
4962 prompt[sizeof(prompt)-1] = '\0';
4963 if(want_to(prompt, 'y', 'n', NO_HELP, WT_NORM) == 'y'){
4964 rv++;
4966 if(plist == &v->main_user_val.l)
4967 write_main++;
4968 else
4969 write_post++;
4972 * Clear the feature from the user's pinerc
4973 * so that we'll stop bothering them when they
4974 * start up Pine.
4976 clear_feature(plist, p);
4979 * clear_feature scoots the list up, so if list[i] was
4980 * the last one going in, now it is the end marker. We
4981 * just decrement i so that it will get incremented and
4982 * then test == 0 in the for loop. We could just goto
4983 * outta_here to accomplish the same thing.
4985 if(!list[i])
4986 i--;
4995 if(write_main)
4996 write_pinerc(ps, Main, WRP_NONE);
4997 if(write_post)
4998 write_pinerc(ps, Post, WRP_NONE);
5000 return;
5005 * Adjust side effects that happen because variable changes values.
5007 * Var->user_val should be set to the new value before calling this.
5009 void
5010 fix_side_effects(struct pine *ps, struct variable *var, int revert)
5012 int val = 0;
5013 char **v, *q, **apval;
5014 struct variable *vars = ps->vars;
5016 /* move this up here so we get the Using default message */
5017 if(var == &ps->vars[V_PERSONAL_NAME]){
5018 if(!(var->main_user_val.p ||
5019 var->post_user_val.p) && ps->ui.fullname){
5020 if(var->current_val.p)
5021 fs_give((void **)&var->current_val.p);
5023 var->current_val.p = cpystr(ps->ui.fullname);
5027 if(!revert
5028 && ((!var->is_fixed
5029 && !var->is_list
5030 && !(var->main_user_val.p ||
5031 var->post_user_val.p)
5032 && var->current_val.p)
5034 (!var->is_fixed
5035 && var->is_list
5036 && !(var->main_user_val.l ||
5037 var->post_user_val.l)
5038 && var->current_val.l)))
5039 q_status_message(SM_ORDER,0,3,_("Using default value"));
5041 if(var == &ps->vars[V_USER_DOMAIN]){
5042 char *p, *q;
5044 if(ps->VAR_USER_DOMAIN
5045 && ps->VAR_USER_DOMAIN[0]
5046 && (p = strrindex(ps->VAR_USER_DOMAIN, '@'))){
5047 if(*(++p)){
5048 if(!revert)
5049 q_status_message2(SM_ORDER, 3, 5,
5050 _("User-Domain (%s) cannot contain \"@\"; using %s"),
5051 ps->VAR_USER_DOMAIN, p);
5052 q = ps->VAR_USER_DOMAIN;
5053 while((*q++ = *p++) != '\0')
5054 ;/* do nothing */
5056 else{
5057 if(!revert)
5058 q_status_message1(SM_ORDER, 3, 5,
5059 _("User-domain (%s) cannot contain \"@\"; deleting"),
5060 ps->VAR_USER_DOMAIN);
5062 if(ps->vars[V_USER_DOMAIN].post_user_val.p){
5063 fs_give((void **)&ps->vars[V_USER_DOMAIN].post_user_val.p);
5064 set_current_val(&vars[V_USER_DOMAIN], TRUE, TRUE);
5067 if(ps->VAR_USER_DOMAIN
5068 && ps->VAR_USER_DOMAIN[0]
5069 && (p = strrindex(ps->VAR_USER_DOMAIN, '@'))){
5070 if(ps->vars[V_USER_DOMAIN].main_user_val.p){
5071 fs_give((void **)&ps->vars[V_USER_DOMAIN].main_user_val.p);
5072 set_current_val(&vars[V_USER_DOMAIN], TRUE, TRUE);
5079 * Reset various pointers pertaining to domain name and such...
5081 init_hostname(ps);
5083 else if(var == &ps->vars[V_INBOX_PATH]){
5085 * fixup the inbox path based on global/default values...
5087 init_inbox_mapping(ps->VAR_INBOX_PATH, ps->context_list);
5089 if(!strucmp(ps->cur_folder, ps->inbox_name) && ps->mail_stream
5090 && strcmp(ps->VAR_INBOX_PATH, ps->mail_stream->mailbox)){
5092 * If we currently have "inbox" open and the mailbox name
5093 * doesn't match, reset the current folder's name and
5094 * remove the SP_INBOX flag.
5096 strncpy(ps->cur_folder, ps->mail_stream->mailbox,
5097 sizeof(ps->cur_folder)-1);
5098 ps->cur_folder[sizeof(ps->cur_folder)-1] = '\0';
5099 sp_set_fldr(ps->mail_stream, ps->cur_folder);
5100 sp_unflag(ps->mail_stream, SP_INBOX);
5101 ps->mangled_header = 1;
5103 else if(sp_inbox_stream()
5104 && strcmp(ps->VAR_INBOX_PATH, sp_inbox_stream()->original_mailbox)){
5105 MAILSTREAM *m = sp_inbox_stream();
5108 * if we don't have inbox directly open, but have it
5109 * open for new mail notification, close the stream like
5110 * any other ordinary folder, and clean up...
5112 if(m){
5113 sp_unflag(m, SP_PERMLOCKED | SP_INBOX);
5114 sp_set_fldr(m, m->mailbox);
5115 expunge_and_close(m, NULL, EC_NONE);
5119 else if(var == &ps->vars[V_INCCHECKTIMEO]){
5120 int old_value = ps->inc_check_timeout;
5122 if(SVAR_INC_CHECK_TIMEO(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5123 if(!revert)
5124 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5126 else
5127 ps->inc_check_timeout = old_value;
5129 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5130 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5132 else if(var == &ps->vars[V_INCCHECKINTERVAL]){
5133 int old_value = ps->inc_check_interval;
5135 if(SVAR_INC_CHECK_INTERV(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5136 if(!revert)
5137 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5139 else
5140 ps->inc_check_interval = old_value;
5142 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5143 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5145 else if(var == &ps->vars[V_INC2NDCHECKINTERVAL]){
5146 int old_value = ps->inc_second_check_interval;
5148 if(SVAR_INC_2NDCHECK_INTERV(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5149 if(!revert)
5150 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5152 else
5153 ps->inc_second_check_interval = old_value;
5155 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5156 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5158 else if(var == &ps->vars[V_INCCHECKLIST]){
5159 if(ps->context_list && ps->context_list->use & CNTXT_INCMNG)
5160 reinit_incoming_folder_list(ps, ps->context_list);
5162 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5163 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5165 else if(var == &ps->vars[V_ADDRESSBOOK] ||
5166 var == &ps->vars[V_GLOB_ADDRBOOK] ||
5167 #ifdef ENABLE_LDAP
5168 var == &ps->vars[V_LDAP_SERVERS] ||
5169 #endif
5170 var == &ps->vars[V_ABOOK_FORMATS]){
5171 addrbook_reset();
5173 else if(var == &ps->vars[V_INDEX_FORMAT]){
5174 reset_index_format();
5175 clear_index_cache(ps->mail_stream, 0);
5177 else if(var == &ps->vars[V_DEFAULT_FCC] ||
5178 var == &ps->vars[V_DEFAULT_SAVE_FOLDER]){
5179 init_save_defaults();
5181 else if(var == &ps->vars[V_KW_BRACES] ||
5182 var == &ps->vars[V_OPENING_SEP] ||
5183 var == &ps->vars[V_ALT_ADDRS]){
5184 clear_index_cache(ps->mail_stream, 0);
5186 else if(var == &ps->vars[V_KEYWORDS]){
5187 if(ps_global->keywords)
5188 free_keyword_list(&ps_global->keywords);
5190 if(var->current_val.l && var->current_val.l[0])
5191 ps_global->keywords = init_keyword_list(var->current_val.l);
5193 clear_index_cache(ps->mail_stream, 0);
5195 else if(var == &ps->vars[V_INIT_CMD_LIST]){
5196 if(!revert)
5197 q_status_message(SM_ASYNC, 0, 3,
5198 _("Initial command changes will affect your next Alpine session."));
5200 else if(var == &ps->vars[V_VIEW_HEADERS]){
5201 ps->view_all_except = 0;
5202 if(ps->VAR_VIEW_HEADERS)
5203 for(v = ps->VAR_VIEW_HEADERS; (q = *v) != NULL; v++)
5204 if(q[0]){
5205 char *p;
5207 removing_leading_white_space(q);
5208 /* look for colon or space or end */
5209 for(p = q; *p && !isspace((unsigned char)*p) && *p != ':'; p++)
5210 ;/* do nothing */
5212 *p = '\0';
5213 if(strucmp(q, ALL_EXCEPT) == 0)
5214 ps->view_all_except = 1;
5217 else if(var == &ps->vars[V_OVERLAP]){
5218 int old_value = ps->viewer_overlap;
5220 if(SVAR_OVERLAP(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5221 if(!revert)
5222 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5224 else
5225 ps->viewer_overlap = old_value;
5227 else if(var == &ps->vars[V_SLEEP]){
5228 int old_value = ps->sleep;
5230 if(SVAR_SLEEP(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5231 if(!revert)
5232 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5234 else
5235 ps->sleep = old_value;
5237 #ifdef SMIME
5238 else if(smime_related_var(ps, var)){
5239 smime_deinit();
5241 #endif /* SMIME */
5242 else if(var == &ps->vars[V_MAXREMSTREAM]){
5243 int old_value = ps->s_pool.max_remstream;
5245 if(SVAR_MAXREMSTREAM(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5246 if(!revert )
5247 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5249 else
5250 ps->s_pool.max_remstream = old_value;
5252 dprint((9, "max_remstream goes to %d\n",
5253 ps->s_pool.max_remstream));
5255 #ifndef _WINDOWS
5256 else if(var == &ps->vars[V_CHAR_SET]){
5257 char *err = NULL;
5259 if(F_ON(F_USE_SYSTEM_TRANS, ps)){
5260 if(!revert)
5261 q_status_message(SM_ORDER, 5, 5, _("This change has no effect because feature Use-System-Translation is on"));
5263 else{
5264 if(reset_character_set_stuff(&err) == -1)
5265 panic(err ? err : "trouble with Character-Set");
5266 else if(err){
5267 q_status_message(SM_ORDER | SM_DING, 3, 5, err);
5268 fs_give((void **) &err);
5272 else if(var == &ps->vars[V_KEY_CHAR_SET]){
5273 char *err = NULL;
5275 if(F_ON(F_USE_SYSTEM_TRANS, ps)){
5276 if(!revert)
5277 q_status_message(SM_ORDER, 5, 5, _("This change has no effect because feature Use-System-Translation is on"));
5279 else{
5280 if(reset_character_set_stuff(&err) == -1)
5281 panic(err ? err : "trouble with Character-Set");
5282 else if(err){
5283 q_status_message(SM_ORDER | SM_DING, 3, 5, err);
5284 fs_give((void **) &err);
5288 #endif /* ! _WINDOWS */
5289 else if(var == &ps->vars[V_POST_CHAR_SET]){
5290 update_posting_charset(ps, revert);
5292 else if(var == &ps->vars[V_MARGIN]){
5293 int old_value = ps->scroll_margin;
5295 if(SVAR_MARGIN(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5296 if(!revert)
5297 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5299 else
5300 ps->scroll_margin = old_value;
5302 else if(var == &ps->vars[V_DEADLETS]){
5303 int old_value = ps->deadlets;
5305 if(SVAR_DEADLETS(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5306 if(!revert)
5307 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5309 else
5310 ps->deadlets = old_value;
5312 else if(var == &ps->vars[V_FILLCOL]){
5313 if(SVAR_FILLCOL(ps, ps->composer_fillcol, tmp_20k_buf, SIZEOF_20KBUF)){
5314 if(!revert)
5315 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5318 else if(var == &ps->vars[V_QUOTE_SUPPRESSION]){
5319 val = ps->quote_suppression_threshold;
5320 if(val < Q_SUPP_LIMIT && val > 0)
5321 val = -val;
5323 if(ps->VAR_QUOTE_SUPPRESSION
5324 && SVAR_QUOTE_SUPPRESSION(ps, val, tmp_20k_buf, SIZEOF_20KBUF)){
5325 if(!revert)
5326 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5328 else{
5329 if(val > 0 && val < Q_SUPP_LIMIT){
5330 if(!revert){
5331 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Ignoring Quote-Suppression-Threshold value of %s, see help"), ps->VAR_QUOTE_SUPPRESSION);
5332 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
5333 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5336 else{
5337 if(val < 0 && val != Q_DEL_ALL)
5338 ps->quote_suppression_threshold = -val;
5339 else
5340 ps->quote_suppression_threshold = val;
5344 else if(var == &ps->vars[V_STATUS_MSG_DELAY]){
5345 if(SVAR_MSGDLAY(ps, ps->status_msg_delay, tmp_20k_buf, SIZEOF_20KBUF)){
5346 if(!revert)
5347 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5350 else if(var == &ps->vars[V_ACTIVE_MSG_INTERVAL]){
5351 if(SVAR_ACTIVEINTERVAL(ps, ps->active_status_interval, tmp_20k_buf, SIZEOF_20KBUF)){
5352 if(!revert)
5353 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5355 else{
5356 busy_cue(_("Active Example"), NULL, 0);
5357 sleep(5);
5358 cancel_busy_cue(-1);
5361 #if !defined(DOS) && !defined(OS2) && !defined(LEAVEOUTFIFO)
5362 else if(var == &ps->vars[V_FIFOPATH]){
5363 init_newmailfifo(ps->VAR_FIFOPATH);
5365 #endif
5366 else if(var == &ps->vars[V_NMW_WIDTH]){
5367 int old_value = ps->nmw_width;
5369 if(SVAR_NMW_WIDTH(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5370 if(!revert )
5371 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5373 else{
5374 #ifdef _WINDOWS
5375 if(old_value != ps->nmw_width)
5376 mswin_setnewmailwidth(old_value); /* actually the new value */
5377 #endif
5378 ps->nmw_width = old_value;
5381 else if(var == &ps->vars[V_TCPOPENTIMEO]){
5382 val = 30;
5383 if(!revert)
5384 if(ps->VAR_TCPOPENTIMEO && SVAR_TCP_OPEN(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5385 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5387 else if(var == &ps->vars[V_TCPREADWARNTIMEO]){
5388 val = 15;
5389 if(!revert)
5390 if(ps->VAR_TCPREADWARNTIMEO && SVAR_TCP_READWARN(ps,val,tmp_20k_buf, SIZEOF_20KBUF))
5391 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5393 else if(var == &ps->vars[V_TCPWRITEWARNTIMEO]){
5394 val = 0;
5395 if(!revert)
5396 if(ps->VAR_TCPWRITEWARNTIMEO && SVAR_TCP_WRITEWARN(ps,val,tmp_20k_buf, SIZEOF_20KBUF))
5397 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5399 else if(var == &ps->vars[V_TCPQUERYTIMEO]){
5400 val = 60;
5401 if(!revert)
5402 if(ps->VAR_TCPQUERYTIMEO && SVAR_TCP_QUERY(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5403 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5405 else if(var == &ps->vars[V_RSHOPENTIMEO]){
5406 val = 15;
5407 if(!revert)
5408 if(ps->VAR_RSHOPENTIMEO && SVAR_RSH_OPEN(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5409 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5411 else if(var == &ps->vars[V_SSHOPENTIMEO]){
5412 val = 15;
5413 if(!revert)
5414 if(ps->VAR_SSHOPENTIMEO && SVAR_SSH_OPEN(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5415 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5417 else if(var == &ps->vars[V_SIGNATURE_FILE]){
5418 if(ps->VAR_OPER_DIR && ps->VAR_SIGNATURE_FILE &&
5419 is_absolute_path(ps->VAR_SIGNATURE_FILE) &&
5420 !in_dir(ps->VAR_OPER_DIR, ps->VAR_SIGNATURE_FILE)){
5421 char *e;
5422 size_t l;
5424 l = strlen(ps->VAR_OPER_DIR) + 100;
5425 e = (char *) fs_get((l+1) * sizeof(char));
5426 snprintf(e, l+1, _("Warning: Sig file can't be outside of %s"),
5427 ps->VAR_OPER_DIR);
5428 e[l] = '\0';
5429 q_status_message(SM_ORDER, 3, 6, e);
5430 fs_give((void **)&e);
5433 else if(var == &ps->vars[V_OPER_DIR]){
5434 if(ps->VAR_OPER_DIR && !ps->VAR_OPER_DIR[0]){
5435 q_status_message(SM_ORDER, 3, 5, "Operating-dir is turned off.");
5436 fs_give((void **)&ps->vars[V_OPER_DIR].current_val.p);
5437 if(ps->vars[V_OPER_DIR].fixed_val.p)
5438 fs_give((void **)&ps->vars[V_OPER_DIR].fixed_val.p);
5439 if(ps->vars[V_OPER_DIR].global_val.p)
5440 fs_give((void **)&ps->vars[V_OPER_DIR].global_val.p);
5441 if(ps->vars[V_OPER_DIR].cmdline_val.p)
5442 fs_give((void **)&ps->vars[V_OPER_DIR].cmdline_val.p);
5443 if(ps->vars[V_OPER_DIR].post_user_val.p)
5444 fs_give((void **)&ps->vars[V_OPER_DIR].post_user_val.p);
5445 if(ps->vars[V_OPER_DIR].main_user_val.p)
5446 fs_give((void **)&ps->vars[V_OPER_DIR].main_user_val.p);
5449 else if(var == &ps->vars[V_MAILCHECK]){
5450 int timeo = 15;
5451 if(SVAR_MAILCHK(ps, timeo, tmp_20k_buf, SIZEOF_20KBUF)){
5452 set_input_timeout(15);
5453 if(!revert)
5454 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5456 else{
5457 set_input_timeout(timeo);
5458 if(get_input_timeout() == 0 && !revert){
5459 q_status_message(SM_ORDER, 4, 6,
5460 _("Warning: automatic new mail checking and mailbox checkpointing is disabled"));
5461 if(ps->VAR_INBOX_PATH && ps->VAR_INBOX_PATH[0] == '{')
5462 q_status_message(SM_ASYNC, 3, 6,
5463 _("Warning: Mail-Check-Interval=0 may cause IMAP server connection to time out"));
5467 else if(var == &ps->vars[V_MAILCHECKNONCURR]){
5468 val = (int) ps->check_interval_for_noncurr;
5469 if(ps->VAR_MAILCHECKNONCURR
5470 && SVAR_MAILCHKNONCURR(ps, val, tmp_20k_buf, SIZEOF_20KBUF)){
5471 if(!revert)
5472 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5474 else
5475 ps->check_interval_for_noncurr = (time_t) val;
5477 else if(var == &ps->vars[V_MAILDROPCHECK]){
5478 long rvl;
5480 rvl = 60L;
5481 if(ps->VAR_MAILDROPCHECK && SVAR_MAILDCHK(ps, rvl, tmp_20k_buf, SIZEOF_20KBUF))
5482 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5483 else{
5484 if(rvl == 0L)
5485 rvl = (60L * 60L * 24L * 100L); /* 100 days */
5487 if(rvl >= 60L)
5488 mail_parameters(NULL, SET_SNARFINTERVAL, (void *) rvl);
5491 else if(var == &ps->vars[V_NNTPRANGE]){
5492 long rvl;
5494 rvl = 0L;
5495 if(ps->VAR_NNTPRANGE && SVAR_NNTPRANGE(ps, rvl, tmp_20k_buf, SIZEOF_20KBUF))
5496 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5497 else{
5498 if(rvl >= 0L)
5499 mail_parameters(NULL, SET_NNTPRANGE, (void *) rvl);
5502 else if(var == &ps->vars[V_CUSTOM_HDRS] || var == &ps->vars[V_COMP_HDRS]){
5503 /* this will give warnings about headers that can't be changed */
5504 if(!revert && var->current_val.l && var->current_val.l[0])
5505 customized_hdr_setup(NULL, var->current_val.l, UseAsDef);
5507 #if defined(DOS) || defined(OS2)
5508 else if(var == &ps->vars[V_FOLDER_EXTENSION]){
5509 mail_parameters(NULL, SET_EXTENSION,
5510 (void *)var->current_val.p);
5512 else if(var == &ps->vars[V_NEWSRC_PATH]){
5513 if(var->current_val.p && var->current_val.p[0])
5514 mail_parameters(NULL, SET_NEWSRC,
5515 (void *)var->current_val.p);
5517 #endif
5518 else if(revert && standard_radio_var(ps, var)){
5520 cur_rule_value(var, TRUE, FALSE);
5521 if(var == &ps_global->vars[V_AB_SORT_RULE])
5522 addrbook_redo_sorts();
5523 else if(var == &ps_global->vars[V_THREAD_INDEX_STYLE]){
5524 clear_index_cache(ps_global->mail_stream, 0);
5525 set_lflags(ps_global->mail_stream, ps_global->msgmap,
5526 MN_COLL | MN_CHID, 0);
5527 if(SORT_IS_THREADED(ps_global->msgmap)
5528 && (SEP_THRDINDX() || COLL_THRDS()))
5529 collapse_threads(ps_global->mail_stream, ps_global->msgmap, NULL);
5531 adjust_cur_to_visible(ps_global->mail_stream, ps_global->msgmap);
5533 #ifndef _WINDOWS
5534 else if(var == &ps->vars[V_COLOR_STYLE]){
5535 pico_toggle_color(0);
5536 switch(ps->color_style){
5537 case COL_NONE:
5538 case COL_TERMDEF:
5539 pico_set_color_options(pico_trans_color() ? COLOR_TRANS_OPT : 0);
5540 break;
5541 case COL_ANSI8:
5542 pico_set_color_options(COLOR_ANSI8_OPT|COLOR_TRANS_OPT);
5543 break;
5544 case COL_ANSI16:
5545 pico_set_color_options(COLOR_ANSI16_OPT|COLOR_TRANS_OPT);
5546 break;
5547 case COL_ANSI256:
5548 pico_set_color_options(COLOR_ANSI256_OPT|COLOR_TRANS_OPT);
5549 break;
5552 if(ps->color_style != COL_NONE)
5553 pico_toggle_color(1);
5555 if(pico_usingcolor())
5556 pico_set_normal_color();
5558 clear_index_cache(ps_global->mail_stream, 0);
5559 ClearScreen();
5560 ps->mangled_screen = 1;
5562 #endif
5564 else if(revert && var == &ps->vars[V_SORT_KEY]){
5565 int def_sort_rev;
5567 decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev);
5568 ps->def_sort_rev = def_sort_rev;
5570 else if(var == &ps->vars[V_THREAD_MORE_CHAR] ||
5571 var == &ps->vars[V_THREAD_EXP_CHAR] ||
5572 var == &ps->vars[V_THREAD_LASTREPLY_CHAR]){
5574 if(var == &ps->vars[V_THREAD_LASTREPLY_CHAR] &&
5575 !(var->current_val.p && var->current_val.p[0])){
5576 if(var->current_val.p)
5577 fs_give((void **) &var->current_val.p);
5579 q_status_message1(SM_ORDER, 3, 5,
5580 _("\"%s\" can't be Empty, using default"), var->name);
5582 apval = APVAL(var, ew);
5583 if(*apval)
5584 fs_give((void **)apval);
5586 set_current_val(var, FALSE, FALSE);
5588 if(!(var->current_val.p && var->current_val.p[0]
5589 && !var->current_val.p[1])){
5590 if(var->current_val.p)
5591 fs_give((void **) &var->current_val.p);
5593 var->current_val.p = cpystr(DF_THREAD_LASTREPLY_CHAR);
5597 if(var == &ps->vars[V_THREAD_MORE_CHAR] ||
5598 var == &ps->vars[V_THREAD_EXP_CHAR] ||
5599 var == &ps->vars[V_THREAD_LASTREPLY_CHAR]){
5600 if(var->current_val.p && var->current_val.p[0] &&
5601 var->current_val.p[1]){
5602 q_status_message1(SM_ORDER, 3, 5,
5603 "Only first character of \"%s\" is used",
5604 var->name);
5605 var->current_val.p[1] = '\0';
5608 if(var->main_user_val.p && var->main_user_val.p[0] &&
5609 var->main_user_val.p[1])
5610 var->main_user_val.p[1] = '\0';
5612 if(var->post_user_val.p && var->post_user_val.p[0] &&
5613 var->post_user_val.p[1])
5614 var->post_user_val.p[1] = '\0';
5617 clear_index_cache(ps_global->mail_stream, 0);
5618 set_need_format_setup(ps_global->mail_stream);
5620 else if(var == &ps->vars[V_NNTP_SERVER]){
5621 free_contexts(&ps_global->context_list);
5622 init_folders(ps_global);
5624 else if(var == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){
5625 init_hostname(ps);
5627 else if(var == &ps->vars[V_PRINTER]){
5628 if(!revert && ps->vars[V_PERSONAL_PRINT_COMMAND].is_fixed){
5629 if(printer_value_check_and_adjust())
5630 q_status_message1(SM_ORDER, 3, 5,
5631 _("Can't set \"%s\" to that value, see Setup/Printer"),
5632 pretty_var_name(var->name));
5635 else if(var == &ps->vars[V_KW_COLORS] ||
5636 var == &ps->vars[V_INDEX_TOKEN_COLORS] ||
5637 var == &ps->vars[V_IND_PLUS_FORE_COLOR] ||
5638 var == &ps->vars[V_IND_IMP_FORE_COLOR] ||
5639 var == &ps->vars[V_IND_DEL_FORE_COLOR] ||
5640 var == &ps->vars[V_IND_ANS_FORE_COLOR] ||
5641 var == &ps->vars[V_IND_NEW_FORE_COLOR] ||
5642 var == &ps->vars[V_IND_UNS_FORE_COLOR] ||
5643 var == &ps->vars[V_IND_HIPRI_FORE_COLOR]||
5644 var == &ps->vars[V_IND_LOPRI_FORE_COLOR]||
5645 var == &ps->vars[V_IND_ARR_FORE_COLOR] ||
5646 var == &ps->vars[V_IND_REC_FORE_COLOR] ||
5647 var == &ps->vars[V_IND_FWD_FORE_COLOR] ||
5648 var == &ps->vars[V_IND_OP_FORE_COLOR] ||
5649 var == &ps->vars[V_IND_FROM_FORE_COLOR] ||
5650 var == &ps->vars[V_IND_SUBJ_FORE_COLOR] ||
5651 var == &ps->vars[V_IND_PLUS_BACK_COLOR] ||
5652 var == &ps->vars[V_IND_IMP_BACK_COLOR] ||
5653 var == &ps->vars[V_IND_DEL_BACK_COLOR] ||
5654 var == &ps->vars[V_IND_ANS_BACK_COLOR] ||
5655 var == &ps->vars[V_IND_NEW_BACK_COLOR] ||
5656 var == &ps->vars[V_IND_UNS_BACK_COLOR] ||
5657 var == &ps->vars[V_IND_ARR_BACK_COLOR] ||
5658 var == &ps->vars[V_IND_REC_BACK_COLOR] ||
5659 var == &ps->vars[V_IND_FWD_BACK_COLOR] ||
5660 var == &ps->vars[V_IND_OP_BACK_COLOR] ||
5661 var == &ps->vars[V_IND_FROM_BACK_COLOR] ||
5662 var == &ps->vars[V_IND_SUBJ_BACK_COLOR]){
5663 clear_index_cache(ps_global->mail_stream, 0);
5665 else if(var == score_act_global_ptr){
5666 int score;
5668 score = atoi(var->current_val.p);
5669 if(score < SCORE_MIN || score > SCORE_MAX){
5670 q_status_message2(SM_ORDER, 3, 5,
5671 _("Score Value must be in range %s to %s"),
5672 comatose(SCORE_MIN), comatose(SCORE_MAX));
5673 apval = APVAL(var, ew);
5674 if(*apval)
5675 fs_give((void **)apval);
5677 set_current_val(var, FALSE, FALSE);
5680 else if(var == scorei_pat_global_ptr || var == age_pat_global_ptr
5681 || var == size_pat_global_ptr || var == cati_global_ptr){
5682 apval = APVAL(var, ew);
5683 if(*apval){
5684 INTVL_S *iv;
5685 iv = parse_intvl(*apval);
5686 if(iv){
5687 fs_give((void **) apval);
5688 *apval = stringform_of_intvl(iv);
5689 free_intvl(&iv);
5691 else
5692 fs_give((void **) apval);
5695 set_current_val(var, FALSE, FALSE);
5697 else if(var == &ps->vars[V_FEATURE_LIST]){
5698 process_feature_list(ps, var->current_val.l, 0, 0, 0);
5700 else if(!revert && (var == &ps->vars[V_LAST_TIME_PRUNE_QUESTION] ||
5701 var == &ps->vars[V_REMOTE_ABOOK_HISTORY] ||
5702 var == &ps->vars[V_REMOTE_ABOOK_VALIDITY] ||
5703 var == &ps->vars[V_USERINPUTTIMEO] ||
5704 var == &ps->vars[V_NEWS_ACTIVE_PATH] ||
5705 var == &ps->vars[V_NEWS_SPOOL_DIR] ||
5706 var == &ps->vars[V_INCOMING_FOLDERS] ||
5707 var == &ps->vars[V_FOLDER_SPEC] ||
5708 var == &ps->vars[V_NEWS_SPEC] ||
5709 var == &ps->vars[V_DISABLE_DRIVERS] ||
5710 var == &ps->vars[V_DISABLE_AUTHS] ||
5711 var == &ps->vars[V_RSHPATH] ||
5712 var == &ps->vars[V_RSHCMD] ||
5713 var == &ps->vars[V_SSHCMD] ||
5714 var == &ps->vars[V_SSHPATH])){
5715 q_status_message2(SM_ASYNC, 0, 3,
5716 _("Changes%s%s will affect your next Alpine session."),
5717 var->name ? " to " : "", var->name ? var->name : "");
5720 if(!revert && (var == &ps->vars[V_TCPOPENTIMEO] ||
5721 var == &ps->vars[V_TCPREADWARNTIMEO] ||
5722 var == &ps->vars[V_TCPWRITEWARNTIMEO] ||
5723 var == &ps->vars[V_TCPQUERYTIMEO] ||
5724 var == &ps->vars[V_RSHOPENTIMEO] ||
5725 var == &ps->vars[V_SSHOPENTIMEO]))
5726 q_status_message(SM_ASYNC, 0, 3,
5727 _("Timeout changes will affect your next Alpine session."));
5732 * Compare saved user_val with current user_val to see if it changed.
5733 * If any have changed, change it back and take the appropriate action.
5735 void
5736 revert_to_saved_config(struct pine *ps, SAVED_CONFIG_S *vsave, int allow_hard_to_config_remotely)
5738 struct variable *vreal;
5739 SAVED_CONFIG_S *v;
5740 int i, n;
5741 int changed = 0;
5742 char *pval, **apval, **lval, ***alval;
5744 v = vsave;
5745 for(vreal = ps->vars; vreal->name; vreal++,v++){
5746 if(!save_include(ps, vreal, allow_hard_to_config_remotely))
5747 continue;
5749 changed = 0;
5750 if(vreal->is_list){
5751 lval = LVAL(vreal, ew);
5752 alval = ALVAL(vreal, ew);
5754 if((v->saved_user_val.l && !lval)
5755 || (!v->saved_user_val.l && lval))
5756 changed++;
5757 else if(!v->saved_user_val.l && !lval)
5758 ;/* no change, nothing to do */
5759 else
5760 for(i = 0; v->saved_user_val.l[i] || lval[i]; i++)
5761 if((v->saved_user_val.l[i]
5762 && (!lval[i]
5763 || strcmp(v->saved_user_val.l[i], lval[i])))
5765 (!v->saved_user_val.l[i] && lval[i])){
5766 changed++;
5767 break;
5770 if(changed){
5771 char **list;
5773 if(alval){
5774 if(*alval)
5775 free_list_array(alval);
5777 /* copy back the original one */
5778 if(v->saved_user_val.l){
5779 list = v->saved_user_val.l;
5780 n = 0;
5781 /* count how many */
5782 while(list[n])
5783 n++;
5785 *alval = (char **)fs_get((n+1) * sizeof(char *));
5787 for(i = 0; i < n; i++)
5788 (*alval)[i] = cpystr(v->saved_user_val.l[i]);
5790 (*alval)[n] = NULL;
5795 else{
5796 pval = PVAL(vreal, ew);
5797 apval = APVAL(vreal, ew);
5799 if((v->saved_user_val.p &&
5800 (!pval || strcmp(v->saved_user_val.p, pval))) ||
5801 (!v->saved_user_val.p && pval)){
5802 /* It changed, fix it */
5803 changed++;
5804 if(apval){
5805 /* free the changed value */
5806 if(*apval)
5807 fs_give((void **)apval);
5809 if(v->saved_user_val.p)
5810 *apval = cpystr(v->saved_user_val.p);
5815 if(changed){
5816 if(vreal == &ps->vars[V_FEATURE_LIST])
5817 set_feature_list_current_val(vreal);
5818 else
5819 set_current_val(vreal, TRUE, FALSE);
5821 fix_side_effects(ps, vreal, 1);
5827 SAVED_CONFIG_S *
5828 save_config_vars(struct pine *ps, int allow_hard_to_config_remotely)
5830 struct variable *vreal;
5831 SAVED_CONFIG_S *vsave, *v;
5833 vsave = (SAVED_CONFIG_S *)fs_get((V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
5834 memset((void *)vsave, 0, (V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
5835 v = vsave;
5836 for(vreal = ps->vars; vreal->name; vreal++,v++){
5837 if(!save_include(ps, vreal, allow_hard_to_config_remotely))
5838 continue;
5840 if(vreal->is_list){
5841 int n, i;
5842 char **list;
5844 if(LVAL(vreal, ew)){
5845 /* count how many */
5846 n = 0;
5847 list = LVAL(vreal, ew);
5848 while(list[n])
5849 n++;
5851 v->saved_user_val.l = (char **)fs_get((n+1) * sizeof(char *));
5852 memset((void *)v->saved_user_val.l, 0, (n+1)*sizeof(char *));
5853 for(i = 0; i < n; i++)
5854 v->saved_user_val.l[i] = cpystr(list[i]);
5856 v->saved_user_val.l[n] = NULL;
5859 else{
5860 if(PVAL(vreal, ew))
5861 v->saved_user_val.p = cpystr(PVAL(vreal, ew));
5865 return(vsave);
5869 void
5870 free_saved_config(struct pine *ps, SAVED_CONFIG_S **vsavep, int allow_hard_to_config_remotely)
5872 struct variable *vreal;
5873 SAVED_CONFIG_S *v;
5875 if(vsavep && *vsavep){
5876 for(v = *vsavep, vreal = ps->vars; vreal->name; vreal++,v++){
5877 if(!save_include(ps, vreal, allow_hard_to_config_remotely))
5878 continue;
5880 if(vreal->is_list){ /* free saved_user_val.l */
5881 if(v && v->saved_user_val.l)
5882 free_list_array(&v->saved_user_val.l);
5884 else if(v && v->saved_user_val.p)
5885 fs_give((void **)&v->saved_user_val.p);
5888 fs_give((void **)vsavep);
5894 * Returns positive if any thing was actually deleted.
5897 delete_user_vals(struct variable *v)
5899 int rv = 0;
5901 if(v){
5902 if(v->is_list){
5903 if(v->post_user_val.l){
5904 rv++;
5905 free_list_array(&v->post_user_val.l);
5907 if(v->main_user_val.l){
5908 rv++;
5909 free_list_array(&v->main_user_val.l);
5912 else{
5913 if(v->post_user_val.p){
5914 rv++;
5915 fs_give((void **)&v->post_user_val.p);
5917 if(v->main_user_val.p){
5918 rv++;
5919 fs_give((void **)&v->main_user_val.p);
5924 return(rv);
5929 * ../pith/conf.c required function
5932 unexpected_pinerc_change(void)
5934 Writechar(BELL, 0);
5935 if(want_to("Unexpected pinerc change! Overwrite with current config",
5936 'n', 0, NO_HELP, WT_FLUSH_IN) == 'n'){
5937 return(-1); /* abort pinerc write */
5940 return(0); /* overwrite */
5944 #ifdef _WINDOWS
5946 /*----------------------------------------------------------------------
5947 MSWin scroll callback. Called during scroll message processing.
5951 Args: cmd - what type of scroll operation.
5952 scroll_pos - paramter for operation.
5953 used as position for SCROLL_TO operation.
5955 Returns: TRUE - did the scroll operation.
5956 FALSE - was not able to do the scroll operation.
5957 ----*/
5959 config_scroll_callback (cmd, scroll_pos)
5960 int cmd;
5961 long scroll_pos;
5963 switch (cmd) {
5964 case MSWIN_KEY_SCROLLUPLINE:
5965 config_scroll_down (scroll_pos);
5966 break;
5968 case MSWIN_KEY_SCROLLDOWNLINE:
5969 config_scroll_up (scroll_pos);
5970 break;
5972 case MSWIN_KEY_SCROLLUPPAGE:
5973 config_scroll_down (BODY_LINES(ps_global));
5974 break;
5976 case MSWIN_KEY_SCROLLDOWNPAGE:
5977 config_scroll_up (BODY_LINES(ps_global));
5978 break;
5980 case MSWIN_KEY_SCROLLTO:
5981 config_scroll_to_pos (scroll_pos);
5982 break;
5985 option_screen_redrawer();
5986 fflush(stdout);
5988 return(TRUE);
5991 #endif /* _WINDOWS */