* Exiting the authroization screen for XOAUTH2 makes alpine cancel the
[alpine.git] / alpine / confscroll.c
blobef0a2dd995aa72f0d233818ba9de30d67f0b1478
1 /*
2 * ========================================================================
3 * Copyright 2006-2008 University of Washington
4 * Copyright 2013-2021 Eduardo Chappa
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
15 #include "headers.h"
16 #include "confscroll.h"
17 #include "keymenu.h"
18 #include "status.h"
19 #include "titlebar.h"
20 #include "help.h"
21 #include "radio.h"
22 #include "print.h"
23 #include "ldapconf.h"
24 #include "roleconf.h"
25 #include "colorconf.h"
26 #include "mailview.h"
27 #include "mailcmd.h"
28 #include "mailindx.h"
29 #include "talk.h"
30 #include "setup.h"
31 #include "smime.h"
32 #include "xoauth2conf.h"
33 #include "../pith/state.h"
34 #include "../pith/flag.h"
35 #include "../pith/list.h"
36 #include "../pith/conf.h"
37 #include "../pith/util.h"
38 #include "../pith/newmail.h"
39 #include "../pith/sort.h"
40 #include "../pith/thread.h"
41 #include "../pith/color.h"
42 #include "../pith/hist.h"
43 #include "../pith/icache.h"
44 #include "../pith/conf.h"
45 #include "../pith/init.h"
46 #include "../pith/folder.h"
47 #include "../pith/busy.h"
48 #include "../pith/tempfile.h"
49 #include "../pith/pattern.h"
50 #include "../pith/charconv/utf8.h"
53 #define CONFIG_SCREEN_HELP_TITLE _("HELP FOR SETUP CONFIGURATION")
55 /* TRANSLATORS: Empty Value is what is shown in the configuration
56 screen when the user not only does not set an option but also
57 wants to explicitly not use the default value. Empty value means
58 an option with no value. */
59 char *empty_val = N_("Empty Value");
60 char *empty_val2 = N_("<Empty Value>");
61 /* TRANSLATORS: No Value set is similar to Empty Value, but the
62 user has not explicitly decided to not use the default. It is
63 just an option which the user has left at the default value. */
64 char *no_val = N_("No Value Set");
65 /* TRANSLATORS: Value is Fixed is what is displayed in the config
66 screen when the system managers have set an option to a specific
67 value and they don't allow the user to change it. The value
68 is fixed to a certain value. This isn't the same word as
69 Repaired, it means Unchanging. */
70 char *fixed_val = N_("Value is Fixed");
71 char yesstr[] = "Yes";
72 char nostr[] = "No";
75 EditWhich ew = Main;
78 OPT_SCREEN_S *opt_screen;
82 * This is pretty ugly. Some of the routines operate differently depending
83 * on which variable they are operating on. Sometimes those variables are
84 * global (real alpine.h V_ style variables) and sometimes they are just
85 * local variables (as in role_config_edit_screen). These pointers are here
86 * so that the routines can figure out which variable they are operating
87 * on and do the right thing.
89 struct variable *score_act_global_ptr,
90 *scorei_pat_global_ptr,
91 *age_pat_global_ptr,
92 *size_pat_global_ptr,
93 *cati_global_ptr,
94 *cat_cmd_global_ptr,
95 *cat_lim_global_ptr,
96 *startup_ptr,
97 *role_comment_ptr,
98 *role_forw_ptr,
99 *role_repl_ptr,
100 *role_fldr_ptr,
101 *role_afrom_ptr,
102 *role_filt_ptr,
103 *role_status1_ptr,
104 *role_status2_ptr,
105 *role_status3_ptr,
106 *role_status4_ptr,
107 *role_status5_ptr,
108 *role_status6_ptr,
109 *role_status7_ptr,
110 *role_status8_ptr,
111 *msg_state1_ptr,
112 *msg_state2_ptr,
113 *msg_state3_ptr,
114 *msg_state4_ptr;
117 typedef NAMEVAL_S *(*PTR_TO_RULEFUNC)(int);
121 * Internal prototypes
123 PTR_TO_RULEFUNC rulefunc_from_var(struct pine *, struct variable *);
124 void set_radio_pretty_vals(struct pine *, CONF_S **);
125 int save_include(struct pine *, struct variable *, int);
126 void config_scroll_up(long);
127 void config_scroll_down(long);
128 void config_scroll_to_pos(long);
129 CONF_S *config_top_scroll(struct pine *, CONF_S *);
130 void update_option_screen(struct pine *, OPT_SCREEN_S *, Pos *);
131 void print_option_screen(OPT_SCREEN_S *, char *);
132 void option_screen_redrawer(void);
133 char *text_pretty_value(struct pine *, CONF_S *);
134 char *checkbox_pretty_value(struct pine *, CONF_S *);
135 char *yesno_pretty_value(struct pine *, CONF_S *);
136 char *radio_pretty_value(struct pine *, CONF_S *);
137 char *sigfile_pretty_value(struct pine *, CONF_S *);
138 char *color_pretty_value(struct pine *, CONF_S *);
139 char *sort_pretty_value(struct pine *, CONF_S *);
140 int longest_feature_name(void);
141 COLOR_PAIR *sample_color(struct pine *, struct variable *);
142 COLOR_PAIR *sampleexc_color(struct pine *, struct variable *);
143 void clear_feature(char ***, char *);
144 CONF_S *last_confline(CONF_S *);
145 #ifdef _WINDOWS
146 int config_scroll_callback(int, long);
147 #endif
151 * We test for this same set of vars in a few places.
154 standard_radio_var(struct pine *ps, struct variable *v)
156 return(v == &ps->vars[V_SAVED_MSG_NAME_RULE] ||
157 v == &ps->vars[V_FCC_RULE] ||
158 v == &ps->vars[V_GOTO_DEFAULT_RULE] ||
159 v == &ps->vars[V_INCOMING_STARTUP] ||
160 v == &ps->vars[V_PRUNING_RULE] ||
161 v == &ps->vars[V_REOPEN_RULE] ||
162 v == &ps->vars[V_THREAD_DISP_STYLE] ||
163 v == &ps->vars[V_THREAD_INDEX_STYLE] ||
164 v == &ps->vars[V_FLD_SORT_RULE] ||
165 #ifndef _WINDOWS
166 v == &ps->vars[V_COLOR_STYLE] ||
167 #endif
168 v == &ps->vars[V_INDEX_COLOR_STYLE] ||
169 v == &ps->vars[V_TITLEBAR_COLOR_STYLE] ||
170 v == &ps->vars[V_AB_SORT_RULE]);
174 PTR_TO_RULEFUNC
175 rulefunc_from_var(struct pine *ps, struct variable *v)
177 PTR_TO_RULEFUNC rulefunc = NULL;
179 if(v == &ps->vars[V_SAVED_MSG_NAME_RULE])
180 rulefunc = save_msg_rules;
181 else if(v == &ps->vars[V_FCC_RULE])
182 rulefunc = fcc_rules;
183 else if(v == &ps->vars[V_GOTO_DEFAULT_RULE])
184 rulefunc = goto_rules;
185 else if(v == &ps->vars[V_INCOMING_STARTUP])
186 rulefunc = incoming_startup_rules;
187 else if(v == startup_ptr)
188 rulefunc = startup_rules;
189 else if(v == &ps->vars[V_PRUNING_RULE])
190 rulefunc = pruning_rules;
191 else if(v == &ps->vars[V_REOPEN_RULE])
192 rulefunc = reopen_rules;
193 else if(v == &ps->vars[V_THREAD_DISP_STYLE])
194 rulefunc = thread_disp_styles;
195 else if(v == &ps->vars[V_THREAD_INDEX_STYLE])
196 rulefunc = thread_index_styles;
197 else if(v == &ps->vars[V_FLD_SORT_RULE])
198 rulefunc = fld_sort_rules;
199 else if(v == &ps->vars[V_AB_SORT_RULE])
200 rulefunc = ab_sort_rules;
201 else if(v == &ps->vars[V_INDEX_COLOR_STYLE])
202 rulefunc = index_col_style;
203 else if(v == &ps->vars[V_TITLEBAR_COLOR_STYLE])
204 rulefunc = titlebar_col_style;
205 #ifndef _WINDOWS
206 else if(v == &ps->vars[V_COLOR_STYLE])
207 rulefunc = col_style;
208 #endif
210 return(rulefunc);
214 void
215 standard_radio_setup(struct pine *ps, CONF_S **cl, struct variable *v, CONF_S **first_line)
217 int i, rindent = 12;
218 CONF_S *ctmpb;
219 PTR_TO_RULEFUNC rulefunc;
220 NAMEVAL_S *f;
221 char b[100];
223 if(!(cl && *cl))
224 return;
226 rulefunc = rulefunc_from_var(ps, v);
227 ctmpb = (*cl);
229 (*cl)->flags |= CF_NOSELECT;
230 (*cl)->keymenu = &config_radiobutton_keymenu;
231 (*cl)->tool = NULL;
233 /* put a nice delimiter before list */
234 new_confline(cl)->var = NULL;
235 (*cl)->varnamep = ctmpb;
236 (*cl)->keymenu = &config_radiobutton_keymenu;
237 (*cl)->help = NO_HELP;
238 (*cl)->tool = radiobutton_tool;
239 (*cl)->valoffset = rindent;
240 (*cl)->flags |= CF_NOSELECT;
241 /* TRANSLATORS: Set and Rule Values are the headings for an option
242 that can take one of several values. Underneath the Set heading
243 will be a column where one possibility is turned on (is Set).
244 The other column will be very short descriptions of what
245 the possibilities are (the Rule Values). */
246 utf8_snprintf(b, sizeof(b), "%-5.5w %s", _("Set"), _("Rule Values"));
247 (*cl)->value = cpystr(b);
249 new_confline(cl)->var = NULL;
250 (*cl)->varnamep = ctmpb;
251 (*cl)->keymenu = &config_radiobutton_keymenu;
252 (*cl)->help = NO_HELP;
253 (*cl)->tool = radiobutton_tool;
254 (*cl)->valoffset = rindent;
255 (*cl)->flags |= CF_NOSELECT;
256 (*cl)->value = cpystr("--- ----------------------");
258 if(rulefunc)
259 for(i = 0; (f = (*rulefunc)(i)); i++){
260 new_confline(cl)->var = v;
261 if(first_line && !*first_line && !pico_usingcolor())
262 *first_line = (*cl);
264 (*cl)->varnamep = ctmpb;
265 (*cl)->keymenu = &config_radiobutton_keymenu;
266 (*cl)->help = (v == startup_ptr)
267 ? h_config_other_startup
268 : config_help(v - ps->vars,0);
269 (*cl)->tool = radiobutton_tool;
270 (*cl)->valoffset = rindent;
271 (*cl)->varmem = i;
272 (*cl)->value = pretty_value(ps, *cl);
278 * Reset the displayed values for all of the lines for this
279 * variable because others besides this line may change.
281 void
282 set_radio_pretty_vals(struct pine *ps, CONF_S **cl)
284 CONF_S *ctmp;
286 if(!(cl && *cl &&
287 ((*cl)->var == &ps->vars[V_SORT_KEY] ||
288 standard_radio_var(ps, (*cl)->var) ||
289 (*cl)->var == startup_ptr)))
290 return;
292 /* hunt backwards */
293 for(ctmp = *cl;
294 ctmp && !(ctmp->flags & CF_NOSELECT) && !ctmp->varname;
295 ctmp = prev_confline(ctmp)){
296 if(ctmp->value)
297 fs_give((void **)&ctmp->value);
299 ctmp->value = pretty_value(ps, ctmp);
302 /* hunt forwards */
303 for(ctmp = *cl;
304 ctmp && !ctmp->varname && !(ctmp->flags & CF_NOSELECT);
305 ctmp = next_confline(ctmp)){
306 if(ctmp->value)
307 fs_give((void **)&ctmp->value);
309 ctmp->value = pretty_value(ps, ctmp);
315 * test whether or not a var is
317 * returns: 1 if it should be excluded, 0 otw
320 exclude_config_var(struct pine *ps, struct variable *var, int allow_hard_to_config_remotely)
322 if((ew != Main && (var->is_onlymain)) ||
323 (ew != ps_global->ew_for_except_vars && var->is_outermost))
324 return(1);
326 if(allow_hard_to_config_remotely)
327 return(!(var->is_user && var->is_used && !var->is_obsolete));
329 switch(var - ps->vars){
330 case V_HTML_DIRECTORY :
331 case V_MAIL_DIRECTORY :
332 case V_INCOMING_FOLDERS :
333 case V_FOLDER_SPEC :
334 case V_NEWS_SPEC :
335 case V_STANDARD_PRINTER :
336 case V_LAST_TIME_PRUNE_QUESTION :
337 case V_LAST_VERS_USED :
338 case V_ADDRESSBOOK :
339 case V_GLOB_ADDRBOOK :
340 case V_DISABLE_DRIVERS :
341 case V_DISABLE_AUTHS :
342 #ifdef DF_ENCRYPTION_RANGE
343 case V_ENCRYPTION_RANGE :
344 #endif /* DF_ENCRYPTION_RANGE */
345 case V_REMOTE_ABOOK_METADATA :
346 case V_REMOTE_ABOOK_HISTORY :
347 case V_REMOTE_ABOOK_VALIDITY :
348 case V_OPER_DIR :
349 case V_USERINPUTTIMEO :
350 case V_TCPOPENTIMEO :
351 case V_TCPREADWARNTIMEO :
352 case V_TCPWRITEWARNTIMEO :
353 case V_TCPQUERYTIMEO :
354 case V_QUITQUERYTIMEO :
355 case V_RSHCMD :
356 case V_RSHPATH :
357 case V_RSHOPENTIMEO :
358 case V_SSHCMD :
359 case V_SSHPATH :
360 case V_SSHOPENTIMEO :
361 case V_SENDMAIL_PATH :
362 case V_NEW_VER_QUELL :
363 case V_PATTERNS :
364 case V_PAT_ROLES :
365 case V_PAT_FILTS :
366 case V_PAT_SCORES :
367 case V_PAT_INCOLS :
368 case V_PAT_OTHER :
369 case V_PAT_SRCH :
370 case V_PRINTER :
371 case V_PERSONAL_PRINT_COMMAND :
372 case V_PERSONAL_PRINT_CATEGORY :
373 case V_RSS_NEWS :
374 case V_RSS_WEATHER :
375 case V_WP_INDEXHEIGHT :
376 case V_WP_INDEXLINES :
377 case V_WP_AGGSTATE :
378 case V_WP_STATE :
379 case V_WP_COLUMNS :
380 #ifndef _WINDOWS
381 case V_OLD_CHAR_SET :
382 #endif /* ! _WINDOWS */
383 #if defined(DOS) || defined(OS2)
384 case V_UPLOAD_CMD :
385 case V_UPLOAD_CMD_PREFIX :
386 case V_DOWNLOAD_CMD :
387 case V_DOWNLOAD_CMD_PREFIX :
388 #ifdef _WINDOWS
389 case V_FONT_NAME :
390 case V_FONT_SIZE :
391 case V_FONT_STYLE :
392 case V_FONT_CHAR_SET :
393 case V_PRINT_FONT_NAME :
394 case V_PRINT_FONT_SIZE :
395 case V_PRINT_FONT_STYLE :
396 case V_PRINT_FONT_CHAR_SET :
397 case V_WINDOW_POSITION :
398 case V_CURSOR_STYLE :
399 #endif /* _WINDOWS */
400 #endif /* DOS */
401 #ifdef ENABLE_LDAP
402 case V_LDAP_SERVERS :
403 #endif /* ENABLE_LDAP */
404 return(1);
406 default:
407 break;
410 return(!(var->is_user && var->is_used && !var->is_obsolete &&
411 #ifdef SMIME
412 !smime_related_var(ps, var) &&
413 #endif /* SMIME */
414 !color_related_var(ps, var)));
419 * Test to indicate what should be saved in case user wants to abandon
420 * changes.
423 save_include(struct pine *ps, struct variable *v, int allow_hard_to_config_remotely)
425 return(!exclude_config_var(ps, v, allow_hard_to_config_remotely)
426 || (v->is_user
427 && v->is_used
428 && !v->is_obsolete
429 && (v == &ps->vars[V_PERSONAL_PRINT_COMMAND]
430 #ifdef ENABLE_LDAP
431 || v == &ps->vars[V_LDAP_SERVERS]
432 #endif
433 )));
438 * Handles screen painting and motion. Passes other commands to
439 * custom tools.
441 * Tool return values: Tools should return the following:
442 * 0 nothing changed
443 * -1 unrecognized command
444 * 1 something changed, conf_scroll_screen should remember that
445 * 2 tells conf_scroll_screen to return with value 1 or 0 depending
446 * on whether or not it has previously gotten a 1 from some tool.
447 * 3 tells conf_scroll_screen to return 1 (like 1 and 2 combined)
448 * ? Other tool-specific values can be used. They will cause
449 * conf_scroll_screen to return that value.
451 * Return values:
452 * 0 if nothing happened. That is, a tool returned 2 and we hadn't
453 * previously noted a return of 1
454 * 1 if something happened. That is, a tool returned 2 and we had
455 * previously noted a return of 1
456 * ? Tool-returned value different from -1, 0, 1, 2, or 3. This is it.
458 * Special proviso: If first_line->flags has CF_CHANGES set on entry, then
459 * that will cause things to behave like a change was made since entering
460 * this function.
463 conf_scroll_screen(struct pine *ps, OPT_SCREEN_S *screen, CONF_S *start_line, char *title, char *pdesc, int multicol, int *pos)
465 char tmp[MAXPATH+1];
466 char *utf8str;
467 UCS ch = 'x';
468 int cmd, i, j, done = 0, changes = 0;
469 int retval = 0;
470 int km_popped = 0, stay_in_col = 0;
471 struct key_menu *km = NULL;
472 CONF_S *ctmpa = NULL, *ctmpb = NULL;
473 Pos cursor_pos;
474 OtherMenu what_keymenu = FirstMenu;
475 void (*prev_redrawer)(void);
477 dprint((7, "conf_scroll_screen()\n"));
479 if(BODY_LINES(ps) < 1){
480 q_status_message(SM_ORDER | SM_DING, 3, 3, _("Screen too small"));
481 return(0);
484 if(screen && screen->ro_warning)
485 q_status_message1(SM_ORDER, 1, 3,
486 /* TRANSLATORS: "Config file not changeable," is what replaces the %s */
487 _("%s can't change options or settings"),
488 ps_global->restricted ? "Alpine demo"
489 : _("Config file not changeable,"));
491 screen->current = start_line;
492 if(start_line && start_line->flags & CF_CHANGES)
493 changes++;
495 opt_screen = screen;
496 ps->mangled_screen = 1;
497 ps->redrawer = option_screen_redrawer;
499 while(!done){
500 ps->user_says_cancel = 0;
501 if(km_popped){
502 km_popped--;
503 if(km_popped == 0){
504 clearfooter(ps);
505 ps->mangled_body = 1;
509 if(ps->mangled_screen){
510 ps->mangled_header = 1;
511 ps->mangled_footer = 1;
512 ps->mangled_body = 1;
513 ps->mangled_screen = 0;
516 /*----------- Check for new mail -----------*/
517 if(new_mail(0, NM_TIMING(ch), NM_STATUS_MSG | NM_DEFER_SORT) >= 0)
518 ps->mangled_header = 1;
520 if(ps->mangled_header){
521 set_titlebar(title, ps->mail_stream,
522 ps->context_current,
523 ps->cur_folder, ps->msgmap, 1, FolderName, 0, 0, NULL);
524 ps->mangled_header = 0;
527 update_option_screen(ps, screen, &cursor_pos);
529 if(F_OFF(F_SHOW_CURSOR, ps)){
530 cursor_pos.row = ps->ttyo->screen_rows - FOOTER_ROWS(ps);
531 cursor_pos.col = 0;
534 /*---- This displays new mail notification, or errors ---*/
535 if(km_popped){
536 FOOTER_ROWS(ps) = 3;
537 mark_status_unknown();
540 display_message(ch);
541 if(km_popped){
542 FOOTER_ROWS(ps) = 1;
543 mark_status_unknown();
546 if(ps->mangled_footer || km != screen->current->keymenu){
547 bitmap_t bitmap;
549 setbitmap(bitmap);
551 ps->mangled_footer = 0;
552 km = screen->current->keymenu;
554 if(multicol &&
555 (F_OFF(F_ARROW_NAV, ps_global) ||
556 F_ON(F_RELAXED_ARROW_NAV, ps_global))){
557 menu_clear_binding(km, KEY_LEFT);
558 menu_clear_binding(km, KEY_RIGHT);
559 menu_clear_binding(km, KEY_UP);
560 menu_clear_binding(km, KEY_DOWN);
561 menu_add_binding(km, KEY_UP, MC_CHARUP);
562 menu_add_binding(km, KEY_DOWN, MC_CHARDOWN);
563 menu_add_binding(km, KEY_LEFT, MC_PREVITEM);
564 menu_add_binding(km, ctrl('B'), MC_PREVITEM);
565 menu_add_binding(km, KEY_RIGHT, MC_NEXTITEM);
566 menu_add_binding(km, ctrl('F'), MC_NEXTITEM);
568 else{
569 menu_clear_binding(km, KEY_LEFT);
570 menu_clear_binding(km, KEY_RIGHT);
571 menu_clear_binding(km, KEY_UP);
572 menu_clear_binding(km, KEY_DOWN);
575 * Fix up arrow nav mode if necessary...
577 if(F_ON(F_ARROW_NAV, ps_global)){
578 int cmd;
580 if((cmd = menu_clear_binding(km, '<')) != MC_UNKNOWN){
581 menu_add_binding(km, '<', cmd);
582 menu_add_binding(km, KEY_LEFT, cmd);
585 if((cmd = menu_clear_binding(km, '>')) != MC_UNKNOWN){
586 menu_add_binding(km, '>', cmd);
587 menu_add_binding(km, KEY_RIGHT, cmd);
590 if((cmd = menu_clear_binding(km, 'p')) != MC_UNKNOWN){
591 menu_add_binding(km, 'p', cmd);
592 menu_add_binding(km, KEY_UP, cmd);
595 if((cmd = menu_clear_binding(km, 'n')) != MC_UNKNOWN){
596 menu_add_binding(km, 'n', cmd);
597 menu_add_binding(km, KEY_DOWN, cmd);
602 if(km_popped){
603 FOOTER_ROWS(ps) = 3;
604 clearfooter(ps);
607 draw_keymenu(km, bitmap, ps->ttyo->screen_cols,
608 1-FOOTER_ROWS(ps), 0, what_keymenu);
609 what_keymenu = SameMenu;
611 if(km_popped){
612 FOOTER_ROWS(ps) = 1;
613 mark_keymenu_dirty();
617 MoveCursor(cursor_pos.row, cursor_pos.col);
618 #ifdef MOUSE
619 mouse_in_content(KEY_MOUSE, -1, -1, 0, 0); /* prime the handler */
620 register_mfunc(mouse_in_content, HEADER_ROWS(ps_global), 0,
621 ps_global->ttyo->screen_rows -(FOOTER_ROWS(ps_global)+1),
622 ps_global->ttyo->screen_cols);
623 #endif
624 #ifdef _WINDOWS
625 mswin_setscrollcallback(config_scroll_callback);
626 #endif
627 /*------ Read the command from the keyboard ----*/
628 ch = READ_COMMAND(&utf8str);
629 #ifdef MOUSE
630 clear_mfunc(mouse_in_content);
631 #endif
632 #ifdef _WINDOWS
633 mswin_setscrollcallback(NULL);
634 #endif
636 cmd = menu_command(ch, km);
638 if(km_popped)
639 switch(cmd){
640 case MC_NONE:
641 case MC_OTHER:
642 case MC_RESIZE:
643 case MC_REPAINT:
644 km_popped++;
645 break;
647 default:
648 clearfooter(ps);
649 break;
652 switch(cmd){
653 case MC_OTHER :
654 what_keymenu = NextMenu;
655 ps->mangled_footer = 1;
656 break;
658 case MC_HELP: /* help! */
659 if(FOOTER_ROWS(ps) == 1 && km_popped == 0){
660 km_popped = 2;
661 ps->mangled_footer = 1;
662 break;
665 if(screen->current->help != NO_HELP){
666 prev_redrawer = ps_global->redrawer;
667 helper(screen->current->help,
668 (screen->current->help_title)
669 ? screen->current->help_title
670 : CONFIG_SCREEN_HELP_TITLE,
671 HLPD_SIMPLE);
672 ps_global->redrawer = prev_redrawer;
673 ps->mangled_screen = 1;
675 else
676 q_status_message(SM_ORDER,0,3,_("No help yet."));
678 break;
681 case MC_NEXTITEM: /* next list element */
682 case MC_CHARDOWN:
683 stay_in_col = 0;
684 if(screen->current->flags & CF_DOUBLEVAR){
685 /* if going from col1 to col2, it's simple */
686 if(!(screen->current->flags & CF_VAR2) && cmd == MC_NEXTITEM){
687 screen->current->flags |= CF_VAR2;
688 break;
691 /* otherwise we fall through to normal next */
692 stay_in_col = (screen->current->flags & CF_VAR2 &&
693 cmd == MC_CHARDOWN);
694 screen->current->flags &= ~CF_VAR2;
697 for(ctmpa = next_confline(screen->current), i = 1;
698 ctmpa && (ctmpa->flags & CF_NOSELECT);
699 ctmpa = next_confline(ctmpa), i++)
702 if(ctmpa){
703 screen->current = ctmpa;
704 if(screen->current->flags & CF_DOUBLEVAR && stay_in_col)
705 screen->current->flags |= CF_VAR2;
707 if(cmd == MC_CHARDOWN){
708 for(ctmpa = screen->top_line,
709 j = BODY_LINES(ps) - 1 - HS_MARGIN(ps);
710 j > 0 && ctmpa && ctmpa != screen->current;
711 ctmpa = next_confline(ctmpa), j--)
714 if(!j && ctmpa){
715 for(i = 0;
716 ctmpa && ctmpa != screen->current;
717 ctmpa = next_confline(ctmpa), i++)
720 if(i)
721 config_scroll_up(i);
725 else{
727 * Scroll screen a bit so we show the non-selectable
728 * lines at the bottom.
731 /* set ctmpa to the bottom line on the screen */
732 for(ctmpa = screen->top_line, j = BODY_LINES(ps) - 1;
733 j > 0 && ctmpa;
734 ctmpa = next_confline(ctmpa), j--)
737 i = 0;
738 if(ctmpa){
739 for(ctmpa = next_confline(ctmpa);
740 ctmpa &&
741 (ctmpa->flags & (CF_NOSELECT | CF_B_LINE)) ==
742 CF_NOSELECT;
743 ctmpa = next_confline(ctmpa), i++)
747 if(i)
748 config_scroll_up(i);
749 else
750 q_status_message(SM_ORDER,0,1, _("Already at end of screen"));
753 break;
755 case MC_PREVITEM: /* prev list element */
756 case MC_CHARUP:
757 stay_in_col = 0;
758 if(screen->current->flags & CF_DOUBLEVAR){
759 if(screen->current->flags & CF_VAR2 && cmd == MC_PREVITEM){
760 screen->current->flags &= ~CF_VAR2;
761 break;
764 /* otherwise we fall through to normal prev */
765 stay_in_col = (!(screen->current->flags & CF_VAR2) &&
766 cmd == MC_CHARUP);
767 screen->current->flags &= ~CF_VAR2;
769 else if(cmd == MC_CHARUP)
770 stay_in_col = 1;
772 ctmpa = screen->current;
773 i = 0;
775 if(ctmpa == config_top_scroll(ps, screen->top_line))
776 i = 1;
777 else if(i)
778 i++;
779 while((ctmpa = prev_confline(ctmpa))
780 && (ctmpa->flags&CF_NOSELECT));
782 if(ctmpa){
783 screen->current = ctmpa;
784 if(screen->current->flags & CF_DOUBLEVAR && !stay_in_col)
785 screen->current->flags |= CF_VAR2;
787 if((cmd == MC_CHARUP) && i)
788 config_scroll_down(i);
790 else
791 q_status_message(SM_ORDER, 0, 1,
792 _("Already at start of screen"));
794 break;
796 case MC_PAGEDN: /* page forward */
797 screen->current->flags &= ~CF_VAR2;
798 for(ctmpa = screen->top_line, i = BODY_LINES(ps);
799 i > 0 && ctmpa;
800 ctmpb = ctmpa, ctmpa = next_confline(ctmpa), i--)
803 if(ctmpa){ /* first line off bottom of screen */
804 ctmpb = ctmpa;
805 ps->mangled_body = 1;
806 /* find first selectable line on next page */
807 for(screen->top_line = ctmpa;
808 ctmpa && (ctmpa->flags & CF_NOSELECT);
809 ctmpa = next_confline(ctmpa))
813 * No selectable lines on next page. Slide up to first
814 * selectable.
816 if(!ctmpa){
817 for(ctmpa = prev_confline(ctmpb);
818 ctmpa && (ctmpa->flags & CF_NOSELECT);
819 ctmpa = prev_confline(ctmpa))
822 if(ctmpa)
823 screen->top_line = ctmpa;
826 else{ /* on last screen */
827 /* just move current down to last entry on screen */
828 if(ctmpb){ /* last line of data */
829 for(ctmpa = ctmpb, i = BODY_LINES(ps);
830 i > 0 && ctmpa && (ctmpa->flags & CF_NOSELECT);
831 ctmpa = prev_confline(ctmpa), i--)
834 if(ctmpa == screen->current){
835 q_status_message(SM_ORDER,0,1,
836 _("Already at end of screen"));
837 goto no_down;
840 ps->mangled_body = 1;
844 if(ctmpa)
845 screen->current = ctmpa;
846 no_down:
847 break;
849 case MC_PAGEUP: /* page backward */
850 ps->mangled_body = 1;
851 screen->current->flags &= ~CF_VAR2;
852 if(!(ctmpa=prev_confline(screen->top_line)))
853 ctmpa = screen->current;
855 for(i = BODY_LINES(ps) - 1;
856 i > 0 && prev_confline(ctmpa);
857 i--, ctmpa = prev_confline(ctmpa))
860 for(screen->top_line = ctmpa;
861 ctmpa && (ctmpa->flags & CF_NOSELECT);
862 ctmpa = next_confline(ctmpa))
865 if(ctmpa){
866 if(ctmpa == screen->current){
868 * We get to here if there was nothing selectable on
869 * the previous page. There still may be something
870 * selectable further back than the previous page,
871 * so look for that.
873 for(ctmpa = prev_confline(screen->top_line);
874 ctmpa && (ctmpa->flags & CF_NOSELECT);
875 ctmpa = prev_confline(ctmpa))
878 if(!ctmpa){
879 ctmpa = screen->current;
880 q_status_message(SM_ORDER, 0, 1,
881 _("Already at start of screen"));
885 screen->current = ctmpa;
888 break;
890 #ifdef MOUSE
891 case MC_MOUSE:
893 MOUSEPRESS mp;
895 mouse_get_last (NULL, &mp);
896 mp.row -= HEADER_ROWS(ps);
897 ctmpa = screen->top_line;
899 while (mp.row && ctmpa != NULL) {
900 --mp.row;
901 ctmpa = ctmpa->next;
904 if (ctmpa != NULL && !(ctmpa->flags & CF_NOSELECT)){
905 if(screen->current->flags & CF_DOUBLEVAR)
906 screen->current->flags &= ~CF_VAR2;
908 screen->current = ctmpa;
910 if(screen->current->flags & CF_DOUBLEVAR &&
911 mp.col >= screen->current->val2offset)
912 screen->current->flags |= CF_VAR2;
914 update_option_screen(ps, screen, &cursor_pos);
916 if(mp.button == M_BUTTON_LEFT && mp.doubleclick){
918 if(screen->current->tool){
919 unsigned flags;
920 int default_cmd;
922 flags = screen->current->flags;
923 flags |= (changes ? CF_CHANGES : 0);
925 default_cmd = menu_command(ctrl('M'), km);
926 switch(i=(*screen->current->tool)(ps, default_cmd,
927 &screen->current, flags)){
928 case -1:
929 case 0:
930 break;
932 case 1:
933 changes = 1;
934 break;
936 case 2:
937 retval = changes;
938 done++;
939 break;
941 case 3:
942 retval = 1;
943 done++;
944 break;
946 default:
947 retval = i;
948 done++;
949 break;
953 #ifdef _WINDOWS
954 else if(mp.button == M_BUTTON_RIGHT) {
955 MPopup other_popup[20];
956 int n = -1, cmd, i;
957 struct key_menu *sckm = screen->current->keymenu; /* only for popup */
959 if((cmd = menu_command(ctrl('M'), sckm)) != MC_UNKNOWN){
960 i = menu_binding_index(sckm, cmd);
961 other_popup[++n].type = tQueue;
962 other_popup[n].label.style = lNormal;
963 other_popup[n].label.string = sckm->keys[i].label;
964 other_popup[n].data.val = ctrl('M');
966 else if((cmd = menu_command('>', sckm)) != MC_UNKNOWN){
967 i = menu_binding_index(sckm, cmd);
968 other_popup[++n].type = tQueue;
969 other_popup[n].label.style = lNormal;
970 other_popup[n].label.string = sckm->keys[i].label;
971 other_popup[n].data.val = '>';
974 if(((i = menu_binding_index(sckm, MC_RGB1)) >= 0) ||
975 ((i = menu_binding_index(sckm, MC_RGB2)) >= 0)){
976 other_popup[++n].type = tQueue;
977 other_popup[n].label.style = lNormal;
978 other_popup[n].label.string = sckm->keys[i].label;
979 other_popup[n].data.val =
980 sckm->keys[i].bind.ch[0];
983 if((cmd = menu_command('<', sckm)) != MC_UNKNOWN){
984 i = menu_binding_index(sckm, cmd);
985 other_popup[++n].type = tQueue;
986 other_popup[n].label.style = lNormal;
987 other_popup[n].label.string = sckm->keys[i].label;
988 other_popup[n].data.val = '<';
990 else if((i = menu_binding_index(sckm, MC_EXIT)) >= 0){
991 other_popup[++n].type = tQueue;
992 other_popup[n].label.style = lNormal;
993 other_popup[n].label.string = sckm->keys[i].label;
994 other_popup[n].data.val =
995 sckm->keys[i].bind.ch[0];
998 if((i = menu_binding_index(sckm, MC_HELP)) >= 0){
999 if(n > 0)
1000 other_popup[++n].type = tSeparator;
1002 other_popup[++n].type = tQueue;
1003 other_popup[n].label.style = lNormal;
1004 other_popup[n].label.string = sckm->keys[i].label;
1005 other_popup[n].data.val = sckm->keys[i].bind.ch[0];
1008 if(n > 0){
1009 other_popup[++n].type = tTail;
1010 mswin_popup(other_popup);
1014 else if(mp.button == M_BUTTON_RIGHT) {
1015 MPopup other_popup[20];
1016 int n = -1, cmd, i;
1017 struct key_menu *sckm = screen->current->keymenu; /* only for popup */
1019 if((cmd = menu_command('<', sckm)) != MC_UNKNOWN){
1020 i = menu_binding_index(sckm, cmd);
1021 other_popup[++n].type = tQueue;
1022 other_popup[n].label.style = lNormal;
1023 other_popup[n].label.string = sckm->keys[i].label;
1024 other_popup[n].data.val = '<';
1026 else if((i = menu_binding_index(sckm, MC_EXIT)) >= 0){
1027 other_popup[++n].type = tQueue;
1028 other_popup[n].label.style = lNormal;
1029 other_popup[n].label.string = sckm->keys[i].label;
1030 other_popup[n].data.val = sckm->keys[i].bind.ch[0];
1033 other_popup[++n].type = tTail;
1035 if(n > 0)
1036 mswin_popup(other_popup);
1037 #endif
1040 break;
1041 #endif
1043 case MC_PRINTTXT: /* print screen */
1044 print_option_screen(screen, pdesc ? pdesc : "");
1045 break;
1047 case MC_WHEREIS: /* whereis */
1048 /*--- get string ---*/
1049 {int rc, found = 0;
1050 #define FOUND_IT 0x01
1051 #define FOUND_CURRENT 0x02
1052 #define FOUND_WRAPPED 0x04
1053 #define FOUND_NOSELECT 0x08
1054 #define FOUND_ABOVE 0x10
1055 char *result = NULL, buf[64];
1056 char *p, last[64];
1057 static HISTORY_S *history = NULL;
1058 HelpType help;
1059 static ESCKEY_S ekey[] = {
1060 {0, 0, "", ""},
1061 /* TRANSLATORS: go to Top of screen */
1062 {ctrl('Y'), 10, "^Y", N_("Top")},
1063 {ctrl('V'), 11, "^V", N_("Bottom")},
1064 {KEY_UP, 30, "", ""},
1065 {KEY_DOWN, 31, "", ""},
1066 {-1, 0, NULL, NULL}};
1067 #define KU_WI (3) /* index of KEY_UP */
1069 init_hist(&history, HISTSIZE);
1070 last[0] = '\0';
1071 if((p = get_prev_hist(history, "", 0, NULL)) != NULL){
1072 strncpy(last, p, sizeof(last));
1073 last[sizeof(last)-1] = '\0';
1076 ps->mangled_footer = 1;
1077 buf[0] = '\0';
1078 snprintf(tmp, sizeof(tmp), "Word to find %s%s%s: ",
1079 (last[0]) ? "[" : "",
1080 (last[0]) ? last : "",
1081 (last[0]) ? "]" : "");
1082 tmp[sizeof(tmp)-1] = '\0';
1083 help = NO_HELP;
1084 while(1){
1085 int flags = OE_APPEND_CURRENT;
1088 * 2 is really 1 because there will be one real entry and
1089 * one entry of "" because of the get_prev_hist above.
1091 if(items_in_hist(history) > 2){
1092 ekey[KU_WI].name = HISTORY_UP_KEYNAME;
1093 ekey[KU_WI].label = HISTORY_KEYLABEL;
1094 ekey[KU_WI+1].name = HISTORY_DOWN_KEYNAME;
1095 ekey[KU_WI+1].label = HISTORY_KEYLABEL;
1097 else{
1098 ekey[KU_WI].name = "";
1099 ekey[KU_WI].label = "";
1100 ekey[KU_WI+1].name = "";
1101 ekey[KU_WI+1].label = "";
1104 rc = optionally_enter(buf,-FOOTER_ROWS(ps),0,sizeof(buf),
1105 tmp,ekey,help,&flags);
1106 if(rc == 3)
1107 help = help == NO_HELP ? h_config_whereis : NO_HELP;
1108 else if(rc == 30){
1109 if((p = get_prev_hist(history, buf, 0, NULL)) != NULL){
1110 strncpy(buf, p, sizeof(buf));
1111 buf[sizeof(buf)-1] = '\0';
1113 else
1114 Writechar(BELL, 0);
1116 continue;
1118 else if(rc == 31){
1119 if((p = get_next_hist(history, buf, 0, NULL)) != NULL){
1120 strncpy(buf, p, sizeof(buf));
1121 buf[sizeof(buf)-1] = '\0';
1123 else
1124 Writechar(BELL, 0);
1126 continue;
1128 else if(rc == 0 || rc == 1 || rc == 10 || rc == 11 || !buf[0]){
1129 if(rc == 0 && !buf[0] && last[0])
1130 strncpy(buf, last, 64);
1132 break;
1136 screen->current->flags &= ~CF_VAR2;
1137 if(rc == 0 && buf[0]){
1138 CONF_S *started_here;
1140 save_hist(history, buf, 0, NULL);
1142 ch = KEY_DOWN;
1143 ctmpa = screen->current;
1145 * Skip over the unselectable lines of this "item"
1146 * before starting search so that we don't find the
1147 * same one again.
1149 while((ctmpb = next_confline(ctmpa)) &&
1150 (ctmpb->flags & CF_NOSELECT) &&
1151 !(ctmpb->flags & CF_STARTITEM))
1152 ctmpa = ctmpb;
1154 started_here = next_confline(ctmpa);
1155 while((ctmpa = next_confline(ctmpa)) != NULL)
1156 if(srchstr(ctmpa->varname, buf)
1157 || srchstr(ctmpa->value, buf)){
1159 found = FOUND_IT;
1161 * If this line is not selectable, back up to the
1162 * previous selectable line, but not past the
1163 * start of this "entry".
1165 if(ctmpa->flags & CF_NOSELECT)
1166 found |= FOUND_NOSELECT;
1168 while((ctmpa->flags & CF_NOSELECT) &&
1169 !(ctmpa->flags & CF_STARTITEM) &&
1170 (ctmpb = prev_confline(ctmpa)))
1171 ctmpa = ctmpb;
1174 * If that isn't selectable, better search forward
1175 * for something that is.
1177 while((ctmpa->flags & CF_NOSELECT) &&
1178 (ctmpb = next_confline(ctmpa))){
1179 ctmpa = ctmpb;
1180 found |= FOUND_ABOVE;
1184 * If that still isn't selectable, better search
1185 * backwards for something that is.
1187 while((ctmpa->flags & CF_NOSELECT) &&
1188 (ctmpb = prev_confline(ctmpa))){
1189 ctmpa = ctmpb;
1190 found &= ~FOUND_ABOVE;
1193 break;
1196 if(!found){
1197 found = FOUND_WRAPPED;
1198 ctmpa = first_confline(screen->current);
1200 while(ctmpa != started_here)
1201 if(srchstr(ctmpa->varname, buf)
1202 || srchstr(ctmpa->value, buf)){
1204 found |= FOUND_IT;
1205 if(ctmpa->flags & CF_NOSELECT)
1206 found |= FOUND_NOSELECT;
1208 while((ctmpa->flags & CF_NOSELECT) &&
1209 !(ctmpa->flags & CF_STARTITEM) &&
1210 (ctmpb = prev_confline(ctmpa)))
1211 ctmpa = ctmpb;
1213 while((ctmpa->flags & CF_NOSELECT) &&
1214 (ctmpb = next_confline(ctmpa))){
1215 ctmpa = ctmpb;
1216 found |= FOUND_ABOVE;
1219 if(ctmpa == screen->current)
1220 found |= FOUND_CURRENT;
1222 break;
1224 else
1225 ctmpa = next_confline(ctmpa);
1228 else if(rc == 10){
1229 screen->current = first_confline(screen->current);
1230 if(screen->current && screen->current->flags & CF_NOSELECT){
1231 for(ctmpa = next_confline(screen->current);
1232 ctmpa && (ctmpa->flags & CF_NOSELECT);
1233 ctmpa = next_confline(ctmpa))
1236 if(ctmpa)
1237 screen->current = ctmpa;
1240 /* TRANSLATORS: Searched to ... is the result of the search, searched
1241 to top means the search went past the bottom of the screen and
1242 wrapped back around to the top. */
1243 result = _("Searched to top");
1245 else if(rc == 11){
1246 screen->current = last_confline(screen->current);
1247 if(screen->current && screen->current->flags & CF_NOSELECT){
1248 for(ctmpa = prev_confline(screen->current);
1249 ctmpa && (ctmpa->flags & CF_NOSELECT);
1250 ctmpa = prev_confline(ctmpa))
1253 if(ctmpa)
1254 screen->current = ctmpa;
1257 result = _("Searched to bottom");
1259 else
1260 result = _("WhereIs cancelled");
1262 if((found & FOUND_IT) && ctmpa){
1263 strncpy(last, buf, 64);
1264 result =
1265 (found & FOUND_CURRENT && found & FOUND_WRAPPED && found & FOUND_NOSELECT)
1266 ? _("Current item contains the only match")
1267 : (found & FOUND_CURRENT && found & FOUND_WRAPPED)
1268 ? _("Current line contains the only match")
1269 : (found & FOUND_NOSELECT && found & FOUND_WRAPPED)
1270 ? ((found & FOUND_ABOVE)
1271 ? _("Search wrapped: word found in text above current line")
1272 : _("Search wrapped: word found in text below current line"))
1273 : (found & FOUND_WRAPPED)
1274 ? _("Search wrapped to beginning: word found")
1275 : (found & FOUND_NOSELECT)
1276 ? ((found & FOUND_ABOVE)
1277 ? _("Word found in text above current line")
1278 : _("Word found in text below current line"))
1279 : _("Word found");
1280 screen->current = ctmpa;
1283 q_status_message(SM_ORDER,0,3,result ? result : _("Word not found"));
1286 break;
1288 case MC_HOMEKEY:
1289 screen->current = first_confline(screen->current);
1290 if(screen->current && screen->current->flags & CF_NOSELECT){
1291 for(ctmpa = next_confline(screen->current);
1292 ctmpa && (ctmpa->flags & CF_NOSELECT);
1293 ctmpa = next_confline(ctmpa))
1296 if(ctmpa)
1297 screen->current = ctmpa;
1300 q_status_message(SM_ORDER,0,3, _("Moved to top"));
1301 break;
1303 case MC_ENDKEY:
1304 screen->current = last_confline(screen->current);
1305 if(screen->current && screen->current->flags & CF_NOSELECT){
1306 for(ctmpa = prev_confline(screen->current);
1307 ctmpa && (ctmpa->flags & CF_NOSELECT);
1308 ctmpa = prev_confline(ctmpa))
1311 if(ctmpa)
1312 screen->current = ctmpa;
1315 q_status_message(SM_ORDER,0,3, _("Moved to bottom"));
1316 break;
1318 case MC_XSHELP: /* help! */
1319 if(FOOTER_ROWS(ps) == 1 && km_popped == 0){
1320 km_popped = 2;
1321 ps->mangled_footer = 1;
1322 break;
1325 prev_redrawer = ps_global->redrawer;
1326 helper(h_xoauth2_config_screen, "XOAUTH2 CONFIGURATION SCREEN", HLPD_SIMPLE);
1327 ps_global->redrawer = prev_redrawer;
1328 ps->mangled_screen = 1;
1329 break;
1331 case MC_XSDELETE: /* Send caller to delete XOAUTH2 info */
1332 case MC_XSADD: /* Send caller to add XOAUTH2 info */
1333 if(pos){
1334 *pos = get_confline_number(screen->current);
1335 done++;
1336 retval = cmd == MC_XSADD ? 4 : 5;
1338 break;
1340 case MC_REPAINT: /* redraw the display */
1341 case MC_RESIZE:
1342 ClearScreen();
1343 ps->mangled_screen = 1;
1344 if(pos){
1345 *pos = get_confline_number(screen->current);
1346 done++;
1347 retval = 0;
1349 break;
1351 default:
1352 if(screen && screen->ro_warning){
1353 if(cmd == MC_EXIT){
1354 retval = 0;
1355 done++;
1357 else
1358 q_status_message1(SM_ORDER|SM_DING, 1, 3,
1359 _("%s can't change options or settings"),
1360 ps_global->restricted ? "Alpine demo"
1361 : _("Config file not changeable,"));
1363 else if(screen->current->tool){
1364 unsigned flags;
1366 flags = screen->current->flags;
1367 flags |= (changes ? CF_CHANGES : 0);
1369 switch(i=(*screen->current->tool)(ps, cmd,
1370 &screen->current, flags)){
1371 case -1:
1372 q_status_message2(SM_ORDER, 0, 2,
1373 /* TRANSLATORS: Command <command letter> not defined here.
1374 Leave the trailing %s which might be a parenthetical
1375 remark. */
1376 _("Command \"%s\" not defined here.%s"),
1377 pretty_command(ch),
1378 F_ON(F_BLANK_KEYMENU,ps) ? "" : " See key menu below.");
1379 break;
1381 case 0:
1382 break;
1384 case 1:
1385 changes = 1;
1386 break;
1388 case 2:
1389 retval = changes;
1390 done++;
1391 break;
1393 case 3:
1394 retval = 1;
1395 done++;
1396 break;
1398 default:
1399 retval = i;
1400 done++;
1401 break;
1405 break;
1407 case MC_UTF8:
1408 bogus_utf8_command(utf8str, "?");
1409 break;
1411 case MC_NONE: /* simple timeout */
1412 break;
1416 screen->current = first_confline(screen->current);
1417 free_conflines(&screen->current);
1418 return(retval);
1425 void
1426 config_scroll_up(long int n)
1428 CONF_S *ctmp = opt_screen->top_line;
1429 int cur_found = 0;
1431 if(n < 0)
1432 config_scroll_down(-n);
1433 else if(n){
1434 for(; n>0 && ctmp->next; n--){
1435 ctmp = next_confline(ctmp);
1436 if(prev_confline(ctmp) == opt_screen->current)
1437 cur_found++;
1440 opt_screen->top_line = ctmp;
1441 ps_global->mangled_body = 1;
1442 if(cur_found){
1443 for(ctmp = opt_screen->top_line;
1444 ctmp && (ctmp->flags & CF_NOSELECT);
1445 ctmp = next_confline(ctmp))
1448 if(ctmp)
1449 opt_screen->current = opt_screen->prev = ctmp;
1450 else {
1451 while(opt_screen->top_line->flags & CF_NOSELECT)
1452 opt_screen->top_line = prev_confline(opt_screen->top_line);
1453 opt_screen->current = opt_screen->prev = opt_screen->top_line;
1461 * config_scroll_down -
1463 void
1464 config_scroll_down(long int n)
1466 CONF_S *ctmp = opt_screen->top_line, *last_sel = NULL;
1467 int i;
1469 if(n < 0)
1470 config_scroll_up(-n);
1471 else if(n){
1472 for(; n>0 && ctmp->prev; n--)
1473 ctmp = prev_confline(ctmp);
1475 opt_screen->top_line = ctmp;
1476 ps_global->mangled_body = 1;
1477 for(ctmp = opt_screen->top_line, i = BODY_LINES(ps_global);
1478 i > 0 && ctmp && ctmp != opt_screen->current;
1479 ctmp = next_confline(ctmp), i--)
1480 if(!(ctmp->flags & CF_NOSELECT))
1481 last_sel = ctmp;
1483 if(!i && last_sel)
1484 opt_screen->current = opt_screen->prev = last_sel;
1490 * config_scroll_to_pos -
1492 void
1493 config_scroll_to_pos(long int n)
1495 CONF_S *ctmp;
1497 for(ctmp = first_confline(opt_screen->current);
1498 n && ctmp && ctmp != opt_screen->top_line;
1499 ctmp = next_confline(ctmp), n--)
1502 if(n == 0)
1503 while(ctmp && ctmp != opt_screen->top_line)
1504 if((ctmp = next_confline(ctmp)) != NULL)
1505 n--;
1507 config_scroll_up(n);
1512 * config_top_scroll - return pointer to the
1514 CONF_S *
1515 config_top_scroll(struct pine *ps, CONF_S *topline)
1517 int i;
1518 CONF_S *ctmp;
1520 for(ctmp = topline, i = HS_MARGIN(ps);
1521 ctmp && i;
1522 ctmp = next_confline(ctmp), i--)
1525 return(ctmp ? ctmp : topline);
1530 text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
1532 return(text_toolit(ps, cmd, cl, flags, 0));
1537 * simple text variable handler
1539 * note, things get a little involved due to the
1540 * screen struct <--> variable mapping. (but, once its
1541 * running it shouldn't need changing ;).
1543 * look_for_backslash == 1 means that backslash is an escape character.
1544 * In particular, \, can be used to put a literal comma
1545 * into a value. The value will still have the backslash
1546 * in it, but the comma after the backslash won't be treated
1547 * as an item separator.
1549 * returns: -1 on unrecognized cmd, 0 if no change, 1 if change
1550 * returns what conf_exit_cmd returns for exit command.
1553 text_toolit(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags, int look_for_backslash)
1555 char prompt[81], *sval, *tmp, *swap_val, **newval = NULL;
1556 char *pval = NULL, **apval = NULL, **lval = NULL, ***alval = NULL;
1557 char *olddefval = NULL;
1558 int rv = 0, skip_to_next = 0, after = 0, i = 4, j, k;
1559 int lowrange = 0, hirange = 0, incr = 0, oeflags, oebufsize;
1560 int numval, repeat_key = 0;
1561 int curindex, previndex, nextindex, deefault;
1562 HelpType help;
1563 ESCKEY_S ekey[6];
1565 if((*cl)->var->is_list){
1566 lval = LVAL((*cl)->var, ew);
1567 alval = ALVAL((*cl)->var, ew);
1569 else{
1570 pval = PVAL((*cl)->var, ew);
1571 apval = APVAL((*cl)->var, ew);
1574 oebufsize = 6*MAXPATH;
1575 sval = (char *) fs_get(oebufsize*sizeof(char));
1576 sval[0] = '\0';
1578 if(flags&CF_NUMBER){ /* only happens if !is_list */
1579 incr = 1;
1580 if((*cl)->var == &ps->vars[V_FILLCOL]){
1581 lowrange = 1;
1582 hirange = MAX_FILLCOL;
1584 else if((*cl)->var == &ps->vars[V_OVERLAP]
1585 || (*cl)->var == &ps->vars[V_MARGIN]){
1586 lowrange = 0;
1587 hirange = 20;
1589 else if((*cl)->var == &ps->vars[V_QUOTE_SUPPRESSION]){
1590 lowrange = -(Q_SUPP_LIMIT-1);
1591 hirange = 1000;
1593 else if((*cl)->var == &ps->vars[V_MAXREMSTREAM]){
1594 lowrange = 0;
1595 hirange = 15;
1597 else if((*cl)->var == &ps->vars[V_STATUS_MSG_DELAY]){
1598 lowrange = -10;
1599 hirange = 30;
1601 else if((*cl)->var == &ps->vars[V_ACTIVE_MSG_INTERVAL]){
1602 lowrange = 0;
1603 hirange = 20;
1605 else if((*cl)->var == &ps->vars[V_MAILCHECK] ||
1606 (*cl)->var == &ps->vars[V_INCCHECKINTERVAL] ||
1607 (*cl)->var == &ps->vars[V_INC2NDCHECKINTERVAL] ||
1608 (*cl)->var == &ps->vars[V_MAILCHECKNONCURR]){
1609 lowrange = 0;
1610 hirange = 25000;
1611 incr = 15;
1613 else if((*cl)->var == &ps->vars[V_DEADLETS]){
1614 lowrange = 0;
1615 hirange = 9;
1617 else if((*cl)->var == &ps->vars[V_NMW_WIDTH]){
1618 lowrange = 20;
1619 hirange = MAX_SCREEN_COLS;
1621 else if((*cl)->var == score_act_global_ptr){
1622 lowrange = -100;
1623 hirange = 100;
1625 else if((*cl)->var == &ps->vars[V_TCPOPENTIMEO] ||
1626 (*cl)->var == &ps->vars[V_TCPREADWARNTIMEO] ||
1627 (*cl)->var == &ps->vars[V_TCPQUERYTIMEO]){
1628 lowrange = 5;
1629 hirange = 1000;
1631 else if((*cl)->var == &ps->vars[V_QUITQUERYTIMEO]){
1632 lowrange = 0;
1633 hirange = 1000;
1635 else if((*cl)->var == &ps->vars[V_TCPWRITEWARNTIMEO] ||
1636 (*cl)->var == &ps->vars[V_RSHOPENTIMEO] ||
1637 (*cl)->var == &ps->vars[V_SSHOPENTIMEO] ||
1638 (*cl)->var == &ps->vars[V_USERINPUTTIMEO]){
1639 lowrange = 0;
1640 hirange = 1000;
1642 else if((*cl)->var == &ps->vars[V_INCCHECKTIMEO]){
1643 lowrange = 1;
1644 hirange = 1000;
1646 else if((*cl)->var == &ps->vars[V_MAILDROPCHECK]){
1647 lowrange = 0;
1648 hirange = 1000000;
1649 incr = 60;
1651 else if((*cl)->var == &ps->vars[V_NNTPRANGE]){
1652 lowrange = 0;
1653 hirange = 1000000;
1654 incr = 100;
1656 else if((*cl)->var == &ps->vars[V_REMOTE_ABOOK_VALIDITY]){
1657 lowrange = -1;
1658 hirange = 25000;
1660 else if((*cl)->var == &ps->vars[V_REMOTE_ABOOK_HISTORY]){
1661 lowrange = 0;
1662 hirange = 100;
1664 else if((*cl)->var == cat_lim_global_ptr){
1665 lowrange = -1;
1666 hirange = 10000000;
1668 else{
1669 lowrange = 0;
1670 hirange = 25000;
1673 ekey[0].ch = -2;
1674 ekey[0].rval = 'x';
1675 ekey[0].name = "";
1676 ekey[0].label = "";
1677 ekey[1].ch = ctrl('P');
1678 ekey[1].rval = ctrl('P');
1679 ekey[1].name = "^P";
1680 ekey[1].label = N_("Decrease");
1681 ekey[2].ch = ctrl('N');
1682 ekey[2].rval = ctrl('N');
1683 ekey[2].name = "^N";
1684 ekey[2].label = N_("Increase");
1685 ekey[3].ch = KEY_DOWN;
1686 ekey[3].rval = ctrl('P');
1687 ekey[3].name = "";
1688 ekey[3].label = "";
1689 ekey[4].ch = KEY_UP;
1690 ekey[4].rval = ctrl('N');
1691 ekey[4].name = "";
1692 ekey[4].label = "";
1693 ekey[5].ch = -1;
1696 switch(cmd){
1697 case MC_ADD: /* add to list */
1698 if(fixed_var((*cl)->var, "add to", NULL)){
1699 break;
1701 else if(!(*cl)->var->is_list && pval){
1702 q_status_message(SM_ORDER, 3, 3,
1703 _("Only single value allowed. Use \"Change\"."));
1705 else{
1706 int maxwidth;
1707 char *p;
1709 if((*cl)->var->is_list
1710 && lval && lval[0] && lval[0][0]
1711 && (*cl)->value){
1712 char tmpval[101];
1713 /* regular add to an existing list */
1715 strncpy(tmpval, (*cl)->value, sizeof(tmpval));
1716 tmpval[sizeof(tmpval)-1] = '\0';
1717 removing_trailing_white_space(tmpval);
1719 /* 33 is the number of chars other than the value */
1720 maxwidth = MIN(80, ps->ttyo->screen_cols) - 15;
1721 k = MIN(18, MAX(maxwidth-33,0));
1722 if(utf8_width(tmpval) > k && k >= 3){
1723 (void) utf8_truncate(tmpval, k-3);
1724 strncat(tmpval, "...", sizeof(tmpval)-strlen(tmpval)-1);
1725 tmpval[sizeof(tmpval)-1] = '\0';
1728 utf8_snprintf(prompt, sizeof(prompt),
1729 _("Enter text to insert before \"%.*w\": "), k, tmpval);
1730 prompt[sizeof(prompt)-1] = '\0';
1732 else if((*cl)->var->is_list
1733 && !lval
1734 && (*cl)->var->current_val.l){
1735 /* Add to list which doesn't exist, but default does exist */
1736 ekey[0].ch = 'r';
1737 ekey[0].rval = 'r';
1738 ekey[0].name = "R";
1739 ekey[0].label = N_("Replace");
1740 ekey[1].ch = 'a';
1741 ekey[1].rval = 'a';
1742 ekey[1].name = "A";
1743 ekey[1].label = N_("Add To");
1744 ekey[2].ch = -1;
1745 strncpy(prompt, _("Replace or Add To default value ? "), sizeof(prompt));
1746 prompt[sizeof(prompt)-1] = '\0';
1747 switch(radio_buttons(prompt, -FOOTER_ROWS(ps), ekey, 'a', 'x',
1748 h_config_replace_add, RB_NORM)){
1749 case 'a':
1750 p = sval;
1751 for(j = 0; (*cl)->var->current_val.l[j]; j++){
1752 sstrncpy(&p, (*cl)->var->current_val.l[j], oebufsize-(p-sval));
1753 if(oebufsize-(p-sval) > 2){
1754 *p++ = ',';
1755 *p++ = ' ';
1758 if(oebufsize-(p-sval) > 0)
1759 *p = '\0';
1762 sval[oebufsize-1] = '\0';
1764 add_text:
1765 if(flags & CF_NUMBER)
1766 snprintf(prompt, sizeof(prompt), _("Enter the numeric text to be added : "));
1767 else
1768 snprintf(prompt, sizeof(prompt), _("Enter the text to be added : "));
1770 break;
1772 case 'r':
1773 replace_text:
1774 if(olddefval){
1775 strncpy(sval, olddefval, oebufsize);
1776 sval[oebufsize-1] = '\0';
1779 if(flags & CF_NUMBER)
1780 snprintf(prompt, sizeof(prompt), _("Enter the numeric replacement text : "));
1781 else
1782 snprintf(prompt, sizeof(prompt), _("Enter the replacement text : "));
1784 break;
1786 case 'x':
1787 i = 1;
1788 cmd_cancelled("Add");
1789 break;
1792 else{
1793 if(flags & CF_NUMBER)
1794 snprintf(prompt, sizeof(prompt), _("Enter the numeric text to be added : "));
1795 else
1796 snprintf(prompt, sizeof(prompt), _("Enter the text to be added : "));
1799 prompt[sizeof(prompt)-1] = '\0';
1801 ps->mangled_footer = 1;
1803 if(i == 1)
1804 break;
1806 help = NO_HELP;
1807 while(1){
1808 if((*cl)->var->is_list
1809 && lval && lval[0] && lval[0][0]
1810 && (*cl)->value){
1811 ekey[0].ch = ctrl('W');
1812 ekey[0].rval = 5;
1813 ekey[0].name = "^W";
1814 /* TRANSLATORS: Insert new item before current item */
1815 ekey[0].label = after ? N_("InsertBefore") : N_("InsertAfter");
1816 ekey[1].ch = -1;
1818 else if(!(flags&CF_NUMBER))
1819 ekey[0].ch = -1;
1821 oeflags = OE_APPEND_CURRENT;
1822 i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, oebufsize,
1823 prompt,
1824 (ekey[0].ch != -1) ? ekey : NULL,
1825 help, &oeflags);
1826 if(i == 0){
1827 rv = 1;
1828 if((*cl)->var->is_list)
1829 ps->mangled_body = 1;
1830 else
1831 ps->mangled_footer = 1;
1833 removing_leading_and_trailing_white_space(sval);
1835 * Coerce "" and <Empty Value> to empty string input.
1836 * Catch <No Value Set> as a substitute for deleting.
1838 if((*sval == '\"' && *(sval+1) == '\"' && *(sval+2) == '\0')
1839 || !struncmp(sval, _(empty_val), strlen(_(empty_val)))
1840 || (*sval == '<'
1841 && !struncmp(sval+1, _(empty_val), strlen(_(empty_val)))))
1842 *sval = '\0';
1843 else if(!struncmp(sval, _(no_val), strlen(_(no_val)))
1844 || (*sval == '<'
1845 && !struncmp(sval+1, _(no_val), strlen(_(no_val)))))
1846 goto delete;
1848 if((*cl)->var->is_list){
1849 if(*sval || !lval){
1850 char **ltmp;
1851 int i;
1853 i = 0;
1854 for(tmp = sval; *tmp; tmp++)
1855 if(*tmp == ',')
1856 i++; /* conservative count of ,'s */
1858 if(!i){
1859 ltmp = (char **)fs_get(2 * sizeof(char *));
1860 ltmp[0] = cpystr(sval);
1861 ltmp[1] = NULL;
1863 else
1864 ltmp = parse_list(sval, i + 1,
1865 look_for_backslash
1866 ? PL_COMMAQUOTE : 0,
1867 NULL);
1869 if(ltmp[0]){
1870 config_add_list(ps, cl, ltmp, &newval, after);
1871 if(after)
1872 skip_to_next = 1;
1874 else{
1875 q_status_message1(SM_ORDER, 0, 3,
1876 _("Can't add %s to list"), _(empty_val));
1877 rv = ps->mangled_body = 0;
1880 fs_give((void **)&ltmp);
1882 else{
1883 q_status_message1(SM_ORDER, 0, 3,
1884 _("Can't add %s to list"), _(empty_val));
1887 else{
1888 if(flags&CF_NUMBER && sval[0]
1889 && !(isdigit((unsigned char)sval[0])
1890 || sval[0] == '-' || sval[0] == '+')){
1891 q_status_message(SM_ORDER,3,3,
1892 _("Entry must be numeric"));
1893 i = 3; /* to keep loop going */
1894 continue;
1897 if(apval && *apval)
1898 fs_give((void **)apval);
1900 if(!(olddefval && !strcmp(sval, olddefval))
1901 || ((*cl)->var == &ps->vars[V_POST_CHAR_SET])
1902 || want_to(_("Leave unset and use default "),
1903 'y', 'y', NO_HELP, WT_FLUSH_IN) == 'n')
1904 *apval = cpystr(sval);
1906 newval = &(*cl)->value;
1909 else if(i == 1){
1910 cmd_cancelled("Add");
1912 else if(i == 3){
1913 help = help == NO_HELP ? h_config_add : NO_HELP;
1914 continue;
1916 else if(i == 4){ /* no redraw, yet */
1917 continue;
1919 else if(i == 5){ /* change from/to prepend to/from append */
1920 char tmpval[101];
1922 after = after ? 0 : 1;
1923 strncpy(tmpval, (*cl)->value, sizeof(tmpval));
1924 tmpval[sizeof(tmpval)-1] = '\0';
1925 removing_trailing_white_space(tmpval);
1926 /* 33 is the number of chars other than the value */
1927 maxwidth = MIN(80, ps->ttyo->screen_cols) - 15;
1928 k = MIN(18, MAX(maxwidth-33,0));
1929 if(utf8_width(tmpval) > k && k >= 3){
1930 (void) utf8_truncate(tmpval, k-3);
1931 strncat(tmpval, "...", sizeof(tmpval)-strlen(tmpval)-1);
1932 tmpval[sizeof(tmpval)-1] = '\0';
1935 if(after)
1936 snprintf(prompt, sizeof(prompt), _("Enter text to insert after \"%.*s\": "), k, tmpval);
1937 else
1938 snprintf(prompt, sizeof(prompt), _("Enter text to insert before \"%.*s\": "), k, tmpval);
1940 continue;
1942 else if(i == ctrl('P')){
1943 if(sval[0])
1944 numval = atoi(sval);
1945 else{
1946 if(pval)
1947 numval = atoi(pval);
1948 else
1949 numval = lowrange + 1;
1952 if(numval == lowrange){
1954 * Protect user from repeating arrow key that
1955 * causes message to appear over and over.
1957 if(++repeat_key > 0){
1958 q_status_message1(SM_ORDER,3,3,
1959 _("Minimum value is %s"), comatose(lowrange));
1960 repeat_key = -5;
1963 else
1964 repeat_key = 0;
1966 numval = MAX(numval - incr, lowrange);
1967 snprintf(sval, oebufsize, "%d", numval);
1968 sval[oebufsize-1] = '\0';
1969 continue;
1971 else if(i == ctrl('N')){
1972 if(sval[0])
1973 numval = atoi(sval);
1974 else{
1975 if(pval)
1976 numval = atoi(pval);
1977 else
1978 numval = lowrange + 1;
1981 if(numval == hirange){
1982 if(++repeat_key > 0){
1983 q_status_message1(SM_ORDER,3,3,
1984 _("Maximum value is %s"), comatose(hirange));
1985 repeat_key = -5;
1988 else
1989 repeat_key = 0;
1991 numval = MIN(numval + incr, hirange);
1992 snprintf(sval, oebufsize, "%d", numval);
1993 sval[oebufsize-1] = '\0';
1994 continue;
1997 break;
2001 break;
2003 case MC_DELETE: /* delete */
2004 delete:
2005 if(!(*cl)->var->is_list
2006 && apval && !*apval
2007 && (*cl)->var->current_val.p){
2008 char pmt[80];
2010 snprintf(pmt, sizeof(pmt), _("Override default with %s"), _(empty_val2));
2011 pmt[sizeof(pmt)-1] = '\0';
2012 if(want_to(pmt, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
2013 sval[0] = '\0';
2014 *apval = cpystr(sval);
2015 newval = &(*cl)->value;
2016 rv = ps->mangled_footer = 1;
2019 else if((*cl)->var->is_list
2020 && alval && !lval
2021 && (*cl)->var->current_val.l){
2022 char pmt[80];
2024 snprintf(pmt, sizeof(pmt), _("Override default with %s"), _(empty_val2));
2025 pmt[sizeof(pmt)-1] = '\0';
2026 if(want_to(pmt, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
2027 char **ltmp;
2029 sval[0] = '\0';
2030 ltmp = (char **)fs_get(2 * sizeof(char *));
2031 ltmp[0] = cpystr(sval);
2032 ltmp[1] = NULL;
2033 config_add_list(ps, cl, ltmp, &newval, 0);
2034 fs_give((void **)&ltmp);
2035 rv = ps->mangled_body = 1;
2038 else if(((*cl)->var->is_list && !lval)
2039 || (!(*cl)->var->is_list && !pval)){
2040 q_status_message(SM_ORDER, 0, 3, _("No set value to delete"));
2042 else{
2043 if((*cl)->var->is_fixed)
2044 snprintf(prompt, sizeof(prompt), _("Delete (unused) %s from %s "),
2045 (*cl)->var->is_list
2046 ? (!*lval[(*cl)->varmem])
2047 ? _(empty_val2)
2048 : lval[(*cl)->varmem]
2049 : (pval)
2050 ? (!*pval)
2051 ? _(empty_val2)
2052 : pval
2053 : "<NULL VALUE>",
2054 (*cl)->var->name);
2055 else
2056 snprintf(prompt, sizeof(prompt), _("Really delete %s%s from %s "),
2057 (*cl)->var->is_list ? "item " : "",
2058 (*cl)->var->is_list
2059 ? int2string((*cl)->varmem + 1)
2060 : (pval)
2061 ? (!*pval)
2062 ? _(empty_val2)
2063 : pval
2064 : "<NULL VALUE>",
2065 (*cl)->var->name);
2067 prompt[sizeof(prompt)-1] = '\0';
2070 ps->mangled_footer = 1;
2071 if(want_to(prompt, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
2072 rv = 1;
2073 if((*cl)->var->is_list)
2074 ps->mangled_body = 1;
2075 else
2076 ps->mangled_footer = 1;
2078 if((*cl)->var->is_list){
2079 if(lval[(*cl)->varmem])
2080 fs_give((void **)&lval[(*cl)->varmem]);
2082 config_del_list_item(cl, &newval);
2084 else{
2085 if(apval && *apval)
2086 fs_give((void **)apval);
2088 newval = &(*cl)->value;
2091 else
2092 q_status_message(SM_ORDER, 0, 3, _("Value not deleted"));
2095 break;
2097 case MC_EDIT: /* edit/change list option */
2098 if(fixed_var((*cl)->var, NULL, NULL)){
2099 break;
2101 else if(((*cl)->var->is_list
2102 && !lval
2103 && (*cl)->var->current_val.l)
2105 (!(*cl)->var->is_list
2106 && !pval
2107 && (*cl)->var->current_val.p)){
2110 * In non-list case, offer default value for editing.
2112 if(!(*cl)->var->is_list
2113 && (*cl)->var != &ps->vars[V_REPLY_INTRO]
2114 && (*cl)->var->current_val.p[0]
2115 && strcmp(VSTRING,(*cl)->var->current_val.p)){
2116 int quote_it;
2117 size_t len;
2119 olddefval = (char *) fs_get(strlen((*cl)->var->current_val.p)+3);
2121 if(!strncmp((*cl)->var->current_val.p,
2122 DSTRING,
2123 (len=strlen(DSTRING)))){
2124 /* strip DSTRING and trailing paren */
2125 strncpy(olddefval, (*cl)->var->current_val.p+len,
2126 strlen((*cl)->var->current_val.p)-len-1);
2127 olddefval[strlen((*cl)->var->current_val.p)-len-1] = '\0';
2129 else{
2130 /* quote it if there are trailing spaces */
2131 quote_it = ((*cl)->var->current_val.p[strlen((*cl)->var->current_val.p)-1] == SPACE);
2132 snprintf(olddefval, strlen((*cl)->var->current_val.p)+3, "%s%s%s", quote_it ? "\"" : "", (*cl)->var->current_val.p, quote_it ? "\"" : "");
2135 olddefval[strlen((*cl)->var->current_val.p)+3-1] = '\0';
2138 goto replace_text;
2140 else if(((*cl)->var->is_list
2141 && !lval
2142 && !(*cl)->var->current_val.l)
2144 (!(*cl)->var->is_list
2145 && !pval
2146 && !(*cl)->var->current_val.p)){
2147 goto add_text;
2149 else{
2150 HelpType help;
2151 char *clptr;
2153 if(sval)
2154 fs_give((void **)&sval);
2155 if((*cl)->var->is_list){
2156 snprintf(prompt, sizeof(prompt), _("Change field %s list entry : "),
2157 (*cl)->var->name);
2158 prompt[sizeof(prompt)-1] = '\0';
2159 clptr = lval[(*cl)->varmem] ? lval[(*cl)->varmem] : NULL;
2161 else{
2162 if(flags & CF_NUMBER)
2163 snprintf(prompt, sizeof(prompt), _("Change numeric field %s value : "), (*cl)->var->name);
2164 else
2165 snprintf(prompt, sizeof(prompt), _("Change field %s value : "), (*cl)->var->name);
2167 clptr = pval ? pval : NULL;
2170 oebufsize = clptr ? (int) MAX(MAXPATH, 50+strlen(clptr)) : MAXPATH;
2171 sval = (char *) fs_get(oebufsize * sizeof(char));
2172 snprintf(sval, oebufsize, "%s", clptr ? clptr : "");
2173 sval[oebufsize-1] = '\0';
2175 ps->mangled_footer = 1;
2176 help = NO_HELP;
2177 while(1){
2178 if(!(flags&CF_NUMBER))
2179 ekey[0].ch = -1;
2181 oeflags = OE_APPEND_CURRENT;
2182 i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, oebufsize,
2183 prompt,
2184 (ekey[0].ch != -1) ? ekey : NULL,
2185 help, &oeflags);
2186 if(i == 0){
2187 removing_leading_and_trailing_white_space(sval);
2189 * Coerce "" and <Empty Value> to empty string input.
2190 * Catch <No Value Set> as a substitute for deleting.
2192 if((*sval == '\"' && *(sval+1) == '\"' && *(sval+2) == '\0')
2193 || !struncmp(sval, _(empty_val), strlen(_(empty_val)))
2194 || (*sval == '<'
2195 && !struncmp(sval+1, _(empty_val), strlen(_(empty_val)))))
2196 *sval = '\0';
2197 else if(!struncmp(sval, _(no_val), strlen(_(no_val)))
2198 || (*sval == '<'
2199 && !struncmp(sval+1, _(no_val), strlen(_(no_val)))))
2200 goto delete;
2202 rv = 1;
2203 if((*cl)->var->is_list)
2204 ps->mangled_body = 1;
2205 else
2206 ps->mangled_footer = 1;
2208 if((*cl)->var->is_list){
2209 char **ltmp = NULL;
2210 int i;
2212 if(lval[(*cl)->varmem])
2213 fs_give((void **)&lval[(*cl)->varmem]);
2215 i = 0;
2216 for(tmp = sval; *tmp; tmp++)
2217 if(*tmp == ',')
2218 i++; /* conservative count of ,'s */
2220 if(i)
2221 ltmp = parse_list(sval, i + 1,
2222 look_for_backslash
2223 ? PL_COMMAQUOTE : 0,
2224 NULL);
2226 if(ltmp && !ltmp[0]) /* only commas */
2227 goto delete;
2228 else if(!i || (ltmp && !ltmp[1])){ /* only one item */
2229 lval[(*cl)->varmem] = cpystr(sval);
2230 newval = &(*cl)->value;
2232 if(ltmp && ltmp[0])
2233 fs_give((void **)&ltmp[0]);
2235 else if(ltmp){
2237 * Looks like the value was changed to a
2238 * list, so delete old value, and insert
2239 * new list...
2241 * If more than one item in existing list and
2242 * current is end of existing list, then we
2243 * have to delete and append instead of
2244 * deleting and prepending.
2246 if(((*cl)->varmem > 0 || lval[1])
2247 && !(lval[(*cl)->varmem+1])){
2248 after = 1;
2249 skip_to_next = 1;
2252 config_del_list_item(cl, &newval);
2253 config_add_list(ps, cl, ltmp, &newval, after);
2256 if(ltmp)
2257 fs_give((void **)&ltmp);
2259 else{
2260 if(flags&CF_NUMBER && sval[0]
2261 && !(isdigit((unsigned char)sval[0])
2262 || sval[0] == '-' || sval[0] == '+')){
2263 q_status_message(SM_ORDER,3,3,
2264 _("Entry must be numeric"));
2265 continue;
2268 if(apval && *apval)
2269 fs_give((void **)apval);
2271 if(sval[0] && apval)
2272 *apval = cpystr(sval);
2274 newval = &(*cl)->value;
2277 else if(i == 1){
2278 cmd_cancelled("Change");
2280 else if(i == 3){
2281 help = help == NO_HELP ? h_config_change : NO_HELP;
2282 continue;
2284 else if(i == 4){ /* no redraw, yet */
2285 continue;
2287 else if(i == ctrl('P')){
2288 numval = atoi(sval);
2289 if(numval == lowrange){
2291 * Protect user from repeating arrow key that
2292 * causes message to appear over and over.
2294 if(++repeat_key > 0){
2295 q_status_message1(SM_ORDER,3,3,
2296 _("Minimum value is %s"), comatose(lowrange));
2297 repeat_key = -5;
2300 else
2301 repeat_key = 0;
2303 numval = MAX(numval - incr, lowrange);
2304 snprintf(sval, oebufsize, "%d", numval);
2305 sval[oebufsize-1] = '\0';
2306 continue;
2308 else if(i == ctrl('N')){
2309 numval = atoi(sval);
2310 if(numval == hirange){
2311 if(++repeat_key > 0){
2312 q_status_message1(SM_ORDER,3,3,
2313 _("Maximum value is %s"), comatose(hirange));
2314 repeat_key = -5;
2317 else
2318 repeat_key = 0;
2320 numval = MIN(numval + incr, hirange);
2321 snprintf(sval, oebufsize, "%d", numval);
2322 sval[oebufsize-1] = '\0';
2323 continue;
2326 break;
2330 break;
2332 case MC_SHUFFLE:
2333 if(!((*cl)->var && (*cl)->var->is_list)){
2334 q_status_message(SM_ORDER, 0, 2,
2335 _("Can't shuffle single-valued setting"));
2336 break;
2339 if(!alval)
2340 break;
2342 curindex = (*cl)->varmem;
2343 previndex = curindex-1;
2344 nextindex = curindex+1;
2345 if(!*alval || !(*alval)[nextindex])
2346 nextindex = -1;
2348 if((previndex < 0 && nextindex < 0) || !*alval){
2349 q_status_message(SM_ORDER, 0, 3,
2350 _("Shuffle only makes sense when there is more than one value defined"));
2351 break;
2354 /* Move it up or down? */
2355 i = 0;
2356 ekey[i].ch = 'u';
2357 ekey[i].rval = 'u';
2358 ekey[i].name = "U";
2359 ekey[i++].label = N_("Up");
2361 ekey[i].ch = 'd';
2362 ekey[i].rval = 'd';
2363 ekey[i].name = "D";
2364 ekey[i++].label = N_("Down");
2366 ekey[i].ch = -1;
2367 deefault = 'u';
2369 if(previndex < 0){ /* no up */
2370 ekey[0].ch = -2;
2371 deefault = 'd';
2373 else if(nextindex < 0)
2374 ekey[1].ch = -2; /* no down */
2376 snprintf(prompt, sizeof(prompt), "Shuffle %s%s%s ? ",
2377 (ekey[0].ch != -2) ? "UP" : "",
2378 (ekey[0].ch != -2 && ekey[1].ch != -2) ? " or " : "",
2379 (ekey[1].ch != -2) ? "DOWN" : "");
2380 help = (ekey[0].ch == -2) ? h_hdrcolor_shuf_down
2381 : (ekey[1].ch == -2) ? h_hdrcolor_shuf_up
2382 : h_hdrcolor_shuf;
2383 prompt[sizeof(prompt)-1] = '\0';
2385 i = radio_buttons(prompt, -FOOTER_ROWS(ps), ekey, deefault, 'x',
2386 help, RB_NORM);
2388 switch(i){
2389 case 'x':
2390 cmd_cancelled("Shuffle");
2391 return(rv);
2393 case 'u':
2394 case 'd':
2395 break;
2398 /* swap order */
2399 if(i == 'd'){
2400 swap_val = (*alval)[curindex];
2401 (*alval)[curindex] = (*alval)[nextindex];
2402 (*alval)[nextindex] = swap_val;
2404 else if(i == 'u'){
2405 swap_val = (*alval)[curindex];
2406 (*alval)[curindex] = (*alval)[previndex];
2407 (*alval)[previndex] = swap_val;
2409 else /* can't happen */
2410 break;
2413 * Fix the conf line values.
2416 if((*cl)->value)
2417 fs_give((void **)&(*cl)->value);
2419 (*cl)->value = pretty_value(ps, *cl);
2421 if(i == 'd'){
2422 if((*cl)->next->value)
2423 fs_give((void **)&(*cl)->next->value);
2425 (*cl)->next->value = pretty_value(ps, (*cl)->next);
2426 *cl = next_confline(*cl);
2428 else{
2429 if((*cl)->prev->value)
2430 fs_give((void **)&(*cl)->prev->value);
2432 (*cl)->prev->value = pretty_value(ps, (*cl)->prev);
2433 *cl = prev_confline(*cl);
2436 rv = ps->mangled_body = 1;
2437 break;
2439 case MC_EXIT: /* exit */
2440 rv = config_exit_cmd(flags);
2441 break;
2443 default:
2444 rv = -1;
2445 break;
2448 if(skip_to_next)
2449 *cl = next_confline(*cl);
2452 * At this point, if changes occurred, var->user_val.X is set.
2453 * So, fix the current_val, and handle special cases...
2455 * NOTE: we don't worry about the "fixed variable" case here, because
2456 * editing such vars should have been prevented above...
2458 if(rv == 1){
2460 * Now go and set the current_val based on user_val changes
2461 * above. Turn off command line settings...
2463 set_current_val((*cl)->var, TRUE, FALSE);
2464 fix_side_effects(ps, (*cl)->var, 0);
2467 * Delay setting the displayed value until "var.current_val" is set
2468 * in case current val gets changed due to a special case above.
2470 if(newval){
2471 if(*newval)
2472 fs_give((void **) newval);
2474 *newval = pretty_value(ps, *cl);
2477 exception_override_warning((*cl)->var);
2480 if(sval)
2481 fs_give((void **) &sval);
2483 if(olddefval)
2484 fs_give((void **) &olddefval);
2486 return(rv);
2491 config_exit_cmd(unsigned int flags)
2493 return(screen_exit_cmd(flags, "Configuration"));
2498 simple_exit_cmd(unsigned int flags)
2500 return(2);
2505 * screen_exit_cmd - basic config/flag screen exit logic
2508 screen_exit_cmd(unsigned int flags, char *cmd)
2510 if(flags & CF_CHANGES){
2511 switch(want_to(EXIT_PMT, 'y', 'x', h_config_undo, WT_FLUSH_IN)){
2512 case 'y':
2513 q_status_message1(SM_ORDER,0,3,"%s changes saved", cmd);
2514 return(2);
2516 case 'n':
2517 q_status_message1(SM_ORDER,3,5,"No %s changes saved", cmd);
2518 return(10);
2520 case 'x': /* ^C */
2521 default :
2522 q_status_message(SM_ORDER,3,5,"Changes not yet saved");
2523 return(0);
2526 else
2527 return(2);
2534 void
2535 config_add_list(struct pine *ps, CONF_S **cl, char **ltmp, char ***newval, int after)
2537 int items, i;
2538 char *tmp, ***alval;
2539 CONF_S *ctmp;
2541 for(items = 0, i = 0; ltmp[i]; i++) /* count list items */
2542 items++;
2544 alval = ALVAL((*cl)->var, ew);
2546 if(alval && (*alval)){
2547 if((*alval)[0] && (*alval)[0][0]){
2549 * Since we were already a list, make room
2550 * for the new member[s] and fall thru to
2551 * actually fill them in below...
2553 for(i = 0; (*alval)[i]; i++)
2556 fs_resize((void **)alval, (i + items + 1) * sizeof(char *));
2559 * move the ones that will be bumped down to the bottom of the list
2561 for(; i >= (*cl)->varmem + (after?1:0); i--)
2562 (*alval)[i+items] = (*alval)[i];
2564 i = 0;
2566 else if(alval){
2567 (*cl)->varmem = 0;
2568 if(*alval)
2569 free_list_array(alval);
2571 *alval = (char **)fs_get((items+1)*sizeof(char *));
2572 memset((void *)(*alval), 0, (items+1)*sizeof(char *));
2573 (*alval)[0] = ltmp[0];
2574 if(newval)
2575 *newval = &(*cl)->value;
2577 if((*cl)->value)
2578 fs_give((void **)&(*cl)->value);
2580 i = 1;
2583 else if(alval){
2585 * since we were previously empty, we want
2586 * to replace the first CONF_S's value with
2587 * the first new value, and fill the other
2588 * in below if there's a list...
2590 * first, make sure we're at the beginning of this config
2591 * section and dump the config lines for the default list,
2592 * except for the first one, which we will over-write.
2594 *cl = (*cl)->varnamep;
2595 while((*cl)->next && (*cl)->next->varnamep == (*cl)->varnamep)
2596 snip_confline(&(*cl)->next);
2599 * now allocate the new user_val array and fill in the first entry.
2601 *alval = (char **)fs_get((items+1)*sizeof(char *));
2602 memset((void *)(*alval), 0, (items+1) * sizeof(char *));
2603 (*alval)[(*cl)->varmem=0] = ltmp[0];
2604 if(newval)
2605 *newval = &(*cl)->value;
2607 if((*cl)->value)
2608 fs_give((void **)&(*cl)->value);
2610 i = 1;
2614 * Make new cl's to fit in the new space. Move the value from the current
2615 * line if inserting before it, else leave it where it is.
2617 for(; i < items ; i++){
2618 (*alval)[i+(*cl)->varmem + (after?1:0)] = ltmp[i];
2619 tmp = (*cl)->value;
2620 new_confline(cl);
2621 if(after)
2622 (*cl)->value = NULL;
2623 else
2624 (*cl)->value = tmp;
2626 (*cl)->var = (*cl)->prev->var;
2627 (*cl)->valoffset = (*cl)->prev->valoffset;
2628 (*cl)->varoffset = (*cl)->prev->varoffset;
2629 (*cl)->headingp = (*cl)->prev->headingp;
2630 (*cl)->keymenu = (*cl)->prev->keymenu;
2631 (*cl)->help = (*cl)->prev->help;
2632 (*cl)->tool = (*cl)->prev->tool;
2633 (*cl)->varnamep = (*cl)->prev->varnamep;
2634 *cl = (*cl)->prev;
2635 if(!after)
2636 (*cl)->value = NULL;
2638 if(newval){
2639 if(after)
2640 *newval = &(*cl)->next->value;
2641 else
2642 *newval = &(*cl)->value;
2647 * now fix up varmem values and fill in new values that have been
2648 * left NULL
2650 for(ctmp = (*cl)->varnamep, i = 0;
2651 (*alval)[i];
2652 ctmp = ctmp->next, i++){
2653 ctmp->varmem = i;
2654 if(!ctmp->value){
2655 /* BUG: We should be able to do this without the temp
2656 * copy...
2658 char *ptmp = pretty_value(ps, ctmp);
2659 ctmp->value = (ctmp->varnamep->flags & CF_PRINTER) ? printer_name(ptmp) : cpystr(ptmp);
2660 fs_give((void **)&ptmp);
2669 void
2670 config_del_list_item(CONF_S **cl, char ***newval)
2672 char **bufp, ***alval;
2673 int i;
2674 CONF_S *ctmp;
2676 alval = ALVAL((*cl)->var, ew);
2678 if((*alval)[(*cl)->varmem + 1]){
2679 for(bufp = &(*alval)[(*cl)->varmem];
2680 (*bufp = *(bufp+1)) != NULL; bufp++)
2683 if(*cl == (*cl)->varnamep){ /* leading value */
2684 if((*cl)->value)
2685 fs_give((void **)&(*cl)->value);
2687 ctmp = (*cl)->next;
2688 (*cl)->value = ctmp->value;
2689 ctmp->value = NULL;
2691 else{
2692 ctmp = *cl; /* blast the confline */
2693 *cl = (*cl)->next;
2694 if(ctmp == opt_screen->top_line)
2695 opt_screen->top_line = *cl;
2698 snip_confline(&ctmp);
2700 for(ctmp = (*cl)->varnamep, i = 0; /* now fix up varmem values */
2701 (*alval)[i];
2702 ctmp = ctmp->next, i++)
2703 ctmp->varmem = i;
2705 else if((*cl)->varmem){ /* blasted last in list */
2706 ctmp = *cl;
2707 *cl = (*cl)->prev;
2708 if(ctmp == opt_screen->top_line)
2709 opt_screen->top_line = *cl;
2711 snip_confline(&ctmp);
2713 else{ /* blasted last remaining */
2714 if(alval && *alval)
2715 fs_give((void **)alval);
2717 *newval = &(*cl)->value;
2723 * feature list manipulation tool
2726 * returns: -1 on unrecognized cmd, 0 if no change, 1 if change
2729 checkbox_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
2731 int rv = 0;
2733 switch(cmd){
2734 case MC_TOGGLE: /* mark/unmark feature */
2735 if((*cl)->var == &ps->vars[V_FEATURE_LIST]){
2736 rv = 1;
2737 toggle_feature_bit(ps, (*cl)->varmem, (*cl)->var, *cl, 0);
2739 else
2740 q_status_message(SM_ORDER | SM_DING, 3, 6,
2741 "Programmer botch! Unknown checkbox type.");
2743 break;
2745 case MC_EXIT: /* exit */
2746 rv = config_exit_cmd(flags);
2747 break;
2749 default :
2750 rv = -1;
2751 break;
2754 return(rv);
2759 * simple radio-button style variable handler
2762 radiobutton_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
2764 char **apval;
2765 int rv = 0;
2766 NAMEVAL_S *rule = NULL;
2767 #ifndef _WINDOWS
2768 int old_uc = 0, old_cs = 0;
2769 CONF_S *ctmp;
2770 #endif
2772 apval = APVAL((*cl)->var, ew);
2774 switch(cmd){
2775 case MC_CHOICE : /* set/unset feature */
2777 if(fixed_var((*cl)->var, NULL, NULL)){
2778 if(((*cl)->var->post_user_val.p || (*cl)->var->main_user_val.p)
2779 && want_to(_("Delete old unused personal option setting"),
2780 'y', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
2781 delete_user_vals((*cl)->var);
2782 q_status_message(SM_ORDER, 0, 3, _("Deleted"));
2783 rv = 1;
2786 return(rv);
2789 if(standard_radio_var(ps, (*cl)->var) || (*cl)->var == startup_ptr){
2790 PTR_TO_RULEFUNC rulefunc;
2792 #ifndef _WINDOWS
2793 if((*cl)->var == &ps->vars[V_COLOR_STYLE]){
2794 old_uc = pico_usingcolor();
2795 old_cs = ps->color_style;
2797 #endif
2799 if((*cl)->var->cmdline_val.p)
2800 fs_give((void **)&(*cl)->var->cmdline_val.p);
2802 if(apval && *apval)
2803 fs_give((void **)apval);
2805 rulefunc = rulefunc_from_var(ps, (*cl)->var);
2806 if(rulefunc)
2807 rule = (*rulefunc)((*cl)->varmem);
2809 if(apval && rule)
2810 *apval = cpystr(S_OR_L(rule));
2812 cur_rule_value((*cl)->var, TRUE, TRUE);
2813 set_radio_pretty_vals(ps, cl);
2815 if((*cl)->var == &ps->vars[V_AB_SORT_RULE])
2816 addrbook_redo_sorts();
2817 else if((*cl)->var == &ps->vars[V_THREAD_DISP_STYLE]){
2818 clear_index_cache(ps->mail_stream, 0);
2820 else if((*cl)->var == &ps->vars[V_THREAD_INDEX_STYLE]){
2821 MAILSTREAM *m;
2822 int i;
2824 clear_index_cache(ps->mail_stream, 0);
2825 /* clear all hidden and collapsed flags */
2826 set_lflags(ps->mail_stream, ps->msgmap, MN_COLL | MN_CHID, 0);
2828 if(SEP_THRDINDX()
2829 && SORT_IS_THREADED(ps->msgmap)
2830 && unview_thread(ps, ps->mail_stream, ps->msgmap)){
2831 ps->next_screen = mail_index_screen;
2832 ps->view_skipped_index = 0;
2833 ps->mangled_screen = 1;
2836 if(SORT_IS_THREADED(ps->msgmap)
2837 && (SEP_THRDINDX() || COLL_THRDS()))
2838 collapse_threads(ps->mail_stream, ps->msgmap, NULL);
2840 for(i = 0; i < ps_global->s_pool.nstream; i++){
2841 m = ps_global->s_pool.streams[i];
2842 if(m)
2843 sp_set_viewing_a_thread(m, 0);
2846 adjust_cur_to_visible(ps->mail_stream, ps->msgmap);
2848 #ifndef _WINDOWS
2849 else if((*cl)->var == &ps->vars[V_COLOR_STYLE]){
2850 if(old_cs != ps->color_style){
2851 pico_toggle_color(0);
2852 switch(ps->color_style){
2853 case COL_NONE:
2854 case COL_TERMDEF:
2855 pico_set_color_options(pico_trans_color() ? COLOR_TRANS_OPT : 0);
2856 break;
2857 case COL_ANSI8:
2858 pico_set_color_options(COLOR_ANSI8_OPT|COLOR_TRANS_OPT);
2859 break;
2860 case COL_ANSI16:
2861 pico_set_color_options(COLOR_ANSI16_OPT|COLOR_TRANS_OPT);
2862 break;
2863 case COL_ANSI256:
2864 pico_set_color_options(COLOR_ANSI256_OPT|COLOR_TRANS_OPT);
2865 break;
2868 if(ps->color_style != COL_NONE)
2869 pico_toggle_color(1);
2872 if(pico_usingcolor())
2873 pico_set_normal_color();
2875 if(!old_uc && pico_usingcolor()){
2878 * remove the explanatory warning line and a blank line
2881 /* first find the first blank line */
2882 for(ctmp = *cl; ctmp; ctmp = next_confline(ctmp))
2883 if(ctmp->flags & CF_NOSELECT)
2884 break;
2886 if(ctmp && ctmp->flags & CF_NOSELECT &&
2887 ctmp->prev && !(ctmp->prev->flags & CF_NOSELECT) &&
2888 ctmp->next && ctmp->next->flags & CF_NOSELECT &&
2889 ctmp->next->next &&
2890 ctmp->next->next->flags & CF_NOSELECT){
2891 ctmp->prev->next = ctmp->next->next;
2892 ctmp->next->next->prev = ctmp->prev;
2893 ctmp->next->next = NULL;
2894 free_conflines(&ctmp);
2897 /* make all the colors selectable */
2898 for(ctmp = *cl; ctmp; ctmp = next_confline(ctmp))
2899 if(ctmp->flags & CF_POT_SLCTBL)
2900 ctmp->flags &= ~CF_NOSELECT;
2902 else if(old_uc && !pico_usingcolor()){
2905 * add the explanatory warning line and a blank line
2908 /* first find the existing blank line */
2909 for(ctmp = *cl; ctmp; ctmp = next_confline(ctmp))
2910 if(ctmp->flags & CF_NOSELECT)
2911 break;
2913 /* add the explanatory warning line */
2914 new_confline(&ctmp);
2915 ctmp->help = NO_HELP;
2916 ctmp->flags |= CF_NOSELECT;
2917 ctmp->value = cpystr(COLORNOSET);
2919 /* and add another blank line */
2920 new_confline(&ctmp);
2921 ctmp->flags |= (CF_NOSELECT | CF_B_LINE);
2923 /* make all the colors non-selectable */
2924 for(ctmp = *cl; ctmp; ctmp = next_confline(ctmp))
2925 if(ctmp->flags & CF_POT_SLCTBL)
2926 ctmp->flags |= CF_NOSELECT;
2929 clear_index_cache(ps->mail_stream, 0);
2930 ClearScreen();
2931 ps->mangled_screen = 1;
2933 #endif
2935 ps->mangled_body = 1; /* BUG: redraw it all for now? */
2936 rv = 1;
2938 else if((*cl)->var == &ps->vars[V_SORT_KEY]){
2939 SortOrder def_sort;
2940 int def_sort_rev;
2942 def_sort_rev = (*cl)->varmem >= (short) EndofList;
2943 def_sort = (SortOrder) ((*cl)->varmem - (def_sort_rev
2944 * EndofList));
2945 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s", sort_name(def_sort),
2946 (def_sort_rev) ? "/Reverse" : "");
2948 if((*cl)->var->cmdline_val.p)
2949 fs_give((void **)&(*cl)->var->cmdline_val.p);
2951 if(apval){
2952 if(*apval)
2953 fs_give((void **)apval);
2955 *apval = cpystr(tmp_20k_buf);
2958 set_current_val((*cl)->var, TRUE, TRUE);
2959 if(decode_sort(ps->VAR_SORT_KEY, &def_sort, &def_sort_rev) != -1){
2960 ps->def_sort = def_sort;
2961 ps->def_sort_rev = def_sort_rev;
2964 set_radio_pretty_vals(ps, cl);
2965 ps->mangled_body = 1; /* BUG: redraw it all for now? */
2966 rv = 1;
2968 else
2969 q_status_message(SM_ORDER | SM_DING, 3, 6,
2970 "Programmer botch! Unknown radiobutton type.");
2972 break;
2974 case MC_EXIT: /* exit */
2975 rv = config_exit_cmd(flags);
2976 break;
2978 default :
2979 rv = -1;
2980 break;
2983 if(rv == 1)
2984 exception_override_warning((*cl)->var);
2986 return(rv);
2991 * simple yes/no style variable handler
2994 yesno_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
2996 int rv = 0, yes = 0;
2997 char *pval, **apval;
2999 pval = PVAL((*cl)->var, ew);
3000 apval = APVAL((*cl)->var, ew);
3002 switch(cmd){
3003 case MC_TOGGLE: /* toggle yes to no and back */
3004 if(fixed_var((*cl)->var, NULL, NULL)){
3005 if(((*cl)->var->post_user_val.p || (*cl)->var->main_user_val.p)
3006 && want_to(_("Delete old unused personal option setting"),
3007 'y', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
3008 delete_user_vals((*cl)->var);
3009 q_status_message(SM_ORDER, 0, 3, _("Deleted"));
3010 rv = 1;
3013 return(rv);
3016 rv = 1;
3017 yes = ((pval && !strucmp(pval, yesstr)) ||
3018 (!pval && (*cl)->var->current_val.p &&
3019 !strucmp((*cl)->var->current_val.p, yesstr)));
3020 fs_give((void **)&(*cl)->value);
3022 if(apval){
3023 if(*apval)
3024 fs_give((void **)apval);
3026 if(yes)
3027 *apval = cpystr(nostr);
3028 else
3029 *apval = cpystr(yesstr);
3032 set_current_val((*cl)->var, FALSE, FALSE);
3033 if((*cl)->value)
3034 fs_give((void **)&(*cl)->value);
3036 (*cl)->value = pretty_value(ps, *cl);
3037 fix_side_effects(ps, (*cl)->var, 0);
3039 break;
3041 case MC_EXIT: /* exit */
3042 rv = config_exit_cmd(flags);
3043 break;
3045 default :
3046 rv = -1;
3047 break;
3050 return(rv);
3055 * Manage display of the config/options menu body.
3057 void
3058 update_option_screen(struct pine *ps, OPT_SCREEN_S *screen, Pos *cursor_pos)
3060 int dline = 0, w, save = '\0';
3061 CONF_S *top_line, *ctmp;
3062 char *value;
3063 unsigned got_width;
3064 int want_width, first_width;
3065 char *saveptr = NULL;
3067 #ifdef _WINDOWS
3068 int last_selectable;
3069 mswin_beginupdate();
3070 #endif
3071 if(screen == NULL || BODY_LINES(ps) < 1)
3072 return;
3074 opt_screen = screen;
3076 if(cursor_pos){
3077 cursor_pos->col = 0;
3078 cursor_pos->row = -1; /* to tell us if we've set it yet */
3082 * calculate top line of display for reframing if the current field
3083 * is off the display defined by screen->top_line...
3085 if((ctmp = screen->top_line) != NULL)
3086 for(dline = BODY_LINES(ps);
3087 dline && ctmp && ctmp != screen->current;
3088 ctmp = next_confline(ctmp), dline--)
3091 if(!ctmp || !dline){ /* force reframing */
3092 dline = 0;
3093 ctmp = top_line = first_confline(screen->current);
3095 if(((dline++)%BODY_LINES(ps)) == 0)
3096 top_line = ctmp;
3097 while(ctmp != screen->current && (ctmp = next_confline(ctmp)));
3099 else
3100 top_line = screen->top_line;
3102 #ifdef _WINDOWS
3104 * Figure out how far down the top line is from the top and how many
3105 * total lines there are. Dumb to loop every time thru, but
3106 * there aren't that many lines, and it's cheaper than rewriting things
3107 * to maintain a line count in each structure...
3109 for(dline = 0, ctmp = prev_confline(top_line); ctmp; ctmp = prev_confline(ctmp))
3110 dline++;
3112 scroll_setpos(dline);
3113 last_selectable = dline;
3114 for(ctmp = next_confline(top_line); ctmp ; ctmp = next_confline(ctmp)){
3115 dline++;
3116 if (!(ctmp->flags & CF_NOSELECT))
3117 last_selectable = dline;
3119 dline = last_selectable;
3120 scroll_setrange(BODY_LINES(ps), dline);
3121 #endif
3123 /* mangled body or new page, force redraw */
3124 if(ps->mangled_body || screen->top_line != top_line)
3125 screen->prev = NULL;
3127 /* loop thru painting what's needed */
3128 for(dline = 0, ctmp = top_line;
3129 dline < BODY_LINES(ps);
3130 dline++, ctmp = next_confline(ctmp)){
3133 * only fall thru painting if something needs painting...
3135 if(!(!screen->prev || ctmp == screen->prev || ctmp == screen->current
3136 || ctmp == screen->prev->varnamep
3137 || ctmp == screen->current->varnamep
3138 || ctmp == screen->prev->headingp
3139 || ctmp == screen->current->headingp))
3140 continue;
3142 ClearLine(dline + HEADER_ROWS(ps));
3144 if(ctmp){
3145 if(ctmp->flags & CF_B_LINE)
3146 continue;
3148 if(ctmp->varname && !(ctmp->flags & CF_INVISIBLEVAR)){
3149 if(ctmp == screen->current && cursor_pos)
3150 cursor_pos->row = dline + HEADER_ROWS(ps);
3152 if((ctmp == screen->current
3153 || ctmp == screen->current->varnamep
3154 || ctmp == screen->current->headingp)
3155 && !(ctmp->flags & CF_NOHILITE))
3156 StartInverse();
3158 if(ctmp->flags & CF_H_LINE){
3159 MoveCursor(dline + HEADER_ROWS(ps), 0);
3160 Write_to_screen(repeat_char(ps->ttyo->screen_cols, '-'));
3163 if(ctmp->flags & CF_CENTERED){
3164 int offset = ps->ttyo->screen_cols/2
3165 - (utf8_width(ctmp->varname)/2);
3166 MoveCursor(dline + HEADER_ROWS(ps),
3167 (offset > 0) ? offset : 0);
3169 else if(ctmp->varoffset)
3170 MoveCursor(dline+HEADER_ROWS(ps), ctmp->varoffset);
3172 Write_to_screen(ctmp->varname);
3173 if((ctmp == screen->current
3174 || ctmp == screen->current->varnamep
3175 || ctmp == screen->current->headingp)
3176 && !(ctmp->flags & CF_NOHILITE))
3177 EndInverse();
3180 value = (ctmp->flags & CF_INHERIT) ? INHERIT : ctmp->value;
3182 if(value){
3183 char *p = NULL;
3184 int i, j;
3186 memset(tmp_20k_buf, '\0',
3187 (6*ps->ttyo->screen_cols + 1) * sizeof(char));
3188 if(ctmp == screen->current){
3189 if(!(ctmp->flags & CF_DOUBLEVAR && ctmp->flags & CF_VAR2))
3190 StartInverse();
3192 if(cursor_pos)
3193 cursor_pos->row = dline + HEADER_ROWS(ps);
3196 if(ctmp->flags & CF_H_LINE)
3197 memset(tmp_20k_buf, '-',
3198 ps->ttyo->screen_cols * sizeof(char));
3200 if(ctmp->flags & CF_CENTERED){
3201 int offset = ps->ttyo->screen_cols/2
3202 - (utf8_width(value)/2);
3203 /* BUG: tabs screw us figuring length above */
3204 if(offset > 0){
3205 char *q;
3207 p = tmp_20k_buf + offset;
3208 if(!*(q = tmp_20k_buf))
3209 while(q < p)
3210 *q++ = ' ';
3213 else
3214 p = tmp_20k_buf;
3217 * Copy the value to a temp buffer expanding tabs, and
3218 * making sure not to write beyond screen right...
3220 for(i = 0, j = ctmp->valoffset; value[i]; i++){
3221 if(value[i] == ctrl('I')){
3223 *p++ = ' ';
3224 while((++j) & 0x07);
3226 else{
3227 *p++ = value[i];
3228 j++;
3232 if(ctmp == screen->current && cursor_pos){
3233 if(ctmp->flags & CF_DOUBLEVAR && ctmp->flags & CF_VAR2)
3234 cursor_pos->col = ctmp->val2offset;
3235 else
3236 cursor_pos->col = ctmp->valoffset;
3238 if(ctmp->tool == radiobutton_tool
3239 #ifdef ENABLE_LDAP
3240 || ctmp->tool==ldap_radiobutton_tool
3241 #endif
3242 || ctmp->tool==role_radiobutton_tool
3243 || ctmp->tool==checkbox_tool
3244 || (ctmp->tool==color_setting_tool &&
3245 ctmp->valoffset != COLOR_INDENT))
3246 cursor_pos->col++;
3249 if(ctmp->flags & CF_DOUBLEVAR){
3250 long l;
3252 p = tmp_20k_buf;
3253 first_width = ctmp->val2offset - ctmp->valoffset - SPACE_BETWEEN_DOUBLEVARS;
3254 if((l=utf8_width(p)) > first_width && first_width >= 0){
3255 saveptr = utf8_count_forw_width(p, first_width, &got_width);
3257 * got_width != first_width indicates there's a problem
3258 * that should not happen. Ignore it.
3260 if(saveptr){
3261 save = *saveptr;
3262 *saveptr = '\0';
3265 else
3266 save = '\0';
3269 * If this is a COLOR_BLOB line we do special coloring.
3270 * The current object inverse hilite is only on the
3271 * checkbox part, the exact format comes from the
3272 * new_color_line function. If we change that we'll have
3273 * to change this to get the coloring right.
3275 if(p[0] == '(' && p[2] == ')' &&
3276 p[3] == ' ' && p[4] == ' ' &&
3277 (!strncmp(p+5, COLOR_BLOB, COLOR_BLOB_LEN)
3278 || !strncmp(p+5, COLOR_BLOB_TRAN, COLOR_BLOB_LEN)
3279 || !strncmp(p+5, COLOR_BLOB_NORM, COLOR_BLOB_LEN))){
3280 COLOR_PAIR *lastc = NULL, *newc = NULL;
3282 MoveCursor(dline+HEADER_ROWS(ps), ctmp->valoffset);
3283 Write_to_screen_n(p, 3);
3284 if(!(ctmp->flags & CF_VAR2) && ctmp == screen->current)
3285 EndInverse();
3287 Write_to_screen_n(p+3, 3);
3288 newc = new_color_pair(colorx(CFC_ICOLOR(ctmp)),
3289 colorx(CFC_ICOLOR(ctmp)));
3290 if(newc){
3291 lastc = pico_get_cur_color();
3292 (void)pico_set_colorp(newc, PSC_NONE);
3293 free_color_pair(&newc);
3296 Write_to_screen_n(p+6, COLOR_BLOB_LEN-2);
3298 if(lastc){
3299 (void)pico_set_colorp(lastc, PSC_NONE);
3300 free_color_pair(&lastc);
3303 Write_to_screen(p+6+COLOR_BLOB_LEN-2);
3305 else{
3306 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset, p);
3307 if(!(ctmp->flags & CF_VAR2) && ctmp == screen->current)
3308 EndInverse();
3311 if(saveptr)
3312 *saveptr = save;
3314 PutLine0(dline+HEADER_ROWS(ps),
3315 ctmp->val2offset - SPACE_BETWEEN_DOUBLEVARS,
3316 repeat_char(SPACE_BETWEEN_DOUBLEVARS, SPACE));
3318 if(l > ctmp->val2offset - ctmp->valoffset && ctmp->val2offset - ctmp->valoffset >= 0)
3319 p = saveptr + SPACE_BETWEEN_DOUBLEVARS;
3321 if(p > tmp_20k_buf){
3322 if(ctmp->flags & CF_VAR2 && ctmp == screen->current)
3323 StartInverse();
3325 if(p[0] == '(' && p[2] == ')' &&
3326 p[3] == ' ' && p[4] == ' ' &&
3327 (!strncmp(p+5, COLOR_BLOB, COLOR_BLOB_LEN)
3328 || !strncmp(p+5, COLOR_BLOB_TRAN, COLOR_BLOB_LEN)
3329 || !strncmp(p+5, COLOR_BLOB_NORM, COLOR_BLOB_LEN))){
3330 COLOR_PAIR *lastc = NULL, *newc = NULL;
3332 MoveCursor(dline+HEADER_ROWS(ps), ctmp->val2offset);
3333 Write_to_screen_n(p, 3);
3334 if(ctmp->flags & CF_VAR2 && ctmp == screen->current)
3335 EndInverse();
3337 Write_to_screen_n(p+3, 3);
3338 newc = new_color_pair(colorx(CFC_ICOLOR(ctmp)),
3339 colorx(CFC_ICOLOR(ctmp)));
3340 if(newc){
3341 lastc = pico_get_cur_color();
3342 (void)pico_set_colorp(newc, PSC_NONE);
3343 free_color_pair(&newc);
3346 Write_to_screen_n(p+6, COLOR_BLOB_LEN-2);
3348 if(lastc){
3349 (void)pico_set_colorp(lastc, PSC_NONE);
3350 free_color_pair(&lastc);
3353 Write_to_screen(p+6+COLOR_BLOB_LEN-2);
3355 else{
3356 PutLine0(dline+HEADER_ROWS(ps),ctmp->val2offset,p);
3357 if(ctmp->flags & CF_VAR2 && ctmp == screen->current)
3358 EndInverse();
3362 else{
3363 char *q, *first_space, *sample, *ptr;
3364 COLOR_PAIR *lastc, *newc;
3365 int invert;
3368 if(ctmp->flags & CF_COLORSAMPLE &&
3369 pico_usingcolor() &&
3370 ((q = strstr(tmp_20k_buf, SAMPLE_LEADER)) ||
3371 (q = strstr(tmp_20k_buf, "Color"))) &&
3372 (first_space = strindex(q, SPACE)) &&
3373 (strstr(value, SAMP1) ||
3374 strstr(value, SAMP2))){
3376 ptr = tmp_20k_buf;
3378 /* write out first part */
3379 *first_space = '\0';
3380 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset,
3381 ptr);
3382 *first_space = SPACE;
3383 ptr = first_space;
3385 if(ctmp == screen->current)
3386 EndInverse();
3388 sample = skip_white_space(ptr);
3389 /* if there's enough room to put some sample up */
3390 save = *sample;
3391 *sample = '\0';
3392 w = utf8_width(tmp_20k_buf);
3393 *sample = save;
3394 if(ctmp->valoffset + w < ps->ttyo->screen_cols){
3396 sample++; /* for `[' at edge of sample */
3398 save = *ptr;
3399 *ptr = '\0';
3400 w = utf8_width(tmp_20k_buf);
3401 *ptr = save;
3403 save = *sample;
3404 *sample = '\0';
3405 /* spaces and bracket before sample1 */
3406 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset+w, ptr);
3407 *sample = save;
3409 ptr = sample;
3411 /* then the color sample */
3412 if(ctmp->var == &ps->vars[V_VIEW_HDR_COLORS]
3413 || ctmp->var == &ps->vars[V_INDEX_TOKEN_COLORS]){
3414 SPEC_COLOR_S *hc, *hcolors;
3416 lastc = newc = NULL;
3418 hcolors =
3419 spec_colors_from_varlist(LVAL(ctmp->var, ew),
3421 for(hc = hcolors, i=0; hc; hc = hc->next, i++)
3422 if(CFC_ICUST(ctmp) == i)
3423 break;
3425 if(hc && hc->fg && hc->fg[0] && hc->bg &&
3426 hc->bg[0])
3427 newc = new_color_pair(hc->fg, hc->bg);
3429 if(newc){
3430 lastc = pico_get_cur_color();
3431 (void)pico_set_colorp(newc, PSC_NONE);
3432 free_color_pair(&newc);
3435 if(hcolors)
3436 free_spec_colors(&hcolors);
3439 /* print out sample1 */
3441 save = *ptr;
3442 *ptr = '\0';
3443 w = utf8_width(tmp_20k_buf);
3444 *ptr = save;
3446 want_width = MIN(utf8_width(SAMP1)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3447 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3448 if(saveptr){
3449 save = *saveptr;
3450 *saveptr = '\0';
3453 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3454 if(saveptr)
3455 *saveptr = save;
3457 ptr = strindex(ptr, ']');
3459 if(lastc){
3460 (void)pico_set_colorp(lastc, PSC_NONE);
3461 free_color_pair(&lastc);
3464 else if(ctmp->var == &ps->vars[V_KW_COLORS]){
3465 KEYWORD_S *kw;
3466 SPEC_COLOR_S *kw_col = NULL;
3468 lastc = newc = NULL;
3470 /* find keyword associated with this line */
3471 for(kw=ps->keywords, i=0; kw; kw=kw->next, i++)
3472 if(CFC_ICUST(ctmp) == i)
3473 break;
3475 if(kw)
3476 kw_col =
3477 spec_colors_from_varlist(LVAL(ctmp->var,ew),
3480 /* color for this keyword */
3481 if(kw && kw_col
3482 && ((kw->nick && kw->nick[0]
3483 && (newc=hdr_color(kw->nick, NULL,
3484 kw_col)))
3486 (kw->kw && kw->kw[0]
3487 && (newc=hdr_color(kw->kw, NULL,
3488 kw_col))))){
3489 lastc = pico_get_cur_color();
3490 (void)pico_set_colorp(newc, PSC_NONE);
3491 free_color_pair(&newc);
3494 if(kw_col)
3495 free_spec_colors(&kw_col);
3497 /* print out sample1 */
3499 save = *ptr;
3500 *ptr = '\0';
3501 w = utf8_width(tmp_20k_buf);
3502 *ptr = save;
3504 want_width = MIN(utf8_width(SAMP1)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3505 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3506 if(saveptr){
3507 save = *saveptr;
3508 *saveptr = '\0';
3511 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3512 if(saveptr)
3513 *saveptr = save;
3515 ptr = strindex(ptr, ']');
3517 if(lastc){
3518 (void)pico_set_colorp(lastc, PSC_NONE);
3519 free_color_pair(&lastc);
3522 else{
3523 lastc = NULL;
3524 invert = 0;
3525 newc = sample_color(ps, ctmp->var);
3526 if(newc){
3527 if((lastc = pico_get_cur_color()) != NULL)
3528 (void)pico_set_colorp(newc, PSC_NONE);
3530 free_color_pair(&newc);
3532 else if(var_defaults_to_rev(ctmp->var)){
3533 if((newc = pico_get_rev_color()) != NULL){
3535 * Note, don't have to free newc.
3537 if((lastc = pico_get_cur_color()) != NULL)
3538 (void)pico_set_colorp(newc, PSC_NONE);
3540 else{
3541 StartInverse();
3542 invert = 1;
3546 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3548 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3549 !(PVAL(ctmp->var,ew) &&
3550 PVAL(ctmp->var+1,ew))))
3551 StartBold();
3553 /* print out sample1 */
3555 save = *ptr;
3556 *ptr = '\0';
3557 w = utf8_width(tmp_20k_buf);
3558 *ptr = save;
3560 want_width = MIN(utf8_width(SAMP1)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3561 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3562 if(saveptr){
3563 save = *saveptr;
3564 *saveptr = '\0';
3567 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3568 if(saveptr)
3569 *saveptr = save;
3571 ptr = strindex(ptr, ']');
3573 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3575 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3576 !(PVAL(ctmp->var,ew) &&
3577 PVAL(ctmp->var+1,ew))))
3578 EndBold();
3580 if(lastc){
3581 (void)pico_set_colorp(lastc, PSC_NONE);
3582 free_color_pair(&lastc);
3584 else if(invert)
3585 EndInverse();
3589 * Finish sample1 with the right bracket.
3591 save = *ptr;
3592 *ptr = '\0';
3593 w = utf8_width(tmp_20k_buf);
3594 *ptr = save;
3595 if(ctmp->valoffset + w < ps->ttyo->screen_cols){
3596 save = *(ptr+1);
3597 *(ptr+1) = '\0';
3598 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3599 *(ptr+1) = save;
3600 ptr++;
3601 w++;
3605 * Now check for an exception sample and paint it.
3607 if(ctmp->valoffset + w + SBS + 1 < ps->ttyo->screen_cols && (q = strstr(ptr, SAMPEXC))){
3608 /* spaces + `[' */
3609 save = ptr[SBS+1];
3610 ptr[SBS+1] = '\0';
3611 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3612 ptr[SBS+1] = save;
3613 ptr += (SBS+1);
3616 * Figure out what color to paint it.
3617 * This only happens with normal variables,
3618 * not with V_VIEW_HDR_COLORS.
3620 lastc = NULL;
3621 invert = 0;
3622 newc = sampleexc_color(ps, ctmp->var);
3623 if(newc){
3624 if((lastc = pico_get_cur_color()) != NULL)
3625 (void)pico_set_colorp(newc, PSC_NONE);
3627 free_color_pair(&newc);
3629 else if(var_defaults_to_rev(ctmp->var)){
3630 if((newc = pico_get_rev_color()) != NULL){
3632 * Note, don't have to free newc.
3634 if((lastc = pico_get_cur_color()) != NULL)
3635 (void)pico_set_colorp(newc, PSC_NONE);
3637 else{
3638 StartInverse();
3639 invert = 1;
3643 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3645 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3646 !(PVAL(ctmp->var,Post) &&
3647 PVAL(ctmp->var+1,Post))))
3648 StartBold();
3650 /* sample2 */
3651 save = *ptr;
3652 *ptr = '\0';
3653 w = utf8_width(tmp_20k_buf);
3654 *ptr = save;
3656 want_width = MIN(utf8_width(SAMPEXC)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3657 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3658 if(saveptr){
3659 save = *saveptr;
3660 *saveptr = '\0';
3663 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3664 if(saveptr)
3665 *saveptr = save;
3667 ptr = strindex(ptr, ']');
3669 /* turn off bold and color */
3670 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3672 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3673 !(PVAL(ctmp->var,Post) &&
3674 PVAL(ctmp->var+1,Post))))
3675 EndBold();
3677 if(lastc){
3678 (void)pico_set_colorp(lastc, PSC_NONE);
3679 free_color_pair(&lastc);
3681 else if(invert)
3682 EndInverse();
3685 * Finish sample2 with the right bracket.
3687 save = *ptr;
3688 *ptr = '\0';
3689 w = utf8_width(tmp_20k_buf);
3690 *ptr = save;
3691 if(ctmp->valoffset + w < ps->ttyo->screen_cols){
3692 save = *(ptr+1);
3693 *(ptr+1) = '\0';
3694 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3695 *(ptr+1) = save;
3696 ptr++;
3697 w++;
3701 /* paint rest of the line if there is any left */
3702 if(ctmp->valoffset + w < ps->ttyo->screen_cols && *ptr){
3703 want_width = ps->ttyo->screen_cols - w - ctmp->valoffset;
3704 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3705 if(saveptr){
3706 save = *saveptr;
3707 *saveptr = '\0';
3710 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3711 if(saveptr)
3712 *saveptr = save;
3716 else{
3717 w = utf8_width(tmp_20k_buf);
3718 want_width = ps->ttyo->screen_cols - ctmp->valoffset;
3719 if(w > want_width){
3720 saveptr = utf8_count_forw_width(tmp_20k_buf, want_width, &got_width);
3721 if(saveptr)
3722 *saveptr = '\0';
3725 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset, tmp_20k_buf);
3726 if(ctmp == screen->current)
3727 EndInverse();
3734 ps->mangled_body = 0;
3735 screen->top_line = top_line;
3736 screen->prev = screen->current;
3737 #ifdef _WINDOWS
3738 mswin_endupdate();
3739 #endif
3747 void
3748 print_option_screen(OPT_SCREEN_S *screen, char *prompt)
3750 CONF_S *ctmp;
3751 int so_far;
3752 char line[500];
3754 if(open_printer(prompt) == 0){
3755 for(ctmp = first_confline(screen->current);
3756 ctmp;
3757 ctmp = next_confline(ctmp)){
3759 so_far = 0;
3760 if(ctmp->varname && !(ctmp->flags & CF_INVISIBLEVAR)){
3762 snprintf(line, sizeof(line), "%*s%s", ctmp->varoffset, "",
3763 ctmp->varname);
3764 line[sizeof(line)-1] = '\0';
3765 print_text(line);
3766 so_far = ctmp->varoffset + utf8_width(ctmp->varname);
3769 if(ctmp && ctmp->value){
3770 char *p = tmp_20k_buf;
3771 int i, j, spaces;
3773 /* Copy the value to a temp buffer expanding tabs. */
3774 for(i = 0, j = ctmp->valoffset; ctmp->value[i]; i++){
3775 if(ctmp->value[i] == ctrl('I')){
3777 *p++ = ' ';
3778 while((++j) & 0x07);
3781 else{
3782 *p++ = ctmp->value[i];
3783 j++;
3787 *p = '\0';
3788 removing_trailing_white_space(tmp_20k_buf);
3790 spaces = MAX(ctmp->valoffset - so_far, 0);
3791 snprintf(line, sizeof(line), "%*s%s\n", spaces, "", tmp_20k_buf);
3792 line[sizeof(line)-1] = '\0';
3793 print_text(line);
3797 close_printer();
3806 void
3807 option_screen_redrawer(void)
3809 ps_global->mangled_body = 1;
3810 update_option_screen(ps_global, opt_screen, (Pos *)NULL);
3816 * pretty_value - given the line, return an
3817 * alloc'd string for line's value...
3819 char *
3820 pretty_value(struct pine *ps, CONF_S *cl)
3822 struct variable *v;
3824 v = cl->var;
3826 if(v == &ps->vars[V_FEATURE_LIST])
3827 return(checkbox_pretty_value(ps, cl));
3828 else if(standard_radio_var(ps, v) || v == startup_ptr)
3829 return(radio_pretty_value(ps, cl));
3830 else if(v == &ps->vars[V_SORT_KEY])
3831 return(sort_pretty_value(ps, cl));
3832 else if(v == &ps->vars[V_SIGNATURE_FILE])
3833 return(sigfile_pretty_value(ps, cl));
3834 else if(v == &ps->vars[V_USE_ONLY_DOMAIN_NAME])
3835 return(yesno_pretty_value(ps, cl));
3836 else if(color_holding_var(ps, v))
3837 return(color_pretty_value(ps, cl));
3838 else
3839 return(text_pretty_value(ps, cl));
3843 char *
3844 text_pretty_value(struct pine *ps, CONF_S *cl)
3846 char tmp[6*MAX_SCREEN_COLS+20], *pvalnorm, **lvalnorm, *pvalexc, **lvalexc = NULL;
3847 char *p, *pval = NULL, **lval = NULL, lastchar = '\0';
3848 int editing_except, fixed, uvalset, uvalposlen;
3849 unsigned got_width;
3850 int comments, except_set, avail_width;
3851 int norm_with_except = 0, norm_with_except_inherit = 0;
3852 int inherit_line = 0;
3854 editing_except = (ew == ps_global->ew_for_except_vars);
3855 fixed = cl->var->is_fixed;
3856 if((ps_global->ew_for_except_vars != Main) && (ew == Main))
3857 norm_with_except++; /* editing normal and except config exists */
3859 if(cl->var->is_list){
3860 lvalnorm = LVAL(cl->var, Main);
3861 lvalexc = LVAL(cl->var, ps_global->ew_for_except_vars);
3862 if(editing_except){
3863 uvalset = lvalexc != NULL;
3864 uvalposlen = uvalset && lvalexc[0] && lvalexc[0][0];
3865 lval = lvalexc;
3867 else{
3868 uvalset = lvalnorm != NULL;
3869 uvalposlen = uvalset && lvalnorm[0] && lvalnorm[0][0];
3870 lval = lvalnorm;
3873 except_set = lvalexc != NULL;
3874 comments = cl->var->current_val.l != NULL;
3875 if(norm_with_except && except_set && lvalexc[0] &&
3876 !strcmp(lvalexc[0],INHERIT))
3877 norm_with_except_inherit++;
3879 if(uvalset && !strcmp(lval[0], INHERIT)){
3880 if(cl->varmem == 0){
3881 inherit_line++;
3882 comments = 0;
3886 /* only add extra comments on last member of list */
3887 if(uvalset && !inherit_line && lval && lval[cl->varmem] &&
3888 lval[cl->varmem + 1])
3889 comments = 0;
3891 else{
3892 pvalnorm = PVAL(cl->var, Main);
3893 pvalexc = PVAL(cl->var, ps_global->ew_for_except_vars);
3894 if(editing_except){
3895 uvalset = pvalexc != NULL;
3896 uvalposlen = uvalset && *pvalexc;
3897 pval = pvalexc;
3899 else{
3900 uvalset = pvalnorm != NULL;
3901 uvalposlen = uvalset && *pvalnorm;
3902 pval = pvalnorm;
3905 except_set = pvalexc != NULL;
3906 comments = cl->var->current_val.p != NULL;
3909 memset(tmp, 0, sizeof(tmp));
3910 p = tmp;
3911 *p = '\0';
3913 avail_width = ps->ttyo->screen_cols - cl->valoffset;
3915 if(fixed || !uvalset || !uvalposlen){
3916 p += utf8_to_width(p, "<", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3917 avail_width -= got_width;
3920 if(fixed){
3921 p += utf8_to_width(p, _(fixed_val), sizeof(tmp)-(p-tmp), avail_width, &got_width);
3922 avail_width -= got_width;
3924 else if(!uvalset){
3925 p += utf8_to_width(p, _(no_val), sizeof(tmp)-(p-tmp), avail_width, &got_width);
3926 avail_width -= got_width;
3928 else if(!uvalposlen){
3929 p += utf8_to_width(p, _(empty_val), sizeof(tmp)-(p-tmp), avail_width, &got_width);
3930 avail_width -= got_width;
3932 else if(inherit_line){
3933 p += utf8_to_width(p, INHERIT, sizeof(tmp)-(p-tmp), avail_width, &got_width);
3934 avail_width -= got_width;
3936 else{
3937 if(cl->var->is_list){
3938 p += utf8_to_width(p, lval[cl->varmem], sizeof(tmp)-(p-tmp), avail_width, &got_width);
3939 avail_width -= got_width;
3941 else{
3942 p += utf8_to_width(p, pval, sizeof(tmp)-(p-tmp), avail_width, &got_width);
3943 avail_width -= got_width;
3947 if(comments && (fixed || !uvalset || (norm_with_except && except_set))){
3948 if(fixed || !uvalset){
3949 p += utf8_to_width(p, ": using ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3950 avail_width -= got_width;
3953 if(norm_with_except && except_set){
3954 if(!uvalset){
3955 p += utf8_to_width(p, "exception ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3956 avail_width -= got_width;
3958 else if(!fixed){
3959 if(!uvalposlen){
3960 p += utf8_to_width(p, ": ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3961 avail_width -= got_width;
3963 else{
3964 p += utf8_to_width(p, " (", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3965 avail_width -= got_width;
3968 if(norm_with_except_inherit){
3969 p += utf8_to_width(p, "added to by exception ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3970 avail_width -= got_width;
3972 else{
3973 p += utf8_to_width(p, "overridden by exception ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3974 avail_width -= got_width;
3979 if(avail_width >= 7){
3980 if(cl->var == &ps_global->vars[V_POST_CHAR_SET]){
3981 p += utf8_to_width(p, "most specific (see help)", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3982 avail_width -= got_width;
3984 else{
3985 sstrncpy(&p, "\"", sizeof(tmp)-(p-tmp));
3986 avail_width--;
3987 if(cl->var->is_list){
3988 char **the_list;
3990 the_list = cl->var->current_val.l;
3992 if(norm_with_except && except_set)
3993 the_list = lvalexc;
3995 if(the_list && the_list[0] && !strcmp(the_list[0], INHERIT))
3996 the_list++;
3998 for(lval = the_list; avail_width-(p-tmp) > 0 && *lval; lval++){
3999 if(lval != the_list){
4000 p += utf8_to_width(p, ",", sizeof(tmp)-(p-tmp), avail_width, &got_width);
4001 avail_width -= got_width;
4004 p += utf8_to_width(p, *lval, sizeof(tmp)-(p-tmp), avail_width, &got_width);
4005 avail_width -= got_width;
4008 else{
4009 p += utf8_to_width(p, cl->var->current_val.p, sizeof(tmp)-(p-tmp), avail_width, &got_width);
4010 avail_width -= got_width;
4013 if(p-tmp+2 < sizeof(tmp)){
4014 *p++ = '\"';
4015 *p = '\0';
4019 else if(*(p-1) == SPACE)
4020 *--p = '\0';
4023 tmp[sizeof(tmp)-1] = '\0';
4025 if(fixed || !uvalset || !uvalposlen)
4026 lastchar = '>';
4027 else if(comments && norm_with_except && except_set)
4028 lastchar = ')';
4030 if(lastchar){
4031 if(p-tmp+2 < sizeof(tmp)){
4032 *p++ = lastchar;
4033 *p = '\0';
4037 tmp[sizeof(tmp)-1] = '\0';
4038 avail_width = ps->ttyo->screen_cols - cl->valoffset;
4040 if(utf8_width(tmp) < avail_width)
4041 snprintf(tmp+strlen(tmp), sizeof(tmp)-strlen(tmp), "%*s", avail_width-utf8_width(tmp), "");
4043 tmp[sizeof(tmp)-1] = '\0';
4045 return(cpystr(tmp));
4049 char *
4050 checkbox_pretty_value(struct pine *ps, CONF_S *cl)
4052 char tmp[6*MAXPATH];
4053 char *comment = NULL;
4054 int indent, x, screen_width, need;
4055 int longest_featname, longest_comment;
4056 int nwidcomm; /* name width with comment */
4057 int nwidnocomm; /* and without comment */
4058 FEATURE_S *feature;
4060 screen_width = (ps && ps->ttyo) ? ps->ttyo->screen_cols : 80;
4061 tmp[0] = '\0';
4063 longest_featname = longest_feature_name();
4064 longest_comment = longest_feature_comment(ps, ew);
4065 indent = feature_indent();
4067 nwidcomm = longest_featname;
4068 nwidnocomm = longest_featname + 2 + longest_comment;
4070 if((need = (indent + 5 + longest_featname + 2 + longest_comment) - screen_width) > 0){
4071 if(need < 10){
4072 nwidcomm -= need;
4073 nwidnocomm -= need;
4075 else{
4076 longest_comment = 0;
4077 nwidnocomm = longest_featname;
4081 feature = feature_list(cl->varmem);
4083 x = feature_gets_an_x(ps, cl->var, feature, &comment, ew);
4085 if(longest_comment && comment && *comment){
4086 utf8_snprintf(tmp, sizeof(tmp), "[%c] %-*.*w %-*.*w", x ? 'X' : ' ',
4087 nwidcomm, nwidcomm,
4088 pretty_feature_name(feature->name, nwidcomm),
4089 longest_comment, longest_comment, comment ? comment : "");
4091 else{
4092 utf8_snprintf(tmp, sizeof(tmp), "[%c] %-*.*w", x ? 'X' : ' ',
4093 nwidnocomm, nwidnocomm,
4094 pretty_feature_name(feature->name, nwidnocomm));
4097 return(cpystr(tmp));
4102 longest_feature_name(void)
4104 static int lv = -1;
4105 int i, j;
4106 FEATURE_S *feature;
4108 if(lv < 0){
4109 for(lv = 0, i = 0; (feature = feature_list(i)); i++)
4110 if(feature_list_section(feature)
4111 && lv < (j = utf8_width(pretty_feature_name(feature->name, -1))))
4112 lv = j;
4114 lv = MIN(lv, 100);
4117 return(lv);
4122 feature_indent(void)
4124 return(6);
4128 char *
4129 yesno_pretty_value(struct pine *ps, CONF_S *cl)
4131 char tmp[6*MAXPATH], *pvalnorm, *pvalexc;
4132 char *p, *pval, lastchar = '\0';
4133 int editing_except, fixed, norm_with_except, uvalset;
4134 int curval, except_set;
4136 editing_except = (ew == ps_global->ew_for_except_vars);
4137 fixed = cl->var->is_fixed;
4138 if((ps_global->ew_for_except_vars == Main) ||
4139 (ew == ps_global->ew_for_except_vars))
4140 norm_with_except = 0;
4141 else
4142 norm_with_except = 1; /* editing normal and except config exists */
4144 pvalnorm = PVAL(cl->var, Main);
4145 pvalexc = PVAL(cl->var, ps_global->ew_for_except_vars);
4146 if(editing_except){
4147 uvalset = (pvalexc != NULL &&
4148 (!strucmp(pvalexc,yesstr) || !strucmp(pvalexc,nostr)));
4149 pval = pvalexc;
4151 else{
4152 uvalset = (pvalnorm != NULL &&
4153 (!strucmp(pvalnorm,yesstr) || !strucmp(pvalnorm,nostr)));
4154 pval = pvalnorm;
4157 except_set = (pvalexc != NULL &&
4158 (!strucmp(pvalexc,yesstr) || !strucmp(pvalexc,nostr)));
4159 curval = (cl->var->current_val.p != NULL &&
4160 (!strucmp(cl->var->current_val.p,yesstr) ||
4161 !strucmp(cl->var->current_val.p,nostr)));
4163 p = tmp;
4164 *p = '\0';
4166 if(fixed || !uvalset)
4167 sstrncpy(&p, "<", sizeof(tmp)-(p-tmp));
4169 if(fixed)
4170 sstrncpy(&p, _(fixed_val), sizeof(tmp)-(p-tmp));
4171 else if(!uvalset)
4172 sstrncpy(&p, _(no_val), sizeof(tmp)-(p-tmp));
4173 else if(!strucmp(pval, yesstr))
4174 sstrncpy(&p, yesstr, sizeof(tmp)-(p-tmp));
4175 else
4176 sstrncpy(&p, nostr, sizeof(tmp)-(p-tmp));
4178 if(curval && (fixed || !uvalset || (norm_with_except && except_set))){
4179 if(fixed || !uvalset)
4180 sstrncpy(&p, ": using ", sizeof(tmp)-(p-tmp));
4182 if(norm_with_except && except_set){
4183 if(!uvalset)
4184 sstrncpy(&p, "exception ", sizeof(tmp)-(p-tmp));
4185 else if(!fixed){
4186 sstrncpy(&p, " (", sizeof(tmp)-(p-tmp));
4187 sstrncpy(&p, "overridden by exception ", sizeof(tmp)-(p-tmp));
4191 sstrncpy(&p, "\"", sizeof(tmp)-(p-tmp));
4192 sstrncpy(&p, !strucmp(cl->var->current_val.p,yesstr) ? yesstr : nostr, sizeof(tmp)-(p-tmp));
4193 sstrncpy(&p, "\"", sizeof(tmp)-(p-tmp));
4196 if(fixed || !uvalset)
4197 lastchar = '>';
4198 else if(curval && norm_with_except && except_set)
4199 lastchar = ')';
4201 if(lastchar && sizeof(tmp)-(p-tmp) > 1){
4202 *p++ = lastchar;
4203 *p = '\0';
4206 tmp[sizeof(tmp)-1] = '\0';
4208 if(utf8_width(tmp) < ps->ttyo->screen_cols - cl->valoffset)
4209 snprintf(tmp+strlen(tmp), sizeof(tmp)-strlen(tmp),
4210 "%*s", ps->ttyo->screen_cols - cl->valoffset - utf8_width(tmp), "");
4212 tmp[sizeof(tmp)-1] = '\0';
4214 return(cpystr(tmp));
4218 char *
4219 radio_pretty_value(struct pine *ps, CONF_S *cl)
4221 char tmp[6*MAXPATH];
4222 char *pvalnorm, *pvalexc, *pval;
4223 int editing_except_which_isnt_normal, editing_normal_which_isnt_except;
4224 int fixed, is_set_for_this_level = 0, is_the_one, the_exc_one;
4225 int i, j, lv = 0;
4226 NAMEVAL_S *rule = NULL, *f;
4227 PTR_TO_RULEFUNC rulefunc;
4228 struct variable *v;
4230 tmp[0] = '\0';
4231 v = cl->var;
4233 editing_except_which_isnt_normal = (ew == ps_global->ew_for_except_vars &&
4234 ew != Main);
4235 editing_normal_which_isnt_except = (ew == Main &&
4236 ew != ps_global->ew_for_except_vars);
4237 fixed = cl->var->is_fixed;
4238 pvalnorm = PVAL(v, Main);
4239 pvalexc = PVAL(v, ps_global->ew_for_except_vars);
4241 rulefunc = rulefunc_from_var(ps, v);
4242 rule = rulefunc ? (*rulefunc)(cl->varmem) : NULL;
4244 /* find longest name */
4245 if(rulefunc)
4246 for(lv = 0, i = 0; (f = (*rulefunc)(i)); i++)
4247 if(lv < (j = utf8_width(f->name)))
4248 lv = j;
4250 lv = MIN(lv, 100);
4252 if(editing_except_which_isnt_normal)
4253 pval = pvalexc;
4254 else
4255 pval = pvalnorm;
4257 if(pval)
4258 is_set_for_this_level++;
4260 if(fixed){
4261 pval = v->fixed_val.p;
4262 is_the_one = (pval && !strucmp(pval, S_OR_L(rule)));
4264 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4265 is_the_one ? R_SELD : ' ',
4266 lv, lv, rule->name, is_the_one ? " (value is fixed)" : "");
4268 else if(is_set_for_this_level){
4269 is_the_one = (pval && !strucmp(pval, S_OR_L(rule)));
4270 the_exc_one = (editing_normal_which_isnt_except && pvalexc &&
4271 !strucmp(pvalexc, S_OR_L(rule)));
4272 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4273 is_the_one ? R_SELD : ' ',
4274 lv, lv, rule->name,
4275 (!is_the_one && the_exc_one) ? " (value set in exceptions)" :
4276 (is_the_one && the_exc_one) ? " (also set in exceptions)" :
4277 (is_the_one &&
4278 editing_normal_which_isnt_except &&
4279 pvalexc &&
4280 !the_exc_one) ? " (overridden by exceptions)" :
4281 "");
4283 else{
4284 if(pvalexc){
4285 is_the_one = !strucmp(pvalexc, S_OR_L(rule));
4286 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4287 is_the_one ? R_SELD : ' ',
4288 lv, lv, rule->name,
4289 is_the_one ? " (value set in exceptions)" : "");
4291 else{
4292 pval = v->current_val.p;
4293 is_the_one = (pval && !strucmp(pval, S_OR_L(rule)));
4294 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4295 is_the_one ? R_SELD : ' ',
4296 lv, lv, rule->name,
4297 is_the_one ? ((editing_except_which_isnt_normal && pvalnorm) ? " (default from regular config)" : " (default)") : "");
4301 tmp[sizeof(tmp)-1] = '\0';
4303 return(cpystr(tmp));
4307 char *
4308 sigfile_pretty_value(struct pine *ps, CONF_S *cl)
4310 if(cl && cl->var == &ps->vars[V_SIGNATURE_FILE] &&
4311 cl->prev && cl->prev->var == &ps->vars[V_LITERAL_SIG]){
4312 if(cl->prev->var->current_val.p){
4313 cl->flags |= CF_NOSELECT; /* side effect */
4314 return(cpystr(_("<Ignored: using Literal-Signature instead>")));
4316 else{
4317 cl->flags &= ~CF_NOSELECT;
4318 return(text_pretty_value(ps, cl));
4321 else
4322 return(cpystr(""));
4326 char *
4327 color_pretty_value(struct pine *ps, CONF_S *cl)
4329 char tmp[6*MAXPATH];
4330 char *p, *q;
4331 struct variable *v;
4332 int is_index;
4334 tmp[0] = '\0';
4335 v = cl->var;
4337 if(v && color_holding_var(ps, v) &&
4338 (p=srchstr(v->name, "-foreground-color"))){
4340 is_index = !struncmp(v->name, "index-", 6);
4342 q = sampleexc_text(ps, v);
4343 utf8_snprintf(tmp, sizeof(tmp), "%c%.*s %sColor%*.50s %.20w%*s%.20w%.20w",
4344 islower((unsigned char)v->name[0])
4345 ? toupper((unsigned char)v->name[0])
4346 : v->name[0],
4347 MIN(p-v->name-1,30), v->name+1,
4348 is_index ? "Symbol " : "",
4349 MAX(EQ_COL - COLOR_INDENT -1 - MIN(p-v->name-1,30)
4350 - 6 - (is_index ? 7 : 0) - 1,0), "",
4351 sample_text(ps,v), *q ? SBS : 0, "", q,
4352 color_parenthetical(v));
4355 tmp[sizeof(tmp)-1] = '\0';
4357 return(cpystr(tmp));
4361 char *
4362 sort_pretty_value(struct pine *ps, CONF_S *cl)
4364 return(generalized_sort_pretty_value(ps, cl, 1));
4368 char *
4369 generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok)
4371 char tmp[6*MAXPATH];
4372 char *pvalnorm, *pvalexc, *pval;
4373 int editing_except_which_isnt_normal, editing_normal_which_isnt_except;
4374 int fixed, is_set_for_this_level = 0, is_the_one, the_exc_one;
4375 int i, j, lv = 0;
4376 struct variable *v;
4377 SortOrder line_sort, var_sort, exc_sort;
4378 int line_sort_rev, var_sort_rev, exc_sort_rev;
4380 tmp[0] = '\0';
4381 v = cl->var;
4383 editing_except_which_isnt_normal = (ew == ps_global->ew_for_except_vars &&
4384 ew != Main);
4385 editing_normal_which_isnt_except = (ew == Main &&
4386 ew != ps_global->ew_for_except_vars);
4387 fixed = cl->var->is_fixed;
4388 pvalnorm = PVAL(v, Main);
4389 pvalexc = PVAL(v, ps_global->ew_for_except_vars);
4391 /* find longest value's name */
4392 for(lv = 0, i = 0; ps->sort_types[i] != EndofList; i++)
4393 if(lv < (j = utf8_width(sort_name(ps->sort_types[i]))))
4394 lv = j;
4396 lv = MIN(lv, 100);
4398 if(editing_except_which_isnt_normal)
4399 pval = pvalexc;
4400 else
4401 pval = pvalnorm;
4403 if(pval)
4404 is_set_for_this_level++;
4406 /* the config line we're talking about */
4407 if(cl->varmem >= 0){
4408 line_sort_rev = cl->varmem >= (short)EndofList;
4409 line_sort = (SortOrder)(cl->varmem - (line_sort_rev * EndofList));
4412 if(cl->varmem < 0){
4413 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*w",
4414 (pval == NULL) ? R_SELD : ' ',
4415 lv, "Default");
4417 else if(fixed){
4418 pval = v->fixed_val.p;
4419 decode_sort(pval, &var_sort, &var_sort_rev);
4420 is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
4422 utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s",
4423 is_the_one ? R_SELD : ' ',
4424 line_sort_rev ? "Reverse " : "",
4425 lv, sort_name(line_sort),
4426 line_sort_rev ? 0 : 8, "",
4427 is_the_one ? " (value is fixed)" : "");
4429 else if(is_set_for_this_level){
4430 decode_sort(pval, &var_sort, &var_sort_rev);
4431 is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
4432 decode_sort(pvalexc, &exc_sort, &exc_sort_rev);
4433 the_exc_one = (editing_normal_which_isnt_except && pvalexc &&
4434 exc_sort_rev == line_sort_rev && exc_sort == line_sort);
4435 utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s",
4436 is_the_one ? R_SELD : ' ',
4437 line_sort_rev ? "Reverse " : "",
4438 lv, sort_name(line_sort),
4439 line_sort_rev ? 0 : 8, "",
4440 (!is_the_one && the_exc_one) ? " (value set in exceptions)" :
4441 (is_the_one && the_exc_one) ? " (also set in exceptions)" :
4442 (is_the_one &&
4443 editing_normal_which_isnt_except &&
4444 pvalexc &&
4445 !the_exc_one) ? " (overridden by exceptions)" :
4446 "");
4448 else{
4449 if(pvalexc){
4450 decode_sort(pvalexc, &exc_sort, &exc_sort_rev);
4451 is_the_one = (exc_sort_rev == line_sort_rev &&
4452 exc_sort == line_sort);
4453 utf8_snprintf(tmp, sizeof(tmp), "( ) %s%-*w%*s%s",
4454 line_sort_rev ? "Reverse " : "",
4455 lv, sort_name(line_sort),
4456 line_sort_rev ? 0 : 8, "",
4457 is_the_one ? " (value set in exceptions)" : "");
4459 else{
4460 pval = v->current_val.p;
4461 decode_sort(pval, &var_sort, &var_sort_rev);
4462 is_the_one = ((pval || default_ok) &&
4463 var_sort_rev == line_sort_rev &&
4464 var_sort == line_sort);
4465 utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s",
4466 is_the_one ? R_SELD : ' ',
4467 line_sort_rev ? "Reverse " : "",
4468 lv, sort_name(line_sort),
4469 line_sort_rev ? 0 : 8, "",
4470 is_the_one ? ((editing_except_which_isnt_normal && pvalnorm) ? " (default from regular config)" : " (default)") : "");
4474 return(cpystr(tmp));
4478 COLOR_PAIR *
4479 sample_color(struct pine *ps, struct variable *v)
4481 COLOR_PAIR *cp = NULL;
4482 char *pvalefg, *pvalebg;
4483 char *pvalmfg, *pvalmbg;
4485 pvalefg = PVAL(v, ew);
4486 pvalebg = PVAL(v+1, ew);
4487 pvalmfg = PVAL(v, Main);
4488 pvalmbg = PVAL(v+1, Main);
4489 if(v && color_holding_var(ps, v) &&
4490 srchstr(v->name, "-foreground-color")){
4491 if(pvalefg && pvalefg[0] && pvalebg && pvalebg[0])
4492 cp = new_color_pair(pvalefg, pvalebg);
4493 else if(ew == Post && pvalmfg && pvalmfg[0] && pvalmbg && pvalmbg[0])
4494 cp = new_color_pair(pvalmfg, pvalmbg);
4495 else if(v->global_val.p && v->global_val.p[0] &&
4496 (v+1)->global_val.p && (v+1)->global_val.p[0])
4497 cp = new_color_pair(v->global_val.p, (v+1)->global_val.p);
4500 return(cp);
4504 COLOR_PAIR *
4505 sampleexc_color(struct pine *ps, struct variable *v)
4507 COLOR_PAIR *cp = NULL;
4508 char *pvalfg, *pvalbg;
4510 pvalfg = PVAL(v, Post);
4511 pvalbg = PVAL(v+1, Post);
4512 if(v && color_holding_var(ps, v) &&
4513 srchstr(v->name, "-foreground-color") &&
4514 pvalfg && pvalfg[0] && pvalbg && pvalbg[0])
4515 cp = new_color_pair(pvalfg, pvalbg);
4517 return(cp);
4521 void
4522 clear_feature(char ***l, char *f)
4524 char **list = l ? *l : NULL;
4525 int count = 0;
4527 for(; list && *list; list++, count++){
4528 if(f && !strucmp(((!struncmp(*list,"no-",3)) ? *list + 3 : *list), f)){
4529 fs_give((void **)list);
4530 f = NULL;
4533 if(!f) /* shift */
4534 *list = *(list + 1);
4538 * this is helpful to keep the array from growing if a feature
4539 * gets set and unset repeatedly
4541 if(!f)
4542 fs_resize((void **)l, count * sizeof(char *));
4549 void
4550 toggle_feature_bit(struct pine *ps, int index, struct variable *var, CONF_S *cl, int just_flip_value)
4552 FEATURE_S *f;
4553 int og, on_before;
4554 char *p, **vp;
4556 f = feature_list(index);
4558 og = test_old_growth_bits(ps, f->id);
4561 * if this feature is in the fixed set, or old-growth is in the fixed
4562 * set and this feature is in the old-growth set, don't alter it...
4564 for(vp = var->fixed_val.l; vp && *vp; vp++){
4565 p = (struncmp(*vp, "no-", 3)) ? *vp : *vp + 3;
4566 if(!strucmp(p, f->name) || (og && !strucmp(p, "old-growth"))){
4567 q_status_message(SM_ORDER, 3, 3,
4568 _("Can't change value fixed by sys-admin."));
4569 return;
4573 on_before = F_ON(f->id, ps);
4575 toggle_feature(ps, var, f, just_flip_value, ew);
4578 * Handle any alpine-specific features that need attention here. Features
4579 * that aren't alpine-specific should be handled in toggle_feature instead.
4581 if(on_before != F_ON(f->id, ps))
4582 switch(f->id){
4583 case F_CMBND_ABOOK_DISP :
4584 addrbook_reset();
4585 break;
4587 case F_PRESERVE_START_STOP :
4588 /* toggle raw mode settings to make tty driver aware of new setting */
4589 PineRaw(0);
4590 PineRaw(1);
4591 break;
4593 case F_USE_FK :
4594 ps->orig_use_fkeys = F_ON(F_USE_FK, ps);
4595 ps->mangled_footer = 1;
4596 mark_keymenu_dirty();
4597 break;
4599 case F_SHOW_SORT :
4600 ps->mangled_header = 1;
4601 break;
4603 case F_BLANK_KEYMENU :
4604 if(F_ON(f->id, ps)){
4605 FOOTER_ROWS(ps) = 1;
4606 ps->mangled_body = 1;
4608 else{
4609 FOOTER_ROWS(ps) = 3;
4610 ps->mangled_footer = 1;
4613 clearfooter(ps);
4614 break;
4616 case F_ENABLE_INCOMING :
4617 q_status_message(SM_ORDER | SM_DING, 3, 4,
4618 "Folder List changes will take effect your next Alpine session.");
4619 break;
4621 #ifdef _WINDOWS
4622 case F_SHOW_CURSOR :
4623 mswin_showcaret(F_ON(f->id,ps));
4624 break;
4626 case F_ENABLE_TRAYICON :
4627 mswin_trayicon(F_ON(f->id,ps));
4628 break;
4629 #endif
4631 #if !defined(DOS) && !defined(OS2)
4632 case F_ALLOW_TALK :
4633 if(F_ON(f->id, ps))
4634 allow_talk(ps);
4635 else
4636 disallow_talk(ps);
4638 break;
4639 #endif
4641 case F_PASS_CONTROL_CHARS :
4642 ps->pass_ctrl_chars = F_ON(F_PASS_CONTROL_CHARS,ps_global) ? 1 : 0;
4643 break;
4645 #ifdef SMIME
4646 case F_USE_CERT_STORE_ONLY:
4647 if(F_OFF(F_USE_CERT_STORE_ONLY, ps))
4648 q_status_message(SM_ORDER | SM_DING, 3, 4,
4649 "Disabling this feature should only be done for testing. Press \"?\" for help");
4650 break;
4651 #endif /* SMIME */
4653 case F_PASS_C1_CONTROL_CHARS :
4654 ps->pass_c1_ctrl_chars = F_ON(F_PASS_C1_CONTROL_CHARS,ps_global) ? 1 : 0;
4655 break;
4657 #ifdef MOUSE
4658 case F_ENABLE_MOUSE :
4659 if(F_ON(f->id, ps)){
4660 init_mouse();
4661 if(!mouseexist())
4662 q_status_message(SM_ORDER | SM_DING, 3, 4,
4663 "Mouse tracking still off ($DISPLAY variable set?)");
4665 else
4666 end_mouse();
4668 break;
4669 #endif
4672 if(just_flip_value){
4673 if(cl->value && cl->value[0])
4674 cl->value[1] = (cl->value[1] == ' ') ? 'X' : ' ';
4676 else{
4678 * This fork is only called from the checkbox_tool, which has
4679 * varmem set to index correctly and cl->var set correctly.
4681 if(cl->value)
4682 fs_give((void **)&cl->value);
4684 cl->value = pretty_value(ps, cl);
4690 * new_confline - create new CONF_S zero it out, and insert it after current.
4691 * NOTE current gets set to the new CONF_S too!
4693 CONF_S *
4694 new_confline(CONF_S **current)
4696 CONF_S *p;
4698 p = (CONF_S *)fs_get(sizeof(CONF_S));
4699 memset((void *)p, 0, sizeof(CONF_S));
4700 if(current){
4701 if(*current){
4702 p->next = (*current)->next;
4703 (*current)->next = p;
4704 p->prev = *current;
4705 if(p->next)
4706 p->next->prev = p;
4709 *current = p;
4712 return(p);
4719 void
4720 snip_confline(CONF_S **p)
4722 CONF_S *q;
4725 * Be careful. We need this line because the
4726 * q->prev->next = ...
4727 * may change q itself if &q == &q->prev->next.
4728 * Then the use of q in the next line is wrong.
4729 * That's what happens if we pass in the address of
4730 * some ->next and use *p directly instead of q.
4732 q = *p;
4734 if(q){
4735 /* Yank it from the linked list */
4736 if(q->prev)
4737 q->prev->next = q->next;
4739 if(q->next)
4740 q->next->prev = q->prev;
4742 /* Then free up it's memory */
4743 q->prev = q->next = NULL;
4744 free_conflines(&q);
4748 int
4749 get_confline_number(CONF_S *conf)
4751 int pos;
4752 CONF_S *p;
4754 for (p = first_confline(conf), pos = 0; p != conf; p = next_confline(p), pos++);
4756 return pos;
4760 CONF_S *
4761 set_confline_number(CONF_S *conf, int pos)
4763 CONF_S *p;
4764 int i;
4765 for(p = first_confline(conf), i = 0; p && i < pos; p=next_confline(p), i++);
4766 return p;
4773 void
4774 free_conflines(CONF_S **p)
4776 if(*p){
4777 free_conflines(&(*p)->next);
4779 if((*p)->varname)
4780 fs_give((void **) &(*p)->varname);
4782 if((*p)->value)
4783 fs_give((void **) &(*p)->value);
4785 fs_give((void **) p);
4793 CONF_S *
4794 first_confline(CONF_S *p)
4796 while(p && p->prev)
4797 p = p->prev;
4799 return(p);
4804 * First selectable confline.
4806 CONF_S *
4807 first_sel_confline(CONF_S *p)
4809 for(p = first_confline(p); p && (p->flags&CF_NOSELECT); p=next_confline(p))
4810 ;/* do nothing */
4812 return(p);
4819 CONF_S *
4820 last_confline(CONF_S *p)
4822 while(p && p->next)
4823 p = p->next;
4825 return(p);
4833 fixed_var(struct variable *v, char *action, char *name)
4835 char **lval;
4837 if(v && v->is_fixed
4838 && (!v->is_list
4839 || ((lval=v->fixed_val.l) && lval[0]
4840 && strcmp(INHERIT, lval[0]) != 0))){
4841 q_status_message2(SM_ORDER, 3, 3,
4842 "Can't %s sys-admin defined %s.",
4843 action ? action : "change", name ? name : "value");
4844 return(1);
4847 return(0);
4851 void
4852 exception_override_warning(struct variable *v)
4854 char **lval;
4856 /* if exceptions config file exists and we're not editing it */
4857 if(v && (ps_global->ew_for_except_vars != Main) && (ew == Main)){
4858 if((!v->is_list && PVAL(v, ps_global->ew_for_except_vars)) ||
4859 (v->is_list && (lval=LVAL(v, ps_global->ew_for_except_vars)) &&
4860 lval[0] && strcmp(INHERIT, lval[0]) != 0))
4861 q_status_message1(SM_ORDER, 3, 3,
4862 _("Warning: \"%s\" is overridden in your exceptions configuration"),
4863 v->name);
4868 void
4869 offer_to_fix_pinerc(struct pine *ps)
4871 struct variable *v;
4872 char prompt[300];
4873 char *p, *q;
4874 char **list;
4875 char **list_fixed;
4876 int rv = 0, write_main = 0, write_post = 0;
4877 int i, k, j, need, exc;
4878 char *clear = ": delete it";
4879 char ***plist;
4881 dprint((4, "offer_to_fix_pinerc()\n"));
4883 ps->fix_fixed_warning = 0; /* so we only ask first time */
4885 if(ps->readonly_pinerc)
4886 return;
4888 set_titlebar(_("FIXING PINERC"), ps->mail_stream,
4889 ps->context_current,
4890 ps->cur_folder, ps->msgmap, 1, FolderName, 0, 0, NULL);
4892 if(want_to(_("Some of your options conflict with site policy. Investigate"),
4893 'y', 'n', NO_HELP, WT_FLUSH_IN) != 'y')
4894 return;
4896 /* space want_to requires in addition to the string you pass in */
4897 #define WANTTO_SPACE 6
4898 need = WANTTO_SPACE + utf8_width(clear);
4900 for(v = ps->vars; v->name; v++){
4901 if(!v->is_fixed ||
4902 !v->is_user ||
4903 v->is_obsolete ||
4904 v == &ps->vars[V_FEATURE_LIST]) /* handle feature-list below */
4905 continue;
4907 prompt[0] = '\0';
4909 if(v->is_list &&
4910 (v->post_user_val.l || v->main_user_val.l)){
4911 char **active_list;
4913 active_list = v->post_user_val.l ? v->post_user_val.l
4914 : v->main_user_val.l;
4915 if(*active_list){
4916 snprintf(prompt, sizeof(prompt), _("Your setting for %s is "), v->name);
4917 prompt[sizeof(prompt)-1] = '\0';
4918 p = prompt + strlen(prompt);
4919 for(i = 0; active_list[i]; i++){
4920 if(utf8_width(prompt) > ps->ttyo->screen_cols - need)
4921 break;
4922 if(i && sizeof(prompt)-(p-prompt) > 0)
4923 *p++ = ',';
4925 sstrncpy(&p, active_list[i], sizeof(prompt)-(p-prompt));
4926 if(sizeof(prompt)-(p-prompt) > 0)
4927 *p = '\0';
4929 prompt[sizeof(prompt)-1] = '\0';
4932 if(sizeof(prompt)-(p-prompt) > 0)
4933 *p = '\0';
4935 else
4936 snprintf(prompt, sizeof(prompt), _("Your setting for %s is %s"), v->name, _(empty_val2));
4938 else{
4939 if(v->post_user_val.p || v->main_user_val.p){
4940 char *active_var;
4942 active_var = v->post_user_val.p ? v->post_user_val.p
4943 : v->main_user_val.p;
4944 if(*active_var){
4945 snprintf(prompt, sizeof(prompt), _("Your setting for %s is %s"),
4946 v->name, active_var);
4948 else{
4949 snprintf(prompt, sizeof(prompt), _("Your setting for %s is %s"),
4950 v->name, _(empty_val2));
4955 prompt[sizeof(prompt)-1] = '\0';
4957 if(*prompt){
4958 if(utf8_width(prompt) > ps->ttyo->screen_cols - need)
4959 (void) utf8_truncate(prompt, ps->ttyo->screen_cols - need);
4961 (void) strncat(prompt, clear, sizeof(prompt)-strlen(prompt)-1);
4962 prompt[sizeof(prompt)-1] = '\0';
4963 if(want_to(prompt, 'y', 'n', NO_HELP, WT_NORM) == 'y'){
4964 if(v->is_list){
4965 if(v->main_user_val.l)
4966 write_main++;
4967 if(v->post_user_val.l)
4968 write_post++;
4970 else{
4971 if(v->main_user_val.p)
4972 write_main++;
4973 if(v->post_user_val.p)
4974 write_post++;
4977 if(delete_user_vals(v))
4978 rv++;
4985 * As always, feature-list has to be handled separately.
4987 exc = (ps->ew_for_except_vars != Main);
4988 v = &ps->vars[V_FEATURE_LIST];
4989 list_fixed = v->fixed_val.l;
4991 for(j = 0; j < 2; j++){
4992 plist = (j==0) ? &v->main_user_val.l : &v->post_user_val.l;
4993 list = *plist;
4994 if(list){
4995 for(i = 0; list[i]; i++){
4996 p = list[i];
4997 if(!struncmp(p, "no-", 3))
4998 p += 3;
4999 for(k = 0; list_fixed && list_fixed[k]; k++){
5000 q = list_fixed[k];
5001 if(!struncmp(q, "no-", 3))
5002 q += 3;
5003 if(!strucmp(q, p) && strucmp(list[i], list_fixed[k])){
5004 snprintf(prompt, sizeof(prompt), "Your %s is %s%s, fixed value is %s",
5005 p, p == list[i] ? _("ON") : _("OFF"),
5006 exc ? ((plist == &v->main_user_val.l) ? ""
5007 : " in postload-config")
5008 : "",
5009 q == list_fixed[k] ? _("ON") : _("OFF"));
5011 prompt[sizeof(prompt)-1] = '\0';
5012 if(utf8_width(prompt) > ps->ttyo->screen_cols - need)
5013 (void) utf8_truncate(prompt, ps->ttyo->screen_cols - need);
5015 (void) strncat(prompt, clear, sizeof(prompt)-strlen(prompt)-1);
5016 prompt[sizeof(prompt)-1] = '\0';
5017 if(want_to(prompt, 'y', 'n', NO_HELP, WT_NORM) == 'y'){
5018 rv++;
5020 if(plist == &v->main_user_val.l)
5021 write_main++;
5022 else
5023 write_post++;
5026 * Clear the feature from the user's pinerc
5027 * so that we'll stop bothering them when they
5028 * start up Pine.
5030 clear_feature(plist, p);
5033 * clear_feature scoots the list up, so if list[i] was
5034 * the last one going in, now it is the end marker. We
5035 * just decrement i so that it will get incremented and
5036 * then test == 0 in the for loop. We could just goto
5037 * outta_here to accomplish the same thing.
5039 if(!list[i])
5040 i--;
5049 if(write_main)
5050 write_pinerc(ps, Main, WRP_NONE);
5051 if(write_post)
5052 write_pinerc(ps, Post, WRP_NONE);
5054 return;
5059 * Adjust side effects that happen because variable changes values.
5061 * Var->user_val should be set to the new value before calling this.
5063 void
5064 fix_side_effects(struct pine *ps, struct variable *var, int revert)
5066 int val = 0;
5067 char **v, *q, **apval;
5068 struct variable *vars = ps->vars;
5070 /* move this up here so we get the Using default message */
5071 if(var == &ps->vars[V_PERSONAL_NAME]){
5072 if(!(var->main_user_val.p ||
5073 var->post_user_val.p) && ps->ui.fullname){
5074 if(var->current_val.p)
5075 fs_give((void **)&var->current_val.p);
5077 var->current_val.p = cpystr(ps->ui.fullname);
5081 if(!revert
5082 && ((!var->is_fixed
5083 && !var->is_list
5084 && !(var->main_user_val.p ||
5085 var->post_user_val.p)
5086 && var->current_val.p)
5088 (!var->is_fixed
5089 && var->is_list
5090 && !(var->main_user_val.l ||
5091 var->post_user_val.l)
5092 && var->current_val.l)))
5093 q_status_message(SM_ORDER,0,3,_("Using default value"));
5095 if(var == &ps->vars[V_USER_DOMAIN]){
5096 char *p, *q;
5098 if(ps->VAR_USER_DOMAIN
5099 && ps->VAR_USER_DOMAIN[0]
5100 && (p = strrindex(ps->VAR_USER_DOMAIN, '@'))){
5101 if(*(++p)){
5102 if(!revert)
5103 q_status_message2(SM_ORDER, 3, 5,
5104 _("User-Domain (%s) cannot contain \"@\"; using %s"),
5105 ps->VAR_USER_DOMAIN, p);
5106 q = ps->VAR_USER_DOMAIN;
5107 while((*q++ = *p++) != '\0')
5108 ;/* do nothing */
5110 else{
5111 if(!revert)
5112 q_status_message1(SM_ORDER, 3, 5,
5113 _("User-domain (%s) cannot contain \"@\"; deleting"),
5114 ps->VAR_USER_DOMAIN);
5116 if(ps->vars[V_USER_DOMAIN].post_user_val.p){
5117 fs_give((void **)&ps->vars[V_USER_DOMAIN].post_user_val.p);
5118 set_current_val(&vars[V_USER_DOMAIN], TRUE, TRUE);
5121 if(ps->VAR_USER_DOMAIN
5122 && ps->VAR_USER_DOMAIN[0]
5123 && (p = strrindex(ps->VAR_USER_DOMAIN, '@'))){
5124 if(ps->vars[V_USER_DOMAIN].main_user_val.p){
5125 fs_give((void **)&ps->vars[V_USER_DOMAIN].main_user_val.p);
5126 set_current_val(&vars[V_USER_DOMAIN], TRUE, TRUE);
5133 * Reset various pointers pertaining to domain name and such...
5135 init_hostname(ps);
5137 else if(var == &ps->vars[V_INBOX_PATH]){
5139 * fixup the inbox path based on global/default values...
5141 init_inbox_mapping(ps->VAR_INBOX_PATH, ps->context_list);
5143 if(!strucmp(ps->cur_folder, ps->inbox_name) && ps->mail_stream
5144 && strcmp(ps->VAR_INBOX_PATH, ps->mail_stream->mailbox)){
5146 * If we currently have "inbox" open and the mailbox name
5147 * doesn't match, reset the current folder's name and
5148 * remove the SP_INBOX flag.
5150 strncpy(ps->cur_folder, ps->mail_stream->mailbox,
5151 sizeof(ps->cur_folder)-1);
5152 ps->cur_folder[sizeof(ps->cur_folder)-1] = '\0';
5153 sp_set_fldr(ps->mail_stream, ps->cur_folder);
5154 sp_unflag(ps->mail_stream, SP_INBOX);
5155 ps->mangled_header = 1;
5157 else if(sp_inbox_stream()
5158 && strcmp(ps->VAR_INBOX_PATH, sp_inbox_stream()->original_mailbox)){
5159 MAILSTREAM *m = sp_inbox_stream();
5162 * if we don't have inbox directly open, but have it
5163 * open for new mail notification, close the stream like
5164 * any other ordinary folder, and clean up...
5166 if(m){
5167 sp_unflag(m, SP_PERMLOCKED | SP_INBOX);
5168 sp_set_fldr(m, m->mailbox);
5169 expunge_and_close(m, NULL, EC_NONE);
5173 else if(var == &ps->vars[V_INCCHECKTIMEO]){
5174 int old_value = ps->inc_check_timeout;
5176 if(SVAR_INC_CHECK_TIMEO(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5177 if(!revert)
5178 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5180 else
5181 ps->inc_check_timeout = old_value;
5183 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5184 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5186 else if(var == &ps->vars[V_INCCHECKINTERVAL]){
5187 int old_value = ps->inc_check_interval;
5189 if(SVAR_INC_CHECK_INTERV(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5190 if(!revert)
5191 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5193 else
5194 ps->inc_check_interval = old_value;
5196 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5197 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5199 else if(var == &ps->vars[V_INC2NDCHECKINTERVAL]){
5200 int old_value = ps->inc_second_check_interval;
5202 if(SVAR_INC_2NDCHECK_INTERV(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5203 if(!revert)
5204 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5206 else
5207 ps->inc_second_check_interval = old_value;
5209 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5210 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5212 else if(var == &ps->vars[V_INCCHECKLIST]){
5213 if(ps->context_list && ps->context_list->use & CNTXT_INCMNG)
5214 reinit_incoming_folder_list(ps, ps->context_list);
5216 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5217 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5219 else if(var == &ps->vars[V_ADDRESSBOOK] ||
5220 var == &ps->vars[V_GLOB_ADDRBOOK] ||
5221 #ifdef ENABLE_LDAP
5222 var == &ps->vars[V_LDAP_SERVERS] ||
5223 #endif
5224 var == &ps->vars[V_ABOOK_FORMATS]){
5225 addrbook_reset();
5227 else if(var == &ps->vars[V_INDEX_FORMAT]){
5228 reset_index_format();
5229 clear_index_cache(ps->mail_stream, 0);
5231 else if(var == &ps->vars[V_DEFAULT_FCC] ||
5232 var == &ps->vars[V_DEFAULT_SAVE_FOLDER]){
5233 init_save_defaults();
5235 else if(var == &ps->vars[V_KW_BRACES] ||
5236 var == &ps->vars[V_OPENING_SEP] ||
5237 var == &ps->vars[V_ALT_ADDRS]){
5238 clear_index_cache(ps->mail_stream, 0);
5240 else if(var == &ps->vars[V_KEYWORDS]){
5241 if(ps_global->keywords)
5242 free_keyword_list(&ps_global->keywords);
5244 if(var->current_val.l && var->current_val.l[0])
5245 ps_global->keywords = init_keyword_list(var->current_val.l);
5247 clear_index_cache(ps->mail_stream, 0);
5249 else if(var == &ps->vars[V_INIT_CMD_LIST]){
5250 if(!revert)
5251 q_status_message(SM_ASYNC, 0, 3,
5252 _("Initial command changes will affect your next Alpine session."));
5254 else if(var == &ps->vars[V_VIEW_HEADERS]){
5255 ps->view_all_except = 0;
5256 if(ps->VAR_VIEW_HEADERS)
5257 for(v = ps->VAR_VIEW_HEADERS; (q = *v) != NULL; v++)
5258 if(q[0]){
5259 char *p;
5261 removing_leading_white_space(q);
5262 /* look for colon or space or end */
5263 for(p = q; *p && !isspace((unsigned char)*p) && *p != ':'; p++)
5264 ;/* do nothing */
5266 *p = '\0';
5267 if(strucmp(q, ALL_EXCEPT) == 0)
5268 ps->view_all_except = 1;
5271 else if(var == &ps->vars[V_OVERLAP]){
5272 int old_value = ps->viewer_overlap;
5274 if(SVAR_OVERLAP(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5275 if(!revert)
5276 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5278 else
5279 ps->viewer_overlap = old_value;
5281 #ifdef SMIME
5282 else if(smime_related_var(ps, var)){
5283 smime_deinit();
5285 #endif /* SMIME */
5286 else if(var == &ps->vars[V_MAXREMSTREAM]){
5287 int old_value = ps->s_pool.max_remstream;
5289 if(SVAR_MAXREMSTREAM(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5290 if(!revert )
5291 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5293 else
5294 ps->s_pool.max_remstream = old_value;
5296 dprint((9, "max_remstream goes to %d\n",
5297 ps->s_pool.max_remstream));
5299 #ifndef _WINDOWS
5300 else if(var == &ps->vars[V_CHAR_SET]){
5301 char *err = NULL;
5303 if(F_ON(F_USE_SYSTEM_TRANS, ps)){
5304 if(!revert)
5305 q_status_message(SM_ORDER, 5, 5, _("This change has no effect because feature Use-System-Translation is on"));
5307 else{
5308 if(reset_character_set_stuff(&err) == -1)
5309 alpine_panic(err ? err : "trouble with Character-Set");
5310 else if(err){
5311 q_status_message(SM_ORDER | SM_DING, 3, 5, err);
5312 fs_give((void **) &err);
5316 else if(var == &ps->vars[V_KEY_CHAR_SET]){
5317 char *err = NULL;
5319 if(F_ON(F_USE_SYSTEM_TRANS, ps)){
5320 if(!revert)
5321 q_status_message(SM_ORDER, 5, 5, _("This change has no effect because feature Use-System-Translation is on"));
5323 else{
5324 if(reset_character_set_stuff(&err) == -1)
5325 alpine_panic(err ? err : "trouble with Character-Set");
5326 else if(err){
5327 q_status_message(SM_ORDER | SM_DING, 3, 5, err);
5328 fs_give((void **) &err);
5332 #endif /* ! _WINDOWS */
5333 else if(var == &ps->vars[V_POST_CHAR_SET]){
5334 update_posting_charset(ps, revert);
5336 else if(var == &ps->vars[V_MARGIN]){
5337 int old_value = ps->scroll_margin;
5339 if(SVAR_MARGIN(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5340 if(!revert)
5341 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5343 else
5344 ps->scroll_margin = old_value;
5346 else if(var == &ps->vars[V_DEADLETS]){
5347 int old_value = ps->deadlets;
5349 if(SVAR_DEADLETS(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5350 if(!revert)
5351 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5353 else
5354 ps->deadlets = old_value;
5356 else if(var == &ps->vars[V_FILLCOL]){
5357 if(SVAR_FILLCOL(ps, ps->composer_fillcol, tmp_20k_buf, SIZEOF_20KBUF)){
5358 if(!revert)
5359 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5362 else if(var == &ps->vars[V_QUOTE_SUPPRESSION]){
5363 val = ps->quote_suppression_threshold;
5364 if(val < Q_SUPP_LIMIT && val > 0)
5365 val = -val;
5367 if(ps->VAR_QUOTE_SUPPRESSION
5368 && SVAR_QUOTE_SUPPRESSION(ps, val, tmp_20k_buf, SIZEOF_20KBUF)){
5369 if(!revert)
5370 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5372 else{
5373 if(val > 0 && val < Q_SUPP_LIMIT){
5374 if(!revert){
5375 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Ignoring Quote-Suppression-Threshold value of %s, see help"), ps->VAR_QUOTE_SUPPRESSION);
5376 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
5377 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5380 else{
5381 if(val < 0 && val != Q_DEL_ALL)
5382 ps->quote_suppression_threshold = -val;
5383 else
5384 ps->quote_suppression_threshold = val;
5388 else if(var == &ps->vars[V_STATUS_MSG_DELAY]){
5389 if(SVAR_MSGDLAY(ps, ps->status_msg_delay, tmp_20k_buf, SIZEOF_20KBUF)){
5390 if(!revert)
5391 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5394 else if(var == &ps->vars[V_ACTIVE_MSG_INTERVAL]){
5395 if(SVAR_ACTIVEINTERVAL(ps, ps->active_status_interval, tmp_20k_buf, SIZEOF_20KBUF)){
5396 if(!revert)
5397 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5399 else{
5400 busy_cue(_("Active Example"), NULL, 0);
5401 sleep(5);
5402 cancel_busy_cue(-1);
5405 #if !defined(DOS) && !defined(OS2) && !defined(LEAVEOUTFIFO)
5406 else if(var == &ps->vars[V_FIFOPATH]){
5407 init_newmailfifo(ps->VAR_FIFOPATH);
5409 #endif
5410 else if(var == &ps->vars[V_NMW_WIDTH]){
5411 int old_value = ps->nmw_width;
5413 if(SVAR_NMW_WIDTH(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5414 if(!revert )
5415 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5417 else{
5418 #ifdef _WINDOWS
5419 if(old_value != ps->nmw_width)
5420 mswin_setnewmailwidth(old_value); /* actually the new value */
5421 #endif
5422 ps->nmw_width = old_value;
5425 else if(var == &ps->vars[V_TCPOPENTIMEO]){
5426 val = 30;
5427 if(!revert)
5428 if(ps->VAR_TCPOPENTIMEO && SVAR_TCP_OPEN(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5429 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5431 else if(var == &ps->vars[V_TCPREADWARNTIMEO]){
5432 val = 15;
5433 if(!revert)
5434 if(ps->VAR_TCPREADWARNTIMEO && SVAR_TCP_READWARN(ps,val,tmp_20k_buf, SIZEOF_20KBUF))
5435 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5437 else if(var == &ps->vars[V_TCPWRITEWARNTIMEO]){
5438 val = 0;
5439 if(!revert)
5440 if(ps->VAR_TCPWRITEWARNTIMEO && SVAR_TCP_WRITEWARN(ps,val,tmp_20k_buf, SIZEOF_20KBUF))
5441 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5443 else if(var == &ps->vars[V_TCPQUERYTIMEO]){
5444 val = 60;
5445 if(!revert)
5446 if(ps->VAR_TCPQUERYTIMEO && SVAR_TCP_QUERY(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5447 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5449 else if(var == &ps->vars[V_QUITQUERYTIMEO]){
5450 val = 0;
5451 if(!revert)
5452 if(ps->VAR_QUITQUERYTIMEO && SVAR_QUIT_QUERY_TIMEO(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5453 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5455 else if(var == &ps->vars[V_RSHOPENTIMEO]){
5456 val = 15;
5457 if(!revert)
5458 if(ps->VAR_RSHOPENTIMEO && SVAR_RSH_OPEN(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5459 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5461 else if(var == &ps->vars[V_SSHOPENTIMEO]){
5462 val = 15;
5463 if(!revert)
5464 if(ps->VAR_SSHOPENTIMEO && SVAR_SSH_OPEN(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5465 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5467 else if(var == &ps->vars[V_SIGNATURE_FILE]){
5468 if(ps->VAR_OPER_DIR && ps->VAR_SIGNATURE_FILE &&
5469 is_absolute_path(ps->VAR_SIGNATURE_FILE) &&
5470 !in_dir(ps->VAR_OPER_DIR, ps->VAR_SIGNATURE_FILE)){
5471 char *e;
5472 size_t l;
5474 l = strlen(ps->VAR_OPER_DIR) + 100;
5475 e = (char *) fs_get((l+1) * sizeof(char));
5476 snprintf(e, l+1, _("Warning: Sig file can't be outside of %s"),
5477 ps->VAR_OPER_DIR);
5478 e[l] = '\0';
5479 q_status_message(SM_ORDER, 3, 6, e);
5480 fs_give((void **)&e);
5483 else if(var == &ps->vars[V_OPER_DIR]){
5484 if(ps->VAR_OPER_DIR && !ps->VAR_OPER_DIR[0]){
5485 q_status_message(SM_ORDER, 3, 5, "Operating-dir is turned off.");
5486 fs_give((void **)&ps->vars[V_OPER_DIR].current_val.p);
5487 if(ps->vars[V_OPER_DIR].fixed_val.p)
5488 fs_give((void **)&ps->vars[V_OPER_DIR].fixed_val.p);
5489 if(ps->vars[V_OPER_DIR].global_val.p)
5490 fs_give((void **)&ps->vars[V_OPER_DIR].global_val.p);
5491 if(ps->vars[V_OPER_DIR].cmdline_val.p)
5492 fs_give((void **)&ps->vars[V_OPER_DIR].cmdline_val.p);
5493 if(ps->vars[V_OPER_DIR].post_user_val.p)
5494 fs_give((void **)&ps->vars[V_OPER_DIR].post_user_val.p);
5495 if(ps->vars[V_OPER_DIR].main_user_val.p)
5496 fs_give((void **)&ps->vars[V_OPER_DIR].main_user_val.p);
5499 else if(var == &ps->vars[V_MAILCHECK]){
5500 int timeo = 15;
5501 if(SVAR_MAILCHK(ps, timeo, tmp_20k_buf, SIZEOF_20KBUF)){
5502 set_input_timeout(15);
5503 if(!revert)
5504 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5506 else{
5507 set_input_timeout(timeo);
5508 if(get_input_timeout() == 0 && !revert){
5509 q_status_message(SM_ORDER, 4, 6,
5510 _("Warning: automatic new mail checking and mailbox checkpointing is disabled"));
5511 if(ps->VAR_INBOX_PATH && ps->VAR_INBOX_PATH[0] == '{')
5512 q_status_message(SM_ASYNC, 3, 6,
5513 _("Warning: Mail-Check-Interval=0 may cause IMAP server connection to time out"));
5517 else if(var == &ps->vars[V_MAILCHECKNONCURR]){
5518 val = (int) ps->check_interval_for_noncurr;
5519 if(ps->VAR_MAILCHECKNONCURR
5520 && SVAR_MAILCHKNONCURR(ps, val, tmp_20k_buf, SIZEOF_20KBUF)){
5521 if(!revert)
5522 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5524 else
5525 ps->check_interval_for_noncurr = (time_t) val;
5527 else if(var == &ps->vars[V_MAILDROPCHECK]){
5528 long rvl;
5530 rvl = 60L;
5531 if(ps->VAR_MAILDROPCHECK && SVAR_MAILDCHK(ps, rvl, tmp_20k_buf, SIZEOF_20KBUF))
5532 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5533 else{
5534 if(rvl == 0L)
5535 rvl = (60L * 60L * 24L * 100L); /* 100 days */
5537 if(rvl >= 60L)
5538 mail_parameters(NULL, SET_SNARFINTERVAL, (void *) rvl);
5541 else if(var == &ps->vars[V_NNTPRANGE]){
5542 long rvl;
5544 rvl = 0L;
5545 if(ps->VAR_NNTPRANGE && SVAR_NNTPRANGE(ps, rvl, tmp_20k_buf, SIZEOF_20KBUF))
5546 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5547 else{
5548 if(rvl >= 0L)
5549 mail_parameters(NULL, SET_NNTPRANGE, (void *) rvl);
5552 else if(var == &ps->vars[V_CUSTOM_HDRS] || var == &ps->vars[V_COMP_HDRS]){
5553 /* this will give warnings about headers that can't be changed */
5554 if(!revert && var->current_val.l && var->current_val.l[0])
5555 customized_hdr_setup(NULL, var->current_val.l, UseAsDef);
5557 #if defined(DOS) || defined(OS2)
5558 else if(var == &ps->vars[V_FOLDER_EXTENSION]){
5559 mail_parameters(NULL, SET_EXTENSION,
5560 (void *)var->current_val.p);
5562 else if(var == &ps->vars[V_NEWSRC_PATH]){
5563 if(var->current_val.p && var->current_val.p[0])
5564 mail_parameters(NULL, SET_NEWSRC,
5565 (void *)var->current_val.p);
5567 #endif
5568 else if(revert && standard_radio_var(ps, var)){
5570 cur_rule_value(var, TRUE, FALSE);
5571 if(var == &ps_global->vars[V_AB_SORT_RULE])
5572 addrbook_redo_sorts();
5573 else if(var == &ps_global->vars[V_THREAD_INDEX_STYLE]){
5574 clear_index_cache(ps_global->mail_stream, 0);
5575 set_lflags(ps_global->mail_stream, ps_global->msgmap,
5576 MN_COLL | MN_CHID, 0);
5577 if(SORT_IS_THREADED(ps_global->msgmap)
5578 && (SEP_THRDINDX() || COLL_THRDS()))
5579 collapse_threads(ps_global->mail_stream, ps_global->msgmap, NULL);
5581 adjust_cur_to_visible(ps_global->mail_stream, ps_global->msgmap);
5583 #ifndef _WINDOWS
5584 else if(var == &ps->vars[V_COLOR_STYLE]){
5585 pico_toggle_color(0);
5586 switch(ps->color_style){
5587 case COL_NONE:
5588 case COL_TERMDEF:
5589 pico_set_color_options(pico_trans_color() ? COLOR_TRANS_OPT : 0);
5590 break;
5591 case COL_ANSI8:
5592 pico_set_color_options(COLOR_ANSI8_OPT|COLOR_TRANS_OPT);
5593 break;
5594 case COL_ANSI16:
5595 pico_set_color_options(COLOR_ANSI16_OPT|COLOR_TRANS_OPT);
5596 break;
5597 case COL_ANSI256:
5598 pico_set_color_options(COLOR_ANSI256_OPT|COLOR_TRANS_OPT);
5599 break;
5602 if(ps->color_style != COL_NONE)
5603 pico_toggle_color(1);
5605 if(pico_usingcolor())
5606 pico_set_normal_color();
5608 clear_index_cache(ps_global->mail_stream, 0);
5609 ClearScreen();
5610 ps->mangled_screen = 1;
5612 #endif
5614 else if(revert && var == &ps->vars[V_SORT_KEY]){
5615 int def_sort_rev;
5617 decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev);
5618 ps->def_sort_rev = def_sort_rev;
5620 else if(var == &ps->vars[V_THREAD_MORE_CHAR] ||
5621 var == &ps->vars[V_THREAD_EXP_CHAR] ||
5622 var == &ps->vars[V_THREAD_LASTREPLY_CHAR]){
5624 if(var == &ps->vars[V_THREAD_LASTREPLY_CHAR] &&
5625 !(var->current_val.p && var->current_val.p[0])){
5626 if(var->current_val.p)
5627 fs_give((void **) &var->current_val.p);
5629 q_status_message1(SM_ORDER, 3, 5,
5630 _("\"%s\" can't be Empty, using default"), var->name);
5632 apval = APVAL(var, ew);
5633 if(*apval)
5634 fs_give((void **)apval);
5636 set_current_val(var, FALSE, FALSE);
5638 if(!(var->current_val.p && var->current_val.p[0]
5639 && !var->current_val.p[1])){
5640 if(var->current_val.p)
5641 fs_give((void **) &var->current_val.p);
5643 var->current_val.p = cpystr(DF_THREAD_LASTREPLY_CHAR);
5647 if(var == &ps->vars[V_THREAD_MORE_CHAR] ||
5648 var == &ps->vars[V_THREAD_EXP_CHAR] ||
5649 var == &ps->vars[V_THREAD_LASTREPLY_CHAR]){
5650 if(var->current_val.p && var->current_val.p[0] &&
5651 var->current_val.p[1]){
5652 q_status_message1(SM_ORDER, 3, 5,
5653 "Only first character of \"%s\" is used",
5654 var->name);
5655 var->current_val.p[1] = '\0';
5658 if(var->main_user_val.p && var->main_user_val.p[0] &&
5659 var->main_user_val.p[1])
5660 var->main_user_val.p[1] = '\0';
5662 if(var->post_user_val.p && var->post_user_val.p[0] &&
5663 var->post_user_val.p[1])
5664 var->post_user_val.p[1] = '\0';
5667 clear_index_cache(ps_global->mail_stream, 0);
5668 set_need_format_setup(ps_global->mail_stream);
5670 else if(var == &ps->vars[V_NNTP_SERVER]){
5671 free_contexts(&ps_global->context_list);
5672 init_folders(ps_global);
5674 else if(var == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){
5675 init_hostname(ps);
5677 else if(var == &ps->vars[V_PRINTER]){
5678 if(!revert && ps->vars[V_PERSONAL_PRINT_COMMAND].is_fixed){
5679 if(printer_value_check_and_adjust())
5680 q_status_message1(SM_ORDER, 3, 5,
5681 _("Can't set \"%s\" to that value, see Setup/Printer"),
5682 pretty_var_name(var->name));
5685 else if(var == &ps->vars[V_NORM_FORE_COLOR] ||
5686 var == &ps->vars[V_NORM_BACK_COLOR] ||
5687 var == &ps->vars[V_REV_FORE_COLOR] ||
5688 var == &ps->vars[V_REV_BACK_COLOR] ||
5689 var == &ps->vars[V_TITLE_FORE_COLOR] ||
5690 var == &ps->vars[V_TITLE_BACK_COLOR] ||
5691 var == &ps->vars[V_TITLECLOSED_FORE_COLOR] ||
5692 var == &ps->vars[V_TITLECLOSED_BACK_COLOR] ||
5693 var == &ps->vars[V_STATUS_FORE_COLOR] ||
5694 var == &ps->vars[V_STATUS_BACK_COLOR] ||
5695 var == &ps->vars[V_KEYLABEL_FORE_COLOR] ||
5696 var == &ps->vars[V_KEYLABEL_BACK_COLOR] ||
5697 var == &ps->vars[V_KEYNAME_FORE_COLOR] ||
5698 var == &ps->vars[V_KEYNAME_BACK_COLOR]){
5699 set_current_color_vals(ps);
5700 ClearScreen();
5701 ps->mangled_screen = 1;
5703 else if(var == &ps->vars[V_KW_COLORS] ||
5704 var == &ps->vars[V_INDEX_TOKEN_COLORS] ||
5705 var == &ps->vars[V_IND_PLUS_FORE_COLOR] ||
5706 var == &ps->vars[V_IND_IMP_FORE_COLOR] ||
5707 var == &ps->vars[V_IND_DEL_FORE_COLOR] ||
5708 var == &ps->vars[V_IND_ANS_FORE_COLOR] ||
5709 var == &ps->vars[V_IND_NEW_FORE_COLOR] ||
5710 var == &ps->vars[V_IND_UNS_FORE_COLOR] ||
5711 var == &ps->vars[V_IND_HIPRI_FORE_COLOR]||
5712 var == &ps->vars[V_IND_LOPRI_FORE_COLOR]||
5713 var == &ps->vars[V_IND_ARR_FORE_COLOR] ||
5714 var == &ps->vars[V_IND_REC_FORE_COLOR] ||
5715 var == &ps->vars[V_IND_FWD_FORE_COLOR] ||
5716 var == &ps->vars[V_IND_OP_FORE_COLOR] ||
5717 var == &ps->vars[V_IND_FROM_FORE_COLOR] ||
5718 var == &ps->vars[V_IND_SUBJ_FORE_COLOR] ||
5719 var == &ps->vars[V_IND_PLUS_BACK_COLOR] ||
5720 var == &ps->vars[V_IND_IMP_BACK_COLOR] ||
5721 var == &ps->vars[V_IND_DEL_BACK_COLOR] ||
5722 var == &ps->vars[V_IND_ANS_BACK_COLOR] ||
5723 var == &ps->vars[V_IND_NEW_BACK_COLOR] ||
5724 var == &ps->vars[V_IND_UNS_BACK_COLOR] ||
5725 var == &ps->vars[V_IND_ARR_BACK_COLOR] ||
5726 var == &ps->vars[V_IND_REC_BACK_COLOR] ||
5727 var == &ps->vars[V_IND_FWD_BACK_COLOR] ||
5728 var == &ps->vars[V_IND_OP_BACK_COLOR] ||
5729 var == &ps->vars[V_IND_FROM_BACK_COLOR] ||
5730 var == &ps->vars[V_IND_SUBJ_BACK_COLOR]){
5731 clear_index_cache(ps_global->mail_stream, 0);
5733 else if(var == score_act_global_ptr){
5734 int score;
5736 score = atoi(var->current_val.p);
5737 if(score < SCORE_MIN || score > SCORE_MAX){
5738 q_status_message2(SM_ORDER, 3, 5,
5739 _("Score Value must be in range %s to %s"),
5740 comatose(SCORE_MIN), comatose(SCORE_MAX));
5741 apval = APVAL(var, ew);
5742 if(*apval)
5743 fs_give((void **)apval);
5745 set_current_val(var, FALSE, FALSE);
5748 else if(var == scorei_pat_global_ptr || var == age_pat_global_ptr
5749 || var == size_pat_global_ptr || var == cati_global_ptr){
5750 apval = APVAL(var, ew);
5751 if(*apval){
5752 INTVL_S *iv;
5753 iv = parse_intvl(*apval);
5754 if(iv){
5755 fs_give((void **) apval);
5756 *apval = stringform_of_intvl(iv);
5757 free_intvl(&iv);
5759 else
5760 fs_give((void **) apval);
5763 set_current_val(var, FALSE, FALSE);
5765 else if(var == &ps->vars[V_FEATURE_LIST]){
5766 process_feature_list(ps, var->current_val.l, 0, 0, 0);
5768 else if(!revert && (var == &ps->vars[V_LAST_TIME_PRUNE_QUESTION] ||
5769 var == &ps->vars[V_REMOTE_ABOOK_HISTORY] ||
5770 var == &ps->vars[V_REMOTE_ABOOK_VALIDITY] ||
5771 var == &ps->vars[V_USERINPUTTIMEO] ||
5772 var == &ps->vars[V_NEWS_ACTIVE_PATH] ||
5773 var == &ps->vars[V_NEWS_SPOOL_DIR] ||
5774 var == &ps->vars[V_INCOMING_FOLDERS] ||
5775 var == &ps->vars[V_FOLDER_SPEC] ||
5776 var == &ps->vars[V_NEWS_SPEC] ||
5777 var == &ps->vars[V_DISABLE_DRIVERS] ||
5778 var == &ps->vars[V_DISABLE_AUTHS] ||
5779 #ifdef DF_ENCRYPTION_RANGE
5780 var == &ps->vars[V_ENCRYPTION_RANGE] ||
5781 #endif /* DF_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 var == &ps->vars[V_SSLCIPHERS] ||
5788 #endif
5789 var == &ps->vars[V_RSHPATH] ||
5790 var == &ps->vars[V_RSHCMD] ||
5791 var == &ps->vars[V_SSHCMD] ||
5792 var == &ps->vars[V_SSHPATH])){
5793 q_status_message2(SM_ASYNC, 0, 3,
5794 _("Changes%s%s will affect your next Alpine session."),
5795 var->name ? " to " : "", var->name ? var->name : "");
5798 if(!revert && (var == &ps->vars[V_TCPOPENTIMEO] ||
5799 var == &ps->vars[V_TCPREADWARNTIMEO] ||
5800 var == &ps->vars[V_TCPWRITEWARNTIMEO] ||
5801 var == &ps->vars[V_TCPQUERYTIMEO] ||
5802 var == &ps->vars[V_QUITQUERYTIMEO] ||
5803 var == &ps->vars[V_RSHOPENTIMEO] ||
5804 var == &ps->vars[V_SSHOPENTIMEO]))
5805 q_status_message(SM_ASYNC, 0, 3,
5806 _("Timeout changes will affect your next Alpine session."));
5811 * Compare saved user_val with current user_val to see if it changed.
5812 * If any have changed, change it back and take the appropriate action.
5814 void
5815 revert_to_saved_config(struct pine *ps, SAVED_CONFIG_S *vsave, int allow_hard_to_config_remotely)
5817 struct variable *vreal;
5818 SAVED_CONFIG_S *v;
5819 int i, n;
5820 int changed = 0;
5821 char *pval, **apval, **lval, ***alval;
5823 v = vsave;
5824 for(vreal = ps->vars; vreal->name; vreal++,v++){
5825 if(!save_include(ps, vreal, allow_hard_to_config_remotely))
5826 continue;
5828 changed = 0;
5829 if(vreal->is_list){
5830 lval = LVAL(vreal, ew);
5831 alval = ALVAL(vreal, ew);
5833 if((v->saved_user_val.l && !lval)
5834 || (!v->saved_user_val.l && lval))
5835 changed++;
5836 else if(!v->saved_user_val.l && !lval)
5837 ;/* no change, nothing to do */
5838 else
5839 for(i = 0; v->saved_user_val.l[i] || lval[i]; i++)
5840 if((v->saved_user_val.l[i]
5841 && (!lval[i]
5842 || strcmp(v->saved_user_val.l[i], lval[i])))
5844 (!v->saved_user_val.l[i] && lval[i])){
5845 changed++;
5846 break;
5849 if(changed){
5850 char **list;
5852 if(alval){
5853 if(*alval)
5854 free_list_array(alval);
5856 /* copy back the original one */
5857 if(v->saved_user_val.l){
5858 list = v->saved_user_val.l;
5859 n = 0;
5860 /* count how many */
5861 while(list[n])
5862 n++;
5864 *alval = (char **)fs_get((n+1) * sizeof(char *));
5866 for(i = 0; i < n; i++)
5867 (*alval)[i] = cpystr(v->saved_user_val.l[i]);
5869 (*alval)[n] = NULL;
5874 else{
5875 pval = PVAL(vreal, ew);
5876 apval = APVAL(vreal, ew);
5878 if((v->saved_user_val.p &&
5879 (!pval || strcmp(v->saved_user_val.p, pval))) ||
5880 (!v->saved_user_val.p && pval)){
5881 /* It changed, fix it */
5882 changed++;
5883 if(apval){
5884 /* free the changed value */
5885 if(*apval)
5886 fs_give((void **)apval);
5888 if(v->saved_user_val.p)
5889 *apval = cpystr(v->saved_user_val.p);
5894 if(changed){
5895 if(vreal == &ps->vars[V_FEATURE_LIST])
5896 set_feature_list_current_val(vreal);
5897 else
5898 set_current_val(vreal, TRUE, FALSE);
5900 fix_side_effects(ps, vreal, 1);
5906 SAVED_CONFIG_S *
5907 save_config_vars(struct pine *ps, int allow_hard_to_config_remotely)
5909 struct variable *vreal;
5910 SAVED_CONFIG_S *vsave, *v;
5912 vsave = (SAVED_CONFIG_S *)fs_get((V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
5913 memset((void *)vsave, 0, (V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
5914 v = vsave;
5915 for(vreal = ps->vars; vreal->name; vreal++,v++){
5916 if(!save_include(ps, vreal, allow_hard_to_config_remotely))
5917 continue;
5919 if(vreal->is_list){
5920 int n, i;
5921 char **list;
5923 if(LVAL(vreal, ew)){
5924 /* count how many */
5925 n = 0;
5926 list = LVAL(vreal, ew);
5927 while(list[n])
5928 n++;
5930 v->saved_user_val.l = (char **)fs_get((n+1) * sizeof(char *));
5931 memset((void *)v->saved_user_val.l, 0, (n+1)*sizeof(char *));
5932 for(i = 0; i < n; i++)
5933 v->saved_user_val.l[i] = cpystr(list[i]);
5935 v->saved_user_val.l[n] = NULL;
5938 else{
5939 if(PVAL(vreal, ew))
5940 v->saved_user_val.p = cpystr(PVAL(vreal, ew));
5944 return(vsave);
5948 void
5949 free_saved_config(struct pine *ps, SAVED_CONFIG_S **vsavep, int allow_hard_to_config_remotely)
5951 struct variable *vreal;
5952 SAVED_CONFIG_S *v;
5954 if(vsavep && *vsavep){
5955 for(v = *vsavep, vreal = ps->vars; vreal->name; vreal++,v++){
5956 if(!save_include(ps, vreal, allow_hard_to_config_remotely))
5957 continue;
5959 if(vreal->is_list){ /* free saved_user_val.l */
5960 if(v && v->saved_user_val.l)
5961 free_list_array(&v->saved_user_val.l);
5963 else if(v && v->saved_user_val.p)
5964 fs_give((void **)&v->saved_user_val.p);
5967 fs_give((void **)vsavep);
5973 * Returns positive if any thing was actually deleted.
5976 delete_user_vals(struct variable *v)
5978 int rv = 0;
5980 if(v){
5981 if(v->is_list){
5982 if(v->post_user_val.l){
5983 rv++;
5984 free_list_array(&v->post_user_val.l);
5986 if(v->main_user_val.l){
5987 rv++;
5988 free_list_array(&v->main_user_val.l);
5991 else{
5992 if(v->post_user_val.p){
5993 rv++;
5994 fs_give((void **)&v->post_user_val.p);
5996 if(v->main_user_val.p){
5997 rv++;
5998 fs_give((void **)&v->main_user_val.p);
6003 return(rv);
6008 * ../pith/conf.c required function
6011 unexpected_pinerc_change(void)
6013 Writechar(BELL, 0);
6014 if(want_to("Unexpected pinerc change! Overwrite with current config",
6015 'n', 0, NO_HELP, WT_FLUSH_IN) == 'n'){
6016 return(-1); /* abort pinerc write */
6019 return(0); /* overwrite */
6023 #ifdef _WINDOWS
6025 /*----------------------------------------------------------------------
6026 MSWin scroll callback. Called during scroll message processing.
6030 Args: cmd - what type of scroll operation.
6031 scroll_pos - parameter for operation.
6032 used as position for SCROLL_TO operation.
6034 Returns: TRUE - did the scroll operation.
6035 FALSE - was not able to do the scroll operation.
6036 ----*/
6038 config_scroll_callback (cmd, scroll_pos)
6039 int cmd;
6040 long scroll_pos;
6042 switch (cmd) {
6043 case MSWIN_KEY_SCROLLUPLINE:
6044 config_scroll_down (scroll_pos);
6045 break;
6047 case MSWIN_KEY_SCROLLDOWNLINE:
6048 config_scroll_up (scroll_pos);
6049 break;
6051 case MSWIN_KEY_SCROLLUPPAGE:
6052 config_scroll_down (BODY_LINES(ps_global));
6053 break;
6055 case MSWIN_KEY_SCROLLDOWNPAGE:
6056 config_scroll_up (BODY_LINES(ps_global));
6057 break;
6059 case MSWIN_KEY_SCROLLTO:
6060 config_scroll_to_pos (scroll_pos);
6061 break;
6064 option_screen_redrawer();
6065 fflush(stdout);
6067 return(TRUE);
6070 #endif /* _WINDOWS */