* clear out some warnings by gcc 9.3.1.
[alpine.git] / alpine / confscroll.c
blob4f366424ab0e53295c46cab9a545d9dc08060b6e
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-2020 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 "xoauth2conf.h"
37 #include "../pith/state.h"
38 #include "../pith/flag.h"
39 #include "../pith/list.h"
40 #include "../pith/conf.h"
41 #include "../pith/util.h"
42 #include "../pith/newmail.h"
43 #include "../pith/sort.h"
44 #include "../pith/thread.h"
45 #include "../pith/color.h"
46 #include "../pith/hist.h"
47 #include "../pith/icache.h"
48 #include "../pith/conf.h"
49 #include "../pith/init.h"
50 #include "../pith/folder.h"
51 #include "../pith/busy.h"
52 #include "../pith/tempfile.h"
53 #include "../pith/pattern.h"
54 #include "../pith/charconv/utf8.h"
57 #define CONFIG_SCREEN_HELP_TITLE _("HELP FOR SETUP CONFIGURATION")
59 /* TRANSLATORS: Empty Value is what is shown in the configuration
60 screen when the user not only does not set an option but also
61 wants to explicitly not use the default value. Empty value means
62 an option with no value. */
63 char *empty_val = N_("Empty Value");
64 char *empty_val2 = N_("<Empty Value>");
65 /* TRANSLATORS: No Value set is similar to Empty Value, but the
66 user has not explicitly decided to not use the default. It is
67 just an option which the user has left at the default value. */
68 char *no_val = N_("No Value Set");
69 /* TRANSLATORS: Value is Fixed is what is displayed in the config
70 screen when the system managers have set an option to a specific
71 value and they don't allow the user to change it. The value
72 is fixed to a certain value. This isn't the same word as
73 Repaired, it means Unchanging. */
74 char *fixed_val = N_("Value is Fixed");
75 char yesstr[] = "Yes";
76 char nostr[] = "No";
79 EditWhich ew = Main;
82 OPT_SCREEN_S *opt_screen;
86 * This is pretty ugly. Some of the routines operate differently depending
87 * on which variable they are operating on. Sometimes those variables are
88 * global (real alpine.h V_ style variables) and sometimes they are just
89 * local variables (as in role_config_edit_screen). These pointers are here
90 * so that the routines can figure out which variable they are operating
91 * on and do the right thing.
93 struct variable *score_act_global_ptr,
94 *scorei_pat_global_ptr,
95 *age_pat_global_ptr,
96 *size_pat_global_ptr,
97 *cati_global_ptr,
98 *cat_cmd_global_ptr,
99 *cat_lim_global_ptr,
100 *startup_ptr,
101 *role_comment_ptr,
102 *role_forw_ptr,
103 *role_repl_ptr,
104 *role_fldr_ptr,
105 *role_afrom_ptr,
106 *role_filt_ptr,
107 *role_status1_ptr,
108 *role_status2_ptr,
109 *role_status3_ptr,
110 *role_status4_ptr,
111 *role_status5_ptr,
112 *role_status6_ptr,
113 *role_status7_ptr,
114 *role_status8_ptr,
115 *msg_state1_ptr,
116 *msg_state2_ptr,
117 *msg_state3_ptr,
118 *msg_state4_ptr;
121 typedef NAMEVAL_S *(*PTR_TO_RULEFUNC)(int);
125 * Internal prototypes
127 PTR_TO_RULEFUNC rulefunc_from_var(struct pine *, struct variable *);
128 void set_radio_pretty_vals(struct pine *, CONF_S **);
129 int save_include(struct pine *, struct variable *, int);
130 void config_scroll_up(long);
131 void config_scroll_down(long);
132 void config_scroll_to_pos(long);
133 CONF_S *config_top_scroll(struct pine *, CONF_S *);
134 void update_option_screen(struct pine *, OPT_SCREEN_S *, Pos *);
135 void print_option_screen(OPT_SCREEN_S *, char *);
136 void option_screen_redrawer(void);
137 char *text_pretty_value(struct pine *, CONF_S *);
138 char *checkbox_pretty_value(struct pine *, CONF_S *);
139 char *yesno_pretty_value(struct pine *, CONF_S *);
140 char *radio_pretty_value(struct pine *, CONF_S *);
141 char *sigfile_pretty_value(struct pine *, CONF_S *);
142 char *color_pretty_value(struct pine *, CONF_S *);
143 char *sort_pretty_value(struct pine *, CONF_S *);
144 int longest_feature_name(void);
145 COLOR_PAIR *sample_color(struct pine *, struct variable *);
146 COLOR_PAIR *sampleexc_color(struct pine *, struct variable *);
147 void clear_feature(char ***, char *);
148 CONF_S *last_confline(CONF_S *);
149 #ifdef _WINDOWS
150 int config_scroll_callback(int, long);
151 #endif
155 * We test for this same set of vars in a few places.
158 standard_radio_var(struct pine *ps, struct variable *v)
160 return(v == &ps->vars[V_SAVED_MSG_NAME_RULE] ||
161 v == &ps->vars[V_FCC_RULE] ||
162 v == &ps->vars[V_GOTO_DEFAULT_RULE] ||
163 v == &ps->vars[V_INCOMING_STARTUP] ||
164 v == &ps->vars[V_PRUNING_RULE] ||
165 v == &ps->vars[V_REOPEN_RULE] ||
166 v == &ps->vars[V_THREAD_DISP_STYLE] ||
167 v == &ps->vars[V_THREAD_INDEX_STYLE] ||
168 v == &ps->vars[V_FLD_SORT_RULE] ||
169 #ifndef _WINDOWS
170 v == &ps->vars[V_COLOR_STYLE] ||
171 #endif
172 v == &ps->vars[V_INDEX_COLOR_STYLE] ||
173 v == &ps->vars[V_TITLEBAR_COLOR_STYLE] ||
174 v == &ps->vars[V_AB_SORT_RULE]);
178 PTR_TO_RULEFUNC
179 rulefunc_from_var(struct pine *ps, struct variable *v)
181 PTR_TO_RULEFUNC rulefunc = NULL;
183 if(v == &ps->vars[V_SAVED_MSG_NAME_RULE])
184 rulefunc = save_msg_rules;
185 else if(v == &ps->vars[V_FCC_RULE])
186 rulefunc = fcc_rules;
187 else if(v == &ps->vars[V_GOTO_DEFAULT_RULE])
188 rulefunc = goto_rules;
189 else if(v == &ps->vars[V_INCOMING_STARTUP])
190 rulefunc = incoming_startup_rules;
191 else if(v == startup_ptr)
192 rulefunc = startup_rules;
193 else if(v == &ps->vars[V_PRUNING_RULE])
194 rulefunc = pruning_rules;
195 else if(v == &ps->vars[V_REOPEN_RULE])
196 rulefunc = reopen_rules;
197 else if(v == &ps->vars[V_THREAD_DISP_STYLE])
198 rulefunc = thread_disp_styles;
199 else if(v == &ps->vars[V_THREAD_INDEX_STYLE])
200 rulefunc = thread_index_styles;
201 else if(v == &ps->vars[V_FLD_SORT_RULE])
202 rulefunc = fld_sort_rules;
203 else if(v == &ps->vars[V_AB_SORT_RULE])
204 rulefunc = ab_sort_rules;
205 else if(v == &ps->vars[V_INDEX_COLOR_STYLE])
206 rulefunc = index_col_style;
207 else if(v == &ps->vars[V_TITLEBAR_COLOR_STYLE])
208 rulefunc = titlebar_col_style;
209 #ifndef _WINDOWS
210 else if(v == &ps->vars[V_COLOR_STYLE])
211 rulefunc = col_style;
212 #endif
214 return(rulefunc);
218 void
219 standard_radio_setup(struct pine *ps, CONF_S **cl, struct variable *v, CONF_S **first_line)
221 int i, rindent = 12;
222 CONF_S *ctmpb;
223 PTR_TO_RULEFUNC rulefunc;
224 NAMEVAL_S *f;
225 char b[100];
227 if(!(cl && *cl))
228 return;
230 rulefunc = rulefunc_from_var(ps, v);
231 ctmpb = (*cl);
233 (*cl)->flags |= CF_NOSELECT;
234 (*cl)->keymenu = &config_radiobutton_keymenu;
235 (*cl)->tool = NULL;
237 /* put a nice delimiter before list */
238 new_confline(cl)->var = NULL;
239 (*cl)->varnamep = ctmpb;
240 (*cl)->keymenu = &config_radiobutton_keymenu;
241 (*cl)->help = NO_HELP;
242 (*cl)->tool = radiobutton_tool;
243 (*cl)->valoffset = rindent;
244 (*cl)->flags |= CF_NOSELECT;
245 /* TRANSLATORS: Set and Rule Values are the headings for an option
246 that can take one of several values. Underneath the Set heading
247 will be a column where one possibility is turned on (is Set).
248 The other column will be very short descriptions of what
249 the possibilities are (the Rule Values). */
250 utf8_snprintf(b, sizeof(b), "%-5.5w %s", _("Set"), _("Rule Values"));
251 (*cl)->value = cpystr(b);
253 new_confline(cl)->var = NULL;
254 (*cl)->varnamep = ctmpb;
255 (*cl)->keymenu = &config_radiobutton_keymenu;
256 (*cl)->help = NO_HELP;
257 (*cl)->tool = radiobutton_tool;
258 (*cl)->valoffset = rindent;
259 (*cl)->flags |= CF_NOSELECT;
260 (*cl)->value = cpystr("--- ----------------------");
262 if(rulefunc)
263 for(i = 0; (f = (*rulefunc)(i)); i++){
264 new_confline(cl)->var = v;
265 if(first_line && !*first_line && !pico_usingcolor())
266 *first_line = (*cl);
268 (*cl)->varnamep = ctmpb;
269 (*cl)->keymenu = &config_radiobutton_keymenu;
270 (*cl)->help = (v == startup_ptr)
271 ? h_config_other_startup
272 : config_help(v - ps->vars,0);
273 (*cl)->tool = radiobutton_tool;
274 (*cl)->valoffset = rindent;
275 (*cl)->varmem = i;
276 (*cl)->value = pretty_value(ps, *cl);
282 * Reset the displayed values for all of the lines for this
283 * variable because others besides this line may change.
285 void
286 set_radio_pretty_vals(struct pine *ps, CONF_S **cl)
288 CONF_S *ctmp;
290 if(!(cl && *cl &&
291 ((*cl)->var == &ps->vars[V_SORT_KEY] ||
292 standard_radio_var(ps, (*cl)->var) ||
293 (*cl)->var == startup_ptr)))
294 return;
296 /* hunt backwards */
297 for(ctmp = *cl;
298 ctmp && !(ctmp->flags & CF_NOSELECT) && !ctmp->varname;
299 ctmp = prev_confline(ctmp)){
300 if(ctmp->value)
301 fs_give((void **)&ctmp->value);
303 ctmp->value = pretty_value(ps, ctmp);
306 /* hunt forwards */
307 for(ctmp = *cl;
308 ctmp && !ctmp->varname && !(ctmp->flags & CF_NOSELECT);
309 ctmp = next_confline(ctmp)){
310 if(ctmp->value)
311 fs_give((void **)&ctmp->value);
313 ctmp->value = pretty_value(ps, ctmp);
319 * test whether or not a var is
321 * returns: 1 if it should be excluded, 0 otw
324 exclude_config_var(struct pine *ps, struct variable *var, int allow_hard_to_config_remotely)
326 if((ew != Main && (var->is_onlymain)) ||
327 (ew != ps_global->ew_for_except_vars && var->is_outermost))
328 return(1);
330 if(allow_hard_to_config_remotely)
331 return(!(var->is_user && var->is_used && !var->is_obsolete));
333 switch(var - ps->vars){
334 case V_HTML_DIRECTORY :
335 case V_MAIL_DIRECTORY :
336 case V_INCOMING_FOLDERS :
337 case V_FOLDER_SPEC :
338 case V_NEWS_SPEC :
339 case V_STANDARD_PRINTER :
340 case V_LAST_TIME_PRUNE_QUESTION :
341 case V_LAST_VERS_USED :
342 case V_ADDRESSBOOK :
343 case V_GLOB_ADDRBOOK :
344 case V_DISABLE_DRIVERS :
345 case V_DISABLE_AUTHS :
346 case V_ENCRYPTION_RANGE :
347 case V_REMOTE_ABOOK_METADATA :
348 case V_REMOTE_ABOOK_HISTORY :
349 case V_REMOTE_ABOOK_VALIDITY :
350 case V_OPER_DIR :
351 case V_USERINPUTTIMEO :
352 case V_TCPOPENTIMEO :
353 case V_TCPREADWARNTIMEO :
354 case V_TCPWRITEWARNTIMEO :
355 case V_TCPQUERYTIMEO :
356 case V_QUITQUERYTIMEO :
357 case V_RSHCMD :
358 case V_RSHPATH :
359 case V_RSHOPENTIMEO :
360 case V_SSHCMD :
361 case V_SSHPATH :
362 case V_SSHOPENTIMEO :
363 case V_SENDMAIL_PATH :
364 case V_NEW_VER_QUELL :
365 case V_PATTERNS :
366 case V_PAT_ROLES :
367 case V_PAT_FILTS :
368 case V_PAT_SCORES :
369 case V_PAT_INCOLS :
370 case V_PAT_OTHER :
371 case V_PAT_SRCH :
372 case V_PRINTER :
373 case V_PERSONAL_PRINT_COMMAND :
374 case V_PERSONAL_PRINT_CATEGORY :
375 case V_RSS_NEWS :
376 case V_RSS_WEATHER :
377 case V_WP_INDEXHEIGHT :
378 case V_WP_INDEXLINES :
379 case V_WP_AGGSTATE :
380 case V_WP_STATE :
381 case V_WP_COLUMNS :
382 #ifndef _WINDOWS
383 case V_OLD_CHAR_SET :
384 #endif /* ! _WINDOWS */
385 #if defined(DOS) || defined(OS2)
386 case V_UPLOAD_CMD :
387 case V_UPLOAD_CMD_PREFIX :
388 case V_DOWNLOAD_CMD :
389 case V_DOWNLOAD_CMD_PREFIX :
390 #ifdef _WINDOWS
391 case V_FONT_NAME :
392 case V_FONT_SIZE :
393 case V_FONT_STYLE :
394 case V_FONT_CHAR_SET :
395 case V_PRINT_FONT_NAME :
396 case V_PRINT_FONT_SIZE :
397 case V_PRINT_FONT_STYLE :
398 case V_PRINT_FONT_CHAR_SET :
399 case V_WINDOW_POSITION :
400 case V_CURSOR_STYLE :
401 #endif /* _WINDOWS */
402 #endif /* DOS */
403 #ifdef ENABLE_LDAP
404 case V_LDAP_SERVERS :
405 #endif /* ENABLE_LDAP */
406 return(1);
408 default:
409 break;
412 return(!(var->is_user && var->is_used && !var->is_obsolete &&
413 #ifdef SMIME
414 !smime_related_var(ps, var) &&
415 #endif /* SMIME */
416 !color_related_var(ps, var)));
421 * Test to indicate what should be saved in case user wants to abandon
422 * changes.
425 save_include(struct pine *ps, struct variable *v, int allow_hard_to_config_remotely)
427 return(!exclude_config_var(ps, v, allow_hard_to_config_remotely)
428 || (v->is_user
429 && v->is_used
430 && !v->is_obsolete
431 && (v == &ps->vars[V_PERSONAL_PRINT_COMMAND]
432 #ifdef ENABLE_LDAP
433 || v == &ps->vars[V_LDAP_SERVERS]
434 #endif
435 )));
440 * Handles screen painting and motion. Passes other commands to
441 * custom tools.
443 * Tool return values: Tools should return the following:
444 * 0 nothing changed
445 * -1 unrecognized command
446 * 1 something changed, conf_scroll_screen should remember that
447 * 2 tells conf_scroll_screen to return with value 1 or 0 depending
448 * on whether or not it has previously gotten a 1 from some tool.
449 * 3 tells conf_scroll_screen to return 1 (like 1 and 2 combined)
450 * ? Other tool-specific values can be used. They will cause
451 * conf_scroll_screen to return that value.
453 * Return values:
454 * 0 if nothing happened. That is, a tool returned 2 and we hadn't
455 * previously noted a return of 1
456 * 1 if something happened. That is, a tool returned 2 and we had
457 * previously noted a return of 1
458 * ? Tool-returned value different from -1, 0, 1, 2, or 3. This is it.
460 * Special proviso: If first_line->flags has CF_CHANGES set on entry, then
461 * that will cause things to behave like a change was made since entering
462 * this function.
465 conf_scroll_screen(struct pine *ps, OPT_SCREEN_S *screen, CONF_S *start_line, char *title, char *pdesc, int multicol, int *pos)
467 char tmp[MAXPATH+1];
468 char *utf8str;
469 UCS ch = 'x';
470 int cmd, i, j, done = 0, changes = 0;
471 int retval = 0;
472 int km_popped = 0, stay_in_col = 0;
473 struct key_menu *km = NULL;
474 CONF_S *ctmpa = NULL, *ctmpb = NULL;
475 Pos cursor_pos;
476 OtherMenu what_keymenu = FirstMenu;
477 void (*prev_redrawer)(void);
479 dprint((7, "conf_scroll_screen()\n"));
481 if(BODY_LINES(ps) < 1){
482 q_status_message(SM_ORDER | SM_DING, 3, 3, _("Screen too small"));
483 return(0);
486 if(screen && screen->ro_warning)
487 q_status_message1(SM_ORDER, 1, 3,
488 /* TRANSLATORS: "Config file not changeable," is what replaces the %s */
489 _("%s can't change options or settings"),
490 ps_global->restricted ? "Alpine demo"
491 : _("Config file not changeable,"));
493 screen->current = start_line;
494 if(start_line && start_line->flags & CF_CHANGES)
495 changes++;
497 opt_screen = screen;
498 ps->mangled_screen = 1;
499 ps->redrawer = option_screen_redrawer;
501 while(!done){
502 ps->user_says_cancel = 0;
503 if(km_popped){
504 km_popped--;
505 if(km_popped == 0){
506 clearfooter(ps);
507 ps->mangled_body = 1;
511 if(ps->mangled_screen){
512 ps->mangled_header = 1;
513 ps->mangled_footer = 1;
514 ps->mangled_body = 1;
515 ps->mangled_screen = 0;
518 /*----------- Check for new mail -----------*/
519 if(new_mail(0, NM_TIMING(ch), NM_STATUS_MSG | NM_DEFER_SORT) >= 0)
520 ps->mangled_header = 1;
522 if(ps->mangled_header){
523 set_titlebar(title, ps->mail_stream,
524 ps->context_current,
525 ps->cur_folder, ps->msgmap, 1, FolderName, 0, 0, NULL);
526 ps->mangled_header = 0;
529 update_option_screen(ps, screen, &cursor_pos);
531 if(F_OFF(F_SHOW_CURSOR, ps)){
532 cursor_pos.row = ps->ttyo->screen_rows - FOOTER_ROWS(ps);
533 cursor_pos.col = 0;
536 /*---- This displays new mail notification, or errors ---*/
537 if(km_popped){
538 FOOTER_ROWS(ps) = 3;
539 mark_status_unknown();
542 display_message(ch);
543 if(km_popped){
544 FOOTER_ROWS(ps) = 1;
545 mark_status_unknown();
548 if(ps->mangled_footer || km != screen->current->keymenu){
549 bitmap_t bitmap;
551 setbitmap(bitmap);
553 ps->mangled_footer = 0;
554 km = screen->current->keymenu;
556 if(multicol &&
557 (F_OFF(F_ARROW_NAV, ps_global) ||
558 F_ON(F_RELAXED_ARROW_NAV, ps_global))){
559 menu_clear_binding(km, KEY_LEFT);
560 menu_clear_binding(km, KEY_RIGHT);
561 menu_clear_binding(km, KEY_UP);
562 menu_clear_binding(km, KEY_DOWN);
563 menu_add_binding(km, KEY_UP, MC_CHARUP);
564 menu_add_binding(km, KEY_DOWN, MC_CHARDOWN);
565 menu_add_binding(km, KEY_LEFT, MC_PREVITEM);
566 menu_add_binding(km, ctrl('B'), MC_PREVITEM);
567 menu_add_binding(km, KEY_RIGHT, MC_NEXTITEM);
568 menu_add_binding(km, ctrl('F'), MC_NEXTITEM);
570 else{
571 menu_clear_binding(km, KEY_LEFT);
572 menu_clear_binding(km, KEY_RIGHT);
573 menu_clear_binding(km, KEY_UP);
574 menu_clear_binding(km, KEY_DOWN);
577 * Fix up arrow nav mode if necessary...
579 if(F_ON(F_ARROW_NAV, ps_global)){
580 int cmd;
582 if((cmd = menu_clear_binding(km, '<')) != MC_UNKNOWN){
583 menu_add_binding(km, '<', cmd);
584 menu_add_binding(km, KEY_LEFT, cmd);
587 if((cmd = menu_clear_binding(km, '>')) != MC_UNKNOWN){
588 menu_add_binding(km, '>', cmd);
589 menu_add_binding(km, KEY_RIGHT, cmd);
592 if((cmd = menu_clear_binding(km, 'p')) != MC_UNKNOWN){
593 menu_add_binding(km, 'p', cmd);
594 menu_add_binding(km, KEY_UP, cmd);
597 if((cmd = menu_clear_binding(km, 'n')) != MC_UNKNOWN){
598 menu_add_binding(km, 'n', cmd);
599 menu_add_binding(km, KEY_DOWN, cmd);
604 if(km_popped){
605 FOOTER_ROWS(ps) = 3;
606 clearfooter(ps);
609 draw_keymenu(km, bitmap, ps->ttyo->screen_cols,
610 1-FOOTER_ROWS(ps), 0, what_keymenu);
611 what_keymenu = SameMenu;
613 if(km_popped){
614 FOOTER_ROWS(ps) = 1;
615 mark_keymenu_dirty();
619 MoveCursor(cursor_pos.row, cursor_pos.col);
620 #ifdef MOUSE
621 mouse_in_content(KEY_MOUSE, -1, -1, 0, 0); /* prime the handler */
622 register_mfunc(mouse_in_content, HEADER_ROWS(ps_global), 0,
623 ps_global->ttyo->screen_rows -(FOOTER_ROWS(ps_global)+1),
624 ps_global->ttyo->screen_cols);
625 #endif
626 #ifdef _WINDOWS
627 mswin_setscrollcallback(config_scroll_callback);
628 #endif
629 /*------ Read the command from the keyboard ----*/
630 ch = READ_COMMAND(&utf8str);
631 #ifdef MOUSE
632 clear_mfunc(mouse_in_content);
633 #endif
634 #ifdef _WINDOWS
635 mswin_setscrollcallback(NULL);
636 #endif
638 cmd = menu_command(ch, km);
640 if(km_popped)
641 switch(cmd){
642 case MC_NONE:
643 case MC_OTHER:
644 case MC_RESIZE:
645 case MC_REPAINT:
646 km_popped++;
647 break;
649 default:
650 clearfooter(ps);
651 break;
654 switch(cmd){
655 case MC_OTHER :
656 what_keymenu = NextMenu;
657 ps->mangled_footer = 1;
658 break;
660 case MC_HELP: /* help! */
661 if(FOOTER_ROWS(ps) == 1 && km_popped == 0){
662 km_popped = 2;
663 ps->mangled_footer = 1;
664 break;
667 if(screen->current->help != NO_HELP){
668 prev_redrawer = ps_global->redrawer;
669 helper(screen->current->help,
670 (screen->current->help_title)
671 ? screen->current->help_title
672 : CONFIG_SCREEN_HELP_TITLE,
673 HLPD_SIMPLE);
674 ps_global->redrawer = prev_redrawer;
675 ps->mangled_screen = 1;
677 else
678 q_status_message(SM_ORDER,0,3,_("No help yet."));
680 break;
683 case MC_NEXTITEM: /* next list element */
684 case MC_CHARDOWN:
685 stay_in_col = 0;
686 if(screen->current->flags & CF_DOUBLEVAR){
687 /* if going from col1 to col2, it's simple */
688 if(!(screen->current->flags & CF_VAR2) && cmd == MC_NEXTITEM){
689 screen->current->flags |= CF_VAR2;
690 break;
693 /* otherwise we fall through to normal next */
694 stay_in_col = (screen->current->flags & CF_VAR2 &&
695 cmd == MC_CHARDOWN);
696 screen->current->flags &= ~CF_VAR2;
699 for(ctmpa = next_confline(screen->current), i = 1;
700 ctmpa && (ctmpa->flags & CF_NOSELECT);
701 ctmpa = next_confline(ctmpa), i++)
704 if(ctmpa){
705 screen->current = ctmpa;
706 if(screen->current->flags & CF_DOUBLEVAR && stay_in_col)
707 screen->current->flags |= CF_VAR2;
709 if(cmd == MC_CHARDOWN){
710 for(ctmpa = screen->top_line,
711 j = BODY_LINES(ps) - 1 - HS_MARGIN(ps);
712 j > 0 && ctmpa && ctmpa != screen->current;
713 ctmpa = next_confline(ctmpa), j--)
716 if(!j && ctmpa){
717 for(i = 0;
718 ctmpa && ctmpa != screen->current;
719 ctmpa = next_confline(ctmpa), i++)
722 if(i)
723 config_scroll_up(i);
727 else{
729 * Scroll screen a bit so we show the non-selectable
730 * lines at the bottom.
733 /* set ctmpa to the bottom line on the screen */
734 for(ctmpa = screen->top_line, j = BODY_LINES(ps) - 1;
735 j > 0 && ctmpa;
736 ctmpa = next_confline(ctmpa), j--)
739 i = 0;
740 if(ctmpa){
741 for(ctmpa = next_confline(ctmpa);
742 ctmpa &&
743 (ctmpa->flags & (CF_NOSELECT | CF_B_LINE)) ==
744 CF_NOSELECT;
745 ctmpa = next_confline(ctmpa), i++)
749 if(i)
750 config_scroll_up(i);
751 else
752 q_status_message(SM_ORDER,0,1, _("Already at end of screen"));
755 break;
757 case MC_PREVITEM: /* prev list element */
758 case MC_CHARUP:
759 stay_in_col = 0;
760 if(screen->current->flags & CF_DOUBLEVAR){
761 if(screen->current->flags & CF_VAR2 && cmd == MC_PREVITEM){
762 screen->current->flags &= ~CF_VAR2;
763 break;
766 /* otherwise we fall through to normal prev */
767 stay_in_col = (!(screen->current->flags & CF_VAR2) &&
768 cmd == MC_CHARUP);
769 screen->current->flags &= ~CF_VAR2;
771 else if(cmd == MC_CHARUP)
772 stay_in_col = 1;
774 ctmpa = screen->current;
775 i = 0;
777 if(ctmpa == config_top_scroll(ps, screen->top_line))
778 i = 1;
779 else if(i)
780 i++;
781 while((ctmpa = prev_confline(ctmpa))
782 && (ctmpa->flags&CF_NOSELECT));
784 if(ctmpa){
785 screen->current = ctmpa;
786 if(screen->current->flags & CF_DOUBLEVAR && !stay_in_col)
787 screen->current->flags |= CF_VAR2;
789 if((cmd == MC_CHARUP) && i)
790 config_scroll_down(i);
792 else
793 q_status_message(SM_ORDER, 0, 1,
794 _("Already at start of screen"));
796 break;
798 case MC_PAGEDN: /* page forward */
799 screen->current->flags &= ~CF_VAR2;
800 for(ctmpa = screen->top_line, i = BODY_LINES(ps);
801 i > 0 && ctmpa;
802 ctmpb = ctmpa, ctmpa = next_confline(ctmpa), i--)
805 if(ctmpa){ /* first line off bottom of screen */
806 ctmpb = ctmpa;
807 ps->mangled_body = 1;
808 /* find first selectable line on next page */
809 for(screen->top_line = ctmpa;
810 ctmpa && (ctmpa->flags & CF_NOSELECT);
811 ctmpa = next_confline(ctmpa))
815 * No selectable lines on next page. Slide up to first
816 * selectable.
818 if(!ctmpa){
819 for(ctmpa = prev_confline(ctmpb);
820 ctmpa && (ctmpa->flags & CF_NOSELECT);
821 ctmpa = prev_confline(ctmpa))
824 if(ctmpa)
825 screen->top_line = ctmpa;
828 else{ /* on last screen */
829 /* just move current down to last entry on screen */
830 if(ctmpb){ /* last line of data */
831 for(ctmpa = ctmpb, i = BODY_LINES(ps);
832 i > 0 && ctmpa && (ctmpa->flags & CF_NOSELECT);
833 ctmpa = prev_confline(ctmpa), i--)
836 if(ctmpa == screen->current){
837 q_status_message(SM_ORDER,0,1,
838 _("Already at end of screen"));
839 goto no_down;
842 ps->mangled_body = 1;
846 if(ctmpa)
847 screen->current = ctmpa;
848 no_down:
849 break;
851 case MC_PAGEUP: /* page backward */
852 ps->mangled_body = 1;
853 screen->current->flags &= ~CF_VAR2;
854 if(!(ctmpa=prev_confline(screen->top_line)))
855 ctmpa = screen->current;
857 for(i = BODY_LINES(ps) - 1;
858 i > 0 && prev_confline(ctmpa);
859 i--, ctmpa = prev_confline(ctmpa))
862 for(screen->top_line = ctmpa;
863 ctmpa && (ctmpa->flags & CF_NOSELECT);
864 ctmpa = next_confline(ctmpa))
867 if(ctmpa){
868 if(ctmpa == screen->current){
870 * We get to here if there was nothing selectable on
871 * the previous page. There still may be something
872 * selectable further back than the previous page,
873 * so look for that.
875 for(ctmpa = prev_confline(screen->top_line);
876 ctmpa && (ctmpa->flags & CF_NOSELECT);
877 ctmpa = prev_confline(ctmpa))
880 if(!ctmpa){
881 ctmpa = screen->current;
882 q_status_message(SM_ORDER, 0, 1,
883 _("Already at start of screen"));
887 screen->current = ctmpa;
890 break;
892 #ifdef MOUSE
893 case MC_MOUSE:
895 MOUSEPRESS mp;
897 mouse_get_last (NULL, &mp);
898 mp.row -= HEADER_ROWS(ps);
899 ctmpa = screen->top_line;
901 while (mp.row && ctmpa != NULL) {
902 --mp.row;
903 ctmpa = ctmpa->next;
906 if (ctmpa != NULL && !(ctmpa->flags & CF_NOSELECT)){
907 if(screen->current->flags & CF_DOUBLEVAR)
908 screen->current->flags &= ~CF_VAR2;
910 screen->current = ctmpa;
912 if(screen->current->flags & CF_DOUBLEVAR &&
913 mp.col >= screen->current->val2offset)
914 screen->current->flags |= CF_VAR2;
916 update_option_screen(ps, screen, &cursor_pos);
918 if(mp.button == M_BUTTON_LEFT && mp.doubleclick){
920 if(screen->current->tool){
921 unsigned flags;
922 int default_cmd;
924 flags = screen->current->flags;
925 flags |= (changes ? CF_CHANGES : 0);
927 default_cmd = menu_command(ctrl('M'), km);
928 switch(i=(*screen->current->tool)(ps, default_cmd,
929 &screen->current, flags)){
930 case -1:
931 case 0:
932 break;
934 case 1:
935 changes = 1;
936 break;
938 case 2:
939 retval = changes;
940 done++;
941 break;
943 case 3:
944 retval = 1;
945 done++;
946 break;
948 default:
949 retval = i;
950 done++;
951 break;
955 #ifdef _WINDOWS
956 else if(mp.button == M_BUTTON_RIGHT) {
957 MPopup other_popup[20];
958 int n = -1, cmd, i;
959 struct key_menu *sckm = screen->current->keymenu; /* only for popup */
961 if((cmd = menu_command(ctrl('M'), sckm)) != MC_UNKNOWN){
962 i = menu_binding_index(sckm, cmd);
963 other_popup[++n].type = tQueue;
964 other_popup[n].label.style = lNormal;
965 other_popup[n].label.string = sckm->keys[i].label;
966 other_popup[n].data.val = ctrl('M');
968 else if((cmd = menu_command('>', sckm)) != MC_UNKNOWN){
969 i = menu_binding_index(sckm, cmd);
970 other_popup[++n].type = tQueue;
971 other_popup[n].label.style = lNormal;
972 other_popup[n].label.string = sckm->keys[i].label;
973 other_popup[n].data.val = '>';
976 if(((i = menu_binding_index(sckm, MC_RGB1)) >= 0) ||
977 ((i = menu_binding_index(sckm, MC_RGB2)) >= 0)){
978 other_popup[++n].type = tQueue;
979 other_popup[n].label.style = lNormal;
980 other_popup[n].label.string = sckm->keys[i].label;
981 other_popup[n].data.val =
982 sckm->keys[i].bind.ch[0];
985 if((cmd = menu_command('<', sckm)) != MC_UNKNOWN){
986 i = menu_binding_index(sckm, cmd);
987 other_popup[++n].type = tQueue;
988 other_popup[n].label.style = lNormal;
989 other_popup[n].label.string = sckm->keys[i].label;
990 other_popup[n].data.val = '<';
992 else if((i = menu_binding_index(sckm, MC_EXIT)) >= 0){
993 other_popup[++n].type = tQueue;
994 other_popup[n].label.style = lNormal;
995 other_popup[n].label.string = sckm->keys[i].label;
996 other_popup[n].data.val =
997 sckm->keys[i].bind.ch[0];
1000 if((i = menu_binding_index(sckm, MC_HELP)) >= 0){
1001 if(n > 0)
1002 other_popup[++n].type = tSeparator;
1004 other_popup[++n].type = tQueue;
1005 other_popup[n].label.style = lNormal;
1006 other_popup[n].label.string = sckm->keys[i].label;
1007 other_popup[n].data.val = sckm->keys[i].bind.ch[0];
1010 if(n > 0){
1011 other_popup[++n].type = tTail;
1012 mswin_popup(other_popup);
1016 else if(mp.button == M_BUTTON_RIGHT) {
1017 MPopup other_popup[20];
1018 int n = -1, cmd, i;
1019 struct key_menu *sckm = screen->current->keymenu; /* only for popup */
1021 if((cmd = menu_command('<', sckm)) != MC_UNKNOWN){
1022 i = menu_binding_index(sckm, cmd);
1023 other_popup[++n].type = tQueue;
1024 other_popup[n].label.style = lNormal;
1025 other_popup[n].label.string = sckm->keys[i].label;
1026 other_popup[n].data.val = '<';
1028 else if((i = menu_binding_index(sckm, MC_EXIT)) >= 0){
1029 other_popup[++n].type = tQueue;
1030 other_popup[n].label.style = lNormal;
1031 other_popup[n].label.string = sckm->keys[i].label;
1032 other_popup[n].data.val = sckm->keys[i].bind.ch[0];
1035 other_popup[++n].type = tTail;
1037 if(n > 0)
1038 mswin_popup(other_popup);
1039 #endif
1042 break;
1043 #endif
1045 case MC_PRINTTXT: /* print screen */
1046 print_option_screen(screen, pdesc ? pdesc : "");
1047 break;
1049 case MC_WHEREIS: /* whereis */
1050 /*--- get string ---*/
1051 {int rc, found = 0;
1052 #define FOUND_IT 0x01
1053 #define FOUND_CURRENT 0x02
1054 #define FOUND_WRAPPED 0x04
1055 #define FOUND_NOSELECT 0x08
1056 #define FOUND_ABOVE 0x10
1057 char *result = NULL, buf[64];
1058 char *p, last[64];
1059 static HISTORY_S *history = NULL;
1060 HelpType help;
1061 static ESCKEY_S ekey[] = {
1062 {0, 0, "", ""},
1063 /* TRANSLATORS: go to Top of screen */
1064 {ctrl('Y'), 10, "^Y", N_("Top")},
1065 {ctrl('V'), 11, "^V", N_("Bottom")},
1066 {KEY_UP, 30, "", ""},
1067 {KEY_DOWN, 31, "", ""},
1068 {-1, 0, NULL, NULL}};
1069 #define KU_WI (3) /* index of KEY_UP */
1071 init_hist(&history, HISTSIZE);
1072 last[0] = '\0';
1073 if((p = get_prev_hist(history, "", 0, NULL)) != NULL){
1074 strncpy(last, p, sizeof(last));
1075 last[sizeof(last)-1] = '\0';
1078 ps->mangled_footer = 1;
1079 buf[0] = '\0';
1080 snprintf(tmp, sizeof(tmp), "Word to find %s%s%s: ",
1081 (last[0]) ? "[" : "",
1082 (last[0]) ? last : "",
1083 (last[0]) ? "]" : "");
1084 tmp[sizeof(tmp)-1] = '\0';
1085 help = NO_HELP;
1086 while(1){
1087 int flags = OE_APPEND_CURRENT;
1090 * 2 is really 1 because there will be one real entry and
1091 * one entry of "" because of the get_prev_hist above.
1093 if(items_in_hist(history) > 2){
1094 ekey[KU_WI].name = HISTORY_UP_KEYNAME;
1095 ekey[KU_WI].label = HISTORY_KEYLABEL;
1096 ekey[KU_WI+1].name = HISTORY_DOWN_KEYNAME;
1097 ekey[KU_WI+1].label = HISTORY_KEYLABEL;
1099 else{
1100 ekey[KU_WI].name = "";
1101 ekey[KU_WI].label = "";
1102 ekey[KU_WI+1].name = "";
1103 ekey[KU_WI+1].label = "";
1106 rc = optionally_enter(buf,-FOOTER_ROWS(ps),0,sizeof(buf),
1107 tmp,ekey,help,&flags);
1108 if(rc == 3)
1109 help = help == NO_HELP ? h_config_whereis : NO_HELP;
1110 else if(rc == 30){
1111 if((p = get_prev_hist(history, buf, 0, NULL)) != NULL){
1112 strncpy(buf, p, sizeof(buf));
1113 buf[sizeof(buf)-1] = '\0';
1115 else
1116 Writechar(BELL, 0);
1118 continue;
1120 else if(rc == 31){
1121 if((p = get_next_hist(history, buf, 0, NULL)) != NULL){
1122 strncpy(buf, p, sizeof(buf));
1123 buf[sizeof(buf)-1] = '\0';
1125 else
1126 Writechar(BELL, 0);
1128 continue;
1130 else if(rc == 0 || rc == 1 || rc == 10 || rc == 11 || !buf[0]){
1131 if(rc == 0 && !buf[0] && last[0])
1132 strncpy(buf, last, 64);
1134 break;
1138 screen->current->flags &= ~CF_VAR2;
1139 if(rc == 0 && buf[0]){
1140 CONF_S *started_here;
1142 save_hist(history, buf, 0, NULL);
1144 ch = KEY_DOWN;
1145 ctmpa = screen->current;
1147 * Skip over the unselectable lines of this "item"
1148 * before starting search so that we don't find the
1149 * same one again.
1151 while((ctmpb = next_confline(ctmpa)) &&
1152 (ctmpb->flags & CF_NOSELECT) &&
1153 !(ctmpb->flags & CF_STARTITEM))
1154 ctmpa = ctmpb;
1156 started_here = next_confline(ctmpa);
1157 while((ctmpa = next_confline(ctmpa)) != NULL)
1158 if(srchstr(ctmpa->varname, buf)
1159 || srchstr(ctmpa->value, buf)){
1161 found = FOUND_IT;
1163 * If this line is not selectable, back up to the
1164 * previous selectable line, but not past the
1165 * start of this "entry".
1167 if(ctmpa->flags & CF_NOSELECT)
1168 found |= FOUND_NOSELECT;
1170 while((ctmpa->flags & CF_NOSELECT) &&
1171 !(ctmpa->flags & CF_STARTITEM) &&
1172 (ctmpb = prev_confline(ctmpa)))
1173 ctmpa = ctmpb;
1176 * If that isn't selectable, better search forward
1177 * for something that is.
1179 while((ctmpa->flags & CF_NOSELECT) &&
1180 (ctmpb = next_confline(ctmpa))){
1181 ctmpa = ctmpb;
1182 found |= FOUND_ABOVE;
1186 * If that still isn't selectable, better search
1187 * backwards for something that is.
1189 while((ctmpa->flags & CF_NOSELECT) &&
1190 (ctmpb = prev_confline(ctmpa))){
1191 ctmpa = ctmpb;
1192 found &= ~FOUND_ABOVE;
1195 break;
1198 if(!found){
1199 found = FOUND_WRAPPED;
1200 ctmpa = first_confline(screen->current);
1202 while(ctmpa != started_here)
1203 if(srchstr(ctmpa->varname, buf)
1204 || srchstr(ctmpa->value, buf)){
1206 found |= FOUND_IT;
1207 if(ctmpa->flags & CF_NOSELECT)
1208 found |= FOUND_NOSELECT;
1210 while((ctmpa->flags & CF_NOSELECT) &&
1211 !(ctmpa->flags & CF_STARTITEM) &&
1212 (ctmpb = prev_confline(ctmpa)))
1213 ctmpa = ctmpb;
1215 while((ctmpa->flags & CF_NOSELECT) &&
1216 (ctmpb = next_confline(ctmpa))){
1217 ctmpa = ctmpb;
1218 found |= FOUND_ABOVE;
1221 if(ctmpa == screen->current)
1222 found |= FOUND_CURRENT;
1224 break;
1226 else
1227 ctmpa = next_confline(ctmpa);
1230 else if(rc == 10){
1231 screen->current = first_confline(screen->current);
1232 if(screen->current && screen->current->flags & CF_NOSELECT){
1233 for(ctmpa = next_confline(screen->current);
1234 ctmpa && (ctmpa->flags & CF_NOSELECT);
1235 ctmpa = next_confline(ctmpa))
1238 if(ctmpa)
1239 screen->current = ctmpa;
1242 /* TRANSLATORS: Searched to ... is the result of the search, searched
1243 to top means the search went past the bottom of the screen and
1244 wrapped back around to the top. */
1245 result = _("Searched to top");
1247 else if(rc == 11){
1248 screen->current = last_confline(screen->current);
1249 if(screen->current && screen->current->flags & CF_NOSELECT){
1250 for(ctmpa = prev_confline(screen->current);
1251 ctmpa && (ctmpa->flags & CF_NOSELECT);
1252 ctmpa = prev_confline(ctmpa))
1255 if(ctmpa)
1256 screen->current = ctmpa;
1259 result = _("Searched to bottom");
1261 else
1262 result = _("WhereIs cancelled");
1264 if((found & FOUND_IT) && ctmpa){
1265 strncpy(last, buf, 64);
1266 result =
1267 (found & FOUND_CURRENT && found & FOUND_WRAPPED && found & FOUND_NOSELECT)
1268 ? _("Current item contains the only match")
1269 : (found & FOUND_CURRENT && found & FOUND_WRAPPED)
1270 ? _("Current line contains the only match")
1271 : (found & FOUND_NOSELECT && found & FOUND_WRAPPED)
1272 ? ((found & FOUND_ABOVE)
1273 ? _("Search wrapped: word found in text above current line")
1274 : _("Search wrapped: word found in text below current line"))
1275 : (found & FOUND_WRAPPED)
1276 ? _("Search wrapped to beginning: word found")
1277 : (found & FOUND_NOSELECT)
1278 ? ((found & FOUND_ABOVE)
1279 ? _("Word found in text above current line")
1280 : _("Word found in text below current line"))
1281 : _("Word found");
1282 screen->current = ctmpa;
1285 q_status_message(SM_ORDER,0,3,result ? result : _("Word not found"));
1288 break;
1290 case MC_HOMEKEY:
1291 screen->current = first_confline(screen->current);
1292 if(screen->current && screen->current->flags & CF_NOSELECT){
1293 for(ctmpa = next_confline(screen->current);
1294 ctmpa && (ctmpa->flags & CF_NOSELECT);
1295 ctmpa = next_confline(ctmpa))
1298 if(ctmpa)
1299 screen->current = ctmpa;
1302 q_status_message(SM_ORDER,0,3, _("Moved to top"));
1303 break;
1305 case MC_ENDKEY:
1306 screen->current = last_confline(screen->current);
1307 if(screen->current && screen->current->flags & CF_NOSELECT){
1308 for(ctmpa = prev_confline(screen->current);
1309 ctmpa && (ctmpa->flags & CF_NOSELECT);
1310 ctmpa = prev_confline(ctmpa))
1313 if(ctmpa)
1314 screen->current = ctmpa;
1317 q_status_message(SM_ORDER,0,3, _("Moved to bottom"));
1318 break;
1320 case MC_XSHELP: /* help! */
1321 if(FOOTER_ROWS(ps) == 1 && km_popped == 0){
1322 km_popped = 2;
1323 ps->mangled_footer = 1;
1324 break;
1327 prev_redrawer = ps_global->redrawer;
1328 helper(h_xoauth2_config_screen, "XOAUTH2 CONFIGURATION SCREEN", HLPD_SIMPLE);
1329 ps_global->redrawer = prev_redrawer;
1330 ps->mangled_screen = 1;
1331 break;
1333 case MC_XSDELETE: /* Send caller to delete XOAUTH2 info */
1334 case MC_XSADD: /* Send caller to add XOAUTH2 info */
1335 if(pos){
1336 *pos = get_confline_number(screen->current);
1337 done++;
1338 retval = cmd == MC_XSADD ? 4 : 5;
1340 break;
1342 case MC_REPAINT: /* redraw the display */
1343 case MC_RESIZE:
1344 ClearScreen();
1345 ps->mangled_screen = 1;
1346 if(pos){
1347 *pos = get_confline_number(screen->current);
1348 done++;
1349 retval = 0;
1351 break;
1353 default:
1354 if(screen && screen->ro_warning){
1355 if(cmd == MC_EXIT){
1356 retval = 0;
1357 done++;
1359 else
1360 q_status_message1(SM_ORDER|SM_DING, 1, 3,
1361 _("%s can't change options or settings"),
1362 ps_global->restricted ? "Alpine demo"
1363 : _("Config file not changeable,"));
1365 else if(screen->current->tool){
1366 unsigned flags;
1368 flags = screen->current->flags;
1369 flags |= (changes ? CF_CHANGES : 0);
1371 switch(i=(*screen->current->tool)(ps, cmd,
1372 &screen->current, flags)){
1373 case -1:
1374 q_status_message2(SM_ORDER, 0, 2,
1375 /* TRANSLATORS: Command <command letter> not defined here.
1376 Leave the trailing %s which might be a parenthetical
1377 remark. */
1378 _("Command \"%s\" not defined here.%s"),
1379 pretty_command(ch),
1380 F_ON(F_BLANK_KEYMENU,ps) ? "" : " See key menu below.");
1381 break;
1383 case 0:
1384 break;
1386 case 1:
1387 changes = 1;
1388 break;
1390 case 2:
1391 retval = changes;
1392 done++;
1393 break;
1395 case 3:
1396 retval = 1;
1397 done++;
1398 break;
1400 default:
1401 retval = i;
1402 done++;
1403 break;
1407 break;
1409 case MC_UTF8:
1410 bogus_utf8_command(utf8str, "?");
1411 break;
1413 case MC_NONE: /* simple timeout */
1414 break;
1418 screen->current = first_confline(screen->current);
1419 free_conflines(&screen->current);
1420 return(retval);
1427 void
1428 config_scroll_up(long int n)
1430 CONF_S *ctmp = opt_screen->top_line;
1431 int cur_found = 0;
1433 if(n < 0)
1434 config_scroll_down(-n);
1435 else if(n){
1436 for(; n>0 && ctmp->next; n--){
1437 ctmp = next_confline(ctmp);
1438 if(prev_confline(ctmp) == opt_screen->current)
1439 cur_found++;
1442 opt_screen->top_line = ctmp;
1443 ps_global->mangled_body = 1;
1444 if(cur_found){
1445 for(ctmp = opt_screen->top_line;
1446 ctmp && (ctmp->flags & CF_NOSELECT);
1447 ctmp = next_confline(ctmp))
1450 if(ctmp)
1451 opt_screen->current = opt_screen->prev = ctmp;
1452 else {
1453 while(opt_screen->top_line->flags & CF_NOSELECT)
1454 opt_screen->top_line = prev_confline(opt_screen->top_line);
1455 opt_screen->current = opt_screen->prev = opt_screen->top_line;
1463 * config_scroll_down -
1465 void
1466 config_scroll_down(long int n)
1468 CONF_S *ctmp = opt_screen->top_line, *last_sel = NULL;
1469 int i;
1471 if(n < 0)
1472 config_scroll_up(-n);
1473 else if(n){
1474 for(; n>0 && ctmp->prev; n--)
1475 ctmp = prev_confline(ctmp);
1477 opt_screen->top_line = ctmp;
1478 ps_global->mangled_body = 1;
1479 for(ctmp = opt_screen->top_line, i = BODY_LINES(ps_global);
1480 i > 0 && ctmp && ctmp != opt_screen->current;
1481 ctmp = next_confline(ctmp), i--)
1482 if(!(ctmp->flags & CF_NOSELECT))
1483 last_sel = ctmp;
1485 if(!i && last_sel)
1486 opt_screen->current = opt_screen->prev = last_sel;
1492 * config_scroll_to_pos -
1494 void
1495 config_scroll_to_pos(long int n)
1497 CONF_S *ctmp;
1499 for(ctmp = first_confline(opt_screen->current);
1500 n && ctmp && ctmp != opt_screen->top_line;
1501 ctmp = next_confline(ctmp), n--)
1504 if(n == 0)
1505 while(ctmp && ctmp != opt_screen->top_line)
1506 if((ctmp = next_confline(ctmp)) != NULL)
1507 n--;
1509 config_scroll_up(n);
1514 * config_top_scroll - return pointer to the
1516 CONF_S *
1517 config_top_scroll(struct pine *ps, CONF_S *topline)
1519 int i;
1520 CONF_S *ctmp;
1522 for(ctmp = topline, i = HS_MARGIN(ps);
1523 ctmp && i;
1524 ctmp = next_confline(ctmp), i--)
1527 return(ctmp ? ctmp : topline);
1532 text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
1534 return(text_toolit(ps, cmd, cl, flags, 0));
1539 * simple text variable handler
1541 * note, things get a little involved due to the
1542 * screen struct <--> variable mapping. (but, once its
1543 * running it shouldn't need changing ;).
1545 * look_for_backslash == 1 means that backslash is an escape character.
1546 * In particular, \, can be used to put a literal comma
1547 * into a value. The value will still have the backslash
1548 * in it, but the comma after the backslash won't be treated
1549 * as an item separator.
1551 * returns: -1 on unrecognized cmd, 0 if no change, 1 if change
1552 * returns what conf_exit_cmd returns for exit command.
1555 text_toolit(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags, int look_for_backslash)
1557 char prompt[81], *sval, *tmp, *swap_val, **newval = NULL;
1558 char *pval, **apval, **lval, ***alval;
1559 char *olddefval = NULL;
1560 int rv = 0, skip_to_next = 0, after = 0, i = 4, j, k;
1561 int lowrange, hirange, incr, oeflags, oebufsize;
1562 int numval, repeat_key = 0;
1563 int curindex, previndex, nextindex, deefault;
1564 HelpType help;
1565 ESCKEY_S ekey[6];
1567 if((*cl)->var->is_list){
1568 lval = LVAL((*cl)->var, ew);
1569 alval = ALVAL((*cl)->var, ew);
1571 else{
1572 pval = PVAL((*cl)->var, ew);
1573 apval = APVAL((*cl)->var, ew);
1576 oebufsize = 6*MAXPATH;
1577 sval = (char *) fs_get(oebufsize*sizeof(char));
1578 sval[0] = '\0';
1580 if(flags&CF_NUMBER){ /* only happens if !is_list */
1581 incr = 1;
1582 if((*cl)->var == &ps->vars[V_FILLCOL]){
1583 lowrange = 1;
1584 hirange = MAX_FILLCOL;
1586 else if((*cl)->var == &ps->vars[V_OVERLAP]
1587 || (*cl)->var == &ps->vars[V_MARGIN]){
1588 lowrange = 0;
1589 hirange = 20;
1591 else if((*cl)->var == &ps->vars[V_QUOTE_SUPPRESSION]){
1592 lowrange = -(Q_SUPP_LIMIT-1);
1593 hirange = 1000;
1595 else if((*cl)->var == &ps->vars[V_MAXREMSTREAM]){
1596 lowrange = 0;
1597 hirange = 15;
1599 else if((*cl)->var == &ps->vars[V_STATUS_MSG_DELAY]){
1600 lowrange = -10;
1601 hirange = 30;
1603 else if((*cl)->var == &ps->vars[V_ACTIVE_MSG_INTERVAL]){
1604 lowrange = 0;
1605 hirange = 20;
1607 else if((*cl)->var == &ps->vars[V_MAILCHECK] ||
1608 (*cl)->var == &ps->vars[V_INCCHECKINTERVAL] ||
1609 (*cl)->var == &ps->vars[V_INC2NDCHECKINTERVAL] ||
1610 (*cl)->var == &ps->vars[V_MAILCHECKNONCURR]){
1611 lowrange = 0;
1612 hirange = 25000;
1613 incr = 15;
1615 else if((*cl)->var == &ps->vars[V_DEADLETS]){
1616 lowrange = 0;
1617 hirange = 9;
1619 else if((*cl)->var == &ps->vars[V_NMW_WIDTH]){
1620 lowrange = 20;
1621 hirange = MAX_SCREEN_COLS;
1623 else if((*cl)->var == score_act_global_ptr){
1624 lowrange = -100;
1625 hirange = 100;
1627 else if((*cl)->var == &ps->vars[V_TCPOPENTIMEO] ||
1628 (*cl)->var == &ps->vars[V_TCPREADWARNTIMEO] ||
1629 (*cl)->var == &ps->vars[V_TCPQUERYTIMEO]){
1630 lowrange = 5;
1631 hirange = 1000;
1633 else if((*cl)->var == &ps->vars[V_QUITQUERYTIMEO]){
1634 lowrange = 0;
1635 hirange = 1000;
1637 else if((*cl)->var == &ps->vars[V_TCPWRITEWARNTIMEO] ||
1638 (*cl)->var == &ps->vars[V_RSHOPENTIMEO] ||
1639 (*cl)->var == &ps->vars[V_SSHOPENTIMEO] ||
1640 (*cl)->var == &ps->vars[V_USERINPUTTIMEO]){
1641 lowrange = 0;
1642 hirange = 1000;
1644 else if((*cl)->var == &ps->vars[V_INCCHECKTIMEO]){
1645 lowrange = 1;
1646 hirange = 1000;
1648 else if((*cl)->var == &ps->vars[V_MAILDROPCHECK]){
1649 lowrange = 0;
1650 hirange = 1000000;
1651 incr = 60;
1653 else if((*cl)->var == &ps->vars[V_NNTPRANGE]){
1654 lowrange = 0;
1655 hirange = 1000000;
1656 incr = 100;
1658 else if((*cl)->var == &ps->vars[V_REMOTE_ABOOK_VALIDITY]){
1659 lowrange = -1;
1660 hirange = 25000;
1662 else if((*cl)->var == &ps->vars[V_REMOTE_ABOOK_HISTORY]){
1663 lowrange = 0;
1664 hirange = 100;
1666 else if((*cl)->var == cat_lim_global_ptr){
1667 lowrange = -1;
1668 hirange = 10000000;
1670 else{
1671 lowrange = 0;
1672 hirange = 25000;
1675 ekey[0].ch = -2;
1676 ekey[0].rval = 'x';
1677 ekey[0].name = "";
1678 ekey[0].label = "";
1679 ekey[1].ch = ctrl('P');
1680 ekey[1].rval = ctrl('P');
1681 ekey[1].name = "^P";
1682 ekey[1].label = N_("Decrease");
1683 ekey[2].ch = ctrl('N');
1684 ekey[2].rval = ctrl('N');
1685 ekey[2].name = "^N";
1686 ekey[2].label = N_("Increase");
1687 ekey[3].ch = KEY_DOWN;
1688 ekey[3].rval = ctrl('P');
1689 ekey[3].name = "";
1690 ekey[3].label = "";
1691 ekey[4].ch = KEY_UP;
1692 ekey[4].rval = ctrl('N');
1693 ekey[4].name = "";
1694 ekey[4].label = "";
1695 ekey[5].ch = -1;
1698 switch(cmd){
1699 case MC_ADD: /* add to list */
1700 if(fixed_var((*cl)->var, "add to", NULL)){
1701 break;
1703 else if(!(*cl)->var->is_list && pval){
1704 q_status_message(SM_ORDER, 3, 3,
1705 _("Only single value allowed. Use \"Change\"."));
1707 else{
1708 int maxwidth;
1709 char *p;
1711 if((*cl)->var->is_list
1712 && lval && lval[0] && lval[0][0]
1713 && (*cl)->value){
1714 char tmpval[101];
1715 /* regular add to an existing list */
1717 strncpy(tmpval, (*cl)->value, sizeof(tmpval));
1718 tmpval[sizeof(tmpval)-1] = '\0';
1719 removing_trailing_white_space(tmpval);
1721 /* 33 is the number of chars other than the value */
1722 maxwidth = MIN(80, ps->ttyo->screen_cols) - 15;
1723 k = MIN(18, MAX(maxwidth-33,0));
1724 if(utf8_width(tmpval) > k && k >= 3){
1725 (void) utf8_truncate(tmpval, k-3);
1726 strncat(tmpval, "...", sizeof(tmpval)-strlen(tmpval)-1);
1727 tmpval[sizeof(tmpval)-1] = '\0';
1730 utf8_snprintf(prompt, sizeof(prompt),
1731 _("Enter text to insert before \"%.*w\": "), k, tmpval);
1732 prompt[sizeof(prompt)-1] = '\0';
1734 else if((*cl)->var->is_list
1735 && !lval
1736 && (*cl)->var->current_val.l){
1737 /* Add to list which doesn't exist, but default does exist */
1738 ekey[0].ch = 'r';
1739 ekey[0].rval = 'r';
1740 ekey[0].name = "R";
1741 ekey[0].label = N_("Replace");
1742 ekey[1].ch = 'a';
1743 ekey[1].rval = 'a';
1744 ekey[1].name = "A";
1745 ekey[1].label = N_("Add To");
1746 ekey[2].ch = -1;
1747 strncpy(prompt, _("Replace or Add To default value ? "), sizeof(prompt));
1748 prompt[sizeof(prompt)-1] = '\0';
1749 switch(radio_buttons(prompt, -FOOTER_ROWS(ps), ekey, 'a', 'x',
1750 h_config_replace_add, RB_NORM)){
1751 case 'a':
1752 p = sval;
1753 for(j = 0; (*cl)->var->current_val.l[j]; j++){
1754 sstrncpy(&p, (*cl)->var->current_val.l[j], oebufsize-(p-sval));
1755 if(oebufsize-(p-sval) > 2){
1756 *p++ = ',';
1757 *p++ = ' ';
1760 if(oebufsize-(p-sval) > 0)
1761 *p = '\0';
1764 sval[oebufsize-1] = '\0';
1766 add_text:
1767 if(flags & CF_NUMBER)
1768 snprintf(prompt, sizeof(prompt), _("Enter the numeric text to be added : "));
1769 else
1770 snprintf(prompt, sizeof(prompt), _("Enter the text to be added : "));
1772 break;
1774 case 'r':
1775 replace_text:
1776 if(olddefval){
1777 strncpy(sval, olddefval, oebufsize);
1778 sval[oebufsize-1] = '\0';
1781 if(flags & CF_NUMBER)
1782 snprintf(prompt, sizeof(prompt), _("Enter the numeric replacement text : "));
1783 else
1784 snprintf(prompt, sizeof(prompt), _("Enter the replacement text : "));
1786 break;
1788 case 'x':
1789 i = 1;
1790 cmd_cancelled("Add");
1791 break;
1794 else{
1795 if(flags & CF_NUMBER)
1796 snprintf(prompt, sizeof(prompt), _("Enter the numeric text to be added : "));
1797 else
1798 snprintf(prompt, sizeof(prompt), _("Enter the text to be added : "));
1801 prompt[sizeof(prompt)-1] = '\0';
1803 ps->mangled_footer = 1;
1805 if(i == 1)
1806 break;
1808 help = NO_HELP;
1809 while(1){
1810 if((*cl)->var->is_list
1811 && lval && lval[0] && lval[0][0]
1812 && (*cl)->value){
1813 ekey[0].ch = ctrl('W');
1814 ekey[0].rval = 5;
1815 ekey[0].name = "^W";
1816 /* TRANSLATORS: Insert new item before current item */
1817 ekey[0].label = after ? N_("InsertBefore") : N_("InsertAfter");
1818 ekey[1].ch = -1;
1820 else if(!(flags&CF_NUMBER))
1821 ekey[0].ch = -1;
1823 oeflags = OE_APPEND_CURRENT;
1824 i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, oebufsize,
1825 prompt,
1826 (ekey[0].ch != -1) ? ekey : NULL,
1827 help, &oeflags);
1828 if(i == 0){
1829 rv = 1;
1830 if((*cl)->var->is_list)
1831 ps->mangled_body = 1;
1832 else
1833 ps->mangled_footer = 1;
1835 removing_leading_and_trailing_white_space(sval);
1837 * Coerce "" and <Empty Value> to empty string input.
1838 * Catch <No Value Set> as a substitute for deleting.
1840 if((*sval == '\"' && *(sval+1) == '\"' && *(sval+2) == '\0')
1841 || !struncmp(sval, _(empty_val), strlen(_(empty_val)))
1842 || (*sval == '<'
1843 && !struncmp(sval+1, _(empty_val), strlen(_(empty_val)))))
1844 *sval = '\0';
1845 else if(!struncmp(sval, _(no_val), strlen(_(no_val)))
1846 || (*sval == '<'
1847 && !struncmp(sval+1, _(no_val), strlen(_(no_val)))))
1848 goto delete;
1850 if((*cl)->var->is_list){
1851 if(*sval || !lval){
1852 char **ltmp;
1853 int i;
1855 i = 0;
1856 for(tmp = sval; *tmp; tmp++)
1857 if(*tmp == ',')
1858 i++; /* conservative count of ,'s */
1860 if(!i){
1861 ltmp = (char **)fs_get(2 * sizeof(char *));
1862 ltmp[0] = cpystr(sval);
1863 ltmp[1] = NULL;
1865 else
1866 ltmp = parse_list(sval, i + 1,
1867 look_for_backslash
1868 ? PL_COMMAQUOTE : 0,
1869 NULL);
1871 if(ltmp[0]){
1872 config_add_list(ps, cl, ltmp, &newval, after);
1873 if(after)
1874 skip_to_next = 1;
1876 else{
1877 q_status_message1(SM_ORDER, 0, 3,
1878 _("Can't add %s to list"), _(empty_val));
1879 rv = ps->mangled_body = 0;
1882 fs_give((void **)&ltmp);
1884 else{
1885 q_status_message1(SM_ORDER, 0, 3,
1886 _("Can't add %s to list"), _(empty_val));
1889 else{
1890 if(flags&CF_NUMBER && sval[0]
1891 && !(isdigit((unsigned char)sval[0])
1892 || sval[0] == '-' || sval[0] == '+')){
1893 q_status_message(SM_ORDER,3,3,
1894 _("Entry must be numeric"));
1895 i = 3; /* to keep loop going */
1896 continue;
1899 if(apval && *apval)
1900 fs_give((void **)apval);
1902 if(!(olddefval && !strcmp(sval, olddefval))
1903 || ((*cl)->var == &ps->vars[V_POST_CHAR_SET])
1904 || want_to(_("Leave unset and use default "),
1905 'y', 'y', NO_HELP, WT_FLUSH_IN) == 'n')
1906 *apval = cpystr(sval);
1908 newval = &(*cl)->value;
1911 else if(i == 1){
1912 cmd_cancelled("Add");
1914 else if(i == 3){
1915 help = help == NO_HELP ? h_config_add : NO_HELP;
1916 continue;
1918 else if(i == 4){ /* no redraw, yet */
1919 continue;
1921 else if(i == 5){ /* change from/to prepend to/from append */
1922 char tmpval[101];
1924 after = after ? 0 : 1;
1925 strncpy(tmpval, (*cl)->value, sizeof(tmpval));
1926 tmpval[sizeof(tmpval)-1] = '\0';
1927 removing_trailing_white_space(tmpval);
1928 /* 33 is the number of chars other than the value */
1929 maxwidth = MIN(80, ps->ttyo->screen_cols) - 15;
1930 k = MIN(18, MAX(maxwidth-33,0));
1931 if(utf8_width(tmpval) > k && k >= 3){
1932 (void) utf8_truncate(tmpval, k-3);
1933 strncat(tmpval, "...", sizeof(tmpval)-strlen(tmpval)-1);
1934 tmpval[sizeof(tmpval)-1] = '\0';
1937 if(after)
1938 snprintf(prompt, sizeof(prompt), _("Enter text to insert after \"%.*s\": "), k, tmpval);
1939 else
1940 snprintf(prompt, sizeof(prompt), _("Enter text to insert before \"%.*s\": "), k, tmpval);
1942 continue;
1944 else if(i == ctrl('P')){
1945 if(sval[0])
1946 numval = atoi(sval);
1947 else{
1948 if(pval)
1949 numval = atoi(pval);
1950 else
1951 numval = lowrange + 1;
1954 if(numval == lowrange){
1956 * Protect user from repeating arrow key that
1957 * causes message to appear over and over.
1959 if(++repeat_key > 0){
1960 q_status_message1(SM_ORDER,3,3,
1961 _("Minimum value is %s"), comatose(lowrange));
1962 repeat_key = -5;
1965 else
1966 repeat_key = 0;
1968 numval = MAX(numval - incr, lowrange);
1969 snprintf(sval, oebufsize, "%d", numval);
1970 sval[oebufsize-1] = '\0';
1971 continue;
1973 else if(i == ctrl('N')){
1974 if(sval[0])
1975 numval = atoi(sval);
1976 else{
1977 if(pval)
1978 numval = atoi(pval);
1979 else
1980 numval = lowrange + 1;
1983 if(numval == hirange){
1984 if(++repeat_key > 0){
1985 q_status_message1(SM_ORDER,3,3,
1986 _("Maximum value is %s"), comatose(hirange));
1987 repeat_key = -5;
1990 else
1991 repeat_key = 0;
1993 numval = MIN(numval + incr, hirange);
1994 snprintf(sval, oebufsize, "%d", numval);
1995 sval[oebufsize-1] = '\0';
1996 continue;
1999 break;
2003 break;
2005 case MC_DELETE: /* delete */
2006 delete:
2007 if(!(*cl)->var->is_list
2008 && apval && !*apval
2009 && (*cl)->var->current_val.p){
2010 char pmt[80];
2012 snprintf(pmt, sizeof(pmt), _("Override default with %s"), _(empty_val2));
2013 pmt[sizeof(pmt)-1] = '\0';
2014 if(want_to(pmt, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
2015 sval[0] = '\0';
2016 *apval = cpystr(sval);
2017 newval = &(*cl)->value;
2018 rv = ps->mangled_footer = 1;
2021 else if((*cl)->var->is_list
2022 && alval && !lval
2023 && (*cl)->var->current_val.l){
2024 char pmt[80];
2026 snprintf(pmt, sizeof(pmt), _("Override default with %s"), _(empty_val2));
2027 pmt[sizeof(pmt)-1] = '\0';
2028 if(want_to(pmt, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
2029 char **ltmp;
2031 sval[0] = '\0';
2032 ltmp = (char **)fs_get(2 * sizeof(char *));
2033 ltmp[0] = cpystr(sval);
2034 ltmp[1] = NULL;
2035 config_add_list(ps, cl, ltmp, &newval, 0);
2036 fs_give((void **)&ltmp);
2037 rv = ps->mangled_body = 1;
2040 else if(((*cl)->var->is_list && !lval)
2041 || (!(*cl)->var->is_list && !pval)){
2042 q_status_message(SM_ORDER, 0, 3, _("No set value to delete"));
2044 else{
2045 if((*cl)->var->is_fixed)
2046 snprintf(prompt, sizeof(prompt), _("Delete (unused) %s from %s "),
2047 (*cl)->var->is_list
2048 ? (!*lval[(*cl)->varmem])
2049 ? _(empty_val2)
2050 : lval[(*cl)->varmem]
2051 : (pval)
2052 ? (!*pval)
2053 ? _(empty_val2)
2054 : pval
2055 : "<NULL VALUE>",
2056 (*cl)->var->name);
2057 else
2058 snprintf(prompt, sizeof(prompt), _("Really delete %s%s from %s "),
2059 (*cl)->var->is_list ? "item " : "",
2060 (*cl)->var->is_list
2061 ? int2string((*cl)->varmem + 1)
2062 : (pval)
2063 ? (!*pval)
2064 ? _(empty_val2)
2065 : pval
2066 : "<NULL VALUE>",
2067 (*cl)->var->name);
2069 prompt[sizeof(prompt)-1] = '\0';
2072 ps->mangled_footer = 1;
2073 if(want_to(prompt, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
2074 rv = 1;
2075 if((*cl)->var->is_list)
2076 ps->mangled_body = 1;
2077 else
2078 ps->mangled_footer = 1;
2080 if((*cl)->var->is_list){
2081 if(lval[(*cl)->varmem])
2082 fs_give((void **)&lval[(*cl)->varmem]);
2084 config_del_list_item(cl, &newval);
2086 else{
2087 if(apval && *apval)
2088 fs_give((void **)apval);
2090 newval = &(*cl)->value;
2093 else
2094 q_status_message(SM_ORDER, 0, 3, _("Value not deleted"));
2097 break;
2099 case MC_EDIT: /* edit/change list option */
2100 if(fixed_var((*cl)->var, NULL, NULL)){
2101 break;
2103 else if(((*cl)->var->is_list
2104 && !lval
2105 && (*cl)->var->current_val.l)
2107 (!(*cl)->var->is_list
2108 && !pval
2109 && (*cl)->var->current_val.p)){
2112 * In non-list case, offer default value for editing.
2114 if(!(*cl)->var->is_list
2115 && (*cl)->var != &ps->vars[V_REPLY_INTRO]
2116 && (*cl)->var->current_val.p[0]
2117 && strcmp(VSTRING,(*cl)->var->current_val.p)){
2118 int quote_it;
2119 size_t len;
2121 olddefval = (char *) fs_get(strlen((*cl)->var->current_val.p)+3);
2123 if(!strncmp((*cl)->var->current_val.p,
2124 DSTRING,
2125 (len=strlen(DSTRING)))){
2126 /* strip DSTRING and trailing paren */
2127 strncpy(olddefval, (*cl)->var->current_val.p+len,
2128 strlen((*cl)->var->current_val.p)-len-1);
2129 olddefval[strlen((*cl)->var->current_val.p)-len-1] = '\0';
2131 else{
2132 /* quote it if there are trailing spaces */
2133 quote_it = ((*cl)->var->current_val.p[strlen((*cl)->var->current_val.p)-1] == SPACE);
2134 snprintf(olddefval, strlen((*cl)->var->current_val.p)+3, "%s%s%s", quote_it ? "\"" : "", (*cl)->var->current_val.p, quote_it ? "\"" : "");
2137 olddefval[strlen((*cl)->var->current_val.p)+3-1] = '\0';
2140 goto replace_text;
2142 else if(((*cl)->var->is_list
2143 && !lval
2144 && !(*cl)->var->current_val.l)
2146 (!(*cl)->var->is_list
2147 && !pval
2148 && !(*cl)->var->current_val.p)){
2149 goto add_text;
2151 else{
2152 HelpType help;
2153 char *clptr;
2155 if(sval)
2156 fs_give((void **)&sval);
2157 if((*cl)->var->is_list){
2158 snprintf(prompt, sizeof(prompt), _("Change field %s list entry : "),
2159 (*cl)->var->name);
2160 prompt[sizeof(prompt)-1] = '\0';
2161 clptr = lval[(*cl)->varmem] ? lval[(*cl)->varmem] : NULL;
2163 else{
2164 if(flags & CF_NUMBER)
2165 snprintf(prompt, sizeof(prompt), _("Change numeric field %s value : "), (*cl)->var->name);
2166 else
2167 snprintf(prompt, sizeof(prompt), _("Change field %s value : "), (*cl)->var->name);
2169 clptr = pval ? pval : NULL;
2172 oebufsize = clptr ? (int) MAX(MAXPATH, 50+strlen(clptr)) : MAXPATH;
2173 sval = (char *) fs_get(oebufsize * sizeof(char));
2174 snprintf(sval, oebufsize, "%s", clptr ? clptr : "");
2175 sval[oebufsize-1] = '\0';
2177 ps->mangled_footer = 1;
2178 help = NO_HELP;
2179 while(1){
2180 if(!(flags&CF_NUMBER))
2181 ekey[0].ch = -1;
2183 oeflags = OE_APPEND_CURRENT;
2184 i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, oebufsize,
2185 prompt,
2186 (ekey[0].ch != -1) ? ekey : NULL,
2187 help, &oeflags);
2188 if(i == 0){
2189 removing_leading_and_trailing_white_space(sval);
2191 * Coerce "" and <Empty Value> to empty string input.
2192 * Catch <No Value Set> as a substitute for deleting.
2194 if((*sval == '\"' && *(sval+1) == '\"' && *(sval+2) == '\0')
2195 || !struncmp(sval, _(empty_val), strlen(_(empty_val)))
2196 || (*sval == '<'
2197 && !struncmp(sval+1, _(empty_val), strlen(_(empty_val)))))
2198 *sval = '\0';
2199 else if(!struncmp(sval, _(no_val), strlen(_(no_val)))
2200 || (*sval == '<'
2201 && !struncmp(sval+1, _(no_val), strlen(_(no_val)))))
2202 goto delete;
2204 rv = 1;
2205 if((*cl)->var->is_list)
2206 ps->mangled_body = 1;
2207 else
2208 ps->mangled_footer = 1;
2210 if((*cl)->var->is_list){
2211 char **ltmp = NULL;
2212 int i;
2214 if(lval[(*cl)->varmem])
2215 fs_give((void **)&lval[(*cl)->varmem]);
2217 i = 0;
2218 for(tmp = sval; *tmp; tmp++)
2219 if(*tmp == ',')
2220 i++; /* conservative count of ,'s */
2222 if(i)
2223 ltmp = parse_list(sval, i + 1,
2224 look_for_backslash
2225 ? PL_COMMAQUOTE : 0,
2226 NULL);
2228 if(ltmp && !ltmp[0]) /* only commas */
2229 goto delete;
2230 else if(!i || (ltmp && !ltmp[1])){ /* only one item */
2231 lval[(*cl)->varmem] = cpystr(sval);
2232 newval = &(*cl)->value;
2234 if(ltmp && ltmp[0])
2235 fs_give((void **)&ltmp[0]);
2237 else if(ltmp){
2239 * Looks like the value was changed to a
2240 * list, so delete old value, and insert
2241 * new list...
2243 * If more than one item in existing list and
2244 * current is end of existing list, then we
2245 * have to delete and append instead of
2246 * deleting and prepending.
2248 if(((*cl)->varmem > 0 || lval[1])
2249 && !(lval[(*cl)->varmem+1])){
2250 after = 1;
2251 skip_to_next = 1;
2254 config_del_list_item(cl, &newval);
2255 config_add_list(ps, cl, ltmp, &newval, after);
2258 if(ltmp)
2259 fs_give((void **)&ltmp);
2261 else{
2262 if(flags&CF_NUMBER && sval[0]
2263 && !(isdigit((unsigned char)sval[0])
2264 || sval[0] == '-' || sval[0] == '+')){
2265 q_status_message(SM_ORDER,3,3,
2266 _("Entry must be numeric"));
2267 continue;
2270 if(apval && *apval)
2271 fs_give((void **)apval);
2273 if(sval[0] && apval)
2274 *apval = cpystr(sval);
2276 newval = &(*cl)->value;
2279 else if(i == 1){
2280 cmd_cancelled("Change");
2282 else if(i == 3){
2283 help = help == NO_HELP ? h_config_change : NO_HELP;
2284 continue;
2286 else if(i == 4){ /* no redraw, yet */
2287 continue;
2289 else if(i == ctrl('P')){
2290 numval = atoi(sval);
2291 if(numval == lowrange){
2293 * Protect user from repeating arrow key that
2294 * causes message to appear over and over.
2296 if(++repeat_key > 0){
2297 q_status_message1(SM_ORDER,3,3,
2298 _("Minimum value is %s"), comatose(lowrange));
2299 repeat_key = -5;
2302 else
2303 repeat_key = 0;
2305 numval = MAX(numval - incr, lowrange);
2306 snprintf(sval, oebufsize, "%d", numval);
2307 sval[oebufsize-1] = '\0';
2308 continue;
2310 else if(i == ctrl('N')){
2311 numval = atoi(sval);
2312 if(numval == hirange){
2313 if(++repeat_key > 0){
2314 q_status_message1(SM_ORDER,3,3,
2315 _("Maximum value is %s"), comatose(hirange));
2316 repeat_key = -5;
2319 else
2320 repeat_key = 0;
2322 numval = MIN(numval + incr, hirange);
2323 snprintf(sval, oebufsize, "%d", numval);
2324 sval[oebufsize-1] = '\0';
2325 continue;
2328 break;
2332 break;
2334 case MC_SHUFFLE:
2335 if(!((*cl)->var && (*cl)->var->is_list)){
2336 q_status_message(SM_ORDER, 0, 2,
2337 _("Can't shuffle single-valued setting"));
2338 break;
2341 if(!alval)
2342 break;
2344 curindex = (*cl)->varmem;
2345 previndex = curindex-1;
2346 nextindex = curindex+1;
2347 if(!*alval || !(*alval)[nextindex])
2348 nextindex = -1;
2350 if((previndex < 0 && nextindex < 0) || !*alval){
2351 q_status_message(SM_ORDER, 0, 3,
2352 _("Shuffle only makes sense when there is more than one value defined"));
2353 break;
2356 /* Move it up or down? */
2357 i = 0;
2358 ekey[i].ch = 'u';
2359 ekey[i].rval = 'u';
2360 ekey[i].name = "U";
2361 ekey[i++].label = N_("Up");
2363 ekey[i].ch = 'd';
2364 ekey[i].rval = 'd';
2365 ekey[i].name = "D";
2366 ekey[i++].label = N_("Down");
2368 ekey[i].ch = -1;
2369 deefault = 'u';
2371 if(previndex < 0){ /* no up */
2372 ekey[0].ch = -2;
2373 deefault = 'd';
2375 else if(nextindex < 0)
2376 ekey[1].ch = -2; /* no down */
2378 snprintf(prompt, sizeof(prompt), "Shuffle %s%s%s ? ",
2379 (ekey[0].ch != -2) ? "UP" : "",
2380 (ekey[0].ch != -2 && ekey[1].ch != -2) ? " or " : "",
2381 (ekey[1].ch != -2) ? "DOWN" : "");
2382 help = (ekey[0].ch == -2) ? h_hdrcolor_shuf_down
2383 : (ekey[1].ch == -2) ? h_hdrcolor_shuf_up
2384 : h_hdrcolor_shuf;
2385 prompt[sizeof(prompt)-1] = '\0';
2387 i = radio_buttons(prompt, -FOOTER_ROWS(ps), ekey, deefault, 'x',
2388 help, RB_NORM);
2390 switch(i){
2391 case 'x':
2392 cmd_cancelled("Shuffle");
2393 return(rv);
2395 case 'u':
2396 case 'd':
2397 break;
2400 /* swap order */
2401 if(i == 'd'){
2402 swap_val = (*alval)[curindex];
2403 (*alval)[curindex] = (*alval)[nextindex];
2404 (*alval)[nextindex] = swap_val;
2406 else if(i == 'u'){
2407 swap_val = (*alval)[curindex];
2408 (*alval)[curindex] = (*alval)[previndex];
2409 (*alval)[previndex] = swap_val;
2411 else /* can't happen */
2412 break;
2415 * Fix the conf line values.
2418 if((*cl)->value)
2419 fs_give((void **)&(*cl)->value);
2421 (*cl)->value = pretty_value(ps, *cl);
2423 if(i == 'd'){
2424 if((*cl)->next->value)
2425 fs_give((void **)&(*cl)->next->value);
2427 (*cl)->next->value = pretty_value(ps, (*cl)->next);
2428 *cl = next_confline(*cl);
2430 else{
2431 if((*cl)->prev->value)
2432 fs_give((void **)&(*cl)->prev->value);
2434 (*cl)->prev->value = pretty_value(ps, (*cl)->prev);
2435 *cl = prev_confline(*cl);
2438 rv = ps->mangled_body = 1;
2439 break;
2441 case MC_EXIT: /* exit */
2442 rv = config_exit_cmd(flags);
2443 break;
2445 default:
2446 rv = -1;
2447 break;
2450 if(skip_to_next)
2451 *cl = next_confline(*cl);
2454 * At this point, if changes occurred, var->user_val.X is set.
2455 * So, fix the current_val, and handle special cases...
2457 * NOTE: we don't worry about the "fixed variable" case here, because
2458 * editing such vars should have been prevented above...
2460 if(rv == 1){
2462 * Now go and set the current_val based on user_val changes
2463 * above. Turn off command line settings...
2465 set_current_val((*cl)->var, TRUE, FALSE);
2466 fix_side_effects(ps, (*cl)->var, 0);
2469 * Delay setting the displayed value until "var.current_val" is set
2470 * in case current val gets changed due to a special case above.
2472 if(newval){
2473 if(*newval)
2474 fs_give((void **) newval);
2476 *newval = pretty_value(ps, *cl);
2479 exception_override_warning((*cl)->var);
2482 if(sval)
2483 fs_give((void **) &sval);
2485 if(olddefval)
2486 fs_give((void **) &olddefval);
2488 return(rv);
2493 config_exit_cmd(unsigned int flags)
2495 return(screen_exit_cmd(flags, "Configuration"));
2500 simple_exit_cmd(unsigned int flags)
2502 return(2);
2507 * screen_exit_cmd - basic config/flag screen exit logic
2510 screen_exit_cmd(unsigned int flags, char *cmd)
2512 if(flags & CF_CHANGES){
2513 switch(want_to(EXIT_PMT, 'y', 'x', h_config_undo, WT_FLUSH_IN)){
2514 case 'y':
2515 q_status_message1(SM_ORDER,0,3,"%s changes saved", cmd);
2516 return(2);
2518 case 'n':
2519 q_status_message1(SM_ORDER,3,5,"No %s changes saved", cmd);
2520 return(10);
2522 case 'x': /* ^C */
2523 default :
2524 q_status_message(SM_ORDER,3,5,"Changes not yet saved");
2525 return(0);
2528 else
2529 return(2);
2536 void
2537 config_add_list(struct pine *ps, CONF_S **cl, char **ltmp, char ***newval, int after)
2539 int items, i;
2540 char *tmp, ***alval;
2541 CONF_S *ctmp;
2543 for(items = 0, i = 0; ltmp[i]; i++) /* count list items */
2544 items++;
2546 alval = ALVAL((*cl)->var, ew);
2548 if(alval && (*alval)){
2549 if((*alval)[0] && (*alval)[0][0]){
2551 * Since we were already a list, make room
2552 * for the new member[s] and fall thru to
2553 * actually fill them in below...
2555 for(i = 0; (*alval)[i]; i++)
2558 fs_resize((void **)alval, (i + items + 1) * sizeof(char *));
2561 * move the ones that will be bumped down to the bottom of the list
2563 for(; i >= (*cl)->varmem + (after?1:0); i--)
2564 (*alval)[i+items] = (*alval)[i];
2566 i = 0;
2568 else if(alval){
2569 (*cl)->varmem = 0;
2570 if(*alval)
2571 free_list_array(alval);
2573 *alval = (char **)fs_get((items+1)*sizeof(char *));
2574 memset((void *)(*alval), 0, (items+1)*sizeof(char *));
2575 (*alval)[0] = ltmp[0];
2576 if(newval)
2577 *newval = &(*cl)->value;
2579 if((*cl)->value)
2580 fs_give((void **)&(*cl)->value);
2582 i = 1;
2585 else if(alval){
2587 * since we were previously empty, we want
2588 * to replace the first CONF_S's value with
2589 * the first new value, and fill the other
2590 * in below if there's a list...
2592 * first, make sure we're at the beginning of this config
2593 * section and dump the config lines for the default list,
2594 * except for the first one, which we will over-write.
2596 *cl = (*cl)->varnamep;
2597 while((*cl)->next && (*cl)->next->varnamep == (*cl)->varnamep)
2598 snip_confline(&(*cl)->next);
2601 * now allocate the new user_val array and fill in the first entry.
2603 *alval = (char **)fs_get((items+1)*sizeof(char *));
2604 memset((void *)(*alval), 0, (items+1) * sizeof(char *));
2605 (*alval)[(*cl)->varmem=0] = ltmp[0];
2606 if(newval)
2607 *newval = &(*cl)->value;
2609 if((*cl)->value)
2610 fs_give((void **)&(*cl)->value);
2612 i = 1;
2616 * Make new cl's to fit in the new space. Move the value from the current
2617 * line if inserting before it, else leave it where it is.
2619 for(; i < items ; i++){
2620 (*alval)[i+(*cl)->varmem + (after?1:0)] = ltmp[i];
2621 tmp = (*cl)->value;
2622 new_confline(cl);
2623 if(after)
2624 (*cl)->value = NULL;
2625 else
2626 (*cl)->value = tmp;
2628 (*cl)->var = (*cl)->prev->var;
2629 (*cl)->valoffset = (*cl)->prev->valoffset;
2630 (*cl)->varoffset = (*cl)->prev->varoffset;
2631 (*cl)->headingp = (*cl)->prev->headingp;
2632 (*cl)->keymenu = (*cl)->prev->keymenu;
2633 (*cl)->help = (*cl)->prev->help;
2634 (*cl)->tool = (*cl)->prev->tool;
2635 (*cl)->varnamep = (*cl)->prev->varnamep;
2636 *cl = (*cl)->prev;
2637 if(!after)
2638 (*cl)->value = NULL;
2640 if(newval){
2641 if(after)
2642 *newval = &(*cl)->next->value;
2643 else
2644 *newval = &(*cl)->value;
2649 * now fix up varmem values and fill in new values that have been
2650 * left NULL
2652 for(ctmp = (*cl)->varnamep, i = 0;
2653 (*alval)[i];
2654 ctmp = ctmp->next, i++){
2655 ctmp->varmem = i;
2656 if(!ctmp->value){
2657 /* BUG: We should be able to do this without the temp
2658 * copy...
2660 char *ptmp = pretty_value(ps, ctmp);
2661 ctmp->value = (ctmp->varnamep->flags & CF_PRINTER) ? printer_name(ptmp) : cpystr(ptmp);
2662 fs_give((void **)&ptmp);
2671 void
2672 config_del_list_item(CONF_S **cl, char ***newval)
2674 char **bufp, ***alval;
2675 int i;
2676 CONF_S *ctmp;
2678 alval = ALVAL((*cl)->var, ew);
2680 if((*alval)[(*cl)->varmem + 1]){
2681 for(bufp = &(*alval)[(*cl)->varmem];
2682 (*bufp = *(bufp+1)) != NULL; bufp++)
2685 if(*cl == (*cl)->varnamep){ /* leading value */
2686 if((*cl)->value)
2687 fs_give((void **)&(*cl)->value);
2689 ctmp = (*cl)->next;
2690 (*cl)->value = ctmp->value;
2691 ctmp->value = NULL;
2693 else{
2694 ctmp = *cl; /* blast the confline */
2695 *cl = (*cl)->next;
2696 if(ctmp == opt_screen->top_line)
2697 opt_screen->top_line = *cl;
2700 snip_confline(&ctmp);
2702 for(ctmp = (*cl)->varnamep, i = 0; /* now fix up varmem values */
2703 (*alval)[i];
2704 ctmp = ctmp->next, i++)
2705 ctmp->varmem = i;
2707 else if((*cl)->varmem){ /* blasted last in list */
2708 ctmp = *cl;
2709 *cl = (*cl)->prev;
2710 if(ctmp == opt_screen->top_line)
2711 opt_screen->top_line = *cl;
2713 snip_confline(&ctmp);
2715 else{ /* blasted last remaining */
2716 if(alval && *alval)
2717 fs_give((void **)alval);
2719 *newval = &(*cl)->value;
2725 * feature list manipulation tool
2728 * returns: -1 on unrecognized cmd, 0 if no change, 1 if change
2731 checkbox_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
2733 int rv = 0;
2735 switch(cmd){
2736 case MC_TOGGLE: /* mark/unmark feature */
2737 if((*cl)->var == &ps->vars[V_FEATURE_LIST]){
2738 rv = 1;
2739 toggle_feature_bit(ps, (*cl)->varmem, (*cl)->var, *cl, 0);
2741 else
2742 q_status_message(SM_ORDER | SM_DING, 3, 6,
2743 "Programmer botch! Unknown checkbox type.");
2745 break;
2747 case MC_EXIT: /* exit */
2748 rv = config_exit_cmd(flags);
2749 break;
2751 default :
2752 rv = -1;
2753 break;
2756 return(rv);
2761 * simple radio-button style variable handler
2764 radiobutton_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
2766 char **apval;
2767 int rv = 0;
2768 NAMEVAL_S *rule = NULL;
2769 #ifndef _WINDOWS
2770 int old_uc, old_cs;
2771 CONF_S *ctmp;
2772 #endif
2774 apval = APVAL((*cl)->var, ew);
2776 switch(cmd){
2777 case MC_CHOICE : /* set/unset feature */
2779 if(fixed_var((*cl)->var, NULL, NULL)){
2780 if(((*cl)->var->post_user_val.p || (*cl)->var->main_user_val.p)
2781 && want_to(_("Delete old unused personal option setting"),
2782 'y', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
2783 delete_user_vals((*cl)->var);
2784 q_status_message(SM_ORDER, 0, 3, _("Deleted"));
2785 rv = 1;
2788 return(rv);
2791 if(standard_radio_var(ps, (*cl)->var) || (*cl)->var == startup_ptr){
2792 PTR_TO_RULEFUNC rulefunc;
2794 #ifndef _WINDOWS
2795 if((*cl)->var == &ps->vars[V_COLOR_STYLE]){
2796 old_uc = pico_usingcolor();
2797 old_cs = ps->color_style;
2799 #endif
2801 if((*cl)->var->cmdline_val.p)
2802 fs_give((void **)&(*cl)->var->cmdline_val.p);
2804 if(apval && *apval)
2805 fs_give((void **)apval);
2807 rulefunc = rulefunc_from_var(ps, (*cl)->var);
2808 if(rulefunc)
2809 rule = (*rulefunc)((*cl)->varmem);
2811 if(apval && rule)
2812 *apval = cpystr(S_OR_L(rule));
2814 cur_rule_value((*cl)->var, TRUE, TRUE);
2815 set_radio_pretty_vals(ps, cl);
2817 if((*cl)->var == &ps->vars[V_AB_SORT_RULE])
2818 addrbook_redo_sorts();
2819 else if((*cl)->var == &ps->vars[V_THREAD_DISP_STYLE]){
2820 clear_index_cache(ps->mail_stream, 0);
2822 else if((*cl)->var == &ps->vars[V_THREAD_INDEX_STYLE]){
2823 MAILSTREAM *m;
2824 int i;
2826 clear_index_cache(ps->mail_stream, 0);
2827 /* clear all hidden and collapsed flags */
2828 set_lflags(ps->mail_stream, ps->msgmap, MN_COLL | MN_CHID, 0);
2830 if(SEP_THRDINDX()
2831 && SORT_IS_THREADED(ps->msgmap)
2832 && unview_thread(ps, ps->mail_stream, ps->msgmap)){
2833 ps->next_screen = mail_index_screen;
2834 ps->view_skipped_index = 0;
2835 ps->mangled_screen = 1;
2838 if(SORT_IS_THREADED(ps->msgmap)
2839 && (SEP_THRDINDX() || COLL_THRDS()))
2840 collapse_threads(ps->mail_stream, ps->msgmap, NULL);
2842 for(i = 0; i < ps_global->s_pool.nstream; i++){
2843 m = ps_global->s_pool.streams[i];
2844 if(m)
2845 sp_set_viewing_a_thread(m, 0);
2848 adjust_cur_to_visible(ps->mail_stream, ps->msgmap);
2850 #ifndef _WINDOWS
2851 else if((*cl)->var == &ps->vars[V_COLOR_STYLE]){
2852 if(old_cs != ps->color_style){
2853 pico_toggle_color(0);
2854 switch(ps->color_style){
2855 case COL_NONE:
2856 case COL_TERMDEF:
2857 pico_set_color_options(pico_trans_color() ? COLOR_TRANS_OPT : 0);
2858 break;
2859 case COL_ANSI8:
2860 pico_set_color_options(COLOR_ANSI8_OPT|COLOR_TRANS_OPT);
2861 break;
2862 case COL_ANSI16:
2863 pico_set_color_options(COLOR_ANSI16_OPT|COLOR_TRANS_OPT);
2864 break;
2865 case COL_ANSI256:
2866 pico_set_color_options(COLOR_ANSI256_OPT|COLOR_TRANS_OPT);
2867 break;
2870 if(ps->color_style != COL_NONE)
2871 pico_toggle_color(1);
2874 if(pico_usingcolor())
2875 pico_set_normal_color();
2877 if(!old_uc && pico_usingcolor()){
2880 * remove the explanatory warning line and a blank line
2883 /* first find the first blank line */
2884 for(ctmp = *cl; ctmp; ctmp = next_confline(ctmp))
2885 if(ctmp->flags & CF_NOSELECT)
2886 break;
2888 if(ctmp && ctmp->flags & CF_NOSELECT &&
2889 ctmp->prev && !(ctmp->prev->flags & CF_NOSELECT) &&
2890 ctmp->next && ctmp->next->flags & CF_NOSELECT &&
2891 ctmp->next->next &&
2892 ctmp->next->next->flags & CF_NOSELECT){
2893 ctmp->prev->next = ctmp->next->next;
2894 ctmp->next->next->prev = ctmp->prev;
2895 ctmp->next->next = NULL;
2896 free_conflines(&ctmp);
2899 /* make all the colors selectable */
2900 for(ctmp = *cl; ctmp; ctmp = next_confline(ctmp))
2901 if(ctmp->flags & CF_POT_SLCTBL)
2902 ctmp->flags &= ~CF_NOSELECT;
2904 else if(old_uc && !pico_usingcolor()){
2907 * add the explanatory warning line and a blank line
2910 /* first find the existing blank line */
2911 for(ctmp = *cl; ctmp; ctmp = next_confline(ctmp))
2912 if(ctmp->flags & CF_NOSELECT)
2913 break;
2915 /* add the explanatory warning line */
2916 new_confline(&ctmp);
2917 ctmp->help = NO_HELP;
2918 ctmp->flags |= CF_NOSELECT;
2919 ctmp->value = cpystr(COLORNOSET);
2921 /* and add another blank line */
2922 new_confline(&ctmp);
2923 ctmp->flags |= (CF_NOSELECT | CF_B_LINE);
2925 /* make all the colors non-selectable */
2926 for(ctmp = *cl; ctmp; ctmp = next_confline(ctmp))
2927 if(ctmp->flags & CF_POT_SLCTBL)
2928 ctmp->flags |= CF_NOSELECT;
2931 clear_index_cache(ps->mail_stream, 0);
2932 ClearScreen();
2933 ps->mangled_screen = 1;
2935 #endif
2937 ps->mangled_body = 1; /* BUG: redraw it all for now? */
2938 rv = 1;
2940 else if((*cl)->var == &ps->vars[V_SORT_KEY]){
2941 SortOrder def_sort;
2942 int def_sort_rev;
2944 def_sort_rev = (*cl)->varmem >= (short) EndofList;
2945 def_sort = (SortOrder) ((*cl)->varmem - (def_sort_rev
2946 * EndofList));
2947 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s", sort_name(def_sort),
2948 (def_sort_rev) ? "/Reverse" : "");
2950 if((*cl)->var->cmdline_val.p)
2951 fs_give((void **)&(*cl)->var->cmdline_val.p);
2953 if(apval){
2954 if(*apval)
2955 fs_give((void **)apval);
2957 *apval = cpystr(tmp_20k_buf);
2960 set_current_val((*cl)->var, TRUE, TRUE);
2961 if(decode_sort(ps->VAR_SORT_KEY, &def_sort, &def_sort_rev) != -1){
2962 ps->def_sort = def_sort;
2963 ps->def_sort_rev = def_sort_rev;
2966 set_radio_pretty_vals(ps, cl);
2967 ps->mangled_body = 1; /* BUG: redraw it all for now? */
2968 rv = 1;
2970 else
2971 q_status_message(SM_ORDER | SM_DING, 3, 6,
2972 "Programmer botch! Unknown radiobutton type.");
2974 break;
2976 case MC_EXIT: /* exit */
2977 rv = config_exit_cmd(flags);
2978 break;
2980 default :
2981 rv = -1;
2982 break;
2985 if(rv == 1)
2986 exception_override_warning((*cl)->var);
2988 return(rv);
2993 * simple yes/no style variable handler
2996 yesno_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
2998 int rv = 0, yes = 0;
2999 char *pval, **apval;
3001 pval = PVAL((*cl)->var, ew);
3002 apval = APVAL((*cl)->var, ew);
3004 switch(cmd){
3005 case MC_TOGGLE: /* toggle yes to no and back */
3006 if(fixed_var((*cl)->var, NULL, NULL)){
3007 if(((*cl)->var->post_user_val.p || (*cl)->var->main_user_val.p)
3008 && want_to(_("Delete old unused personal option setting"),
3009 'y', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
3010 delete_user_vals((*cl)->var);
3011 q_status_message(SM_ORDER, 0, 3, _("Deleted"));
3012 rv = 1;
3015 return(rv);
3018 rv = 1;
3019 yes = ((pval && !strucmp(pval, yesstr)) ||
3020 (!pval && (*cl)->var->current_val.p &&
3021 !strucmp((*cl)->var->current_val.p, yesstr)));
3022 fs_give((void **)&(*cl)->value);
3024 if(apval){
3025 if(*apval)
3026 fs_give((void **)apval);
3028 if(yes)
3029 *apval = cpystr(nostr);
3030 else
3031 *apval = cpystr(yesstr);
3034 set_current_val((*cl)->var, FALSE, FALSE);
3035 if((*cl)->value)
3036 fs_give((void **)&(*cl)->value);
3038 (*cl)->value = pretty_value(ps, *cl);
3039 fix_side_effects(ps, (*cl)->var, 0);
3041 break;
3043 case MC_EXIT: /* exit */
3044 rv = config_exit_cmd(flags);
3045 break;
3047 default :
3048 rv = -1;
3049 break;
3052 return(rv);
3057 * Manage display of the config/options menu body.
3059 void
3060 update_option_screen(struct pine *ps, OPT_SCREEN_S *screen, Pos *cursor_pos)
3062 int dline, w, save = '\0';
3063 CONF_S *top_line, *ctmp;
3064 char *value;
3065 unsigned got_width;
3066 int want_width, first_width;
3067 char *saveptr = NULL;
3069 #ifdef _WINDOWS
3070 int last_selectable;
3071 mswin_beginupdate();
3072 #endif
3073 if(screen == NULL || BODY_LINES(ps) < 1)
3074 return;
3076 opt_screen = screen;
3078 if(cursor_pos){
3079 cursor_pos->col = 0;
3080 cursor_pos->row = -1; /* to tell us if we've set it yet */
3084 * calculate top line of display for reframing if the current field
3085 * is off the display defined by screen->top_line...
3087 if((ctmp = screen->top_line) != NULL)
3088 for(dline = BODY_LINES(ps);
3089 dline && ctmp && ctmp != screen->current;
3090 ctmp = next_confline(ctmp), dline--)
3093 if(!ctmp || !dline){ /* force reframing */
3094 dline = 0;
3095 ctmp = top_line = first_confline(screen->current);
3097 if(((dline++)%BODY_LINES(ps)) == 0)
3098 top_line = ctmp;
3099 while(ctmp != screen->current && (ctmp = next_confline(ctmp)));
3101 else
3102 top_line = screen->top_line;
3104 #ifdef _WINDOWS
3106 * Figure out how far down the top line is from the top and how many
3107 * total lines there are. Dumb to loop every time thru, but
3108 * there aren't that many lines, and it's cheaper than rewriting things
3109 * to maintain a line count in each structure...
3111 for(dline = 0, ctmp = prev_confline(top_line); ctmp; ctmp = prev_confline(ctmp))
3112 dline++;
3114 scroll_setpos(dline);
3115 last_selectable = dline;
3116 for(ctmp = next_confline(top_line); ctmp ; ctmp = next_confline(ctmp)){
3117 dline++;
3118 if (!(ctmp->flags & CF_NOSELECT))
3119 last_selectable = dline;
3121 dline = last_selectable;
3122 scroll_setrange(BODY_LINES(ps), dline);
3123 #endif
3125 /* mangled body or new page, force redraw */
3126 if(ps->mangled_body || screen->top_line != top_line)
3127 screen->prev = NULL;
3129 /* loop thru painting what's needed */
3130 for(dline = 0, ctmp = top_line;
3131 dline < BODY_LINES(ps);
3132 dline++, ctmp = next_confline(ctmp)){
3135 * only fall thru painting if something needs painting...
3137 if(!(!screen->prev || ctmp == screen->prev || ctmp == screen->current
3138 || ctmp == screen->prev->varnamep
3139 || ctmp == screen->current->varnamep
3140 || ctmp == screen->prev->headingp
3141 || ctmp == screen->current->headingp))
3142 continue;
3144 ClearLine(dline + HEADER_ROWS(ps));
3146 if(ctmp){
3147 if(ctmp->flags & CF_B_LINE)
3148 continue;
3150 if(ctmp->varname && !(ctmp->flags & CF_INVISIBLEVAR)){
3151 if(ctmp == screen->current && cursor_pos)
3152 cursor_pos->row = dline + HEADER_ROWS(ps);
3154 if((ctmp == screen->current
3155 || ctmp == screen->current->varnamep
3156 || ctmp == screen->current->headingp)
3157 && !(ctmp->flags & CF_NOHILITE))
3158 StartInverse();
3160 if(ctmp->flags & CF_H_LINE){
3161 MoveCursor(dline + HEADER_ROWS(ps), 0);
3162 Write_to_screen(repeat_char(ps->ttyo->screen_cols, '-'));
3165 if(ctmp->flags & CF_CENTERED){
3166 int offset = ps->ttyo->screen_cols/2
3167 - (utf8_width(ctmp->varname)/2);
3168 MoveCursor(dline + HEADER_ROWS(ps),
3169 (offset > 0) ? offset : 0);
3171 else if(ctmp->varoffset)
3172 MoveCursor(dline+HEADER_ROWS(ps), ctmp->varoffset);
3174 Write_to_screen(ctmp->varname);
3175 if((ctmp == screen->current
3176 || ctmp == screen->current->varnamep
3177 || ctmp == screen->current->headingp)
3178 && !(ctmp->flags & CF_NOHILITE))
3179 EndInverse();
3182 value = (ctmp->flags & CF_INHERIT) ? INHERIT : ctmp->value;
3184 if(value){
3185 char *p;
3186 int i, j;
3188 memset(tmp_20k_buf, '\0',
3189 (6*ps->ttyo->screen_cols + 1) * sizeof(char));
3190 if(ctmp == screen->current){
3191 if(!(ctmp->flags & CF_DOUBLEVAR && ctmp->flags & CF_VAR2))
3192 StartInverse();
3194 if(cursor_pos)
3195 cursor_pos->row = dline + HEADER_ROWS(ps);
3198 if(ctmp->flags & CF_H_LINE)
3199 memset(tmp_20k_buf, '-',
3200 ps->ttyo->screen_cols * sizeof(char));
3202 if(ctmp->flags & CF_CENTERED){
3203 int offset = ps->ttyo->screen_cols/2
3204 - (utf8_width(value)/2);
3205 /* BUG: tabs screw us figuring length above */
3206 if(offset > 0){
3207 char *q;
3209 p = tmp_20k_buf + offset;
3210 if(!*(q = tmp_20k_buf))
3211 while(q < p)
3212 *q++ = ' ';
3215 else
3216 p = tmp_20k_buf;
3219 * Copy the value to a temp buffer expanding tabs, and
3220 * making sure not to write beyond screen right...
3222 for(i = 0, j = ctmp->valoffset; value[i]; i++){
3223 if(value[i] == ctrl('I')){
3225 *p++ = ' ';
3226 while((++j) & 0x07);
3228 else{
3229 *p++ = value[i];
3230 j++;
3234 if(ctmp == screen->current && cursor_pos){
3235 if(ctmp->flags & CF_DOUBLEVAR && ctmp->flags & CF_VAR2)
3236 cursor_pos->col = ctmp->val2offset;
3237 else
3238 cursor_pos->col = ctmp->valoffset;
3240 if(ctmp->tool == radiobutton_tool
3241 #ifdef ENABLE_LDAP
3242 || ctmp->tool==ldap_radiobutton_tool
3243 #endif
3244 || ctmp->tool==role_radiobutton_tool
3245 || ctmp->tool==checkbox_tool
3246 || (ctmp->tool==color_setting_tool &&
3247 ctmp->valoffset != COLOR_INDENT))
3248 cursor_pos->col++;
3251 if(ctmp->flags & CF_DOUBLEVAR){
3252 long l;
3254 p = tmp_20k_buf;
3255 first_width = ctmp->val2offset - ctmp->valoffset - SPACE_BETWEEN_DOUBLEVARS;
3256 if((l=utf8_width(p)) > first_width && first_width >= 0){
3257 saveptr = utf8_count_forw_width(p, first_width, &got_width);
3259 * got_width != first_width indicates there's a problem
3260 * that should not happen. Ignore it.
3262 if(saveptr){
3263 save = *saveptr;
3264 *saveptr = '\0';
3267 else
3268 save = '\0';
3271 * If this is a COLOR_BLOB line we do special coloring.
3272 * The current object inverse hilite is only on the
3273 * checkbox part, the exact format comes from the
3274 * new_color_line function. If we change that we'll have
3275 * to change this to get the coloring right.
3277 if(p[0] == '(' && p[2] == ')' &&
3278 p[3] == ' ' && p[4] == ' ' &&
3279 (!strncmp(p+5, COLOR_BLOB, COLOR_BLOB_LEN)
3280 || !strncmp(p+5, COLOR_BLOB_TRAN, COLOR_BLOB_LEN)
3281 || !strncmp(p+5, COLOR_BLOB_NORM, COLOR_BLOB_LEN))){
3282 COLOR_PAIR *lastc = NULL, *newc = NULL;
3284 MoveCursor(dline+HEADER_ROWS(ps), ctmp->valoffset);
3285 Write_to_screen_n(p, 3);
3286 if(!(ctmp->flags & CF_VAR2) && ctmp == screen->current)
3287 EndInverse();
3289 Write_to_screen_n(p+3, 3);
3290 newc = new_color_pair(colorx(CFC_ICOLOR(ctmp)),
3291 colorx(CFC_ICOLOR(ctmp)));
3292 if(newc){
3293 lastc = pico_get_cur_color();
3294 (void)pico_set_colorp(newc, PSC_NONE);
3295 free_color_pair(&newc);
3298 Write_to_screen_n(p+6, COLOR_BLOB_LEN-2);
3300 if(lastc){
3301 (void)pico_set_colorp(lastc, PSC_NONE);
3302 free_color_pair(&lastc);
3305 Write_to_screen(p+6+COLOR_BLOB_LEN-2);
3307 else{
3308 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset, p);
3309 if(!(ctmp->flags & CF_VAR2) && ctmp == screen->current)
3310 EndInverse();
3313 if(saveptr)
3314 *saveptr = save;
3316 PutLine0(dline+HEADER_ROWS(ps),
3317 ctmp->val2offset - SPACE_BETWEEN_DOUBLEVARS,
3318 repeat_char(SPACE_BETWEEN_DOUBLEVARS, SPACE));
3320 if(l > ctmp->val2offset - ctmp->valoffset && ctmp->val2offset - ctmp->valoffset >= 0)
3321 p = saveptr + SPACE_BETWEEN_DOUBLEVARS;
3323 if(p > tmp_20k_buf){
3324 if(ctmp->flags & CF_VAR2 && ctmp == screen->current)
3325 StartInverse();
3327 if(p[0] == '(' && p[2] == ')' &&
3328 p[3] == ' ' && p[4] == ' ' &&
3329 (!strncmp(p+5, COLOR_BLOB, COLOR_BLOB_LEN)
3330 || !strncmp(p+5, COLOR_BLOB_TRAN, COLOR_BLOB_LEN)
3331 || !strncmp(p+5, COLOR_BLOB_NORM, COLOR_BLOB_LEN))){
3332 COLOR_PAIR *lastc = NULL, *newc = NULL;
3334 MoveCursor(dline+HEADER_ROWS(ps), ctmp->val2offset);
3335 Write_to_screen_n(p, 3);
3336 if(ctmp->flags & CF_VAR2 && ctmp == screen->current)
3337 EndInverse();
3339 Write_to_screen_n(p+3, 3);
3340 newc = new_color_pair(colorx(CFC_ICOLOR(ctmp)),
3341 colorx(CFC_ICOLOR(ctmp)));
3342 if(newc){
3343 lastc = pico_get_cur_color();
3344 (void)pico_set_colorp(newc, PSC_NONE);
3345 free_color_pair(&newc);
3348 Write_to_screen_n(p+6, COLOR_BLOB_LEN-2);
3350 if(lastc){
3351 (void)pico_set_colorp(lastc, PSC_NONE);
3352 free_color_pair(&lastc);
3355 Write_to_screen(p+6+COLOR_BLOB_LEN-2);
3357 else{
3358 PutLine0(dline+HEADER_ROWS(ps),ctmp->val2offset,p);
3359 if(ctmp->flags & CF_VAR2 && ctmp == screen->current)
3360 EndInverse();
3364 else{
3365 char *q, *first_space, *sample, *ptr;
3366 COLOR_PAIR *lastc, *newc;
3367 int invert;
3370 if(ctmp->flags & CF_COLORSAMPLE &&
3371 pico_usingcolor() &&
3372 ((q = strstr(tmp_20k_buf, SAMPLE_LEADER)) ||
3373 (q = strstr(tmp_20k_buf, "Color"))) &&
3374 (first_space = strindex(q, SPACE)) &&
3375 (strstr(value, SAMP1) ||
3376 strstr(value, SAMP2))){
3378 ptr = tmp_20k_buf;
3380 /* write out first part */
3381 *first_space = '\0';
3382 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset,
3383 ptr);
3384 *first_space = SPACE;
3385 ptr = first_space;
3387 if(ctmp == screen->current)
3388 EndInverse();
3390 sample = skip_white_space(ptr);
3391 /* if there's enough room to put some sample up */
3392 save = *sample;
3393 *sample = '\0';
3394 w = utf8_width(tmp_20k_buf);
3395 *sample = save;
3396 if(ctmp->valoffset + w < ps->ttyo->screen_cols){
3398 sample++; /* for `[' at edge of sample */
3400 save = *ptr;
3401 *ptr = '\0';
3402 w = utf8_width(tmp_20k_buf);
3403 *ptr = save;
3405 save = *sample;
3406 *sample = '\0';
3407 /* spaces and bracket before sample1 */
3408 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset+w, ptr);
3409 *sample = save;
3411 ptr = sample;
3413 /* then the color sample */
3414 if(ctmp->var == &ps->vars[V_VIEW_HDR_COLORS]
3415 || ctmp->var == &ps->vars[V_INDEX_TOKEN_COLORS]){
3416 SPEC_COLOR_S *hc, *hcolors;
3418 lastc = newc = NULL;
3420 hcolors =
3421 spec_colors_from_varlist(LVAL(ctmp->var, ew),
3423 for(hc = hcolors, i=0; hc; hc = hc->next, i++)
3424 if(CFC_ICUST(ctmp) == i)
3425 break;
3427 if(hc && hc->fg && hc->fg[0] && hc->bg &&
3428 hc->bg[0])
3429 newc = new_color_pair(hc->fg, hc->bg);
3431 if(newc){
3432 lastc = pico_get_cur_color();
3433 (void)pico_set_colorp(newc, PSC_NONE);
3434 free_color_pair(&newc);
3437 if(hcolors)
3438 free_spec_colors(&hcolors);
3441 /* print out sample1 */
3443 save = *ptr;
3444 *ptr = '\0';
3445 w = utf8_width(tmp_20k_buf);
3446 *ptr = save;
3448 want_width = MIN(utf8_width(SAMP1)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3449 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3450 if(saveptr){
3451 save = *saveptr;
3452 *saveptr = '\0';
3455 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3456 if(saveptr)
3457 *saveptr = save;
3459 ptr = strindex(ptr, ']');
3461 if(lastc){
3462 (void)pico_set_colorp(lastc, PSC_NONE);
3463 free_color_pair(&lastc);
3466 else if(ctmp->var == &ps->vars[V_KW_COLORS]){
3467 KEYWORD_S *kw;
3468 SPEC_COLOR_S *kw_col = NULL;
3470 lastc = newc = NULL;
3472 /* find keyword associated with this line */
3473 for(kw=ps->keywords, i=0; kw; kw=kw->next, i++)
3474 if(CFC_ICUST(ctmp) == i)
3475 break;
3477 if(kw)
3478 kw_col =
3479 spec_colors_from_varlist(LVAL(ctmp->var,ew),
3482 /* color for this keyword */
3483 if(kw && kw_col
3484 && ((kw->nick && kw->nick[0]
3485 && (newc=hdr_color(kw->nick, NULL,
3486 kw_col)))
3488 (kw->kw && kw->kw[0]
3489 && (newc=hdr_color(kw->kw, NULL,
3490 kw_col))))){
3491 lastc = pico_get_cur_color();
3492 (void)pico_set_colorp(newc, PSC_NONE);
3493 free_color_pair(&newc);
3496 if(kw_col)
3497 free_spec_colors(&kw_col);
3499 /* print out sample1 */
3501 save = *ptr;
3502 *ptr = '\0';
3503 w = utf8_width(tmp_20k_buf);
3504 *ptr = save;
3506 want_width = MIN(utf8_width(SAMP1)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3507 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3508 if(saveptr){
3509 save = *saveptr;
3510 *saveptr = '\0';
3513 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3514 if(saveptr)
3515 *saveptr = save;
3517 ptr = strindex(ptr, ']');
3519 if(lastc){
3520 (void)pico_set_colorp(lastc, PSC_NONE);
3521 free_color_pair(&lastc);
3524 else{
3525 lastc = NULL;
3526 invert = 0;
3527 newc = sample_color(ps, ctmp->var);
3528 if(newc){
3529 if((lastc = pico_get_cur_color()) != NULL)
3530 (void)pico_set_colorp(newc, PSC_NONE);
3532 free_color_pair(&newc);
3534 else if(var_defaults_to_rev(ctmp->var)){
3535 if((newc = pico_get_rev_color()) != NULL){
3537 * Note, don't have to free newc.
3539 if((lastc = pico_get_cur_color()) != NULL)
3540 (void)pico_set_colorp(newc, PSC_NONE);
3542 else{
3543 StartInverse();
3544 invert = 1;
3548 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3550 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3551 !(PVAL(ctmp->var,ew) &&
3552 PVAL(ctmp->var+1,ew))))
3553 StartBold();
3555 /* print out sample1 */
3557 save = *ptr;
3558 *ptr = '\0';
3559 w = utf8_width(tmp_20k_buf);
3560 *ptr = save;
3562 want_width = MIN(utf8_width(SAMP1)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3563 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3564 if(saveptr){
3565 save = *saveptr;
3566 *saveptr = '\0';
3569 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3570 if(saveptr)
3571 *saveptr = save;
3573 ptr = strindex(ptr, ']');
3575 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3577 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3578 !(PVAL(ctmp->var,ew) &&
3579 PVAL(ctmp->var+1,ew))))
3580 EndBold();
3582 if(lastc){
3583 (void)pico_set_colorp(lastc, PSC_NONE);
3584 free_color_pair(&lastc);
3586 else if(invert)
3587 EndInverse();
3591 * Finish sample1 with the right bracket.
3593 save = *ptr;
3594 *ptr = '\0';
3595 w = utf8_width(tmp_20k_buf);
3596 *ptr = save;
3597 if(ctmp->valoffset + w < ps->ttyo->screen_cols){
3598 save = *(ptr+1);
3599 *(ptr+1) = '\0';
3600 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3601 *(ptr+1) = save;
3602 ptr++;
3603 w++;
3607 * Now check for an exception sample and paint it.
3609 if(ctmp->valoffset + w + SBS + 1 < ps->ttyo->screen_cols && (q = strstr(ptr, SAMPEXC))){
3610 /* spaces + `[' */
3611 save = ptr[SBS+1];
3612 ptr[SBS+1] = '\0';
3613 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3614 ptr[SBS+1] = save;
3615 ptr += (SBS+1);
3618 * Figure out what color to paint it.
3619 * This only happens with normal variables,
3620 * not with V_VIEW_HDR_COLORS.
3622 lastc = NULL;
3623 invert = 0;
3624 newc = sampleexc_color(ps, ctmp->var);
3625 if(newc){
3626 if((lastc = pico_get_cur_color()) != NULL)
3627 (void)pico_set_colorp(newc, PSC_NONE);
3629 free_color_pair(&newc);
3631 else if(var_defaults_to_rev(ctmp->var)){
3632 if((newc = pico_get_rev_color()) != NULL){
3634 * Note, don't have to free newc.
3636 if((lastc = pico_get_cur_color()) != NULL)
3637 (void)pico_set_colorp(newc, PSC_NONE);
3639 else{
3640 StartInverse();
3641 invert = 1;
3645 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3647 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3648 !(PVAL(ctmp->var,Post) &&
3649 PVAL(ctmp->var+1,Post))))
3650 StartBold();
3652 /* sample2 */
3653 save = *ptr;
3654 *ptr = '\0';
3655 w = utf8_width(tmp_20k_buf);
3656 *ptr = save;
3658 want_width = MIN(utf8_width(SAMPEXC)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3659 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3660 if(saveptr){
3661 save = *saveptr;
3662 *saveptr = '\0';
3665 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3666 if(saveptr)
3667 *saveptr = save;
3669 ptr = strindex(ptr, ']');
3671 /* turn off bold and color */
3672 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3674 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3675 !(PVAL(ctmp->var,Post) &&
3676 PVAL(ctmp->var+1,Post))))
3677 EndBold();
3679 if(lastc){
3680 (void)pico_set_colorp(lastc, PSC_NONE);
3681 free_color_pair(&lastc);
3683 else if(invert)
3684 EndInverse();
3687 * Finish sample2 with the right bracket.
3689 save = *ptr;
3690 *ptr = '\0';
3691 w = utf8_width(tmp_20k_buf);
3692 *ptr = save;
3693 if(ctmp->valoffset + w < ps->ttyo->screen_cols){
3694 save = *(ptr+1);
3695 *(ptr+1) = '\0';
3696 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3697 *(ptr+1) = save;
3698 ptr++;
3699 w++;
3703 /* paint rest of the line if there is any left */
3704 if(ctmp->valoffset + w < ps->ttyo->screen_cols && *ptr){
3705 want_width = ps->ttyo->screen_cols - w - ctmp->valoffset;
3706 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3707 if(saveptr){
3708 save = *saveptr;
3709 *saveptr = '\0';
3712 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3713 if(saveptr)
3714 *saveptr = save;
3718 else{
3719 w = utf8_width(tmp_20k_buf);
3720 want_width = ps->ttyo->screen_cols - ctmp->valoffset;
3721 if(w > want_width){
3722 saveptr = utf8_count_forw_width(tmp_20k_buf, want_width, &got_width);
3723 if(saveptr)
3724 *saveptr = '\0';
3727 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset, tmp_20k_buf);
3728 if(ctmp == screen->current)
3729 EndInverse();
3736 ps->mangled_body = 0;
3737 screen->top_line = top_line;
3738 screen->prev = screen->current;
3739 #ifdef _WINDOWS
3740 mswin_endupdate();
3741 #endif
3749 void
3750 print_option_screen(OPT_SCREEN_S *screen, char *prompt)
3752 CONF_S *ctmp;
3753 int so_far;
3754 char line[500];
3756 if(open_printer(prompt) == 0){
3757 for(ctmp = first_confline(screen->current);
3758 ctmp;
3759 ctmp = next_confline(ctmp)){
3761 so_far = 0;
3762 if(ctmp->varname && !(ctmp->flags & CF_INVISIBLEVAR)){
3764 snprintf(line, sizeof(line), "%*s%s", ctmp->varoffset, "",
3765 ctmp->varname);
3766 line[sizeof(line)-1] = '\0';
3767 print_text(line);
3768 so_far = ctmp->varoffset + utf8_width(ctmp->varname);
3771 if(ctmp && ctmp->value){
3772 char *p = tmp_20k_buf;
3773 int i, j, spaces;
3775 /* Copy the value to a temp buffer expanding tabs. */
3776 for(i = 0, j = ctmp->valoffset; ctmp->value[i]; i++){
3777 if(ctmp->value[i] == ctrl('I')){
3779 *p++ = ' ';
3780 while((++j) & 0x07);
3783 else{
3784 *p++ = ctmp->value[i];
3785 j++;
3789 *p = '\0';
3790 removing_trailing_white_space(tmp_20k_buf);
3792 spaces = MAX(ctmp->valoffset - so_far, 0);
3793 snprintf(line, sizeof(line), "%*s%s\n", spaces, "", tmp_20k_buf);
3794 line[sizeof(line)-1] = '\0';
3795 print_text(line);
3799 close_printer();
3808 void
3809 option_screen_redrawer(void)
3811 ps_global->mangled_body = 1;
3812 update_option_screen(ps_global, opt_screen, (Pos *)NULL);
3818 * pretty_value - given the line, return an
3819 * alloc'd string for line's value...
3821 char *
3822 pretty_value(struct pine *ps, CONF_S *cl)
3824 struct variable *v;
3826 v = cl->var;
3828 if(v == &ps->vars[V_FEATURE_LIST])
3829 return(checkbox_pretty_value(ps, cl));
3830 else if(standard_radio_var(ps, v) || v == startup_ptr)
3831 return(radio_pretty_value(ps, cl));
3832 else if(v == &ps->vars[V_SORT_KEY])
3833 return(sort_pretty_value(ps, cl));
3834 else if(v == &ps->vars[V_SIGNATURE_FILE])
3835 return(sigfile_pretty_value(ps, cl));
3836 else if(v == &ps->vars[V_USE_ONLY_DOMAIN_NAME])
3837 return(yesno_pretty_value(ps, cl));
3838 else if(color_holding_var(ps, v))
3839 return(color_pretty_value(ps, cl));
3840 else
3841 return(text_pretty_value(ps, cl));
3845 char *
3846 text_pretty_value(struct pine *ps, CONF_S *cl)
3848 char tmp[6*MAX_SCREEN_COLS+20], *pvalnorm, **lvalnorm, *pvalexc, **lvalexc;
3849 char *p, *pval, **lval, lastchar = '\0';
3850 int editing_except, fixed, uvalset, uvalposlen;
3851 unsigned got_width;
3852 int comments, except_set, avail_width;
3853 int norm_with_except = 0, norm_with_except_inherit = 0;
3854 int inherit_line = 0;
3856 editing_except = (ew == ps_global->ew_for_except_vars);
3857 fixed = cl->var->is_fixed;
3858 if((ps_global->ew_for_except_vars != Main) && (ew == Main))
3859 norm_with_except++; /* editing normal and except config exists */
3861 if(cl->var->is_list){
3862 lvalnorm = LVAL(cl->var, Main);
3863 lvalexc = LVAL(cl->var, ps_global->ew_for_except_vars);
3864 if(editing_except){
3865 uvalset = lvalexc != NULL;
3866 uvalposlen = uvalset && lvalexc[0] && lvalexc[0][0];
3867 lval = lvalexc;
3869 else{
3870 uvalset = lvalnorm != NULL;
3871 uvalposlen = uvalset && lvalnorm[0] && lvalnorm[0][0];
3872 lval = lvalnorm;
3875 except_set = lvalexc != NULL;
3876 comments = cl->var->current_val.l != NULL;
3877 if(norm_with_except && except_set && lvalexc[0] &&
3878 !strcmp(lvalexc[0],INHERIT))
3879 norm_with_except_inherit++;
3881 if(uvalset && !strcmp(lval[0], INHERIT)){
3882 if(cl->varmem == 0){
3883 inherit_line++;
3884 comments = 0;
3888 /* only add extra comments on last member of list */
3889 if(uvalset && !inherit_line && lval && lval[cl->varmem] &&
3890 lval[cl->varmem + 1])
3891 comments = 0;
3893 else{
3894 pvalnorm = PVAL(cl->var, Main);
3895 pvalexc = PVAL(cl->var, ps_global->ew_for_except_vars);
3896 if(editing_except){
3897 uvalset = pvalexc != NULL;
3898 uvalposlen = uvalset && *pvalexc;
3899 pval = pvalexc;
3901 else{
3902 uvalset = pvalnorm != NULL;
3903 uvalposlen = uvalset && *pvalnorm;
3904 pval = pvalnorm;
3907 except_set = pvalexc != NULL;
3908 comments = cl->var->current_val.p != NULL;
3911 memset(tmp, 0, sizeof(tmp));
3912 p = tmp;
3913 *p = '\0';
3915 avail_width = ps->ttyo->screen_cols - cl->valoffset;
3917 if(fixed || !uvalset || !uvalposlen){
3918 p += utf8_to_width(p, "<", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3919 avail_width -= got_width;
3922 if(fixed){
3923 p += utf8_to_width(p, _(fixed_val), sizeof(tmp)-(p-tmp), avail_width, &got_width);
3924 avail_width -= got_width;
3926 else if(!uvalset){
3927 p += utf8_to_width(p, _(no_val), sizeof(tmp)-(p-tmp), avail_width, &got_width);
3928 avail_width -= got_width;
3930 else if(!uvalposlen){
3931 p += utf8_to_width(p, _(empty_val), sizeof(tmp)-(p-tmp), avail_width, &got_width);
3932 avail_width -= got_width;
3934 else if(inherit_line){
3935 p += utf8_to_width(p, INHERIT, sizeof(tmp)-(p-tmp), avail_width, &got_width);
3936 avail_width -= got_width;
3938 else{
3939 if(cl->var->is_list){
3940 p += utf8_to_width(p, lval[cl->varmem], sizeof(tmp)-(p-tmp), avail_width, &got_width);
3941 avail_width -= got_width;
3943 else{
3944 p += utf8_to_width(p, pval, sizeof(tmp)-(p-tmp), avail_width, &got_width);
3945 avail_width -= got_width;
3949 if(comments && (fixed || !uvalset || (norm_with_except && except_set))){
3950 if(fixed || !uvalset){
3951 p += utf8_to_width(p, ": using ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3952 avail_width -= got_width;
3955 if(norm_with_except && except_set){
3956 if(!uvalset){
3957 p += utf8_to_width(p, "exception ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3958 avail_width -= got_width;
3960 else if(!fixed){
3961 if(!uvalposlen){
3962 p += utf8_to_width(p, ": ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3963 avail_width -= got_width;
3965 else{
3966 p += utf8_to_width(p, " (", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3967 avail_width -= got_width;
3970 if(norm_with_except_inherit){
3971 p += utf8_to_width(p, "added to by exception ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3972 avail_width -= got_width;
3974 else{
3975 p += utf8_to_width(p, "overridden by exception ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3976 avail_width -= got_width;
3981 if(avail_width >= 7){
3982 if(cl->var == &ps_global->vars[V_POST_CHAR_SET]){
3983 p += utf8_to_width(p, "most specific (see help)", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3984 avail_width -= got_width;
3986 else{
3987 sstrncpy(&p, "\"", sizeof(tmp)-(p-tmp));
3988 avail_width--;
3989 if(cl->var->is_list){
3990 char **the_list;
3992 the_list = cl->var->current_val.l;
3994 if(norm_with_except && except_set)
3995 the_list = lvalexc;
3997 if(the_list && the_list[0] && !strcmp(the_list[0], INHERIT))
3998 the_list++;
4000 for(lval = the_list; avail_width-(p-tmp) > 0 && *lval; lval++){
4001 if(lval != the_list){
4002 p += utf8_to_width(p, ",", sizeof(tmp)-(p-tmp), avail_width, &got_width);
4003 avail_width -= got_width;
4006 p += utf8_to_width(p, *lval, sizeof(tmp)-(p-tmp), avail_width, &got_width);
4007 avail_width -= got_width;
4010 else{
4011 p += utf8_to_width(p, cl->var->current_val.p, sizeof(tmp)-(p-tmp), avail_width, &got_width);
4012 avail_width -= got_width;
4015 if(p-tmp+2 < sizeof(tmp)){
4016 *p++ = '\"';
4017 *p = '\0';
4021 else if(*(p-1) == SPACE)
4022 *--p = '\0';
4025 tmp[sizeof(tmp)-1] = '\0';
4027 if(fixed || !uvalset || !uvalposlen)
4028 lastchar = '>';
4029 else if(comments && norm_with_except && except_set)
4030 lastchar = ')';
4032 if(lastchar){
4033 if(p-tmp+2 < sizeof(tmp)){
4034 *p++ = lastchar;
4035 *p = '\0';
4039 tmp[sizeof(tmp)-1] = '\0';
4040 avail_width = ps->ttyo->screen_cols - cl->valoffset;
4042 if(utf8_width(tmp) < avail_width)
4043 snprintf(tmp+strlen(tmp), sizeof(tmp)-strlen(tmp), "%*s", avail_width-utf8_width(tmp), "");
4045 tmp[sizeof(tmp)-1] = '\0';
4047 return(cpystr(tmp));
4051 char *
4052 checkbox_pretty_value(struct pine *ps, CONF_S *cl)
4054 char tmp[6*MAXPATH];
4055 char *comment = NULL;
4056 int indent, x, screen_width, need;
4057 int longest_featname, longest_comment;
4058 int nwidcomm; /* name width with comment */
4059 int nwidnocomm; /* and without comment */
4060 FEATURE_S *feature;
4062 screen_width = (ps && ps->ttyo) ? ps->ttyo->screen_cols : 80;
4063 tmp[0] = '\0';
4065 longest_featname = longest_feature_name();
4066 longest_comment = longest_feature_comment(ps, ew);
4067 indent = feature_indent();
4069 nwidcomm = longest_featname;
4070 nwidnocomm = longest_featname + 2 + longest_comment;
4072 if((need = (indent + 5 + longest_featname + 2 + longest_comment) - screen_width) > 0){
4073 if(need < 10){
4074 nwidcomm -= need;
4075 nwidnocomm -= need;
4077 else{
4078 longest_comment = 0;
4079 nwidnocomm = longest_featname;
4083 feature = feature_list(cl->varmem);
4085 x = feature_gets_an_x(ps, cl->var, feature, &comment, ew);
4087 if(longest_comment && comment && *comment){
4088 utf8_snprintf(tmp, sizeof(tmp), "[%c] %-*.*w %-*.*w", x ? 'X' : ' ',
4089 nwidcomm, nwidcomm,
4090 pretty_feature_name(feature->name, nwidcomm),
4091 longest_comment, longest_comment, comment ? comment : "");
4093 else{
4094 utf8_snprintf(tmp, sizeof(tmp), "[%c] %-*.*w", x ? 'X' : ' ',
4095 nwidnocomm, nwidnocomm,
4096 pretty_feature_name(feature->name, nwidnocomm));
4099 return(cpystr(tmp));
4104 longest_feature_name(void)
4106 static int lv = -1;
4107 int i, j;
4108 FEATURE_S *feature;
4110 if(lv < 0){
4111 for(lv = 0, i = 0; (feature = feature_list(i)); i++)
4112 if(feature_list_section(feature)
4113 && lv < (j = utf8_width(pretty_feature_name(feature->name, -1))))
4114 lv = j;
4116 lv = MIN(lv, 100);
4119 return(lv);
4124 feature_indent(void)
4126 return(6);
4130 char *
4131 yesno_pretty_value(struct pine *ps, CONF_S *cl)
4133 char tmp[6*MAXPATH], *pvalnorm, *pvalexc;
4134 char *p, *pval, lastchar = '\0';
4135 int editing_except, fixed, norm_with_except, uvalset;
4136 int curval, except_set;
4138 editing_except = (ew == ps_global->ew_for_except_vars);
4139 fixed = cl->var->is_fixed;
4140 if((ps_global->ew_for_except_vars == Main) ||
4141 (ew == ps_global->ew_for_except_vars))
4142 norm_with_except = 0;
4143 else
4144 norm_with_except = 1; /* editing normal and except config exists */
4146 pvalnorm = PVAL(cl->var, Main);
4147 pvalexc = PVAL(cl->var, ps_global->ew_for_except_vars);
4148 if(editing_except){
4149 uvalset = (pvalexc != NULL &&
4150 (!strucmp(pvalexc,yesstr) || !strucmp(pvalexc,nostr)));
4151 pval = pvalexc;
4153 else{
4154 uvalset = (pvalnorm != NULL &&
4155 (!strucmp(pvalnorm,yesstr) || !strucmp(pvalnorm,nostr)));
4156 pval = pvalnorm;
4159 except_set = (pvalexc != NULL &&
4160 (!strucmp(pvalexc,yesstr) || !strucmp(pvalexc,nostr)));
4161 curval = (cl->var->current_val.p != NULL &&
4162 (!strucmp(cl->var->current_val.p,yesstr) ||
4163 !strucmp(cl->var->current_val.p,nostr)));
4165 p = tmp;
4166 *p = '\0';
4168 if(fixed || !uvalset)
4169 sstrncpy(&p, "<", sizeof(tmp)-(p-tmp));
4171 if(fixed)
4172 sstrncpy(&p, _(fixed_val), sizeof(tmp)-(p-tmp));
4173 else if(!uvalset)
4174 sstrncpy(&p, _(no_val), sizeof(tmp)-(p-tmp));
4175 else if(!strucmp(pval, yesstr))
4176 sstrncpy(&p, yesstr, sizeof(tmp)-(p-tmp));
4177 else
4178 sstrncpy(&p, nostr, sizeof(tmp)-(p-tmp));
4180 if(curval && (fixed || !uvalset || (norm_with_except && except_set))){
4181 if(fixed || !uvalset)
4182 sstrncpy(&p, ": using ", sizeof(tmp)-(p-tmp));
4184 if(norm_with_except && except_set){
4185 if(!uvalset)
4186 sstrncpy(&p, "exception ", sizeof(tmp)-(p-tmp));
4187 else if(!fixed){
4188 sstrncpy(&p, " (", sizeof(tmp)-(p-tmp));
4189 sstrncpy(&p, "overridden by exception ", sizeof(tmp)-(p-tmp));
4193 sstrncpy(&p, "\"", sizeof(tmp)-(p-tmp));
4194 sstrncpy(&p, !strucmp(cl->var->current_val.p,yesstr) ? yesstr : nostr, sizeof(tmp)-(p-tmp));
4195 sstrncpy(&p, "\"", sizeof(tmp)-(p-tmp));
4198 if(fixed || !uvalset)
4199 lastchar = '>';
4200 else if(curval && norm_with_except && except_set)
4201 lastchar = ')';
4203 if(lastchar && sizeof(tmp)-(p-tmp) > 1){
4204 *p++ = lastchar;
4205 *p = '\0';
4208 tmp[sizeof(tmp)-1] = '\0';
4210 if(utf8_width(tmp) < ps->ttyo->screen_cols - cl->valoffset)
4211 snprintf(tmp+strlen(tmp), sizeof(tmp)-strlen(tmp),
4212 "%*s", ps->ttyo->screen_cols - cl->valoffset - utf8_width(tmp), "");
4214 tmp[sizeof(tmp)-1] = '\0';
4216 return(cpystr(tmp));
4220 char *
4221 radio_pretty_value(struct pine *ps, CONF_S *cl)
4223 char tmp[6*MAXPATH];
4224 char *pvalnorm, *pvalexc, *pval;
4225 int editing_except_which_isnt_normal, editing_normal_which_isnt_except;
4226 int fixed, is_set_for_this_level = 0, is_the_one, the_exc_one;
4227 int i, j, lv = 0;
4228 NAMEVAL_S *rule = NULL, *f;
4229 PTR_TO_RULEFUNC rulefunc;
4230 struct variable *v;
4232 tmp[0] = '\0';
4233 v = cl->var;
4235 editing_except_which_isnt_normal = (ew == ps_global->ew_for_except_vars &&
4236 ew != Main);
4237 editing_normal_which_isnt_except = (ew == Main &&
4238 ew != ps_global->ew_for_except_vars);
4239 fixed = cl->var->is_fixed;
4240 pvalnorm = PVAL(v, Main);
4241 pvalexc = PVAL(v, ps_global->ew_for_except_vars);
4243 rulefunc = rulefunc_from_var(ps, v);
4244 rule = rulefunc ? (*rulefunc)(cl->varmem) : NULL;
4246 /* find longest name */
4247 if(rulefunc)
4248 for(lv = 0, i = 0; (f = (*rulefunc)(i)); i++)
4249 if(lv < (j = utf8_width(f->name)))
4250 lv = j;
4252 lv = MIN(lv, 100);
4254 if(editing_except_which_isnt_normal)
4255 pval = pvalexc;
4256 else
4257 pval = pvalnorm;
4259 if(pval)
4260 is_set_for_this_level++;
4262 if(fixed){
4263 pval = v->fixed_val.p;
4264 is_the_one = (pval && !strucmp(pval, S_OR_L(rule)));
4266 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4267 is_the_one ? R_SELD : ' ',
4268 lv, lv, rule->name, is_the_one ? " (value is fixed)" : "");
4270 else if(is_set_for_this_level){
4271 is_the_one = (pval && !strucmp(pval, S_OR_L(rule)));
4272 the_exc_one = (editing_normal_which_isnt_except && pvalexc &&
4273 !strucmp(pvalexc, S_OR_L(rule)));
4274 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4275 is_the_one ? R_SELD : ' ',
4276 lv, lv, rule->name,
4277 (!is_the_one && the_exc_one) ? " (value set in exceptions)" :
4278 (is_the_one && the_exc_one) ? " (also set in exceptions)" :
4279 (is_the_one &&
4280 editing_normal_which_isnt_except &&
4281 pvalexc &&
4282 !the_exc_one) ? " (overridden by exceptions)" :
4283 "");
4285 else{
4286 if(pvalexc){
4287 is_the_one = !strucmp(pvalexc, S_OR_L(rule));
4288 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4289 is_the_one ? R_SELD : ' ',
4290 lv, lv, rule->name,
4291 is_the_one ? " (value set in exceptions)" : "");
4293 else{
4294 pval = v->current_val.p;
4295 is_the_one = (pval && !strucmp(pval, S_OR_L(rule)));
4296 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4297 is_the_one ? R_SELD : ' ',
4298 lv, lv, rule->name,
4299 is_the_one ? ((editing_except_which_isnt_normal && pvalnorm) ? " (default from regular config)" : " (default)") : "");
4303 tmp[sizeof(tmp)-1] = '\0';
4305 return(cpystr(tmp));
4309 char *
4310 sigfile_pretty_value(struct pine *ps, CONF_S *cl)
4312 if(cl && cl->var == &ps->vars[V_SIGNATURE_FILE] &&
4313 cl->prev && cl->prev->var == &ps->vars[V_LITERAL_SIG]){
4314 if(cl->prev->var->current_val.p){
4315 cl->flags |= CF_NOSELECT; /* side effect */
4316 return(cpystr(_("<Ignored: using Literal-Signature instead>")));
4318 else{
4319 cl->flags &= ~CF_NOSELECT;
4320 return(text_pretty_value(ps, cl));
4323 else
4324 return(cpystr(""));
4328 char *
4329 color_pretty_value(struct pine *ps, CONF_S *cl)
4331 char tmp[6*MAXPATH];
4332 char *p, *q;
4333 struct variable *v;
4334 int is_index;
4336 tmp[0] = '\0';
4337 v = cl->var;
4339 if(v && color_holding_var(ps, v) &&
4340 (p=srchstr(v->name, "-foreground-color"))){
4342 is_index = !struncmp(v->name, "index-", 6);
4344 q = sampleexc_text(ps, v);
4345 utf8_snprintf(tmp, sizeof(tmp), "%c%.*s %sColor%*.50s %.20w%*s%.20w%.20w",
4346 islower((unsigned char)v->name[0])
4347 ? toupper((unsigned char)v->name[0])
4348 : v->name[0],
4349 MIN(p-v->name-1,30), v->name+1,
4350 is_index ? "Symbol " : "",
4351 MAX(EQ_COL - COLOR_INDENT -1 - MIN(p-v->name-1,30)
4352 - 6 - (is_index ? 7 : 0) - 1,0), "",
4353 sample_text(ps,v), *q ? SBS : 0, "", q,
4354 color_parenthetical(v));
4357 tmp[sizeof(tmp)-1] = '\0';
4359 return(cpystr(tmp));
4363 char *
4364 sort_pretty_value(struct pine *ps, CONF_S *cl)
4366 return(generalized_sort_pretty_value(ps, cl, 1));
4370 char *
4371 generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok)
4373 char tmp[6*MAXPATH];
4374 char *pvalnorm, *pvalexc, *pval;
4375 int editing_except_which_isnt_normal, editing_normal_which_isnt_except;
4376 int fixed, is_set_for_this_level = 0, is_the_one, the_exc_one;
4377 int i, j, lv = 0;
4378 struct variable *v;
4379 SortOrder line_sort, var_sort, exc_sort;
4380 int line_sort_rev, var_sort_rev, exc_sort_rev;
4382 tmp[0] = '\0';
4383 v = cl->var;
4385 editing_except_which_isnt_normal = (ew == ps_global->ew_for_except_vars &&
4386 ew != Main);
4387 editing_normal_which_isnt_except = (ew == Main &&
4388 ew != ps_global->ew_for_except_vars);
4389 fixed = cl->var->is_fixed;
4390 pvalnorm = PVAL(v, Main);
4391 pvalexc = PVAL(v, ps_global->ew_for_except_vars);
4393 /* find longest value's name */
4394 for(lv = 0, i = 0; ps->sort_types[i] != EndofList; i++)
4395 if(lv < (j = utf8_width(sort_name(ps->sort_types[i]))))
4396 lv = j;
4398 lv = MIN(lv, 100);
4400 if(editing_except_which_isnt_normal)
4401 pval = pvalexc;
4402 else
4403 pval = pvalnorm;
4405 if(pval)
4406 is_set_for_this_level++;
4408 /* the config line we're talking about */
4409 if(cl->varmem >= 0){
4410 line_sort_rev = cl->varmem >= (short)EndofList;
4411 line_sort = (SortOrder)(cl->varmem - (line_sort_rev * EndofList));
4414 if(cl->varmem < 0){
4415 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*w",
4416 (pval == NULL) ? R_SELD : ' ',
4417 lv, "Default");
4419 else if(fixed){
4420 pval = v->fixed_val.p;
4421 decode_sort(pval, &var_sort, &var_sort_rev);
4422 is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
4424 utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s",
4425 is_the_one ? R_SELD : ' ',
4426 line_sort_rev ? "Reverse " : "",
4427 lv, sort_name(line_sort),
4428 line_sort_rev ? 0 : 8, "",
4429 is_the_one ? " (value is fixed)" : "");
4431 else if(is_set_for_this_level){
4432 decode_sort(pval, &var_sort, &var_sort_rev);
4433 is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
4434 decode_sort(pvalexc, &exc_sort, &exc_sort_rev);
4435 the_exc_one = (editing_normal_which_isnt_except && pvalexc &&
4436 exc_sort_rev == line_sort_rev && exc_sort == line_sort);
4437 utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s",
4438 is_the_one ? R_SELD : ' ',
4439 line_sort_rev ? "Reverse " : "",
4440 lv, sort_name(line_sort),
4441 line_sort_rev ? 0 : 8, "",
4442 (!is_the_one && the_exc_one) ? " (value set in exceptions)" :
4443 (is_the_one && the_exc_one) ? " (also set in exceptions)" :
4444 (is_the_one &&
4445 editing_normal_which_isnt_except &&
4446 pvalexc &&
4447 !the_exc_one) ? " (overridden by exceptions)" :
4448 "");
4450 else{
4451 if(pvalexc){
4452 decode_sort(pvalexc, &exc_sort, &exc_sort_rev);
4453 is_the_one = (exc_sort_rev == line_sort_rev &&
4454 exc_sort == line_sort);
4455 utf8_snprintf(tmp, sizeof(tmp), "( ) %s%-*w%*s%s",
4456 line_sort_rev ? "Reverse " : "",
4457 lv, sort_name(line_sort),
4458 line_sort_rev ? 0 : 8, "",
4459 is_the_one ? " (value set in exceptions)" : "");
4461 else{
4462 pval = v->current_val.p;
4463 decode_sort(pval, &var_sort, &var_sort_rev);
4464 is_the_one = ((pval || default_ok) &&
4465 var_sort_rev == line_sort_rev &&
4466 var_sort == line_sort);
4467 utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s",
4468 is_the_one ? R_SELD : ' ',
4469 line_sort_rev ? "Reverse " : "",
4470 lv, sort_name(line_sort),
4471 line_sort_rev ? 0 : 8, "",
4472 is_the_one ? ((editing_except_which_isnt_normal && pvalnorm) ? " (default from regular config)" : " (default)") : "");
4476 return(cpystr(tmp));
4480 COLOR_PAIR *
4481 sample_color(struct pine *ps, struct variable *v)
4483 COLOR_PAIR *cp = NULL;
4484 char *pvalefg, *pvalebg;
4485 char *pvalmfg, *pvalmbg;
4487 pvalefg = PVAL(v, ew);
4488 pvalebg = PVAL(v+1, ew);
4489 pvalmfg = PVAL(v, Main);
4490 pvalmbg = PVAL(v+1, Main);
4491 if(v && color_holding_var(ps, v) &&
4492 srchstr(v->name, "-foreground-color")){
4493 if(pvalefg && pvalefg[0] && pvalebg && pvalebg[0])
4494 cp = new_color_pair(pvalefg, pvalebg);
4495 else if(ew == Post && pvalmfg && pvalmfg[0] && pvalmbg && pvalmbg[0])
4496 cp = new_color_pair(pvalmfg, pvalmbg);
4497 else if(v->global_val.p && v->global_val.p[0] &&
4498 (v+1)->global_val.p && (v+1)->global_val.p[0])
4499 cp = new_color_pair(v->global_val.p, (v+1)->global_val.p);
4502 return(cp);
4506 COLOR_PAIR *
4507 sampleexc_color(struct pine *ps, struct variable *v)
4509 COLOR_PAIR *cp = NULL;
4510 char *pvalfg, *pvalbg;
4512 pvalfg = PVAL(v, Post);
4513 pvalbg = PVAL(v+1, Post);
4514 if(v && color_holding_var(ps, v) &&
4515 srchstr(v->name, "-foreground-color") &&
4516 pvalfg && pvalfg[0] && pvalbg && pvalbg[0])
4517 cp = new_color_pair(pvalfg, pvalbg);
4519 return(cp);
4523 void
4524 clear_feature(char ***l, char *f)
4526 char **list = l ? *l : NULL;
4527 int count = 0;
4529 for(; list && *list; list++, count++){
4530 if(f && !strucmp(((!struncmp(*list,"no-",3)) ? *list + 3 : *list), f)){
4531 fs_give((void **)list);
4532 f = NULL;
4535 if(!f) /* shift */
4536 *list = *(list + 1);
4540 * this is helpful to keep the array from growing if a feature
4541 * gets set and unset repeatedly
4543 if(!f)
4544 fs_resize((void **)l, count * sizeof(char *));
4551 void
4552 toggle_feature_bit(struct pine *ps, int index, struct variable *var, CONF_S *cl, int just_flip_value)
4554 FEATURE_S *f;
4555 int og, on_before;
4556 char *p, **vp;
4558 f = feature_list(index);
4560 og = test_old_growth_bits(ps, f->id);
4563 * if this feature is in the fixed set, or old-growth is in the fixed
4564 * set and this feature is in the old-growth set, don't alter it...
4566 for(vp = var->fixed_val.l; vp && *vp; vp++){
4567 p = (struncmp(*vp, "no-", 3)) ? *vp : *vp + 3;
4568 if(!strucmp(p, f->name) || (og && !strucmp(p, "old-growth"))){
4569 q_status_message(SM_ORDER, 3, 3,
4570 _("Can't change value fixed by sys-admin."));
4571 return;
4575 on_before = F_ON(f->id, ps);
4577 toggle_feature(ps, var, f, just_flip_value, ew);
4580 * Handle any alpine-specific features that need attention here. Features
4581 * that aren't alpine-specific should be handled in toggle_feature instead.
4583 if(on_before != F_ON(f->id, ps))
4584 switch(f->id){
4585 case F_CMBND_ABOOK_DISP :
4586 addrbook_reset();
4587 break;
4589 case F_PRESERVE_START_STOP :
4590 /* toggle raw mode settings to make tty driver aware of new setting */
4591 PineRaw(0);
4592 PineRaw(1);
4593 break;
4595 case F_USE_FK :
4596 ps->orig_use_fkeys = F_ON(F_USE_FK, ps);
4597 ps->mangled_footer = 1;
4598 mark_keymenu_dirty();
4599 break;
4601 case F_SHOW_SORT :
4602 ps->mangled_header = 1;
4603 break;
4605 case F_BLANK_KEYMENU :
4606 if(F_ON(f->id, ps)){
4607 FOOTER_ROWS(ps) = 1;
4608 ps->mangled_body = 1;
4610 else{
4611 FOOTER_ROWS(ps) = 3;
4612 ps->mangled_footer = 1;
4615 clearfooter(ps);
4616 break;
4618 case F_ENABLE_INCOMING :
4619 q_status_message(SM_ORDER | SM_DING, 3, 4,
4620 "Folder List changes will take effect your next Alpine session.");
4621 break;
4623 #ifdef _WINDOWS
4624 case F_SHOW_CURSOR :
4625 mswin_showcaret(F_ON(f->id,ps));
4626 break;
4628 case F_ENABLE_TRAYICON :
4629 mswin_trayicon(F_ON(f->id,ps));
4630 break;
4631 #endif
4633 #if !defined(DOS) && !defined(OS2)
4634 case F_ALLOW_TALK :
4635 if(F_ON(f->id, ps))
4636 allow_talk(ps);
4637 else
4638 disallow_talk(ps);
4640 break;
4641 #endif
4643 case F_PASS_CONTROL_CHARS :
4644 ps->pass_ctrl_chars = F_ON(F_PASS_CONTROL_CHARS,ps_global) ? 1 : 0;
4645 break;
4647 #ifdef SMIME
4648 case F_USE_CERT_STORE_ONLY:
4649 if(F_OFF(F_USE_CERT_STORE_ONLY, ps))
4650 q_status_message(SM_ORDER | SM_DING, 3, 4,
4651 "Disabling this feature should only be done for testing. Press \"?\" for help");
4652 break;
4653 #endif /* SMIME */
4655 case F_PASS_C1_CONTROL_CHARS :
4656 ps->pass_c1_ctrl_chars = F_ON(F_PASS_C1_CONTROL_CHARS,ps_global) ? 1 : 0;
4657 break;
4659 #ifdef MOUSE
4660 case F_ENABLE_MOUSE :
4661 if(F_ON(f->id, ps)){
4662 init_mouse();
4663 if(!mouseexist())
4664 q_status_message(SM_ORDER | SM_DING, 3, 4,
4665 "Mouse tracking still off ($DISPLAY variable set?)");
4667 else
4668 end_mouse();
4670 break;
4671 #endif
4674 if(just_flip_value){
4675 if(cl->value && cl->value[0])
4676 cl->value[1] = (cl->value[1] == ' ') ? 'X' : ' ';
4678 else{
4680 * This fork is only called from the checkbox_tool, which has
4681 * varmem set to index correctly and cl->var set correctly.
4683 if(cl->value)
4684 fs_give((void **)&cl->value);
4686 cl->value = pretty_value(ps, cl);
4692 * new_confline - create new CONF_S zero it out, and insert it after current.
4693 * NOTE current gets set to the new CONF_S too!
4695 CONF_S *
4696 new_confline(CONF_S **current)
4698 CONF_S *p;
4700 p = (CONF_S *)fs_get(sizeof(CONF_S));
4701 memset((void *)p, 0, sizeof(CONF_S));
4702 if(current){
4703 if(*current){
4704 p->next = (*current)->next;
4705 (*current)->next = p;
4706 p->prev = *current;
4707 if(p->next)
4708 p->next->prev = p;
4711 *current = p;
4714 return(p);
4721 void
4722 snip_confline(CONF_S **p)
4724 CONF_S *q;
4727 * Be careful. We need this line because the
4728 * q->prev->next = ...
4729 * may change q itself if &q == &q->prev->next.
4730 * Then the use of q in the next line is wrong.
4731 * That's what happens if we pass in the address of
4732 * some ->next and use *p directly instead of q.
4734 q = *p;
4736 if(q){
4737 /* Yank it from the linked list */
4738 if(q->prev)
4739 q->prev->next = q->next;
4741 if(q->next)
4742 q->next->prev = q->prev;
4744 /* Then free up it's memory */
4745 q->prev = q->next = NULL;
4746 free_conflines(&q);
4750 int
4751 get_confline_number(CONF_S *conf)
4753 int pos;
4754 CONF_S *p;
4756 for (p = first_confline(conf), pos = 0; p != conf; p = next_confline(p), pos++);
4758 return pos;
4762 CONF_S *
4763 set_confline_number(CONF_S *conf, int pos)
4765 CONF_S *p;
4766 int i;
4767 for(p = first_confline(conf), i = 0; p && i < pos; p=next_confline(p), i++);
4768 return p;
4775 void
4776 free_conflines(CONF_S **p)
4778 if(*p){
4779 free_conflines(&(*p)->next);
4781 if((*p)->varname)
4782 fs_give((void **) &(*p)->varname);
4784 if((*p)->value)
4785 fs_give((void **) &(*p)->value);
4787 fs_give((void **) p);
4795 CONF_S *
4796 first_confline(CONF_S *p)
4798 while(p && p->prev)
4799 p = p->prev;
4801 return(p);
4806 * First selectable confline.
4808 CONF_S *
4809 first_sel_confline(CONF_S *p)
4811 for(p = first_confline(p); p && (p->flags&CF_NOSELECT); p=next_confline(p))
4812 ;/* do nothing */
4814 return(p);
4821 CONF_S *
4822 last_confline(CONF_S *p)
4824 while(p && p->next)
4825 p = p->next;
4827 return(p);
4835 fixed_var(struct variable *v, char *action, char *name)
4837 char **lval;
4839 if(v && v->is_fixed
4840 && (!v->is_list
4841 || ((lval=v->fixed_val.l) && lval[0]
4842 && strcmp(INHERIT, lval[0]) != 0))){
4843 q_status_message2(SM_ORDER, 3, 3,
4844 "Can't %s sys-admin defined %s.",
4845 action ? action : "change", name ? name : "value");
4846 return(1);
4849 return(0);
4853 void
4854 exception_override_warning(struct variable *v)
4856 char **lval;
4858 /* if exceptions config file exists and we're not editing it */
4859 if(v && (ps_global->ew_for_except_vars != Main) && (ew == Main)){
4860 if((!v->is_list && PVAL(v, ps_global->ew_for_except_vars)) ||
4861 (v->is_list && (lval=LVAL(v, ps_global->ew_for_except_vars)) &&
4862 lval[0] && strcmp(INHERIT, lval[0]) != 0))
4863 q_status_message1(SM_ORDER, 3, 3,
4864 _("Warning: \"%s\" is overridden in your exceptions configuration"),
4865 v->name);
4870 void
4871 offer_to_fix_pinerc(struct pine *ps)
4873 struct variable *v;
4874 char prompt[300];
4875 char *p, *q;
4876 char **list;
4877 char **list_fixed;
4878 int rv = 0, write_main = 0, write_post = 0;
4879 int i, k, j, need, exc;
4880 char *clear = ": delete it";
4881 char ***plist;
4883 dprint((4, "offer_to_fix_pinerc()\n"));
4885 ps->fix_fixed_warning = 0; /* so we only ask first time */
4887 if(ps->readonly_pinerc)
4888 return;
4890 set_titlebar(_("FIXING PINERC"), ps->mail_stream,
4891 ps->context_current,
4892 ps->cur_folder, ps->msgmap, 1, FolderName, 0, 0, NULL);
4894 if(want_to(_("Some of your options conflict with site policy. Investigate"),
4895 'y', 'n', NO_HELP, WT_FLUSH_IN) != 'y')
4896 return;
4898 /* space want_to requires in addition to the string you pass in */
4899 #define WANTTO_SPACE 6
4900 need = WANTTO_SPACE + utf8_width(clear);
4902 for(v = ps->vars; v->name; v++){
4903 if(!v->is_fixed ||
4904 !v->is_user ||
4905 v->is_obsolete ||
4906 v == &ps->vars[V_FEATURE_LIST]) /* handle feature-list below */
4907 continue;
4909 prompt[0] = '\0';
4911 if(v->is_list &&
4912 (v->post_user_val.l || v->main_user_val.l)){
4913 char **active_list;
4915 active_list = v->post_user_val.l ? v->post_user_val.l
4916 : v->main_user_val.l;
4917 if(*active_list){
4918 snprintf(prompt, sizeof(prompt), _("Your setting for %s is "), v->name);
4919 prompt[sizeof(prompt)-1] = '\0';
4920 p = prompt + strlen(prompt);
4921 for(i = 0; active_list[i]; i++){
4922 if(utf8_width(prompt) > ps->ttyo->screen_cols - need)
4923 break;
4924 if(i && sizeof(prompt)-(p-prompt) > 0)
4925 *p++ = ',';
4927 sstrncpy(&p, active_list[i], sizeof(prompt)-(p-prompt));
4928 if(sizeof(prompt)-(p-prompt) > 0)
4929 *p = '\0';
4931 prompt[sizeof(prompt)-1] = '\0';
4934 if(sizeof(prompt)-(p-prompt) > 0)
4935 *p = '\0';
4937 else
4938 snprintf(prompt, sizeof(prompt), _("Your setting for %s is %s"), v->name, _(empty_val2));
4940 else{
4941 if(v->post_user_val.p || v->main_user_val.p){
4942 char *active_var;
4944 active_var = v->post_user_val.p ? v->post_user_val.p
4945 : v->main_user_val.p;
4946 if(*active_var){
4947 snprintf(prompt, sizeof(prompt), _("Your setting for %s is %s"),
4948 v->name, active_var);
4950 else{
4951 snprintf(prompt, sizeof(prompt), _("Your setting for %s is %s"),
4952 v->name, _(empty_val2));
4957 prompt[sizeof(prompt)-1] = '\0';
4959 if(*prompt){
4960 if(utf8_width(prompt) > ps->ttyo->screen_cols - need)
4961 (void) utf8_truncate(prompt, ps->ttyo->screen_cols - need);
4963 (void) strncat(prompt, clear, sizeof(prompt)-strlen(prompt)-1);
4964 prompt[sizeof(prompt)-1] = '\0';
4965 if(want_to(prompt, 'y', 'n', NO_HELP, WT_NORM) == 'y'){
4966 if(v->is_list){
4967 if(v->main_user_val.l)
4968 write_main++;
4969 if(v->post_user_val.l)
4970 write_post++;
4972 else{
4973 if(v->main_user_val.p)
4974 write_main++;
4975 if(v->post_user_val.p)
4976 write_post++;
4979 if(delete_user_vals(v))
4980 rv++;
4987 * As always, feature-list has to be handled separately.
4989 exc = (ps->ew_for_except_vars != Main);
4990 v = &ps->vars[V_FEATURE_LIST];
4991 list_fixed = v->fixed_val.l;
4993 for(j = 0; j < 2; j++){
4994 plist = (j==0) ? &v->main_user_val.l : &v->post_user_val.l;
4995 list = *plist;
4996 if(list){
4997 for(i = 0; list[i]; i++){
4998 p = list[i];
4999 if(!struncmp(p, "no-", 3))
5000 p += 3;
5001 for(k = 0; list_fixed && list_fixed[k]; k++){
5002 q = list_fixed[k];
5003 if(!struncmp(q, "no-", 3))
5004 q += 3;
5005 if(!strucmp(q, p) && strucmp(list[i], list_fixed[k])){
5006 snprintf(prompt, sizeof(prompt), "Your %s is %s%s, fixed value is %s",
5007 p, p == list[i] ? _("ON") : _("OFF"),
5008 exc ? ((plist == &v->main_user_val.l) ? ""
5009 : " in postload-config")
5010 : "",
5011 q == list_fixed[k] ? _("ON") : _("OFF"));
5013 prompt[sizeof(prompt)-1] = '\0';
5014 if(utf8_width(prompt) > ps->ttyo->screen_cols - need)
5015 (void) utf8_truncate(prompt, ps->ttyo->screen_cols - need);
5017 (void) strncat(prompt, clear, sizeof(prompt)-strlen(prompt)-1);
5018 prompt[sizeof(prompt)-1] = '\0';
5019 if(want_to(prompt, 'y', 'n', NO_HELP, WT_NORM) == 'y'){
5020 rv++;
5022 if(plist == &v->main_user_val.l)
5023 write_main++;
5024 else
5025 write_post++;
5028 * Clear the feature from the user's pinerc
5029 * so that we'll stop bothering them when they
5030 * start up Pine.
5032 clear_feature(plist, p);
5035 * clear_feature scoots the list up, so if list[i] was
5036 * the last one going in, now it is the end marker. We
5037 * just decrement i so that it will get incremented and
5038 * then test == 0 in the for loop. We could just goto
5039 * outta_here to accomplish the same thing.
5041 if(!list[i])
5042 i--;
5051 if(write_main)
5052 write_pinerc(ps, Main, WRP_NONE);
5053 if(write_post)
5054 write_pinerc(ps, Post, WRP_NONE);
5056 return;
5061 * Adjust side effects that happen because variable changes values.
5063 * Var->user_val should be set to the new value before calling this.
5065 void
5066 fix_side_effects(struct pine *ps, struct variable *var, int revert)
5068 int val = 0;
5069 char **v, *q, **apval;
5070 struct variable *vars = ps->vars;
5072 /* move this up here so we get the Using default message */
5073 if(var == &ps->vars[V_PERSONAL_NAME]){
5074 if(!(var->main_user_val.p ||
5075 var->post_user_val.p) && ps->ui.fullname){
5076 if(var->current_val.p)
5077 fs_give((void **)&var->current_val.p);
5079 var->current_val.p = cpystr(ps->ui.fullname);
5083 if(!revert
5084 && ((!var->is_fixed
5085 && !var->is_list
5086 && !(var->main_user_val.p ||
5087 var->post_user_val.p)
5088 && var->current_val.p)
5090 (!var->is_fixed
5091 && var->is_list
5092 && !(var->main_user_val.l ||
5093 var->post_user_val.l)
5094 && var->current_val.l)))
5095 q_status_message(SM_ORDER,0,3,_("Using default value"));
5097 if(var == &ps->vars[V_USER_DOMAIN]){
5098 char *p, *q;
5100 if(ps->VAR_USER_DOMAIN
5101 && ps->VAR_USER_DOMAIN[0]
5102 && (p = strrindex(ps->VAR_USER_DOMAIN, '@'))){
5103 if(*(++p)){
5104 if(!revert)
5105 q_status_message2(SM_ORDER, 3, 5,
5106 _("User-Domain (%s) cannot contain \"@\"; using %s"),
5107 ps->VAR_USER_DOMAIN, p);
5108 q = ps->VAR_USER_DOMAIN;
5109 while((*q++ = *p++) != '\0')
5110 ;/* do nothing */
5112 else{
5113 if(!revert)
5114 q_status_message1(SM_ORDER, 3, 5,
5115 _("User-domain (%s) cannot contain \"@\"; deleting"),
5116 ps->VAR_USER_DOMAIN);
5118 if(ps->vars[V_USER_DOMAIN].post_user_val.p){
5119 fs_give((void **)&ps->vars[V_USER_DOMAIN].post_user_val.p);
5120 set_current_val(&vars[V_USER_DOMAIN], TRUE, TRUE);
5123 if(ps->VAR_USER_DOMAIN
5124 && ps->VAR_USER_DOMAIN[0]
5125 && (p = strrindex(ps->VAR_USER_DOMAIN, '@'))){
5126 if(ps->vars[V_USER_DOMAIN].main_user_val.p){
5127 fs_give((void **)&ps->vars[V_USER_DOMAIN].main_user_val.p);
5128 set_current_val(&vars[V_USER_DOMAIN], TRUE, TRUE);
5135 * Reset various pointers pertaining to domain name and such...
5137 init_hostname(ps);
5139 else if(var == &ps->vars[V_INBOX_PATH]){
5141 * fixup the inbox path based on global/default values...
5143 init_inbox_mapping(ps->VAR_INBOX_PATH, ps->context_list);
5145 if(!strucmp(ps->cur_folder, ps->inbox_name) && ps->mail_stream
5146 && strcmp(ps->VAR_INBOX_PATH, ps->mail_stream->mailbox)){
5148 * If we currently have "inbox" open and the mailbox name
5149 * doesn't match, reset the current folder's name and
5150 * remove the SP_INBOX flag.
5152 strncpy(ps->cur_folder, ps->mail_stream->mailbox,
5153 sizeof(ps->cur_folder)-1);
5154 ps->cur_folder[sizeof(ps->cur_folder)-1] = '\0';
5155 sp_set_fldr(ps->mail_stream, ps->cur_folder);
5156 sp_unflag(ps->mail_stream, SP_INBOX);
5157 ps->mangled_header = 1;
5159 else if(sp_inbox_stream()
5160 && strcmp(ps->VAR_INBOX_PATH, sp_inbox_stream()->original_mailbox)){
5161 MAILSTREAM *m = sp_inbox_stream();
5164 * if we don't have inbox directly open, but have it
5165 * open for new mail notification, close the stream like
5166 * any other ordinary folder, and clean up...
5168 if(m){
5169 sp_unflag(m, SP_PERMLOCKED | SP_INBOX);
5170 sp_set_fldr(m, m->mailbox);
5171 expunge_and_close(m, NULL, EC_NONE);
5175 else if(var == &ps->vars[V_INCCHECKTIMEO]){
5176 int old_value = ps->inc_check_timeout;
5178 if(SVAR_INC_CHECK_TIMEO(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5179 if(!revert)
5180 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5182 else
5183 ps->inc_check_timeout = old_value;
5185 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5186 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5188 else if(var == &ps->vars[V_INCCHECKINTERVAL]){
5189 int old_value = ps->inc_check_interval;
5191 if(SVAR_INC_CHECK_INTERV(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5192 if(!revert)
5193 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5195 else
5196 ps->inc_check_interval = old_value;
5198 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5199 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5201 else if(var == &ps->vars[V_INC2NDCHECKINTERVAL]){
5202 int old_value = ps->inc_second_check_interval;
5204 if(SVAR_INC_2NDCHECK_INTERV(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5205 if(!revert)
5206 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5208 else
5209 ps->inc_second_check_interval = old_value;
5211 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5212 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5214 else if(var == &ps->vars[V_INCCHECKLIST]){
5215 if(ps->context_list && ps->context_list->use & CNTXT_INCMNG)
5216 reinit_incoming_folder_list(ps, ps->context_list);
5218 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5219 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5221 else if(var == &ps->vars[V_ADDRESSBOOK] ||
5222 var == &ps->vars[V_GLOB_ADDRBOOK] ||
5223 #ifdef ENABLE_LDAP
5224 var == &ps->vars[V_LDAP_SERVERS] ||
5225 #endif
5226 var == &ps->vars[V_ABOOK_FORMATS]){
5227 addrbook_reset();
5229 else if(var == &ps->vars[V_INDEX_FORMAT]){
5230 reset_index_format();
5231 clear_index_cache(ps->mail_stream, 0);
5233 else if(var == &ps->vars[V_DEFAULT_FCC] ||
5234 var == &ps->vars[V_DEFAULT_SAVE_FOLDER]){
5235 init_save_defaults();
5237 else if(var == &ps->vars[V_KW_BRACES] ||
5238 var == &ps->vars[V_OPENING_SEP] ||
5239 var == &ps->vars[V_ALT_ADDRS]){
5240 clear_index_cache(ps->mail_stream, 0);
5242 else if(var == &ps->vars[V_KEYWORDS]){
5243 if(ps_global->keywords)
5244 free_keyword_list(&ps_global->keywords);
5246 if(var->current_val.l && var->current_val.l[0])
5247 ps_global->keywords = init_keyword_list(var->current_val.l);
5249 clear_index_cache(ps->mail_stream, 0);
5251 else if(var == &ps->vars[V_INIT_CMD_LIST]){
5252 if(!revert)
5253 q_status_message(SM_ASYNC, 0, 3,
5254 _("Initial command changes will affect your next Alpine session."));
5256 else if(var == &ps->vars[V_VIEW_HEADERS]){
5257 ps->view_all_except = 0;
5258 if(ps->VAR_VIEW_HEADERS)
5259 for(v = ps->VAR_VIEW_HEADERS; (q = *v) != NULL; v++)
5260 if(q[0]){
5261 char *p;
5263 removing_leading_white_space(q);
5264 /* look for colon or space or end */
5265 for(p = q; *p && !isspace((unsigned char)*p) && *p != ':'; p++)
5266 ;/* do nothing */
5268 *p = '\0';
5269 if(strucmp(q, ALL_EXCEPT) == 0)
5270 ps->view_all_except = 1;
5273 else if(var == &ps->vars[V_OVERLAP]){
5274 int old_value = ps->viewer_overlap;
5276 if(SVAR_OVERLAP(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5277 if(!revert)
5278 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5280 else
5281 ps->viewer_overlap = old_value;
5283 #ifdef SMIME
5284 else if(smime_related_var(ps, var)){
5285 smime_deinit();
5287 #endif /* SMIME */
5288 else if(var == &ps->vars[V_MAXREMSTREAM]){
5289 int old_value = ps->s_pool.max_remstream;
5291 if(SVAR_MAXREMSTREAM(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5292 if(!revert )
5293 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5295 else
5296 ps->s_pool.max_remstream = old_value;
5298 dprint((9, "max_remstream goes to %d\n",
5299 ps->s_pool.max_remstream));
5301 #ifndef _WINDOWS
5302 else if(var == &ps->vars[V_CHAR_SET]){
5303 char *err = NULL;
5305 if(F_ON(F_USE_SYSTEM_TRANS, ps)){
5306 if(!revert)
5307 q_status_message(SM_ORDER, 5, 5, _("This change has no effect because feature Use-System-Translation is on"));
5309 else{
5310 if(reset_character_set_stuff(&err) == -1)
5311 alpine_panic(err ? err : "trouble with Character-Set");
5312 else if(err){
5313 q_status_message(SM_ORDER | SM_DING, 3, 5, err);
5314 fs_give((void **) &err);
5318 else if(var == &ps->vars[V_KEY_CHAR_SET]){
5319 char *err = NULL;
5321 if(F_ON(F_USE_SYSTEM_TRANS, ps)){
5322 if(!revert)
5323 q_status_message(SM_ORDER, 5, 5, _("This change has no effect because feature Use-System-Translation is on"));
5325 else{
5326 if(reset_character_set_stuff(&err) == -1)
5327 alpine_panic(err ? err : "trouble with Character-Set");
5328 else if(err){
5329 q_status_message(SM_ORDER | SM_DING, 3, 5, err);
5330 fs_give((void **) &err);
5334 #endif /* ! _WINDOWS */
5335 else if(var == &ps->vars[V_POST_CHAR_SET]){
5336 update_posting_charset(ps, revert);
5338 else if(var == &ps->vars[V_MARGIN]){
5339 int old_value = ps->scroll_margin;
5341 if(SVAR_MARGIN(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5342 if(!revert)
5343 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5345 else
5346 ps->scroll_margin = old_value;
5348 else if(var == &ps->vars[V_DEADLETS]){
5349 int old_value = ps->deadlets;
5351 if(SVAR_DEADLETS(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5352 if(!revert)
5353 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5355 else
5356 ps->deadlets = old_value;
5358 else if(var == &ps->vars[V_FILLCOL]){
5359 if(SVAR_FILLCOL(ps, ps->composer_fillcol, tmp_20k_buf, SIZEOF_20KBUF)){
5360 if(!revert)
5361 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5364 else if(var == &ps->vars[V_QUOTE_SUPPRESSION]){
5365 val = ps->quote_suppression_threshold;
5366 if(val < Q_SUPP_LIMIT && val > 0)
5367 val = -val;
5369 if(ps->VAR_QUOTE_SUPPRESSION
5370 && SVAR_QUOTE_SUPPRESSION(ps, val, tmp_20k_buf, SIZEOF_20KBUF)){
5371 if(!revert)
5372 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5374 else{
5375 if(val > 0 && val < Q_SUPP_LIMIT){
5376 if(!revert){
5377 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Ignoring Quote-Suppression-Threshold value of %s, see help"), ps->VAR_QUOTE_SUPPRESSION);
5378 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
5379 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5382 else{
5383 if(val < 0 && val != Q_DEL_ALL)
5384 ps->quote_suppression_threshold = -val;
5385 else
5386 ps->quote_suppression_threshold = val;
5390 else if(var == &ps->vars[V_STATUS_MSG_DELAY]){
5391 if(SVAR_MSGDLAY(ps, ps->status_msg_delay, tmp_20k_buf, SIZEOF_20KBUF)){
5392 if(!revert)
5393 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5396 else if(var == &ps->vars[V_ACTIVE_MSG_INTERVAL]){
5397 if(SVAR_ACTIVEINTERVAL(ps, ps->active_status_interval, tmp_20k_buf, SIZEOF_20KBUF)){
5398 if(!revert)
5399 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5401 else{
5402 busy_cue(_("Active Example"), NULL, 0);
5403 sleep(5);
5404 cancel_busy_cue(-1);
5407 #if !defined(DOS) && !defined(OS2) && !defined(LEAVEOUTFIFO)
5408 else if(var == &ps->vars[V_FIFOPATH]){
5409 init_newmailfifo(ps->VAR_FIFOPATH);
5411 #endif
5412 else if(var == &ps->vars[V_NMW_WIDTH]){
5413 int old_value = ps->nmw_width;
5415 if(SVAR_NMW_WIDTH(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5416 if(!revert )
5417 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5419 else{
5420 #ifdef _WINDOWS
5421 if(old_value != ps->nmw_width)
5422 mswin_setnewmailwidth(old_value); /* actually the new value */
5423 #endif
5424 ps->nmw_width = old_value;
5427 else if(var == &ps->vars[V_TCPOPENTIMEO]){
5428 val = 30;
5429 if(!revert)
5430 if(ps->VAR_TCPOPENTIMEO && SVAR_TCP_OPEN(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5431 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5433 else if(var == &ps->vars[V_TCPREADWARNTIMEO]){
5434 val = 15;
5435 if(!revert)
5436 if(ps->VAR_TCPREADWARNTIMEO && SVAR_TCP_READWARN(ps,val,tmp_20k_buf, SIZEOF_20KBUF))
5437 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5439 else if(var == &ps->vars[V_TCPWRITEWARNTIMEO]){
5440 val = 0;
5441 if(!revert)
5442 if(ps->VAR_TCPWRITEWARNTIMEO && SVAR_TCP_WRITEWARN(ps,val,tmp_20k_buf, SIZEOF_20KBUF))
5443 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5445 else if(var == &ps->vars[V_TCPQUERYTIMEO]){
5446 val = 60;
5447 if(!revert)
5448 if(ps->VAR_TCPQUERYTIMEO && SVAR_TCP_QUERY(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5449 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5451 else if(var == &ps->vars[V_QUITQUERYTIMEO]){
5452 val = 0;
5453 if(!revert)
5454 if(ps->VAR_QUITQUERYTIMEO && SVAR_QUIT_QUERY_TIMEO(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5455 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5457 else if(var == &ps->vars[V_RSHOPENTIMEO]){
5458 val = 15;
5459 if(!revert)
5460 if(ps->VAR_RSHOPENTIMEO && SVAR_RSH_OPEN(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5461 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5463 else if(var == &ps->vars[V_SSHOPENTIMEO]){
5464 val = 15;
5465 if(!revert)
5466 if(ps->VAR_SSHOPENTIMEO && SVAR_SSH_OPEN(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5467 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5469 else if(var == &ps->vars[V_SIGNATURE_FILE]){
5470 if(ps->VAR_OPER_DIR && ps->VAR_SIGNATURE_FILE &&
5471 is_absolute_path(ps->VAR_SIGNATURE_FILE) &&
5472 !in_dir(ps->VAR_OPER_DIR, ps->VAR_SIGNATURE_FILE)){
5473 char *e;
5474 size_t l;
5476 l = strlen(ps->VAR_OPER_DIR) + 100;
5477 e = (char *) fs_get((l+1) * sizeof(char));
5478 snprintf(e, l+1, _("Warning: Sig file can't be outside of %s"),
5479 ps->VAR_OPER_DIR);
5480 e[l] = '\0';
5481 q_status_message(SM_ORDER, 3, 6, e);
5482 fs_give((void **)&e);
5485 else if(var == &ps->vars[V_OPER_DIR]){
5486 if(ps->VAR_OPER_DIR && !ps->VAR_OPER_DIR[0]){
5487 q_status_message(SM_ORDER, 3, 5, "Operating-dir is turned off.");
5488 fs_give((void **)&ps->vars[V_OPER_DIR].current_val.p);
5489 if(ps->vars[V_OPER_DIR].fixed_val.p)
5490 fs_give((void **)&ps->vars[V_OPER_DIR].fixed_val.p);
5491 if(ps->vars[V_OPER_DIR].global_val.p)
5492 fs_give((void **)&ps->vars[V_OPER_DIR].global_val.p);
5493 if(ps->vars[V_OPER_DIR].cmdline_val.p)
5494 fs_give((void **)&ps->vars[V_OPER_DIR].cmdline_val.p);
5495 if(ps->vars[V_OPER_DIR].post_user_val.p)
5496 fs_give((void **)&ps->vars[V_OPER_DIR].post_user_val.p);
5497 if(ps->vars[V_OPER_DIR].main_user_val.p)
5498 fs_give((void **)&ps->vars[V_OPER_DIR].main_user_val.p);
5501 else if(var == &ps->vars[V_MAILCHECK]){
5502 int timeo = 15;
5503 if(SVAR_MAILCHK(ps, timeo, tmp_20k_buf, SIZEOF_20KBUF)){
5504 set_input_timeout(15);
5505 if(!revert)
5506 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5508 else{
5509 set_input_timeout(timeo);
5510 if(get_input_timeout() == 0 && !revert){
5511 q_status_message(SM_ORDER, 4, 6,
5512 _("Warning: automatic new mail checking and mailbox checkpointing is disabled"));
5513 if(ps->VAR_INBOX_PATH && ps->VAR_INBOX_PATH[0] == '{')
5514 q_status_message(SM_ASYNC, 3, 6,
5515 _("Warning: Mail-Check-Interval=0 may cause IMAP server connection to time out"));
5519 else if(var == &ps->vars[V_MAILCHECKNONCURR]){
5520 val = (int) ps->check_interval_for_noncurr;
5521 if(ps->VAR_MAILCHECKNONCURR
5522 && SVAR_MAILCHKNONCURR(ps, val, tmp_20k_buf, SIZEOF_20KBUF)){
5523 if(!revert)
5524 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5526 else
5527 ps->check_interval_for_noncurr = (time_t) val;
5529 else if(var == &ps->vars[V_MAILDROPCHECK]){
5530 long rvl;
5532 rvl = 60L;
5533 if(ps->VAR_MAILDROPCHECK && SVAR_MAILDCHK(ps, rvl, tmp_20k_buf, SIZEOF_20KBUF))
5534 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5535 else{
5536 if(rvl == 0L)
5537 rvl = (60L * 60L * 24L * 100L); /* 100 days */
5539 if(rvl >= 60L)
5540 mail_parameters(NULL, SET_SNARFINTERVAL, (void *) rvl);
5543 else if(var == &ps->vars[V_NNTPRANGE]){
5544 long rvl;
5546 rvl = 0L;
5547 if(ps->VAR_NNTPRANGE && SVAR_NNTPRANGE(ps, rvl, tmp_20k_buf, SIZEOF_20KBUF))
5548 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5549 else{
5550 if(rvl >= 0L)
5551 mail_parameters(NULL, SET_NNTPRANGE, (void *) rvl);
5554 else if(var == &ps->vars[V_CUSTOM_HDRS] || var == &ps->vars[V_COMP_HDRS]){
5555 /* this will give warnings about headers that can't be changed */
5556 if(!revert && var->current_val.l && var->current_val.l[0])
5557 customized_hdr_setup(NULL, var->current_val.l, UseAsDef);
5559 #if defined(DOS) || defined(OS2)
5560 else if(var == &ps->vars[V_FOLDER_EXTENSION]){
5561 mail_parameters(NULL, SET_EXTENSION,
5562 (void *)var->current_val.p);
5564 else if(var == &ps->vars[V_NEWSRC_PATH]){
5565 if(var->current_val.p && var->current_val.p[0])
5566 mail_parameters(NULL, SET_NEWSRC,
5567 (void *)var->current_val.p);
5569 #endif
5570 else if(revert && standard_radio_var(ps, var)){
5572 cur_rule_value(var, TRUE, FALSE);
5573 if(var == &ps_global->vars[V_AB_SORT_RULE])
5574 addrbook_redo_sorts();
5575 else if(var == &ps_global->vars[V_THREAD_INDEX_STYLE]){
5576 clear_index_cache(ps_global->mail_stream, 0);
5577 set_lflags(ps_global->mail_stream, ps_global->msgmap,
5578 MN_COLL | MN_CHID, 0);
5579 if(SORT_IS_THREADED(ps_global->msgmap)
5580 && (SEP_THRDINDX() || COLL_THRDS()))
5581 collapse_threads(ps_global->mail_stream, ps_global->msgmap, NULL);
5583 adjust_cur_to_visible(ps_global->mail_stream, ps_global->msgmap);
5585 #ifndef _WINDOWS
5586 else if(var == &ps->vars[V_COLOR_STYLE]){
5587 pico_toggle_color(0);
5588 switch(ps->color_style){
5589 case COL_NONE:
5590 case COL_TERMDEF:
5591 pico_set_color_options(pico_trans_color() ? COLOR_TRANS_OPT : 0);
5592 break;
5593 case COL_ANSI8:
5594 pico_set_color_options(COLOR_ANSI8_OPT|COLOR_TRANS_OPT);
5595 break;
5596 case COL_ANSI16:
5597 pico_set_color_options(COLOR_ANSI16_OPT|COLOR_TRANS_OPT);
5598 break;
5599 case COL_ANSI256:
5600 pico_set_color_options(COLOR_ANSI256_OPT|COLOR_TRANS_OPT);
5601 break;
5604 if(ps->color_style != COL_NONE)
5605 pico_toggle_color(1);
5607 if(pico_usingcolor())
5608 pico_set_normal_color();
5610 clear_index_cache(ps_global->mail_stream, 0);
5611 ClearScreen();
5612 ps->mangled_screen = 1;
5614 #endif
5616 else if(revert && var == &ps->vars[V_SORT_KEY]){
5617 int def_sort_rev;
5619 decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev);
5620 ps->def_sort_rev = def_sort_rev;
5622 else if(var == &ps->vars[V_THREAD_MORE_CHAR] ||
5623 var == &ps->vars[V_THREAD_EXP_CHAR] ||
5624 var == &ps->vars[V_THREAD_LASTREPLY_CHAR]){
5626 if(var == &ps->vars[V_THREAD_LASTREPLY_CHAR] &&
5627 !(var->current_val.p && var->current_val.p[0])){
5628 if(var->current_val.p)
5629 fs_give((void **) &var->current_val.p);
5631 q_status_message1(SM_ORDER, 3, 5,
5632 _("\"%s\" can't be Empty, using default"), var->name);
5634 apval = APVAL(var, ew);
5635 if(*apval)
5636 fs_give((void **)apval);
5638 set_current_val(var, FALSE, FALSE);
5640 if(!(var->current_val.p && var->current_val.p[0]
5641 && !var->current_val.p[1])){
5642 if(var->current_val.p)
5643 fs_give((void **) &var->current_val.p);
5645 var->current_val.p = cpystr(DF_THREAD_LASTREPLY_CHAR);
5649 if(var == &ps->vars[V_THREAD_MORE_CHAR] ||
5650 var == &ps->vars[V_THREAD_EXP_CHAR] ||
5651 var == &ps->vars[V_THREAD_LASTREPLY_CHAR]){
5652 if(var->current_val.p && var->current_val.p[0] &&
5653 var->current_val.p[1]){
5654 q_status_message1(SM_ORDER, 3, 5,
5655 "Only first character of \"%s\" is used",
5656 var->name);
5657 var->current_val.p[1] = '\0';
5660 if(var->main_user_val.p && var->main_user_val.p[0] &&
5661 var->main_user_val.p[1])
5662 var->main_user_val.p[1] = '\0';
5664 if(var->post_user_val.p && var->post_user_val.p[0] &&
5665 var->post_user_val.p[1])
5666 var->post_user_val.p[1] = '\0';
5669 clear_index_cache(ps_global->mail_stream, 0);
5670 set_need_format_setup(ps_global->mail_stream);
5672 else if(var == &ps->vars[V_NNTP_SERVER]){
5673 free_contexts(&ps_global->context_list);
5674 init_folders(ps_global);
5676 else if(var == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){
5677 init_hostname(ps);
5679 else if(var == &ps->vars[V_PRINTER]){
5680 if(!revert && ps->vars[V_PERSONAL_PRINT_COMMAND].is_fixed){
5681 if(printer_value_check_and_adjust())
5682 q_status_message1(SM_ORDER, 3, 5,
5683 _("Can't set \"%s\" to that value, see Setup/Printer"),
5684 pretty_var_name(var->name));
5687 else if(var == &ps->vars[V_NORM_FORE_COLOR] ||
5688 var == &ps->vars[V_NORM_BACK_COLOR] ||
5689 var == &ps->vars[V_REV_FORE_COLOR] ||
5690 var == &ps->vars[V_REV_BACK_COLOR] ||
5691 var == &ps->vars[V_TITLE_FORE_COLOR] ||
5692 var == &ps->vars[V_TITLE_BACK_COLOR] ||
5693 var == &ps->vars[V_TITLECLOSED_FORE_COLOR] ||
5694 var == &ps->vars[V_TITLECLOSED_BACK_COLOR] ||
5695 var == &ps->vars[V_STATUS_FORE_COLOR] ||
5696 var == &ps->vars[V_STATUS_BACK_COLOR] ||
5697 var == &ps->vars[V_KEYLABEL_FORE_COLOR] ||
5698 var == &ps->vars[V_KEYLABEL_BACK_COLOR] ||
5699 var == &ps->vars[V_KEYNAME_FORE_COLOR] ||
5700 var == &ps->vars[V_KEYNAME_BACK_COLOR]){
5701 set_current_color_vals(ps);
5702 ClearScreen();
5703 ps->mangled_screen = 1;
5705 else if(var == &ps->vars[V_KW_COLORS] ||
5706 var == &ps->vars[V_INDEX_TOKEN_COLORS] ||
5707 var == &ps->vars[V_IND_PLUS_FORE_COLOR] ||
5708 var == &ps->vars[V_IND_IMP_FORE_COLOR] ||
5709 var == &ps->vars[V_IND_DEL_FORE_COLOR] ||
5710 var == &ps->vars[V_IND_ANS_FORE_COLOR] ||
5711 var == &ps->vars[V_IND_NEW_FORE_COLOR] ||
5712 var == &ps->vars[V_IND_UNS_FORE_COLOR] ||
5713 var == &ps->vars[V_IND_HIPRI_FORE_COLOR]||
5714 var == &ps->vars[V_IND_LOPRI_FORE_COLOR]||
5715 var == &ps->vars[V_IND_ARR_FORE_COLOR] ||
5716 var == &ps->vars[V_IND_REC_FORE_COLOR] ||
5717 var == &ps->vars[V_IND_FWD_FORE_COLOR] ||
5718 var == &ps->vars[V_IND_OP_FORE_COLOR] ||
5719 var == &ps->vars[V_IND_FROM_FORE_COLOR] ||
5720 var == &ps->vars[V_IND_SUBJ_FORE_COLOR] ||
5721 var == &ps->vars[V_IND_PLUS_BACK_COLOR] ||
5722 var == &ps->vars[V_IND_IMP_BACK_COLOR] ||
5723 var == &ps->vars[V_IND_DEL_BACK_COLOR] ||
5724 var == &ps->vars[V_IND_ANS_BACK_COLOR] ||
5725 var == &ps->vars[V_IND_NEW_BACK_COLOR] ||
5726 var == &ps->vars[V_IND_UNS_BACK_COLOR] ||
5727 var == &ps->vars[V_IND_ARR_BACK_COLOR] ||
5728 var == &ps->vars[V_IND_REC_BACK_COLOR] ||
5729 var == &ps->vars[V_IND_FWD_BACK_COLOR] ||
5730 var == &ps->vars[V_IND_OP_BACK_COLOR] ||
5731 var == &ps->vars[V_IND_FROM_BACK_COLOR] ||
5732 var == &ps->vars[V_IND_SUBJ_BACK_COLOR]){
5733 clear_index_cache(ps_global->mail_stream, 0);
5735 else if(var == score_act_global_ptr){
5736 int score;
5738 score = atoi(var->current_val.p);
5739 if(score < SCORE_MIN || score > SCORE_MAX){
5740 q_status_message2(SM_ORDER, 3, 5,
5741 _("Score Value must be in range %s to %s"),
5742 comatose(SCORE_MIN), comatose(SCORE_MAX));
5743 apval = APVAL(var, ew);
5744 if(*apval)
5745 fs_give((void **)apval);
5747 set_current_val(var, FALSE, FALSE);
5750 else if(var == scorei_pat_global_ptr || var == age_pat_global_ptr
5751 || var == size_pat_global_ptr || var == cati_global_ptr){
5752 apval = APVAL(var, ew);
5753 if(*apval){
5754 INTVL_S *iv;
5755 iv = parse_intvl(*apval);
5756 if(iv){
5757 fs_give((void **) apval);
5758 *apval = stringform_of_intvl(iv);
5759 free_intvl(&iv);
5761 else
5762 fs_give((void **) apval);
5765 set_current_val(var, FALSE, FALSE);
5767 else if(var == &ps->vars[V_FEATURE_LIST]){
5768 process_feature_list(ps, var->current_val.l, 0, 0, 0);
5770 else if(!revert && (var == &ps->vars[V_LAST_TIME_PRUNE_QUESTION] ||
5771 var == &ps->vars[V_REMOTE_ABOOK_HISTORY] ||
5772 var == &ps->vars[V_REMOTE_ABOOK_VALIDITY] ||
5773 var == &ps->vars[V_USERINPUTTIMEO] ||
5774 var == &ps->vars[V_NEWS_ACTIVE_PATH] ||
5775 var == &ps->vars[V_NEWS_SPOOL_DIR] ||
5776 var == &ps->vars[V_INCOMING_FOLDERS] ||
5777 var == &ps->vars[V_FOLDER_SPEC] ||
5778 var == &ps->vars[V_NEWS_SPEC] ||
5779 var == &ps->vars[V_DISABLE_DRIVERS] ||
5780 var == &ps->vars[V_DISABLE_AUTHS] ||
5781 var == &ps->vars[V_ENCRYPTION_RANGE] ||
5782 #if !defined(_WINDOWS) || defined(ENABLE_WINDOWS_UNIXSSL_CERTS)
5783 var == &ps->vars[V_SSLCAPATH] ||
5784 var == &ps->vars[V_SSLCAFILE] ||
5785 var == &ps->vars[V_USERSSLCAPATH] ||
5786 var == &ps->vars[V_USERSSLCAFILE] ||
5787 #endif
5788 var == &ps->vars[V_RSHPATH] ||
5789 var == &ps->vars[V_RSHCMD] ||
5790 var == &ps->vars[V_SSHCMD] ||
5791 var == &ps->vars[V_SSHPATH])){
5792 q_status_message2(SM_ASYNC, 0, 3,
5793 _("Changes%s%s will affect your next Alpine session."),
5794 var->name ? " to " : "", var->name ? var->name : "");
5797 if(!revert && (var == &ps->vars[V_TCPOPENTIMEO] ||
5798 var == &ps->vars[V_TCPREADWARNTIMEO] ||
5799 var == &ps->vars[V_TCPWRITEWARNTIMEO] ||
5800 var == &ps->vars[V_TCPQUERYTIMEO] ||
5801 var == &ps->vars[V_QUITQUERYTIMEO] ||
5802 var == &ps->vars[V_RSHOPENTIMEO] ||
5803 var == &ps->vars[V_SSHOPENTIMEO]))
5804 q_status_message(SM_ASYNC, 0, 3,
5805 _("Timeout changes will affect your next Alpine session."));
5810 * Compare saved user_val with current user_val to see if it changed.
5811 * If any have changed, change it back and take the appropriate action.
5813 void
5814 revert_to_saved_config(struct pine *ps, SAVED_CONFIG_S *vsave, int allow_hard_to_config_remotely)
5816 struct variable *vreal;
5817 SAVED_CONFIG_S *v;
5818 int i, n;
5819 int changed = 0;
5820 char *pval, **apval, **lval, ***alval;
5822 v = vsave;
5823 for(vreal = ps->vars; vreal->name; vreal++,v++){
5824 if(!save_include(ps, vreal, allow_hard_to_config_remotely))
5825 continue;
5827 changed = 0;
5828 if(vreal->is_list){
5829 lval = LVAL(vreal, ew);
5830 alval = ALVAL(vreal, ew);
5832 if((v->saved_user_val.l && !lval)
5833 || (!v->saved_user_val.l && lval))
5834 changed++;
5835 else if(!v->saved_user_val.l && !lval)
5836 ;/* no change, nothing to do */
5837 else
5838 for(i = 0; v->saved_user_val.l[i] || lval[i]; i++)
5839 if((v->saved_user_val.l[i]
5840 && (!lval[i]
5841 || strcmp(v->saved_user_val.l[i], lval[i])))
5843 (!v->saved_user_val.l[i] && lval[i])){
5844 changed++;
5845 break;
5848 if(changed){
5849 char **list;
5851 if(alval){
5852 if(*alval)
5853 free_list_array(alval);
5855 /* copy back the original one */
5856 if(v->saved_user_val.l){
5857 list = v->saved_user_val.l;
5858 n = 0;
5859 /* count how many */
5860 while(list[n])
5861 n++;
5863 *alval = (char **)fs_get((n+1) * sizeof(char *));
5865 for(i = 0; i < n; i++)
5866 (*alval)[i] = cpystr(v->saved_user_val.l[i]);
5868 (*alval)[n] = NULL;
5873 else{
5874 pval = PVAL(vreal, ew);
5875 apval = APVAL(vreal, ew);
5877 if((v->saved_user_val.p &&
5878 (!pval || strcmp(v->saved_user_val.p, pval))) ||
5879 (!v->saved_user_val.p && pval)){
5880 /* It changed, fix it */
5881 changed++;
5882 if(apval){
5883 /* free the changed value */
5884 if(*apval)
5885 fs_give((void **)apval);
5887 if(v->saved_user_val.p)
5888 *apval = cpystr(v->saved_user_val.p);
5893 if(changed){
5894 if(vreal == &ps->vars[V_FEATURE_LIST])
5895 set_feature_list_current_val(vreal);
5896 else
5897 set_current_val(vreal, TRUE, FALSE);
5899 fix_side_effects(ps, vreal, 1);
5905 SAVED_CONFIG_S *
5906 save_config_vars(struct pine *ps, int allow_hard_to_config_remotely)
5908 struct variable *vreal;
5909 SAVED_CONFIG_S *vsave, *v;
5911 vsave = (SAVED_CONFIG_S *)fs_get((V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
5912 memset((void *)vsave, 0, (V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
5913 v = vsave;
5914 for(vreal = ps->vars; vreal->name; vreal++,v++){
5915 if(!save_include(ps, vreal, allow_hard_to_config_remotely))
5916 continue;
5918 if(vreal->is_list){
5919 int n, i;
5920 char **list;
5922 if(LVAL(vreal, ew)){
5923 /* count how many */
5924 n = 0;
5925 list = LVAL(vreal, ew);
5926 while(list[n])
5927 n++;
5929 v->saved_user_val.l = (char **)fs_get((n+1) * sizeof(char *));
5930 memset((void *)v->saved_user_val.l, 0, (n+1)*sizeof(char *));
5931 for(i = 0; i < n; i++)
5932 v->saved_user_val.l[i] = cpystr(list[i]);
5934 v->saved_user_val.l[n] = NULL;
5937 else{
5938 if(PVAL(vreal, ew))
5939 v->saved_user_val.p = cpystr(PVAL(vreal, ew));
5943 return(vsave);
5947 void
5948 free_saved_config(struct pine *ps, SAVED_CONFIG_S **vsavep, int allow_hard_to_config_remotely)
5950 struct variable *vreal;
5951 SAVED_CONFIG_S *v;
5953 if(vsavep && *vsavep){
5954 for(v = *vsavep, vreal = ps->vars; vreal->name; vreal++,v++){
5955 if(!save_include(ps, vreal, allow_hard_to_config_remotely))
5956 continue;
5958 if(vreal->is_list){ /* free saved_user_val.l */
5959 if(v && v->saved_user_val.l)
5960 free_list_array(&v->saved_user_val.l);
5962 else if(v && v->saved_user_val.p)
5963 fs_give((void **)&v->saved_user_val.p);
5966 fs_give((void **)vsavep);
5972 * Returns positive if any thing was actually deleted.
5975 delete_user_vals(struct variable *v)
5977 int rv = 0;
5979 if(v){
5980 if(v->is_list){
5981 if(v->post_user_val.l){
5982 rv++;
5983 free_list_array(&v->post_user_val.l);
5985 if(v->main_user_val.l){
5986 rv++;
5987 free_list_array(&v->main_user_val.l);
5990 else{
5991 if(v->post_user_val.p){
5992 rv++;
5993 fs_give((void **)&v->post_user_val.p);
5995 if(v->main_user_val.p){
5996 rv++;
5997 fs_give((void **)&v->main_user_val.p);
6002 return(rv);
6007 * ../pith/conf.c required function
6010 unexpected_pinerc_change(void)
6012 Writechar(BELL, 0);
6013 if(want_to("Unexpected pinerc change! Overwrite with current config",
6014 'n', 0, NO_HELP, WT_FLUSH_IN) == 'n'){
6015 return(-1); /* abort pinerc write */
6018 return(0); /* overwrite */
6022 #ifdef _WINDOWS
6024 /*----------------------------------------------------------------------
6025 MSWin scroll callback. Called during scroll message processing.
6029 Args: cmd - what type of scroll operation.
6030 scroll_pos - parameter for operation.
6031 used as position for SCROLL_TO operation.
6033 Returns: TRUE - did the scroll operation.
6034 FALSE - was not able to do the scroll operation.
6035 ----*/
6037 config_scroll_callback (cmd, scroll_pos)
6038 int cmd;
6039 long scroll_pos;
6041 switch (cmd) {
6042 case MSWIN_KEY_SCROLLUPLINE:
6043 config_scroll_down (scroll_pos);
6044 break;
6046 case MSWIN_KEY_SCROLLDOWNLINE:
6047 config_scroll_up (scroll_pos);
6048 break;
6050 case MSWIN_KEY_SCROLLUPPAGE:
6051 config_scroll_down (BODY_LINES(ps_global));
6052 break;
6054 case MSWIN_KEY_SCROLLDOWNPAGE:
6055 config_scroll_up (BODY_LINES(ps_global));
6056 break;
6058 case MSWIN_KEY_SCROLLTO:
6059 config_scroll_to_pos (scroll_pos);
6060 break;
6063 option_screen_redrawer();
6064 fflush(stdout);
6066 return(TRUE);
6069 #endif /* _WINDOWS */