* new version 2.19.9999
[alpine.git] / alpine / confscroll.c
blob53c2c82adbea38ca1c191c27f79c76430d389c54
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-2015 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 opt_screen = screen;
3047 if(cursor_pos){
3048 cursor_pos->col = 0;
3049 cursor_pos->row = -1; /* to tell us if we've set it yet */
3053 * calculate top line of display for reframing if the current field
3054 * is off the display defined by screen->top_line...
3056 if((ctmp = screen->top_line) != NULL)
3057 for(dline = BODY_LINES(ps);
3058 dline && ctmp && ctmp != screen->current;
3059 ctmp = next_confline(ctmp), dline--)
3062 if(!ctmp || !dline){ /* force reframing */
3063 dline = 0;
3064 ctmp = top_line = first_confline(screen->current);
3066 if(((dline++)%BODY_LINES(ps)) == 0)
3067 top_line = ctmp;
3068 while(ctmp != screen->current && (ctmp = next_confline(ctmp)));
3070 else
3071 top_line = screen->top_line;
3073 #ifdef _WINDOWS
3075 * Figure out how far down the top line is from the top and how many
3076 * total lines there are. Dumb to loop every time thru, but
3077 * there aren't that many lines, and it's cheaper than rewriting things
3078 * to maintain a line count in each structure...
3080 for(dline = 0, ctmp = prev_confline(top_line); ctmp; ctmp = prev_confline(ctmp))
3081 dline++;
3083 scroll_setpos(dline);
3084 last_selectable = dline;
3085 for(ctmp = next_confline(top_line); ctmp ; ctmp = next_confline(ctmp)){
3086 dline++;
3087 if (!(ctmp->flags & CF_NOSELECT))
3088 last_selectable = dline;
3090 dline = last_selectable;
3091 scroll_setrange(BODY_LINES(ps), dline);
3092 #endif
3094 /* mangled body or new page, force redraw */
3095 if(ps->mangled_body || screen->top_line != top_line)
3096 screen->prev = NULL;
3098 /* loop thru painting what's needed */
3099 for(dline = 0, ctmp = top_line;
3100 dline < BODY_LINES(ps);
3101 dline++, ctmp = next_confline(ctmp)){
3104 * only fall thru painting if something needs painting...
3106 if(!(!screen->prev || ctmp == screen->prev || ctmp == screen->current
3107 || ctmp == screen->prev->varnamep
3108 || ctmp == screen->current->varnamep
3109 || ctmp == screen->prev->headingp
3110 || ctmp == screen->current->headingp))
3111 continue;
3113 ClearLine(dline + HEADER_ROWS(ps));
3115 if(ctmp){
3116 if(ctmp->flags & CF_B_LINE)
3117 continue;
3119 if(ctmp->varname && !(ctmp->flags & CF_INVISIBLEVAR)){
3120 if(ctmp == screen->current && cursor_pos)
3121 cursor_pos->row = dline + HEADER_ROWS(ps);
3123 if((ctmp == screen->current
3124 || ctmp == screen->current->varnamep
3125 || ctmp == screen->current->headingp)
3126 && !(ctmp->flags & CF_NOHILITE))
3127 StartInverse();
3129 if(ctmp->flags & CF_H_LINE){
3130 MoveCursor(dline + HEADER_ROWS(ps), 0);
3131 Write_to_screen(repeat_char(ps->ttyo->screen_cols, '-'));
3134 if(ctmp->flags & CF_CENTERED){
3135 int offset = ps->ttyo->screen_cols/2
3136 - (utf8_width(ctmp->varname)/2);
3137 MoveCursor(dline + HEADER_ROWS(ps),
3138 (offset > 0) ? offset : 0);
3140 else if(ctmp->varoffset)
3141 MoveCursor(dline+HEADER_ROWS(ps), ctmp->varoffset);
3143 Write_to_screen(ctmp->varname);
3144 if((ctmp == screen->current
3145 || ctmp == screen->current->varnamep
3146 || ctmp == screen->current->headingp)
3147 && !(ctmp->flags & CF_NOHILITE))
3148 EndInverse();
3151 value = (ctmp->flags & CF_INHERIT) ? INHERIT : ctmp->value;
3153 if(value){
3154 char *p;
3155 int i, j;
3157 memset(tmp_20k_buf, '\0',
3158 (6*ps->ttyo->screen_cols + 1) * sizeof(char));
3159 if(ctmp == screen->current){
3160 if(!(ctmp->flags & CF_DOUBLEVAR && ctmp->flags & CF_VAR2))
3161 StartInverse();
3163 if(cursor_pos)
3164 cursor_pos->row = dline + HEADER_ROWS(ps);
3167 if(ctmp->flags & CF_H_LINE)
3168 memset(tmp_20k_buf, '-',
3169 ps->ttyo->screen_cols * sizeof(char));
3171 if(ctmp->flags & CF_CENTERED){
3172 int offset = ps->ttyo->screen_cols/2
3173 - (utf8_width(value)/2);
3174 /* BUG: tabs screw us figuring length above */
3175 if(offset > 0){
3176 char *q;
3178 p = tmp_20k_buf + offset;
3179 if(!*(q = tmp_20k_buf))
3180 while(q < p)
3181 *q++ = ' ';
3184 else
3185 p = tmp_20k_buf;
3188 * Copy the value to a temp buffer expanding tabs, and
3189 * making sure not to write beyond screen right...
3191 for(i = 0, j = ctmp->valoffset; value[i]; i++){
3192 if(value[i] == ctrl('I')){
3194 *p++ = ' ';
3195 while((++j) & 0x07);
3197 else{
3198 *p++ = value[i];
3199 j++;
3203 if(ctmp == screen->current && cursor_pos){
3204 if(ctmp->flags & CF_DOUBLEVAR && ctmp->flags & CF_VAR2)
3205 cursor_pos->col = ctmp->val2offset;
3206 else
3207 cursor_pos->col = ctmp->valoffset;
3209 if(ctmp->tool == radiobutton_tool
3210 #ifdef ENABLE_LDAP
3211 || ctmp->tool==ldap_radiobutton_tool
3212 #endif
3213 || ctmp->tool==role_radiobutton_tool
3214 || ctmp->tool==checkbox_tool
3215 || (ctmp->tool==color_setting_tool &&
3216 ctmp->valoffset != COLOR_INDENT))
3217 cursor_pos->col++;
3220 if(ctmp->flags & CF_DOUBLEVAR){
3221 long l;
3223 p = tmp_20k_buf;
3224 first_width = ctmp->val2offset - ctmp->valoffset - SPACE_BETWEEN_DOUBLEVARS;
3225 if((l=utf8_width(p)) > first_width && first_width >= 0){
3226 saveptr = utf8_count_forw_width(p, first_width, &got_width);
3228 * got_width != first_width indicates there's a problem
3229 * that should not happen. Ignore it.
3231 if(saveptr){
3232 save = *saveptr;
3233 *saveptr = '\0';
3236 else
3237 save = '\0';
3240 * If this is a COLOR_BLOB line we do special coloring.
3241 * The current object inverse hilite is only on the
3242 * checkbox part, the exact format comes from the
3243 * new_color_line function. If we change that we'll have
3244 * to change this to get the coloring right.
3246 if(p[0] == '(' && p[2] == ')' &&
3247 p[3] == ' ' && p[4] == ' ' &&
3248 (!strncmp(p+5, COLOR_BLOB, COLOR_BLOB_LEN)
3249 || !strncmp(p+5, COLOR_BLOB_TRAN, COLOR_BLOB_LEN)
3250 || !strncmp(p+5, COLOR_BLOB_NORM, COLOR_BLOB_LEN))){
3251 COLOR_PAIR *lastc = NULL, *newc = NULL;
3253 MoveCursor(dline+HEADER_ROWS(ps), ctmp->valoffset);
3254 Write_to_screen_n(p, 3);
3255 if(!(ctmp->flags & CF_VAR2) && ctmp == screen->current)
3256 EndInverse();
3258 Write_to_screen_n(p+3, 3);
3259 newc = new_color_pair(colorx(CFC_ICOLOR(ctmp)),
3260 colorx(CFC_ICOLOR(ctmp)));
3261 if(newc){
3262 lastc = pico_get_cur_color();
3263 (void)pico_set_colorp(newc, PSC_NONE);
3264 free_color_pair(&newc);
3267 Write_to_screen_n(p+6, COLOR_BLOB_LEN-2);
3269 if(lastc){
3270 (void)pico_set_colorp(lastc, PSC_NONE);
3271 free_color_pair(&lastc);
3274 Write_to_screen(p+6+COLOR_BLOB_LEN-2);
3276 else{
3277 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset, p);
3278 if(!(ctmp->flags & CF_VAR2) && ctmp == screen->current)
3279 EndInverse();
3282 if(saveptr)
3283 *saveptr = save;
3285 PutLine0(dline+HEADER_ROWS(ps),
3286 ctmp->val2offset - SPACE_BETWEEN_DOUBLEVARS,
3287 repeat_char(SPACE_BETWEEN_DOUBLEVARS, SPACE));
3289 if(l > ctmp->val2offset - ctmp->valoffset && ctmp->val2offset - ctmp->valoffset >= 0)
3290 p = saveptr + SPACE_BETWEEN_DOUBLEVARS;
3292 if(p > tmp_20k_buf){
3293 if(ctmp->flags & CF_VAR2 && ctmp == screen->current)
3294 StartInverse();
3296 if(p[0] == '(' && p[2] == ')' &&
3297 p[3] == ' ' && p[4] == ' ' &&
3298 (!strncmp(p+5, COLOR_BLOB, COLOR_BLOB_LEN)
3299 || !strncmp(p+5, COLOR_BLOB_TRAN, COLOR_BLOB_LEN)
3300 || !strncmp(p+5, COLOR_BLOB_NORM, COLOR_BLOB_LEN))){
3301 COLOR_PAIR *lastc = NULL, *newc = NULL;
3303 MoveCursor(dline+HEADER_ROWS(ps), ctmp->val2offset);
3304 Write_to_screen_n(p, 3);
3305 if(ctmp->flags & CF_VAR2 && ctmp == screen->current)
3306 EndInverse();
3308 Write_to_screen_n(p+3, 3);
3309 newc = new_color_pair(colorx(CFC_ICOLOR(ctmp)),
3310 colorx(CFC_ICOLOR(ctmp)));
3311 if(newc){
3312 lastc = pico_get_cur_color();
3313 (void)pico_set_colorp(newc, PSC_NONE);
3314 free_color_pair(&newc);
3317 Write_to_screen_n(p+6, COLOR_BLOB_LEN-2);
3319 if(lastc){
3320 (void)pico_set_colorp(lastc, PSC_NONE);
3321 free_color_pair(&lastc);
3324 Write_to_screen(p+6+COLOR_BLOB_LEN-2);
3326 else{
3327 PutLine0(dline+HEADER_ROWS(ps),ctmp->val2offset,p);
3328 if(ctmp->flags & CF_VAR2 && ctmp == screen->current)
3329 EndInverse();
3333 else{
3334 char *q, *first_space, *sample, *ptr;
3335 COLOR_PAIR *lastc, *newc;
3336 int invert;
3339 if(ctmp->flags & CF_COLORSAMPLE &&
3340 pico_usingcolor() &&
3341 ((q = strstr(tmp_20k_buf, SAMPLE_LEADER)) ||
3342 (q = strstr(tmp_20k_buf, "Color"))) &&
3343 (first_space = strindex(q, SPACE)) &&
3344 (strstr(value, SAMP1) ||
3345 strstr(value, SAMP2))){
3347 ptr = tmp_20k_buf;
3349 /* write out first part */
3350 *first_space = '\0';
3351 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset,
3352 ptr);
3353 *first_space = SPACE;
3354 ptr = first_space;
3356 if(ctmp == screen->current)
3357 EndInverse();
3359 sample = skip_white_space(ptr);
3360 /* if there's enough room to put some sample up */
3361 save = *sample;
3362 *sample = '\0';
3363 w = utf8_width(tmp_20k_buf);
3364 *sample = save;
3365 if(ctmp->valoffset + w < ps->ttyo->screen_cols){
3367 sample++; /* for `[' at edge of sample */
3369 save = *ptr;
3370 *ptr = '\0';
3371 w = utf8_width(tmp_20k_buf);
3372 *ptr = save;
3374 save = *sample;
3375 *sample = '\0';
3376 /* spaces and bracket before sample1 */
3377 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset+w, ptr);
3378 *sample = save;
3380 ptr = sample;
3382 /* then the color sample */
3383 if(ctmp->var == &ps->vars[V_VIEW_HDR_COLORS]
3384 || ctmp->var == &ps->vars[V_INDEX_TOKEN_COLORS]){
3385 SPEC_COLOR_S *hc, *hcolors;
3387 lastc = newc = NULL;
3389 hcolors =
3390 spec_colors_from_varlist(LVAL(ctmp->var, ew),
3392 for(hc = hcolors, i=0; hc; hc = hc->next, i++)
3393 if(CFC_ICUST(ctmp) == i)
3394 break;
3396 if(hc && hc->fg && hc->fg[0] && hc->bg &&
3397 hc->bg[0])
3398 newc = new_color_pair(hc->fg, hc->bg);
3400 if(newc){
3401 lastc = pico_get_cur_color();
3402 (void)pico_set_colorp(newc, PSC_NONE);
3403 free_color_pair(&newc);
3406 if(hcolors)
3407 free_spec_colors(&hcolors);
3410 /* print out sample1 */
3412 save = *ptr;
3413 *ptr = '\0';
3414 w = utf8_width(tmp_20k_buf);
3415 *ptr = save;
3417 want_width = MIN(utf8_width(SAMP1)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3418 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3419 if(saveptr){
3420 save = *saveptr;
3421 *saveptr = '\0';
3424 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3425 if(saveptr)
3426 *saveptr = save;
3428 ptr = strindex(ptr, ']');
3430 if(lastc){
3431 (void)pico_set_colorp(lastc, PSC_NONE);
3432 free_color_pair(&lastc);
3435 else if(ctmp->var == &ps->vars[V_KW_COLORS]){
3436 KEYWORD_S *kw;
3437 SPEC_COLOR_S *kw_col = NULL;
3439 lastc = newc = NULL;
3441 /* find keyword associated with this line */
3442 for(kw=ps->keywords, i=0; kw; kw=kw->next, i++)
3443 if(CFC_ICUST(ctmp) == i)
3444 break;
3446 if(kw)
3447 kw_col =
3448 spec_colors_from_varlist(LVAL(ctmp->var,ew),
3451 /* color for this keyword */
3452 if(kw && kw_col
3453 && ((kw->nick && kw->nick[0]
3454 && (newc=hdr_color(kw->nick, NULL,
3455 kw_col)))
3457 (kw->kw && kw->kw[0]
3458 && (newc=hdr_color(kw->kw, NULL,
3459 kw_col))))){
3460 lastc = pico_get_cur_color();
3461 (void)pico_set_colorp(newc, PSC_NONE);
3462 free_color_pair(&newc);
3465 if(kw_col)
3466 free_spec_colors(&kw_col);
3468 /* print out sample1 */
3470 save = *ptr;
3471 *ptr = '\0';
3472 w = utf8_width(tmp_20k_buf);
3473 *ptr = save;
3475 want_width = MIN(utf8_width(SAMP1)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3476 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3477 if(saveptr){
3478 save = *saveptr;
3479 *saveptr = '\0';
3482 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3483 if(saveptr)
3484 *saveptr = save;
3486 ptr = strindex(ptr, ']');
3488 if(lastc){
3489 (void)pico_set_colorp(lastc, PSC_NONE);
3490 free_color_pair(&lastc);
3493 else{
3494 lastc = NULL;
3495 invert = 0;
3496 newc = sample_color(ps, ctmp->var);
3497 if(newc){
3498 if((lastc = pico_get_cur_color()) != NULL)
3499 (void)pico_set_colorp(newc, PSC_NONE);
3501 free_color_pair(&newc);
3503 else if(var_defaults_to_rev(ctmp->var)){
3504 if((newc = pico_get_rev_color()) != NULL){
3506 * Note, don't have to free newc.
3508 if((lastc = pico_get_cur_color()) != NULL)
3509 (void)pico_set_colorp(newc, PSC_NONE);
3511 else{
3512 StartInverse();
3513 invert = 1;
3517 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3519 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3520 !(PVAL(ctmp->var,ew) &&
3521 PVAL(ctmp->var+1,ew))))
3522 StartBold();
3524 /* print out sample1 */
3526 save = *ptr;
3527 *ptr = '\0';
3528 w = utf8_width(tmp_20k_buf);
3529 *ptr = save;
3531 want_width = MIN(utf8_width(SAMP1)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3532 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3533 if(saveptr){
3534 save = *saveptr;
3535 *saveptr = '\0';
3538 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3539 if(saveptr)
3540 *saveptr = save;
3542 ptr = strindex(ptr, ']');
3544 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3546 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3547 !(PVAL(ctmp->var,ew) &&
3548 PVAL(ctmp->var+1,ew))))
3549 EndBold();
3551 if(lastc){
3552 (void)pico_set_colorp(lastc, PSC_NONE);
3553 free_color_pair(&lastc);
3555 else if(invert)
3556 EndInverse();
3560 * Finish sample1 with the right bracket.
3562 save = *ptr;
3563 *ptr = '\0';
3564 w = utf8_width(tmp_20k_buf);
3565 *ptr = save;
3566 if(ctmp->valoffset + w < ps->ttyo->screen_cols){
3567 save = *(ptr+1);
3568 *(ptr+1) = '\0';
3569 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3570 *(ptr+1) = save;
3571 ptr++;
3572 w++;
3576 * Now check for an exception sample and paint it.
3578 if(ctmp->valoffset + w + SBS + 1 < ps->ttyo->screen_cols && (q = strstr(ptr, SAMPEXC))){
3579 /* spaces + `[' */
3580 save = ptr[SBS+1];
3581 ptr[SBS+1] = '\0';
3582 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3583 ptr[SBS+1] = save;
3584 ptr += (SBS+1);
3587 * Figure out what color to paint it.
3588 * This only happens with normal variables,
3589 * not with V_VIEW_HDR_COLORS.
3591 lastc = NULL;
3592 invert = 0;
3593 newc = sampleexc_color(ps, ctmp->var);
3594 if(newc){
3595 if((lastc = pico_get_cur_color()) != NULL)
3596 (void)pico_set_colorp(newc, PSC_NONE);
3598 free_color_pair(&newc);
3600 else if(var_defaults_to_rev(ctmp->var)){
3601 if((newc = pico_get_rev_color()) != NULL){
3603 * Note, don't have to free newc.
3605 if((lastc = pico_get_cur_color()) != NULL)
3606 (void)pico_set_colorp(newc, PSC_NONE);
3608 else{
3609 StartInverse();
3610 invert = 1;
3614 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3616 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3617 !(PVAL(ctmp->var,Post) &&
3618 PVAL(ctmp->var+1,Post))))
3619 StartBold();
3621 /* sample2 */
3622 save = *ptr;
3623 *ptr = '\0';
3624 w = utf8_width(tmp_20k_buf);
3625 *ptr = save;
3627 want_width = MIN(utf8_width(SAMPEXC)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3628 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3629 if(saveptr){
3630 save = *saveptr;
3631 *saveptr = '\0';
3634 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3635 if(saveptr)
3636 *saveptr = save;
3638 ptr = strindex(ptr, ']');
3640 /* turn off bold and color */
3641 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3643 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3644 !(PVAL(ctmp->var,Post) &&
3645 PVAL(ctmp->var+1,Post))))
3646 EndBold();
3648 if(lastc){
3649 (void)pico_set_colorp(lastc, PSC_NONE);
3650 free_color_pair(&lastc);
3652 else if(invert)
3653 EndInverse();
3656 * Finish sample2 with the right bracket.
3658 save = *ptr;
3659 *ptr = '\0';
3660 w = utf8_width(tmp_20k_buf);
3661 *ptr = save;
3662 if(ctmp->valoffset + w < ps->ttyo->screen_cols){
3663 save = *(ptr+1);
3664 *(ptr+1) = '\0';
3665 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3666 *(ptr+1) = save;
3667 ptr++;
3668 w++;
3672 /* paint rest of the line if there is any left */
3673 if(ctmp->valoffset + w < ps->ttyo->screen_cols && *ptr){
3674 want_width = ps->ttyo->screen_cols - w - ctmp->valoffset;
3675 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3676 if(saveptr){
3677 save = *saveptr;
3678 *saveptr = '\0';
3681 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3682 if(saveptr)
3683 *saveptr = save;
3687 else{
3688 w = utf8_width(tmp_20k_buf);
3689 want_width = ps->ttyo->screen_cols - ctmp->valoffset;
3690 if(w > want_width){
3691 saveptr = utf8_count_forw_width(tmp_20k_buf, want_width, &got_width);
3692 if(saveptr)
3693 *saveptr = '\0';
3696 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset, tmp_20k_buf);
3697 if(ctmp == screen->current)
3698 EndInverse();
3705 ps->mangled_body = 0;
3706 screen->top_line = top_line;
3707 screen->prev = screen->current;
3708 #ifdef _WINDOWS
3709 mswin_endupdate();
3710 #endif
3718 void
3719 print_option_screen(OPT_SCREEN_S *screen, char *prompt)
3721 CONF_S *ctmp;
3722 int so_far;
3723 char line[500];
3725 if(open_printer(prompt) == 0){
3726 for(ctmp = first_confline(screen->current);
3727 ctmp;
3728 ctmp = next_confline(ctmp)){
3730 so_far = 0;
3731 if(ctmp->varname && !(ctmp->flags & CF_INVISIBLEVAR)){
3733 snprintf(line, sizeof(line), "%*s%s", ctmp->varoffset, "",
3734 ctmp->varname);
3735 line[sizeof(line)-1] = '\0';
3736 print_text(line);
3737 so_far = ctmp->varoffset + utf8_width(ctmp->varname);
3740 if(ctmp && ctmp->value){
3741 char *p = tmp_20k_buf;
3742 int i, j, spaces;
3744 /* Copy the value to a temp buffer expanding tabs. */
3745 for(i = 0, j = ctmp->valoffset; ctmp->value[i]; i++){
3746 if(ctmp->value[i] == ctrl('I')){
3748 *p++ = ' ';
3749 while((++j) & 0x07);
3752 else{
3753 *p++ = ctmp->value[i];
3754 j++;
3758 *p = '\0';
3759 removing_trailing_white_space(tmp_20k_buf);
3761 spaces = MAX(ctmp->valoffset - so_far, 0);
3762 snprintf(line, sizeof(line), "%*s%s\n", spaces, "", tmp_20k_buf);
3763 line[sizeof(line)-1] = '\0';
3764 print_text(line);
3768 close_printer();
3777 void
3778 option_screen_redrawer(void)
3780 ps_global->mangled_body = 1;
3781 update_option_screen(ps_global, opt_screen, (Pos *)NULL);
3787 * pretty_value - given the line, return an
3788 * alloc'd string for line's value...
3790 char *
3791 pretty_value(struct pine *ps, CONF_S *cl)
3793 struct variable *v;
3795 v = cl->var;
3797 if(v == &ps->vars[V_FEATURE_LIST])
3798 return(checkbox_pretty_value(ps, cl));
3799 else if(standard_radio_var(ps, v) || v == startup_ptr)
3800 return(radio_pretty_value(ps, cl));
3801 else if(v == &ps->vars[V_SORT_KEY])
3802 return(sort_pretty_value(ps, cl));
3803 else if(v == &ps->vars[V_SIGNATURE_FILE])
3804 return(sigfile_pretty_value(ps, cl));
3805 else if(v == &ps->vars[V_USE_ONLY_DOMAIN_NAME])
3806 return(yesno_pretty_value(ps, cl));
3807 else if(color_holding_var(ps, v))
3808 return(color_pretty_value(ps, cl));
3809 else
3810 return(text_pretty_value(ps, cl));
3814 char *
3815 text_pretty_value(struct pine *ps, CONF_S *cl)
3817 char tmp[6*MAX_SCREEN_COLS+20], *pvalnorm, **lvalnorm, *pvalexc, **lvalexc;
3818 char *p, *pval, **lval, lastchar = '\0';
3819 int editing_except, fixed, uvalset, uvalposlen;
3820 unsigned got_width;
3821 int comments, except_set, avail_width;
3822 int norm_with_except = 0, norm_with_except_inherit = 0;
3823 int inherit_line = 0;
3825 editing_except = (ew == ps_global->ew_for_except_vars);
3826 fixed = cl->var->is_fixed;
3827 if((ps_global->ew_for_except_vars != Main) && (ew == Main))
3828 norm_with_except++; /* editing normal and except config exists */
3830 if(cl->var->is_list){
3831 lvalnorm = LVAL(cl->var, Main);
3832 lvalexc = LVAL(cl->var, ps_global->ew_for_except_vars);
3833 if(editing_except){
3834 uvalset = lvalexc != NULL;
3835 uvalposlen = uvalset && lvalexc[0] && lvalexc[0][0];
3836 lval = lvalexc;
3838 else{
3839 uvalset = lvalnorm != NULL;
3840 uvalposlen = uvalset && lvalnorm[0] && lvalnorm[0][0];
3841 lval = lvalnorm;
3844 except_set = lvalexc != NULL;
3845 comments = cl->var->current_val.l != NULL;
3846 if(norm_with_except && except_set && lvalexc[0] &&
3847 !strcmp(lvalexc[0],INHERIT))
3848 norm_with_except_inherit++;
3850 if(uvalset && !strcmp(lval[0], INHERIT)){
3851 if(cl->varmem == 0){
3852 inherit_line++;
3853 comments = 0;
3857 /* only add extra comments on last member of list */
3858 if(uvalset && !inherit_line && lval && lval[cl->varmem] &&
3859 lval[cl->varmem + 1])
3860 comments = 0;
3862 else{
3863 pvalnorm = PVAL(cl->var, Main);
3864 pvalexc = PVAL(cl->var, ps_global->ew_for_except_vars);
3865 if(editing_except){
3866 uvalset = pvalexc != NULL;
3867 uvalposlen = uvalset && *pvalexc;
3868 pval = pvalexc;
3870 else{
3871 uvalset = pvalnorm != NULL;
3872 uvalposlen = uvalset && *pvalnorm;
3873 pval = pvalnorm;
3876 except_set = pvalexc != NULL;
3877 comments = cl->var->current_val.p != NULL;
3880 memset(tmp, 0, sizeof(tmp));
3881 p = tmp;
3882 *p = '\0';
3884 avail_width = ps->ttyo->screen_cols - cl->valoffset;
3886 if(fixed || !uvalset || !uvalposlen){
3887 p += utf8_to_width(p, "<", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3888 avail_width -= got_width;
3891 if(fixed){
3892 p += utf8_to_width(p, _(fixed_val), sizeof(tmp)-(p-tmp), avail_width, &got_width);
3893 avail_width -= got_width;
3895 else if(!uvalset){
3896 p += utf8_to_width(p, _(no_val), sizeof(tmp)-(p-tmp), avail_width, &got_width);
3897 avail_width -= got_width;
3899 else if(!uvalposlen){
3900 p += utf8_to_width(p, _(empty_val), sizeof(tmp)-(p-tmp), avail_width, &got_width);
3901 avail_width -= got_width;
3903 else if(inherit_line){
3904 p += utf8_to_width(p, INHERIT, sizeof(tmp)-(p-tmp), avail_width, &got_width);
3905 avail_width -= got_width;
3907 else{
3908 if(cl->var->is_list){
3909 p += utf8_to_width(p, lval[cl->varmem], sizeof(tmp)-(p-tmp), avail_width, &got_width);
3910 avail_width -= got_width;
3912 else{
3913 p += utf8_to_width(p, pval, sizeof(tmp)-(p-tmp), avail_width, &got_width);
3914 avail_width -= got_width;
3918 if(comments && (fixed || !uvalset || (norm_with_except && except_set))){
3919 if(fixed || !uvalset){
3920 p += utf8_to_width(p, ": using ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3921 avail_width -= got_width;
3924 if(norm_with_except && except_set){
3925 if(!uvalset){
3926 p += utf8_to_width(p, "exception ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3927 avail_width -= got_width;
3929 else if(!fixed){
3930 if(!uvalposlen){
3931 p += utf8_to_width(p, ": ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3932 avail_width -= got_width;
3934 else{
3935 p += utf8_to_width(p, " (", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3936 avail_width -= got_width;
3939 if(norm_with_except_inherit){
3940 p += utf8_to_width(p, "added to by exception ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3941 avail_width -= got_width;
3943 else{
3944 p += utf8_to_width(p, "overridden by exception ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3945 avail_width -= got_width;
3950 if(avail_width >= 7){
3951 if(cl->var == &ps_global->vars[V_POST_CHAR_SET]){
3952 p += utf8_to_width(p, "most specific (see help)", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3953 avail_width -= got_width;
3955 else{
3956 sstrncpy(&p, "\"", sizeof(tmp)-(p-tmp));
3957 avail_width--;
3958 if(cl->var->is_list){
3959 char **the_list;
3961 the_list = cl->var->current_val.l;
3963 if(norm_with_except && except_set)
3964 the_list = lvalexc;
3966 if(the_list && the_list[0] && !strcmp(the_list[0], INHERIT))
3967 the_list++;
3969 for(lval = the_list; avail_width-(p-tmp) > 0 && *lval; lval++){
3970 if(lval != the_list){
3971 p += utf8_to_width(p, ",", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3972 avail_width -= got_width;
3975 p += utf8_to_width(p, *lval, sizeof(tmp)-(p-tmp), avail_width, &got_width);
3976 avail_width -= got_width;
3979 else{
3980 p += utf8_to_width(p, cl->var->current_val.p, sizeof(tmp)-(p-tmp), avail_width, &got_width);
3981 avail_width -= got_width;
3984 if(p-tmp+2 < sizeof(tmp)){
3985 *p++ = '\"';
3986 *p = '\0';
3990 else if(*(p-1) == SPACE)
3991 *--p = '\0';
3994 tmp[sizeof(tmp)-1] = '\0';
3996 if(fixed || !uvalset || !uvalposlen)
3997 lastchar = '>';
3998 else if(comments && norm_with_except && except_set)
3999 lastchar = ')';
4001 if(lastchar){
4002 if(p-tmp+2 < sizeof(tmp)){
4003 *p++ = lastchar;
4004 *p = '\0';
4008 tmp[sizeof(tmp)-1] = '\0';
4009 avail_width = ps->ttyo->screen_cols - cl->valoffset;
4011 if(utf8_width(tmp) < avail_width)
4012 snprintf(tmp+strlen(tmp), sizeof(tmp)-strlen(tmp), "%*s", avail_width-utf8_width(tmp), "");
4014 tmp[sizeof(tmp)-1] = '\0';
4016 return(cpystr(tmp));
4020 char *
4021 checkbox_pretty_value(struct pine *ps, CONF_S *cl)
4023 char tmp[6*MAXPATH];
4024 char *comment = NULL;
4025 int indent, x, screen_width, need;
4026 int longest_featname, longest_comment;
4027 int nwidcomm; /* name width with comment */
4028 int nwidnocomm; /* and without comment */
4029 FEATURE_S *feature;
4031 screen_width = (ps && ps->ttyo) ? ps->ttyo->screen_cols : 80;
4032 tmp[0] = '\0';
4034 longest_featname = longest_feature_name();
4035 longest_comment = longest_feature_comment(ps, ew);
4036 indent = feature_indent();
4038 nwidcomm = longest_featname;
4039 nwidnocomm = longest_featname + 2 + longest_comment;
4041 if((need = (indent + 5 + longest_featname + 2 + longest_comment) - screen_width) > 0){
4042 if(need < 10){
4043 nwidcomm -= need;
4044 nwidnocomm -= need;
4046 else{
4047 longest_comment = 0;
4048 nwidnocomm = longest_featname;
4052 feature = feature_list(cl->varmem);
4054 x = feature_gets_an_x(ps, cl->var, feature, &comment, ew);
4056 if(longest_comment && comment && *comment){
4057 utf8_snprintf(tmp, sizeof(tmp), "[%c] %-*.*w %-*.*w", x ? 'X' : ' ',
4058 nwidcomm, nwidcomm,
4059 pretty_feature_name(feature->name, nwidcomm),
4060 longest_comment, longest_comment, comment ? comment : "");
4062 else{
4063 utf8_snprintf(tmp, sizeof(tmp), "[%c] %-*.*w", x ? 'X' : ' ',
4064 nwidnocomm, nwidnocomm,
4065 pretty_feature_name(feature->name, nwidnocomm));
4068 return(cpystr(tmp));
4073 longest_feature_name(void)
4075 static int lv = -1;
4076 int i, j;
4077 FEATURE_S *feature;
4079 if(lv < 0){
4080 for(lv = 0, i = 0; (feature = feature_list(i)); i++)
4081 if(feature_list_section(feature)
4082 && lv < (j = utf8_width(pretty_feature_name(feature->name, -1))))
4083 lv = j;
4085 lv = MIN(lv, 100);
4088 return(lv);
4093 feature_indent(void)
4095 return(6);
4099 char *
4100 yesno_pretty_value(struct pine *ps, CONF_S *cl)
4102 char tmp[6*MAXPATH], *pvalnorm, *pvalexc;
4103 char *p, *pval, lastchar = '\0';
4104 int editing_except, fixed, norm_with_except, uvalset;
4105 int curval, except_set;
4107 editing_except = (ew == ps_global->ew_for_except_vars);
4108 fixed = cl->var->is_fixed;
4109 if((ps_global->ew_for_except_vars == Main) ||
4110 (ew == ps_global->ew_for_except_vars))
4111 norm_with_except = 0;
4112 else
4113 norm_with_except = 1; /* editing normal and except config exists */
4115 pvalnorm = PVAL(cl->var, Main);
4116 pvalexc = PVAL(cl->var, ps_global->ew_for_except_vars);
4117 if(editing_except){
4118 uvalset = (pvalexc != NULL &&
4119 (!strucmp(pvalexc,yesstr) || !strucmp(pvalexc,nostr)));
4120 pval = pvalexc;
4122 else{
4123 uvalset = (pvalnorm != NULL &&
4124 (!strucmp(pvalnorm,yesstr) || !strucmp(pvalnorm,nostr)));
4125 pval = pvalnorm;
4128 except_set = (pvalexc != NULL &&
4129 (!strucmp(pvalexc,yesstr) || !strucmp(pvalexc,nostr)));
4130 curval = (cl->var->current_val.p != NULL &&
4131 (!strucmp(cl->var->current_val.p,yesstr) ||
4132 !strucmp(cl->var->current_val.p,nostr)));
4134 p = tmp;
4135 *p = '\0';
4137 if(fixed || !uvalset)
4138 sstrncpy(&p, "<", sizeof(tmp)-(p-tmp));
4140 if(fixed)
4141 sstrncpy(&p, _(fixed_val), sizeof(tmp)-(p-tmp));
4142 else if(!uvalset)
4143 sstrncpy(&p, _(no_val), sizeof(tmp)-(p-tmp));
4144 else if(!strucmp(pval, yesstr))
4145 sstrncpy(&p, yesstr, sizeof(tmp)-(p-tmp));
4146 else
4147 sstrncpy(&p, nostr, sizeof(tmp)-(p-tmp));
4149 if(curval && (fixed || !uvalset || (norm_with_except && except_set))){
4150 if(fixed || !uvalset)
4151 sstrncpy(&p, ": using ", sizeof(tmp)-(p-tmp));
4153 if(norm_with_except && except_set){
4154 if(!uvalset)
4155 sstrncpy(&p, "exception ", sizeof(tmp)-(p-tmp));
4156 else if(!fixed){
4157 sstrncpy(&p, " (", sizeof(tmp)-(p-tmp));
4158 sstrncpy(&p, "overridden by exception ", sizeof(tmp)-(p-tmp));
4162 sstrncpy(&p, "\"", sizeof(tmp)-(p-tmp));
4163 sstrncpy(&p, !strucmp(cl->var->current_val.p,yesstr) ? yesstr : nostr, sizeof(tmp)-(p-tmp));
4164 sstrncpy(&p, "\"", sizeof(tmp)-(p-tmp));
4167 if(fixed || !uvalset)
4168 lastchar = '>';
4169 else if(curval && norm_with_except && except_set)
4170 lastchar = ')';
4172 if(lastchar && sizeof(tmp)-(p-tmp) > 1){
4173 *p++ = lastchar;
4174 *p = '\0';
4177 tmp[sizeof(tmp)-1] = '\0';
4179 if(utf8_width(tmp) < ps->ttyo->screen_cols - cl->valoffset)
4180 snprintf(tmp+strlen(tmp), sizeof(tmp)-strlen(tmp),
4181 "%*s", ps->ttyo->screen_cols - cl->valoffset - utf8_width(tmp), "");
4183 tmp[sizeof(tmp)-1] = '\0';
4185 return(cpystr(tmp));
4189 char *
4190 radio_pretty_value(struct pine *ps, CONF_S *cl)
4192 char tmp[6*MAXPATH];
4193 char *pvalnorm, *pvalexc, *pval;
4194 int editing_except_which_isnt_normal, editing_normal_which_isnt_except;
4195 int fixed, is_set_for_this_level = 0, is_the_one, the_exc_one;
4196 int i, j, lv = 0;
4197 NAMEVAL_S *rule = NULL, *f;
4198 PTR_TO_RULEFUNC rulefunc;
4199 struct variable *v;
4201 tmp[0] = '\0';
4202 v = cl->var;
4204 editing_except_which_isnt_normal = (ew == ps_global->ew_for_except_vars &&
4205 ew != Main);
4206 editing_normal_which_isnt_except = (ew == Main &&
4207 ew != ps_global->ew_for_except_vars);
4208 fixed = cl->var->is_fixed;
4209 pvalnorm = PVAL(v, Main);
4210 pvalexc = PVAL(v, ps_global->ew_for_except_vars);
4212 rulefunc = rulefunc_from_var(ps, v);
4213 rule = rulefunc ? (*rulefunc)(cl->varmem) : NULL;
4215 /* find longest name */
4216 if(rulefunc)
4217 for(lv = 0, i = 0; (f = (*rulefunc)(i)); i++)
4218 if(lv < (j = utf8_width(f->name)))
4219 lv = j;
4221 lv = MIN(lv, 100);
4223 if(editing_except_which_isnt_normal)
4224 pval = pvalexc;
4225 else
4226 pval = pvalnorm;
4228 if(pval)
4229 is_set_for_this_level++;
4231 if(fixed){
4232 pval = v->fixed_val.p;
4233 is_the_one = (pval && !strucmp(pval, S_OR_L(rule)));
4235 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4236 is_the_one ? R_SELD : ' ',
4237 lv, lv, rule->name, is_the_one ? " (value is fixed)" : "");
4239 else if(is_set_for_this_level){
4240 is_the_one = (pval && !strucmp(pval, S_OR_L(rule)));
4241 the_exc_one = (editing_normal_which_isnt_except && pvalexc &&
4242 !strucmp(pvalexc, S_OR_L(rule)));
4243 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4244 is_the_one ? R_SELD : ' ',
4245 lv, lv, rule->name,
4246 (!is_the_one && the_exc_one) ? " (value set in exceptions)" :
4247 (is_the_one && the_exc_one) ? " (also set in exceptions)" :
4248 (is_the_one &&
4249 editing_normal_which_isnt_except &&
4250 pvalexc &&
4251 !the_exc_one) ? " (overridden by exceptions)" :
4252 "");
4254 else{
4255 if(pvalexc){
4256 is_the_one = !strucmp(pvalexc, S_OR_L(rule));
4257 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4258 is_the_one ? R_SELD : ' ',
4259 lv, lv, rule->name,
4260 is_the_one ? " (value set in exceptions)" : "");
4262 else{
4263 pval = v->current_val.p;
4264 is_the_one = (pval && !strucmp(pval, S_OR_L(rule)));
4265 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4266 is_the_one ? R_SELD : ' ',
4267 lv, lv, rule->name,
4268 is_the_one ? ((editing_except_which_isnt_normal && pvalnorm) ? " (default from regular config)" : " (default)") : "");
4272 tmp[sizeof(tmp)-1] = '\0';
4274 return(cpystr(tmp));
4278 char *
4279 sigfile_pretty_value(struct pine *ps, CONF_S *cl)
4281 if(cl && cl->var == &ps->vars[V_SIGNATURE_FILE] &&
4282 cl->prev && cl->prev->var == &ps->vars[V_LITERAL_SIG]){
4283 if(cl->prev->var->current_val.p){
4284 cl->flags |= CF_NOSELECT; /* side effect */
4285 return(cpystr(_("<Ignored: using Literal-Signature instead>")));
4287 else{
4288 cl->flags &= ~CF_NOSELECT;
4289 return(text_pretty_value(ps, cl));
4292 else
4293 return(cpystr(""));
4297 char *
4298 color_pretty_value(struct pine *ps, CONF_S *cl)
4300 char tmp[6*MAXPATH];
4301 char *p, *q;
4302 struct variable *v;
4303 int is_index;
4305 tmp[0] = '\0';
4306 v = cl->var;
4308 if(v && color_holding_var(ps, v) &&
4309 (p=srchstr(v->name, "-foreground-color"))){
4311 is_index = !struncmp(v->name, "index-", 6);
4313 q = sampleexc_text(ps, v);
4314 utf8_snprintf(tmp, sizeof(tmp), "%c%.*s %sColor%*.50s %.20w%*s%.20w%.20w",
4315 islower((unsigned char)v->name[0])
4316 ? toupper((unsigned char)v->name[0])
4317 : v->name[0],
4318 MIN(p-v->name-1,30), v->name+1,
4319 is_index ? "Symbol " : "",
4320 MAX(EQ_COL - COLOR_INDENT -1 - MIN(p-v->name-1,30)
4321 - 6 - (is_index ? 7 : 0) - 1,0), "",
4322 sample_text(ps,v), *q ? SBS : 0, "", q,
4323 color_parenthetical(v));
4326 tmp[sizeof(tmp)-1] = '\0';
4328 return(cpystr(tmp));
4332 char *
4333 sort_pretty_value(struct pine *ps, CONF_S *cl)
4335 return(generalized_sort_pretty_value(ps, cl, 1));
4339 char *
4340 generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok)
4342 char tmp[6*MAXPATH];
4343 char *pvalnorm, *pvalexc, *pval;
4344 int editing_except_which_isnt_normal, editing_normal_which_isnt_except;
4345 int fixed, is_set_for_this_level = 0, is_the_one, the_exc_one;
4346 int i, j, lv = 0;
4347 struct variable *v;
4348 SortOrder line_sort, var_sort, exc_sort;
4349 int line_sort_rev, var_sort_rev, exc_sort_rev;
4351 tmp[0] = '\0';
4352 v = cl->var;
4354 editing_except_which_isnt_normal = (ew == ps_global->ew_for_except_vars &&
4355 ew != Main);
4356 editing_normal_which_isnt_except = (ew == Main &&
4357 ew != ps_global->ew_for_except_vars);
4358 fixed = cl->var->is_fixed;
4359 pvalnorm = PVAL(v, Main);
4360 pvalexc = PVAL(v, ps_global->ew_for_except_vars);
4362 /* find longest value's name */
4363 for(lv = 0, i = 0; ps->sort_types[i] != EndofList; i++)
4364 if(lv < (j = utf8_width(sort_name(ps->sort_types[i]))))
4365 lv = j;
4367 lv = MIN(lv, 100);
4369 if(editing_except_which_isnt_normal)
4370 pval = pvalexc;
4371 else
4372 pval = pvalnorm;
4374 if(pval)
4375 is_set_for_this_level++;
4377 /* the config line we're talking about */
4378 if(cl->varmem >= 0){
4379 line_sort_rev = cl->varmem >= (short)EndofList;
4380 line_sort = (SortOrder)(cl->varmem - (line_sort_rev * EndofList));
4383 if(cl->varmem < 0){
4384 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*w",
4385 (pval == NULL) ? R_SELD : ' ',
4386 lv, "Default");
4388 else if(fixed){
4389 pval = v->fixed_val.p;
4390 decode_sort(pval, &var_sort, &var_sort_rev);
4391 is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
4393 utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s",
4394 is_the_one ? R_SELD : ' ',
4395 line_sort_rev ? "Reverse " : "",
4396 lv, sort_name(line_sort),
4397 line_sort_rev ? 0 : 8, "",
4398 is_the_one ? " (value is fixed)" : "");
4400 else if(is_set_for_this_level){
4401 decode_sort(pval, &var_sort, &var_sort_rev);
4402 is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
4403 decode_sort(pvalexc, &exc_sort, &exc_sort_rev);
4404 the_exc_one = (editing_normal_which_isnt_except && pvalexc &&
4405 exc_sort_rev == line_sort_rev && exc_sort == line_sort);
4406 utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s",
4407 is_the_one ? R_SELD : ' ',
4408 line_sort_rev ? "Reverse " : "",
4409 lv, sort_name(line_sort),
4410 line_sort_rev ? 0 : 8, "",
4411 (!is_the_one && the_exc_one) ? " (value set in exceptions)" :
4412 (is_the_one && the_exc_one) ? " (also set in exceptions)" :
4413 (is_the_one &&
4414 editing_normal_which_isnt_except &&
4415 pvalexc &&
4416 !the_exc_one) ? " (overridden by exceptions)" :
4417 "");
4419 else{
4420 if(pvalexc){
4421 decode_sort(pvalexc, &exc_sort, &exc_sort_rev);
4422 is_the_one = (exc_sort_rev == line_sort_rev &&
4423 exc_sort == line_sort);
4424 utf8_snprintf(tmp, sizeof(tmp), "( ) %s%-*w%*s%s",
4425 line_sort_rev ? "Reverse " : "",
4426 lv, sort_name(line_sort),
4427 line_sort_rev ? 0 : 8, "",
4428 is_the_one ? " (value set in exceptions)" : "");
4430 else{
4431 pval = v->current_val.p;
4432 decode_sort(pval, &var_sort, &var_sort_rev);
4433 is_the_one = ((pval || default_ok) &&
4434 var_sort_rev == line_sort_rev &&
4435 var_sort == line_sort);
4436 utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s",
4437 is_the_one ? R_SELD : ' ',
4438 line_sort_rev ? "Reverse " : "",
4439 lv, sort_name(line_sort),
4440 line_sort_rev ? 0 : 8, "",
4441 is_the_one ? ((editing_except_which_isnt_normal && pvalnorm) ? " (default from regular config)" : " (default)") : "");
4445 return(cpystr(tmp));
4449 COLOR_PAIR *
4450 sample_color(struct pine *ps, struct variable *v)
4452 COLOR_PAIR *cp = NULL;
4453 char *pvalefg, *pvalebg;
4454 char *pvalmfg, *pvalmbg;
4456 pvalefg = PVAL(v, ew);
4457 pvalebg = PVAL(v+1, ew);
4458 pvalmfg = PVAL(v, Main);
4459 pvalmbg = PVAL(v+1, Main);
4460 if(v && color_holding_var(ps, v) &&
4461 srchstr(v->name, "-foreground-color")){
4462 if(pvalefg && pvalefg[0] && pvalebg && pvalebg[0])
4463 cp = new_color_pair(pvalefg, pvalebg);
4464 else if(ew == Post && pvalmfg && pvalmfg[0] && pvalmbg && pvalmbg[0])
4465 cp = new_color_pair(pvalmfg, pvalmbg);
4466 else if(v->global_val.p && v->global_val.p[0] &&
4467 (v+1)->global_val.p && (v+1)->global_val.p[0])
4468 cp = new_color_pair(v->global_val.p, (v+1)->global_val.p);
4471 return(cp);
4475 COLOR_PAIR *
4476 sampleexc_color(struct pine *ps, struct variable *v)
4478 COLOR_PAIR *cp = NULL;
4479 char *pvalfg, *pvalbg;
4481 pvalfg = PVAL(v, Post);
4482 pvalbg = PVAL(v+1, Post);
4483 if(v && color_holding_var(ps, v) &&
4484 srchstr(v->name, "-foreground-color") &&
4485 pvalfg && pvalfg[0] && pvalbg && pvalbg[0])
4486 cp = new_color_pair(pvalfg, pvalbg);
4488 return(cp);
4492 void
4493 clear_feature(char ***l, char *f)
4495 char **list = l ? *l : NULL;
4496 int count = 0;
4498 for(; list && *list; list++, count++){
4499 if(f && !strucmp(((!struncmp(*list,"no-",3)) ? *list + 3 : *list), f)){
4500 fs_give((void **)list);
4501 f = NULL;
4504 if(!f) /* shift */
4505 *list = *(list + 1);
4509 * this is helpful to keep the array from growing if a feature
4510 * get's set and unset repeatedly
4512 if(!f)
4513 fs_resize((void **)l, count * sizeof(char *));
4520 void
4521 toggle_feature_bit(struct pine *ps, int index, struct variable *var, CONF_S *cl, int just_flip_value)
4523 FEATURE_S *f;
4524 int og, on_before;
4525 char *p, **vp;
4527 f = feature_list(index);
4529 og = test_old_growth_bits(ps, f->id);
4532 * if this feature is in the fixed set, or old-growth is in the fixed
4533 * set and this feature is in the old-growth set, don't alter it...
4535 for(vp = var->fixed_val.l; vp && *vp; vp++){
4536 p = (struncmp(*vp, "no-", 3)) ? *vp : *vp + 3;
4537 if(!strucmp(p, f->name) || (og && !strucmp(p, "old-growth"))){
4538 q_status_message(SM_ORDER, 3, 3,
4539 _("Can't change value fixed by sys-admin."));
4540 return;
4544 on_before = F_ON(f->id, ps);
4546 toggle_feature(ps, var, f, just_flip_value, ew);
4549 * Handle any alpine-specific features that need attention here. Features
4550 * that aren't alpine-specific should be handled in toggle_feature instead.
4552 if(on_before != F_ON(f->id, ps))
4553 switch(f->id){
4554 case F_CMBND_ABOOK_DISP :
4555 addrbook_reset();
4556 break;
4558 case F_PRESERVE_START_STOP :
4559 /* toggle raw mode settings to make tty driver aware of new setting */
4560 PineRaw(0);
4561 PineRaw(1);
4562 break;
4564 case F_USE_FK :
4565 ps->orig_use_fkeys = F_ON(F_USE_FK, ps);
4566 ps->mangled_footer = 1;
4567 mark_keymenu_dirty();
4568 break;
4570 case F_SHOW_SORT :
4571 ps->mangled_header = 1;
4572 break;
4574 case F_BLANK_KEYMENU :
4575 if(F_ON(f->id, ps)){
4576 FOOTER_ROWS(ps) = 1;
4577 ps->mangled_body = 1;
4579 else{
4580 FOOTER_ROWS(ps) = 3;
4581 ps->mangled_footer = 1;
4584 clearfooter(ps);
4585 break;
4587 case F_ENABLE_INCOMING :
4588 q_status_message(SM_ORDER | SM_DING, 3, 4,
4589 "Folder List changes will take effect your next Alpine session.");
4590 break;
4592 #ifdef _WINDOWS
4593 case F_SHOW_CURSOR :
4594 mswin_showcaret(F_ON(f->id,ps));
4595 break;
4597 case F_ENABLE_TRAYICON :
4598 mswin_trayicon(F_ON(f->id,ps));
4599 break;
4600 #endif
4602 #if !defined(DOS) && !defined(OS2)
4603 case F_ALLOW_TALK :
4604 if(F_ON(f->id, ps))
4605 allow_talk(ps);
4606 else
4607 disallow_talk(ps);
4609 break;
4610 #endif
4612 case F_PASS_CONTROL_CHARS :
4613 ps->pass_ctrl_chars = F_ON(F_PASS_CONTROL_CHARS,ps_global) ? 1 : 0;
4614 break;
4616 #ifdef SMIME
4617 case F_USE_CERT_STORE_ONLY:
4618 if(F_OFF(F_USE_CERT_STORE_ONLY, ps))
4619 q_status_message(SM_ORDER | SM_DING, 3, 4,
4620 "Disabling this feature should only be done for testing. Press \"?\" for help");
4621 break;
4622 #endif /* SMIME */
4624 case F_PASS_C1_CONTROL_CHARS :
4625 ps->pass_c1_ctrl_chars = F_ON(F_PASS_C1_CONTROL_CHARS,ps_global) ? 1 : 0;
4626 break;
4628 #ifdef MOUSE
4629 case F_ENABLE_MOUSE :
4630 if(F_ON(f->id, ps)){
4631 init_mouse();
4632 if(!mouseexist())
4633 q_status_message(SM_ORDER | SM_DING, 3, 4,
4634 "Mouse tracking still off ($DISPLAY variable set?)");
4636 else
4637 end_mouse();
4639 break;
4640 #endif
4643 if(just_flip_value){
4644 if(cl->value && cl->value[0])
4645 cl->value[1] = (cl->value[1] == ' ') ? 'X' : ' ';
4647 else{
4649 * This fork is only called from the checkbox_tool, which has
4650 * varmem set to index correctly and cl->var set correctly.
4652 if(cl->value)
4653 fs_give((void **)&cl->value);
4655 cl->value = pretty_value(ps, cl);
4661 * new_confline - create new CONF_S zero it out, and insert it after current.
4662 * NOTE current gets set to the new CONF_S too!
4664 CONF_S *
4665 new_confline(CONF_S **current)
4667 CONF_S *p;
4669 p = (CONF_S *)fs_get(sizeof(CONF_S));
4670 memset((void *)p, 0, sizeof(CONF_S));
4671 if(current){
4672 if(*current){
4673 p->next = (*current)->next;
4674 (*current)->next = p;
4675 p->prev = *current;
4676 if(p->next)
4677 p->next->prev = p;
4680 *current = p;
4683 return(p);
4690 void
4691 snip_confline(CONF_S **p)
4693 CONF_S *q;
4696 * Be careful. We need this line because the
4697 * q->prev->next = ...
4698 * may change q itself if &q == &q->prev->next.
4699 * Then the use of q in the next line is wrong.
4700 * That's what happens if we pass in the address of
4701 * some ->next and use *p directly instead of q.
4703 q = *p;
4705 if(q){
4706 /* Yank it from the linked list */
4707 if(q->prev)
4708 q->prev->next = q->next;
4710 if(q->next)
4711 q->next->prev = q->prev;
4713 /* Then free up it's memory */
4714 q->prev = q->next = NULL;
4715 free_conflines(&q);
4723 void
4724 free_conflines(CONF_S **p)
4726 if(*p){
4727 free_conflines(&(*p)->next);
4729 if((*p)->varname)
4730 fs_give((void **) &(*p)->varname);
4732 if((*p)->value)
4733 fs_give((void **) &(*p)->value);
4735 fs_give((void **) p);
4743 CONF_S *
4744 first_confline(CONF_S *p)
4746 while(p && p->prev)
4747 p = p->prev;
4749 return(p);
4754 * First selectable confline.
4756 CONF_S *
4757 first_sel_confline(CONF_S *p)
4759 for(p = first_confline(p); p && (p->flags&CF_NOSELECT); p=next_confline(p))
4760 ;/* do nothing */
4762 return(p);
4769 CONF_S *
4770 last_confline(CONF_S *p)
4772 while(p && p->next)
4773 p = p->next;
4775 return(p);
4783 fixed_var(struct variable *v, char *action, char *name)
4785 char **lval;
4787 if(v && v->is_fixed
4788 && (!v->is_list
4789 || ((lval=v->fixed_val.l) && lval[0]
4790 && strcmp(INHERIT, lval[0]) != 0))){
4791 q_status_message2(SM_ORDER, 3, 3,
4792 "Can't %s sys-admin defined %s.",
4793 action ? action : "change", name ? name : "value");
4794 return(1);
4797 return(0);
4801 void
4802 exception_override_warning(struct variable *v)
4804 char **lval;
4806 /* if exceptions config file exists and we're not editing it */
4807 if(v && (ps_global->ew_for_except_vars != Main) && (ew == Main)){
4808 if((!v->is_list && PVAL(v, ps_global->ew_for_except_vars)) ||
4809 (v->is_list && (lval=LVAL(v, ps_global->ew_for_except_vars)) &&
4810 lval[0] && strcmp(INHERIT, lval[0]) != 0))
4811 q_status_message1(SM_ORDER, 3, 3,
4812 _("Warning: \"%s\" is overridden in your exceptions configuration"),
4813 v->name);
4818 void
4819 offer_to_fix_pinerc(struct pine *ps)
4821 struct variable *v;
4822 char prompt[300];
4823 char *p, *q;
4824 char **list;
4825 char **list_fixed;
4826 int rv = 0, write_main = 0, write_post = 0;
4827 int i, k, j, need, exc;
4828 char *clear = ": delete it";
4829 char ***plist;
4831 dprint((4, "offer_to_fix_pinerc()\n"));
4833 ps->fix_fixed_warning = 0; /* so we only ask first time */
4835 if(ps->readonly_pinerc)
4836 return;
4838 set_titlebar(_("FIXING PINERC"), ps->mail_stream,
4839 ps->context_current,
4840 ps->cur_folder, ps->msgmap, 1, FolderName, 0, 0, NULL);
4842 if(want_to(_("Some of your options conflict with site policy. Investigate"),
4843 'y', 'n', NO_HELP, WT_FLUSH_IN) != 'y')
4844 return;
4846 /* space want_to requires in addition to the string you pass in */
4847 #define WANTTO_SPACE 6
4848 need = WANTTO_SPACE + utf8_width(clear);
4850 for(v = ps->vars; v->name; v++){
4851 if(!v->is_fixed ||
4852 !v->is_user ||
4853 v->is_obsolete ||
4854 v == &ps->vars[V_FEATURE_LIST]) /* handle feature-list below */
4855 continue;
4857 prompt[0] = '\0';
4859 if(v->is_list &&
4860 (v->post_user_val.l || v->main_user_val.l)){
4861 char **active_list;
4863 active_list = v->post_user_val.l ? v->post_user_val.l
4864 : v->main_user_val.l;
4865 if(*active_list){
4866 snprintf(prompt, sizeof(prompt), _("Your setting for %s is "), v->name);
4867 prompt[sizeof(prompt)-1] = '\0';
4868 p = prompt + strlen(prompt);
4869 for(i = 0; active_list[i]; i++){
4870 if(utf8_width(prompt) > ps->ttyo->screen_cols - need)
4871 break;
4872 if(i && sizeof(prompt)-(p-prompt) > 0)
4873 *p++ = ',';
4875 sstrncpy(&p, active_list[i], sizeof(prompt)-(p-prompt));
4876 if(sizeof(prompt)-(p-prompt) > 0)
4877 *p = '\0';
4879 prompt[sizeof(prompt)-1] = '\0';
4882 if(sizeof(prompt)-(p-prompt) > 0)
4883 *p = '\0';
4885 else
4886 snprintf(prompt, sizeof(prompt), _("Your setting for %s is %s"), v->name, _(empty_val2));
4888 else{
4889 if(v->post_user_val.p || v->main_user_val.p){
4890 char *active_var;
4892 active_var = v->post_user_val.p ? v->post_user_val.p
4893 : v->main_user_val.p;
4894 if(*active_var){
4895 snprintf(prompt, sizeof(prompt), _("Your setting for %s is %s"),
4896 v->name, active_var);
4898 else{
4899 snprintf(prompt, sizeof(prompt), _("Your setting for %s is %s"),
4900 v->name, _(empty_val2));
4905 prompt[sizeof(prompt)-1] = '\0';
4907 if(*prompt){
4908 if(utf8_width(prompt) > ps->ttyo->screen_cols - need)
4909 (void) utf8_truncate(prompt, ps->ttyo->screen_cols - need);
4911 (void) strncat(prompt, clear, sizeof(prompt)-strlen(prompt)-1);
4912 prompt[sizeof(prompt)-1] = '\0';
4913 if(want_to(prompt, 'y', 'n', NO_HELP, WT_NORM) == 'y'){
4914 if(v->is_list){
4915 if(v->main_user_val.l)
4916 write_main++;
4917 if(v->post_user_val.l)
4918 write_post++;
4920 else{
4921 if(v->main_user_val.p)
4922 write_main++;
4923 if(v->post_user_val.p)
4924 write_post++;
4927 if(delete_user_vals(v))
4928 rv++;
4935 * As always, feature-list has to be handled separately.
4937 exc = (ps->ew_for_except_vars != Main);
4938 v = &ps->vars[V_FEATURE_LIST];
4939 list_fixed = v->fixed_val.l;
4941 for(j = 0; j < 2; j++){
4942 plist = (j==0) ? &v->main_user_val.l : &v->post_user_val.l;
4943 list = *plist;
4944 if(list){
4945 for(i = 0; list[i]; i++){
4946 p = list[i];
4947 if(!struncmp(p, "no-", 3))
4948 p += 3;
4949 for(k = 0; list_fixed && list_fixed[k]; k++){
4950 q = list_fixed[k];
4951 if(!struncmp(q, "no-", 3))
4952 q += 3;
4953 if(!strucmp(q, p) && strucmp(list[i], list_fixed[k])){
4954 snprintf(prompt, sizeof(prompt), "Your %s is %s%s, fixed value is %s",
4955 p, p == list[i] ? _("ON") : _("OFF"),
4956 exc ? ((plist == &v->main_user_val.l) ? ""
4957 : " in postload-config")
4958 : "",
4959 q == list_fixed[k] ? _("ON") : _("OFF"));
4961 prompt[sizeof(prompt)-1] = '\0';
4962 if(utf8_width(prompt) > ps->ttyo->screen_cols - need)
4963 (void) utf8_truncate(prompt, ps->ttyo->screen_cols - need);
4965 (void) strncat(prompt, clear, sizeof(prompt)-strlen(prompt)-1);
4966 prompt[sizeof(prompt)-1] = '\0';
4967 if(want_to(prompt, 'y', 'n', NO_HELP, WT_NORM) == 'y'){
4968 rv++;
4970 if(plist == &v->main_user_val.l)
4971 write_main++;
4972 else
4973 write_post++;
4976 * Clear the feature from the user's pinerc
4977 * so that we'll stop bothering them when they
4978 * start up Pine.
4980 clear_feature(plist, p);
4983 * clear_feature scoots the list up, so if list[i] was
4984 * the last one going in, now it is the end marker. We
4985 * just decrement i so that it will get incremented and
4986 * then test == 0 in the for loop. We could just goto
4987 * outta_here to accomplish the same thing.
4989 if(!list[i])
4990 i--;
4999 if(write_main)
5000 write_pinerc(ps, Main, WRP_NONE);
5001 if(write_post)
5002 write_pinerc(ps, Post, WRP_NONE);
5004 return;
5009 * Adjust side effects that happen because variable changes values.
5011 * Var->user_val should be set to the new value before calling this.
5013 void
5014 fix_side_effects(struct pine *ps, struct variable *var, int revert)
5016 int val = 0;
5017 char **v, *q, **apval;
5018 struct variable *vars = ps->vars;
5020 /* move this up here so we get the Using default message */
5021 if(var == &ps->vars[V_PERSONAL_NAME]){
5022 if(!(var->main_user_val.p ||
5023 var->post_user_val.p) && ps->ui.fullname){
5024 if(var->current_val.p)
5025 fs_give((void **)&var->current_val.p);
5027 var->current_val.p = cpystr(ps->ui.fullname);
5031 if(!revert
5032 && ((!var->is_fixed
5033 && !var->is_list
5034 && !(var->main_user_val.p ||
5035 var->post_user_val.p)
5036 && var->current_val.p)
5038 (!var->is_fixed
5039 && var->is_list
5040 && !(var->main_user_val.l ||
5041 var->post_user_val.l)
5042 && var->current_val.l)))
5043 q_status_message(SM_ORDER,0,3,_("Using default value"));
5045 if(var == &ps->vars[V_USER_DOMAIN]){
5046 char *p, *q;
5048 if(ps->VAR_USER_DOMAIN
5049 && ps->VAR_USER_DOMAIN[0]
5050 && (p = strrindex(ps->VAR_USER_DOMAIN, '@'))){
5051 if(*(++p)){
5052 if(!revert)
5053 q_status_message2(SM_ORDER, 3, 5,
5054 _("User-Domain (%s) cannot contain \"@\"; using %s"),
5055 ps->VAR_USER_DOMAIN, p);
5056 q = ps->VAR_USER_DOMAIN;
5057 while((*q++ = *p++) != '\0')
5058 ;/* do nothing */
5060 else{
5061 if(!revert)
5062 q_status_message1(SM_ORDER, 3, 5,
5063 _("User-domain (%s) cannot contain \"@\"; deleting"),
5064 ps->VAR_USER_DOMAIN);
5066 if(ps->vars[V_USER_DOMAIN].post_user_val.p){
5067 fs_give((void **)&ps->vars[V_USER_DOMAIN].post_user_val.p);
5068 set_current_val(&vars[V_USER_DOMAIN], TRUE, TRUE);
5071 if(ps->VAR_USER_DOMAIN
5072 && ps->VAR_USER_DOMAIN[0]
5073 && (p = strrindex(ps->VAR_USER_DOMAIN, '@'))){
5074 if(ps->vars[V_USER_DOMAIN].main_user_val.p){
5075 fs_give((void **)&ps->vars[V_USER_DOMAIN].main_user_val.p);
5076 set_current_val(&vars[V_USER_DOMAIN], TRUE, TRUE);
5083 * Reset various pointers pertaining to domain name and such...
5085 init_hostname(ps);
5087 else if(var == &ps->vars[V_INBOX_PATH]){
5089 * fixup the inbox path based on global/default values...
5091 init_inbox_mapping(ps->VAR_INBOX_PATH, ps->context_list);
5093 if(!strucmp(ps->cur_folder, ps->inbox_name) && ps->mail_stream
5094 && strcmp(ps->VAR_INBOX_PATH, ps->mail_stream->mailbox)){
5096 * If we currently have "inbox" open and the mailbox name
5097 * doesn't match, reset the current folder's name and
5098 * remove the SP_INBOX flag.
5100 strncpy(ps->cur_folder, ps->mail_stream->mailbox,
5101 sizeof(ps->cur_folder)-1);
5102 ps->cur_folder[sizeof(ps->cur_folder)-1] = '\0';
5103 sp_set_fldr(ps->mail_stream, ps->cur_folder);
5104 sp_unflag(ps->mail_stream, SP_INBOX);
5105 ps->mangled_header = 1;
5107 else if(sp_inbox_stream()
5108 && strcmp(ps->VAR_INBOX_PATH, sp_inbox_stream()->original_mailbox)){
5109 MAILSTREAM *m = sp_inbox_stream();
5112 * if we don't have inbox directly open, but have it
5113 * open for new mail notification, close the stream like
5114 * any other ordinary folder, and clean up...
5116 if(m){
5117 sp_unflag(m, SP_PERMLOCKED | SP_INBOX);
5118 sp_set_fldr(m, m->mailbox);
5119 expunge_and_close(m, NULL, EC_NONE);
5123 else if(var == &ps->vars[V_INCCHECKTIMEO]){
5124 int old_value = ps->inc_check_timeout;
5126 if(SVAR_INC_CHECK_TIMEO(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5127 if(!revert)
5128 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5130 else
5131 ps->inc_check_timeout = old_value;
5133 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5134 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5136 else if(var == &ps->vars[V_INCCHECKINTERVAL]){
5137 int old_value = ps->inc_check_interval;
5139 if(SVAR_INC_CHECK_INTERV(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5140 if(!revert)
5141 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5143 else
5144 ps->inc_check_interval = old_value;
5146 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5147 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5149 else if(var == &ps->vars[V_INC2NDCHECKINTERVAL]){
5150 int old_value = ps->inc_second_check_interval;
5152 if(SVAR_INC_2NDCHECK_INTERV(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5153 if(!revert)
5154 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5156 else
5157 ps->inc_second_check_interval = old_value;
5159 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5160 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5162 else if(var == &ps->vars[V_INCCHECKLIST]){
5163 if(ps->context_list && ps->context_list->use & CNTXT_INCMNG)
5164 reinit_incoming_folder_list(ps, ps->context_list);
5166 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5167 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5169 else if(var == &ps->vars[V_ADDRESSBOOK] ||
5170 var == &ps->vars[V_GLOB_ADDRBOOK] ||
5171 #ifdef ENABLE_LDAP
5172 var == &ps->vars[V_LDAP_SERVERS] ||
5173 #endif
5174 var == &ps->vars[V_ABOOK_FORMATS]){
5175 addrbook_reset();
5177 else if(var == &ps->vars[V_INDEX_FORMAT]){
5178 reset_index_format();
5179 clear_index_cache(ps->mail_stream, 0);
5181 else if(var == &ps->vars[V_DEFAULT_FCC] ||
5182 var == &ps->vars[V_DEFAULT_SAVE_FOLDER]){
5183 init_save_defaults();
5185 else if(var == &ps->vars[V_KW_BRACES] ||
5186 var == &ps->vars[V_OPENING_SEP] ||
5187 var == &ps->vars[V_ALT_ADDRS]){
5188 clear_index_cache(ps->mail_stream, 0);
5190 else if(var == &ps->vars[V_KEYWORDS]){
5191 if(ps_global->keywords)
5192 free_keyword_list(&ps_global->keywords);
5194 if(var->current_val.l && var->current_val.l[0])
5195 ps_global->keywords = init_keyword_list(var->current_val.l);
5197 clear_index_cache(ps->mail_stream, 0);
5199 else if(var == &ps->vars[V_INIT_CMD_LIST]){
5200 if(!revert)
5201 q_status_message(SM_ASYNC, 0, 3,
5202 _("Initial command changes will affect your next Alpine session."));
5204 else if(var == &ps->vars[V_VIEW_HEADERS]){
5205 ps->view_all_except = 0;
5206 if(ps->VAR_VIEW_HEADERS)
5207 for(v = ps->VAR_VIEW_HEADERS; (q = *v) != NULL; v++)
5208 if(q[0]){
5209 char *p;
5211 removing_leading_white_space(q);
5212 /* look for colon or space or end */
5213 for(p = q; *p && !isspace((unsigned char)*p) && *p != ':'; p++)
5214 ;/* do nothing */
5216 *p = '\0';
5217 if(strucmp(q, ALL_EXCEPT) == 0)
5218 ps->view_all_except = 1;
5221 else if(var == &ps->vars[V_OVERLAP]){
5222 int old_value = ps->viewer_overlap;
5224 if(SVAR_OVERLAP(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5225 if(!revert)
5226 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5228 else
5229 ps->viewer_overlap = old_value;
5231 else if(var == &ps->vars[V_SLEEP]){
5232 int old_value = ps->sleep;
5234 if(SVAR_SLEEP(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5235 if(!revert)
5236 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5238 else
5239 ps->sleep = old_value;
5241 #ifdef SMIME
5242 else if(smime_related_var(ps, var)){
5243 smime_deinit();
5245 #endif /* SMIME */
5246 else if(var == &ps->vars[V_MAXREMSTREAM]){
5247 int old_value = ps->s_pool.max_remstream;
5249 if(SVAR_MAXREMSTREAM(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5250 if(!revert )
5251 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5253 else
5254 ps->s_pool.max_remstream = old_value;
5256 dprint((9, "max_remstream goes to %d\n",
5257 ps->s_pool.max_remstream));
5259 #ifndef _WINDOWS
5260 else if(var == &ps->vars[V_CHAR_SET]){
5261 char *err = NULL;
5263 if(F_ON(F_USE_SYSTEM_TRANS, ps)){
5264 if(!revert)
5265 q_status_message(SM_ORDER, 5, 5, _("This change has no effect because feature Use-System-Translation is on"));
5267 else{
5268 if(reset_character_set_stuff(&err) == -1)
5269 alpine_panic(err ? err : "trouble with Character-Set");
5270 else if(err){
5271 q_status_message(SM_ORDER | SM_DING, 3, 5, err);
5272 fs_give((void **) &err);
5276 else if(var == &ps->vars[V_KEY_CHAR_SET]){
5277 char *err = NULL;
5279 if(F_ON(F_USE_SYSTEM_TRANS, ps)){
5280 if(!revert)
5281 q_status_message(SM_ORDER, 5, 5, _("This change has no effect because feature Use-System-Translation is on"));
5283 else{
5284 if(reset_character_set_stuff(&err) == -1)
5285 alpine_panic(err ? err : "trouble with Character-Set");
5286 else if(err){
5287 q_status_message(SM_ORDER | SM_DING, 3, 5, err);
5288 fs_give((void **) &err);
5292 #endif /* ! _WINDOWS */
5293 else if(var == &ps->vars[V_POST_CHAR_SET]){
5294 update_posting_charset(ps, revert);
5296 else if(var == &ps->vars[V_MARGIN]){
5297 int old_value = ps->scroll_margin;
5299 if(SVAR_MARGIN(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5300 if(!revert)
5301 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5303 else
5304 ps->scroll_margin = old_value;
5306 else if(var == &ps->vars[V_DEADLETS]){
5307 int old_value = ps->deadlets;
5309 if(SVAR_DEADLETS(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5310 if(!revert)
5311 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5313 else
5314 ps->deadlets = old_value;
5316 else if(var == &ps->vars[V_FILLCOL]){
5317 if(SVAR_FILLCOL(ps, ps->composer_fillcol, tmp_20k_buf, SIZEOF_20KBUF)){
5318 if(!revert)
5319 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5322 else if(var == &ps->vars[V_QUOTE_SUPPRESSION]){
5323 val = ps->quote_suppression_threshold;
5324 if(val < Q_SUPP_LIMIT && val > 0)
5325 val = -val;
5327 if(ps->VAR_QUOTE_SUPPRESSION
5328 && SVAR_QUOTE_SUPPRESSION(ps, val, tmp_20k_buf, SIZEOF_20KBUF)){
5329 if(!revert)
5330 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5332 else{
5333 if(val > 0 && val < Q_SUPP_LIMIT){
5334 if(!revert){
5335 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Ignoring Quote-Suppression-Threshold value of %s, see help"), ps->VAR_QUOTE_SUPPRESSION);
5336 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
5337 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5340 else{
5341 if(val < 0 && val != Q_DEL_ALL)
5342 ps->quote_suppression_threshold = -val;
5343 else
5344 ps->quote_suppression_threshold = val;
5348 else if(var == &ps->vars[V_STATUS_MSG_DELAY]){
5349 if(SVAR_MSGDLAY(ps, ps->status_msg_delay, tmp_20k_buf, SIZEOF_20KBUF)){
5350 if(!revert)
5351 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5354 else if(var == &ps->vars[V_ACTIVE_MSG_INTERVAL]){
5355 if(SVAR_ACTIVEINTERVAL(ps, ps->active_status_interval, tmp_20k_buf, SIZEOF_20KBUF)){
5356 if(!revert)
5357 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5359 else{
5360 busy_cue(_("Active Example"), NULL, 0);
5361 sleep(5);
5362 cancel_busy_cue(-1);
5365 #if !defined(DOS) && !defined(OS2) && !defined(LEAVEOUTFIFO)
5366 else if(var == &ps->vars[V_FIFOPATH]){
5367 init_newmailfifo(ps->VAR_FIFOPATH);
5369 #endif
5370 else if(var == &ps->vars[V_NMW_WIDTH]){
5371 int old_value = ps->nmw_width;
5373 if(SVAR_NMW_WIDTH(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5374 if(!revert )
5375 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5377 else{
5378 #ifdef _WINDOWS
5379 if(old_value != ps->nmw_width)
5380 mswin_setnewmailwidth(old_value); /* actually the new value */
5381 #endif
5382 ps->nmw_width = old_value;
5385 else if(var == &ps->vars[V_TCPOPENTIMEO]){
5386 val = 30;
5387 if(!revert)
5388 if(ps->VAR_TCPOPENTIMEO && SVAR_TCP_OPEN(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5389 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5391 else if(var == &ps->vars[V_TCPREADWARNTIMEO]){
5392 val = 15;
5393 if(!revert)
5394 if(ps->VAR_TCPREADWARNTIMEO && SVAR_TCP_READWARN(ps,val,tmp_20k_buf, SIZEOF_20KBUF))
5395 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5397 else if(var == &ps->vars[V_TCPWRITEWARNTIMEO]){
5398 val = 0;
5399 if(!revert)
5400 if(ps->VAR_TCPWRITEWARNTIMEO && SVAR_TCP_WRITEWARN(ps,val,tmp_20k_buf, SIZEOF_20KBUF))
5401 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5403 else if(var == &ps->vars[V_TCPQUERYTIMEO]){
5404 val = 60;
5405 if(!revert)
5406 if(ps->VAR_TCPQUERYTIMEO && SVAR_TCP_QUERY(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5407 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5409 else if(var == &ps->vars[V_RSHOPENTIMEO]){
5410 val = 15;
5411 if(!revert)
5412 if(ps->VAR_RSHOPENTIMEO && SVAR_RSH_OPEN(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5413 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5415 else if(var == &ps->vars[V_SSHOPENTIMEO]){
5416 val = 15;
5417 if(!revert)
5418 if(ps->VAR_SSHOPENTIMEO && SVAR_SSH_OPEN(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5419 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5421 else if(var == &ps->vars[V_SIGNATURE_FILE]){
5422 if(ps->VAR_OPER_DIR && ps->VAR_SIGNATURE_FILE &&
5423 is_absolute_path(ps->VAR_SIGNATURE_FILE) &&
5424 !in_dir(ps->VAR_OPER_DIR, ps->VAR_SIGNATURE_FILE)){
5425 char *e;
5426 size_t l;
5428 l = strlen(ps->VAR_OPER_DIR) + 100;
5429 e = (char *) fs_get((l+1) * sizeof(char));
5430 snprintf(e, l+1, _("Warning: Sig file can't be outside of %s"),
5431 ps->VAR_OPER_DIR);
5432 e[l] = '\0';
5433 q_status_message(SM_ORDER, 3, 6, e);
5434 fs_give((void **)&e);
5437 else if(var == &ps->vars[V_OPER_DIR]){
5438 if(ps->VAR_OPER_DIR && !ps->VAR_OPER_DIR[0]){
5439 q_status_message(SM_ORDER, 3, 5, "Operating-dir is turned off.");
5440 fs_give((void **)&ps->vars[V_OPER_DIR].current_val.p);
5441 if(ps->vars[V_OPER_DIR].fixed_val.p)
5442 fs_give((void **)&ps->vars[V_OPER_DIR].fixed_val.p);
5443 if(ps->vars[V_OPER_DIR].global_val.p)
5444 fs_give((void **)&ps->vars[V_OPER_DIR].global_val.p);
5445 if(ps->vars[V_OPER_DIR].cmdline_val.p)
5446 fs_give((void **)&ps->vars[V_OPER_DIR].cmdline_val.p);
5447 if(ps->vars[V_OPER_DIR].post_user_val.p)
5448 fs_give((void **)&ps->vars[V_OPER_DIR].post_user_val.p);
5449 if(ps->vars[V_OPER_DIR].main_user_val.p)
5450 fs_give((void **)&ps->vars[V_OPER_DIR].main_user_val.p);
5453 else if(var == &ps->vars[V_MAILCHECK]){
5454 int timeo = 15;
5455 if(SVAR_MAILCHK(ps, timeo, tmp_20k_buf, SIZEOF_20KBUF)){
5456 set_input_timeout(15);
5457 if(!revert)
5458 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5460 else{
5461 set_input_timeout(timeo);
5462 if(get_input_timeout() == 0 && !revert){
5463 q_status_message(SM_ORDER, 4, 6,
5464 _("Warning: automatic new mail checking and mailbox checkpointing is disabled"));
5465 if(ps->VAR_INBOX_PATH && ps->VAR_INBOX_PATH[0] == '{')
5466 q_status_message(SM_ASYNC, 3, 6,
5467 _("Warning: Mail-Check-Interval=0 may cause IMAP server connection to time out"));
5471 else if(var == &ps->vars[V_MAILCHECKNONCURR]){
5472 val = (int) ps->check_interval_for_noncurr;
5473 if(ps->VAR_MAILCHECKNONCURR
5474 && SVAR_MAILCHKNONCURR(ps, val, tmp_20k_buf, SIZEOF_20KBUF)){
5475 if(!revert)
5476 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5478 else
5479 ps->check_interval_for_noncurr = (time_t) val;
5481 else if(var == &ps->vars[V_MAILDROPCHECK]){
5482 long rvl;
5484 rvl = 60L;
5485 if(ps->VAR_MAILDROPCHECK && SVAR_MAILDCHK(ps, rvl, tmp_20k_buf, SIZEOF_20KBUF))
5486 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5487 else{
5488 if(rvl == 0L)
5489 rvl = (60L * 60L * 24L * 100L); /* 100 days */
5491 if(rvl >= 60L)
5492 mail_parameters(NULL, SET_SNARFINTERVAL, (void *) rvl);
5495 else if(var == &ps->vars[V_NNTPRANGE]){
5496 long rvl;
5498 rvl = 0L;
5499 if(ps->VAR_NNTPRANGE && SVAR_NNTPRANGE(ps, rvl, tmp_20k_buf, SIZEOF_20KBUF))
5500 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5501 else{
5502 if(rvl >= 0L)
5503 mail_parameters(NULL, SET_NNTPRANGE, (void *) rvl);
5506 else if(var == &ps->vars[V_CUSTOM_HDRS] || var == &ps->vars[V_COMP_HDRS]){
5507 /* this will give warnings about headers that can't be changed */
5508 if(!revert && var->current_val.l && var->current_val.l[0])
5509 customized_hdr_setup(NULL, var->current_val.l, UseAsDef);
5511 #if defined(DOS) || defined(OS2)
5512 else if(var == &ps->vars[V_FOLDER_EXTENSION]){
5513 mail_parameters(NULL, SET_EXTENSION,
5514 (void *)var->current_val.p);
5516 else if(var == &ps->vars[V_NEWSRC_PATH]){
5517 if(var->current_val.p && var->current_val.p[0])
5518 mail_parameters(NULL, SET_NEWSRC,
5519 (void *)var->current_val.p);
5521 #endif
5522 else if(revert && standard_radio_var(ps, var)){
5524 cur_rule_value(var, TRUE, FALSE);
5525 if(var == &ps_global->vars[V_AB_SORT_RULE])
5526 addrbook_redo_sorts();
5527 else if(var == &ps_global->vars[V_THREAD_INDEX_STYLE]){
5528 clear_index_cache(ps_global->mail_stream, 0);
5529 set_lflags(ps_global->mail_stream, ps_global->msgmap,
5530 MN_COLL | MN_CHID, 0);
5531 if(SORT_IS_THREADED(ps_global->msgmap)
5532 && (SEP_THRDINDX() || COLL_THRDS()))
5533 collapse_threads(ps_global->mail_stream, ps_global->msgmap, NULL);
5535 adjust_cur_to_visible(ps_global->mail_stream, ps_global->msgmap);
5537 #ifndef _WINDOWS
5538 else if(var == &ps->vars[V_COLOR_STYLE]){
5539 pico_toggle_color(0);
5540 switch(ps->color_style){
5541 case COL_NONE:
5542 case COL_TERMDEF:
5543 pico_set_color_options(pico_trans_color() ? COLOR_TRANS_OPT : 0);
5544 break;
5545 case COL_ANSI8:
5546 pico_set_color_options(COLOR_ANSI8_OPT|COLOR_TRANS_OPT);
5547 break;
5548 case COL_ANSI16:
5549 pico_set_color_options(COLOR_ANSI16_OPT|COLOR_TRANS_OPT);
5550 break;
5551 case COL_ANSI256:
5552 pico_set_color_options(COLOR_ANSI256_OPT|COLOR_TRANS_OPT);
5553 break;
5556 if(ps->color_style != COL_NONE)
5557 pico_toggle_color(1);
5559 if(pico_usingcolor())
5560 pico_set_normal_color();
5562 clear_index_cache(ps_global->mail_stream, 0);
5563 ClearScreen();
5564 ps->mangled_screen = 1;
5566 #endif
5568 else if(revert && var == &ps->vars[V_SORT_KEY]){
5569 int def_sort_rev;
5571 decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev);
5572 ps->def_sort_rev = def_sort_rev;
5574 else if(var == &ps->vars[V_THREAD_MORE_CHAR] ||
5575 var == &ps->vars[V_THREAD_EXP_CHAR] ||
5576 var == &ps->vars[V_THREAD_LASTREPLY_CHAR]){
5578 if(var == &ps->vars[V_THREAD_LASTREPLY_CHAR] &&
5579 !(var->current_val.p && var->current_val.p[0])){
5580 if(var->current_val.p)
5581 fs_give((void **) &var->current_val.p);
5583 q_status_message1(SM_ORDER, 3, 5,
5584 _("\"%s\" can't be Empty, using default"), var->name);
5586 apval = APVAL(var, ew);
5587 if(*apval)
5588 fs_give((void **)apval);
5590 set_current_val(var, FALSE, FALSE);
5592 if(!(var->current_val.p && var->current_val.p[0]
5593 && !var->current_val.p[1])){
5594 if(var->current_val.p)
5595 fs_give((void **) &var->current_val.p);
5597 var->current_val.p = cpystr(DF_THREAD_LASTREPLY_CHAR);
5601 if(var == &ps->vars[V_THREAD_MORE_CHAR] ||
5602 var == &ps->vars[V_THREAD_EXP_CHAR] ||
5603 var == &ps->vars[V_THREAD_LASTREPLY_CHAR]){
5604 if(var->current_val.p && var->current_val.p[0] &&
5605 var->current_val.p[1]){
5606 q_status_message1(SM_ORDER, 3, 5,
5607 "Only first character of \"%s\" is used",
5608 var->name);
5609 var->current_val.p[1] = '\0';
5612 if(var->main_user_val.p && var->main_user_val.p[0] &&
5613 var->main_user_val.p[1])
5614 var->main_user_val.p[1] = '\0';
5616 if(var->post_user_val.p && var->post_user_val.p[0] &&
5617 var->post_user_val.p[1])
5618 var->post_user_val.p[1] = '\0';
5621 clear_index_cache(ps_global->mail_stream, 0);
5622 set_need_format_setup(ps_global->mail_stream);
5624 else if(var == &ps->vars[V_NNTP_SERVER]){
5625 free_contexts(&ps_global->context_list);
5626 init_folders(ps_global);
5628 else if(var == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){
5629 init_hostname(ps);
5631 else if(var == &ps->vars[V_PRINTER]){
5632 if(!revert && ps->vars[V_PERSONAL_PRINT_COMMAND].is_fixed){
5633 if(printer_value_check_and_adjust())
5634 q_status_message1(SM_ORDER, 3, 5,
5635 _("Can't set \"%s\" to that value, see Setup/Printer"),
5636 pretty_var_name(var->name));
5639 else if(var == &ps->vars[V_KW_COLORS] ||
5640 var == &ps->vars[V_INDEX_TOKEN_COLORS] ||
5641 var == &ps->vars[V_IND_PLUS_FORE_COLOR] ||
5642 var == &ps->vars[V_IND_IMP_FORE_COLOR] ||
5643 var == &ps->vars[V_IND_DEL_FORE_COLOR] ||
5644 var == &ps->vars[V_IND_ANS_FORE_COLOR] ||
5645 var == &ps->vars[V_IND_NEW_FORE_COLOR] ||
5646 var == &ps->vars[V_IND_UNS_FORE_COLOR] ||
5647 var == &ps->vars[V_IND_HIPRI_FORE_COLOR]||
5648 var == &ps->vars[V_IND_LOPRI_FORE_COLOR]||
5649 var == &ps->vars[V_IND_ARR_FORE_COLOR] ||
5650 var == &ps->vars[V_IND_REC_FORE_COLOR] ||
5651 var == &ps->vars[V_IND_FWD_FORE_COLOR] ||
5652 var == &ps->vars[V_IND_OP_FORE_COLOR] ||
5653 var == &ps->vars[V_IND_FROM_FORE_COLOR] ||
5654 var == &ps->vars[V_IND_SUBJ_FORE_COLOR] ||
5655 var == &ps->vars[V_IND_PLUS_BACK_COLOR] ||
5656 var == &ps->vars[V_IND_IMP_BACK_COLOR] ||
5657 var == &ps->vars[V_IND_DEL_BACK_COLOR] ||
5658 var == &ps->vars[V_IND_ANS_BACK_COLOR] ||
5659 var == &ps->vars[V_IND_NEW_BACK_COLOR] ||
5660 var == &ps->vars[V_IND_UNS_BACK_COLOR] ||
5661 var == &ps->vars[V_IND_ARR_BACK_COLOR] ||
5662 var == &ps->vars[V_IND_REC_BACK_COLOR] ||
5663 var == &ps->vars[V_IND_FWD_BACK_COLOR] ||
5664 var == &ps->vars[V_IND_OP_BACK_COLOR] ||
5665 var == &ps->vars[V_IND_FROM_BACK_COLOR] ||
5666 var == &ps->vars[V_IND_SUBJ_BACK_COLOR]){
5667 clear_index_cache(ps_global->mail_stream, 0);
5669 else if(var == score_act_global_ptr){
5670 int score;
5672 score = atoi(var->current_val.p);
5673 if(score < SCORE_MIN || score > SCORE_MAX){
5674 q_status_message2(SM_ORDER, 3, 5,
5675 _("Score Value must be in range %s to %s"),
5676 comatose(SCORE_MIN), comatose(SCORE_MAX));
5677 apval = APVAL(var, ew);
5678 if(*apval)
5679 fs_give((void **)apval);
5681 set_current_val(var, FALSE, FALSE);
5684 else if(var == scorei_pat_global_ptr || var == age_pat_global_ptr
5685 || var == size_pat_global_ptr || var == cati_global_ptr){
5686 apval = APVAL(var, ew);
5687 if(*apval){
5688 INTVL_S *iv;
5689 iv = parse_intvl(*apval);
5690 if(iv){
5691 fs_give((void **) apval);
5692 *apval = stringform_of_intvl(iv);
5693 free_intvl(&iv);
5695 else
5696 fs_give((void **) apval);
5699 set_current_val(var, FALSE, FALSE);
5701 else if(var == &ps->vars[V_FEATURE_LIST]){
5702 process_feature_list(ps, var->current_val.l, 0, 0, 0);
5704 else if(!revert && (var == &ps->vars[V_LAST_TIME_PRUNE_QUESTION] ||
5705 var == &ps->vars[V_REMOTE_ABOOK_HISTORY] ||
5706 var == &ps->vars[V_REMOTE_ABOOK_VALIDITY] ||
5707 var == &ps->vars[V_USERINPUTTIMEO] ||
5708 var == &ps->vars[V_NEWS_ACTIVE_PATH] ||
5709 var == &ps->vars[V_NEWS_SPOOL_DIR] ||
5710 var == &ps->vars[V_INCOMING_FOLDERS] ||
5711 var == &ps->vars[V_FOLDER_SPEC] ||
5712 var == &ps->vars[V_NEWS_SPEC] ||
5713 var == &ps->vars[V_DISABLE_DRIVERS] ||
5714 var == &ps->vars[V_DISABLE_AUTHS] ||
5715 var == &ps->vars[V_RSHPATH] ||
5716 var == &ps->vars[V_RSHCMD] ||
5717 var == &ps->vars[V_SSHCMD] ||
5718 var == &ps->vars[V_SSHPATH])){
5719 q_status_message2(SM_ASYNC, 0, 3,
5720 _("Changes%s%s will affect your next Alpine session."),
5721 var->name ? " to " : "", var->name ? var->name : "");
5724 if(!revert && (var == &ps->vars[V_TCPOPENTIMEO] ||
5725 var == &ps->vars[V_TCPREADWARNTIMEO] ||
5726 var == &ps->vars[V_TCPWRITEWARNTIMEO] ||
5727 var == &ps->vars[V_TCPQUERYTIMEO] ||
5728 var == &ps->vars[V_RSHOPENTIMEO] ||
5729 var == &ps->vars[V_SSHOPENTIMEO]))
5730 q_status_message(SM_ASYNC, 0, 3,
5731 _("Timeout changes will affect your next Alpine session."));
5736 * Compare saved user_val with current user_val to see if it changed.
5737 * If any have changed, change it back and take the appropriate action.
5739 void
5740 revert_to_saved_config(struct pine *ps, SAVED_CONFIG_S *vsave, int allow_hard_to_config_remotely)
5742 struct variable *vreal;
5743 SAVED_CONFIG_S *v;
5744 int i, n;
5745 int changed = 0;
5746 char *pval, **apval, **lval, ***alval;
5748 v = vsave;
5749 for(vreal = ps->vars; vreal->name; vreal++,v++){
5750 if(!save_include(ps, vreal, allow_hard_to_config_remotely))
5751 continue;
5753 changed = 0;
5754 if(vreal->is_list){
5755 lval = LVAL(vreal, ew);
5756 alval = ALVAL(vreal, ew);
5758 if((v->saved_user_val.l && !lval)
5759 || (!v->saved_user_val.l && lval))
5760 changed++;
5761 else if(!v->saved_user_val.l && !lval)
5762 ;/* no change, nothing to do */
5763 else
5764 for(i = 0; v->saved_user_val.l[i] || lval[i]; i++)
5765 if((v->saved_user_val.l[i]
5766 && (!lval[i]
5767 || strcmp(v->saved_user_val.l[i], lval[i])))
5769 (!v->saved_user_val.l[i] && lval[i])){
5770 changed++;
5771 break;
5774 if(changed){
5775 char **list;
5777 if(alval){
5778 if(*alval)
5779 free_list_array(alval);
5781 /* copy back the original one */
5782 if(v->saved_user_val.l){
5783 list = v->saved_user_val.l;
5784 n = 0;
5785 /* count how many */
5786 while(list[n])
5787 n++;
5789 *alval = (char **)fs_get((n+1) * sizeof(char *));
5791 for(i = 0; i < n; i++)
5792 (*alval)[i] = cpystr(v->saved_user_val.l[i]);
5794 (*alval)[n] = NULL;
5799 else{
5800 pval = PVAL(vreal, ew);
5801 apval = APVAL(vreal, ew);
5803 if((v->saved_user_val.p &&
5804 (!pval || strcmp(v->saved_user_val.p, pval))) ||
5805 (!v->saved_user_val.p && pval)){
5806 /* It changed, fix it */
5807 changed++;
5808 if(apval){
5809 /* free the changed value */
5810 if(*apval)
5811 fs_give((void **)apval);
5813 if(v->saved_user_val.p)
5814 *apval = cpystr(v->saved_user_val.p);
5819 if(changed){
5820 if(vreal == &ps->vars[V_FEATURE_LIST])
5821 set_feature_list_current_val(vreal);
5822 else
5823 set_current_val(vreal, TRUE, FALSE);
5825 fix_side_effects(ps, vreal, 1);
5831 SAVED_CONFIG_S *
5832 save_config_vars(struct pine *ps, int allow_hard_to_config_remotely)
5834 struct variable *vreal;
5835 SAVED_CONFIG_S *vsave, *v;
5837 vsave = (SAVED_CONFIG_S *)fs_get((V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
5838 memset((void *)vsave, 0, (V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
5839 v = vsave;
5840 for(vreal = ps->vars; vreal->name; vreal++,v++){
5841 if(!save_include(ps, vreal, allow_hard_to_config_remotely))
5842 continue;
5844 if(vreal->is_list){
5845 int n, i;
5846 char **list;
5848 if(LVAL(vreal, ew)){
5849 /* count how many */
5850 n = 0;
5851 list = LVAL(vreal, ew);
5852 while(list[n])
5853 n++;
5855 v->saved_user_val.l = (char **)fs_get((n+1) * sizeof(char *));
5856 memset((void *)v->saved_user_val.l, 0, (n+1)*sizeof(char *));
5857 for(i = 0; i < n; i++)
5858 v->saved_user_val.l[i] = cpystr(list[i]);
5860 v->saved_user_val.l[n] = NULL;
5863 else{
5864 if(PVAL(vreal, ew))
5865 v->saved_user_val.p = cpystr(PVAL(vreal, ew));
5869 return(vsave);
5873 void
5874 free_saved_config(struct pine *ps, SAVED_CONFIG_S **vsavep, int allow_hard_to_config_remotely)
5876 struct variable *vreal;
5877 SAVED_CONFIG_S *v;
5879 if(vsavep && *vsavep){
5880 for(v = *vsavep, vreal = ps->vars; vreal->name; vreal++,v++){
5881 if(!save_include(ps, vreal, allow_hard_to_config_remotely))
5882 continue;
5884 if(vreal->is_list){ /* free saved_user_val.l */
5885 if(v && v->saved_user_val.l)
5886 free_list_array(&v->saved_user_val.l);
5888 else if(v && v->saved_user_val.p)
5889 fs_give((void **)&v->saved_user_val.p);
5892 fs_give((void **)vsavep);
5898 * Returns positive if any thing was actually deleted.
5901 delete_user_vals(struct variable *v)
5903 int rv = 0;
5905 if(v){
5906 if(v->is_list){
5907 if(v->post_user_val.l){
5908 rv++;
5909 free_list_array(&v->post_user_val.l);
5911 if(v->main_user_val.l){
5912 rv++;
5913 free_list_array(&v->main_user_val.l);
5916 else{
5917 if(v->post_user_val.p){
5918 rv++;
5919 fs_give((void **)&v->post_user_val.p);
5921 if(v->main_user_val.p){
5922 rv++;
5923 fs_give((void **)&v->main_user_val.p);
5928 return(rv);
5933 * ../pith/conf.c required function
5936 unexpected_pinerc_change(void)
5938 Writechar(BELL, 0);
5939 if(want_to("Unexpected pinerc change! Overwrite with current config",
5940 'n', 0, NO_HELP, WT_FLUSH_IN) == 'n'){
5941 return(-1); /* abort pinerc write */
5944 return(0); /* overwrite */
5948 #ifdef _WINDOWS
5950 /*----------------------------------------------------------------------
5951 MSWin scroll callback. Called during scroll message processing.
5955 Args: cmd - what type of scroll operation.
5956 scroll_pos - paramter for operation.
5957 used as position for SCROLL_TO operation.
5959 Returns: TRUE - did the scroll operation.
5960 FALSE - was not able to do the scroll operation.
5961 ----*/
5963 config_scroll_callback (cmd, scroll_pos)
5964 int cmd;
5965 long scroll_pos;
5967 switch (cmd) {
5968 case MSWIN_KEY_SCROLLUPLINE:
5969 config_scroll_down (scroll_pos);
5970 break;
5972 case MSWIN_KEY_SCROLLDOWNLINE:
5973 config_scroll_up (scroll_pos);
5974 break;
5976 case MSWIN_KEY_SCROLLUPPAGE:
5977 config_scroll_down (BODY_LINES(ps_global));
5978 break;
5980 case MSWIN_KEY_SCROLLDOWNPAGE:
5981 config_scroll_up (BODY_LINES(ps_global));
5982 break;
5984 case MSWIN_KEY_SCROLLTO:
5985 config_scroll_to_pos (scroll_pos);
5986 break;
5989 option_screen_redrawer();
5990 fflush(stdout);
5992 return(TRUE);
5995 #endif /* _WINDOWS */