1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: setup.c 918 2008-01-23 19:39:38Z hubert@u.washington.edu $";
3 #endif
4 
5 /*
6  * ========================================================================
7  * Copyright 2006-2008 University of Washington
8  * Copyright 2013-2021 Eduardo Chappa
9  *
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
13  *
14  *     http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * ========================================================================
17  */
18 
19 #include "headers.h"
20 #include "setup.h"
21 #include "keymenu.h"
22 #include "status.h"
23 #include "confscroll.h"
24 #include "colorconf.h"
25 #include "reply.h"
26 #include "radio.h"
27 #include "listsel.h"
28 #include "folder.h"
29 #include "mailcmd.h"
30 #include "../pith/state.h"
31 #include "../pith/conf.h"
32 #include "../pith/util.h"
33 #include "../pith/sort.h"
34 #include "../pith/folder.h"
35 #include "../pith/list.h"
36 #include "../pith/icache.h"
37 
38 
39 /*
40  * Internal prototypes
41  */
42 int      inbox_path_text_tool(struct pine *, int, CONF_S **, unsigned);
43 int      incoming_monitoring_list_tool(struct pine *, int, CONF_S **, unsigned);
44 int      stayopen_list_tool(struct pine *, int, CONF_S **, unsigned);
45 char   **adjust_list_of_monitored_incoming(CONTEXT_S *, EditWhich, int);
46 int      to_charsets_text_tool(struct pine *, int, CONF_S **, unsigned);
47 
48 
49 #define CONFIG_SCREEN_TITLE             _("SETUP CONFIGURATION")
50 #define CONFIG_SCREEN_TITLE_EXC         _("SETUP CONFIGURATION EXCEPTIONS")
51 
52 
53 
54 /*----------------------------------------------------------------------
55     Present pinerc data for manipulation
56 
57     Args: None
58 
59   Result: help edit certain pinerc fields.
60   ---*/
61 void
option_screen(struct pine * ps,int edit_exceptions)62 option_screen(struct pine *ps, int edit_exceptions)
63 {
64     char	    tmp[MAXPATH+1], *pval = NULL, **lval = NULL;
65     int		    i, j, ln = 0, readonly_warning = 0, pos;
66     struct	    variable  *vtmp;
67     CONF_S	   *ctmpa = NULL, *ctmpb = NULL, *first_line = NULL;
68     FEATURE_S	   *feature;
69     PINERC_S       *prc = NULL;
70     SAVED_CONFIG_S *vsave;
71     OPT_SCREEN_S    screen;
72     int             expose_hidden_config, add_hidden_vars_title = 0;
73 
74     dprint((3, "-- option_screen --\n"));
75 
76     expose_hidden_config = F_ON(F_EXPOSE_HIDDEN_CONFIG, ps_global);
77     treat_color_vars_as_text = expose_hidden_config;
78 
79     ew = edit_exceptions ? ps_global->ew_for_except_vars : Main;
80 
81     if(ps->restricted)
82       readonly_warning = 1;
83     else{
84 	switch(ew){
85 	  case Main:
86 	    prc = ps->prc;
87 	    break;
88 	  case Post:
89 	    prc = ps->post_prc;
90 	    break;
91 	  default:
92 	    break;
93 	}
94 
95 	readonly_warning = prc ? prc->readonly : 1;
96 	if(prc && prc->quit_to_edit){
97 	    quit_to_edit_msg(prc);
98 	    treat_color_vars_as_text = 0;
99 	    return;
100 	}
101     }
102 
103     ps->next_screen = SCREEN_FUN_NULL;
104 
105     mailcap_free(); /* free resources we won't be using for a while */
106 
107     if(ps->fix_fixed_warning)
108       offer_to_fix_pinerc(ps);
109 
110     pos = -1;
111     do {	/* Beginning of BIG LOOP */
112        ctmpa = first_line = NULL;
113 
114     /*
115      * First, find longest variable name
116      */
117     for(vtmp = ps->vars; vtmp->name; vtmp++){
118 	if(exclude_config_var(ps, vtmp, expose_hidden_config))
119 	  continue;
120 
121 	if((i = utf8_width(pretty_var_name(vtmp->name))) > ln)
122 	  ln = i;
123     }
124 
125     dprint((9, "initialize config list\n"));
126 
127     /*
128      * Next, allocate and initialize config line list...
129      */
130     for(vtmp = ps->vars; vtmp->name; vtmp++){
131 	/*
132 	 * INCOMING_FOLDERS is currently the first of the normally
133 	 * hidden variables. Should probably invent a more robust way
134 	 * to keep this up to date.
135 	 */
136 	if(expose_hidden_config && vtmp == &ps->vars[V_INCOMING_FOLDERS])
137 	  add_hidden_vars_title = 1;
138 
139 	if(exclude_config_var(ps, vtmp, expose_hidden_config))
140 	  continue;
141 
142 	if(add_hidden_vars_title){
143 
144 	    add_hidden_vars_title = 0;
145 
146 	    new_confline(&ctmpa);		/* Blank line */
147 	    ctmpa->flags	       |= CF_NOSELECT | CF_B_LINE;
148 
149 	    new_confline(&ctmpa)->var	= NULL;
150 	    ctmpa->help			= NO_HELP;
151 	    ctmpa->valoffset		= 2;
152 	    ctmpa->flags	       |= CF_NOSELECT;
153 	    ctmpa->value = cpystr("--- [ Normally hidden configuration options ] ---");
154 
155 	    new_confline(&ctmpa);		/* Blank line */
156 	    ctmpa->flags	       |= CF_NOSELECT | CF_B_LINE;
157 	}
158 
159 	if(vtmp->is_list)
160 	  lval  = LVAL(vtmp, ew);
161 	else
162 	  pval  = PVAL(vtmp, ew);
163 
164 	new_confline(&ctmpa)->var = vtmp;
165 	if(!first_line)
166 	  first_line = ctmpa;
167 
168 	ctmpa->valoffset = ln + 3;
169 	if(vtmp->is_list)
170 	  ctmpa->keymenu	 = &config_text_wshuf_keymenu;
171 	else
172 	  ctmpa->keymenu	 = &config_text_keymenu;
173 
174 	ctmpa->help	 = config_help(vtmp - ps->vars, 0);
175 	ctmpa->tool	 = text_tool;
176 
177 	utf8_snprintf(tmp, sizeof(tmp), "%-*.100w =", ln, pretty_var_name(vtmp->name));
178 	tmp[sizeof(tmp)-1] = '\0';
179 	ctmpa->varname  = cpystr(tmp);
180 	ctmpa->varnamep = ctmpb = ctmpa;
181 	ctmpa->flags   |= CF_STARTITEM;
182 	if(vtmp == &ps->vars[V_FEATURE_LIST]){	/* special checkbox case */
183 	    char *this_sect, *new_sect;
184 
185 	    ctmpa->flags		 |= CF_NOSELECT;
186 	    ctmpa->keymenu		  = &config_checkbox_keymenu;
187 	    ctmpa->tool			  = NULL;
188 
189 	    /* put a nice delimiter before list */
190 	    new_confline(&ctmpa)->var = NULL;
191 	    ctmpa->varnamep		  = ctmpb;
192 	    ctmpa->keymenu		  = &config_checkbox_keymenu;
193 	    ctmpa->help			  = NO_HELP;
194 	    ctmpa->tool			  = checkbox_tool;
195 	    ctmpa->valoffset		  = feature_indent();
196 	    ctmpa->flags		 |= CF_NOSELECT;
197 	    ctmpa->value = cpystr("Set    Feature Name");
198 
199 	    new_confline(&ctmpa)->var = NULL;
200 	    ctmpa->varnamep		  = ctmpb;
201 	    ctmpa->keymenu		  = &config_checkbox_keymenu;
202 	    ctmpa->help			  = NO_HELP;
203 	    ctmpa->tool			  = checkbox_tool;
204 	    ctmpa->valoffset		  = feature_indent();
205 	    ctmpa->flags		 |= CF_NOSELECT;
206 	    ctmpa->value = cpystr("---  ----------------------");
207 
208 	    for(i = 0, this_sect = NULL; (feature = feature_list(i)); i++)
209 	      if((new_sect = feature_list_section(feature)) &&
210 		 (strcmp(new_sect, HIDDEN_PREF) != 0)){
211 		  if(this_sect != new_sect){
212 		      new_confline(&ctmpa)->var = NULL;
213 		      ctmpa->varnamep		= ctmpb;
214 		      ctmpa->keymenu		= &config_checkbox_keymenu;
215 		      ctmpa->help		= NO_HELP;
216 		      ctmpa->tool		= checkbox_tool;
217 		      ctmpa->valoffset		= 2;
218 		      ctmpa->flags	       |= (CF_NOSELECT | CF_STARTITEM);
219 		      snprintf(tmp, sizeof(tmp), "[ %s ]", this_sect = new_sect);
220 		      tmp[sizeof(tmp)-1] = '\0';
221 		      ctmpa->value = cpystr(tmp);
222 		  }
223 
224 		  new_confline(&ctmpa)->var = vtmp;
225 		  ctmpa->varnamep	    = ctmpb;
226 		  ctmpa->keymenu	    = &config_checkbox_keymenu;
227 		  ctmpa->help		    = config_help(vtmp-ps->vars,
228 							  feature->id);
229 		  ctmpa->tool		    = checkbox_tool;
230 		  ctmpa->valoffset	    = feature_indent();
231 		  ctmpa->varmem		    = i;
232 		  ctmpa->value		    = pretty_value(ps, ctmpa);
233 	      }
234 	}
235 	else if(standard_radio_var(ps, vtmp)){
236 	    standard_radio_setup(ps, &ctmpa, vtmp, NULL);
237 	}
238 	else if(vtmp == &ps->vars[V_SORT_KEY]){ /* radio case */
239 	    SortOrder def_sort;
240 	    int       def_sort_rev;
241 
242 	    ctmpa->flags       |= CF_NOSELECT;
243 	    ctmpa->keymenu      = &config_radiobutton_keymenu;
244 	    ctmpa->tool		= NULL;
245 
246 	    /* put a nice delimiter before list */
247 	    new_confline(&ctmpa)->var = NULL;
248 	    ctmpa->varnamep		  = ctmpb;
249 	    ctmpa->keymenu		  = &config_radiobutton_keymenu;
250 	    ctmpa->help			  = NO_HELP;
251 	    ctmpa->tool			  = radiobutton_tool;
252 	    ctmpa->valoffset		  = 12;
253 	    ctmpa->flags		 |= CF_NOSELECT;
254 	    ctmpa->value = cpystr("Set    Sort Options");
255 
256 	    new_confline(&ctmpa)->var = NULL;
257 	    ctmpa->varnamep	      = ctmpb;
258 	    ctmpa->keymenu	      = &config_radiobutton_keymenu;
259 	    ctmpa->help		      = NO_HELP;
260 	    ctmpa->tool		      = radiobutton_tool;
261 	    ctmpa->valoffset	      = 12;
262 	    ctmpa->flags             |= CF_NOSELECT;
263 	    ctmpa->value = cpystr("---  ----------------------");
264 
265 	    decode_sort(pval, &def_sort, &def_sort_rev);
266 
267 	    for(j = 0; j < 2; j++){
268 		for(i = 0; ps->sort_types[i] != EndofList; i++){
269 		    new_confline(&ctmpa)->var = vtmp;
270 		    ctmpa->varnamep	      = ctmpb;
271 		    ctmpa->keymenu	      = &config_radiobutton_keymenu;
272 		    ctmpa->help		      = config_help(vtmp - ps->vars, 0);
273 		    ctmpa->tool		      = radiobutton_tool;
274 		    ctmpa->valoffset	      = 12;
275 		    ctmpa->varmem	      = i + (j * EndofList);
276 		    ctmpa->value	      = pretty_value(ps, ctmpa);
277 		}
278 	    }
279 	}
280 	else if(vtmp == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){ /* yesno case */
281 	    ctmpa->keymenu = &config_yesno_keymenu;
282 	    ctmpa->tool	   = yesno_tool;
283 	    ctmpa->value   = pretty_value(ps, ctmpa);
284 	}
285 	else if(vtmp == &ps->vars[V_LITERAL_SIG]){
286 	    ctmpa->tool    = litsig_text_tool;
287 	    ctmpa->value   = pretty_value(ps, ctmpa);
288 	}
289 	else if(vtmp == &ps->vars[V_INBOX_PATH]){
290 	    ctmpa->tool    = inbox_path_text_tool;
291 	    ctmpa->value   = pretty_value(ps, ctmpa);
292 	}
293 	else if(vtmp == &ps->vars[V_POST_CHAR_SET]
294 #ifndef _WINDOWS
295 		|| vtmp == &ps->vars[V_CHAR_SET]
296 	        || vtmp == &ps->vars[V_KEY_CHAR_SET]
297 #endif /* !_WINDOWS */
298 		|| vtmp == &ps->vars[V_UNK_CHAR_SET]){
299 	    ctmpa->keymenu = &config_text_to_charsets_keymenu;
300 	    ctmpa->tool    = to_charsets_text_tool;
301 	    ctmpa->value   = pretty_value(ps, ctmpa);
302 	}
303 	else if(vtmp->is_list){
304 	    int (*t_tool)(struct pine *, int, CONF_S **, unsigned);
305 	    struct key_menu *km;
306 
307 	    t_tool = NULL;
308 	    km = NULL;
309 	    if(vtmp == &ps->vars[V_INCCHECKLIST]){
310 		t_tool = incoming_monitoring_list_tool;
311 		km     = &config_text_keymenu;
312 	    }
313 	    else if(vtmp == &ps->vars[V_PERMLOCKED]){
314 		t_tool = stayopen_list_tool;
315 		km     = &config_text_wshufandfldr_keymenu;
316 	    }
317 
318 	    if(lval){
319 		for(i = 0; lval[i]; i++){
320 		    if(i)
321 		      (void)new_confline(&ctmpa);
322 
323 		    ctmpa->var       = vtmp;
324 		    ctmpa->varmem    = i;
325 		    ctmpa->valoffset = ln + 3;
326 		    ctmpa->value     = pretty_value(ps, ctmpa);
327 		    ctmpa->keymenu   = km ? km : &config_text_wshuf_keymenu;
328 		    ctmpa->help      = config_help(vtmp - ps->vars, 0);
329 		    ctmpa->tool      = t_tool ? t_tool : text_tool;
330 		    ctmpa->varnamep  = ctmpb;
331 		}
332 	    }
333 	    else{
334 		ctmpa->varmem = 0;
335 		ctmpa->value  = pretty_value(ps, ctmpa);
336 		ctmpa->tool   = t_tool ? t_tool : text_tool;
337 		ctmpa->keymenu = km ? km : &config_text_wshuf_keymenu;
338 	    }
339 	}
340 	else{
341 	    if(vtmp == &ps->vars[V_FILLCOL]
342 	       || vtmp == &ps->vars[V_QUOTE_SUPPRESSION]
343 	       || vtmp == &ps->vars[V_OVERLAP]
344 	       || vtmp == &ps->vars[V_MAXREMSTREAM]
345 	       || vtmp == &ps->vars[V_MARGIN]
346 	       || vtmp == &ps->vars[V_DEADLETS]
347 	       || vtmp == &ps->vars[V_NMW_WIDTH]
348 	       || vtmp == &ps->vars[V_STATUS_MSG_DELAY]
349 	       || vtmp == &ps->vars[V_ACTIVE_MSG_INTERVAL]
350 	       || vtmp == &ps->vars[V_MAILCHECK]
351 	       || vtmp == &ps->vars[V_MAILCHECKNONCURR]
352 	       || vtmp == &ps->vars[V_MAILDROPCHECK]
353 	       || vtmp == &ps->vars[V_NNTPRANGE]
354 	       || vtmp == &ps->vars[V_TCPOPENTIMEO]
355 	       || vtmp == &ps->vars[V_TCPREADWARNTIMEO]
356 	       || vtmp == &ps->vars[V_TCPWRITEWARNTIMEO]
357 	       || vtmp == &ps->vars[V_TCPQUERYTIMEO]
358 	       || vtmp == &ps->vars[V_RSHOPENTIMEO]
359 	       || vtmp == &ps->vars[V_SSHOPENTIMEO]
360 	       || vtmp == &ps->vars[V_INCCHECKTIMEO]
361 	       || vtmp == &ps->vars[V_INCCHECKINTERVAL]
362 	       || vtmp == &ps->vars[V_INC2NDCHECKINTERVAL]
363 	       || vtmp == &ps->vars[V_USERINPUTTIMEO]
364 	       || vtmp == &ps->vars[V_REMOTE_ABOOK_VALIDITY]
365 	       || vtmp == &ps->vars[V_REMOTE_ABOOK_HISTORY])
366 	      ctmpa->flags |= CF_NUMBER;
367 
368 	    ctmpa->value = pretty_value(ps, ctmpa);
369 	}
370     }
371 
372     dprint((9, "add hidden features\n"));
373 
374     /* add the hidden features */
375     if(expose_hidden_config){
376 	char *new_sect;
377 
378 	new_confline(&ctmpa);		/* Blank line */
379 	ctmpa->flags	       |= CF_NOSELECT | CF_B_LINE;
380 
381 	new_confline(&ctmpa)->var	= NULL;
382 	ctmpa->help			= NO_HELP;
383 	ctmpa->valoffset		= 2;
384 	ctmpa->flags	       |= CF_NOSELECT;
385 	ctmpa->value = cpystr("--- [ Normally hidden configuration features ] ---");
386 
387 	new_confline(&ctmpa);		/* Blank line */
388 	ctmpa->flags	       |= CF_NOSELECT | CF_B_LINE;
389 
390 	vtmp = &ps->vars[V_FEATURE_LIST];
391 
392 	ctmpa->flags		 |= CF_NOSELECT;
393 	ctmpa->keymenu		  = &config_checkbox_keymenu;
394 	ctmpa->tool			  = NULL;
395 
396 	/* put a nice delimiter before list */
397 	new_confline(&ctmpa)->var = NULL;
398 	ctmpa->varnamep		  = ctmpb;
399 	ctmpa->keymenu		  = &config_checkbox_keymenu;
400 	ctmpa->help			  = NO_HELP;
401 	ctmpa->tool			  = checkbox_tool;
402 	ctmpa->valoffset		  = feature_indent();
403 	ctmpa->flags		 |= CF_NOSELECT;
404 	ctmpa->value = cpystr("Set    Feature Name");
405 
406 	new_confline(&ctmpa)->var = NULL;
407 	ctmpa->varnamep		  = ctmpb;
408 	ctmpa->keymenu		  = &config_checkbox_keymenu;
409 	ctmpa->help			  = NO_HELP;
410 	ctmpa->tool			  = checkbox_tool;
411 	ctmpa->valoffset		  = feature_indent();
412 	ctmpa->flags		 |= CF_NOSELECT;
413 	ctmpa->value = cpystr("---  ----------------------");
414 
415 	for(i = 0; (feature = feature_list(i)); i++)
416 	  if((new_sect = feature_list_section(feature)) &&
417 	     (strcmp(new_sect, HIDDEN_PREF) == 0)){
418 
419 	      new_confline(&ctmpa)->var	= vtmp;
420 	      ctmpa->varnamep		= ctmpb;
421 	      ctmpa->keymenu		= &config_checkbox_keymenu;
422 	      ctmpa->help		= config_help(vtmp-ps->vars,
423 						      feature->id);
424 	      ctmpa->tool		= checkbox_tool;
425 	      ctmpa->valoffset		= feature_indent();
426 	      ctmpa->varmem		= i;
427 	      ctmpa->value		= pretty_value(ps, ctmpa);
428 	  }
429     }
430 
431     vsave = save_config_vars(ps, expose_hidden_config);
432     first_line = pos < 0 ? first_sel_confline(first_line) : set_confline_number(first_line, pos);
433     pos = -1;
434     memset(&screen, 0, sizeof(screen));
435     screen.ro_warning = readonly_warning;
436     /* TRANSLATORS: Print something1 using something2.
437        "configuration" is something1 */
438        switch(conf_scroll_screen(ps, &screen, first_line,
439 			      edit_exceptions ? CONFIG_SCREEN_TITLE_EXC
440 					      : CONFIG_SCREEN_TITLE,
441 			      _("configuration"), 0, &pos)){
442          case 0:
443 	   break;
444 
445          case 1:
446 	   write_pinerc(ps, ew, WRP_NONE);
447 	   break;
448 
449          case 10:
450 	   revert_to_saved_config(ps, vsave, expose_hidden_config);
451 	   if(prc)
452 	     prc->outstanding_pinerc_changes = 0;
453 
454 	   break;
455 
456          default:
457 	   q_status_message(SM_ORDER,7,10,
458 	    "conf_scroll_screen bad ret, not supposed to happen");
459 	   break;
460        }
461     } while (pos >= 0);
462 
463     pval = PVAL(&ps->vars[V_SORT_KEY], ew);
464     if(vsave[V_SORT_KEY].saved_user_val.p && pval
465        && strcmp(vsave[V_SORT_KEY].saved_user_val.p, pval)){
466 	if(!mn_get_mansort(ps_global->msgmap)){
467 	    clear_index_cache(ps_global->mail_stream, 0);
468 	    reset_sort_order(SRT_VRB);
469 	}
470     }
471 
472     treat_color_vars_as_text = 0;
473     free_saved_config(ps, &vsave, expose_hidden_config);
474 #ifdef _WINDOWS
475     mswin_set_quit_confirm (F_OFF(F_QUIT_WO_CONFIRM, ps_global));
476 #endif
477 }
478 
479 
480 int
litsig_text_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)481 litsig_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
482 {
483     char           **apval;
484     int		     rv = 0;
485 
486     if(cmd != MC_EXIT && fixed_var((*cl)->var, NULL, NULL))
487       return(rv);
488 
489     apval = APVAL((*cl)->var, ew);
490 
491     switch(cmd){
492       case MC_ADD:
493       case MC_EDIT :
494 	if(apval){
495 	    char *input = NULL, *result = NULL, *err = NULL, *cstring_version;
496 	    char *olddefval = NULL, *start_with;
497 	    size_t len;
498 
499 	    if(!*apval && (*cl)->var->current_val.p &&
500 	       (*cl)->var->current_val.p[0]){
501 		if(!strncmp((*cl)->var->current_val.p,
502 			    DSTRING,
503 			    (len=strlen(DSTRING)))){
504 		    /* strip DSTRING and trailing paren */
505 		    olddefval = (char *)fs_get(strlen((*cl)->var->current_val.p)+1);
506 		    strncpy(olddefval, (*cl)->var->current_val.p+len,
507 			    strlen((*cl)->var->current_val.p)-len-1);
508 		    olddefval[strlen((*cl)->var->current_val.p)-len-1] = '\0';
509 		    start_with = olddefval;
510 		}
511 		else{
512 		    olddefval = cpystr((*cl)->var->current_val.p);
513 		    start_with = olddefval;
514 		}
515 	    }
516 	    else
517 	      start_with = (*apval) ? *apval : "";
518 
519 	    input = (char *)fs_get((strlen(start_with)+1) * sizeof(char));
520 	    input[0] = '\0';
521 	    cstring_to_string(start_with, input);
522 	    err = signature_edit_lit(input, &result,
523 				     ((*cl)->var == role_comment_ptr)
524 					 ? "COMMENT EDITOR"
525 					 : "SIGNATURE EDITOR",
526 				     ((*cl)->var == role_comment_ptr)
527 					 ? h_composer_commentedit
528 					 : h_composer_sigedit);
529 
530 	    if(!err){
531 		if(olddefval && !strcmp(input, result) &&
532 		   want_to(_("Leave unset and use default "), 'y',
533 			   'y', NO_HELP, WT_FLUSH_IN) == 'y'){
534 		    rv = 0;
535 		}
536 		else{
537 		    cstring_version = string_to_cstring(result);
538 
539 		    if(apval && *apval)
540 		      fs_give((void **)apval);
541 
542 		    if(apval){
543 			*apval = cstring_version;
544 			cstring_version = NULL;
545 		    }
546 
547 		    if(cstring_version)
548 		      fs_give((void **)&cstring_version);
549 
550 		    rv = 1;
551 		}
552 	    }
553 	    else
554 	      rv = 0;
555 
556 	    if(err){
557 		q_status_message1(SM_ORDER, 3, 5, "%s", err);
558 		fs_give((void **)&err);
559 	    }
560 
561 	    if(result)
562 	      fs_give((void **)&result);
563 	    if(olddefval)
564 	      fs_give((void **)&olddefval);
565 	    if(input)
566 	      fs_give((void **)&input);
567 	}
568 
569 	ps->mangled_screen = 1;
570 	break;
571 
572       default:
573 	rv = text_tool(ps, cmd, cl, flags);
574 	break;
575     }
576 
577     /*
578      * At this point, if changes occurred, var->user_val.X is set.
579      * So, fix the current_val, and handle special cases...
580      *
581      * NOTE: we don't worry about the "fixed variable" case here, because
582      *       editing such vars should have been prevented above...
583      */
584     if(rv == 1){
585 	/*
586 	 * Now go and set the current_val based on user_val changes
587 	 * above.  Turn off command line settings...
588 	 */
589 	set_current_val((*cl)->var, TRUE, FALSE);
590 
591 	if((*cl)->value)
592 	  fs_give((void **)&(*cl)->value);
593 
594 	(*cl)->value = pretty_value(ps, *cl);
595 
596 	exception_override_warning((*cl)->var);
597 
598 	/*
599 	 * The value of literal sig can affect whether signature file is
600 	 * used or not. So it affects what we display for sig file variable.
601 	 */
602 	if((*cl)->next && (*cl)->next->var == &ps->vars[V_SIGNATURE_FILE]){
603 	    if((*cl)->next->value)
604 	      fs_give((void **)&(*cl)->next->value);
605 
606 	    (*cl)->next->value = pretty_value(ps, (*cl)->next);
607 	}
608     }
609 
610     return(rv);
611 }
612 
613 
614 int
inbox_path_text_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)615 inbox_path_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
616 {
617     char           **apval;
618     int		     rv = 0;
619     char             new_inbox_path[2*MAXFOLDER+1];
620     char            *def = NULL;
621     CONTEXT_S       *cntxt;
622 
623     if(cmd != MC_EXIT && fixed_var((*cl)->var, NULL, NULL))
624       return(rv);
625 
626     apval = APVAL((*cl)->var, ew);
627 
628     switch(cmd){
629       case MC_ADD:
630       case MC_EDIT:
631 	cntxt = ps->context_list;
632 	if(cmd == MC_EDIT && (*cl)->var){
633 	    if(ew == Post && (*cl)->var->post_user_val.p)
634 	      def = (*cl)->var->post_user_val.p;
635 	    else if(ew == Main && (*cl)->var->main_user_val.p)
636 	      def = (*cl)->var->main_user_val.p;
637 	    else if((*cl)->var->current_val.p)
638 	      def = (*cl)->var->current_val.p;
639 	}
640 
641 	rv = add_new_folder(cntxt, ew, V_INBOX_PATH, new_inbox_path,
642 			    sizeof(new_inbox_path), NULL, def);
643 	rv = rv ? 1 : 0;
644 
645 	ps->mangled_screen = 1;
646         break;
647 
648       default:
649 	rv = text_tool(ps, cmd, cl, flags);
650 	break;
651     }
652 
653     /*
654      * This is just like the end of text_tool.
655      */
656     if(rv == 1){
657 	/*
658 	 * Now go and set the current_val based on user_val changes
659 	 * above.  Turn off command line settings...
660 	 */
661 	set_current_val((*cl)->var, TRUE, FALSE);
662 	fix_side_effects(ps, (*cl)->var, 0);
663 
664 	if((*cl)->value)
665 	  fs_give((void **) &(*cl)->value);
666 
667 	(*cl)->value = pretty_value(ps, *cl);
668 
669 	exception_override_warning((*cl)->var);
670     }
671 
672     return(rv);
673 }
674 
675 
676 int
incoming_monitoring_list_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)677 incoming_monitoring_list_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
678 {
679     int	        rv = 0;
680     CONTEXT_S  *cntxt;
681     char      **the_list;
682     CONF_S     *ctmp;
683     char     ***alval;
684     OPT_SCREEN_S *saved_screen;
685 
686     if(cmd != MC_EXIT && fixed_var((*cl)->var, NULL, NULL))
687       return(rv);
688 
689     switch(cmd){
690       case MC_ADD:
691       case MC_EDIT:
692 	cntxt = ps->context_list;
693 	if(!(cntxt && cntxt->use & CNTXT_INCMNG)){
694 	    q_status_message1(SM_ORDER, 3, 3, _("Turn on incoming folders with Config feature \"%s\""), pretty_feature_name(feature_list_name(F_ENABLE_INCOMING), -1));
695 	    return(rv);
696 	}
697 
698 	saved_screen = opt_screen;
699 
700 	the_list = adjust_list_of_monitored_incoming(cntxt, ew, V_INCCHECKLIST);
701 
702 	/* adjust top if it might be necessary */
703 	for(ctmp = (*cl)->varnamep;
704 	    ctmp && ctmp->varnamep == (*cl)->varnamep;
705 	    ctmp = next_confline(ctmp))
706 	  if(ctmp == opt_screen->top_line)
707 	    opt_screen->top_line = (*cl)->varnamep;
708 
709 	if(the_list){
710 	    alval = ALVAL((*cl)->var, ew);
711 	    free_list_array(alval);
712 	    if(!*the_list){
713 		q_status_message(SM_ORDER, 0, 3, _("Using default, monitor all incoming folders"));
714 		if(alval){
715 		    /*
716 		     * Remove config lines except for first one.
717 		     */
718 		    *cl = (*cl)->varnamep;
719 		    while((*cl)->next && (*cl)->next->varnamep == (*cl)->varnamep)
720 		      snip_confline(&(*cl)->next);
721 		}
722 	    }
723 	    else
724 	      config_add_list(ps, cl, the_list, NULL, 0);
725 
726 	    /* only have to free the top-level pointer */
727 	    fs_give((void **) &the_list);
728 	    rv = 1;
729 	}
730 	else{
731 	    if(LVAL((*cl)->var, ew))
732 	      q_status_message(SM_ORDER, 0, 3, _("List is unchanged"));
733 	    else
734 	      q_status_message(SM_ORDER, 0, 3, _("Using default, monitor all incoming folders"));
735 	}
736 
737 	opt_screen = saved_screen;
738 	ps->mangled_screen = 1;
739         break;
740 
741       default:
742 	rv = text_tool(ps, cmd, cl, flags);
743 	/* if we deleted last one, reverts to default */
744         if(cmd == MC_DELETE && rv == 1 && (*cl)->varmem == 0
745 	   && (!(*cl)->next || (*cl)->next->varnamep != (*cl)))
746 	  q_status_message(SM_ORDER, 0, 3, _("Using default, monitor all incoming folders"));
747 
748 	break;
749     }
750 
751     /*
752      * This is just like the end of text_tool.
753      */
754     if(rv == 1){
755 	/*
756 	 * Now go and set the current_val based on user_val changes
757 	 * above.  Turn off command line settings...
758 	 */
759 	set_current_val((*cl)->var, TRUE, FALSE);
760 	fix_side_effects(ps, (*cl)->var, 0);
761 
762 	if((*cl)->value)
763 	  fs_give((void **) &(*cl)->value);
764 
765 	(*cl)->value = pretty_value(ps, *cl);
766 
767 	exception_override_warning((*cl)->var);
768     }
769 
770     return(rv);
771 }
772 
773 
774 char **
adjust_list_of_monitored_incoming(CONTEXT_S * cntxt,EditWhich which,int varnum)775 adjust_list_of_monitored_incoming(CONTEXT_S *cntxt, EditWhich which, int varnum)
776 {
777     LIST_SEL_S *listhead, *p, *ls;
778     int i, cnt, ftotal;
779     long width;
780     FOLDER_S *f;
781     char **the_list = NULL, buf[1000];
782 
783     if(!(cntxt && cntxt->use & CNTXT_INCMNG))
784       return(the_list);
785 
786     p = listhead = NULL;
787 
788     /* this width is determined by select_from_list_screen() */
789     width = ps_global->ttyo->screen_cols - 4;
790 
791     /*
792      * Put together a list of folders to select from.
793      * We could choose to use the list associated with
794      * the config we're editing, and that may be correct.
795      * However, we think most users will expect the list
796      * to be the list that is in use. In any case, these
797      * are almost always the same.
798      */
799 
800     ftotal = folder_total(FOLDERS(cntxt));
801 
802     for(i = 0; i < ftotal; i++){
803 
804 	f = folder_entry(i, FOLDERS(cntxt));
805 
806 	ls = (LIST_SEL_S *) fs_get(sizeof(*ls));
807 	memset(ls, 0, sizeof(*ls));
808 
809 	if(f && f->nickname){
810 	    ls->item = cpystr(f->nickname);
811 	    snprintf(buf, sizeof(buf), "%s  (%s)", f->nickname, f->name ? f->name : "?");
812 	    ls->display_item = cpystr(buf);
813 	}
814 	else
815 	  ls->item = cpystr((f && f->name) ? f->name : "?");
816 
817 	if(f && f->last_unseen_update != LUU_NEVERCHK)
818 	  ls->selected = 1;
819 
820 	if(p){
821 	    p->next = ls;
822 	    p = p->next;
823 	}
824 	else{
825 	    /* add a heading */
826 	    listhead = (LIST_SEL_S *) fs_get(sizeof(*ls));
827 	    memset(listhead, 0, sizeof(*listhead));
828 	    listhead->flags = SFL_NOSELECT;
829 	    listhead->display_item = cpystr(_("Incoming folders to be monitored"));
830 	    listhead->next = (LIST_SEL_S *) fs_get(sizeof(*ls));
831 	    memset(listhead->next, 0, sizeof(*listhead));
832 	    listhead->next->flags = SFL_NOSELECT;
833 	    listhead->next->display_item = cpystr(repeat_char(width, '-'));
834 
835 	    listhead->next->next = ls;
836 	    p = ls;
837 	}
838     }
839 
840     if(!listhead){
841 	q_status_message1(SM_ORDER, 3, 3, _("Turn on incoming folders with Config feature \"%s\""), pretty_feature_name(feature_list_name(F_ENABLE_INCOMING), -1));
842 	return(the_list);
843     }
844 
845     if(!select_from_list_screen(listhead,
846 			SFL_ALLOW_LISTMODE|SFL_STARTIN_LISTMODE|SFL_ONLY_LISTMODE|SFL_CTRLC,
847 			        _("SELECT FOLDERS TO MONITOR"), _("folders"),
848 				h_select_incoming_to_monitor,
849 				_("HELP FOR SELECTING FOLDERS"), NULL)){
850 
851 	for(cnt = 0, p = listhead; p; p = p->next)
852 	  if(p->selected)
853 	    cnt++;
854 
855 	if(cnt >= 0 && cnt <= ftotal){
856 	    the_list = (char **) fs_get((cnt+1) * sizeof(*the_list));
857 	    memset(the_list, 0, (cnt+1) * sizeof(*the_list));
858 	    for(i = 0, p = listhead; p; p = p->next)
859 	      if(p->selected)
860 		the_list[i++] = cpystr(p->item ? p->item : "");
861 	}
862     }
863 
864     free_list_sel(&listhead);
865 
866     return(the_list);
867 }
868 
869 
870 int
stayopen_list_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)871 stayopen_list_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
872 {
873     int	        rv = 0;
874     char      **newval = NULL;
875     char      **ltmp = NULL;
876     char       *folder = NULL;
877     void      (*prev_screen)(struct pine *) = ps->prev_screen,
878 	      (*redraw)(void) = ps->redrawer;
879     OPT_SCREEN_S *saved_screen = NULL;
880 
881     switch(cmd){
882       case MC_CHOICE:
883 	if(fixed_var((*cl)->var, NULL, NULL))
884 	  break;
885 
886 	ps->redrawer = NULL;
887 	ps->next_screen = SCREEN_FUN_NULL;
888 	saved_screen = opt_screen;
889 	folder = folder_for_config(FOR_OPTIONSCREEN);
890 	removing_leading_and_trailing_white_space(folder);
891 	if(folder && *folder){
892 	    ltmp    = (char **) fs_get(2 * sizeof(char *));
893 	    ltmp[0] = cpystr(folder);
894 	    ltmp[1] = NULL;
895 
896 	    config_add_list(ps, cl, ltmp, &newval, 0);
897 
898 	    if(ltmp)
899 	      fs_give((void **) &ltmp);
900 
901 	    rv = 1;
902 
903 	    /* this stuff is from bottom of text_toolit() */
904 
905 	    /*
906 	     * At this point, if changes occurred, var->user_val.X is set.
907 	     * So, fix the current_val, and handle special cases...
908 	     *
909 	     * NOTE: we don't worry about the "fixed variable" case here, because
910 	     *       editing such vars should have been prevented above...
911 	     */
912 
913 	    /*
914 	     * Now go and set the current_val based on user_val changes
915 	     * above.  Turn off command line settings...
916 	     */
917 	    set_current_val((*cl)->var, TRUE, FALSE);
918 	    fix_side_effects(ps, (*cl)->var, 0);
919 
920 	    /*
921 	     * Delay setting the displayed value until "var.current_val" is set
922 	     * in case current val gets changed due to a special case above.
923 	     */
924 	    if(newval){
925 		if(*newval)
926 		  fs_give((void **) newval);
927 
928 		*newval = pretty_value(ps, *cl);
929 	    }
930 
931 	    exception_override_warning((*cl)->var);
932 
933 	    if(folder)
934 	      fs_give((void **) &folder);
935 	}
936 	else{
937 	    ps->next_screen = prev_screen;
938 	    ps->redrawer = redraw;
939 	    rv = 0;
940 	}
941 
942 	opt_screen = saved_screen;
943 	ps->mangled_screen = 1;
944         break;
945 
946       default:
947 	rv = text_tool(ps, cmd, cl, flags);
948 	break;
949     }
950 
951     return(rv);
952 }
953 
954 
955 int
to_charsets_text_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned int flags)956 to_charsets_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
957 {
958     int	        rv = 0;
959     char      **newval = NULL;
960     void      (*prev_screen)(struct pine *) = ps->prev_screen,
961 	      (*redraw)(void) = ps->redrawer;
962     OPT_SCREEN_S *saved_screen = NULL;
963     char      **apval;
964     char       *charset = NULL;
965 
966     switch(cmd){
967       case MC_CHOICE:
968 	if(fixed_var((*cl)->var, NULL, NULL))
969 	  break;
970 
971 	apval = APVAL((*cl)->var, ew);
972 
973 	if(apval){
974 	    int cac_flags = CAC_ALL;
975 
976 	    ps->redrawer = NULL;
977 	    ps->next_screen = SCREEN_FUN_NULL;
978 	    saved_screen = opt_screen;
979 
980 	    if((*cl)->var == &ps->vars[V_POST_CHAR_SET])
981 	      cac_flags = CAC_POSTING;
982 #ifndef _WINDOWS
983 	    else if((*cl)->var == &ps->vars[V_CHAR_SET]
984 		    || (*cl)->var == &ps->vars[V_KEY_CHAR_SET])
985 	      cac_flags = CAC_DISPLAY;
986 #endif /* !_WINDOWS */
987 
988 	    charset = choose_a_charset(cac_flags);
989 
990 	    removing_leading_and_trailing_white_space(charset);
991 	    if(charset && *charset){
992 		rv = 1;
993 		if(apval && *apval)
994 		  fs_give((void **) apval);
995 
996 		*apval = charset;
997 		charset = NULL;
998 		newval = &(*cl)->value;
999 
1000 		/* this stuff is from bottom of text_toolit() */
1001 
1002 		/*
1003 		 * At this point, if changes occurred, var->user_val.X is set.
1004 		 * So, fix the current_val, and handle special cases...
1005 		 *
1006 		 * NOTE: we don't worry about the "fixed variable" case here, because
1007 		 *       editing such vars should have been prevented above...
1008 		 */
1009 
1010 		/*
1011 		 * Now go and set the current_val based on user_val changes
1012 		 * above.  Turn off command line settings...
1013 		 */
1014 		set_current_val((*cl)->var, TRUE, FALSE);
1015 		fix_side_effects(ps, (*cl)->var, 0);
1016 		if(newval){
1017 		    if(*newval)
1018 		      fs_give((void **) newval);
1019 
1020 		    *newval = pretty_value(ps, *cl);
1021 		}
1022 
1023 		exception_override_warning((*cl)->var);
1024 	    }
1025 	    else{
1026 		ps->next_screen = prev_screen;
1027 		ps->redrawer = redraw;
1028 		rv = 0;
1029 	    }
1030 
1031 	    if(charset)
1032 	      fs_give((void **) &charset);
1033 
1034 	    opt_screen = saved_screen;
1035 	    ps->mangled_screen = 1;
1036 	}
1037         break;
1038 
1039       default:
1040 	rv = text_tool(ps, cmd, cl, flags);
1041 	break;
1042     }
1043 
1044     return(rv);
1045 }
1046 
1047 
1048 /*
1049  * pretty_var_name - return a pleasantly displayable form
1050  *                   of variable name variable
1051  */
1052 char *
pretty_var_name(char * varname)1053 pretty_var_name(char *varname)
1054 {
1055     struct variable *v;
1056     int		i, upper = 1;
1057     static char vbuf[100];
1058 
1059     vbuf[0] = '\0';
1060     v = var_from_name(varname);
1061 
1062     if(!v)
1063       return(vbuf);
1064 
1065     if(v->dname && v->dname[0])
1066       return(v->dname);
1067 
1068     if(!(v->name && v->name[0]))
1069       return(vbuf);
1070 
1071     /* default: uppercase first letters, dashes to spaces */
1072     for(i = 0; i < sizeof(vbuf)-1 && v->name[i]; i++)
1073       if(upper){
1074 	  vbuf[i] = (islower((unsigned char) v->name[i]))
1075 		     ? toupper((unsigned char) v->name[i])
1076 		    : v->name[i];
1077 	  upper = 0;
1078       }
1079       else if(v->name[i] == '-'){
1080 	  vbuf[i] = SPACE;
1081 	  upper++;
1082       }
1083       else
1084 	vbuf[i] = v->name[i];
1085 
1086     vbuf[i] = '\0';
1087     return(vbuf);
1088 }
1089 
1090 
1091 /*
1092  * pretty_feature_name - return a pleasantly displayable form
1093  *                       of feature name variable
1094  */
1095 char *
pretty_feature_name(char * feat,int width)1096 pretty_feature_name(char *feat, int width)
1097 {
1098     FEATURE_S  *f;
1099     int		i, upper = 1;
1100     static char fbuf[100];
1101 
1102     f = feature_list(feature_list_index(feature_list_id(feat)));
1103     if(f && f->dname && f->dname[0])
1104       return(f->dname);
1105 
1106     /* default: uppercase first letters, dashes become spaces */
1107     for(i = 0; i < sizeof(fbuf)-1 && feat[i]; i++)
1108       if(upper){
1109 	  fbuf[i] = (islower((unsigned char) feat[i]))
1110 		     ? toupper((unsigned char) feat[i])
1111 		    : feat[i];
1112 	  upper = 0;
1113       }
1114       else if(feat[i] == '-'){
1115 	  fbuf[i] = SPACE;
1116 	  upper++;
1117       }
1118       else
1119 	fbuf[i] = feat[i];
1120 
1121     fbuf[i] = '\0';
1122 
1123     /* cut off right hand edge if necessary */
1124     if(width > 0){
1125 	char *p, gbuf[100];
1126 
1127 	p = short_str(fbuf, gbuf, sizeof(gbuf), width, EndDots);
1128 
1129 	if(p != fbuf){
1130 	    strncpy(fbuf, p, sizeof(fbuf)-1);
1131 	    fbuf[sizeof(fbuf)-1] = '\0';
1132 	}
1133     }
1134 
1135     return(fbuf);
1136 }
1137