* NTLM authentication support with the ntlm library, in Unix systems.
[alpine.git] / alpine / confscroll.c
blob9b1390836c2f94a10c6994326861d177e0c77dfa
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: confscroll.c 1169 2008-08-27 06:42:06Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2006-2008 University of Washington
8 * Copyright 2013-2017 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
19 #include "headers.h"
20 #include "confscroll.h"
21 #include "keymenu.h"
22 #include "status.h"
23 #include "titlebar.h"
24 #include "help.h"
25 #include "radio.h"
26 #include "print.h"
27 #include "ldapconf.h"
28 #include "roleconf.h"
29 #include "colorconf.h"
30 #include "mailview.h"
31 #include "mailcmd.h"
32 #include "mailindx.h"
33 #include "talk.h"
34 #include "setup.h"
35 #include "smime.h"
36 #include "../pith/state.h"
37 #include "../pith/flag.h"
38 #include "../pith/list.h"
39 #include "../pith/conf.h"
40 #include "../pith/util.h"
41 #include "../pith/newmail.h"
42 #include "../pith/sort.h"
43 #include "../pith/thread.h"
44 #include "../pith/color.h"
45 #include "../pith/hist.h"
46 #include "../pith/icache.h"
47 #include "../pith/conf.h"
48 #include "../pith/init.h"
49 #include "../pith/folder.h"
50 #include "../pith/busy.h"
51 #include "../pith/tempfile.h"
52 #include "../pith/pattern.h"
53 #include "../pith/charconv/utf8.h"
56 #define CONFIG_SCREEN_HELP_TITLE _("HELP FOR SETUP CONFIGURATION")
58 /* TRANSLATORS: Empty Value is what is shown in the configuration
59 screen when the user not only does not set an option but also
60 wants to explicitly not use the default value. Empty value means
61 an option with no value. */
62 char *empty_val = N_("Empty Value");
63 char *empty_val2 = N_("<Empty Value>");
64 /* TRANSLATORS: No Value set is similar to Empty Value, but the
65 user has not explicitly decided to not use the default. It is
66 just an option which the user has left at the default value. */
67 char *no_val = N_("No Value Set");
68 /* TRANSLATORS: Value is Fixed is what is displayed in the config
69 screen when the system managers have set an option to a specific
70 value and they don't allow the user to change it. The value
71 is fixed to a certain value. This isn't the same word as
72 Repaired, it means Unchanging. */
73 char *fixed_val = N_("Value is Fixed");
74 char yesstr[] = "Yes";
75 char nostr[] = "No";
78 EditWhich ew = Main;
81 OPT_SCREEN_S *opt_screen;
85 * This is pretty ugly. Some of the routines operate differently depending
86 * on which variable they are operating on. Sometimes those variables are
87 * global (real alpine.h V_ style variables) and sometimes they are just
88 * local variables (as in role_config_edit_screen). These pointers are here
89 * so that the routines can figure out which variable they are operating
90 * on and do the right thing.
92 struct variable *score_act_global_ptr,
93 *scorei_pat_global_ptr,
94 *age_pat_global_ptr,
95 *size_pat_global_ptr,
96 *cati_global_ptr,
97 *cat_cmd_global_ptr,
98 *cat_lim_global_ptr,
99 *startup_ptr,
100 *role_comment_ptr,
101 *role_forw_ptr,
102 *role_repl_ptr,
103 *role_fldr_ptr,
104 *role_afrom_ptr,
105 *role_filt_ptr,
106 *role_status1_ptr,
107 *role_status2_ptr,
108 *role_status3_ptr,
109 *role_status4_ptr,
110 *role_status5_ptr,
111 *role_status6_ptr,
112 *role_status7_ptr,
113 *role_status8_ptr,
114 *msg_state1_ptr,
115 *msg_state2_ptr,
116 *msg_state3_ptr,
117 *msg_state4_ptr;
120 typedef NAMEVAL_S *(*PTR_TO_RULEFUNC)(int);
124 * Internal prototypes
126 PTR_TO_RULEFUNC rulefunc_from_var(struct pine *, struct variable *);
127 void set_radio_pretty_vals(struct pine *, CONF_S **);
128 int save_include(struct pine *, struct variable *, int);
129 void config_scroll_up(long);
130 void config_scroll_down(long);
131 void config_scroll_to_pos(long);
132 CONF_S *config_top_scroll(struct pine *, CONF_S *);
133 void update_option_screen(struct pine *, OPT_SCREEN_S *, Pos *);
134 void print_option_screen(OPT_SCREEN_S *, char *);
135 void option_screen_redrawer(void);
136 char *text_pretty_value(struct pine *, CONF_S *);
137 char *checkbox_pretty_value(struct pine *, CONF_S *);
138 char *yesno_pretty_value(struct pine *, CONF_S *);
139 char *radio_pretty_value(struct pine *, CONF_S *);
140 char *sigfile_pretty_value(struct pine *, CONF_S *);
141 char *color_pretty_value(struct pine *, CONF_S *);
142 char *sort_pretty_value(struct pine *, CONF_S *);
143 int longest_feature_name(void);
144 COLOR_PAIR *sample_color(struct pine *, struct variable *);
145 COLOR_PAIR *sampleexc_color(struct pine *, struct variable *);
146 void clear_feature(char ***, char *);
147 CONF_S *last_confline(CONF_S *);
148 #ifdef _WINDOWS
149 int config_scroll_callback(int, long);
150 #endif
154 * We test for this same set of vars in a few places.
157 standard_radio_var(struct pine *ps, struct variable *v)
159 return(v == &ps->vars[V_SAVED_MSG_NAME_RULE] ||
160 v == &ps->vars[V_FCC_RULE] ||
161 v == &ps->vars[V_GOTO_DEFAULT_RULE] ||
162 v == &ps->vars[V_INCOMING_STARTUP] ||
163 v == &ps->vars[V_PRUNING_RULE] ||
164 v == &ps->vars[V_REOPEN_RULE] ||
165 v == &ps->vars[V_THREAD_DISP_STYLE] ||
166 v == &ps->vars[V_THREAD_INDEX_STYLE] ||
167 v == &ps->vars[V_FLD_SORT_RULE] ||
168 #ifndef _WINDOWS
169 v == &ps->vars[V_COLOR_STYLE] ||
170 #endif
171 v == &ps->vars[V_INDEX_COLOR_STYLE] ||
172 v == &ps->vars[V_TITLEBAR_COLOR_STYLE] ||
173 v == &ps->vars[V_AB_SORT_RULE]);
177 PTR_TO_RULEFUNC
178 rulefunc_from_var(struct pine *ps, struct variable *v)
180 PTR_TO_RULEFUNC rulefunc = NULL;
182 if(v == &ps->vars[V_SAVED_MSG_NAME_RULE])
183 rulefunc = save_msg_rules;
184 else if(v == &ps->vars[V_FCC_RULE])
185 rulefunc = fcc_rules;
186 else if(v == &ps->vars[V_GOTO_DEFAULT_RULE])
187 rulefunc = goto_rules;
188 else if(v == &ps->vars[V_INCOMING_STARTUP])
189 rulefunc = incoming_startup_rules;
190 else if(v == startup_ptr)
191 rulefunc = startup_rules;
192 else if(v == &ps->vars[V_PRUNING_RULE])
193 rulefunc = pruning_rules;
194 else if(v == &ps->vars[V_REOPEN_RULE])
195 rulefunc = reopen_rules;
196 else if(v == &ps->vars[V_THREAD_DISP_STYLE])
197 rulefunc = thread_disp_styles;
198 else if(v == &ps->vars[V_THREAD_INDEX_STYLE])
199 rulefunc = thread_index_styles;
200 else if(v == &ps->vars[V_FLD_SORT_RULE])
201 rulefunc = fld_sort_rules;
202 else if(v == &ps->vars[V_AB_SORT_RULE])
203 rulefunc = ab_sort_rules;
204 else if(v == &ps->vars[V_INDEX_COLOR_STYLE])
205 rulefunc = index_col_style;
206 else if(v == &ps->vars[V_TITLEBAR_COLOR_STYLE])
207 rulefunc = titlebar_col_style;
208 #ifndef _WINDOWS
209 else if(v == &ps->vars[V_COLOR_STYLE])
210 rulefunc = col_style;
211 #endif
213 return(rulefunc);
217 void
218 standard_radio_setup(struct pine *ps, CONF_S **cl, struct variable *v, CONF_S **first_line)
220 int i, rindent = 12;
221 CONF_S *ctmpb;
222 PTR_TO_RULEFUNC rulefunc;
223 NAMEVAL_S *f;
224 char b[100];
226 if(!(cl && *cl))
227 return;
229 rulefunc = rulefunc_from_var(ps, v);
230 ctmpb = (*cl);
232 (*cl)->flags |= CF_NOSELECT;
233 (*cl)->keymenu = &config_radiobutton_keymenu;
234 (*cl)->tool = NULL;
236 /* put a nice delimiter before list */
237 new_confline(cl)->var = NULL;
238 (*cl)->varnamep = ctmpb;
239 (*cl)->keymenu = &config_radiobutton_keymenu;
240 (*cl)->help = NO_HELP;
241 (*cl)->tool = radiobutton_tool;
242 (*cl)->valoffset = rindent;
243 (*cl)->flags |= CF_NOSELECT;
244 /* TRANSLATORS: Set and Rule Values are the headings for an option
245 that can take one of several values. Underneath the Set heading
246 will be a column where one possibility is turned on (is Set).
247 The other column will be very short descriptions of what
248 the possibilities are (the Rule Values). */
249 utf8_snprintf(b, sizeof(b), "%-5.5w %s", _("Set"), _("Rule Values"));
250 (*cl)->value = cpystr(b);
252 new_confline(cl)->var = NULL;
253 (*cl)->varnamep = ctmpb;
254 (*cl)->keymenu = &config_radiobutton_keymenu;
255 (*cl)->help = NO_HELP;
256 (*cl)->tool = radiobutton_tool;
257 (*cl)->valoffset = rindent;
258 (*cl)->flags |= CF_NOSELECT;
259 (*cl)->value = cpystr("--- ----------------------");
261 if(rulefunc)
262 for(i = 0; (f = (*rulefunc)(i)); i++){
263 new_confline(cl)->var = v;
264 if(first_line && !*first_line && !pico_usingcolor())
265 *first_line = (*cl);
267 (*cl)->varnamep = ctmpb;
268 (*cl)->keymenu = &config_radiobutton_keymenu;
269 (*cl)->help = (v == startup_ptr)
270 ? h_config_other_startup
271 : config_help(v - ps->vars,0);
272 (*cl)->tool = radiobutton_tool;
273 (*cl)->valoffset = rindent;
274 (*cl)->varmem = i;
275 (*cl)->value = pretty_value(ps, *cl);
281 * Reset the displayed values for all of the lines for this
282 * variable because others besides this line may change.
284 void
285 set_radio_pretty_vals(struct pine *ps, CONF_S **cl)
287 CONF_S *ctmp;
289 if(!(cl && *cl &&
290 ((*cl)->var == &ps->vars[V_SORT_KEY] ||
291 standard_radio_var(ps, (*cl)->var) ||
292 (*cl)->var == startup_ptr)))
293 return;
295 /* hunt backwards */
296 for(ctmp = *cl;
297 ctmp && !(ctmp->flags & CF_NOSELECT) && !ctmp->varname;
298 ctmp = prev_confline(ctmp)){
299 if(ctmp->value)
300 fs_give((void **)&ctmp->value);
302 ctmp->value = pretty_value(ps, ctmp);
305 /* hunt forwards */
306 for(ctmp = *cl;
307 ctmp && !ctmp->varname && !(ctmp->flags & CF_NOSELECT);
308 ctmp = next_confline(ctmp)){
309 if(ctmp->value)
310 fs_give((void **)&ctmp->value);
312 ctmp->value = pretty_value(ps, ctmp);
318 * test whether or not a var is
320 * returns: 1 if it should be excluded, 0 otw
323 exclude_config_var(struct pine *ps, struct variable *var, int allow_hard_to_config_remotely)
325 if((ew != Main && (var->is_onlymain)) ||
326 (ew != ps_global->ew_for_except_vars && var->is_outermost))
327 return(1);
329 if(allow_hard_to_config_remotely)
330 return(!(var->is_user && var->is_used && !var->is_obsolete));
332 switch(var - ps->vars){
333 case V_MAIL_DIRECTORY :
334 case V_INCOMING_FOLDERS :
335 case V_FOLDER_SPEC :
336 case V_NEWS_SPEC :
337 case V_STANDARD_PRINTER :
338 case V_LAST_TIME_PRUNE_QUESTION :
339 case V_LAST_VERS_USED :
340 case V_ADDRESSBOOK :
341 case V_GLOB_ADDRBOOK :
342 case V_DISABLE_DRIVERS :
343 case V_DISABLE_AUTHS :
344 case V_REMOTE_ABOOK_METADATA :
345 case V_REMOTE_ABOOK_HISTORY :
346 case V_REMOTE_ABOOK_VALIDITY :
347 case V_OPER_DIR :
348 case V_USERINPUTTIMEO :
349 case V_TCPOPENTIMEO :
350 case V_TCPREADWARNTIMEO :
351 case V_TCPWRITEWARNTIMEO :
352 case V_TCPQUERYTIMEO :
353 case V_RSHCMD :
354 case V_RSHPATH :
355 case V_RSHOPENTIMEO :
356 case V_SSHCMD :
357 case V_SSHPATH :
358 case V_SSHOPENTIMEO :
359 case V_SENDMAIL_PATH :
360 case V_NEW_VER_QUELL :
361 case V_PATTERNS :
362 case V_PAT_ROLES :
363 case V_PAT_FILTS :
364 case V_PAT_SCORES :
365 case V_PAT_INCOLS :
366 case V_PAT_OTHER :
367 case V_PAT_SRCH :
368 case V_PRINTER :
369 case V_PERSONAL_PRINT_COMMAND :
370 case V_PERSONAL_PRINT_CATEGORY :
371 case V_RSS_NEWS :
372 case V_RSS_WEATHER :
373 case V_WP_INDEXHEIGHT :
374 case V_WP_INDEXLINES :
375 case V_WP_AGGSTATE :
376 case V_WP_STATE :
377 case V_WP_COLUMNS :
378 #ifndef _WINDOWS
379 case V_OLD_CHAR_SET :
380 #endif /* ! _WINDOWS */
381 #if defined(DOS) || defined(OS2)
382 case V_UPLOAD_CMD :
383 case V_UPLOAD_CMD_PREFIX :
384 case V_DOWNLOAD_CMD :
385 case V_DOWNLOAD_CMD_PREFIX :
386 #ifdef _WINDOWS
387 case V_FONT_NAME :
388 case V_FONT_SIZE :
389 case V_FONT_STYLE :
390 case V_FONT_CHAR_SET :
391 case V_PRINT_FONT_NAME :
392 case V_PRINT_FONT_SIZE :
393 case V_PRINT_FONT_STYLE :
394 case V_PRINT_FONT_CHAR_SET :
395 case V_WINDOW_POSITION :
396 case V_CURSOR_STYLE :
397 #endif /* _WINDOWS */
398 #endif /* DOS */
399 #ifdef ENABLE_LDAP
400 case V_LDAP_SERVERS :
401 #endif /* ENABLE_LDAP */
402 return(1);
404 default:
405 break;
408 return(!(var->is_user && var->is_used && !var->is_obsolete &&
409 #ifdef SMIME
410 !smime_related_var(ps, var) &&
411 #endif /* SMIME */
412 !color_related_var(ps, var)));
417 * Test to indicate what should be saved in case user wants to abandon
418 * changes.
421 save_include(struct pine *ps, struct variable *v, int allow_hard_to_config_remotely)
423 return(!exclude_config_var(ps, v, allow_hard_to_config_remotely)
424 || (v->is_user
425 && v->is_used
426 && !v->is_obsolete
427 && (v == &ps->vars[V_PERSONAL_PRINT_COMMAND]
428 #ifdef ENABLE_LDAP
429 || v == &ps->vars[V_LDAP_SERVERS]
430 #endif
431 )));
436 * Handles screen painting and motion. Passes other commands to
437 * custom tools.
439 * Tool return values: Tools should return the following:
440 * 0 nothing changed
441 * -1 unrecognized command
442 * 1 something changed, conf_scroll_screen should remember that
443 * 2 tells conf_scroll_screen to return with value 1 or 0 depending
444 * on whether or not it has previously gotten a 1 from some tool.
445 * 3 tells conf_scroll_screen to return 1 (like 1 and 2 combined)
446 * ? Other tool-specific values can be used. They will cause
447 * conf_scroll_screen to return that value.
449 * Return values:
450 * 0 if nothing happened. That is, a tool returned 2 and we hadn't
451 * previously noted a return of 1
452 * 1 if something happened. That is, a tool returned 2 and we had
453 * previously noted a return of 1
454 * ? Tool-returned value different from -1, 0, 1, 2, or 3. This is it.
456 * Special proviso: If first_line->flags has CF_CHANGES set on entry, then
457 * that will cause things to behave like a change was made since entering
458 * this function.
461 conf_scroll_screen(struct pine *ps, OPT_SCREEN_S *screen, CONF_S *start_line, char *title, char *pdesc, int multicol, int *pos)
463 char tmp[MAXPATH+1];
464 char *utf8str;
465 UCS ch = 'x';
466 int cmd, i, j, done = 0, changes = 0;
467 int retval = 0;
468 int km_popped = 0, stay_in_col = 0;
469 struct key_menu *km = NULL;
470 CONF_S *ctmpa = NULL, *ctmpb = NULL;
471 Pos cursor_pos;
472 OtherMenu what_keymenu = FirstMenu;
473 void (*prev_redrawer)(void);
475 dprint((7, "conf_scroll_screen()\n"));
477 if(BODY_LINES(ps) < 1){
478 q_status_message(SM_ORDER | SM_DING, 3, 3, _("Screen too small"));
479 return(0);
482 if(screen && screen->ro_warning)
483 q_status_message1(SM_ORDER, 1, 3,
484 /* TRANSLATORS: "Config file not changeable," is what replaces the %s */
485 _("%s can't change options or settings"),
486 ps_global->restricted ? "Alpine demo"
487 : _("Config file not changeable,"));
489 screen->current = start_line;
490 if(start_line && start_line->flags & CF_CHANGES)
491 changes++;
493 opt_screen = screen;
494 ps->mangled_screen = 1;
495 ps->redrawer = option_screen_redrawer;
497 while(!done){
498 ps->user_says_cancel = 0;
499 if(km_popped){
500 km_popped--;
501 if(km_popped == 0){
502 clearfooter(ps);
503 ps->mangled_body = 1;
507 if(ps->mangled_screen){
508 ps->mangled_header = 1;
509 ps->mangled_footer = 1;
510 ps->mangled_body = 1;
511 ps->mangled_screen = 0;
514 /*----------- Check for new mail -----------*/
515 if(new_mail(0, NM_TIMING(ch), NM_STATUS_MSG | NM_DEFER_SORT) >= 0)
516 ps->mangled_header = 1;
518 if(ps->mangled_header){
519 set_titlebar(title, ps->mail_stream,
520 ps->context_current,
521 ps->cur_folder, ps->msgmap, 1, FolderName, 0, 0, NULL);
522 ps->mangled_header = 0;
525 update_option_screen(ps, screen, &cursor_pos);
527 if(F_OFF(F_SHOW_CURSOR, ps)){
528 cursor_pos.row = ps->ttyo->screen_rows - FOOTER_ROWS(ps);
529 cursor_pos.col = 0;
532 /*---- This displays new mail notification, or errors ---*/
533 if(km_popped){
534 FOOTER_ROWS(ps) = 3;
535 mark_status_unknown();
538 display_message(ch);
539 if(km_popped){
540 FOOTER_ROWS(ps) = 1;
541 mark_status_unknown();
544 if(ps->mangled_footer || km != screen->current->keymenu){
545 bitmap_t bitmap;
547 setbitmap(bitmap);
549 ps->mangled_footer = 0;
550 km = screen->current->keymenu;
552 if(multicol &&
553 (F_OFF(F_ARROW_NAV, ps_global) ||
554 F_ON(F_RELAXED_ARROW_NAV, ps_global))){
555 menu_clear_binding(km, KEY_LEFT);
556 menu_clear_binding(km, KEY_RIGHT);
557 menu_clear_binding(km, KEY_UP);
558 menu_clear_binding(km, KEY_DOWN);
559 menu_add_binding(km, KEY_UP, MC_CHARUP);
560 menu_add_binding(km, KEY_DOWN, MC_CHARDOWN);
561 menu_add_binding(km, KEY_LEFT, MC_PREVITEM);
562 menu_add_binding(km, ctrl('B'), MC_PREVITEM);
563 menu_add_binding(km, KEY_RIGHT, MC_NEXTITEM);
564 menu_add_binding(km, ctrl('F'), MC_NEXTITEM);
566 else{
567 menu_clear_binding(km, KEY_LEFT);
568 menu_clear_binding(km, KEY_RIGHT);
569 menu_clear_binding(km, KEY_UP);
570 menu_clear_binding(km, KEY_DOWN);
573 * Fix up arrow nav mode if necessary...
575 if(F_ON(F_ARROW_NAV, ps_global)){
576 int cmd;
578 if((cmd = menu_clear_binding(km, '<')) != MC_UNKNOWN){
579 menu_add_binding(km, '<', cmd);
580 menu_add_binding(km, KEY_LEFT, cmd);
583 if((cmd = menu_clear_binding(km, '>')) != MC_UNKNOWN){
584 menu_add_binding(km, '>', cmd);
585 menu_add_binding(km, KEY_RIGHT, cmd);
588 if((cmd = menu_clear_binding(km, 'p')) != MC_UNKNOWN){
589 menu_add_binding(km, 'p', cmd);
590 menu_add_binding(km, KEY_UP, cmd);
593 if((cmd = menu_clear_binding(km, 'n')) != MC_UNKNOWN){
594 menu_add_binding(km, 'n', cmd);
595 menu_add_binding(km, KEY_DOWN, cmd);
600 if(km_popped){
601 FOOTER_ROWS(ps) = 3;
602 clearfooter(ps);
605 draw_keymenu(km, bitmap, ps->ttyo->screen_cols,
606 1-FOOTER_ROWS(ps), 0, what_keymenu);
607 what_keymenu = SameMenu;
609 if(km_popped){
610 FOOTER_ROWS(ps) = 1;
611 mark_keymenu_dirty();
615 MoveCursor(cursor_pos.row, cursor_pos.col);
616 #ifdef MOUSE
617 mouse_in_content(KEY_MOUSE, -1, -1, 0, 0); /* prime the handler */
618 register_mfunc(mouse_in_content, HEADER_ROWS(ps_global), 0,
619 ps_global->ttyo->screen_rows -(FOOTER_ROWS(ps_global)+1),
620 ps_global->ttyo->screen_cols);
621 #endif
622 #ifdef _WINDOWS
623 mswin_setscrollcallback(config_scroll_callback);
624 #endif
625 /*------ Read the command from the keyboard ----*/
626 ch = READ_COMMAND(&utf8str);
627 #ifdef MOUSE
628 clear_mfunc(mouse_in_content);
629 #endif
630 #ifdef _WINDOWS
631 mswin_setscrollcallback(NULL);
632 #endif
634 cmd = menu_command(ch, km);
636 if(km_popped)
637 switch(cmd){
638 case MC_NONE:
639 case MC_OTHER:
640 case MC_RESIZE:
641 case MC_REPAINT:
642 km_popped++;
643 break;
645 default:
646 clearfooter(ps);
647 break;
650 switch(cmd){
651 case MC_OTHER :
652 what_keymenu = NextMenu;
653 ps->mangled_footer = 1;
654 break;
656 case MC_HELP: /* help! */
657 if(FOOTER_ROWS(ps) == 1 && km_popped == 0){
658 km_popped = 2;
659 ps->mangled_footer = 1;
660 break;
663 if(screen->current->help != NO_HELP){
664 prev_redrawer = ps_global->redrawer;
665 helper(screen->current->help,
666 (screen->current->help_title)
667 ? screen->current->help_title
668 : CONFIG_SCREEN_HELP_TITLE,
669 HLPD_SIMPLE);
670 ps_global->redrawer = prev_redrawer;
671 ps->mangled_screen = 1;
673 else
674 q_status_message(SM_ORDER,0,3,_("No help yet."));
676 break;
679 case MC_NEXTITEM: /* next list element */
680 case MC_CHARDOWN:
681 stay_in_col = 0;
682 if(screen->current->flags & CF_DOUBLEVAR){
683 /* if going from col1 to col2, it's simple */
684 if(!(screen->current->flags & CF_VAR2) && cmd == MC_NEXTITEM){
685 screen->current->flags |= CF_VAR2;
686 break;
689 /* otherwise we fall through to normal next */
690 stay_in_col = (screen->current->flags & CF_VAR2 &&
691 cmd == MC_CHARDOWN);
692 screen->current->flags &= ~CF_VAR2;
695 for(ctmpa = next_confline(screen->current), i = 1;
696 ctmpa && (ctmpa->flags & CF_NOSELECT);
697 ctmpa = next_confline(ctmpa), i++)
700 if(ctmpa){
701 screen->current = ctmpa;
702 if(screen->current->flags & CF_DOUBLEVAR && stay_in_col)
703 screen->current->flags |= CF_VAR2;
705 if(cmd == MC_CHARDOWN){
706 for(ctmpa = screen->top_line,
707 j = BODY_LINES(ps) - 1 - HS_MARGIN(ps);
708 j > 0 && ctmpa && ctmpa != screen->current;
709 ctmpa = next_confline(ctmpa), j--)
712 if(!j && ctmpa){
713 for(i = 0;
714 ctmpa && ctmpa != screen->current;
715 ctmpa = next_confline(ctmpa), i++)
718 if(i)
719 config_scroll_up(i);
723 else{
725 * Scroll screen a bit so we show the non-selectable
726 * lines at the bottom.
729 /* set ctmpa to the bottom line on the screen */
730 for(ctmpa = screen->top_line, j = BODY_LINES(ps) - 1;
731 j > 0 && ctmpa;
732 ctmpa = next_confline(ctmpa), j--)
735 i = 0;
736 if(ctmpa){
737 for(ctmpa = next_confline(ctmpa);
738 ctmpa &&
739 (ctmpa->flags & (CF_NOSELECT | CF_B_LINE)) ==
740 CF_NOSELECT;
741 ctmpa = next_confline(ctmpa), i++)
745 if(i)
746 config_scroll_up(i);
747 else
748 q_status_message(SM_ORDER,0,1, _("Already at end of screen"));
751 break;
753 case MC_PREVITEM: /* prev list element */
754 case MC_CHARUP:
755 stay_in_col = 0;
756 if(screen->current->flags & CF_DOUBLEVAR){
757 if(screen->current->flags & CF_VAR2 && cmd == MC_PREVITEM){
758 screen->current->flags &= ~CF_VAR2;
759 break;
762 /* otherwise we fall through to normal prev */
763 stay_in_col = (!(screen->current->flags & CF_VAR2) &&
764 cmd == MC_CHARUP);
765 screen->current->flags &= ~CF_VAR2;
767 else if(cmd == MC_CHARUP)
768 stay_in_col = 1;
770 ctmpa = screen->current;
771 i = 0;
773 if(ctmpa == config_top_scroll(ps, screen->top_line))
774 i = 1;
775 else if(i)
776 i++;
777 while((ctmpa = prev_confline(ctmpa))
778 && (ctmpa->flags&CF_NOSELECT));
780 if(ctmpa){
781 screen->current = ctmpa;
782 if(screen->current->flags & CF_DOUBLEVAR && !stay_in_col)
783 screen->current->flags |= CF_VAR2;
785 if((cmd == MC_CHARUP) && i)
786 config_scroll_down(i);
788 else
789 q_status_message(SM_ORDER, 0, 1,
790 _("Already at start of screen"));
792 break;
794 case MC_PAGEDN: /* page forward */
795 screen->current->flags &= ~CF_VAR2;
796 for(ctmpa = screen->top_line, i = BODY_LINES(ps);
797 i > 0 && ctmpa;
798 ctmpb = ctmpa, ctmpa = next_confline(ctmpa), i--)
801 if(ctmpa){ /* first line off bottom of screen */
802 ctmpb = ctmpa;
803 ps->mangled_body = 1;
804 /* find first selectable line on next page */
805 for(screen->top_line = ctmpa;
806 ctmpa && (ctmpa->flags & CF_NOSELECT);
807 ctmpa = next_confline(ctmpa))
811 * No selectable lines on next page. Slide up to first
812 * selectable.
814 if(!ctmpa){
815 for(ctmpa = prev_confline(ctmpb);
816 ctmpa && (ctmpa->flags & CF_NOSELECT);
817 ctmpa = prev_confline(ctmpa))
820 if(ctmpa)
821 screen->top_line = ctmpa;
824 else{ /* on last screen */
825 /* just move current down to last entry on screen */
826 if(ctmpb){ /* last line of data */
827 for(ctmpa = ctmpb, i = BODY_LINES(ps);
828 i > 0 && ctmpa && (ctmpa->flags & CF_NOSELECT);
829 ctmpa = prev_confline(ctmpa), i--)
832 if(ctmpa == screen->current){
833 q_status_message(SM_ORDER,0,1,
834 _("Already at end of screen"));
835 goto no_down;
838 ps->mangled_body = 1;
842 if(ctmpa)
843 screen->current = ctmpa;
844 no_down:
845 break;
847 case MC_PAGEUP: /* page backward */
848 ps->mangled_body = 1;
849 screen->current->flags &= ~CF_VAR2;
850 if(!(ctmpa=prev_confline(screen->top_line)))
851 ctmpa = screen->current;
853 for(i = BODY_LINES(ps) - 1;
854 i > 0 && prev_confline(ctmpa);
855 i--, ctmpa = prev_confline(ctmpa))
858 for(screen->top_line = ctmpa;
859 ctmpa && (ctmpa->flags & CF_NOSELECT);
860 ctmpa = next_confline(ctmpa))
863 if(ctmpa){
864 if(ctmpa == screen->current){
866 * We get to here if there was nothing selectable on
867 * the previous page. There still may be something
868 * selectable further back than the previous page,
869 * so look for that.
871 for(ctmpa = prev_confline(screen->top_line);
872 ctmpa && (ctmpa->flags & CF_NOSELECT);
873 ctmpa = prev_confline(ctmpa))
876 if(!ctmpa){
877 ctmpa = screen->current;
878 q_status_message(SM_ORDER, 0, 1,
879 _("Already at start of screen"));
883 screen->current = ctmpa;
886 break;
888 #ifdef MOUSE
889 case MC_MOUSE:
891 MOUSEPRESS mp;
893 mouse_get_last (NULL, &mp);
894 mp.row -= HEADER_ROWS(ps);
895 ctmpa = screen->top_line;
897 while (mp.row && ctmpa != NULL) {
898 --mp.row;
899 ctmpa = ctmpa->next;
902 if (ctmpa != NULL && !(ctmpa->flags & CF_NOSELECT)){
903 if(screen->current->flags & CF_DOUBLEVAR)
904 screen->current->flags &= ~CF_VAR2;
906 screen->current = ctmpa;
908 if(screen->current->flags & CF_DOUBLEVAR &&
909 mp.col >= screen->current->val2offset)
910 screen->current->flags |= CF_VAR2;
912 update_option_screen(ps, screen, &cursor_pos);
914 if(mp.button == M_BUTTON_LEFT && mp.doubleclick){
916 if(screen->current->tool){
917 unsigned flags;
918 int default_cmd;
920 flags = screen->current->flags;
921 flags |= (changes ? CF_CHANGES : 0);
923 default_cmd = menu_command(ctrl('M'), km);
924 switch(i=(*screen->current->tool)(ps, default_cmd,
925 &screen->current, flags)){
926 case -1:
927 case 0:
928 break;
930 case 1:
931 changes = 1;
932 break;
934 case 2:
935 retval = changes;
936 done++;
937 break;
939 case 3:
940 retval = 1;
941 done++;
942 break;
944 default:
945 retval = i;
946 done++;
947 break;
951 #ifdef _WINDOWS
952 else if(mp.button == M_BUTTON_RIGHT) {
953 MPopup other_popup[20];
954 int n = -1, cmd, i;
955 struct key_menu *sckm = screen->current->keymenu; /* only for popup */
957 if((cmd = menu_command(ctrl('M'), sckm)) != MC_UNKNOWN){
958 i = menu_binding_index(sckm, cmd);
959 other_popup[++n].type = tQueue;
960 other_popup[n].label.style = lNormal;
961 other_popup[n].label.string = sckm->keys[i].label;
962 other_popup[n].data.val = ctrl('M');
964 else if((cmd = menu_command('>', sckm)) != MC_UNKNOWN){
965 i = menu_binding_index(sckm, cmd);
966 other_popup[++n].type = tQueue;
967 other_popup[n].label.style = lNormal;
968 other_popup[n].label.string = sckm->keys[i].label;
969 other_popup[n].data.val = '>';
972 if(((i = menu_binding_index(sckm, MC_RGB1)) >= 0) ||
973 ((i = menu_binding_index(sckm, MC_RGB2)) >= 0)){
974 other_popup[++n].type = tQueue;
975 other_popup[n].label.style = lNormal;
976 other_popup[n].label.string = sckm->keys[i].label;
977 other_popup[n].data.val =
978 sckm->keys[i].bind.ch[0];
981 if((cmd = menu_command('<', sckm)) != MC_UNKNOWN){
982 i = menu_binding_index(sckm, cmd);
983 other_popup[++n].type = tQueue;
984 other_popup[n].label.style = lNormal;
985 other_popup[n].label.string = sckm->keys[i].label;
986 other_popup[n].data.val = '<';
988 else if((i = menu_binding_index(sckm, MC_EXIT)) >= 0){
989 other_popup[++n].type = tQueue;
990 other_popup[n].label.style = lNormal;
991 other_popup[n].label.string = sckm->keys[i].label;
992 other_popup[n].data.val =
993 sckm->keys[i].bind.ch[0];
996 if((i = menu_binding_index(sckm, MC_HELP)) >= 0){
997 if(n > 0)
998 other_popup[++n].type = tSeparator;
1000 other_popup[++n].type = tQueue;
1001 other_popup[n].label.style = lNormal;
1002 other_popup[n].label.string = sckm->keys[i].label;
1003 other_popup[n].data.val = sckm->keys[i].bind.ch[0];
1006 if(n > 0){
1007 other_popup[++n].type = tTail;
1008 mswin_popup(other_popup);
1012 else if(mp.button == M_BUTTON_RIGHT) {
1013 MPopup other_popup[20];
1014 int n = -1, cmd, i;
1015 struct key_menu *sckm = screen->current->keymenu; /* only for popup */
1017 if((cmd = menu_command('<', sckm)) != MC_UNKNOWN){
1018 i = menu_binding_index(sckm, cmd);
1019 other_popup[++n].type = tQueue;
1020 other_popup[n].label.style = lNormal;
1021 other_popup[n].label.string = sckm->keys[i].label;
1022 other_popup[n].data.val = '<';
1024 else if((i = menu_binding_index(sckm, MC_EXIT)) >= 0){
1025 other_popup[++n].type = tQueue;
1026 other_popup[n].label.style = lNormal;
1027 other_popup[n].label.string = sckm->keys[i].label;
1028 other_popup[n].data.val = sckm->keys[i].bind.ch[0];
1031 other_popup[++n].type = tTail;
1033 if(n > 0)
1034 mswin_popup(other_popup);
1035 #endif
1038 break;
1039 #endif
1041 case MC_PRINTTXT: /* print screen */
1042 print_option_screen(screen, pdesc ? pdesc : "");
1043 break;
1045 case MC_WHEREIS: /* whereis */
1046 /*--- get string ---*/
1047 {int rc, found = 0;
1048 #define FOUND_IT 0x01
1049 #define FOUND_CURRENT 0x02
1050 #define FOUND_WRAPPED 0x04
1051 #define FOUND_NOSELECT 0x08
1052 #define FOUND_ABOVE 0x10
1053 char *result = NULL, buf[64];
1054 char *p, last[64];
1055 static HISTORY_S *history = NULL;
1056 HelpType help;
1057 static ESCKEY_S ekey[] = {
1058 {0, 0, "", ""},
1059 /* TRANSLATORS: go to Top of screen */
1060 {ctrl('Y'), 10, "^Y", N_("Top")},
1061 {ctrl('V'), 11, "^V", N_("Bottom")},
1062 {KEY_UP, 30, "", ""},
1063 {KEY_DOWN, 31, "", ""},
1064 {-1, 0, NULL, NULL}};
1065 #define KU_WI (3) /* index of KEY_UP */
1067 init_hist(&history, HISTSIZE);
1068 last[0] = '\0';
1069 if((p = get_prev_hist(history, "", 0, NULL)) != NULL){
1070 strncpy(last, p, sizeof(last));
1071 last[sizeof(last)-1] = '\0';
1074 ps->mangled_footer = 1;
1075 buf[0] = '\0';
1076 snprintf(tmp, sizeof(tmp), "Word to find %s%s%s: ",
1077 (last[0]) ? "[" : "",
1078 (last[0]) ? last : "",
1079 (last[0]) ? "]" : "");
1080 tmp[sizeof(tmp)-1] = '\0';
1081 help = NO_HELP;
1082 while(1){
1083 int flags = OE_APPEND_CURRENT;
1086 * 2 is really 1 because there will be one real entry and
1087 * one entry of "" because of the get_prev_hist above.
1089 if(items_in_hist(history) > 2){
1090 ekey[KU_WI].name = HISTORY_UP_KEYNAME;
1091 ekey[KU_WI].label = HISTORY_KEYLABEL;
1092 ekey[KU_WI+1].name = HISTORY_DOWN_KEYNAME;
1093 ekey[KU_WI+1].label = HISTORY_KEYLABEL;
1095 else{
1096 ekey[KU_WI].name = "";
1097 ekey[KU_WI].label = "";
1098 ekey[KU_WI+1].name = "";
1099 ekey[KU_WI+1].label = "";
1102 rc = optionally_enter(buf,-FOOTER_ROWS(ps),0,sizeof(buf),
1103 tmp,ekey,help,&flags);
1104 if(rc == 3)
1105 help = help == NO_HELP ? h_config_whereis : NO_HELP;
1106 else if(rc == 30){
1107 if((p = get_prev_hist(history, buf, 0, NULL)) != NULL){
1108 strncpy(buf, p, sizeof(buf));
1109 buf[sizeof(buf)-1] = '\0';
1111 else
1112 Writechar(BELL, 0);
1114 continue;
1116 else if(rc == 31){
1117 if((p = get_next_hist(history, buf, 0, NULL)) != NULL){
1118 strncpy(buf, p, sizeof(buf));
1119 buf[sizeof(buf)-1] = '\0';
1121 else
1122 Writechar(BELL, 0);
1124 continue;
1126 else if(rc == 0 || rc == 1 || rc == 10 || rc == 11 || !buf[0]){
1127 if(rc == 0 && !buf[0] && last[0])
1128 strncpy(buf, last, 64);
1130 break;
1134 screen->current->flags &= ~CF_VAR2;
1135 if(rc == 0 && buf[0]){
1136 CONF_S *started_here;
1138 save_hist(history, buf, 0, NULL);
1140 ch = KEY_DOWN;
1141 ctmpa = screen->current;
1143 * Skip over the unselectable lines of this "item"
1144 * before starting search so that we don't find the
1145 * same one again.
1147 while((ctmpb = next_confline(ctmpa)) &&
1148 (ctmpb->flags & CF_NOSELECT) &&
1149 !(ctmpb->flags & CF_STARTITEM))
1150 ctmpa = ctmpb;
1152 started_here = next_confline(ctmpa);
1153 while((ctmpa = next_confline(ctmpa)) != NULL)
1154 if(srchstr(ctmpa->varname, buf)
1155 || srchstr(ctmpa->value, buf)){
1157 found = FOUND_IT;
1159 * If this line is not selectable, back up to the
1160 * previous selectable line, but not past the
1161 * start of this "entry".
1163 if(ctmpa->flags & CF_NOSELECT)
1164 found |= FOUND_NOSELECT;
1166 while((ctmpa->flags & CF_NOSELECT) &&
1167 !(ctmpa->flags & CF_STARTITEM) &&
1168 (ctmpb = prev_confline(ctmpa)))
1169 ctmpa = ctmpb;
1172 * If that isn't selectable, better search forward
1173 * for something that is.
1175 while((ctmpa->flags & CF_NOSELECT) &&
1176 (ctmpb = next_confline(ctmpa))){
1177 ctmpa = ctmpb;
1178 found |= FOUND_ABOVE;
1182 * If that still isn't selectable, better search
1183 * backwards for something that is.
1185 while((ctmpa->flags & CF_NOSELECT) &&
1186 (ctmpb = prev_confline(ctmpa))){
1187 ctmpa = ctmpb;
1188 found &= ~FOUND_ABOVE;
1191 break;
1194 if(!found){
1195 found = FOUND_WRAPPED;
1196 ctmpa = first_confline(screen->current);
1198 while(ctmpa != started_here)
1199 if(srchstr(ctmpa->varname, buf)
1200 || srchstr(ctmpa->value, buf)){
1202 found |= FOUND_IT;
1203 if(ctmpa->flags & CF_NOSELECT)
1204 found |= FOUND_NOSELECT;
1206 while((ctmpa->flags & CF_NOSELECT) &&
1207 !(ctmpa->flags & CF_STARTITEM) &&
1208 (ctmpb = prev_confline(ctmpa)))
1209 ctmpa = ctmpb;
1211 while((ctmpa->flags & CF_NOSELECT) &&
1212 (ctmpb = next_confline(ctmpa))){
1213 ctmpa = ctmpb;
1214 found |= FOUND_ABOVE;
1217 if(ctmpa == screen->current)
1218 found |= FOUND_CURRENT;
1220 break;
1222 else
1223 ctmpa = next_confline(ctmpa);
1226 else if(rc == 10){
1227 screen->current = first_confline(screen->current);
1228 if(screen->current && screen->current->flags & CF_NOSELECT){
1229 for(ctmpa = next_confline(screen->current);
1230 ctmpa && (ctmpa->flags & CF_NOSELECT);
1231 ctmpa = next_confline(ctmpa))
1234 if(ctmpa)
1235 screen->current = ctmpa;
1238 /* TRANSLATORS: Searched to ... is the result of the search, searched
1239 to top means the search went past the bottom of the screen and
1240 wrapped back around to the top. */
1241 result = _("Searched to top");
1243 else if(rc == 11){
1244 screen->current = last_confline(screen->current);
1245 if(screen->current && screen->current->flags & CF_NOSELECT){
1246 for(ctmpa = prev_confline(screen->current);
1247 ctmpa && (ctmpa->flags & CF_NOSELECT);
1248 ctmpa = prev_confline(ctmpa))
1251 if(ctmpa)
1252 screen->current = ctmpa;
1255 result = _("Searched to bottom");
1257 else
1258 result = _("WhereIs cancelled");
1260 if((found & FOUND_IT) && ctmpa){
1261 strncpy(last, buf, 64);
1262 result =
1263 (found & FOUND_CURRENT && found & FOUND_WRAPPED && found & FOUND_NOSELECT)
1264 ? _("Current item contains the only match")
1265 : (found & FOUND_CURRENT && found & FOUND_WRAPPED)
1266 ? _("Current line contains the only match")
1267 : (found & FOUND_NOSELECT && found & FOUND_WRAPPED)
1268 ? ((found & FOUND_ABOVE)
1269 ? _("Search wrapped: word found in text above current line")
1270 : _("Search wrapped: word found in text below current line"))
1271 : (found & FOUND_WRAPPED)
1272 ? _("Search wrapped to beginning: word found")
1273 : (found & FOUND_NOSELECT)
1274 ? ((found & FOUND_ABOVE)
1275 ? _("Word found in text above current line")
1276 : _("Word found in text below current line"))
1277 : _("Word found");
1278 screen->current = ctmpa;
1281 q_status_message(SM_ORDER,0,3,result ? result : _("Word not found"));
1284 break;
1286 case MC_HOMEKEY:
1287 screen->current = first_confline(screen->current);
1288 if(screen->current && screen->current->flags & CF_NOSELECT){
1289 for(ctmpa = next_confline(screen->current);
1290 ctmpa && (ctmpa->flags & CF_NOSELECT);
1291 ctmpa = next_confline(ctmpa))
1294 if(ctmpa)
1295 screen->current = ctmpa;
1298 q_status_message(SM_ORDER,0,3, _("Moved to top"));
1299 break;
1301 case MC_ENDKEY:
1302 screen->current = last_confline(screen->current);
1303 if(screen->current && screen->current->flags & CF_NOSELECT){
1304 for(ctmpa = prev_confline(screen->current);
1305 ctmpa && (ctmpa->flags & CF_NOSELECT);
1306 ctmpa = prev_confline(ctmpa))
1309 if(ctmpa)
1310 screen->current = ctmpa;
1313 q_status_message(SM_ORDER,0,3, _("Moved to bottom"));
1314 break;
1316 case MC_REPAINT: /* redraw the display */
1317 case MC_RESIZE:
1318 ClearScreen();
1319 ps->mangled_screen = 1;
1320 if(pos){
1321 *pos = get_confline_number(screen->current);
1322 done++;
1323 retval = 0;
1325 break;
1327 default:
1328 if(screen && screen->ro_warning){
1329 if(cmd == MC_EXIT){
1330 retval = 0;
1331 done++;
1333 else
1334 q_status_message1(SM_ORDER|SM_DING, 1, 3,
1335 _("%s can't change options or settings"),
1336 ps_global->restricted ? "Alpine demo"
1337 : _("Config file not changeable,"));
1339 else if(screen->current->tool){
1340 unsigned flags;
1342 flags = screen->current->flags;
1343 flags |= (changes ? CF_CHANGES : 0);
1345 switch(i=(*screen->current->tool)(ps, cmd,
1346 &screen->current, flags)){
1347 case -1:
1348 q_status_message2(SM_ORDER, 0, 2,
1349 /* TRANSLATORS: Command <command letter> not defined here.
1350 Leave the trailing %s which might be a parenthetical
1351 remark. */
1352 _("Command \"%s\" not defined here.%s"),
1353 pretty_command(ch),
1354 F_ON(F_BLANK_KEYMENU,ps) ? "" : " See key menu below.");
1355 break;
1357 case 0:
1358 break;
1360 case 1:
1361 changes = 1;
1362 break;
1364 case 2:
1365 retval = changes;
1366 done++;
1367 break;
1369 case 3:
1370 retval = 1;
1371 done++;
1372 break;
1374 default:
1375 retval = i;
1376 done++;
1377 break;
1381 break;
1383 case MC_UTF8:
1384 bogus_utf8_command(utf8str, "?");
1385 break;
1387 case MC_NONE: /* simple timeout */
1388 break;
1392 screen->current = first_confline(screen->current);
1393 free_conflines(&screen->current);
1394 return(retval);
1401 void
1402 config_scroll_up(long int n)
1404 CONF_S *ctmp = opt_screen->top_line;
1405 int cur_found = 0;
1407 if(n < 0)
1408 config_scroll_down(-n);
1409 else if(n){
1410 for(; n>0 && ctmp->next; n--){
1411 ctmp = next_confline(ctmp);
1412 if(prev_confline(ctmp) == opt_screen->current)
1413 cur_found++;
1416 opt_screen->top_line = ctmp;
1417 ps_global->mangled_body = 1;
1418 if(cur_found){
1419 for(ctmp = opt_screen->top_line;
1420 ctmp && (ctmp->flags & CF_NOSELECT);
1421 ctmp = next_confline(ctmp))
1424 if(ctmp)
1425 opt_screen->current = opt_screen->prev = ctmp;
1426 else {
1427 while(opt_screen->top_line->flags & CF_NOSELECT)
1428 opt_screen->top_line = prev_confline(opt_screen->top_line);
1429 opt_screen->current = opt_screen->prev = opt_screen->top_line;
1437 * config_scroll_down -
1439 void
1440 config_scroll_down(long int n)
1442 CONF_S *ctmp = opt_screen->top_line, *last_sel = NULL;
1443 int i;
1445 if(n < 0)
1446 config_scroll_up(-n);
1447 else if(n){
1448 for(; n>0 && ctmp->prev; n--)
1449 ctmp = prev_confline(ctmp);
1451 opt_screen->top_line = ctmp;
1452 ps_global->mangled_body = 1;
1453 for(ctmp = opt_screen->top_line, i = BODY_LINES(ps_global);
1454 i > 0 && ctmp && ctmp != opt_screen->current;
1455 ctmp = next_confline(ctmp), i--)
1456 if(!(ctmp->flags & CF_NOSELECT))
1457 last_sel = ctmp;
1459 if(!i && last_sel)
1460 opt_screen->current = opt_screen->prev = last_sel;
1466 * config_scroll_to_pos -
1468 void
1469 config_scroll_to_pos(long int n)
1471 CONF_S *ctmp;
1473 for(ctmp = first_confline(opt_screen->current);
1474 n && ctmp && ctmp != opt_screen->top_line;
1475 ctmp = next_confline(ctmp), n--)
1478 if(n == 0)
1479 while(ctmp && ctmp != opt_screen->top_line)
1480 if((ctmp = next_confline(ctmp)) != NULL)
1481 n--;
1483 config_scroll_up(n);
1488 * config_top_scroll - return pointer to the
1490 CONF_S *
1491 config_top_scroll(struct pine *ps, CONF_S *topline)
1493 int i;
1494 CONF_S *ctmp;
1496 for(ctmp = topline, i = HS_MARGIN(ps);
1497 ctmp && i;
1498 ctmp = next_confline(ctmp), i--)
1501 return(ctmp ? ctmp : topline);
1506 text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
1508 return(text_toolit(ps, cmd, cl, flags, 0));
1513 * simple text variable handler
1515 * note, things get a little involved due to the
1516 * screen struct <--> variable mapping. (but, once its
1517 * running it shouldn't need changing ;).
1519 * look_for_backslash == 1 means that backslash is an escape character.
1520 * In particular, \, can be used to put a literal comma
1521 * into a value. The value will still have the backslash
1522 * in it, but the comma after the backslash won't be treated
1523 * as an item separator.
1525 * returns: -1 on unrecognized cmd, 0 if no change, 1 if change
1526 * returns what conf_exit_cmd returns for exit command.
1529 text_toolit(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags, int look_for_backslash)
1531 char prompt[81], *sval, *tmp, *swap_val, **newval = NULL;
1532 char *pval, **apval, **lval, ***alval;
1533 char *olddefval = NULL;
1534 int rv = 0, skip_to_next = 0, after = 0, i = 4, j, k;
1535 int lowrange, hirange, incr, oeflags, oebufsize;
1536 int numval, repeat_key = 0;
1537 int curindex, previndex, nextindex, deefault;
1538 HelpType help;
1539 ESCKEY_S ekey[6];
1541 if((*cl)->var->is_list){
1542 lval = LVAL((*cl)->var, ew);
1543 alval = ALVAL((*cl)->var, ew);
1545 else{
1546 pval = PVAL((*cl)->var, ew);
1547 apval = APVAL((*cl)->var, ew);
1550 oebufsize = 6*MAXPATH;
1551 sval = (char *) fs_get(oebufsize*sizeof(char));
1552 sval[0] = '\0';
1554 if(flags&CF_NUMBER){ /* only happens if !is_list */
1555 incr = 1;
1556 if((*cl)->var == &ps->vars[V_FILLCOL]){
1557 lowrange = 1;
1558 hirange = MAX_FILLCOL;
1560 else if((*cl)->var == &ps->vars[V_SLEEP]){
1561 lowrange = 60;
1562 hirange = 600;
1564 else if((*cl)->var == &ps->vars[V_OVERLAP]
1565 || (*cl)->var == &ps->vars[V_MARGIN]){
1566 lowrange = 0;
1567 hirange = 20;
1569 else if((*cl)->var == &ps->vars[V_QUOTE_SUPPRESSION]){
1570 lowrange = -(Q_SUPP_LIMIT-1);
1571 hirange = 1000;
1573 else if((*cl)->var == &ps->vars[V_MAXREMSTREAM]){
1574 lowrange = 0;
1575 hirange = 15;
1577 else if((*cl)->var == &ps->vars[V_STATUS_MSG_DELAY]){
1578 lowrange = -10;
1579 hirange = 30;
1581 else if((*cl)->var == &ps->vars[V_ACTIVE_MSG_INTERVAL]){
1582 lowrange = 0;
1583 hirange = 20;
1585 else if((*cl)->var == &ps->vars[V_MAILCHECK] ||
1586 (*cl)->var == &ps->vars[V_INCCHECKINTERVAL] ||
1587 (*cl)->var == &ps->vars[V_INC2NDCHECKINTERVAL] ||
1588 (*cl)->var == &ps->vars[V_MAILCHECKNONCURR]){
1589 lowrange = 0;
1590 hirange = 25000;
1591 incr = 15;
1593 else if((*cl)->var == &ps->vars[V_DEADLETS]){
1594 lowrange = 0;
1595 hirange = 9;
1597 else if((*cl)->var == &ps->vars[V_NMW_WIDTH]){
1598 lowrange = 20;
1599 hirange = MAX_SCREEN_COLS;
1601 else if((*cl)->var == score_act_global_ptr){
1602 lowrange = -100;
1603 hirange = 100;
1605 else if((*cl)->var == &ps->vars[V_TCPOPENTIMEO] ||
1606 (*cl)->var == &ps->vars[V_TCPREADWARNTIMEO] ||
1607 (*cl)->var == &ps->vars[V_TCPQUERYTIMEO]){
1608 lowrange = 5;
1609 hirange = 1000;
1611 else if((*cl)->var == &ps->vars[V_TCPWRITEWARNTIMEO] ||
1612 (*cl)->var == &ps->vars[V_RSHOPENTIMEO] ||
1613 (*cl)->var == &ps->vars[V_SSHOPENTIMEO] ||
1614 (*cl)->var == &ps->vars[V_USERINPUTTIMEO]){
1615 lowrange = 0;
1616 hirange = 1000;
1618 else if((*cl)->var == &ps->vars[V_INCCHECKTIMEO]){
1619 lowrange = 1;
1620 hirange = 1000;
1622 else if((*cl)->var == &ps->vars[V_MAILDROPCHECK]){
1623 lowrange = 0;
1624 hirange = 1000000;
1625 incr = 60;
1627 else if((*cl)->var == &ps->vars[V_NNTPRANGE]){
1628 lowrange = 0;
1629 hirange = 1000000;
1630 incr = 100;
1632 else if((*cl)->var == &ps->vars[V_REMOTE_ABOOK_VALIDITY]){
1633 lowrange = -1;
1634 hirange = 25000;
1636 else if((*cl)->var == &ps->vars[V_REMOTE_ABOOK_HISTORY]){
1637 lowrange = 0;
1638 hirange = 100;
1640 else if((*cl)->var == cat_lim_global_ptr){
1641 lowrange = -1;
1642 hirange = 10000000;
1644 else{
1645 lowrange = 0;
1646 hirange = 25000;
1649 ekey[0].ch = -2;
1650 ekey[0].rval = 'x';
1651 ekey[0].name = "";
1652 ekey[0].label = "";
1653 ekey[1].ch = ctrl('P');
1654 ekey[1].rval = ctrl('P');
1655 ekey[1].name = "^P";
1656 ekey[1].label = N_("Decrease");
1657 ekey[2].ch = ctrl('N');
1658 ekey[2].rval = ctrl('N');
1659 ekey[2].name = "^N";
1660 ekey[2].label = N_("Increase");
1661 ekey[3].ch = KEY_DOWN;
1662 ekey[3].rval = ctrl('P');
1663 ekey[3].name = "";
1664 ekey[3].label = "";
1665 ekey[4].ch = KEY_UP;
1666 ekey[4].rval = ctrl('N');
1667 ekey[4].name = "";
1668 ekey[4].label = "";
1669 ekey[5].ch = -1;
1672 switch(cmd){
1673 case MC_ADD: /* add to list */
1674 if(fixed_var((*cl)->var, "add to", NULL)){
1675 break;
1677 else if(!(*cl)->var->is_list && pval){
1678 q_status_message(SM_ORDER, 3, 3,
1679 _("Only single value allowed. Use \"Change\"."));
1681 else{
1682 int maxwidth;
1683 char *p;
1685 if((*cl)->var->is_list
1686 && lval && lval[0] && lval[0][0]
1687 && (*cl)->value){
1688 char tmpval[101];
1689 /* regular add to an existing list */
1691 strncpy(tmpval, (*cl)->value, sizeof(tmpval));
1692 tmpval[sizeof(tmpval)-1] = '\0';
1693 removing_trailing_white_space(tmpval);
1695 /* 33 is the number of chars other than the value */
1696 maxwidth = MIN(80, ps->ttyo->screen_cols) - 15;
1697 k = MIN(18, MAX(maxwidth-33,0));
1698 if(utf8_width(tmpval) > k && k >= 3){
1699 (void) utf8_truncate(tmpval, k-3);
1700 strncat(tmpval, "...", sizeof(tmpval)-strlen(tmpval)-1);
1701 tmpval[sizeof(tmpval)-1] = '\0';
1704 utf8_snprintf(prompt, sizeof(prompt),
1705 _("Enter text to insert before \"%.*w\": "), k, tmpval);
1706 prompt[sizeof(prompt)-1] = '\0';
1708 else if((*cl)->var->is_list
1709 && !lval
1710 && (*cl)->var->current_val.l){
1711 /* Add to list which doesn't exist, but default does exist */
1712 ekey[0].ch = 'r';
1713 ekey[0].rval = 'r';
1714 ekey[0].name = "R";
1715 ekey[0].label = N_("Replace");
1716 ekey[1].ch = 'a';
1717 ekey[1].rval = 'a';
1718 ekey[1].name = "A";
1719 ekey[1].label = N_("Add To");
1720 ekey[2].ch = -1;
1721 strncpy(prompt, _("Replace or Add To default value ? "), sizeof(prompt));
1722 prompt[sizeof(prompt)-1] = '\0';
1723 switch(radio_buttons(prompt, -FOOTER_ROWS(ps), ekey, 'a', 'x',
1724 h_config_replace_add, RB_NORM)){
1725 case 'a':
1726 p = sval;
1727 for(j = 0; (*cl)->var->current_val.l[j]; j++){
1728 sstrncpy(&p, (*cl)->var->current_val.l[j], oebufsize-(p-sval));
1729 if(oebufsize-(p-sval) > 2){
1730 *p++ = ',';
1731 *p++ = ' ';
1734 if(oebufsize-(p-sval) > 0)
1735 *p = '\0';
1738 sval[oebufsize-1] = '\0';
1740 add_text:
1741 if(flags & CF_NUMBER)
1742 snprintf(prompt, sizeof(prompt), _("Enter the numeric text to be added : "));
1743 else
1744 snprintf(prompt, sizeof(prompt), _("Enter the text to be added : "));
1746 break;
1748 case 'r':
1749 replace_text:
1750 if(olddefval){
1751 strncpy(sval, olddefval, oebufsize);
1752 sval[oebufsize-1] = '\0';
1755 if(flags & CF_NUMBER)
1756 snprintf(prompt, sizeof(prompt), _("Enter the numeric replacement text : "));
1757 else
1758 snprintf(prompt, sizeof(prompt), _("Enter the replacement text : "));
1760 break;
1762 case 'x':
1763 i = 1;
1764 cmd_cancelled("Add");
1765 break;
1768 else{
1769 if(flags & CF_NUMBER)
1770 snprintf(prompt, sizeof(prompt), _("Enter the numeric text to be added : "));
1771 else
1772 snprintf(prompt, sizeof(prompt), _("Enter the text to be added : "));
1775 prompt[sizeof(prompt)-1] = '\0';
1777 ps->mangled_footer = 1;
1779 if(i == 1)
1780 break;
1782 help = NO_HELP;
1783 while(1){
1784 if((*cl)->var->is_list
1785 && lval && lval[0] && lval[0][0]
1786 && (*cl)->value){
1787 ekey[0].ch = ctrl('W');
1788 ekey[0].rval = 5;
1789 ekey[0].name = "^W";
1790 /* TRANSLATORS: Insert new item before current item */
1791 ekey[0].label = after ? N_("InsertBefore") : N_("InsertAfter");
1792 ekey[1].ch = -1;
1794 else if(!(flags&CF_NUMBER))
1795 ekey[0].ch = -1;
1797 oeflags = OE_APPEND_CURRENT;
1798 i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, oebufsize,
1799 prompt,
1800 (ekey[0].ch != -1) ? ekey : NULL,
1801 help, &oeflags);
1802 if(i == 0){
1803 rv = 1;
1804 if((*cl)->var->is_list)
1805 ps->mangled_body = 1;
1806 else
1807 ps->mangled_footer = 1;
1809 removing_leading_and_trailing_white_space(sval);
1811 * Coerce "" and <Empty Value> to empty string input.
1812 * Catch <No Value Set> as a substitute for deleting.
1814 if((*sval == '\"' && *(sval+1) == '\"' && *(sval+2) == '\0')
1815 || !struncmp(sval, _(empty_val), strlen(_(empty_val)))
1816 || (*sval == '<'
1817 && !struncmp(sval+1, _(empty_val), strlen(_(empty_val)))))
1818 *sval = '\0';
1819 else if(!struncmp(sval, _(no_val), strlen(_(no_val)))
1820 || (*sval == '<'
1821 && !struncmp(sval+1, _(no_val), strlen(_(no_val)))))
1822 goto delete;
1824 if((*cl)->var->is_list){
1825 if(*sval || !lval){
1826 char **ltmp;
1827 int i;
1829 i = 0;
1830 for(tmp = sval; *tmp; tmp++)
1831 if(*tmp == ',')
1832 i++; /* conservative count of ,'s */
1834 if(!i){
1835 ltmp = (char **)fs_get(2 * sizeof(char *));
1836 ltmp[0] = cpystr(sval);
1837 ltmp[1] = NULL;
1839 else
1840 ltmp = parse_list(sval, i + 1,
1841 look_for_backslash
1842 ? PL_COMMAQUOTE : 0,
1843 NULL);
1845 if(ltmp[0]){
1846 config_add_list(ps, cl, ltmp, &newval, after);
1847 if(after)
1848 skip_to_next = 1;
1850 else{
1851 q_status_message1(SM_ORDER, 0, 3,
1852 _("Can't add %s to list"), _(empty_val));
1853 rv = ps->mangled_body = 0;
1856 fs_give((void **)&ltmp);
1858 else{
1859 q_status_message1(SM_ORDER, 0, 3,
1860 _("Can't add %s to list"), _(empty_val));
1863 else{
1864 if(flags&CF_NUMBER && sval[0]
1865 && !(isdigit((unsigned char)sval[0])
1866 || sval[0] == '-' || sval[0] == '+')){
1867 q_status_message(SM_ORDER,3,3,
1868 _("Entry must be numeric"));
1869 i = 3; /* to keep loop going */
1870 continue;
1873 if(apval && *apval)
1874 fs_give((void **)apval);
1876 if(!(olddefval && !strcmp(sval, olddefval))
1877 || ((*cl)->var == &ps->vars[V_POST_CHAR_SET])
1878 || want_to(_("Leave unset and use default "),
1879 'y', 'y', NO_HELP, WT_FLUSH_IN) == 'n')
1880 *apval = cpystr(sval);
1882 newval = &(*cl)->value;
1885 else if(i == 1){
1886 cmd_cancelled("Add");
1888 else if(i == 3){
1889 help = help == NO_HELP ? h_config_add : NO_HELP;
1890 continue;
1892 else if(i == 4){ /* no redraw, yet */
1893 continue;
1895 else if(i == 5){ /* change from/to prepend to/from append */
1896 char tmpval[101];
1898 after = after ? 0 : 1;
1899 strncpy(tmpval, (*cl)->value, sizeof(tmpval));
1900 tmpval[sizeof(tmpval)-1] = '\0';
1901 removing_trailing_white_space(tmpval);
1902 /* 33 is the number of chars other than the value */
1903 maxwidth = MIN(80, ps->ttyo->screen_cols) - 15;
1904 k = MIN(18, MAX(maxwidth-33,0));
1905 if(utf8_width(tmpval) > k && k >= 3){
1906 (void) utf8_truncate(tmpval, k-3);
1907 strncat(tmpval, "...", sizeof(tmpval)-strlen(tmpval)-1);
1908 tmpval[sizeof(tmpval)-1] = '\0';
1911 if(after)
1912 snprintf(prompt, sizeof(prompt), _("Enter text to insert after \"%.*s\": "), k, tmpval);
1913 else
1914 snprintf(prompt, sizeof(prompt), _("Enter text to insert before \"%.*s\": "), k, tmpval);
1916 continue;
1918 else if(i == ctrl('P')){
1919 if(sval[0])
1920 numval = atoi(sval);
1921 else{
1922 if(pval)
1923 numval = atoi(pval);
1924 else
1925 numval = lowrange + 1;
1928 if(numval == lowrange){
1930 * Protect user from repeating arrow key that
1931 * causes message to appear over and over.
1933 if(++repeat_key > 0){
1934 q_status_message1(SM_ORDER,3,3,
1935 _("Minimum value is %s"), comatose(lowrange));
1936 repeat_key = -5;
1939 else
1940 repeat_key = 0;
1942 numval = MAX(numval - incr, lowrange);
1943 snprintf(sval, oebufsize, "%d", numval);
1944 sval[oebufsize-1] = '\0';
1945 continue;
1947 else if(i == ctrl('N')){
1948 if(sval[0])
1949 numval = atoi(sval);
1950 else{
1951 if(pval)
1952 numval = atoi(pval);
1953 else
1954 numval = lowrange + 1;
1957 if(numval == hirange){
1958 if(++repeat_key > 0){
1959 q_status_message1(SM_ORDER,3,3,
1960 _("Maximum value is %s"), comatose(hirange));
1961 repeat_key = -5;
1964 else
1965 repeat_key = 0;
1967 numval = MIN(numval + incr, hirange);
1968 snprintf(sval, oebufsize, "%d", numval);
1969 sval[oebufsize-1] = '\0';
1970 continue;
1973 break;
1977 break;
1979 case MC_DELETE: /* delete */
1980 delete:
1981 if(!(*cl)->var->is_list
1982 && apval && !*apval
1983 && (*cl)->var->current_val.p){
1984 char pmt[80];
1986 snprintf(pmt, sizeof(pmt), _("Override default with %s"), _(empty_val2));
1987 pmt[sizeof(pmt)-1] = '\0';
1988 if(want_to(pmt, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
1989 sval[0] = '\0';
1990 *apval = cpystr(sval);
1991 newval = &(*cl)->value;
1992 rv = ps->mangled_footer = 1;
1995 else if((*cl)->var->is_list
1996 && alval && !lval
1997 && (*cl)->var->current_val.l){
1998 char pmt[80];
2000 snprintf(pmt, sizeof(pmt), _("Override default with %s"), _(empty_val2));
2001 pmt[sizeof(pmt)-1] = '\0';
2002 if(want_to(pmt, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
2003 char **ltmp;
2005 sval[0] = '\0';
2006 ltmp = (char **)fs_get(2 * sizeof(char *));
2007 ltmp[0] = cpystr(sval);
2008 ltmp[1] = NULL;
2009 config_add_list(ps, cl, ltmp, &newval, 0);
2010 fs_give((void **)&ltmp);
2011 rv = ps->mangled_body = 1;
2014 else if(((*cl)->var->is_list && !lval)
2015 || (!(*cl)->var->is_list && !pval)){
2016 q_status_message(SM_ORDER, 0, 3, _("No set value to delete"));
2018 else{
2019 if((*cl)->var->is_fixed)
2020 snprintf(prompt, sizeof(prompt), _("Delete (unused) %s from %s "),
2021 (*cl)->var->is_list
2022 ? (!*lval[(*cl)->varmem])
2023 ? _(empty_val2)
2024 : lval[(*cl)->varmem]
2025 : (pval)
2026 ? (!*pval)
2027 ? _(empty_val2)
2028 : pval
2029 : "<NULL VALUE>",
2030 (*cl)->var->name);
2031 else
2032 snprintf(prompt, sizeof(prompt), _("Really delete %s%s from %s "),
2033 (*cl)->var->is_list ? "item " : "",
2034 (*cl)->var->is_list
2035 ? int2string((*cl)->varmem + 1)
2036 : (pval)
2037 ? (!*pval)
2038 ? _(empty_val2)
2039 : pval
2040 : "<NULL VALUE>",
2041 (*cl)->var->name);
2043 prompt[sizeof(prompt)-1] = '\0';
2046 ps->mangled_footer = 1;
2047 if(want_to(prompt, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
2048 rv = 1;
2049 if((*cl)->var->is_list)
2050 ps->mangled_body = 1;
2051 else
2052 ps->mangled_footer = 1;
2054 if((*cl)->var->is_list){
2055 if(lval[(*cl)->varmem])
2056 fs_give((void **)&lval[(*cl)->varmem]);
2058 config_del_list_item(cl, &newval);
2060 else{
2061 if(apval && *apval)
2062 fs_give((void **)apval);
2064 newval = &(*cl)->value;
2067 else
2068 q_status_message(SM_ORDER, 0, 3, _("Value not deleted"));
2071 break;
2073 case MC_EDIT: /* edit/change list option */
2074 if(fixed_var((*cl)->var, NULL, NULL)){
2075 break;
2077 else if(((*cl)->var->is_list
2078 && !lval
2079 && (*cl)->var->current_val.l)
2081 (!(*cl)->var->is_list
2082 && !pval
2083 && (*cl)->var->current_val.p)){
2086 * In non-list case, offer default value for editing.
2088 if(!(*cl)->var->is_list
2089 && (*cl)->var != &ps->vars[V_REPLY_INTRO]
2090 && (*cl)->var->current_val.p[0]
2091 && strcmp(VSTRING,(*cl)->var->current_val.p)){
2092 int quote_it;
2093 size_t len;
2095 olddefval = (char *) fs_get(strlen((*cl)->var->current_val.p)+3);
2097 if(!strncmp((*cl)->var->current_val.p,
2098 DSTRING,
2099 (len=strlen(DSTRING)))){
2100 /* strip DSTRING and trailing paren */
2101 strncpy(olddefval, (*cl)->var->current_val.p+len,
2102 strlen((*cl)->var->current_val.p)-len-1);
2103 olddefval[strlen((*cl)->var->current_val.p)-len-1] = '\0';
2105 else{
2106 /* quote it if there are trailing spaces */
2107 quote_it = ((*cl)->var->current_val.p[strlen((*cl)->var->current_val.p)-1] == SPACE);
2108 snprintf(olddefval, strlen((*cl)->var->current_val.p)+3, "%s%s%s", quote_it ? "\"" : "", (*cl)->var->current_val.p, quote_it ? "\"" : "");
2111 olddefval[strlen((*cl)->var->current_val.p)+3-1] = '\0';
2114 goto replace_text;
2116 else if(((*cl)->var->is_list
2117 && !lval
2118 && !(*cl)->var->current_val.l)
2120 (!(*cl)->var->is_list
2121 && !pval
2122 && !(*cl)->var->current_val.p)){
2123 goto add_text;
2125 else{
2126 HelpType help;
2127 char *clptr;
2129 if(sval)
2130 fs_give((void **)&sval);
2131 if((*cl)->var->is_list){
2132 snprintf(prompt, sizeof(prompt), _("Change field %s list entry : "),
2133 (*cl)->var->name);
2134 prompt[sizeof(prompt)-1] = '\0';
2135 clptr = lval[(*cl)->varmem] ? lval[(*cl)->varmem] : NULL;
2137 else{
2138 if(flags & CF_NUMBER)
2139 snprintf(prompt, sizeof(prompt), _("Change numeric field %s value : "), (*cl)->var->name);
2140 else
2141 snprintf(prompt, sizeof(prompt), _("Change field %s value : "), (*cl)->var->name);
2143 clptr = pval ? pval : NULL;
2146 oebufsize = clptr ? (int) MAX(MAXPATH, 50+strlen(clptr)) : MAXPATH;
2147 sval = (char *) fs_get(oebufsize * sizeof(char));
2148 snprintf(sval, oebufsize, "%s", clptr ? clptr : "");
2149 sval[oebufsize-1] = '\0';
2151 ps->mangled_footer = 1;
2152 help = NO_HELP;
2153 while(1){
2154 if(!(flags&CF_NUMBER))
2155 ekey[0].ch = -1;
2157 oeflags = OE_APPEND_CURRENT;
2158 i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, oebufsize,
2159 prompt,
2160 (ekey[0].ch != -1) ? ekey : NULL,
2161 help, &oeflags);
2162 if(i == 0){
2163 removing_leading_and_trailing_white_space(sval);
2165 * Coerce "" and <Empty Value> to empty string input.
2166 * Catch <No Value Set> as a substitute for deleting.
2168 if((*sval == '\"' && *(sval+1) == '\"' && *(sval+2) == '\0')
2169 || !struncmp(sval, _(empty_val), strlen(_(empty_val)))
2170 || (*sval == '<'
2171 && !struncmp(sval+1, _(empty_val), strlen(_(empty_val)))))
2172 *sval = '\0';
2173 else if(!struncmp(sval, _(no_val), strlen(_(no_val)))
2174 || (*sval == '<'
2175 && !struncmp(sval+1, _(no_val), strlen(_(no_val)))))
2176 goto delete;
2178 rv = 1;
2179 if((*cl)->var->is_list)
2180 ps->mangled_body = 1;
2181 else
2182 ps->mangled_footer = 1;
2184 if((*cl)->var->is_list){
2185 char **ltmp = NULL;
2186 int i;
2188 if(lval[(*cl)->varmem])
2189 fs_give((void **)&lval[(*cl)->varmem]);
2191 i = 0;
2192 for(tmp = sval; *tmp; tmp++)
2193 if(*tmp == ',')
2194 i++; /* conservative count of ,'s */
2196 if(i)
2197 ltmp = parse_list(sval, i + 1,
2198 look_for_backslash
2199 ? PL_COMMAQUOTE : 0,
2200 NULL);
2202 if(ltmp && !ltmp[0]) /* only commas */
2203 goto delete;
2204 else if(!i || (ltmp && !ltmp[1])){ /* only one item */
2205 lval[(*cl)->varmem] = cpystr(sval);
2206 newval = &(*cl)->value;
2208 if(ltmp && ltmp[0])
2209 fs_give((void **)&ltmp[0]);
2211 else if(ltmp){
2213 * Looks like the value was changed to a
2214 * list, so delete old value, and insert
2215 * new list...
2217 * If more than one item in existing list and
2218 * current is end of existing list, then we
2219 * have to delete and append instead of
2220 * deleting and prepending.
2222 if(((*cl)->varmem > 0 || lval[1])
2223 && !(lval[(*cl)->varmem+1])){
2224 after = 1;
2225 skip_to_next = 1;
2228 config_del_list_item(cl, &newval);
2229 config_add_list(ps, cl, ltmp, &newval, after);
2232 if(ltmp)
2233 fs_give((void **)&ltmp);
2235 else{
2236 if(flags&CF_NUMBER && sval[0]
2237 && !(isdigit((unsigned char)sval[0])
2238 || sval[0] == '-' || sval[0] == '+')){
2239 q_status_message(SM_ORDER,3,3,
2240 _("Entry must be numeric"));
2241 continue;
2244 if(apval && *apval)
2245 fs_give((void **)apval);
2247 if(sval[0] && apval)
2248 *apval = cpystr(sval);
2250 newval = &(*cl)->value;
2253 else if(i == 1){
2254 cmd_cancelled("Change");
2256 else if(i == 3){
2257 help = help == NO_HELP ? h_config_change : NO_HELP;
2258 continue;
2260 else if(i == 4){ /* no redraw, yet */
2261 continue;
2263 else if(i == ctrl('P')){
2264 numval = atoi(sval);
2265 if(numval == lowrange){
2267 * Protect user from repeating arrow key that
2268 * causes message to appear over and over.
2270 if(++repeat_key > 0){
2271 q_status_message1(SM_ORDER,3,3,
2272 _("Minimum value is %s"), comatose(lowrange));
2273 repeat_key = -5;
2276 else
2277 repeat_key = 0;
2279 numval = MAX(numval - incr, lowrange);
2280 snprintf(sval, oebufsize, "%d", numval);
2281 sval[oebufsize-1] = '\0';
2282 continue;
2284 else if(i == ctrl('N')){
2285 numval = atoi(sval);
2286 if(numval == hirange){
2287 if(++repeat_key > 0){
2288 q_status_message1(SM_ORDER,3,3,
2289 _("Maximum value is %s"), comatose(hirange));
2290 repeat_key = -5;
2293 else
2294 repeat_key = 0;
2296 numval = MIN(numval + incr, hirange);
2297 snprintf(sval, oebufsize, "%d", numval);
2298 sval[oebufsize-1] = '\0';
2299 continue;
2302 break;
2306 break;
2308 case MC_SHUFFLE:
2309 if(!((*cl)->var && (*cl)->var->is_list)){
2310 q_status_message(SM_ORDER, 0, 2,
2311 _("Can't shuffle single-valued setting"));
2312 break;
2315 if(!alval)
2316 break;
2318 curindex = (*cl)->varmem;
2319 previndex = curindex-1;
2320 nextindex = curindex+1;
2321 if(!*alval || !(*alval)[nextindex])
2322 nextindex = -1;
2324 if((previndex < 0 && nextindex < 0) || !*alval){
2325 q_status_message(SM_ORDER, 0, 3,
2326 _("Shuffle only makes sense when there is more than one value defined"));
2327 break;
2330 /* Move it up or down? */
2331 i = 0;
2332 ekey[i].ch = 'u';
2333 ekey[i].rval = 'u';
2334 ekey[i].name = "U";
2335 ekey[i++].label = N_("Up");
2337 ekey[i].ch = 'd';
2338 ekey[i].rval = 'd';
2339 ekey[i].name = "D";
2340 ekey[i++].label = N_("Down");
2342 ekey[i].ch = -1;
2343 deefault = 'u';
2345 if(previndex < 0){ /* no up */
2346 ekey[0].ch = -2;
2347 deefault = 'd';
2349 else if(nextindex < 0)
2350 ekey[1].ch = -2; /* no down */
2352 snprintf(prompt, sizeof(prompt), "Shuffle %s%s%s ? ",
2353 (ekey[0].ch != -2) ? "UP" : "",
2354 (ekey[0].ch != -2 && ekey[1].ch != -2) ? " or " : "",
2355 (ekey[1].ch != -2) ? "DOWN" : "");
2356 help = (ekey[0].ch == -2) ? h_hdrcolor_shuf_down
2357 : (ekey[1].ch == -2) ? h_hdrcolor_shuf_up
2358 : h_hdrcolor_shuf;
2359 prompt[sizeof(prompt)-1] = '\0';
2361 i = radio_buttons(prompt, -FOOTER_ROWS(ps), ekey, deefault, 'x',
2362 help, RB_NORM);
2364 switch(i){
2365 case 'x':
2366 cmd_cancelled("Shuffle");
2367 return(rv);
2369 case 'u':
2370 case 'd':
2371 break;
2374 /* swap order */
2375 if(i == 'd'){
2376 swap_val = (*alval)[curindex];
2377 (*alval)[curindex] = (*alval)[nextindex];
2378 (*alval)[nextindex] = swap_val;
2380 else if(i == 'u'){
2381 swap_val = (*alval)[curindex];
2382 (*alval)[curindex] = (*alval)[previndex];
2383 (*alval)[previndex] = swap_val;
2385 else /* can't happen */
2386 break;
2389 * Fix the conf line values.
2392 if((*cl)->value)
2393 fs_give((void **)&(*cl)->value);
2395 (*cl)->value = pretty_value(ps, *cl);
2397 if(i == 'd'){
2398 if((*cl)->next->value)
2399 fs_give((void **)&(*cl)->next->value);
2401 (*cl)->next->value = pretty_value(ps, (*cl)->next);
2402 *cl = next_confline(*cl);
2404 else{
2405 if((*cl)->prev->value)
2406 fs_give((void **)&(*cl)->prev->value);
2408 (*cl)->prev->value = pretty_value(ps, (*cl)->prev);
2409 *cl = prev_confline(*cl);
2412 rv = ps->mangled_body = 1;
2413 break;
2415 case MC_EXIT: /* exit */
2416 rv = config_exit_cmd(flags);
2417 break;
2419 default:
2420 rv = -1;
2421 break;
2424 if(skip_to_next)
2425 *cl = next_confline(*cl);
2428 * At this point, if changes occurred, var->user_val.X is set.
2429 * So, fix the current_val, and handle special cases...
2431 * NOTE: we don't worry about the "fixed variable" case here, because
2432 * editing such vars should have been prevented above...
2434 if(rv == 1){
2436 * Now go and set the current_val based on user_val changes
2437 * above. Turn off command line settings...
2439 set_current_val((*cl)->var, TRUE, FALSE);
2440 fix_side_effects(ps, (*cl)->var, 0);
2443 * Delay setting the displayed value until "var.current_val" is set
2444 * in case current val get's changed due to a special case above.
2446 if(newval){
2447 if(*newval)
2448 fs_give((void **) newval);
2450 *newval = pretty_value(ps, *cl);
2453 exception_override_warning((*cl)->var);
2456 if(sval)
2457 fs_give((void **) &sval);
2459 if(olddefval)
2460 fs_give((void **) &olddefval);
2462 return(rv);
2467 config_exit_cmd(unsigned int flags)
2469 return(screen_exit_cmd(flags, "Configuration"));
2474 simple_exit_cmd(unsigned int flags)
2476 return(2);
2481 * screen_exit_cmd - basic config/flag screen exit logic
2484 screen_exit_cmd(unsigned int flags, char *cmd)
2486 if(flags & CF_CHANGES){
2487 switch(want_to(EXIT_PMT, 'y', 'x', h_config_undo, WT_FLUSH_IN)){
2488 case 'y':
2489 q_status_message1(SM_ORDER,0,3,"%s changes saved", cmd);
2490 return(2);
2492 case 'n':
2493 q_status_message1(SM_ORDER,3,5,"No %s changes saved", cmd);
2494 return(10);
2496 case 'x': /* ^C */
2497 default :
2498 q_status_message(SM_ORDER,3,5,"Changes not yet saved");
2499 return(0);
2502 else
2503 return(2);
2510 void
2511 config_add_list(struct pine *ps, CONF_S **cl, char **ltmp, char ***newval, int after)
2513 int items, i;
2514 char *tmp, ***alval;
2515 CONF_S *ctmp;
2517 for(items = 0, i = 0; ltmp[i]; i++) /* count list items */
2518 items++;
2520 alval = ALVAL((*cl)->var, ew);
2522 if(alval && (*alval)){
2523 if((*alval)[0] && (*alval)[0][0]){
2525 * Since we were already a list, make room
2526 * for the new member[s] and fall thru to
2527 * actually fill them in below...
2529 for(i = 0; (*alval)[i]; i++)
2532 fs_resize((void **)alval, (i + items + 1) * sizeof(char *));
2535 * move the ones that will be bumped down to the bottom of the list
2537 for(; i >= (*cl)->varmem + (after?1:0); i--)
2538 (*alval)[i+items] = (*alval)[i];
2540 i = 0;
2542 else if(alval){
2543 (*cl)->varmem = 0;
2544 if(*alval)
2545 free_list_array(alval);
2547 *alval = (char **)fs_get((items+1)*sizeof(char *));
2548 memset((void *)(*alval), 0, (items+1)*sizeof(char *));
2549 (*alval)[0] = ltmp[0];
2550 if(newval)
2551 *newval = &(*cl)->value;
2553 if((*cl)->value)
2554 fs_give((void **)&(*cl)->value);
2556 i = 1;
2559 else if(alval){
2561 * since we were previously empty, we want
2562 * to replace the first CONF_S's value with
2563 * the first new value, and fill the other
2564 * in below if there's a list...
2566 * first, make sure we're at the beginning of this config
2567 * section and dump the config lines for the default list,
2568 * except for the first one, which we will over-write.
2570 *cl = (*cl)->varnamep;
2571 while((*cl)->next && (*cl)->next->varnamep == (*cl)->varnamep)
2572 snip_confline(&(*cl)->next);
2575 * now allocate the new user_val array and fill in the first entry.
2577 *alval = (char **)fs_get((items+1)*sizeof(char *));
2578 memset((void *)(*alval), 0, (items+1) * sizeof(char *));
2579 (*alval)[(*cl)->varmem=0] = ltmp[0];
2580 if(newval)
2581 *newval = &(*cl)->value;
2583 if((*cl)->value)
2584 fs_give((void **)&(*cl)->value);
2586 i = 1;
2590 * Make new cl's to fit in the new space. Move the value from the current
2591 * line if inserting before it, else leave it where it is.
2593 for(; i < items ; i++){
2594 (*alval)[i+(*cl)->varmem + (after?1:0)] = ltmp[i];
2595 tmp = (*cl)->value;
2596 new_confline(cl);
2597 if(after)
2598 (*cl)->value = NULL;
2599 else
2600 (*cl)->value = tmp;
2602 (*cl)->var = (*cl)->prev->var;
2603 (*cl)->valoffset = (*cl)->prev->valoffset;
2604 (*cl)->varoffset = (*cl)->prev->varoffset;
2605 (*cl)->headingp = (*cl)->prev->headingp;
2606 (*cl)->keymenu = (*cl)->prev->keymenu;
2607 (*cl)->help = (*cl)->prev->help;
2608 (*cl)->tool = (*cl)->prev->tool;
2609 (*cl)->varnamep = (*cl)->prev->varnamep;
2610 *cl = (*cl)->prev;
2611 if(!after)
2612 (*cl)->value = NULL;
2614 if(newval){
2615 if(after)
2616 *newval = &(*cl)->next->value;
2617 else
2618 *newval = &(*cl)->value;
2623 * now fix up varmem values and fill in new values that have been
2624 * left NULL
2626 for(ctmp = (*cl)->varnamep, i = 0;
2627 (*alval)[i];
2628 ctmp = ctmp->next, i++){
2629 ctmp->varmem = i;
2630 if(!ctmp->value){
2631 /* BUG: We should be able to do this without the temp
2632 * copy...
2634 char *ptmp = pretty_value(ps, ctmp);
2635 ctmp->value = (ctmp->varnamep->flags & CF_PRINTER) ? printer_name(ptmp) : cpystr(ptmp);
2636 fs_give((void **)&ptmp);
2645 void
2646 config_del_list_item(CONF_S **cl, char ***newval)
2648 char **bufp, ***alval;
2649 int i;
2650 CONF_S *ctmp;
2652 alval = ALVAL((*cl)->var, ew);
2654 if((*alval)[(*cl)->varmem + 1]){
2655 for(bufp = &(*alval)[(*cl)->varmem];
2656 (*bufp = *(bufp+1)) != NULL; bufp++)
2659 if(*cl == (*cl)->varnamep){ /* leading value */
2660 if((*cl)->value)
2661 fs_give((void **)&(*cl)->value);
2663 ctmp = (*cl)->next;
2664 (*cl)->value = ctmp->value;
2665 ctmp->value = NULL;
2667 else{
2668 ctmp = *cl; /* blast the confline */
2669 *cl = (*cl)->next;
2670 if(ctmp == opt_screen->top_line)
2671 opt_screen->top_line = *cl;
2674 snip_confline(&ctmp);
2676 for(ctmp = (*cl)->varnamep, i = 0; /* now fix up varmem values */
2677 (*alval)[i];
2678 ctmp = ctmp->next, i++)
2679 ctmp->varmem = i;
2681 else if((*cl)->varmem){ /* blasted last in list */
2682 ctmp = *cl;
2683 *cl = (*cl)->prev;
2684 if(ctmp == opt_screen->top_line)
2685 opt_screen->top_line = *cl;
2687 snip_confline(&ctmp);
2689 else{ /* blasted last remaining */
2690 if(alval && *alval)
2691 fs_give((void **)alval);
2693 *newval = &(*cl)->value;
2699 * feature list manipulation tool
2702 * returns: -1 on unrecognized cmd, 0 if no change, 1 if change
2705 checkbox_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
2707 int rv = 0;
2709 switch(cmd){
2710 case MC_TOGGLE: /* mark/unmark feature */
2711 if((*cl)->var == &ps->vars[V_FEATURE_LIST]){
2712 rv = 1;
2713 toggle_feature_bit(ps, (*cl)->varmem, (*cl)->var, *cl, 0);
2715 else
2716 q_status_message(SM_ORDER | SM_DING, 3, 6,
2717 "Programmer botch! Unknown checkbox type.");
2719 break;
2721 case MC_EXIT: /* exit */
2722 rv = config_exit_cmd(flags);
2723 break;
2725 default :
2726 rv = -1;
2727 break;
2730 return(rv);
2735 * simple radio-button style variable handler
2738 radiobutton_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
2740 char **apval;
2741 int rv = 0;
2742 NAMEVAL_S *rule = NULL;
2743 #ifndef _WINDOWS
2744 int old_uc, old_cs;
2745 CONF_S *ctmp;
2746 #endif
2748 apval = APVAL((*cl)->var, ew);
2750 switch(cmd){
2751 case MC_CHOICE : /* set/unset feature */
2753 if(fixed_var((*cl)->var, NULL, NULL)){
2754 if(((*cl)->var->post_user_val.p || (*cl)->var->main_user_val.p)
2755 && want_to(_("Delete old unused personal option setting"),
2756 'y', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
2757 delete_user_vals((*cl)->var);
2758 q_status_message(SM_ORDER, 0, 3, _("Deleted"));
2759 rv = 1;
2762 return(rv);
2765 if(standard_radio_var(ps, (*cl)->var) || (*cl)->var == startup_ptr){
2766 PTR_TO_RULEFUNC rulefunc;
2768 #ifndef _WINDOWS
2769 if((*cl)->var == &ps->vars[V_COLOR_STYLE]){
2770 old_uc = pico_usingcolor();
2771 old_cs = ps->color_style;
2773 #endif
2775 if((*cl)->var->cmdline_val.p)
2776 fs_give((void **)&(*cl)->var->cmdline_val.p);
2778 if(apval && *apval)
2779 fs_give((void **)apval);
2781 rulefunc = rulefunc_from_var(ps, (*cl)->var);
2782 if(rulefunc)
2783 rule = (*rulefunc)((*cl)->varmem);
2785 if(apval && rule)
2786 *apval = cpystr(S_OR_L(rule));
2788 cur_rule_value((*cl)->var, TRUE, TRUE);
2789 set_radio_pretty_vals(ps, cl);
2791 if((*cl)->var == &ps->vars[V_AB_SORT_RULE])
2792 addrbook_redo_sorts();
2793 else if((*cl)->var == &ps->vars[V_THREAD_DISP_STYLE]){
2794 clear_index_cache(ps->mail_stream, 0);
2796 else if((*cl)->var == &ps->vars[V_THREAD_INDEX_STYLE]){
2797 MAILSTREAM *m;
2798 int i;
2800 clear_index_cache(ps->mail_stream, 0);
2801 /* clear all hidden and collapsed flags */
2802 set_lflags(ps->mail_stream, ps->msgmap, MN_COLL | MN_CHID, 0);
2804 if(SEP_THRDINDX()
2805 && SORT_IS_THREADED(ps->msgmap)
2806 && unview_thread(ps, ps->mail_stream, ps->msgmap)){
2807 ps->next_screen = mail_index_screen;
2808 ps->view_skipped_index = 0;
2809 ps->mangled_screen = 1;
2812 if(SORT_IS_THREADED(ps->msgmap)
2813 && (SEP_THRDINDX() || COLL_THRDS()))
2814 collapse_threads(ps->mail_stream, ps->msgmap, NULL);
2816 for(i = 0; i < ps_global->s_pool.nstream; i++){
2817 m = ps_global->s_pool.streams[i];
2818 if(m)
2819 sp_set_viewing_a_thread(m, 0);
2822 adjust_cur_to_visible(ps->mail_stream, ps->msgmap);
2824 #ifndef _WINDOWS
2825 else if((*cl)->var == &ps->vars[V_COLOR_STYLE]){
2826 if(old_cs != ps->color_style){
2827 pico_toggle_color(0);
2828 switch(ps->color_style){
2829 case COL_NONE:
2830 case COL_TERMDEF:
2831 pico_set_color_options(pico_trans_color() ? COLOR_TRANS_OPT : 0);
2832 break;
2833 case COL_ANSI8:
2834 pico_set_color_options(COLOR_ANSI8_OPT|COLOR_TRANS_OPT);
2835 break;
2836 case COL_ANSI16:
2837 pico_set_color_options(COLOR_ANSI16_OPT|COLOR_TRANS_OPT);
2838 break;
2839 case COL_ANSI256:
2840 pico_set_color_options(COLOR_ANSI256_OPT|COLOR_TRANS_OPT);
2841 break;
2844 if(ps->color_style != COL_NONE)
2845 pico_toggle_color(1);
2848 if(pico_usingcolor())
2849 pico_set_normal_color();
2851 if(!old_uc && pico_usingcolor()){
2854 * remove the explanatory warning line and a blank line
2857 /* first find the first blank line */
2858 for(ctmp = *cl; ctmp; ctmp = next_confline(ctmp))
2859 if(ctmp->flags & CF_NOSELECT)
2860 break;
2862 if(ctmp && ctmp->flags & CF_NOSELECT &&
2863 ctmp->prev && !(ctmp->prev->flags & CF_NOSELECT) &&
2864 ctmp->next && ctmp->next->flags & CF_NOSELECT &&
2865 ctmp->next->next &&
2866 ctmp->next->next->flags & CF_NOSELECT){
2867 ctmp->prev->next = ctmp->next->next;
2868 ctmp->next->next->prev = ctmp->prev;
2869 ctmp->next->next = NULL;
2870 free_conflines(&ctmp);
2873 /* make all the colors selectable */
2874 for(ctmp = *cl; ctmp; ctmp = next_confline(ctmp))
2875 if(ctmp->flags & CF_POT_SLCTBL)
2876 ctmp->flags &= ~CF_NOSELECT;
2878 else if(old_uc && !pico_usingcolor()){
2881 * add the explanatory warning line and a blank line
2884 /* first find the existing blank line */
2885 for(ctmp = *cl; ctmp; ctmp = next_confline(ctmp))
2886 if(ctmp->flags & CF_NOSELECT)
2887 break;
2889 /* add the explanatory warning line */
2890 new_confline(&ctmp);
2891 ctmp->help = NO_HELP;
2892 ctmp->flags |= CF_NOSELECT;
2893 ctmp->value = cpystr(COLORNOSET);
2895 /* and add another blank line */
2896 new_confline(&ctmp);
2897 ctmp->flags |= (CF_NOSELECT | CF_B_LINE);
2899 /* make all the colors non-selectable */
2900 for(ctmp = *cl; ctmp; ctmp = next_confline(ctmp))
2901 if(ctmp->flags & CF_POT_SLCTBL)
2902 ctmp->flags |= CF_NOSELECT;
2905 clear_index_cache(ps->mail_stream, 0);
2906 ClearScreen();
2907 ps->mangled_screen = 1;
2909 #endif
2911 ps->mangled_body = 1; /* BUG: redraw it all for now? */
2912 rv = 1;
2914 else if((*cl)->var == &ps->vars[V_SORT_KEY]){
2915 SortOrder def_sort;
2916 int def_sort_rev;
2918 def_sort_rev = (*cl)->varmem >= (short) EndofList;
2919 def_sort = (SortOrder) ((*cl)->varmem - (def_sort_rev
2920 * EndofList));
2921 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s", sort_name(def_sort),
2922 (def_sort_rev) ? "/Reverse" : "");
2924 if((*cl)->var->cmdline_val.p)
2925 fs_give((void **)&(*cl)->var->cmdline_val.p);
2927 if(apval){
2928 if(*apval)
2929 fs_give((void **)apval);
2931 *apval = cpystr(tmp_20k_buf);
2934 set_current_val((*cl)->var, TRUE, TRUE);
2935 if(decode_sort(ps->VAR_SORT_KEY, &def_sort, &def_sort_rev) != -1){
2936 ps->def_sort = def_sort;
2937 ps->def_sort_rev = def_sort_rev;
2940 set_radio_pretty_vals(ps, cl);
2941 ps->mangled_body = 1; /* BUG: redraw it all for now? */
2942 rv = 1;
2944 else
2945 q_status_message(SM_ORDER | SM_DING, 3, 6,
2946 "Programmer botch! Unknown radiobutton type.");
2948 break;
2950 case MC_EXIT: /* exit */
2951 rv = config_exit_cmd(flags);
2952 break;
2954 default :
2955 rv = -1;
2956 break;
2959 if(rv == 1)
2960 exception_override_warning((*cl)->var);
2962 return(rv);
2967 * simple yes/no style variable handler
2970 yesno_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
2972 int rv = 0, yes = 0;
2973 char *pval, **apval;
2975 pval = PVAL((*cl)->var, ew);
2976 apval = APVAL((*cl)->var, ew);
2978 switch(cmd){
2979 case MC_TOGGLE: /* toggle yes to no and back */
2980 if(fixed_var((*cl)->var, NULL, NULL)){
2981 if(((*cl)->var->post_user_val.p || (*cl)->var->main_user_val.p)
2982 && want_to(_("Delete old unused personal option setting"),
2983 'y', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){
2984 delete_user_vals((*cl)->var);
2985 q_status_message(SM_ORDER, 0, 3, _("Deleted"));
2986 rv = 1;
2989 return(rv);
2992 rv = 1;
2993 yes = ((pval && !strucmp(pval, yesstr)) ||
2994 (!pval && (*cl)->var->current_val.p &&
2995 !strucmp((*cl)->var->current_val.p, yesstr)));
2996 fs_give((void **)&(*cl)->value);
2998 if(apval){
2999 if(*apval)
3000 fs_give((void **)apval);
3002 if(yes)
3003 *apval = cpystr(nostr);
3004 else
3005 *apval = cpystr(yesstr);
3008 set_current_val((*cl)->var, FALSE, FALSE);
3009 if((*cl)->value)
3010 fs_give((void **)&(*cl)->value);
3012 (*cl)->value = pretty_value(ps, *cl);
3013 fix_side_effects(ps, (*cl)->var, 0);
3015 break;
3017 case MC_EXIT: /* exit */
3018 rv = config_exit_cmd(flags);
3019 break;
3021 default :
3022 rv = -1;
3023 break;
3026 return(rv);
3031 * Manage display of the config/options menu body.
3033 void
3034 update_option_screen(struct pine *ps, OPT_SCREEN_S *screen, Pos *cursor_pos)
3036 int dline, w, save = '\0';
3037 CONF_S *top_line, *ctmp;
3038 char *value;
3039 unsigned got_width;
3040 int want_width, first_width;
3041 char *saveptr = NULL;
3043 #ifdef _WINDOWS
3044 int last_selectable;
3045 mswin_beginupdate();
3046 #endif
3047 if(screen == NULL || BODY_LINES(ps) < 1)
3048 return;
3050 opt_screen = screen;
3052 if(cursor_pos){
3053 cursor_pos->col = 0;
3054 cursor_pos->row = -1; /* to tell us if we've set it yet */
3058 * calculate top line of display for reframing if the current field
3059 * is off the display defined by screen->top_line...
3061 if((ctmp = screen->top_line) != NULL)
3062 for(dline = BODY_LINES(ps);
3063 dline && ctmp && ctmp != screen->current;
3064 ctmp = next_confline(ctmp), dline--)
3067 if(!ctmp || !dline){ /* force reframing */
3068 dline = 0;
3069 ctmp = top_line = first_confline(screen->current);
3071 if(((dline++)%BODY_LINES(ps)) == 0)
3072 top_line = ctmp;
3073 while(ctmp != screen->current && (ctmp = next_confline(ctmp)));
3075 else
3076 top_line = screen->top_line;
3078 #ifdef _WINDOWS
3080 * Figure out how far down the top line is from the top and how many
3081 * total lines there are. Dumb to loop every time thru, but
3082 * there aren't that many lines, and it's cheaper than rewriting things
3083 * to maintain a line count in each structure...
3085 for(dline = 0, ctmp = prev_confline(top_line); ctmp; ctmp = prev_confline(ctmp))
3086 dline++;
3088 scroll_setpos(dline);
3089 last_selectable = dline;
3090 for(ctmp = next_confline(top_line); ctmp ; ctmp = next_confline(ctmp)){
3091 dline++;
3092 if (!(ctmp->flags & CF_NOSELECT))
3093 last_selectable = dline;
3095 dline = last_selectable;
3096 scroll_setrange(BODY_LINES(ps), dline);
3097 #endif
3099 /* mangled body or new page, force redraw */
3100 if(ps->mangled_body || screen->top_line != top_line)
3101 screen->prev = NULL;
3103 /* loop thru painting what's needed */
3104 for(dline = 0, ctmp = top_line;
3105 dline < BODY_LINES(ps);
3106 dline++, ctmp = next_confline(ctmp)){
3109 * only fall thru painting if something needs painting...
3111 if(!(!screen->prev || ctmp == screen->prev || ctmp == screen->current
3112 || ctmp == screen->prev->varnamep
3113 || ctmp == screen->current->varnamep
3114 || ctmp == screen->prev->headingp
3115 || ctmp == screen->current->headingp))
3116 continue;
3118 ClearLine(dline + HEADER_ROWS(ps));
3120 if(ctmp){
3121 if(ctmp->flags & CF_B_LINE)
3122 continue;
3124 if(ctmp->varname && !(ctmp->flags & CF_INVISIBLEVAR)){
3125 if(ctmp == screen->current && cursor_pos)
3126 cursor_pos->row = dline + HEADER_ROWS(ps);
3128 if((ctmp == screen->current
3129 || ctmp == screen->current->varnamep
3130 || ctmp == screen->current->headingp)
3131 && !(ctmp->flags & CF_NOHILITE))
3132 StartInverse();
3134 if(ctmp->flags & CF_H_LINE){
3135 MoveCursor(dline + HEADER_ROWS(ps), 0);
3136 Write_to_screen(repeat_char(ps->ttyo->screen_cols, '-'));
3139 if(ctmp->flags & CF_CENTERED){
3140 int offset = ps->ttyo->screen_cols/2
3141 - (utf8_width(ctmp->varname)/2);
3142 MoveCursor(dline + HEADER_ROWS(ps),
3143 (offset > 0) ? offset : 0);
3145 else if(ctmp->varoffset)
3146 MoveCursor(dline+HEADER_ROWS(ps), ctmp->varoffset);
3148 Write_to_screen(ctmp->varname);
3149 if((ctmp == screen->current
3150 || ctmp == screen->current->varnamep
3151 || ctmp == screen->current->headingp)
3152 && !(ctmp->flags & CF_NOHILITE))
3153 EndInverse();
3156 value = (ctmp->flags & CF_INHERIT) ? INHERIT : ctmp->value;
3158 if(value){
3159 char *p;
3160 int i, j;
3162 memset(tmp_20k_buf, '\0',
3163 (6*ps->ttyo->screen_cols + 1) * sizeof(char));
3164 if(ctmp == screen->current){
3165 if(!(ctmp->flags & CF_DOUBLEVAR && ctmp->flags & CF_VAR2))
3166 StartInverse();
3168 if(cursor_pos)
3169 cursor_pos->row = dline + HEADER_ROWS(ps);
3172 if(ctmp->flags & CF_H_LINE)
3173 memset(tmp_20k_buf, '-',
3174 ps->ttyo->screen_cols * sizeof(char));
3176 if(ctmp->flags & CF_CENTERED){
3177 int offset = ps->ttyo->screen_cols/2
3178 - (utf8_width(value)/2);
3179 /* BUG: tabs screw us figuring length above */
3180 if(offset > 0){
3181 char *q;
3183 p = tmp_20k_buf + offset;
3184 if(!*(q = tmp_20k_buf))
3185 while(q < p)
3186 *q++ = ' ';
3189 else
3190 p = tmp_20k_buf;
3193 * Copy the value to a temp buffer expanding tabs, and
3194 * making sure not to write beyond screen right...
3196 for(i = 0, j = ctmp->valoffset; value[i]; i++){
3197 if(value[i] == ctrl('I')){
3199 *p++ = ' ';
3200 while((++j) & 0x07);
3202 else{
3203 *p++ = value[i];
3204 j++;
3208 if(ctmp == screen->current && cursor_pos){
3209 if(ctmp->flags & CF_DOUBLEVAR && ctmp->flags & CF_VAR2)
3210 cursor_pos->col = ctmp->val2offset;
3211 else
3212 cursor_pos->col = ctmp->valoffset;
3214 if(ctmp->tool == radiobutton_tool
3215 #ifdef ENABLE_LDAP
3216 || ctmp->tool==ldap_radiobutton_tool
3217 #endif
3218 || ctmp->tool==role_radiobutton_tool
3219 || ctmp->tool==checkbox_tool
3220 || (ctmp->tool==color_setting_tool &&
3221 ctmp->valoffset != COLOR_INDENT))
3222 cursor_pos->col++;
3225 if(ctmp->flags & CF_DOUBLEVAR){
3226 long l;
3228 p = tmp_20k_buf;
3229 first_width = ctmp->val2offset - ctmp->valoffset - SPACE_BETWEEN_DOUBLEVARS;
3230 if((l=utf8_width(p)) > first_width && first_width >= 0){
3231 saveptr = utf8_count_forw_width(p, first_width, &got_width);
3233 * got_width != first_width indicates there's a problem
3234 * that should not happen. Ignore it.
3236 if(saveptr){
3237 save = *saveptr;
3238 *saveptr = '\0';
3241 else
3242 save = '\0';
3245 * If this is a COLOR_BLOB line we do special coloring.
3246 * The current object inverse hilite is only on the
3247 * checkbox part, the exact format comes from the
3248 * new_color_line function. If we change that we'll have
3249 * to change this to get the coloring right.
3251 if(p[0] == '(' && p[2] == ')' &&
3252 p[3] == ' ' && p[4] == ' ' &&
3253 (!strncmp(p+5, COLOR_BLOB, COLOR_BLOB_LEN)
3254 || !strncmp(p+5, COLOR_BLOB_TRAN, COLOR_BLOB_LEN)
3255 || !strncmp(p+5, COLOR_BLOB_NORM, COLOR_BLOB_LEN))){
3256 COLOR_PAIR *lastc = NULL, *newc = NULL;
3258 MoveCursor(dline+HEADER_ROWS(ps), ctmp->valoffset);
3259 Write_to_screen_n(p, 3);
3260 if(!(ctmp->flags & CF_VAR2) && ctmp == screen->current)
3261 EndInverse();
3263 Write_to_screen_n(p+3, 3);
3264 newc = new_color_pair(colorx(CFC_ICOLOR(ctmp)),
3265 colorx(CFC_ICOLOR(ctmp)));
3266 if(newc){
3267 lastc = pico_get_cur_color();
3268 (void)pico_set_colorp(newc, PSC_NONE);
3269 free_color_pair(&newc);
3272 Write_to_screen_n(p+6, COLOR_BLOB_LEN-2);
3274 if(lastc){
3275 (void)pico_set_colorp(lastc, PSC_NONE);
3276 free_color_pair(&lastc);
3279 Write_to_screen(p+6+COLOR_BLOB_LEN-2);
3281 else{
3282 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset, p);
3283 if(!(ctmp->flags & CF_VAR2) && ctmp == screen->current)
3284 EndInverse();
3287 if(saveptr)
3288 *saveptr = save;
3290 PutLine0(dline+HEADER_ROWS(ps),
3291 ctmp->val2offset - SPACE_BETWEEN_DOUBLEVARS,
3292 repeat_char(SPACE_BETWEEN_DOUBLEVARS, SPACE));
3294 if(l > ctmp->val2offset - ctmp->valoffset && ctmp->val2offset - ctmp->valoffset >= 0)
3295 p = saveptr + SPACE_BETWEEN_DOUBLEVARS;
3297 if(p > tmp_20k_buf){
3298 if(ctmp->flags & CF_VAR2 && ctmp == screen->current)
3299 StartInverse();
3301 if(p[0] == '(' && p[2] == ')' &&
3302 p[3] == ' ' && p[4] == ' ' &&
3303 (!strncmp(p+5, COLOR_BLOB, COLOR_BLOB_LEN)
3304 || !strncmp(p+5, COLOR_BLOB_TRAN, COLOR_BLOB_LEN)
3305 || !strncmp(p+5, COLOR_BLOB_NORM, COLOR_BLOB_LEN))){
3306 COLOR_PAIR *lastc = NULL, *newc = NULL;
3308 MoveCursor(dline+HEADER_ROWS(ps), ctmp->val2offset);
3309 Write_to_screen_n(p, 3);
3310 if(ctmp->flags & CF_VAR2 && ctmp == screen->current)
3311 EndInverse();
3313 Write_to_screen_n(p+3, 3);
3314 newc = new_color_pair(colorx(CFC_ICOLOR(ctmp)),
3315 colorx(CFC_ICOLOR(ctmp)));
3316 if(newc){
3317 lastc = pico_get_cur_color();
3318 (void)pico_set_colorp(newc, PSC_NONE);
3319 free_color_pair(&newc);
3322 Write_to_screen_n(p+6, COLOR_BLOB_LEN-2);
3324 if(lastc){
3325 (void)pico_set_colorp(lastc, PSC_NONE);
3326 free_color_pair(&lastc);
3329 Write_to_screen(p+6+COLOR_BLOB_LEN-2);
3331 else{
3332 PutLine0(dline+HEADER_ROWS(ps),ctmp->val2offset,p);
3333 if(ctmp->flags & CF_VAR2 && ctmp == screen->current)
3334 EndInverse();
3338 else{
3339 char *q, *first_space, *sample, *ptr;
3340 COLOR_PAIR *lastc, *newc;
3341 int invert;
3344 if(ctmp->flags & CF_COLORSAMPLE &&
3345 pico_usingcolor() &&
3346 ((q = strstr(tmp_20k_buf, SAMPLE_LEADER)) ||
3347 (q = strstr(tmp_20k_buf, "Color"))) &&
3348 (first_space = strindex(q, SPACE)) &&
3349 (strstr(value, SAMP1) ||
3350 strstr(value, SAMP2))){
3352 ptr = tmp_20k_buf;
3354 /* write out first part */
3355 *first_space = '\0';
3356 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset,
3357 ptr);
3358 *first_space = SPACE;
3359 ptr = first_space;
3361 if(ctmp == screen->current)
3362 EndInverse();
3364 sample = skip_white_space(ptr);
3365 /* if there's enough room to put some sample up */
3366 save = *sample;
3367 *sample = '\0';
3368 w = utf8_width(tmp_20k_buf);
3369 *sample = save;
3370 if(ctmp->valoffset + w < ps->ttyo->screen_cols){
3372 sample++; /* for `[' at edge of sample */
3374 save = *ptr;
3375 *ptr = '\0';
3376 w = utf8_width(tmp_20k_buf);
3377 *ptr = save;
3379 save = *sample;
3380 *sample = '\0';
3381 /* spaces and bracket before sample1 */
3382 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset+w, ptr);
3383 *sample = save;
3385 ptr = sample;
3387 /* then the color sample */
3388 if(ctmp->var == &ps->vars[V_VIEW_HDR_COLORS]
3389 || ctmp->var == &ps->vars[V_INDEX_TOKEN_COLORS]){
3390 SPEC_COLOR_S *hc, *hcolors;
3392 lastc = newc = NULL;
3394 hcolors =
3395 spec_colors_from_varlist(LVAL(ctmp->var, ew),
3397 for(hc = hcolors, i=0; hc; hc = hc->next, i++)
3398 if(CFC_ICUST(ctmp) == i)
3399 break;
3401 if(hc && hc->fg && hc->fg[0] && hc->bg &&
3402 hc->bg[0])
3403 newc = new_color_pair(hc->fg, hc->bg);
3405 if(newc){
3406 lastc = pico_get_cur_color();
3407 (void)pico_set_colorp(newc, PSC_NONE);
3408 free_color_pair(&newc);
3411 if(hcolors)
3412 free_spec_colors(&hcolors);
3415 /* print out sample1 */
3417 save = *ptr;
3418 *ptr = '\0';
3419 w = utf8_width(tmp_20k_buf);
3420 *ptr = save;
3422 want_width = MIN(utf8_width(SAMP1)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3423 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3424 if(saveptr){
3425 save = *saveptr;
3426 *saveptr = '\0';
3429 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3430 if(saveptr)
3431 *saveptr = save;
3433 ptr = strindex(ptr, ']');
3435 if(lastc){
3436 (void)pico_set_colorp(lastc, PSC_NONE);
3437 free_color_pair(&lastc);
3440 else if(ctmp->var == &ps->vars[V_KW_COLORS]){
3441 KEYWORD_S *kw;
3442 SPEC_COLOR_S *kw_col = NULL;
3444 lastc = newc = NULL;
3446 /* find keyword associated with this line */
3447 for(kw=ps->keywords, i=0; kw; kw=kw->next, i++)
3448 if(CFC_ICUST(ctmp) == i)
3449 break;
3451 if(kw)
3452 kw_col =
3453 spec_colors_from_varlist(LVAL(ctmp->var,ew),
3456 /* color for this keyword */
3457 if(kw && kw_col
3458 && ((kw->nick && kw->nick[0]
3459 && (newc=hdr_color(kw->nick, NULL,
3460 kw_col)))
3462 (kw->kw && kw->kw[0]
3463 && (newc=hdr_color(kw->kw, NULL,
3464 kw_col))))){
3465 lastc = pico_get_cur_color();
3466 (void)pico_set_colorp(newc, PSC_NONE);
3467 free_color_pair(&newc);
3470 if(kw_col)
3471 free_spec_colors(&kw_col);
3473 /* print out sample1 */
3475 save = *ptr;
3476 *ptr = '\0';
3477 w = utf8_width(tmp_20k_buf);
3478 *ptr = save;
3480 want_width = MIN(utf8_width(SAMP1)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3481 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3482 if(saveptr){
3483 save = *saveptr;
3484 *saveptr = '\0';
3487 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3488 if(saveptr)
3489 *saveptr = save;
3491 ptr = strindex(ptr, ']');
3493 if(lastc){
3494 (void)pico_set_colorp(lastc, PSC_NONE);
3495 free_color_pair(&lastc);
3498 else{
3499 lastc = NULL;
3500 invert = 0;
3501 newc = sample_color(ps, ctmp->var);
3502 if(newc){
3503 if((lastc = pico_get_cur_color()) != NULL)
3504 (void)pico_set_colorp(newc, PSC_NONE);
3506 free_color_pair(&newc);
3508 else if(var_defaults_to_rev(ctmp->var)){
3509 if((newc = pico_get_rev_color()) != NULL){
3511 * Note, don't have to free newc.
3513 if((lastc = pico_get_cur_color()) != NULL)
3514 (void)pico_set_colorp(newc, PSC_NONE);
3516 else{
3517 StartInverse();
3518 invert = 1;
3522 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3524 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3525 !(PVAL(ctmp->var,ew) &&
3526 PVAL(ctmp->var+1,ew))))
3527 StartBold();
3529 /* print out sample1 */
3531 save = *ptr;
3532 *ptr = '\0';
3533 w = utf8_width(tmp_20k_buf);
3534 *ptr = save;
3536 want_width = MIN(utf8_width(SAMP1)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3537 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3538 if(saveptr){
3539 save = *saveptr;
3540 *saveptr = '\0';
3543 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3544 if(saveptr)
3545 *saveptr = save;
3547 ptr = strindex(ptr, ']');
3549 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3551 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3552 !(PVAL(ctmp->var,ew) &&
3553 PVAL(ctmp->var+1,ew))))
3554 EndBold();
3556 if(lastc){
3557 (void)pico_set_colorp(lastc, PSC_NONE);
3558 free_color_pair(&lastc);
3560 else if(invert)
3561 EndInverse();
3565 * Finish sample1 with the right bracket.
3567 save = *ptr;
3568 *ptr = '\0';
3569 w = utf8_width(tmp_20k_buf);
3570 *ptr = save;
3571 if(ctmp->valoffset + w < ps->ttyo->screen_cols){
3572 save = *(ptr+1);
3573 *(ptr+1) = '\0';
3574 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3575 *(ptr+1) = save;
3576 ptr++;
3577 w++;
3581 * Now check for an exception sample and paint it.
3583 if(ctmp->valoffset + w + SBS + 1 < ps->ttyo->screen_cols && (q = strstr(ptr, SAMPEXC))){
3584 /* spaces + `[' */
3585 save = ptr[SBS+1];
3586 ptr[SBS+1] = '\0';
3587 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3588 ptr[SBS+1] = save;
3589 ptr += (SBS+1);
3592 * Figure out what color to paint it.
3593 * This only happens with normal variables,
3594 * not with V_VIEW_HDR_COLORS.
3596 lastc = NULL;
3597 invert = 0;
3598 newc = sampleexc_color(ps, ctmp->var);
3599 if(newc){
3600 if((lastc = pico_get_cur_color()) != NULL)
3601 (void)pico_set_colorp(newc, PSC_NONE);
3603 free_color_pair(&newc);
3605 else if(var_defaults_to_rev(ctmp->var)){
3606 if((newc = pico_get_rev_color()) != NULL){
3608 * Note, don't have to free newc.
3610 if((lastc = pico_get_cur_color()) != NULL)
3611 (void)pico_set_colorp(newc, PSC_NONE);
3613 else{
3614 StartInverse();
3615 invert = 1;
3619 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3621 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3622 !(PVAL(ctmp->var,Post) &&
3623 PVAL(ctmp->var+1,Post))))
3624 StartBold();
3626 /* sample2 */
3627 save = *ptr;
3628 *ptr = '\0';
3629 w = utf8_width(tmp_20k_buf);
3630 *ptr = save;
3632 want_width = MIN(utf8_width(SAMPEXC)-2, ps->ttyo->screen_cols - w - ctmp->valoffset);
3633 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3634 if(saveptr){
3635 save = *saveptr;
3636 *saveptr = '\0';
3639 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3640 if(saveptr)
3641 *saveptr = save;
3643 ptr = strindex(ptr, ']');
3645 /* turn off bold and color */
3646 if(ctmp->var==&ps->vars[V_SLCTBL_FORE_COLOR] &&
3648 (F_OFF(F_SLCTBL_ITEM_NOBOLD, ps) ||
3649 !(PVAL(ctmp->var,Post) &&
3650 PVAL(ctmp->var+1,Post))))
3651 EndBold();
3653 if(lastc){
3654 (void)pico_set_colorp(lastc, PSC_NONE);
3655 free_color_pair(&lastc);
3657 else if(invert)
3658 EndInverse();
3661 * Finish sample2 with the right bracket.
3663 save = *ptr;
3664 *ptr = '\0';
3665 w = utf8_width(tmp_20k_buf);
3666 *ptr = save;
3667 if(ctmp->valoffset + w < ps->ttyo->screen_cols){
3668 save = *(ptr+1);
3669 *(ptr+1) = '\0';
3670 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3671 *(ptr+1) = save;
3672 ptr++;
3673 w++;
3677 /* paint rest of the line if there is any left */
3678 if(ctmp->valoffset + w < ps->ttyo->screen_cols && *ptr){
3679 want_width = ps->ttyo->screen_cols - w - ctmp->valoffset;
3680 saveptr = utf8_count_forw_width(ptr, want_width, &got_width);
3681 if(saveptr){
3682 save = *saveptr;
3683 *saveptr = '\0';
3686 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset + w, ptr);
3687 if(saveptr)
3688 *saveptr = save;
3692 else{
3693 w = utf8_width(tmp_20k_buf);
3694 want_width = ps->ttyo->screen_cols - ctmp->valoffset;
3695 if(w > want_width){
3696 saveptr = utf8_count_forw_width(tmp_20k_buf, want_width, &got_width);
3697 if(saveptr)
3698 *saveptr = '\0';
3701 PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset, tmp_20k_buf);
3702 if(ctmp == screen->current)
3703 EndInverse();
3710 ps->mangled_body = 0;
3711 screen->top_line = top_line;
3712 screen->prev = screen->current;
3713 #ifdef _WINDOWS
3714 mswin_endupdate();
3715 #endif
3723 void
3724 print_option_screen(OPT_SCREEN_S *screen, char *prompt)
3726 CONF_S *ctmp;
3727 int so_far;
3728 char line[500];
3730 if(open_printer(prompt) == 0){
3731 for(ctmp = first_confline(screen->current);
3732 ctmp;
3733 ctmp = next_confline(ctmp)){
3735 so_far = 0;
3736 if(ctmp->varname && !(ctmp->flags & CF_INVISIBLEVAR)){
3738 snprintf(line, sizeof(line), "%*s%s", ctmp->varoffset, "",
3739 ctmp->varname);
3740 line[sizeof(line)-1] = '\0';
3741 print_text(line);
3742 so_far = ctmp->varoffset + utf8_width(ctmp->varname);
3745 if(ctmp && ctmp->value){
3746 char *p = tmp_20k_buf;
3747 int i, j, spaces;
3749 /* Copy the value to a temp buffer expanding tabs. */
3750 for(i = 0, j = ctmp->valoffset; ctmp->value[i]; i++){
3751 if(ctmp->value[i] == ctrl('I')){
3753 *p++ = ' ';
3754 while((++j) & 0x07);
3757 else{
3758 *p++ = ctmp->value[i];
3759 j++;
3763 *p = '\0';
3764 removing_trailing_white_space(tmp_20k_buf);
3766 spaces = MAX(ctmp->valoffset - so_far, 0);
3767 snprintf(line, sizeof(line), "%*s%s\n", spaces, "", tmp_20k_buf);
3768 line[sizeof(line)-1] = '\0';
3769 print_text(line);
3773 close_printer();
3782 void
3783 option_screen_redrawer(void)
3785 ps_global->mangled_body = 1;
3786 update_option_screen(ps_global, opt_screen, (Pos *)NULL);
3792 * pretty_value - given the line, return an
3793 * alloc'd string for line's value...
3795 char *
3796 pretty_value(struct pine *ps, CONF_S *cl)
3798 struct variable *v;
3800 v = cl->var;
3802 if(v == &ps->vars[V_FEATURE_LIST])
3803 return(checkbox_pretty_value(ps, cl));
3804 else if(standard_radio_var(ps, v) || v == startup_ptr)
3805 return(radio_pretty_value(ps, cl));
3806 else if(v == &ps->vars[V_SORT_KEY])
3807 return(sort_pretty_value(ps, cl));
3808 else if(v == &ps->vars[V_SIGNATURE_FILE])
3809 return(sigfile_pretty_value(ps, cl));
3810 else if(v == &ps->vars[V_USE_ONLY_DOMAIN_NAME])
3811 return(yesno_pretty_value(ps, cl));
3812 else if(color_holding_var(ps, v))
3813 return(color_pretty_value(ps, cl));
3814 else
3815 return(text_pretty_value(ps, cl));
3819 char *
3820 text_pretty_value(struct pine *ps, CONF_S *cl)
3822 char tmp[6*MAX_SCREEN_COLS+20], *pvalnorm, **lvalnorm, *pvalexc, **lvalexc;
3823 char *p, *pval, **lval, lastchar = '\0';
3824 int editing_except, fixed, uvalset, uvalposlen;
3825 unsigned got_width;
3826 int comments, except_set, avail_width;
3827 int norm_with_except = 0, norm_with_except_inherit = 0;
3828 int inherit_line = 0;
3830 editing_except = (ew == ps_global->ew_for_except_vars);
3831 fixed = cl->var->is_fixed;
3832 if((ps_global->ew_for_except_vars != Main) && (ew == Main))
3833 norm_with_except++; /* editing normal and except config exists */
3835 if(cl->var->is_list){
3836 lvalnorm = LVAL(cl->var, Main);
3837 lvalexc = LVAL(cl->var, ps_global->ew_for_except_vars);
3838 if(editing_except){
3839 uvalset = lvalexc != NULL;
3840 uvalposlen = uvalset && lvalexc[0] && lvalexc[0][0];
3841 lval = lvalexc;
3843 else{
3844 uvalset = lvalnorm != NULL;
3845 uvalposlen = uvalset && lvalnorm[0] && lvalnorm[0][0];
3846 lval = lvalnorm;
3849 except_set = lvalexc != NULL;
3850 comments = cl->var->current_val.l != NULL;
3851 if(norm_with_except && except_set && lvalexc[0] &&
3852 !strcmp(lvalexc[0],INHERIT))
3853 norm_with_except_inherit++;
3855 if(uvalset && !strcmp(lval[0], INHERIT)){
3856 if(cl->varmem == 0){
3857 inherit_line++;
3858 comments = 0;
3862 /* only add extra comments on last member of list */
3863 if(uvalset && !inherit_line && lval && lval[cl->varmem] &&
3864 lval[cl->varmem + 1])
3865 comments = 0;
3867 else{
3868 pvalnorm = PVAL(cl->var, Main);
3869 pvalexc = PVAL(cl->var, ps_global->ew_for_except_vars);
3870 if(editing_except){
3871 uvalset = pvalexc != NULL;
3872 uvalposlen = uvalset && *pvalexc;
3873 pval = pvalexc;
3875 else{
3876 uvalset = pvalnorm != NULL;
3877 uvalposlen = uvalset && *pvalnorm;
3878 pval = pvalnorm;
3881 except_set = pvalexc != NULL;
3882 comments = cl->var->current_val.p != NULL;
3885 memset(tmp, 0, sizeof(tmp));
3886 p = tmp;
3887 *p = '\0';
3889 avail_width = ps->ttyo->screen_cols - cl->valoffset;
3891 if(fixed || !uvalset || !uvalposlen){
3892 p += utf8_to_width(p, "<", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3893 avail_width -= got_width;
3896 if(fixed){
3897 p += utf8_to_width(p, _(fixed_val), sizeof(tmp)-(p-tmp), avail_width, &got_width);
3898 avail_width -= got_width;
3900 else if(!uvalset){
3901 p += utf8_to_width(p, _(no_val), sizeof(tmp)-(p-tmp), avail_width, &got_width);
3902 avail_width -= got_width;
3904 else if(!uvalposlen){
3905 p += utf8_to_width(p, _(empty_val), sizeof(tmp)-(p-tmp), avail_width, &got_width);
3906 avail_width -= got_width;
3908 else if(inherit_line){
3909 p += utf8_to_width(p, INHERIT, sizeof(tmp)-(p-tmp), avail_width, &got_width);
3910 avail_width -= got_width;
3912 else{
3913 if(cl->var->is_list){
3914 p += utf8_to_width(p, lval[cl->varmem], sizeof(tmp)-(p-tmp), avail_width, &got_width);
3915 avail_width -= got_width;
3917 else{
3918 p += utf8_to_width(p, pval, sizeof(tmp)-(p-tmp), avail_width, &got_width);
3919 avail_width -= got_width;
3923 if(comments && (fixed || !uvalset || (norm_with_except && except_set))){
3924 if(fixed || !uvalset){
3925 p += utf8_to_width(p, ": using ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3926 avail_width -= got_width;
3929 if(norm_with_except && except_set){
3930 if(!uvalset){
3931 p += utf8_to_width(p, "exception ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3932 avail_width -= got_width;
3934 else if(!fixed){
3935 if(!uvalposlen){
3936 p += utf8_to_width(p, ": ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3937 avail_width -= got_width;
3939 else{
3940 p += utf8_to_width(p, " (", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3941 avail_width -= got_width;
3944 if(norm_with_except_inherit){
3945 p += utf8_to_width(p, "added to by exception ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3946 avail_width -= got_width;
3948 else{
3949 p += utf8_to_width(p, "overridden by exception ", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3950 avail_width -= got_width;
3955 if(avail_width >= 7){
3956 if(cl->var == &ps_global->vars[V_POST_CHAR_SET]){
3957 p += utf8_to_width(p, "most specific (see help)", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3958 avail_width -= got_width;
3960 else{
3961 sstrncpy(&p, "\"", sizeof(tmp)-(p-tmp));
3962 avail_width--;
3963 if(cl->var->is_list){
3964 char **the_list;
3966 the_list = cl->var->current_val.l;
3968 if(norm_with_except && except_set)
3969 the_list = lvalexc;
3971 if(the_list && the_list[0] && !strcmp(the_list[0], INHERIT))
3972 the_list++;
3974 for(lval = the_list; avail_width-(p-tmp) > 0 && *lval; lval++){
3975 if(lval != the_list){
3976 p += utf8_to_width(p, ",", sizeof(tmp)-(p-tmp), avail_width, &got_width);
3977 avail_width -= got_width;
3980 p += utf8_to_width(p, *lval, sizeof(tmp)-(p-tmp), avail_width, &got_width);
3981 avail_width -= got_width;
3984 else{
3985 p += utf8_to_width(p, cl->var->current_val.p, sizeof(tmp)-(p-tmp), avail_width, &got_width);
3986 avail_width -= got_width;
3989 if(p-tmp+2 < sizeof(tmp)){
3990 *p++ = '\"';
3991 *p = '\0';
3995 else if(*(p-1) == SPACE)
3996 *--p = '\0';
3999 tmp[sizeof(tmp)-1] = '\0';
4001 if(fixed || !uvalset || !uvalposlen)
4002 lastchar = '>';
4003 else if(comments && norm_with_except && except_set)
4004 lastchar = ')';
4006 if(lastchar){
4007 if(p-tmp+2 < sizeof(tmp)){
4008 *p++ = lastchar;
4009 *p = '\0';
4013 tmp[sizeof(tmp)-1] = '\0';
4014 avail_width = ps->ttyo->screen_cols - cl->valoffset;
4016 if(utf8_width(tmp) < avail_width)
4017 snprintf(tmp+strlen(tmp), sizeof(tmp)-strlen(tmp), "%*s", avail_width-utf8_width(tmp), "");
4019 tmp[sizeof(tmp)-1] = '\0';
4021 return(cpystr(tmp));
4025 char *
4026 checkbox_pretty_value(struct pine *ps, CONF_S *cl)
4028 char tmp[6*MAXPATH];
4029 char *comment = NULL;
4030 int indent, x, screen_width, need;
4031 int longest_featname, longest_comment;
4032 int nwidcomm; /* name width with comment */
4033 int nwidnocomm; /* and without comment */
4034 FEATURE_S *feature;
4036 screen_width = (ps && ps->ttyo) ? ps->ttyo->screen_cols : 80;
4037 tmp[0] = '\0';
4039 longest_featname = longest_feature_name();
4040 longest_comment = longest_feature_comment(ps, ew);
4041 indent = feature_indent();
4043 nwidcomm = longest_featname;
4044 nwidnocomm = longest_featname + 2 + longest_comment;
4046 if((need = (indent + 5 + longest_featname + 2 + longest_comment) - screen_width) > 0){
4047 if(need < 10){
4048 nwidcomm -= need;
4049 nwidnocomm -= need;
4051 else{
4052 longest_comment = 0;
4053 nwidnocomm = longest_featname;
4057 feature = feature_list(cl->varmem);
4059 x = feature_gets_an_x(ps, cl->var, feature, &comment, ew);
4061 if(longest_comment && comment && *comment){
4062 utf8_snprintf(tmp, sizeof(tmp), "[%c] %-*.*w %-*.*w", x ? 'X' : ' ',
4063 nwidcomm, nwidcomm,
4064 pretty_feature_name(feature->name, nwidcomm),
4065 longest_comment, longest_comment, comment ? comment : "");
4067 else{
4068 utf8_snprintf(tmp, sizeof(tmp), "[%c] %-*.*w", x ? 'X' : ' ',
4069 nwidnocomm, nwidnocomm,
4070 pretty_feature_name(feature->name, nwidnocomm));
4073 return(cpystr(tmp));
4078 longest_feature_name(void)
4080 static int lv = -1;
4081 int i, j;
4082 FEATURE_S *feature;
4084 if(lv < 0){
4085 for(lv = 0, i = 0; (feature = feature_list(i)); i++)
4086 if(feature_list_section(feature)
4087 && lv < (j = utf8_width(pretty_feature_name(feature->name, -1))))
4088 lv = j;
4090 lv = MIN(lv, 100);
4093 return(lv);
4098 feature_indent(void)
4100 return(6);
4104 char *
4105 yesno_pretty_value(struct pine *ps, CONF_S *cl)
4107 char tmp[6*MAXPATH], *pvalnorm, *pvalexc;
4108 char *p, *pval, lastchar = '\0';
4109 int editing_except, fixed, norm_with_except, uvalset;
4110 int curval, except_set;
4112 editing_except = (ew == ps_global->ew_for_except_vars);
4113 fixed = cl->var->is_fixed;
4114 if((ps_global->ew_for_except_vars == Main) ||
4115 (ew == ps_global->ew_for_except_vars))
4116 norm_with_except = 0;
4117 else
4118 norm_with_except = 1; /* editing normal and except config exists */
4120 pvalnorm = PVAL(cl->var, Main);
4121 pvalexc = PVAL(cl->var, ps_global->ew_for_except_vars);
4122 if(editing_except){
4123 uvalset = (pvalexc != NULL &&
4124 (!strucmp(pvalexc,yesstr) || !strucmp(pvalexc,nostr)));
4125 pval = pvalexc;
4127 else{
4128 uvalset = (pvalnorm != NULL &&
4129 (!strucmp(pvalnorm,yesstr) || !strucmp(pvalnorm,nostr)));
4130 pval = pvalnorm;
4133 except_set = (pvalexc != NULL &&
4134 (!strucmp(pvalexc,yesstr) || !strucmp(pvalexc,nostr)));
4135 curval = (cl->var->current_val.p != NULL &&
4136 (!strucmp(cl->var->current_val.p,yesstr) ||
4137 !strucmp(cl->var->current_val.p,nostr)));
4139 p = tmp;
4140 *p = '\0';
4142 if(fixed || !uvalset)
4143 sstrncpy(&p, "<", sizeof(tmp)-(p-tmp));
4145 if(fixed)
4146 sstrncpy(&p, _(fixed_val), sizeof(tmp)-(p-tmp));
4147 else if(!uvalset)
4148 sstrncpy(&p, _(no_val), sizeof(tmp)-(p-tmp));
4149 else if(!strucmp(pval, yesstr))
4150 sstrncpy(&p, yesstr, sizeof(tmp)-(p-tmp));
4151 else
4152 sstrncpy(&p, nostr, sizeof(tmp)-(p-tmp));
4154 if(curval && (fixed || !uvalset || (norm_with_except && except_set))){
4155 if(fixed || !uvalset)
4156 sstrncpy(&p, ": using ", sizeof(tmp)-(p-tmp));
4158 if(norm_with_except && except_set){
4159 if(!uvalset)
4160 sstrncpy(&p, "exception ", sizeof(tmp)-(p-tmp));
4161 else if(!fixed){
4162 sstrncpy(&p, " (", sizeof(tmp)-(p-tmp));
4163 sstrncpy(&p, "overridden by exception ", sizeof(tmp)-(p-tmp));
4167 sstrncpy(&p, "\"", sizeof(tmp)-(p-tmp));
4168 sstrncpy(&p, !strucmp(cl->var->current_val.p,yesstr) ? yesstr : nostr, sizeof(tmp)-(p-tmp));
4169 sstrncpy(&p, "\"", sizeof(tmp)-(p-tmp));
4172 if(fixed || !uvalset)
4173 lastchar = '>';
4174 else if(curval && norm_with_except && except_set)
4175 lastchar = ')';
4177 if(lastchar && sizeof(tmp)-(p-tmp) > 1){
4178 *p++ = lastchar;
4179 *p = '\0';
4182 tmp[sizeof(tmp)-1] = '\0';
4184 if(utf8_width(tmp) < ps->ttyo->screen_cols - cl->valoffset)
4185 snprintf(tmp+strlen(tmp), sizeof(tmp)-strlen(tmp),
4186 "%*s", ps->ttyo->screen_cols - cl->valoffset - utf8_width(tmp), "");
4188 tmp[sizeof(tmp)-1] = '\0';
4190 return(cpystr(tmp));
4194 char *
4195 radio_pretty_value(struct pine *ps, CONF_S *cl)
4197 char tmp[6*MAXPATH];
4198 char *pvalnorm, *pvalexc, *pval;
4199 int editing_except_which_isnt_normal, editing_normal_which_isnt_except;
4200 int fixed, is_set_for_this_level = 0, is_the_one, the_exc_one;
4201 int i, j, lv = 0;
4202 NAMEVAL_S *rule = NULL, *f;
4203 PTR_TO_RULEFUNC rulefunc;
4204 struct variable *v;
4206 tmp[0] = '\0';
4207 v = cl->var;
4209 editing_except_which_isnt_normal = (ew == ps_global->ew_for_except_vars &&
4210 ew != Main);
4211 editing_normal_which_isnt_except = (ew == Main &&
4212 ew != ps_global->ew_for_except_vars);
4213 fixed = cl->var->is_fixed;
4214 pvalnorm = PVAL(v, Main);
4215 pvalexc = PVAL(v, ps_global->ew_for_except_vars);
4217 rulefunc = rulefunc_from_var(ps, v);
4218 rule = rulefunc ? (*rulefunc)(cl->varmem) : NULL;
4220 /* find longest name */
4221 if(rulefunc)
4222 for(lv = 0, i = 0; (f = (*rulefunc)(i)); i++)
4223 if(lv < (j = utf8_width(f->name)))
4224 lv = j;
4226 lv = MIN(lv, 100);
4228 if(editing_except_which_isnt_normal)
4229 pval = pvalexc;
4230 else
4231 pval = pvalnorm;
4233 if(pval)
4234 is_set_for_this_level++;
4236 if(fixed){
4237 pval = v->fixed_val.p;
4238 is_the_one = (pval && !strucmp(pval, S_OR_L(rule)));
4240 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4241 is_the_one ? R_SELD : ' ',
4242 lv, lv, rule->name, is_the_one ? " (value is fixed)" : "");
4244 else if(is_set_for_this_level){
4245 is_the_one = (pval && !strucmp(pval, S_OR_L(rule)));
4246 the_exc_one = (editing_normal_which_isnt_except && pvalexc &&
4247 !strucmp(pvalexc, S_OR_L(rule)));
4248 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4249 is_the_one ? R_SELD : ' ',
4250 lv, lv, rule->name,
4251 (!is_the_one && the_exc_one) ? " (value set in exceptions)" :
4252 (is_the_one && the_exc_one) ? " (also set in exceptions)" :
4253 (is_the_one &&
4254 editing_normal_which_isnt_except &&
4255 pvalexc &&
4256 !the_exc_one) ? " (overridden by exceptions)" :
4257 "");
4259 else{
4260 if(pvalexc){
4261 is_the_one = !strucmp(pvalexc, S_OR_L(rule));
4262 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4263 is_the_one ? R_SELD : ' ',
4264 lv, lv, rule->name,
4265 is_the_one ? " (value set in exceptions)" : "");
4267 else{
4268 pval = v->current_val.p;
4269 is_the_one = (pval && !strucmp(pval, S_OR_L(rule)));
4270 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*.*w%s",
4271 is_the_one ? R_SELD : ' ',
4272 lv, lv, rule->name,
4273 is_the_one ? ((editing_except_which_isnt_normal && pvalnorm) ? " (default from regular config)" : " (default)") : "");
4277 tmp[sizeof(tmp)-1] = '\0';
4279 return(cpystr(tmp));
4283 char *
4284 sigfile_pretty_value(struct pine *ps, CONF_S *cl)
4286 if(cl && cl->var == &ps->vars[V_SIGNATURE_FILE] &&
4287 cl->prev && cl->prev->var == &ps->vars[V_LITERAL_SIG]){
4288 if(cl->prev->var->current_val.p){
4289 cl->flags |= CF_NOSELECT; /* side effect */
4290 return(cpystr(_("<Ignored: using Literal-Signature instead>")));
4292 else{
4293 cl->flags &= ~CF_NOSELECT;
4294 return(text_pretty_value(ps, cl));
4297 else
4298 return(cpystr(""));
4302 char *
4303 color_pretty_value(struct pine *ps, CONF_S *cl)
4305 char tmp[6*MAXPATH];
4306 char *p, *q;
4307 struct variable *v;
4308 int is_index;
4310 tmp[0] = '\0';
4311 v = cl->var;
4313 if(v && color_holding_var(ps, v) &&
4314 (p=srchstr(v->name, "-foreground-color"))){
4316 is_index = !struncmp(v->name, "index-", 6);
4318 q = sampleexc_text(ps, v);
4319 utf8_snprintf(tmp, sizeof(tmp), "%c%.*s %sColor%*.50s %.20w%*s%.20w%.20w",
4320 islower((unsigned char)v->name[0])
4321 ? toupper((unsigned char)v->name[0])
4322 : v->name[0],
4323 MIN(p-v->name-1,30), v->name+1,
4324 is_index ? "Symbol " : "",
4325 MAX(EQ_COL - COLOR_INDENT -1 - MIN(p-v->name-1,30)
4326 - 6 - (is_index ? 7 : 0) - 1,0), "",
4327 sample_text(ps,v), *q ? SBS : 0, "", q,
4328 color_parenthetical(v));
4331 tmp[sizeof(tmp)-1] = '\0';
4333 return(cpystr(tmp));
4337 char *
4338 sort_pretty_value(struct pine *ps, CONF_S *cl)
4340 return(generalized_sort_pretty_value(ps, cl, 1));
4344 char *
4345 generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok)
4347 char tmp[6*MAXPATH];
4348 char *pvalnorm, *pvalexc, *pval;
4349 int editing_except_which_isnt_normal, editing_normal_which_isnt_except;
4350 int fixed, is_set_for_this_level = 0, is_the_one, the_exc_one;
4351 int i, j, lv = 0;
4352 struct variable *v;
4353 SortOrder line_sort, var_sort, exc_sort;
4354 int line_sort_rev, var_sort_rev, exc_sort_rev;
4356 tmp[0] = '\0';
4357 v = cl->var;
4359 editing_except_which_isnt_normal = (ew == ps_global->ew_for_except_vars &&
4360 ew != Main);
4361 editing_normal_which_isnt_except = (ew == Main &&
4362 ew != ps_global->ew_for_except_vars);
4363 fixed = cl->var->is_fixed;
4364 pvalnorm = PVAL(v, Main);
4365 pvalexc = PVAL(v, ps_global->ew_for_except_vars);
4367 /* find longest value's name */
4368 for(lv = 0, i = 0; ps->sort_types[i] != EndofList; i++)
4369 if(lv < (j = utf8_width(sort_name(ps->sort_types[i]))))
4370 lv = j;
4372 lv = MIN(lv, 100);
4374 if(editing_except_which_isnt_normal)
4375 pval = pvalexc;
4376 else
4377 pval = pvalnorm;
4379 if(pval)
4380 is_set_for_this_level++;
4382 /* the config line we're talking about */
4383 if(cl->varmem >= 0){
4384 line_sort_rev = cl->varmem >= (short)EndofList;
4385 line_sort = (SortOrder)(cl->varmem - (line_sort_rev * EndofList));
4388 if(cl->varmem < 0){
4389 utf8_snprintf(tmp, sizeof(tmp), "(%c) %-*w",
4390 (pval == NULL) ? R_SELD : ' ',
4391 lv, "Default");
4393 else if(fixed){
4394 pval = v->fixed_val.p;
4395 decode_sort(pval, &var_sort, &var_sort_rev);
4396 is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
4398 utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s",
4399 is_the_one ? R_SELD : ' ',
4400 line_sort_rev ? "Reverse " : "",
4401 lv, sort_name(line_sort),
4402 line_sort_rev ? 0 : 8, "",
4403 is_the_one ? " (value is fixed)" : "");
4405 else if(is_set_for_this_level){
4406 decode_sort(pval, &var_sort, &var_sort_rev);
4407 is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort);
4408 decode_sort(pvalexc, &exc_sort, &exc_sort_rev);
4409 the_exc_one = (editing_normal_which_isnt_except && pvalexc &&
4410 exc_sort_rev == line_sort_rev && exc_sort == line_sort);
4411 utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s",
4412 is_the_one ? R_SELD : ' ',
4413 line_sort_rev ? "Reverse " : "",
4414 lv, sort_name(line_sort),
4415 line_sort_rev ? 0 : 8, "",
4416 (!is_the_one && the_exc_one) ? " (value set in exceptions)" :
4417 (is_the_one && the_exc_one) ? " (also set in exceptions)" :
4418 (is_the_one &&
4419 editing_normal_which_isnt_except &&
4420 pvalexc &&
4421 !the_exc_one) ? " (overridden by exceptions)" :
4422 "");
4424 else{
4425 if(pvalexc){
4426 decode_sort(pvalexc, &exc_sort, &exc_sort_rev);
4427 is_the_one = (exc_sort_rev == line_sort_rev &&
4428 exc_sort == line_sort);
4429 utf8_snprintf(tmp, sizeof(tmp), "( ) %s%-*w%*s%s",
4430 line_sort_rev ? "Reverse " : "",
4431 lv, sort_name(line_sort),
4432 line_sort_rev ? 0 : 8, "",
4433 is_the_one ? " (value set in exceptions)" : "");
4435 else{
4436 pval = v->current_val.p;
4437 decode_sort(pval, &var_sort, &var_sort_rev);
4438 is_the_one = ((pval || default_ok) &&
4439 var_sort_rev == line_sort_rev &&
4440 var_sort == line_sort);
4441 utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s",
4442 is_the_one ? R_SELD : ' ',
4443 line_sort_rev ? "Reverse " : "",
4444 lv, sort_name(line_sort),
4445 line_sort_rev ? 0 : 8, "",
4446 is_the_one ? ((editing_except_which_isnt_normal && pvalnorm) ? " (default from regular config)" : " (default)") : "");
4450 return(cpystr(tmp));
4454 COLOR_PAIR *
4455 sample_color(struct pine *ps, struct variable *v)
4457 COLOR_PAIR *cp = NULL;
4458 char *pvalefg, *pvalebg;
4459 char *pvalmfg, *pvalmbg;
4461 pvalefg = PVAL(v, ew);
4462 pvalebg = PVAL(v+1, ew);
4463 pvalmfg = PVAL(v, Main);
4464 pvalmbg = PVAL(v+1, Main);
4465 if(v && color_holding_var(ps, v) &&
4466 srchstr(v->name, "-foreground-color")){
4467 if(pvalefg && pvalefg[0] && pvalebg && pvalebg[0])
4468 cp = new_color_pair(pvalefg, pvalebg);
4469 else if(ew == Post && pvalmfg && pvalmfg[0] && pvalmbg && pvalmbg[0])
4470 cp = new_color_pair(pvalmfg, pvalmbg);
4471 else if(v->global_val.p && v->global_val.p[0] &&
4472 (v+1)->global_val.p && (v+1)->global_val.p[0])
4473 cp = new_color_pair(v->global_val.p, (v+1)->global_val.p);
4476 return(cp);
4480 COLOR_PAIR *
4481 sampleexc_color(struct pine *ps, struct variable *v)
4483 COLOR_PAIR *cp = NULL;
4484 char *pvalfg, *pvalbg;
4486 pvalfg = PVAL(v, Post);
4487 pvalbg = PVAL(v+1, Post);
4488 if(v && color_holding_var(ps, v) &&
4489 srchstr(v->name, "-foreground-color") &&
4490 pvalfg && pvalfg[0] && pvalbg && pvalbg[0])
4491 cp = new_color_pair(pvalfg, pvalbg);
4493 return(cp);
4497 void
4498 clear_feature(char ***l, char *f)
4500 char **list = l ? *l : NULL;
4501 int count = 0;
4503 for(; list && *list; list++, count++){
4504 if(f && !strucmp(((!struncmp(*list,"no-",3)) ? *list + 3 : *list), f)){
4505 fs_give((void **)list);
4506 f = NULL;
4509 if(!f) /* shift */
4510 *list = *(list + 1);
4514 * this is helpful to keep the array from growing if a feature
4515 * get's set and unset repeatedly
4517 if(!f)
4518 fs_resize((void **)l, count * sizeof(char *));
4525 void
4526 toggle_feature_bit(struct pine *ps, int index, struct variable *var, CONF_S *cl, int just_flip_value)
4528 FEATURE_S *f;
4529 int og, on_before;
4530 char *p, **vp;
4532 f = feature_list(index);
4534 og = test_old_growth_bits(ps, f->id);
4537 * if this feature is in the fixed set, or old-growth is in the fixed
4538 * set and this feature is in the old-growth set, don't alter it...
4540 for(vp = var->fixed_val.l; vp && *vp; vp++){
4541 p = (struncmp(*vp, "no-", 3)) ? *vp : *vp + 3;
4542 if(!strucmp(p, f->name) || (og && !strucmp(p, "old-growth"))){
4543 q_status_message(SM_ORDER, 3, 3,
4544 _("Can't change value fixed by sys-admin."));
4545 return;
4549 on_before = F_ON(f->id, ps);
4551 toggle_feature(ps, var, f, just_flip_value, ew);
4554 * Handle any alpine-specific features that need attention here. Features
4555 * that aren't alpine-specific should be handled in toggle_feature instead.
4557 if(on_before != F_ON(f->id, ps))
4558 switch(f->id){
4559 case F_CMBND_ABOOK_DISP :
4560 addrbook_reset();
4561 break;
4563 case F_PRESERVE_START_STOP :
4564 /* toggle raw mode settings to make tty driver aware of new setting */
4565 PineRaw(0);
4566 PineRaw(1);
4567 break;
4569 case F_USE_FK :
4570 ps->orig_use_fkeys = F_ON(F_USE_FK, ps);
4571 ps->mangled_footer = 1;
4572 mark_keymenu_dirty();
4573 break;
4575 case F_SHOW_SORT :
4576 ps->mangled_header = 1;
4577 break;
4579 case F_BLANK_KEYMENU :
4580 if(F_ON(f->id, ps)){
4581 FOOTER_ROWS(ps) = 1;
4582 ps->mangled_body = 1;
4584 else{
4585 FOOTER_ROWS(ps) = 3;
4586 ps->mangled_footer = 1;
4589 clearfooter(ps);
4590 break;
4592 case F_ENABLE_INCOMING :
4593 q_status_message(SM_ORDER | SM_DING, 3, 4,
4594 "Folder List changes will take effect your next Alpine session.");
4595 break;
4597 #ifdef _WINDOWS
4598 case F_SHOW_CURSOR :
4599 mswin_showcaret(F_ON(f->id,ps));
4600 break;
4602 case F_ENABLE_TRAYICON :
4603 mswin_trayicon(F_ON(f->id,ps));
4604 break;
4605 #endif
4607 #if !defined(DOS) && !defined(OS2)
4608 case F_ALLOW_TALK :
4609 if(F_ON(f->id, ps))
4610 allow_talk(ps);
4611 else
4612 disallow_talk(ps);
4614 break;
4615 #endif
4617 case F_PASS_CONTROL_CHARS :
4618 ps->pass_ctrl_chars = F_ON(F_PASS_CONTROL_CHARS,ps_global) ? 1 : 0;
4619 break;
4621 #ifdef SMIME
4622 case F_USE_CERT_STORE_ONLY:
4623 if(F_OFF(F_USE_CERT_STORE_ONLY, ps))
4624 q_status_message(SM_ORDER | SM_DING, 3, 4,
4625 "Disabling this feature should only be done for testing. Press \"?\" for help");
4626 break;
4627 #endif /* SMIME */
4629 case F_PASS_C1_CONTROL_CHARS :
4630 ps->pass_c1_ctrl_chars = F_ON(F_PASS_C1_CONTROL_CHARS,ps_global) ? 1 : 0;
4631 break;
4633 #ifdef MOUSE
4634 case F_ENABLE_MOUSE :
4635 if(F_ON(f->id, ps)){
4636 init_mouse();
4637 if(!mouseexist())
4638 q_status_message(SM_ORDER | SM_DING, 3, 4,
4639 "Mouse tracking still off ($DISPLAY variable set?)");
4641 else
4642 end_mouse();
4644 break;
4645 #endif
4648 if(just_flip_value){
4649 if(cl->value && cl->value[0])
4650 cl->value[1] = (cl->value[1] == ' ') ? 'X' : ' ';
4652 else{
4654 * This fork is only called from the checkbox_tool, which has
4655 * varmem set to index correctly and cl->var set correctly.
4657 if(cl->value)
4658 fs_give((void **)&cl->value);
4660 cl->value = pretty_value(ps, cl);
4666 * new_confline - create new CONF_S zero it out, and insert it after current.
4667 * NOTE current gets set to the new CONF_S too!
4669 CONF_S *
4670 new_confline(CONF_S **current)
4672 CONF_S *p;
4674 p = (CONF_S *)fs_get(sizeof(CONF_S));
4675 memset((void *)p, 0, sizeof(CONF_S));
4676 if(current){
4677 if(*current){
4678 p->next = (*current)->next;
4679 (*current)->next = p;
4680 p->prev = *current;
4681 if(p->next)
4682 p->next->prev = p;
4685 *current = p;
4688 return(p);
4695 void
4696 snip_confline(CONF_S **p)
4698 CONF_S *q;
4701 * Be careful. We need this line because the
4702 * q->prev->next = ...
4703 * may change q itself if &q == &q->prev->next.
4704 * Then the use of q in the next line is wrong.
4705 * That's what happens if we pass in the address of
4706 * some ->next and use *p directly instead of q.
4708 q = *p;
4710 if(q){
4711 /* Yank it from the linked list */
4712 if(q->prev)
4713 q->prev->next = q->next;
4715 if(q->next)
4716 q->next->prev = q->prev;
4718 /* Then free up it's memory */
4719 q->prev = q->next = NULL;
4720 free_conflines(&q);
4724 int
4725 get_confline_number(CONF_S *conf)
4727 int pos;
4728 CONF_S *p;
4730 for (p = first_confline(conf), pos = 0; p != conf; p = next_confline(p), pos++);
4732 return pos;
4736 CONF_S *
4737 set_confline_number(CONF_S *conf, int pos)
4739 CONF_S *p;
4740 int i;
4741 for(p = first_confline(conf), i = 0; p && i < pos; p=next_confline(p), i++);
4742 return p;
4749 void
4750 free_conflines(CONF_S **p)
4752 if(*p){
4753 free_conflines(&(*p)->next);
4755 if((*p)->varname)
4756 fs_give((void **) &(*p)->varname);
4758 if((*p)->value)
4759 fs_give((void **) &(*p)->value);
4761 fs_give((void **) p);
4769 CONF_S *
4770 first_confline(CONF_S *p)
4772 while(p && p->prev)
4773 p = p->prev;
4775 return(p);
4780 * First selectable confline.
4782 CONF_S *
4783 first_sel_confline(CONF_S *p)
4785 for(p = first_confline(p); p && (p->flags&CF_NOSELECT); p=next_confline(p))
4786 ;/* do nothing */
4788 return(p);
4795 CONF_S *
4796 last_confline(CONF_S *p)
4798 while(p && p->next)
4799 p = p->next;
4801 return(p);
4809 fixed_var(struct variable *v, char *action, char *name)
4811 char **lval;
4813 if(v && v->is_fixed
4814 && (!v->is_list
4815 || ((lval=v->fixed_val.l) && lval[0]
4816 && strcmp(INHERIT, lval[0]) != 0))){
4817 q_status_message2(SM_ORDER, 3, 3,
4818 "Can't %s sys-admin defined %s.",
4819 action ? action : "change", name ? name : "value");
4820 return(1);
4823 return(0);
4827 void
4828 exception_override_warning(struct variable *v)
4830 char **lval;
4832 /* if exceptions config file exists and we're not editing it */
4833 if(v && (ps_global->ew_for_except_vars != Main) && (ew == Main)){
4834 if((!v->is_list && PVAL(v, ps_global->ew_for_except_vars)) ||
4835 (v->is_list && (lval=LVAL(v, ps_global->ew_for_except_vars)) &&
4836 lval[0] && strcmp(INHERIT, lval[0]) != 0))
4837 q_status_message1(SM_ORDER, 3, 3,
4838 _("Warning: \"%s\" is overridden in your exceptions configuration"),
4839 v->name);
4844 void
4845 offer_to_fix_pinerc(struct pine *ps)
4847 struct variable *v;
4848 char prompt[300];
4849 char *p, *q;
4850 char **list;
4851 char **list_fixed;
4852 int rv = 0, write_main = 0, write_post = 0;
4853 int i, k, j, need, exc;
4854 char *clear = ": delete it";
4855 char ***plist;
4857 dprint((4, "offer_to_fix_pinerc()\n"));
4859 ps->fix_fixed_warning = 0; /* so we only ask first time */
4861 if(ps->readonly_pinerc)
4862 return;
4864 set_titlebar(_("FIXING PINERC"), ps->mail_stream,
4865 ps->context_current,
4866 ps->cur_folder, ps->msgmap, 1, FolderName, 0, 0, NULL);
4868 if(want_to(_("Some of your options conflict with site policy. Investigate"),
4869 'y', 'n', NO_HELP, WT_FLUSH_IN) != 'y')
4870 return;
4872 /* space want_to requires in addition to the string you pass in */
4873 #define WANTTO_SPACE 6
4874 need = WANTTO_SPACE + utf8_width(clear);
4876 for(v = ps->vars; v->name; v++){
4877 if(!v->is_fixed ||
4878 !v->is_user ||
4879 v->is_obsolete ||
4880 v == &ps->vars[V_FEATURE_LIST]) /* handle feature-list below */
4881 continue;
4883 prompt[0] = '\0';
4885 if(v->is_list &&
4886 (v->post_user_val.l || v->main_user_val.l)){
4887 char **active_list;
4889 active_list = v->post_user_val.l ? v->post_user_val.l
4890 : v->main_user_val.l;
4891 if(*active_list){
4892 snprintf(prompt, sizeof(prompt), _("Your setting for %s is "), v->name);
4893 prompt[sizeof(prompt)-1] = '\0';
4894 p = prompt + strlen(prompt);
4895 for(i = 0; active_list[i]; i++){
4896 if(utf8_width(prompt) > ps->ttyo->screen_cols - need)
4897 break;
4898 if(i && sizeof(prompt)-(p-prompt) > 0)
4899 *p++ = ',';
4901 sstrncpy(&p, active_list[i], sizeof(prompt)-(p-prompt));
4902 if(sizeof(prompt)-(p-prompt) > 0)
4903 *p = '\0';
4905 prompt[sizeof(prompt)-1] = '\0';
4908 if(sizeof(prompt)-(p-prompt) > 0)
4909 *p = '\0';
4911 else
4912 snprintf(prompt, sizeof(prompt), _("Your setting for %s is %s"), v->name, _(empty_val2));
4914 else{
4915 if(v->post_user_val.p || v->main_user_val.p){
4916 char *active_var;
4918 active_var = v->post_user_val.p ? v->post_user_val.p
4919 : v->main_user_val.p;
4920 if(*active_var){
4921 snprintf(prompt, sizeof(prompt), _("Your setting for %s is %s"),
4922 v->name, active_var);
4924 else{
4925 snprintf(prompt, sizeof(prompt), _("Your setting for %s is %s"),
4926 v->name, _(empty_val2));
4931 prompt[sizeof(prompt)-1] = '\0';
4933 if(*prompt){
4934 if(utf8_width(prompt) > ps->ttyo->screen_cols - need)
4935 (void) utf8_truncate(prompt, ps->ttyo->screen_cols - need);
4937 (void) strncat(prompt, clear, sizeof(prompt)-strlen(prompt)-1);
4938 prompt[sizeof(prompt)-1] = '\0';
4939 if(want_to(prompt, 'y', 'n', NO_HELP, WT_NORM) == 'y'){
4940 if(v->is_list){
4941 if(v->main_user_val.l)
4942 write_main++;
4943 if(v->post_user_val.l)
4944 write_post++;
4946 else{
4947 if(v->main_user_val.p)
4948 write_main++;
4949 if(v->post_user_val.p)
4950 write_post++;
4953 if(delete_user_vals(v))
4954 rv++;
4961 * As always, feature-list has to be handled separately.
4963 exc = (ps->ew_for_except_vars != Main);
4964 v = &ps->vars[V_FEATURE_LIST];
4965 list_fixed = v->fixed_val.l;
4967 for(j = 0; j < 2; j++){
4968 plist = (j==0) ? &v->main_user_val.l : &v->post_user_val.l;
4969 list = *plist;
4970 if(list){
4971 for(i = 0; list[i]; i++){
4972 p = list[i];
4973 if(!struncmp(p, "no-", 3))
4974 p += 3;
4975 for(k = 0; list_fixed && list_fixed[k]; k++){
4976 q = list_fixed[k];
4977 if(!struncmp(q, "no-", 3))
4978 q += 3;
4979 if(!strucmp(q, p) && strucmp(list[i], list_fixed[k])){
4980 snprintf(prompt, sizeof(prompt), "Your %s is %s%s, fixed value is %s",
4981 p, p == list[i] ? _("ON") : _("OFF"),
4982 exc ? ((plist == &v->main_user_val.l) ? ""
4983 : " in postload-config")
4984 : "",
4985 q == list_fixed[k] ? _("ON") : _("OFF"));
4987 prompt[sizeof(prompt)-1] = '\0';
4988 if(utf8_width(prompt) > ps->ttyo->screen_cols - need)
4989 (void) utf8_truncate(prompt, ps->ttyo->screen_cols - need);
4991 (void) strncat(prompt, clear, sizeof(prompt)-strlen(prompt)-1);
4992 prompt[sizeof(prompt)-1] = '\0';
4993 if(want_to(prompt, 'y', 'n', NO_HELP, WT_NORM) == 'y'){
4994 rv++;
4996 if(plist == &v->main_user_val.l)
4997 write_main++;
4998 else
4999 write_post++;
5002 * Clear the feature from the user's pinerc
5003 * so that we'll stop bothering them when they
5004 * start up Pine.
5006 clear_feature(plist, p);
5009 * clear_feature scoots the list up, so if list[i] was
5010 * the last one going in, now it is the end marker. We
5011 * just decrement i so that it will get incremented and
5012 * then test == 0 in the for loop. We could just goto
5013 * outta_here to accomplish the same thing.
5015 if(!list[i])
5016 i--;
5025 if(write_main)
5026 write_pinerc(ps, Main, WRP_NONE);
5027 if(write_post)
5028 write_pinerc(ps, Post, WRP_NONE);
5030 return;
5035 * Adjust side effects that happen because variable changes values.
5037 * Var->user_val should be set to the new value before calling this.
5039 void
5040 fix_side_effects(struct pine *ps, struct variable *var, int revert)
5042 int val = 0;
5043 char **v, *q, **apval;
5044 struct variable *vars = ps->vars;
5046 /* move this up here so we get the Using default message */
5047 if(var == &ps->vars[V_PERSONAL_NAME]){
5048 if(!(var->main_user_val.p ||
5049 var->post_user_val.p) && ps->ui.fullname){
5050 if(var->current_val.p)
5051 fs_give((void **)&var->current_val.p);
5053 var->current_val.p = cpystr(ps->ui.fullname);
5057 if(!revert
5058 && ((!var->is_fixed
5059 && !var->is_list
5060 && !(var->main_user_val.p ||
5061 var->post_user_val.p)
5062 && var->current_val.p)
5064 (!var->is_fixed
5065 && var->is_list
5066 && !(var->main_user_val.l ||
5067 var->post_user_val.l)
5068 && var->current_val.l)))
5069 q_status_message(SM_ORDER,0,3,_("Using default value"));
5071 if(var == &ps->vars[V_USER_DOMAIN]){
5072 char *p, *q;
5074 if(ps->VAR_USER_DOMAIN
5075 && ps->VAR_USER_DOMAIN[0]
5076 && (p = strrindex(ps->VAR_USER_DOMAIN, '@'))){
5077 if(*(++p)){
5078 if(!revert)
5079 q_status_message2(SM_ORDER, 3, 5,
5080 _("User-Domain (%s) cannot contain \"@\"; using %s"),
5081 ps->VAR_USER_DOMAIN, p);
5082 q = ps->VAR_USER_DOMAIN;
5083 while((*q++ = *p++) != '\0')
5084 ;/* do nothing */
5086 else{
5087 if(!revert)
5088 q_status_message1(SM_ORDER, 3, 5,
5089 _("User-domain (%s) cannot contain \"@\"; deleting"),
5090 ps->VAR_USER_DOMAIN);
5092 if(ps->vars[V_USER_DOMAIN].post_user_val.p){
5093 fs_give((void **)&ps->vars[V_USER_DOMAIN].post_user_val.p);
5094 set_current_val(&vars[V_USER_DOMAIN], TRUE, TRUE);
5097 if(ps->VAR_USER_DOMAIN
5098 && ps->VAR_USER_DOMAIN[0]
5099 && (p = strrindex(ps->VAR_USER_DOMAIN, '@'))){
5100 if(ps->vars[V_USER_DOMAIN].main_user_val.p){
5101 fs_give((void **)&ps->vars[V_USER_DOMAIN].main_user_val.p);
5102 set_current_val(&vars[V_USER_DOMAIN], TRUE, TRUE);
5109 * Reset various pointers pertaining to domain name and such...
5111 init_hostname(ps);
5113 else if(var == &ps->vars[V_INBOX_PATH]){
5115 * fixup the inbox path based on global/default values...
5117 init_inbox_mapping(ps->VAR_INBOX_PATH, ps->context_list);
5119 if(!strucmp(ps->cur_folder, ps->inbox_name) && ps->mail_stream
5120 && strcmp(ps->VAR_INBOX_PATH, ps->mail_stream->mailbox)){
5122 * If we currently have "inbox" open and the mailbox name
5123 * doesn't match, reset the current folder's name and
5124 * remove the SP_INBOX flag.
5126 strncpy(ps->cur_folder, ps->mail_stream->mailbox,
5127 sizeof(ps->cur_folder)-1);
5128 ps->cur_folder[sizeof(ps->cur_folder)-1] = '\0';
5129 sp_set_fldr(ps->mail_stream, ps->cur_folder);
5130 sp_unflag(ps->mail_stream, SP_INBOX);
5131 ps->mangled_header = 1;
5133 else if(sp_inbox_stream()
5134 && strcmp(ps->VAR_INBOX_PATH, sp_inbox_stream()->original_mailbox)){
5135 MAILSTREAM *m = sp_inbox_stream();
5138 * if we don't have inbox directly open, but have it
5139 * open for new mail notification, close the stream like
5140 * any other ordinary folder, and clean up...
5142 if(m){
5143 sp_unflag(m, SP_PERMLOCKED | SP_INBOX);
5144 sp_set_fldr(m, m->mailbox);
5145 expunge_and_close(m, NULL, EC_NONE);
5149 else if(var == &ps->vars[V_INCCHECKTIMEO]){
5150 int old_value = ps->inc_check_timeout;
5152 if(SVAR_INC_CHECK_TIMEO(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5153 if(!revert)
5154 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5156 else
5157 ps->inc_check_timeout = old_value;
5159 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5160 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5162 else if(var == &ps->vars[V_INCCHECKINTERVAL]){
5163 int old_value = ps->inc_check_interval;
5165 if(SVAR_INC_CHECK_INTERV(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5166 if(!revert)
5167 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5169 else
5170 ps->inc_check_interval = old_value;
5172 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5173 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5175 else if(var == &ps->vars[V_INC2NDCHECKINTERVAL]){
5176 int old_value = ps->inc_second_check_interval;
5178 if(SVAR_INC_2NDCHECK_INTERV(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5179 if(!revert)
5180 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5182 else
5183 ps->inc_second_check_interval = old_value;
5185 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5186 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5188 else if(var == &ps->vars[V_INCCHECKLIST]){
5189 if(ps->context_list && ps->context_list->use & CNTXT_INCMNG)
5190 reinit_incoming_folder_list(ps, ps->context_list);
5192 if(!revert && (F_OFF(F_ENABLE_INCOMING, ps) || F_OFF(F_ENABLE_INCOMING_CHECKING, ps)))
5193 q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));
5195 else if(var == &ps->vars[V_ADDRESSBOOK] ||
5196 var == &ps->vars[V_GLOB_ADDRBOOK] ||
5197 #ifdef ENABLE_LDAP
5198 var == &ps->vars[V_LDAP_SERVERS] ||
5199 #endif
5200 var == &ps->vars[V_ABOOK_FORMATS]){
5201 addrbook_reset();
5203 else if(var == &ps->vars[V_INDEX_FORMAT]){
5204 reset_index_format();
5205 clear_index_cache(ps->mail_stream, 0);
5207 else if(var == &ps->vars[V_DEFAULT_FCC] ||
5208 var == &ps->vars[V_DEFAULT_SAVE_FOLDER]){
5209 init_save_defaults();
5211 else if(var == &ps->vars[V_KW_BRACES] ||
5212 var == &ps->vars[V_OPENING_SEP] ||
5213 var == &ps->vars[V_ALT_ADDRS]){
5214 clear_index_cache(ps->mail_stream, 0);
5216 else if(var == &ps->vars[V_KEYWORDS]){
5217 if(ps_global->keywords)
5218 free_keyword_list(&ps_global->keywords);
5220 if(var->current_val.l && var->current_val.l[0])
5221 ps_global->keywords = init_keyword_list(var->current_val.l);
5223 clear_index_cache(ps->mail_stream, 0);
5225 else if(var == &ps->vars[V_INIT_CMD_LIST]){
5226 if(!revert)
5227 q_status_message(SM_ASYNC, 0, 3,
5228 _("Initial command changes will affect your next Alpine session."));
5230 else if(var == &ps->vars[V_VIEW_HEADERS]){
5231 ps->view_all_except = 0;
5232 if(ps->VAR_VIEW_HEADERS)
5233 for(v = ps->VAR_VIEW_HEADERS; (q = *v) != NULL; v++)
5234 if(q[0]){
5235 char *p;
5237 removing_leading_white_space(q);
5238 /* look for colon or space or end */
5239 for(p = q; *p && !isspace((unsigned char)*p) && *p != ':'; p++)
5240 ;/* do nothing */
5242 *p = '\0';
5243 if(strucmp(q, ALL_EXCEPT) == 0)
5244 ps->view_all_except = 1;
5247 else if(var == &ps->vars[V_OVERLAP]){
5248 int old_value = ps->viewer_overlap;
5250 if(SVAR_OVERLAP(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5251 if(!revert)
5252 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5254 else
5255 ps->viewer_overlap = old_value;
5257 else if(var == &ps->vars[V_SLEEP]){
5258 int old_value = ps->sleep;
5260 if(SVAR_SLEEP(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5261 if(!revert)
5262 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5264 else
5265 ps->sleep = old_value;
5267 #ifdef SMIME
5268 else if(smime_related_var(ps, var)){
5269 smime_deinit();
5271 #endif /* SMIME */
5272 else if(var == &ps->vars[V_MAXREMSTREAM]){
5273 int old_value = ps->s_pool.max_remstream;
5275 if(SVAR_MAXREMSTREAM(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5276 if(!revert )
5277 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5279 else
5280 ps->s_pool.max_remstream = old_value;
5282 dprint((9, "max_remstream goes to %d\n",
5283 ps->s_pool.max_remstream));
5285 #ifndef _WINDOWS
5286 else if(var == &ps->vars[V_CHAR_SET]){
5287 char *err = NULL;
5289 if(F_ON(F_USE_SYSTEM_TRANS, ps)){
5290 if(!revert)
5291 q_status_message(SM_ORDER, 5, 5, _("This change has no effect because feature Use-System-Translation is on"));
5293 else{
5294 if(reset_character_set_stuff(&err) == -1)
5295 alpine_panic(err ? err : "trouble with Character-Set");
5296 else if(err){
5297 q_status_message(SM_ORDER | SM_DING, 3, 5, err);
5298 fs_give((void **) &err);
5302 else if(var == &ps->vars[V_KEY_CHAR_SET]){
5303 char *err = NULL;
5305 if(F_ON(F_USE_SYSTEM_TRANS, ps)){
5306 if(!revert)
5307 q_status_message(SM_ORDER, 5, 5, _("This change has no effect because feature Use-System-Translation is on"));
5309 else{
5310 if(reset_character_set_stuff(&err) == -1)
5311 alpine_panic(err ? err : "trouble with Character-Set");
5312 else if(err){
5313 q_status_message(SM_ORDER | SM_DING, 3, 5, err);
5314 fs_give((void **) &err);
5318 #endif /* ! _WINDOWS */
5319 else if(var == &ps->vars[V_POST_CHAR_SET]){
5320 update_posting_charset(ps, revert);
5322 else if(var == &ps->vars[V_MARGIN]){
5323 int old_value = ps->scroll_margin;
5325 if(SVAR_MARGIN(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5326 if(!revert)
5327 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5329 else
5330 ps->scroll_margin = old_value;
5332 else if(var == &ps->vars[V_DEADLETS]){
5333 int old_value = ps->deadlets;
5335 if(SVAR_DEADLETS(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5336 if(!revert)
5337 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5339 else
5340 ps->deadlets = old_value;
5342 else if(var == &ps->vars[V_FILLCOL]){
5343 if(SVAR_FILLCOL(ps, ps->composer_fillcol, tmp_20k_buf, SIZEOF_20KBUF)){
5344 if(!revert)
5345 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5348 else if(var == &ps->vars[V_QUOTE_SUPPRESSION]){
5349 val = ps->quote_suppression_threshold;
5350 if(val < Q_SUPP_LIMIT && val > 0)
5351 val = -val;
5353 if(ps->VAR_QUOTE_SUPPRESSION
5354 && SVAR_QUOTE_SUPPRESSION(ps, val, tmp_20k_buf, SIZEOF_20KBUF)){
5355 if(!revert)
5356 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5358 else{
5359 if(val > 0 && val < Q_SUPP_LIMIT){
5360 if(!revert){
5361 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Ignoring Quote-Suppression-Threshold value of %s, see help"), ps->VAR_QUOTE_SUPPRESSION);
5362 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
5363 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5366 else{
5367 if(val < 0 && val != Q_DEL_ALL)
5368 ps->quote_suppression_threshold = -val;
5369 else
5370 ps->quote_suppression_threshold = val;
5374 else if(var == &ps->vars[V_STATUS_MSG_DELAY]){
5375 if(SVAR_MSGDLAY(ps, ps->status_msg_delay, tmp_20k_buf, SIZEOF_20KBUF)){
5376 if(!revert)
5377 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5380 else if(var == &ps->vars[V_ACTIVE_MSG_INTERVAL]){
5381 if(SVAR_ACTIVEINTERVAL(ps, ps->active_status_interval, tmp_20k_buf, SIZEOF_20KBUF)){
5382 if(!revert)
5383 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5385 else{
5386 busy_cue(_("Active Example"), NULL, 0);
5387 sleep(5);
5388 cancel_busy_cue(-1);
5391 #if !defined(DOS) && !defined(OS2) && !defined(LEAVEOUTFIFO)
5392 else if(var == &ps->vars[V_FIFOPATH]){
5393 init_newmailfifo(ps->VAR_FIFOPATH);
5395 #endif
5396 else if(var == &ps->vars[V_NMW_WIDTH]){
5397 int old_value = ps->nmw_width;
5399 if(SVAR_NMW_WIDTH(ps, old_value, tmp_20k_buf, SIZEOF_20KBUF)){
5400 if(!revert )
5401 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5403 else{
5404 #ifdef _WINDOWS
5405 if(old_value != ps->nmw_width)
5406 mswin_setnewmailwidth(old_value); /* actually the new value */
5407 #endif
5408 ps->nmw_width = old_value;
5411 else if(var == &ps->vars[V_TCPOPENTIMEO]){
5412 val = 30;
5413 if(!revert)
5414 if(ps->VAR_TCPOPENTIMEO && SVAR_TCP_OPEN(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5415 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5417 else if(var == &ps->vars[V_TCPREADWARNTIMEO]){
5418 val = 15;
5419 if(!revert)
5420 if(ps->VAR_TCPREADWARNTIMEO && SVAR_TCP_READWARN(ps,val,tmp_20k_buf, SIZEOF_20KBUF))
5421 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5423 else if(var == &ps->vars[V_TCPWRITEWARNTIMEO]){
5424 val = 0;
5425 if(!revert)
5426 if(ps->VAR_TCPWRITEWARNTIMEO && SVAR_TCP_WRITEWARN(ps,val,tmp_20k_buf, SIZEOF_20KBUF))
5427 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5429 else if(var == &ps->vars[V_TCPQUERYTIMEO]){
5430 val = 60;
5431 if(!revert)
5432 if(ps->VAR_TCPQUERYTIMEO && SVAR_TCP_QUERY(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5433 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5435 else if(var == &ps->vars[V_RSHOPENTIMEO]){
5436 val = 15;
5437 if(!revert)
5438 if(ps->VAR_RSHOPENTIMEO && SVAR_RSH_OPEN(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5439 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5441 else if(var == &ps->vars[V_SSHOPENTIMEO]){
5442 val = 15;
5443 if(!revert)
5444 if(ps->VAR_SSHOPENTIMEO && SVAR_SSH_OPEN(ps, val, tmp_20k_buf, SIZEOF_20KBUF))
5445 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5447 else if(var == &ps->vars[V_SIGNATURE_FILE]){
5448 if(ps->VAR_OPER_DIR && ps->VAR_SIGNATURE_FILE &&
5449 is_absolute_path(ps->VAR_SIGNATURE_FILE) &&
5450 !in_dir(ps->VAR_OPER_DIR, ps->VAR_SIGNATURE_FILE)){
5451 char *e;
5452 size_t l;
5454 l = strlen(ps->VAR_OPER_DIR) + 100;
5455 e = (char *) fs_get((l+1) * sizeof(char));
5456 snprintf(e, l+1, _("Warning: Sig file can't be outside of %s"),
5457 ps->VAR_OPER_DIR);
5458 e[l] = '\0';
5459 q_status_message(SM_ORDER, 3, 6, e);
5460 fs_give((void **)&e);
5463 else if(var == &ps->vars[V_OPER_DIR]){
5464 if(ps->VAR_OPER_DIR && !ps->VAR_OPER_DIR[0]){
5465 q_status_message(SM_ORDER, 3, 5, "Operating-dir is turned off.");
5466 fs_give((void **)&ps->vars[V_OPER_DIR].current_val.p);
5467 if(ps->vars[V_OPER_DIR].fixed_val.p)
5468 fs_give((void **)&ps->vars[V_OPER_DIR].fixed_val.p);
5469 if(ps->vars[V_OPER_DIR].global_val.p)
5470 fs_give((void **)&ps->vars[V_OPER_DIR].global_val.p);
5471 if(ps->vars[V_OPER_DIR].cmdline_val.p)
5472 fs_give((void **)&ps->vars[V_OPER_DIR].cmdline_val.p);
5473 if(ps->vars[V_OPER_DIR].post_user_val.p)
5474 fs_give((void **)&ps->vars[V_OPER_DIR].post_user_val.p);
5475 if(ps->vars[V_OPER_DIR].main_user_val.p)
5476 fs_give((void **)&ps->vars[V_OPER_DIR].main_user_val.p);
5479 else if(var == &ps->vars[V_MAILCHECK]){
5480 int timeo = 15;
5481 if(SVAR_MAILCHK(ps, timeo, tmp_20k_buf, SIZEOF_20KBUF)){
5482 set_input_timeout(15);
5483 if(!revert)
5484 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5486 else{
5487 set_input_timeout(timeo);
5488 if(get_input_timeout() == 0 && !revert){
5489 q_status_message(SM_ORDER, 4, 6,
5490 _("Warning: automatic new mail checking and mailbox checkpointing is disabled"));
5491 if(ps->VAR_INBOX_PATH && ps->VAR_INBOX_PATH[0] == '{')
5492 q_status_message(SM_ASYNC, 3, 6,
5493 _("Warning: Mail-Check-Interval=0 may cause IMAP server connection to time out"));
5497 else if(var == &ps->vars[V_MAILCHECKNONCURR]){
5498 val = (int) ps->check_interval_for_noncurr;
5499 if(ps->VAR_MAILCHECKNONCURR
5500 && SVAR_MAILCHKNONCURR(ps, val, tmp_20k_buf, SIZEOF_20KBUF)){
5501 if(!revert)
5502 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5504 else
5505 ps->check_interval_for_noncurr = (time_t) val;
5507 else if(var == &ps->vars[V_MAILDROPCHECK]){
5508 long rvl;
5510 rvl = 60L;
5511 if(ps->VAR_MAILDROPCHECK && SVAR_MAILDCHK(ps, rvl, tmp_20k_buf, SIZEOF_20KBUF))
5512 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5513 else{
5514 if(rvl == 0L)
5515 rvl = (60L * 60L * 24L * 100L); /* 100 days */
5517 if(rvl >= 60L)
5518 mail_parameters(NULL, SET_SNARFINTERVAL, (void *) rvl);
5521 else if(var == &ps->vars[V_NNTPRANGE]){
5522 long rvl;
5524 rvl = 0L;
5525 if(ps->VAR_NNTPRANGE && SVAR_NNTPRANGE(ps, rvl, tmp_20k_buf, SIZEOF_20KBUF))
5526 q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
5527 else{
5528 if(rvl >= 0L)
5529 mail_parameters(NULL, SET_NNTPRANGE, (void *) rvl);
5532 else if(var == &ps->vars[V_CUSTOM_HDRS] || var == &ps->vars[V_COMP_HDRS]){
5533 /* this will give warnings about headers that can't be changed */
5534 if(!revert && var->current_val.l && var->current_val.l[0])
5535 customized_hdr_setup(NULL, var->current_val.l, UseAsDef);
5537 #if defined(DOS) || defined(OS2)
5538 else if(var == &ps->vars[V_FOLDER_EXTENSION]){
5539 mail_parameters(NULL, SET_EXTENSION,
5540 (void *)var->current_val.p);
5542 else if(var == &ps->vars[V_NEWSRC_PATH]){
5543 if(var->current_val.p && var->current_val.p[0])
5544 mail_parameters(NULL, SET_NEWSRC,
5545 (void *)var->current_val.p);
5547 #endif
5548 else if(revert && standard_radio_var(ps, var)){
5550 cur_rule_value(var, TRUE, FALSE);
5551 if(var == &ps_global->vars[V_AB_SORT_RULE])
5552 addrbook_redo_sorts();
5553 else if(var == &ps_global->vars[V_THREAD_INDEX_STYLE]){
5554 clear_index_cache(ps_global->mail_stream, 0);
5555 set_lflags(ps_global->mail_stream, ps_global->msgmap,
5556 MN_COLL | MN_CHID, 0);
5557 if(SORT_IS_THREADED(ps_global->msgmap)
5558 && (SEP_THRDINDX() || COLL_THRDS()))
5559 collapse_threads(ps_global->mail_stream, ps_global->msgmap, NULL);
5561 adjust_cur_to_visible(ps_global->mail_stream, ps_global->msgmap);
5563 #ifndef _WINDOWS
5564 else if(var == &ps->vars[V_COLOR_STYLE]){
5565 pico_toggle_color(0);
5566 switch(ps->color_style){
5567 case COL_NONE:
5568 case COL_TERMDEF:
5569 pico_set_color_options(pico_trans_color() ? COLOR_TRANS_OPT : 0);
5570 break;
5571 case COL_ANSI8:
5572 pico_set_color_options(COLOR_ANSI8_OPT|COLOR_TRANS_OPT);
5573 break;
5574 case COL_ANSI16:
5575 pico_set_color_options(COLOR_ANSI16_OPT|COLOR_TRANS_OPT);
5576 break;
5577 case COL_ANSI256:
5578 pico_set_color_options(COLOR_ANSI256_OPT|COLOR_TRANS_OPT);
5579 break;
5582 if(ps->color_style != COL_NONE)
5583 pico_toggle_color(1);
5585 if(pico_usingcolor())
5586 pico_set_normal_color();
5588 clear_index_cache(ps_global->mail_stream, 0);
5589 ClearScreen();
5590 ps->mangled_screen = 1;
5592 #endif
5594 else if(revert && var == &ps->vars[V_SORT_KEY]){
5595 int def_sort_rev;
5597 decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev);
5598 ps->def_sort_rev = def_sort_rev;
5600 else if(var == &ps->vars[V_THREAD_MORE_CHAR] ||
5601 var == &ps->vars[V_THREAD_EXP_CHAR] ||
5602 var == &ps->vars[V_THREAD_LASTREPLY_CHAR]){
5604 if(var == &ps->vars[V_THREAD_LASTREPLY_CHAR] &&
5605 !(var->current_val.p && var->current_val.p[0])){
5606 if(var->current_val.p)
5607 fs_give((void **) &var->current_val.p);
5609 q_status_message1(SM_ORDER, 3, 5,
5610 _("\"%s\" can't be Empty, using default"), var->name);
5612 apval = APVAL(var, ew);
5613 if(*apval)
5614 fs_give((void **)apval);
5616 set_current_val(var, FALSE, FALSE);
5618 if(!(var->current_val.p && var->current_val.p[0]
5619 && !var->current_val.p[1])){
5620 if(var->current_val.p)
5621 fs_give((void **) &var->current_val.p);
5623 var->current_val.p = cpystr(DF_THREAD_LASTREPLY_CHAR);
5627 if(var == &ps->vars[V_THREAD_MORE_CHAR] ||
5628 var == &ps->vars[V_THREAD_EXP_CHAR] ||
5629 var == &ps->vars[V_THREAD_LASTREPLY_CHAR]){
5630 if(var->current_val.p && var->current_val.p[0] &&
5631 var->current_val.p[1]){
5632 q_status_message1(SM_ORDER, 3, 5,
5633 "Only first character of \"%s\" is used",
5634 var->name);
5635 var->current_val.p[1] = '\0';
5638 if(var->main_user_val.p && var->main_user_val.p[0] &&
5639 var->main_user_val.p[1])
5640 var->main_user_val.p[1] = '\0';
5642 if(var->post_user_val.p && var->post_user_val.p[0] &&
5643 var->post_user_val.p[1])
5644 var->post_user_val.p[1] = '\0';
5647 clear_index_cache(ps_global->mail_stream, 0);
5648 set_need_format_setup(ps_global->mail_stream);
5650 else if(var == &ps->vars[V_NNTP_SERVER]){
5651 free_contexts(&ps_global->context_list);
5652 init_folders(ps_global);
5654 else if(var == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){
5655 init_hostname(ps);
5657 else if(var == &ps->vars[V_PRINTER]){
5658 if(!revert && ps->vars[V_PERSONAL_PRINT_COMMAND].is_fixed){
5659 if(printer_value_check_and_adjust())
5660 q_status_message1(SM_ORDER, 3, 5,
5661 _("Can't set \"%s\" to that value, see Setup/Printer"),
5662 pretty_var_name(var->name));
5665 else if(var == &ps->vars[V_KW_COLORS] ||
5666 var == &ps->vars[V_INDEX_TOKEN_COLORS] ||
5667 var == &ps->vars[V_IND_PLUS_FORE_COLOR] ||
5668 var == &ps->vars[V_IND_IMP_FORE_COLOR] ||
5669 var == &ps->vars[V_IND_DEL_FORE_COLOR] ||
5670 var == &ps->vars[V_IND_ANS_FORE_COLOR] ||
5671 var == &ps->vars[V_IND_NEW_FORE_COLOR] ||
5672 var == &ps->vars[V_IND_UNS_FORE_COLOR] ||
5673 var == &ps->vars[V_IND_HIPRI_FORE_COLOR]||
5674 var == &ps->vars[V_IND_LOPRI_FORE_COLOR]||
5675 var == &ps->vars[V_IND_ARR_FORE_COLOR] ||
5676 var == &ps->vars[V_IND_REC_FORE_COLOR] ||
5677 var == &ps->vars[V_IND_FWD_FORE_COLOR] ||
5678 var == &ps->vars[V_IND_OP_FORE_COLOR] ||
5679 var == &ps->vars[V_IND_FROM_FORE_COLOR] ||
5680 var == &ps->vars[V_IND_SUBJ_FORE_COLOR] ||
5681 var == &ps->vars[V_IND_PLUS_BACK_COLOR] ||
5682 var == &ps->vars[V_IND_IMP_BACK_COLOR] ||
5683 var == &ps->vars[V_IND_DEL_BACK_COLOR] ||
5684 var == &ps->vars[V_IND_ANS_BACK_COLOR] ||
5685 var == &ps->vars[V_IND_NEW_BACK_COLOR] ||
5686 var == &ps->vars[V_IND_UNS_BACK_COLOR] ||
5687 var == &ps->vars[V_IND_ARR_BACK_COLOR] ||
5688 var == &ps->vars[V_IND_REC_BACK_COLOR] ||
5689 var == &ps->vars[V_IND_FWD_BACK_COLOR] ||
5690 var == &ps->vars[V_IND_OP_BACK_COLOR] ||
5691 var == &ps->vars[V_IND_FROM_BACK_COLOR] ||
5692 var == &ps->vars[V_IND_SUBJ_BACK_COLOR]){
5693 clear_index_cache(ps_global->mail_stream, 0);
5695 else if(var == score_act_global_ptr){
5696 int score;
5698 score = atoi(var->current_val.p);
5699 if(score < SCORE_MIN || score > SCORE_MAX){
5700 q_status_message2(SM_ORDER, 3, 5,
5701 _("Score Value must be in range %s to %s"),
5702 comatose(SCORE_MIN), comatose(SCORE_MAX));
5703 apval = APVAL(var, ew);
5704 if(*apval)
5705 fs_give((void **)apval);
5707 set_current_val(var, FALSE, FALSE);
5710 else if(var == scorei_pat_global_ptr || var == age_pat_global_ptr
5711 || var == size_pat_global_ptr || var == cati_global_ptr){
5712 apval = APVAL(var, ew);
5713 if(*apval){
5714 INTVL_S *iv;
5715 iv = parse_intvl(*apval);
5716 if(iv){
5717 fs_give((void **) apval);
5718 *apval = stringform_of_intvl(iv);
5719 free_intvl(&iv);
5721 else
5722 fs_give((void **) apval);
5725 set_current_val(var, FALSE, FALSE);
5727 else if(var == &ps->vars[V_FEATURE_LIST]){
5728 process_feature_list(ps, var->current_val.l, 0, 0, 0);
5730 else if(!revert && (var == &ps->vars[V_LAST_TIME_PRUNE_QUESTION] ||
5731 var == &ps->vars[V_REMOTE_ABOOK_HISTORY] ||
5732 var == &ps->vars[V_REMOTE_ABOOK_VALIDITY] ||
5733 var == &ps->vars[V_USERINPUTTIMEO] ||
5734 var == &ps->vars[V_NEWS_ACTIVE_PATH] ||
5735 var == &ps->vars[V_NEWS_SPOOL_DIR] ||
5736 var == &ps->vars[V_INCOMING_FOLDERS] ||
5737 var == &ps->vars[V_FOLDER_SPEC] ||
5738 var == &ps->vars[V_NEWS_SPEC] ||
5739 var == &ps->vars[V_DISABLE_DRIVERS] ||
5740 var == &ps->vars[V_DISABLE_AUTHS] ||
5741 var == &ps->vars[V_RSHPATH] ||
5742 var == &ps->vars[V_RSHCMD] ||
5743 var == &ps->vars[V_SSHCMD] ||
5744 var == &ps->vars[V_SSHPATH])){
5745 q_status_message2(SM_ASYNC, 0, 3,
5746 _("Changes%s%s will affect your next Alpine session."),
5747 var->name ? " to " : "", var->name ? var->name : "");
5750 if(!revert && (var == &ps->vars[V_TCPOPENTIMEO] ||
5751 var == &ps->vars[V_TCPREADWARNTIMEO] ||
5752 var == &ps->vars[V_TCPWRITEWARNTIMEO] ||
5753 var == &ps->vars[V_TCPQUERYTIMEO] ||
5754 var == &ps->vars[V_RSHOPENTIMEO] ||
5755 var == &ps->vars[V_SSHOPENTIMEO]))
5756 q_status_message(SM_ASYNC, 0, 3,
5757 _("Timeout changes will affect your next Alpine session."));
5762 * Compare saved user_val with current user_val to see if it changed.
5763 * If any have changed, change it back and take the appropriate action.
5765 void
5766 revert_to_saved_config(struct pine *ps, SAVED_CONFIG_S *vsave, int allow_hard_to_config_remotely)
5768 struct variable *vreal;
5769 SAVED_CONFIG_S *v;
5770 int i, n;
5771 int changed = 0;
5772 char *pval, **apval, **lval, ***alval;
5774 v = vsave;
5775 for(vreal = ps->vars; vreal->name; vreal++,v++){
5776 if(!save_include(ps, vreal, allow_hard_to_config_remotely))
5777 continue;
5779 changed = 0;
5780 if(vreal->is_list){
5781 lval = LVAL(vreal, ew);
5782 alval = ALVAL(vreal, ew);
5784 if((v->saved_user_val.l && !lval)
5785 || (!v->saved_user_val.l && lval))
5786 changed++;
5787 else if(!v->saved_user_val.l && !lval)
5788 ;/* no change, nothing to do */
5789 else
5790 for(i = 0; v->saved_user_val.l[i] || lval[i]; i++)
5791 if((v->saved_user_val.l[i]
5792 && (!lval[i]
5793 || strcmp(v->saved_user_val.l[i], lval[i])))
5795 (!v->saved_user_val.l[i] && lval[i])){
5796 changed++;
5797 break;
5800 if(changed){
5801 char **list;
5803 if(alval){
5804 if(*alval)
5805 free_list_array(alval);
5807 /* copy back the original one */
5808 if(v->saved_user_val.l){
5809 list = v->saved_user_val.l;
5810 n = 0;
5811 /* count how many */
5812 while(list[n])
5813 n++;
5815 *alval = (char **)fs_get((n+1) * sizeof(char *));
5817 for(i = 0; i < n; i++)
5818 (*alval)[i] = cpystr(v->saved_user_val.l[i]);
5820 (*alval)[n] = NULL;
5825 else{
5826 pval = PVAL(vreal, ew);
5827 apval = APVAL(vreal, ew);
5829 if((v->saved_user_val.p &&
5830 (!pval || strcmp(v->saved_user_val.p, pval))) ||
5831 (!v->saved_user_val.p && pval)){
5832 /* It changed, fix it */
5833 changed++;
5834 if(apval){
5835 /* free the changed value */
5836 if(*apval)
5837 fs_give((void **)apval);
5839 if(v->saved_user_val.p)
5840 *apval = cpystr(v->saved_user_val.p);
5845 if(changed){
5846 if(vreal == &ps->vars[V_FEATURE_LIST])
5847 set_feature_list_current_val(vreal);
5848 else
5849 set_current_val(vreal, TRUE, FALSE);
5851 fix_side_effects(ps, vreal, 1);
5857 SAVED_CONFIG_S *
5858 save_config_vars(struct pine *ps, int allow_hard_to_config_remotely)
5860 struct variable *vreal;
5861 SAVED_CONFIG_S *vsave, *v;
5863 vsave = (SAVED_CONFIG_S *)fs_get((V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
5864 memset((void *)vsave, 0, (V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
5865 v = vsave;
5866 for(vreal = ps->vars; vreal->name; vreal++,v++){
5867 if(!save_include(ps, vreal, allow_hard_to_config_remotely))
5868 continue;
5870 if(vreal->is_list){
5871 int n, i;
5872 char **list;
5874 if(LVAL(vreal, ew)){
5875 /* count how many */
5876 n = 0;
5877 list = LVAL(vreal, ew);
5878 while(list[n])
5879 n++;
5881 v->saved_user_val.l = (char **)fs_get((n+1) * sizeof(char *));
5882 memset((void *)v->saved_user_val.l, 0, (n+1)*sizeof(char *));
5883 for(i = 0; i < n; i++)
5884 v->saved_user_val.l[i] = cpystr(list[i]);
5886 v->saved_user_val.l[n] = NULL;
5889 else{
5890 if(PVAL(vreal, ew))
5891 v->saved_user_val.p = cpystr(PVAL(vreal, ew));
5895 return(vsave);
5899 void
5900 free_saved_config(struct pine *ps, SAVED_CONFIG_S **vsavep, int allow_hard_to_config_remotely)
5902 struct variable *vreal;
5903 SAVED_CONFIG_S *v;
5905 if(vsavep && *vsavep){
5906 for(v = *vsavep, vreal = ps->vars; vreal->name; vreal++,v++){
5907 if(!save_include(ps, vreal, allow_hard_to_config_remotely))
5908 continue;
5910 if(vreal->is_list){ /* free saved_user_val.l */
5911 if(v && v->saved_user_val.l)
5912 free_list_array(&v->saved_user_val.l);
5914 else if(v && v->saved_user_val.p)
5915 fs_give((void **)&v->saved_user_val.p);
5918 fs_give((void **)vsavep);
5924 * Returns positive if any thing was actually deleted.
5927 delete_user_vals(struct variable *v)
5929 int rv = 0;
5931 if(v){
5932 if(v->is_list){
5933 if(v->post_user_val.l){
5934 rv++;
5935 free_list_array(&v->post_user_val.l);
5937 if(v->main_user_val.l){
5938 rv++;
5939 free_list_array(&v->main_user_val.l);
5942 else{
5943 if(v->post_user_val.p){
5944 rv++;
5945 fs_give((void **)&v->post_user_val.p);
5947 if(v->main_user_val.p){
5948 rv++;
5949 fs_give((void **)&v->main_user_val.p);
5954 return(rv);
5959 * ../pith/conf.c required function
5962 unexpected_pinerc_change(void)
5964 Writechar(BELL, 0);
5965 if(want_to("Unexpected pinerc change! Overwrite with current config",
5966 'n', 0, NO_HELP, WT_FLUSH_IN) == 'n'){
5967 return(-1); /* abort pinerc write */
5970 return(0); /* overwrite */
5974 #ifdef _WINDOWS
5976 /*----------------------------------------------------------------------
5977 MSWin scroll callback. Called during scroll message processing.
5981 Args: cmd - what type of scroll operation.
5982 scroll_pos - paramter for operation.
5983 used as position for SCROLL_TO operation.
5985 Returns: TRUE - did the scroll operation.
5986 FALSE - was not able to do the scroll operation.
5987 ----*/
5989 config_scroll_callback (cmd, scroll_pos)
5990 int cmd;
5991 long scroll_pos;
5993 switch (cmd) {
5994 case MSWIN_KEY_SCROLLUPLINE:
5995 config_scroll_down (scroll_pos);
5996 break;
5998 case MSWIN_KEY_SCROLLDOWNLINE:
5999 config_scroll_up (scroll_pos);
6000 break;
6002 case MSWIN_KEY_SCROLLUPPAGE:
6003 config_scroll_down (BODY_LINES(ps_global));
6004 break;
6006 case MSWIN_KEY_SCROLLDOWNPAGE:
6007 config_scroll_up (BODY_LINES(ps_global));
6008 break;
6010 case MSWIN_KEY_SCROLLTO:
6011 config_scroll_to_pos (scroll_pos);
6012 break;
6015 option_screen_redrawer();
6016 fflush(stdout);
6018 return(TRUE);
6021 #endif /* _WINDOWS */