* clear out some warnings by gcc 9.3.1.
[alpine.git] / alpine / alpine.c
blob5182e869bbbbc61868cf8ab567b779923cb31b49
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: alpine.c 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2013-2020 Eduardo Chappa
8 * Copyright 2006-2008 University of Washington
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"
21 #include "../pith/newmail.h"
22 #include "../pith/init.h"
23 #include "../pith/sort.h"
24 #include "../pith/options.h"
25 #include "../pith/list.h"
26 #include "../pith/conf.h"
27 #include "../pith/body.h"
29 #include "osdep/debuging.h"
30 #include "osdep/termout.gen.h"
31 #include "osdep/chnge_pw.h"
33 #include "alpine.h"
34 #include "mailindx.h"
35 #include "mailcmd.h"
36 #include "addrbook.h"
37 #include "reply.h"
38 #include "arg.h"
39 #include "keymenu.h"
40 #include "status.h"
41 #include "context.h"
42 #include "mailview.h"
43 #include "imap.h"
44 #include "xoauth2conf.h"
45 #include "radio.h"
46 #include "folder.h"
47 #include "send.h"
48 #include "help.h"
49 #include "titlebar.h"
50 #include "takeaddr.h"
51 #include "dispfilt.h"
52 #include "init.h"
53 #include "remote.h"
54 #include "pattern.h"
55 #include "setup.h"
56 #include "newuser.h"
57 #include "adrbkcmd.h"
58 #include "signal.h"
59 #include "kblock.h"
60 #include "ldapconf.h"
61 #include "roleconf.h"
62 #include "colorconf.h"
63 #include "print.h"
64 #include "after.h"
65 #include "smime.h"
66 #include "newmail.h"
67 #include "xoauth2conf.h"
68 #ifndef _WINDOWS
69 #include "../pico/osdep/raw.h" /* for STD*_FD */
70 #endif
73 #define PIPED_FD 5 /* Some innocuous desc */
76 /* look for my_timer_period in pico directory for an explanation */
77 int my_timer_period = ((IDLE_TIMEOUT + 1)*1000);
79 /* byte count used by our gets routine to keep track */
80 static unsigned long gets_bytes;
84 * Internal prototypes
86 void convert_args_to_utf8(struct pine *, ARGDATA_S *);
87 void preopen_stayopen_folders(void);
88 int read_stdin_char(char *);
89 void main_redrawer(void);
90 void show_main_screen(struct pine *, int, OtherMenu, struct key_menu *, int, Pos *);
91 void do_menu(int, Pos *, struct key_menu *);
92 int choose_setup_cmd(int, MSGNO_S *, SCROLL_S *);
93 int setup_menu(struct pine *);
94 void do_setup_task(int);
95 void queue_init_errors(struct pine *);
96 void process_init_cmds(struct pine *, char **);
97 void goodnight_gracey(struct pine *, int);
98 void pine_read_progress(GETS_DATA *, unsigned long);
99 int remote_pinerc_failure(void);
100 void dump_supported_options(void);
101 int prune_folders_ok(void);
102 void free_alpine_module_globals(void);
103 #ifdef WIN32
104 char *pine_user_callback(void);
105 #endif
106 #ifdef _WINDOWS
107 int fkey_mode_callback(int, long);
108 void imap_telemetry_on(void);
109 void imap_telemetry_off(void);
110 char *pcpine_help_main(char *);
111 int pcpine_main_cursor(int, long);
112 #define main app_main
113 #endif
116 typedef struct setup_return_val {
117 int cmd;
118 int exc;
119 }SRV_S;
123 * strlen of longest label from keymenu, of labels corresponding to
124 * commands in the middle of the screen. 9 is length of ListFldrs
126 #define LONGEST_LABEL 9 /* length of longest label from keymenu */
128 #define EDIT_EXCEPTION (0x100)
131 static int in_panic = 0;
134 /*----------------------------------------------------------------------
135 main routine -- entry point
137 Args: argv, argc -- The command line arguments
140 Initialize pine, parse arguments and so on
142 If there is a user address on the command line go into send mode and exit,
143 otherwise loop executing the various screens in Alpine.
145 NOTE: The Windows port def's this to "app_main"
146 ----*/
149 main(int argc, char **argv)
151 ARGDATA_S args;
152 int rv;
153 long rvl;
154 struct pine *pine_state;
155 gf_io_t stdin_getc = NULL;
156 char *args_for_debug = NULL, *init_pinerc_debugging = NULL;
158 /*----------------------------------------------------------------------
159 Set up buffering and some data structures
160 ----------------------------------------------------------------------*/
162 pine_state = new_pine_struct();
163 pine_state->id = fs_get(sizeof(IDLIST));
164 pine_state->id->name = cpystr("name");
165 pine_state->id->value = cpystr(PACKAGE_NAME);
166 pine_state->id->next = fs_get(sizeof(IDLIST));
167 pine_state->id->next->name = cpystr("version");
168 pine_state->id->next->value = cpystr(PACKAGE_VERSION);
169 pine_state->id->next->next = NULL;
170 mail_parameters(NULL, SET_IDPARAMS, (void *) pine_state->id);
171 ps_global = pine_state;
174 * fill in optional pith-offered behavior hooks
176 pith_opt_read_msg_prompt = read_msg_prompt;
177 pith_opt_paint_index_hline = paint_index_hline;
178 pith_opt_rfc2369_editorial = rfc2369_editorial;
179 pith_opt_condense_thread_cue = condensed_thread_cue;
180 pith_opt_truncate_sfstr = truncate_subj_and_from_strings;
181 pith_opt_save_and_restore = save_and_restore;
182 pith_opt_newmail_announce = newmail_status_message;
183 pith_opt_newmail_check_cue = newmail_check_cue;
184 pith_opt_checkpoint_cue = newmail_check_point_cue;
185 pith_opt_icon_text = icon_text;
186 pith_opt_rd_metadata_name = rd_metadata_name;
187 pith_opt_remote_pinerc_failure = remote_pinerc_failure;
188 pith_opt_reopen_folder = ask_mailbox_reopen;
189 pith_opt_expunge_prompt = expunge_prompt;
190 pith_opt_begin_closing = expunge_and_close_begins;
191 pith_opt_replyto_prompt = reply_using_replyto_query;
192 pith_opt_reply_to_all_prompt = reply_to_all_query;
193 pith_opt_save_create_prompt = create_for_save_prompt;
194 pith_opt_daemon_confirm = confirm_daemon_send;
195 pith_opt_save_size_changed_prompt = save_size_changed_prompt;
196 pith_opt_save_index_state = setup_index_state;
197 pith_opt_filter_pattern_cmd = pattern_filter_command;
198 pith_opt_get_signature_file = get_signature_file;
199 pith_opt_pretty_var_name = pretty_var_name;
200 pith_opt_pretty_feature_name = pretty_feature_name;
201 pith_opt_closing_stream = titlebar_stream_closing;
202 pith_opt_current_expunged = mm_expunged_current;
203 #ifdef SMIME
204 pith_opt_smime_get_passphrase = smime_get_passphrase;
205 pith_smime_import_certificate = smime_import_certificate;
206 pith_smime_enter_password = alpine_get_password;
207 pith_smime_confirm_save = alpine_smime_confirm_save;
208 #endif
209 #ifdef ENABLE_LDAP
210 pith_opt_save_ldap_entry = save_ldap_entry;
211 #endif
213 status_message_lock_init();
214 inverse_itokens();
216 #if HAVE_SRANDOM
218 * Seed the random number generator with the date & pid. Random
219 * numbers are used for new mail notification and bug report id's
221 srandom(getpid() + time(0));
222 #endif
224 /* need home directory early */
225 get_user_info(&ps_global->ui);
227 if(!(pine_state->home_dir = our_getenv("HOME")))
228 pine_state->home_dir = cpystr(ps_global->ui.homedir);
230 #ifdef _WINDOWS
232 char *p;
234 /* normalize path delimiters */
235 for(p = pine_state->home_dir; p = strchr(p, '/'); p++)
236 *p='\\';
238 #endif /* _WINDOWS */
240 #ifdef DEBUG
241 { size_t len = 0;
242 int i;
243 char *p;
244 char *no_args = " <no args>";
246 for(i = 0; i < argc; i++)
247 len += (strlen(argv[i] ? argv[i] : "")+3);
249 if(argc == 1)
250 len += strlen(no_args);
252 p = args_for_debug = (char *)fs_get((len+2) * sizeof(char));
253 *p++ = '\n';
254 *p = '\0';
256 for(i = 0; i < argc; i++){
257 snprintf(p, len+2-(p-args_for_debug), "%s\"%s\"", i ? " " : "", argv[i] ? argv[i] : "");
258 args_for_debug[len+2-1] = '\0';
259 p += strlen(p);
262 if(argc == 1){
263 strncat(args_for_debug, no_args, len+2-strlen(args_for_debug)-1);
264 args_for_debug[len+2-1] = '\0';
267 #endif
269 /*----------------------------------------------------------------------
270 Parse arguments and initialize debugging
271 ----------------------------------------------------------------------*/
272 pine_args(pine_state, argc, argv, &args);
274 #ifndef _WINDOWS
275 if(!isatty(0)){
277 * monkey with descriptors so our normal tty i/o routines don't
278 * choke...
280 dup2(STDIN_FD, PIPED_FD); /* redirected stdin to new desc */
281 dup2(STDERR_FD, STDIN_FD); /* rebind stdin to the tty */
282 stdin_getc = read_stdin_char;
283 if(stdin_getc){
284 if(args.action == aaURL){
285 display_args_err(
286 "Cannot read stdin when using -url\nFor mailto URLs, use \'body=\' instead",
287 NULL, 1);
288 args_help();
289 exit(-1);
290 } else if (args.action == aaFolder){
291 display_args_err("Cannot take input from pipe when opening a folder", NULL, 1);
292 args_help();
293 exit(-1);
298 #else /* _WINDOWS */
300 * We now have enough information to do some of the basic registry settings.
302 if(ps_global->update_registry != UREG_NEVER_SET){
303 mswin_reg(MSWR_OP_SET
304 | ((ps_global->update_registry == UREG_ALWAYS_SET)
305 ? MSWR_OP_FORCE : 0),
306 MSWR_PINE_DIR, ps_global->pine_dir, (size_t)NULL);
307 mswin_reg(MSWR_OP_SET
308 | ((ps_global->update_registry == UREG_ALWAYS_SET)
309 ? MSWR_OP_FORCE : 0),
310 MSWR_PINE_EXE, ps_global->pine_name, (size_t)NULL);
313 #endif /* _WINDOWS */
315 if(ps_global->convert_sigs &&
316 (!ps_global->pinerc || !ps_global->pinerc[0])){
317 fprintf(stderr, "Use -p <pinerc> with -convert_sigs\n");
318 exit(-1);
321 /* Windows has its own functions to determine width of a character
322 * in the screen, so this is not necessary to do in Window, and
323 * using pith_ucs4width does not produce the correct result
325 #if !defined(_WINDOWS) && defined(LC_CTYPE)
326 { char *s;
327 if((s = setlocale(LC_CTYPE, "")) != NULL
328 && strlen(s) >= 5
329 && !strucmp(s+strlen(s)-5, "UTF-8"))
330 mail_parameters(NULL, SET_UCS4WIDTH, (void *) pith_ucs4width);
332 #endif /* !_WINDOWS && LC_CTYPE */
333 mail_parameters(NULL, SET_QUOTA, (void *) pine_parse_quota);
334 /* set some default timeouts in case pinerc is remote */
335 mail_parameters(NULL, SET_OPENTIMEOUT, (void *)(long)30);
336 mail_parameters(NULL, SET_READTIMEOUT, (void *)(long)15);
337 mail_parameters(NULL, SET_TIMEOUT, (void *) pine_tcptimeout);
338 /* could be TO_BAIL_THRESHOLD, 15 seems more appropriate for now */
339 pine_state->tcp_query_timeout = 15;
341 mail_parameters(NULL, SET_SENDCOMMAND, (void *) pine_imap_cmd_happened);
342 mail_parameters(NULL, SET_FREESTREAMSPAREP, (void *) sp_free_callback);
343 mail_parameters(NULL, SET_FREEELTSPAREP, (void *) free_pine_elt);
344 mail_parameters(NULL, SET_FREEBODYSPAREP, (void *) free_body_sparep);
345 mail_parameters(NULL, SET_OA2CLIENTGETACCESSCODE, (void *) oauth2_get_access_code);
346 mail_parameters(NULL, SET_OA2CLIENTINFO, (void *) oauth2_get_client_info);
347 mail_parameters(NULL, SET_OA2DEVICEINFO, (void *) oauth2_set_device_info);
349 init_pinerc(pine_state, &init_pinerc_debugging);
351 #ifdef DEBUG
352 /* Since this is specific debugging we don't mind if the
353 ifdef is the type of system.
355 #if defined(HAVE_SMALLOC) || defined(NXT)
356 if(ps_global->debug_malloc)
357 malloc_debug(ps_global->debug_malloc);
358 #endif
359 #ifdef CSRIMALLOC
360 if(ps_global->debug_malloc)
361 mal_debug(ps_global->debug_malloc);
362 #endif
364 if(!ps_global->convert_sigs
365 #ifdef _WINDOWS
366 && !ps_global->install_flag
367 #endif /* _WINDOWS */
369 init_debug();
371 if(args_for_debug){
372 dprint((0, " %s (PID=%ld)\n\n", args_for_debug,
373 (long) getpid()));
374 fs_give((void **)&args_for_debug);
378 char *env_to_free;
379 if((env_to_free = our_getenv("HOME")) != NULL){
380 dprint((2, "Setting home dir from $HOME: \"%s\"\n",
381 env_to_free));
382 fs_give((void **)&env_to_free);
384 else{
385 dprint((2, "Setting home dir: \"%s\"\n",
386 pine_state->home_dir ? pine_state->home_dir : "<?>"));
390 /* Watch out. Sensitive information in debug file. */
391 if(ps_global->debug_imap > 4)
392 mail_parameters(NULL, SET_DEBUGSENSITIVE, (void *) TRUE);
394 #ifndef DEBUGJOURNAL
395 if(ps_global->debug_tcp)
396 #endif
397 mail_parameters(NULL, SET_TCPDEBUG, (void *) TRUE);
399 #ifdef _WINDOWS
400 mswin_setdebug(debug, debugfile);
401 mswin_setdebugoncallback (imap_telemetry_on);
402 mswin_setdebugoffcallback (imap_telemetry_off);
403 mswin_enableimaptelemetry(ps_global->debug_imap != 0);
404 #endif
405 #endif /* DEBUG */
407 #ifdef _WINDOWS
408 mswin_setsortcallback(index_sort_callback);
409 mswin_setflagcallback(flag_callback);
410 mswin_sethdrmodecallback(header_mode_callback);
411 mswin_setselectedcallback(any_selected_callback);
412 mswin_setzoomodecallback(zoom_mode_callback);
413 mswin_setfkeymodecallback(fkey_mode_callback);
414 #endif
416 /*------- Set up c-client drivers -------*/
417 #include "../c-client/linkage.c"
419 /*------- ... then tune the drivers just installed -------*/
420 #ifdef _WINDOWS
421 if(_tgetenv(TEXT("HOME")))
422 mail_parameters(NULL, SET_HOMEDIR, (void *) pine_state->home_dir);
424 mail_parameters(NULL, SET_USERPROMPT, (void *) pine_user_callback);
427 * Sniff the environment for timezone offset. We need to do this
428 * here since Windows needs help figuring out UTC, and will adjust
429 * what time() returns based on TZ. THIS WILL SCREW US because
430 * we use time() differences to manage status messages. So, if
431 * rfc822_date, which calls localtime() and thus needs tzset(),
432 * is called while a status message is displayed, it's possible
433 * for time() to return a time *before* what we remember as the
434 * time we put the status message on the display. Sheesh.
436 tzset();
437 #else /* !_WINDOWS */
439 * We used to let c-client do this for us automatically, but it declines
440 * to do so for root. This forces c-client to establish an environment,
441 * even if the uid is 0.
443 env_init(ps_global->ui.login, ps_global->ui.homedir);
446 * Install callback to let us know the progress of network reads...
448 (void) mail_parameters(NULL, SET_READPROGRESS, (void *)pine_read_progress);
449 #endif /* !_WINDOWS */
452 * Install callback to handle certificate validation failures,
453 * allowing the user to continue if they wish.
455 mail_parameters(NULL, SET_SSLCERTIFICATEQUERY, (void *) pine_sslcertquery);
456 mail_parameters(NULL, SET_SSLFAILURE, (void *) pine_sslfailure);
458 if(init_pinerc_debugging){
459 dprint((2, "%s", init_pinerc_debugging));
460 fs_give((void **)&init_pinerc_debugging);
464 * Initial allocation of array of stream pool pointers.
465 * We do this before init_vars so that we can re-use streams used for
466 * remote config files. These sizes may get changed later.
468 ps_global->s_pool.max_remstream = 2;
469 dprint((9,
470 "Setting initial max_remstream to %d for remote config re-use\n",
471 ps_global->s_pool.max_remstream));
473 init_vars(pine_state, process_init_cmds);
475 #if !defined(_WINDOWS) || defined(WINDOWS_UNIXSSL_CERTS)
476 set_system_certs_path(pine_state);
477 set_system_certs_container(pine_state);
478 set_user_certs_path(pine_state);
479 set_user_certs_container(pine_state);
480 #endif
482 #ifdef SMIME
483 if(F_ON(F_DONT_DO_SMIME, ps_global))
484 smime_deinit();
485 #endif /* SMIME */
487 #ifdef ENABLE_NLS
489 * LC_CTYPE is already set from the set_collation call above.
491 * We can't use gettext calls before we do this stuff so it doesn't
492 * help to translate strings that come before this in the program.
493 * Maybe we could rearrange things to accommodate that.
495 setlocale(LC_MESSAGES, "");
496 bindtextdomain(PACKAGE, LOCALEDIR);
497 bind_textdomain_codeset(PACKAGE, "UTF-8");
498 textdomain(PACKAGE);
499 #endif /* ENABLE_NLS */
501 convert_args_to_utf8(pine_state, &args);
503 if(args.action == aaFolder){
504 pine_state->beginning_of_month = first_run_of_month();
505 pine_state->beginning_of_year = first_run_of_year();
508 /* Set up optional for user-defined display filtering */
509 pine_state->tools.display_filter = dfilter;
510 pine_state->tools.display_filter_trigger = dfilter_trigger;
512 #ifdef _WINDOWS
513 if(ps_global->install_flag){
514 init_install_get_vars();
516 if(ps_global->prc)
517 free_pinerc_s(&ps_global->prc);
519 exit(0);
521 #endif
523 if(ps_global->convert_sigs){
524 if(convert_sigs_to_literal(ps_global, 0) == -1){
525 /* TRANSLATORS: sigs refers to signatures, which the user was trying to convert */
526 fprintf(stderr, _("trouble converting sigs\n"));
527 exit(-1);
530 if(ps_global->prc){
531 if(ps_global->prc->outstanding_pinerc_changes)
532 write_pinerc(ps_global, Main, WRP_NONE);
534 free_pinerc_s(&pine_state->prc);
537 exit(0);
541 * Set up a c-client read timeout and timeout handler. In general,
542 * it shouldn't happen, but a server crash or dead link can cause
543 * pine to appear wedged if we don't set this up...
545 rv = 30;
546 if(pine_state->VAR_TCPOPENTIMEO)
547 (void)SVAR_TCP_OPEN(pine_state, rv, tmp_20k_buf, SIZEOF_20KBUF);
548 mail_parameters(NULL, SET_OPENTIMEOUT, (void *)(long)rv);
550 rv = 15;
551 if(pine_state->VAR_TCPREADWARNTIMEO)
552 (void)SVAR_TCP_READWARN(pine_state, rv, tmp_20k_buf, SIZEOF_20KBUF);
553 mail_parameters(NULL, SET_READTIMEOUT, (void *)(long)rv);
555 rv = 0;
556 if(pine_state->VAR_TCPWRITEWARNTIMEO){
557 if(!SVAR_TCP_WRITEWARN(pine_state, rv, tmp_20k_buf, SIZEOF_20KBUF))
558 if(rv == 0 || rv > 4) /* making sure */
559 mail_parameters(NULL, SET_WRITETIMEOUT, (void *)(long)rv);
562 mail_parameters(NULL, SET_TIMEOUT, (void *) pine_tcptimeout);
564 rv = 15;
565 if(pine_state->VAR_RSHOPENTIMEO){
566 if(!SVAR_RSH_OPEN(pine_state, rv, tmp_20k_buf, SIZEOF_20KBUF))
567 if(rv == 0 || rv > 4) /* making sure */
568 mail_parameters(NULL, SET_RSHTIMEOUT, (void *)(long)rv);
571 rv = 15;
572 if(pine_state->VAR_SSHOPENTIMEO){
573 if(!SVAR_SSH_OPEN(pine_state, rv, tmp_20k_buf, SIZEOF_20KBUF))
574 if(rv == 0 || rv > 4) /* making sure */
575 mail_parameters(NULL, SET_SSHTIMEOUT, (void *)(long)rv);
578 rvl = 60L;
579 if(pine_state->VAR_MAILDROPCHECK){
580 if(!SVAR_MAILDCHK(pine_state, rvl, tmp_20k_buf, SIZEOF_20KBUF)){
581 if(rvl == 0L)
582 rvl = (60L * 60L * 24L * 100L); /* 100 days */
584 if(rvl >= 60L) /* making sure */
585 mail_parameters(NULL, SET_SNARFINTERVAL, (void *) rvl);
590 * Lookups of long login names which don't exist are very slow in aix.
591 * This would normally get set in system-wide config if not needed.
593 if(F_ON(F_DISABLE_SHARED_NAMESPACES, ps_global))
594 mail_parameters(NULL, SET_DISABLEAUTOSHAREDNS, (void *) TRUE);
596 if(F_ON(F_HIDE_NNTP_PATH, ps_global))
597 mail_parameters(NULL, SET_NNTPHIDEPATH, (void *) TRUE);
599 if(F_ON(F_MAILDROPS_PRESERVE_STATE, ps_global))
600 mail_parameters(NULL, SET_SNARFPRESERVE, (void *) TRUE);
602 rvl = 0L;
603 if(pine_state->VAR_NNTPRANGE){
604 if(!SVAR_NNTPRANGE(pine_state, rvl, tmp_20k_buf, SIZEOF_20KBUF))
605 if(rvl > 0L)
606 mail_parameters(NULL, SET_NNTPRANGE, (void *) rvl);
610 * Tell c-client not to be so aggressive about uid mappings
612 mail_parameters(NULL, SET_UIDLOOKAHEAD, (void *) 20);
615 * Setup referral handling
617 mail_parameters(NULL, SET_IMAPREFERRAL, (void *) imap_referral);
618 mail_parameters(NULL, SET_MAILPROXYCOPY, (void *) imap_proxycopy);
621 * Setup multiple newsrc transition
623 mail_parameters(NULL, SET_NEWSRCQUERY, (void *) pine_newsrcquery);
626 * Disable some drivers if requested.
628 if(ps_global->VAR_DISABLE_DRIVERS &&
629 ps_global->VAR_DISABLE_DRIVERS[0] &&
630 ps_global->VAR_DISABLE_DRIVERS[0][0]){
631 char **t;
633 for(t = ps_global->VAR_DISABLE_DRIVERS; t[0] && t[0][0]; t++)
634 if(mail_parameters(NULL, DISABLE_DRIVER, (void *)(*t))){
635 dprint((2, "Disabled mail driver \"%s\"\n", *t));
637 else{
638 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
639 _("Failed to disable mail driver \"%s\": name not found"),
640 *t);
641 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
642 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
647 * Disable some authenticators if requested.
649 if(ps_global->VAR_DISABLE_AUTHS &&
650 ps_global->VAR_DISABLE_AUTHS[0] &&
651 ps_global->VAR_DISABLE_AUTHS[0][0]){
652 char **t;
654 for(t = ps_global->VAR_DISABLE_AUTHS; t[0] && t[0][0]; t++)
655 if(mail_parameters(NULL, DISABLE_AUTHENTICATOR, (void *)(*t))){
656 dprint((2,"Disabled SASL authenticator \"%s\"\n", *t));
658 else{
659 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
660 _("Failed to disable SASL authenticator \"%s\": name not found"),
661 *t);
662 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
663 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
667 if(ps_global->VAR_ENCRYPTION_RANGE
668 && ps_global->VAR_ENCRYPTION_RANGE[0]){
669 char *min_s, *max_s, *s;
670 int min_v, max_v;
672 if((s = strchr(ps_global->VAR_ENCRYPTION_RANGE, ',')) == NULL){
673 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
674 _("Bad encryption range: \"%s\": resetting to default"),
675 ps_global->VAR_ENCRYPTION_RANGE);
676 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
677 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
678 fs_give((void **) &ps_global->VAR_ENCRYPTION_RANGE);
679 ps_global->VAR_ENCRYPTION_RANGE = cpystr(DF_ENCRYPTION_RANGE);
680 s = strchr(ps_global->VAR_ENCRYPTION_RANGE, ','); /* try again */
683 if(s == NULL){
684 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
685 _("Bad default encryption range: \"%s\""),
686 ps_global->VAR_ENCRYPTION_RANGE);
687 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
688 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
690 else {
691 *s = ' ';
692 get_pair(ps_global->VAR_ENCRYPTION_RANGE, &min_s, &max_s, 1, 0);
693 *s = ',';
695 min_v = pith_ssl_encryption_version(min_s);
696 max_v = pith_ssl_encryption_version(max_s);
698 if(min_v < 0 || max_v < 0){
699 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
700 _("Bad encryption range: \"%s\": resetting to default"),
701 ps_global->VAR_ENCRYPTION_RANGE);
702 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
703 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
704 min_v = max_v = 0;
707 if(min_v > max_v){
708 int bubble;
709 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
710 _("Minimum encryption protocol (%s) bigger than maximum value (%s). Reversing..."),
711 min_s, max_s);
712 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
713 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
714 bubble = min_v;
715 min_v = max_v;
716 max_v = bubble;
719 if(max_v > 0 && max_v < (long) pith_ssl_encryption_version("tls1")){
720 strncpy(tmp_20k_buf, _("Security alert: SSL maximum encryption version was set to SSLv3."), SIZEOF_20KBUF);
721 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
722 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
725 mail_parameters(NULL, SET_ENCRYPTION_RANGE_MIN, (void *) &min_v);
726 mail_parameters(NULL, SET_ENCRYPTION_RANGE_MAX, (void *) &max_v);
732 * setup alternative authentication driver preference for IMAP opens
734 if(F_ON(F_PREFER_ALT_AUTH, ps_global))
735 mail_parameters(NULL, SET_IMAPTRYALT, (void *) TRUE);
738 * Install handler to let us know about potential delays
740 (void) mail_parameters(NULL, SET_BLOCKNOTIFY, (void *) pine_block_notify);
742 if(ps_global->dump_supported_options){
743 dump_supported_options();
744 exit(0);
748 * Install extra headers to fetch along with all the other stuff
749 * mail_fetch_structure and mail_fetch_overview requests.
751 calc_extra_hdrs();
752 if(get_extra_hdrs())
753 (void) mail_parameters(NULL, SET_IMAPEXTRAHEADERS,
754 (void *) get_extra_hdrs());
756 if(init_username(pine_state) < 0){
757 fprintf(stderr, _("Who are you? (Unable to look up login name)\n"));
758 exit(-1);
761 if(init_userdir(pine_state) < 0)
762 exit(-1);
764 if(init_hostname(pine_state) < 0)
765 exit(-1);
768 * Verify mail dir if we're not in send only mode...
770 if(args.action == aaFolder && init_mail_dir(pine_state) < 0)
771 exit(-1);
773 init_signals();
775 /*--- input side ---*/
776 if(init_tty_driver(pine_state)){
777 #ifndef _WINDOWS /* always succeeds under _WINDOWS */
778 fprintf(stderr, _("Can't access terminal or input is not a terminal. Redirection of\nstandard input is not allowed. For example \"pine < file\" doesn't work.\n%c"), BELL);
779 exit(-1);
780 #endif /* !_WINDOWS */
784 /*--- output side ---*/
785 rv = config_screen(&(pine_state->ttyo));
786 #ifndef _WINDOWS /* always succeeds under _WINDOWS */
787 if(rv){
788 switch(rv){
789 case -1:
790 printf(_("Terminal type (environment variable TERM) not set.\n"));
791 break;
792 case -2:
793 printf(_("Terminal type \"%s\" is unknown.\n"), getenv("TERM"));
794 break;
795 case -3:
796 printf(_("Can't open terminal capabilities database.\n"));
797 break;
798 case -4:
799 printf(_("Your terminal, of type \"%s\", is lacking functions needed to run alpine.\n"), getenv("TERM"));
800 break;
803 printf("\r");
804 end_tty_driver(pine_state);
805 exit(-1);
807 #endif /* !_WINDOWS */
809 if(F_ON(F_BLANK_KEYMENU,ps_global))
810 FOOTER_ROWS(ps_global) = 1;
812 init_screen();
813 init_keyboard(pine_state->orig_use_fkeys);
814 strncpy(pine_state->inbox_name, INBOX_NAME,
815 sizeof(pine_state->inbox_name)-1);
816 init_folders(pine_state); /* digest folder spec's */
818 pine_state->in_init_seq = 0; /* so output (& ClearScreen) show up */
819 pine_state->dont_use_init_cmds = 1; /* don't use up initial_commands yet */
820 ClearScreen();
822 /* initialize titlebar in case we use it */
823 set_titlebar("", NULL, NULL, NULL, NULL, 0, FolderName, 0, 0, NULL);
826 * Prep storage object driver for PicoText
828 so_register_external_driver(pine_pico_get, pine_pico_give, pine_pico_writec, pine_pico_readc,
829 pine_pico_puts, pine_pico_seek, NULL, NULL);
831 #ifdef DEBUG
832 if(ps_global->debug_imap > 4 || debug > 9){
833 q_status_message(SM_ORDER | SM_DING, 5, 9,
834 _("Warning: sensitive authentication data included in debug file"));
835 flush_status_messages(0);
837 #endif
839 if(args.action == aaPrcCopy || args.action == aaAbookCopy){
840 int exit_val = -1;
841 char *err_msg = NULL;
844 * Don't translate these into UTF-8 because we'll be using them
845 * before we translate next time. User should use ascii.
847 if(args.data.copy.local && args.data.copy.remote){
848 switch(args.action){
849 case aaPrcCopy:
850 exit_val = copy_pinerc(args.data.copy.local,
851 args.data.copy.remote, &err_msg);
852 break;
854 case aaAbookCopy:
855 exit_val = copy_abook(args.data.copy.local,
856 args.data.copy.remote, &err_msg);
857 break;
859 default:
860 break;
863 if(err_msg){
864 q_status_message(SM_ORDER | SM_DING, 3, 4, err_msg);
865 fs_give((void **)&err_msg);
867 goodnight_gracey(pine_state, exit_val);
870 if(args.action == aaFolder
871 && (pine_state->first_time_user || pine_state->show_new_version)){
872 pine_state->mangled_header = 1;
873 show_main_screen(pine_state, 0, FirstMenu, &main_keymenu, 0,
874 (Pos *) NULL);
875 new_user_or_version(pine_state);
876 ClearScreen();
879 /* put back in case we need to suppress output */
880 pine_state->in_init_seq = pine_state->save_in_init_seq;
882 /* queue any init errors so they get displayed in a screen below */
883 queue_init_errors(ps_global);
885 /* "Page" the given file? */
886 if(args.action == aaMore){
887 int dice = 1, redir = 0;
889 if(pine_state->in_init_seq){
890 pine_state->in_init_seq = pine_state->save_in_init_seq = 0;
891 clear_cursor_pos();
892 if(pine_state->free_initial_cmds)
893 fs_give((void **)&(pine_state->free_initial_cmds));
895 pine_state->initial_cmds = NULL;
898 /*======= Requested that we simply page the given file =======*/
899 if(args.data.file){ /* Open the requested file... */
900 SourceType src;
901 STORE_S *store = NULL;
902 char *decode_error = NULL;
903 char filename[MAILTMPLEN];
905 if(args.data.file[0] == '\0'){
906 HelpType help = NO_HELP;
908 pine_state->mangled_footer = 1;
909 filename[0] = '\0';
910 while(1){
911 int flags = OE_APPEND_CURRENT;
913 rv = optionally_enter(filename, -FOOTER_ROWS(pine_state),
914 0, sizeof(filename),
915 /* TRANSLATORS: file is computer data */
916 _("File to open : "),
917 NULL, help, &flags);
918 if(rv == 3){
919 help = (help == NO_HELP) ? h_no_F_arg : NO_HELP;
920 continue;
923 if(rv != 4)
924 break;
927 if(rv == 1){
928 q_status_message(SM_ORDER, 0, 2, _("Cancelled"));
929 goodnight_gracey(pine_state, -1);
932 if(*filename){
933 removing_trailing_white_space(filename);
934 removing_leading_white_space(filename);
935 if(is_absolute_path(filename))
936 fnexpand(filename, sizeof(filename));
938 args.data.file = filename;
941 if(!*filename){
942 /* TRANSLATORS: file is computer data */
943 q_status_message(SM_ORDER, 0, 2 ,_("No file to open"));
944 goodnight_gracey(pine_state, -1);
948 if(stdin_getc){
949 redir++;
950 src = CharStar;
951 if(isatty(0) && (store = so_get(src, NULL, EDIT_ACCESS))){
952 gf_io_t pc;
954 gf_set_so_writec(&pc, store);
955 gf_filter_init();
956 if((decode_error = gf_pipe(stdin_getc, pc)) != NULL){
957 dice = 0;
958 q_status_message1(SM_ORDER, 3, 4,
959 _("Problem reading standard input: %s"),
960 decode_error);
963 gf_clear_so_writec(store);
965 else
966 dice = 0;
968 else{
969 src = FileStar;
970 strncpy(ps_global->cur_folder, args.data.file,
971 sizeof(ps_global->cur_folder)-1);
972 ps_global->cur_folder[sizeof(ps_global->cur_folder)-1] = '\0';
973 if(!(store = so_get(src, args.data.file, READ_ACCESS|READ_FROM_LOCALE)))
974 dice = 0;
977 if(dice){
978 SCROLL_S sargs;
980 memset(&sargs, 0, sizeof(SCROLL_S));
981 sargs.text.text = so_text(store);
982 sargs.text.src = src;
983 /* TRANSLATORS: file is computer file being read by user */
984 sargs.text.desc = _("file");
985 /* TRANSLATORS: this is in the title bar at top of screen */
986 sargs.bar.title = _("FILE VIEW");
987 sargs.bar.style = FileTextPercent;
988 sargs.keys.menu = &simple_file_keymenu;
989 setbitmap(sargs.keys.bitmap);
990 scrolltool(&sargs);
992 printf("\n\n");
993 so_give(&store);
997 if(!dice){
998 q_status_message2(SM_ORDER, 3, 4,
999 _("Can't display \"%s\": %s"),
1000 (redir) ? _("Standard Input")
1001 : args.data.file ? args.data.file : "NULL",
1002 error_description(errno));
1005 goodnight_gracey(pine_state, 0);
1007 else if(args.action == aaMail || (stdin_getc && (args.action != aaURL))){
1008 /*======= address on command line/send one message mode ============*/
1009 char *to = NULL, *error = NULL, *addr = NULL;
1010 int len, good_addr = 1;
1011 int exit_val = 0;
1012 BUILDER_ARG fcc;
1014 if(pine_state->in_init_seq){
1015 pine_state->in_init_seq = pine_state->save_in_init_seq = 0;
1016 clear_cursor_pos();
1017 if(pine_state->free_initial_cmds)
1018 fs_give((void **) &(pine_state->free_initial_cmds));
1020 pine_state->initial_cmds = NULL;
1023 /*----- Format the To: line with commas for the composer ---*/
1024 if(args.data.mail.addrlist){
1025 STRLIST_S *p;
1027 for(p = args.data.mail.addrlist, len = 0; p; p = p->next)
1028 len += strlen(p->name) + 2;
1030 to = (char *) fs_get((len + 5) * sizeof(char));
1031 for(p = args.data.mail.addrlist, *to = '\0'; p; p = p->next){
1032 if(*to){
1033 strncat(to, ", ", len+5-strlen(to)-1);
1034 to[len+5-1] = '\0';
1037 strncat(to, p->name, len+5-strlen(to)-1);
1038 to[len+5-1] = '\0';
1041 memset((void *)&fcc, 0, sizeof(BUILDER_ARG));
1042 dprint((2, "building addr: -->%s<--\n", to ? to : "?"));
1043 good_addr = (build_address(to, &addr, &error, &fcc, NULL) >= 0);
1044 dprint((2, "mailing to: -->%s<--\n", addr ? addr : "?"));
1045 free_strlist(&args.data.mail.addrlist);
1047 else
1048 memset(&fcc, 0, sizeof(fcc));
1050 if(good_addr){
1051 compose_mail(addr, fcc.tptr, NULL,
1052 args.data.mail.attachlist, stdin_getc);
1054 else{
1055 /* TRANSLATORS: refers to bad email address */
1056 q_status_message1(SM_ORDER, 3, 4, _("Bad address: %s"), error);
1057 exit_val = -1;
1060 if(addr)
1061 fs_give((void **) &addr);
1063 if(fcc.tptr)
1064 fs_give((void **) &fcc.tptr);
1066 if(args.data.mail.attachlist)
1067 free_attachment_list(&args.data.mail.attachlist);
1069 if(to)
1070 fs_give((void **) &to);
1072 if(error)
1073 fs_give((void **) &error);
1075 goodnight_gracey(pine_state, exit_val);
1077 else{
1078 char int_mail[MAXPATH+1];
1079 struct key_menu *km = &main_keymenu;
1081 /*========== Normal pine mail reading mode ==========*/
1083 pine_state->mail_stream = NULL;
1084 pine_state->mangled_screen = 1;
1086 if(args.action == aaURL){
1087 url_tool_t f;
1089 if(pine_state->in_init_seq){
1090 pine_state->in_init_seq = pine_state->save_in_init_seq = 0;
1091 clear_cursor_pos();
1092 if(pine_state->free_initial_cmds)
1093 fs_give((void **) &(pine_state->free_initial_cmds));
1094 pine_state->initial_cmds = NULL;
1096 if((f = url_local_handler(args.url)) != NULL){
1097 if(args.data.mail.attachlist){
1098 if(f == url_local_mailto){
1099 if(!(url_local_mailto_and_atts(args.url,
1100 args.data.mail.attachlist)
1101 && pine_state->next_screen))
1102 free_attachment_list(&args.data.mail.attachlist);
1103 goodnight_gracey(pine_state, 0);
1105 else {
1106 q_status_message(SM_ORDER | SM_DING, 3, 4,
1107 _("Only mailto URLs are allowed with file attachments"));
1108 goodnight_gracey(pine_state, -1); /* no return */
1111 else if(!((*f)(args.url) && pine_state->next_screen))
1112 goodnight_gracey(pine_state, 0); /* no return */
1114 else{
1115 q_status_message1(SM_ORDER | SM_DING, 3, 4,
1116 _("Unrecognized URL \"%s\""), args.url);
1117 goodnight_gracey(pine_state, -1); /* no return */
1120 else if(!pine_state->start_in_index){
1121 /* flash message about executing initial commands */
1122 if(pine_state->in_init_seq){
1123 pine_state->in_init_seq = 0;
1124 clear_cursor_pos();
1125 pine_state->mangled_header = 1;
1126 pine_state->mangled_footer = 1;
1127 pine_state->mangled_screen = 0;
1128 /* show that this is Alpine */
1129 show_main_screen(pine_state, 0, FirstMenu, km, 0, (Pos *)NULL);
1130 pine_state->mangled_screen = 1;
1131 pine_state->painted_footer_on_startup = 1;
1132 if(MIN(4, pine_state->ttyo->screen_rows - 4) > 1){
1133 char buf1[6*MAX_SCREEN_COLS+1];
1134 char buf2[6*MAX_SCREEN_COLS+1];
1135 int wid;
1137 /* TRANSLATORS: Initial Keystroke List is the literal name of an option */
1138 strncpy(buf1, _("Executing Initial Keystroke List......"), sizeof(buf1));
1139 buf1[sizeof(buf1)-1] = '\0';
1140 wid = utf8_width(buf1);
1141 if(wid > ps_global->ttyo->screen_cols){
1142 utf8_pad_to_width(buf2, buf1, sizeof(buf2), ps_global->ttyo->screen_cols, 1);
1143 PutLine0(MIN(4, pine_state->ttyo->screen_rows - 4), 0, buf2);
1145 else{
1146 PutLine0(MIN(4, pine_state->ttyo->screen_rows - 4),
1147 MAX(MIN(11, pine_state->ttyo->screen_cols - wid), 0), buf1);
1151 pine_state->in_init_seq = 1;
1153 else{
1154 show_main_screen(pine_state, 0, FirstMenu, km, 0, (Pos *)NULL);
1155 pine_state->painted_body_on_startup = 1;
1156 pine_state->painted_footer_on_startup = 1;
1159 else{
1160 /* cancel any initial commands, overridden by cmd line */
1161 if(pine_state->in_init_seq){
1162 pine_state->in_init_seq = 0;
1163 pine_state->save_in_init_seq = 0;
1164 clear_cursor_pos();
1165 if(pine_state->initial_cmds){
1166 if(pine_state->free_initial_cmds)
1167 fs_give((void **)&(pine_state->free_initial_cmds));
1169 pine_state->initial_cmds = NULL;
1172 F_SET(F_USE_FK,pine_state, pine_state->orig_use_fkeys);
1175 (void) do_index_border(pine_state->context_current,
1176 pine_state->cur_folder,
1177 pine_state->mail_stream,
1178 pine_state->msgmap, MsgIndex, NULL,
1179 INDX_CLEAR|INDX_HEADER|INDX_FOOTER);
1180 pine_state->painted_footer_on_startup = 1;
1181 if(MIN(4, pine_state->ttyo->screen_rows - 4) > 1){
1182 char buf1[6*MAX_SCREEN_COLS+1];
1183 char buf2[6*MAX_SCREEN_COLS+1];
1184 int wid;
1186 strncpy(buf1, _("Please wait, opening mail folder......"), sizeof(buf1));
1187 buf1[sizeof(buf1)-1] = '\0';
1188 wid = utf8_width(buf1);
1189 if(wid > ps_global->ttyo->screen_cols){
1190 utf8_pad_to_width(buf2, buf1, sizeof(buf2), ps_global->ttyo->screen_cols, 1);
1191 PutLine0(MIN(4, pine_state->ttyo->screen_rows - 4), 0, buf2);
1193 else{
1194 PutLine0(MIN(4, pine_state->ttyo->screen_rows - 4),
1195 MAX(MIN(11, pine_state->ttyo->screen_cols - wid), 0), buf1);
1200 fflush(stdout);
1202 #if !defined(_WINDOWS) && !defined(LEAVEOUTFIFO)
1203 if(ps_global->VAR_FIFOPATH && ps_global->VAR_FIFOPATH[0])
1204 init_newmailfifo(ps_global->VAR_FIFOPATH);
1205 #endif
1207 if(pine_state->in_init_seq){
1208 pine_state->in_init_seq = 0;
1209 clear_cursor_pos();
1212 if(args.action == aaFolder && args.data.folder){
1213 CONTEXT_S *cntxt = NULL, *tc = NULL;
1214 char foldername[MAILTMPLEN];
1215 int notrealinbox = 0;
1217 if(args.data.folder[0] == '\0'){
1218 char *fldr;
1219 unsigned save_def_goto_rule;
1221 foldername[0] = '\0';
1222 save_def_goto_rule = pine_state->goto_default_rule;
1223 pine_state->goto_default_rule = GOTO_FIRST_CLCTN;
1224 tc = default_save_context(pine_state->context_list);
1225 fldr = broach_folder(-FOOTER_ROWS(pine_state), 1, &notrealinbox, &tc);
1226 pine_state->goto_default_rule = save_def_goto_rule;
1227 if(fldr){
1228 strncpy(foldername, fldr, sizeof(foldername)-1);
1229 foldername[sizeof(foldername)-1] = '\0';
1232 if(*foldername){
1233 removing_trailing_white_space(foldername);
1234 removing_leading_white_space(foldername);
1235 args.data.folder = cpystr(foldername);
1238 if(!*foldername){
1239 q_status_message(SM_ORDER, 0, 2 ,_("No folder to open"));
1240 goodnight_gracey(pine_state, -1);
1244 if(tc)
1245 cntxt = tc;
1246 else if((rv = pine_state->init_context) < 0)
1248 * As with almost all the folder vars in the pinerc,
1249 * we subvert the collection "breakout" here if the
1250 * folder name given looks like an absolute path on
1251 * this system...
1253 cntxt = (is_absolute_path(args.data.folder))
1254 ? NULL : pine_state->context_current;
1255 else if(rv == 0)
1256 cntxt = NULL;
1257 else
1258 for(cntxt = pine_state->context_list;
1259 rv > 1 && cntxt->next;
1260 rv--, cntxt = cntxt->next)
1263 if(pine_state && pine_state->ttyo){
1264 blank_keymenu(pine_state->ttyo->screen_rows - 2, 0);
1265 pine_state->painted_footer_on_startup = 0;
1266 pine_state->mangled_footer = 1;
1269 if(args.data.folder && *args.data.folder
1270 && !strucmp(args.data.folder, ps_global->inbox_name)
1271 && cntxt != ps_global->context_list)
1272 notrealinbox = 1;
1274 if(do_broach_folder(args.data.folder, cntxt, NULL, notrealinbox ? 0L : DB_INBOXWOCNTXT) <= 0){
1275 q_status_message1(SM_ORDER, 3, 4,
1276 _("Unable to open folder \"%s\""), args.data.folder);
1278 fs_give((void **) &args.data.folder);
1280 goodnight_gracey(pine_state, -1);
1283 else if(args.action == aaFolder){
1284 #ifdef _WINDOWS
1286 * need to ask for the inbox name if no default under DOS
1287 * since there is no "inbox"
1290 if(!pine_state->VAR_INBOX_PATH || !pine_state->VAR_INBOX_PATH[0]
1291 || strucmp(pine_state->VAR_INBOX_PATH, "inbox") == 0){
1292 HelpType help = NO_HELP;
1293 static ESCKEY_S ekey[] = {{ctrl(T), 2, "^T", "To Fldrs"},
1294 {-1, 0, NULL, NULL}};
1296 pine_state->mangled_footer = 1;
1297 int_mail[0] = '\0';
1298 while(1){
1299 int flags = OE_APPEND_CURRENT;
1301 rv = optionally_enter(int_mail, -FOOTER_ROWS(pine_state),
1302 0, sizeof(int_mail),
1303 _("No inbox! Folder to open as inbox : "),
1304 /* ekey */ NULL, help, &flags);
1305 if(rv == 3){
1306 help = (help == NO_HELP) ? h_sticky_inbox : NO_HELP;
1307 continue;
1310 if(rv != 4)
1311 break;
1314 if(rv == 1){
1315 q_status_message(SM_ORDER, 0, 2 ,_("Folder open cancelled"));
1316 rv = 0; /* reset rv */
1318 else if(rv == 2){
1319 show_main_screen(pine_state,0,FirstMenu,km,0,(Pos *)NULL);
1322 if(*int_mail){
1323 removing_trailing_white_space(int_mail);
1324 removing_leading_white_space(int_mail);
1325 if((!pine_state->VAR_INBOX_PATH
1326 || strucmp(pine_state->VAR_INBOX_PATH, "inbox") == 0)
1327 /* TRANSLATORS: Inbox-Path and PINERC are literal, not to be translated */
1328 && want_to(_("Preserve folder as \"Inbox-Path\" in PINERC"),
1329 'y', 'n', NO_HELP, WT_NORM) == 'y'){
1330 set_variable(V_INBOX_PATH, int_mail, 1, 1, Main);
1332 else{
1333 if(pine_state->VAR_INBOX_PATH)
1334 fs_give((void **)&pine_state->VAR_INBOX_PATH);
1336 pine_state->VAR_INBOX_PATH = cpystr(int_mail);
1339 if(pine_state && pine_state->ttyo){
1340 blank_keymenu(pine_state->ttyo->screen_rows - 2, 0);
1341 pine_state->painted_footer_on_startup = 0;
1342 pine_state->mangled_footer = 1;
1345 do_broach_folder(pine_state->inbox_name,
1346 pine_state->context_list, NULL, DB_INBOXWOCNTXT);
1348 else
1349 q_status_message(SM_ORDER, 0, 2 ,_("No folder opened"));
1352 else
1354 #endif /* _WINDOWS */
1355 if(F_ON(F_PREOPEN_STAYOPENS, ps_global))
1356 preopen_stayopen_folders();
1358 if(pine_state && pine_state->ttyo){
1359 blank_keymenu(pine_state->ttyo->screen_rows - 2, 0);
1360 pine_state->painted_footer_on_startup = 0;
1361 pine_state->mangled_footer = 1;
1364 /* open inbox */
1365 do_broach_folder(pine_state->inbox_name,
1366 pine_state->context_list, NULL, DB_INBOXWOCNTXT);
1369 if(pine_state->mangled_footer)
1370 pine_state->painted_footer_on_startup = 0;
1372 if(args.action == aaFolder
1373 && pine_state->mail_stream
1374 && expire_sent_mail())
1375 pine_state->painted_footer_on_startup = 0;
1378 * Initialize the defaults. Initializing here means that
1379 * if they're remote, the user isn't prompted for an imap login
1380 * before the display's drawn, AND there's the chance that
1381 * we can climb onto the already opened folder's stream...
1383 if(ps_global->first_time_user)
1384 init_save_defaults(); /* initialize default save folders */
1386 build_path(int_mail,
1387 ps_global->VAR_OPER_DIR ? ps_global->VAR_OPER_DIR
1388 : pine_state->home_dir,
1389 INTERRUPTED_MAIL, sizeof(int_mail));
1390 if(args.action == aaFolder
1391 && (folder_exists(NULL, int_mail) & FEX_ISFILE))
1392 q_status_message(SM_ORDER | SM_DING, 4, 5,
1393 _("Use Compose command to continue interrupted message."));
1395 if(args.action == aaFolder && args.data.folder)
1396 fs_give((void **) &args.data.folder);
1398 #if defined(USE_QUOTAS)
1400 long q;
1401 int over;
1402 q = disk_quota(pine_state->home_dir, &over);
1403 if(q > 0 && over){
1404 q_status_message2(SM_ASYNC | SM_DING, 4, 5,
1405 _("WARNING! Over your disk quota by %s bytes (%s)"),
1406 comatose(q),byte_string(q));
1409 #endif
1411 pine_state->in_init_seq = pine_state->save_in_init_seq;
1412 pine_state->dont_use_init_cmds = 0;
1413 clear_cursor_pos();
1415 if(pine_state->give_fixed_warning)
1416 q_status_message(SM_ASYNC, 0, 10,
1417 /* TRANSLATORS: config is an abbreviation for configuration */
1418 _("Note: some of your config options conflict with site policy and are ignored"));
1420 if(!prune_folders_ok())
1421 q_status_message(SM_ASYNC, 0, 10,
1422 /* TRANSLATORS: Pruned-Folders is literal */
1423 _("Note: ignoring Pruned-Folders outside of default collection for saves"));
1425 if(get_input_timeout() == 0 &&
1426 ps_global->VAR_INBOX_PATH &&
1427 ps_global->VAR_INBOX_PATH[0] == '{')
1428 q_status_message(SM_ASYNC, 0, 10,
1429 _("Note: Mail-Check-Interval=0 may cause IMAP server connection to time out"));
1431 #ifdef _WINDOWS
1432 mswin_setnewmailwidth(ps_global->nmw_width);
1433 #endif
1436 /*-------------------------------------------------------------------
1437 Loop executing the commands
1439 This is done like this so that one command screen can cause
1440 another one to execute it with out going through the main menu.
1441 ------------------------------------------------------------------*/
1442 if(!pine_state->next_screen)
1443 pine_state->next_screen = pine_state->start_in_index
1444 ? mail_index_screen : main_menu_screen;
1445 while(1){
1446 if(pine_state->next_screen == SCREEN_FUN_NULL)
1447 pine_state->next_screen = main_menu_screen;
1449 (*(pine_state->next_screen))(pine_state);
1453 exit(0);
1458 * The arguments need to be converted to UTF-8 for our internal use.
1459 * Not all arguments are converted because some are used before we
1460 * are able to do the conversion, like the pinerc name.
1462 void
1463 convert_args_to_utf8(struct pine *ps, ARGDATA_S *args)
1465 char *fromcharset = NULL;
1466 char *conv;
1468 if(args){
1469 if(ps->keyboard_charmap && strucmp(ps->keyboard_charmap, "UTF-8")
1470 && strucmp(ps->keyboard_charmap, "US-ASCII"))
1471 fromcharset = ps->keyboard_charmap;
1472 else if(ps->display_charmap && strucmp(ps->display_charmap, "UTF-8")
1473 && strucmp(ps->display_charmap, "US-ASCII"))
1474 fromcharset = ps->display_charmap;
1475 #ifndef _WINDOWS
1476 else if(ps->VAR_OLD_CHAR_SET && strucmp(ps->VAR_OLD_CHAR_SET, "UTF-8")
1477 && strucmp(ps->VAR_OLD_CHAR_SET, "US-ASCII"))
1478 fromcharset = ps->VAR_OLD_CHAR_SET;
1479 #endif /* ! _WINDOWS */
1481 if(args->action == aaURL && args->url){
1482 conv = convert_to_utf8(args->url, fromcharset, 0);
1483 if(conv){
1484 fs_give((void **) &args->url);
1485 args->url = conv;
1489 if(args->action == aaFolder && args->data.folder){
1490 conv = convert_to_utf8(args->data.folder, fromcharset, 0);
1491 if(conv){
1492 fs_give((void **) &args->data.folder);
1493 args->data.folder = conv;
1497 if(args->action == aaMore && args->data.file){
1498 conv = convert_to_utf8(args->data.file, fromcharset, 0);
1499 if(conv){
1500 fs_give((void **) &args->data.file);
1501 args->data.file = conv;
1505 if(args->action == aaURL || args->action == aaMail){
1506 if(args->data.mail.addrlist){
1507 STRLIST_S *p;
1509 for(p = args->data.mail.addrlist; p; p=p->next){
1510 if(p->name){
1511 conv = convert_to_utf8(p->name, fromcharset, 0);
1512 if(conv){
1513 fs_give((void **) &p->name);
1514 p->name = conv;
1520 if(args->data.mail.attachlist){
1521 PATMT *p;
1523 for(p = args->data.mail.attachlist; p; p=p->next){
1524 if(p->filename){
1525 conv = convert_to_utf8(p->filename, fromcharset, 0);
1526 if(conv){
1527 fs_give((void **) &p->filename);
1528 p->filename = conv;
1538 void
1539 preopen_stayopen_folders(void)
1541 char **open_these;
1543 for(open_these = ps_global->VAR_PERMLOCKED;
1544 open_these && *open_these; open_these++)
1545 (void) do_broach_folder(*open_these, ps_global->context_list,
1546 NULL, DB_NOVISIT);
1551 * read_stdin_char - simple function to return a character from
1552 * redirected stdin
1555 read_stdin_char(char *c)
1557 int rv;
1559 /* it'd probably be a good idea to fix this to pre-read blocks */
1560 while(1){
1561 rv = read(PIPED_FD, c, 1);
1562 if(rv < 0){
1563 if(errno == EINTR){
1564 dprint((2, "read_stdin_char: read interrupted, restarting\n"));
1565 continue;
1567 else
1568 dprint((1, "read_stdin_char: read FAILED: %s\n",
1569 error_description(errno)));
1571 break;
1573 return(rv);
1577 /* this default is from the array of structs below */
1578 #define DEFAULT_MENU_ITEM ((unsigned) 3) /* LIST FOLDERS */
1579 #define ABOOK_MENU_ITEM ((unsigned) 4) /* ADDRESS BOOK */
1580 #define MAX_MENU_ITEM ((unsigned) 6)
1582 * Skip this many spaces between rows of main menu screen.
1583 * We have MAX_MENU_ITEM+1 = # of commands in menu
1584 * 1 = copyright line
1585 * MAX_MENU_ITEM = rows between commands
1586 * 1 = extra row above commands
1587 * 1 = row between commands and copyright
1589 * To make it simple, if there is enough room for all of that include all the
1590 * extra space, if not, cut it all out.
1592 #define MNSKIP(X) (((HEADER_ROWS(X)+FOOTER_ROWS(X)+(MAX_MENU_ITEM+1)+1+MAX_MENU_ITEM+1+1) <= (X)->ttyo->screen_rows) ? 1 : 0)
1594 static unsigned menu_index = DEFAULT_MENU_ITEM;
1597 * One of these for each line that gets printed in the middle of the
1598 * screen in the main menu.
1600 static struct menu_key {
1601 char *key_and_name,
1602 *news_addition;
1603 int key_index; /* index into keymenu array for this cmd */
1604 } mkeys[] = {
1606 * TRANSLATORS: These next few are headings on the Main alpine menu.
1607 * It's nice if the dashes can be made to line up vertically.
1609 {N_(" %s HELP - Get help using Alpine"),
1610 NULL, MAIN_HELP_KEY},
1611 {N_(" %s COMPOSE MESSAGE - Compose and send%s a message"),
1612 /* TRANSLATORS: We think of sending an email message or posting a news message.
1613 The message is shown as Compose and send/post a message */
1614 N_("/post"), MAIN_COMPOSE_KEY},
1615 {N_(" %s MESSAGE INDEX - View messages in current folder"),
1616 NULL, MAIN_INDEX_KEY},
1617 {N_(" %s FOLDER LIST - Select a folder%s to view"),
1618 /* TRANSLATORS: When news is supported the message above becomes
1619 Select a folder OR news group to view */
1620 N_(" OR news group"), MAIN_FOLDER_KEY},
1621 {N_(" %s ADDRESS BOOK - Update address book"),
1622 NULL, MAIN_ADDRESS_KEY},
1623 {N_(" %s SETUP - Configure Alpine Options"),
1624 NULL, MAIN_SETUP_KEY},
1625 /* TRANSLATORS: final Main menu line */
1626 {N_(" %s QUIT - Leave the Alpine program"),
1627 NULL, MAIN_QUIT_KEY}
1632 /*----------------------------------------------------------------------
1633 display main menu and execute main menu commands
1635 Args: The usual pine structure
1637 Result: main menu commands are executed
1640 M A I N M E N U S C R E E N
1642 Paint the main menu on the screen, get the commands and either execute
1643 the function or pass back the name of the function to execute for the menu
1644 selection. Only simple functions that always return here can be executed
1645 here.
1647 This functions handling of new mail, redrawing, errors and such can
1648 serve as a template for the other screen that do much the same thing.
1650 There is a loop that fetches and executes commands until a command to leave
1651 this screen is given. Then the name of the next screen to display is
1652 stored in next_screen member of the structure and this function is exited
1653 with a return.
1655 First a check for new mail is performed. This might involve reading the new
1656 mail into the inbox which might then cause the screen to be repainted.
1658 Then the general screen painting is done. This is usually controlled
1659 by a few flags and some other position variables. If they change they
1660 tell this part of the code what to repaint. This will include cursor
1661 motion and so on.
1662 ----*/
1663 void
1664 main_menu_screen(struct pine *pine_state)
1666 UCS ch;
1667 int cmd, just_a_navigate_cmd, setup_command, km_popped;
1668 int notrealinbox;
1669 char *new_folder, *utf8str;
1670 CONTEXT_S *tc;
1671 struct key_menu *km;
1672 OtherMenu what;
1673 Pos curs_pos;
1675 ps_global = pine_state;
1676 just_a_navigate_cmd = 0;
1677 km_popped = 0;
1678 menu_index = DEFAULT_MENU_ITEM;
1679 what = FirstMenu; /* which keymenu to display */
1680 ch = 'x'; /* For display_message 1st time through */
1681 pine_state->next_screen = SCREEN_FUN_NULL;
1682 pine_state->prev_screen = main_menu_screen;
1683 curs_pos.row = pine_state->ttyo->screen_rows-FOOTER_ROWS(pine_state);
1684 curs_pos.col = 0;
1685 km = &main_keymenu;
1687 mailcap_free(); /* free resources we won't be using for a while */
1689 if(!pine_state->painted_body_on_startup
1690 && !pine_state->painted_footer_on_startup){
1691 pine_state->mangled_screen = 1;
1694 dprint((1, "\n\n ---- MAIN_MENU_SCREEN ----\n"));
1696 while(1){
1697 if(km_popped){
1698 km_popped--;
1699 if(km_popped == 0){
1700 clearfooter(pine_state);
1701 pine_state->mangled_body = 1;
1706 * fix up redrawer just in case some submenu caused it to get
1707 * reassigned...
1709 pine_state->redrawer = main_redrawer;
1711 /*----------- Check for new mail -----------*/
1712 if(new_mail(0, NM_TIMING(ch), NM_STATUS_MSG | NM_DEFER_SORT) >= 0)
1713 pine_state->mangled_header = 1;
1715 if(streams_died())
1716 pine_state->mangled_header = 1;
1718 show_main_screen(pine_state, just_a_navigate_cmd, what, km,
1719 km_popped, &curs_pos);
1720 just_a_navigate_cmd = 0;
1721 what = SameMenu;
1723 /*---- This displays new mail notification, or errors ---*/
1724 if(km_popped){
1725 FOOTER_ROWS(pine_state) = 3;
1726 mark_status_dirty();
1729 display_message(ch);
1730 if(km_popped){
1731 FOOTER_ROWS(pine_state) = 1;
1732 mark_status_dirty();
1735 if(F_OFF(F_SHOW_CURSOR, ps_global)){
1736 curs_pos.row =pine_state->ttyo->screen_rows-FOOTER_ROWS(pine_state);
1737 curs_pos.col =0;
1740 MoveCursor(curs_pos.row, curs_pos.col);
1742 /*------ Read the command from the keyboard ----*/
1743 #ifdef MOUSE
1744 mouse_in_content(KEY_MOUSE, -1, -1, 0, 0);
1745 register_mfunc(mouse_in_content, HEADER_ROWS(pine_state), 0,
1746 pine_state->ttyo->screen_rows-(FOOTER_ROWS(pine_state)+1),
1747 pine_state->ttyo->screen_cols);
1748 #endif
1749 #if defined(DOS) || defined(OS2)
1751 * AND pre-build header lines. This works just fine under
1752 * DOS since we wait for characters in a loop. Something will
1753 * will have to change under UNIX if we want to do the same.
1755 /* while_waiting = build_header_cache; */
1756 #ifdef _WINDOWS
1757 mswin_sethelptextcallback(pcpine_help_main);
1758 mswin_mousetrackcallback(pcpine_main_cursor);
1759 #endif
1760 #endif
1761 ch = READ_COMMAND(&utf8str);
1762 #ifdef MOUSE
1763 clear_mfunc(mouse_in_content);
1764 #endif
1765 #if defined(DOS) || defined(OS2)
1766 /* while_waiting = NULL; */
1767 #ifdef _WINDOWS
1768 mswin_sethelptextcallback(NULL);
1769 mswin_mousetrackcallback(NULL);
1770 #endif
1771 #endif
1773 /* No matter what, Quit here always works */
1774 if(ch == 'q' || ch == 'Q'){
1775 cmd = MC_QUIT;
1777 #ifdef DEBUG
1778 else if(debug && ch && ch < 0x80 && strchr("123456789", ch)){
1779 int olddebug;
1781 olddebug = debug;
1782 debug = ch - '0';
1783 if(debug > 7)
1784 ps_global->debug_timestamp = 1;
1785 else
1786 ps_global->debug_timestamp = 0;
1788 if(debug > 7)
1789 ps_global->debug_imap = 4;
1790 else if(debug > 6)
1791 ps_global->debug_imap = 3;
1792 else if(debug > 4)
1793 ps_global->debug_imap = 2;
1794 else if(debug > 2)
1795 ps_global->debug_imap = 1;
1796 else
1797 ps_global->debug_imap = 0;
1799 if(ps_global->mail_stream){
1800 if(ps_global->debug_imap > 0){
1801 mail_debug(ps_global->mail_stream);
1802 #ifdef _WINDOWS
1803 mswin_enableimaptelemetry(TRUE);
1804 #endif
1806 else{
1807 mail_nodebug(ps_global->mail_stream);
1808 #ifdef _WINDOWS
1809 mswin_enableimaptelemetry(FALSE);
1810 #endif
1814 if(debug > 7 && olddebug <= 7)
1815 mail_parameters(NULL, SET_TCPDEBUG, (void *) TRUE);
1816 else if(debug <= 7 && olddebug > 7 && !ps_global->debugmem)
1817 mail_parameters(NULL, SET_TCPDEBUG, (void *) FALSE);
1819 dprint((1, "*** Debug level set to %d ***\n", debug));
1820 if(debugfile)
1821 fflush(debugfile);
1823 q_status_message1(SM_ORDER, 0, 1, _("Debug level set to %s"),
1824 int2string(debug));
1825 continue;
1827 #endif /* DEBUG */
1828 else{
1829 cmd = menu_command(ch, km);
1831 if(km_popped)
1832 switch(cmd){
1833 case MC_NONE :
1834 case MC_OTHER :
1835 case MC_RESIZE :
1836 case MC_REPAINT :
1837 km_popped++;
1838 break;
1840 default:
1841 clearfooter(pine_state);
1842 break;
1846 /*------ Execute the command ------*/
1847 switch (cmd){
1848 help_case :
1849 /*------ HELP ------*/
1850 case MC_HELP :
1852 if(FOOTER_ROWS(pine_state) == 1 && km_popped == 0){
1853 km_popped = 2;
1854 pine_state->mangled_footer = 1;
1856 else{
1857 /* TRANSLATORS: This is a screen title */
1858 helper(main_menu_tx, _("HELP FOR MAIN MENU"), 0);
1859 pine_state->mangled_screen = 1;
1862 break;
1865 /*---------- display other key bindings ------*/
1866 case MC_OTHER :
1867 if(ch == 'o')
1868 warn_other_cmds();
1870 what = NextMenu;
1871 pine_state->mangled_footer = 1;
1872 break;
1875 /*---------- Previous item in menu ----------*/
1876 case MC_PREVITEM :
1877 if(menu_index > 0) {
1878 menu_index--;
1879 pine_state->mangled_body = 1;
1880 if(km->which == 0)
1881 pine_state->mangled_footer = 1;
1883 just_a_navigate_cmd++;
1885 else
1886 /* TRANSLATORS: list refers to list of commands in main menu */
1887 q_status_message(SM_ORDER, 0, 2, _("Already at top of list"));
1889 break;
1892 /*---------- Next item in menu ----------*/
1893 case MC_NEXTITEM :
1894 if(menu_index < MAX_MENU_ITEM){
1895 menu_index++;
1896 pine_state->mangled_body = 1;
1897 if(km->which == 0)
1898 pine_state->mangled_footer = 1;
1900 just_a_navigate_cmd++;
1902 else
1903 q_status_message(SM_ORDER, 0, 2, _("Already at bottom of list"));
1905 break;
1908 /*---------- Release Notes ----------*/
1909 case MC_RELNOTES :
1910 /* TRANSLATORS: This is a screen title */
1911 helper(h_news, _("ALPINE RELEASE NOTES"), 0);
1912 pine_state->mangled_screen = 1;
1913 break;
1916 #ifdef KEYBOARD_LOCK
1917 /*---------- Keyboard lock ----------*/
1918 case MC_KBLOCK :
1919 (void) lock_keyboard();
1920 pine_state->mangled_screen = 1;
1921 break;
1922 #endif /* KEYBOARD_LOCK */
1925 /*---------- Quit pine ----------*/
1926 case MC_QUIT :
1927 pine_state->next_screen = quit_screen;
1928 return;
1931 /*---------- Go to composer ----------*/
1932 case MC_COMPOSE :
1933 pine_state->next_screen = compose_screen;
1934 return;
1937 /*---- Go to alternate composer ------*/
1938 case MC_ROLE :
1939 pine_state->next_screen = alt_compose_screen;
1940 return;
1943 /*---------- Top of Folder list ----------*/
1944 case MC_COLLECTIONS :
1945 pine_state->next_screen = folder_screen;
1946 return;
1949 /*---------- Goto new folder ----------*/
1950 case MC_GOTO :
1951 tc = ps_global->context_current;
1952 new_folder = broach_folder(-FOOTER_ROWS(pine_state), 1, &notrealinbox, &tc);
1953 if(new_folder)
1954 visit_folder(ps_global, new_folder, tc, NULL, notrealinbox ? 0L : DB_INBOXWOCNTXT);
1956 return;
1959 /*---------- Go to index ----------*/
1960 case MC_INDEX :
1961 if(THREADING()
1962 && sp_viewing_a_thread(pine_state->mail_stream)
1963 && unview_thread(pine_state, pine_state->mail_stream,
1964 pine_state->msgmap)){
1965 pine_state->view_skipped_index = 0;
1966 pine_state->mangled_screen = 1;
1969 pine_state->next_screen = mail_index_screen;
1970 return;
1973 /*---------- Review Status Messages ----------*/
1974 case MC_JOURNAL :
1975 review_messages();
1976 pine_state->mangled_screen = 1;
1977 break;
1980 /*---------- Setup mini menu ----------*/
1981 case MC_SETUP :
1982 setup_case :
1983 setup_command = setup_menu(pine_state);
1984 pine_state->mangled_footer = 1;
1985 do_setup_task(setup_command);
1986 if(ps_global->next_screen != main_menu_screen)
1987 return;
1989 break;
1992 /*---------- Go to address book ----------*/
1993 case MC_ADDRBOOK :
1994 pine_state->next_screen = addr_book_screen;
1995 return;
1998 /*------ Repaint the works -------*/
1999 case MC_RESIZE :
2000 case MC_REPAINT :
2001 ClearScreen();
2002 pine_state->mangled_screen = 1;
2003 break;
2006 #ifdef MOUSE
2007 /*------- Mouse event ------*/
2008 case MC_MOUSE :
2010 MOUSEPRESS mp;
2011 unsigned ndmi;
2012 struct pine *ps = pine_state;
2014 mouse_get_last (NULL, &mp);
2016 #ifdef _WINDOWS
2017 if(mp.button == M_BUTTON_RIGHT){
2018 if(!mp.doubleclick){
2019 static MPopup main_popup[] = {
2020 {tQueue, {"Folder List", lNormal}, {'L'}},
2021 {tQueue, {"Message Index", lNormal}, {'I'}},
2022 {tSeparator},
2023 {tQueue, {"Address Book", lNormal}, {'A'}},
2024 {tQueue, {"Setup Options", lNormal}, {'S'}},
2025 {tTail}
2028 mswin_popup(main_popup);
2031 else {
2032 #endif
2033 if (mp.row >= (HEADER_ROWS(ps) + MNSKIP(ps)))
2034 ndmi = (mp.row+1 - HEADER_ROWS(ps) - (MNSKIP(ps)+1))/(MNSKIP(ps)+1);
2036 if (mp.row >= (HEADER_ROWS(ps) + MNSKIP(ps))
2037 && !(MNSKIP(ps) && (mp.row+1) & 0x01)
2038 && ndmi <= MAX_MENU_ITEM
2039 && FOOTER_ROWS(ps) + (ndmi+1)*(MNSKIP(ps)+1)
2040 + MNSKIP(ps) + FOOTER_ROWS(ps) <= ps->ttyo->screen_rows){
2041 if(mp.doubleclick){
2042 switch(ndmi){ /* fake main_screen request */
2043 case 0 :
2044 goto help_case;
2046 case 1 :
2047 pine_state->next_screen = compose_screen;
2048 return;
2050 case 2 :
2051 pine_state->next_screen = mail_index_screen;
2052 return;
2054 case 3 :
2055 pine_state->next_screen = folder_screen;
2056 return;
2058 case 4 :
2059 pine_state->next_screen = addr_book_screen;
2060 return;
2062 case 5 :
2063 goto setup_case;
2065 case 6 :
2066 pine_state->next_screen = quit_screen;
2067 return;
2069 default: /* no op */
2070 break;
2073 else{
2074 menu_index = ndmi;
2075 pine_state->mangled_body = 1;
2076 if(km->which == 0)
2077 pine_state->mangled_footer = 1;
2079 just_a_navigate_cmd++;
2082 #ifdef _WINDOWS
2084 #endif
2087 break;
2088 #endif
2091 /*------ Input timeout ------*/
2092 case MC_NONE :
2093 break; /* noop for timeout loop mail check */
2096 /*------ Bogus Input ------*/
2097 case MC_UNKNOWN :
2098 if(ch == 'm' || ch == 'M'){
2099 q_status_message(SM_ORDER, 0, 1, "Already in Main Menu");
2100 break;
2103 default:
2104 bogus_command(ch, F_ON(F_USE_FK,pine_state) ? "F1" : "?");
2105 break;
2107 case MC_UTF8:
2108 bogus_utf8_command(utf8str, F_ON(F_USE_FK, pine_state) ? "F1" : "?");
2109 break;
2110 } /* the switch */
2111 } /* the BIG while loop! */
2115 /*----------------------------------------------------------------------
2116 Re-Draw the main menu
2118 Args: none.
2120 Result: main menu is re-displayed
2121 ----*/
2122 void
2123 main_redrawer(void)
2125 struct key_menu *km = &main_keymenu;
2127 ps_global->mangled_screen = 1;
2128 show_main_screen(ps_global, 0, FirstMenu, km, 0, (Pos *)NULL);
2132 /*----------------------------------------------------------------------
2133 Draw the main menu
2135 Args: pine_state - the usual struct
2136 quick_draw - tells do_menu() it can skip some drawing
2137 what - tells which section of keymenu to draw
2138 km - the keymenu
2139 cursor_pos - returns a good position for the cursor to be located
2141 Result: main menu is displayed
2142 ----*/
2143 void
2144 show_main_screen(struct pine *ps, int quick_draw, OtherMenu what,
2145 struct key_menu *km, int km_popped, Pos *cursor_pos)
2147 if(ps->painted_body_on_startup || ps->painted_footer_on_startup){
2148 ps->mangled_screen = 0; /* only worry about it here */
2149 ps->mangled_header = 1; /* we have to redo header */
2150 if(!ps->painted_body_on_startup)
2151 ps->mangled_body = 1; /* make sure to paint body*/
2153 if(!ps->painted_footer_on_startup)
2154 ps->mangled_footer = 1; /* make sure to paint footer*/
2156 ps->painted_body_on_startup = 0;
2157 ps->painted_footer_on_startup = 0;
2160 if(ps->mangled_screen){
2161 ps->mangled_header = 1;
2162 ps->mangled_body = 1;
2163 ps->mangled_footer = 1;
2164 ps->mangled_screen = 0;
2167 #ifdef _WINDOWS
2168 /* Reset the scroll range. Main screen never scrolls. */
2169 scroll_setrange (0L, 0L);
2170 mswin_beginupdate();
2171 #endif
2173 /* paint the titlebar if needed */
2174 if(ps->mangled_header){
2175 /* TRANSLATORS: screen title */
2176 set_titlebar(_("MAIN MENU"), ps->mail_stream, ps->context_current,
2177 ps->cur_folder, ps->msgmap, 1, FolderName, 0, 0, NULL);
2178 ps->mangled_header = 0;
2181 /* paint the body if needed */
2182 if(ps->mangled_body){
2183 if(!quick_draw)
2184 ClearBody();
2186 do_menu(quick_draw, cursor_pos, km);
2187 ps->mangled_body = 0;
2190 /* paint the keymenu if needed */
2191 if(km && ps->mangled_footer){
2192 static char label[LONGEST_LABEL + 2 + 1], /* label + brackets + \0 */
2193 name[8];
2194 bitmap_t bitmap;
2196 setbitmap(bitmap);
2198 #ifdef KEYBOARD_LOCK
2199 if(ps_global->restricted || F_ON(F_DISABLE_KBLOCK_CMD,ps_global))
2200 #endif
2201 clrbitn(MAIN_KBLOCK_KEY, bitmap);
2203 menu_clear_binding(km, '>');
2204 menu_clear_binding(km, '.');
2205 menu_clear_binding(km, KEY_RIGHT);
2206 menu_clear_binding(km, ctrl('M'));
2207 menu_clear_binding(km, ctrl('J'));
2208 km->keys[MAIN_DEFAULT_KEY].bind
2209 = km->keys[mkeys[menu_index].key_index].bind;
2210 km->keys[MAIN_DEFAULT_KEY].label
2211 = km->keys[mkeys[menu_index].key_index].label;
2213 /* put brackets around the default action */
2214 snprintf(label, sizeof(label), "[%s]", km->keys[mkeys[menu_index].key_index].label);
2215 label[sizeof(label)-1] = '\0';
2216 strncpy(name, ">", sizeof(name));
2217 name[sizeof(name)-1] = '\0';
2218 km->keys[MAIN_DEFAULT_KEY].label = label;
2219 km->keys[MAIN_DEFAULT_KEY].name = name;
2220 menu_add_binding(km, '>', km->keys[MAIN_DEFAULT_KEY].bind.cmd);
2221 menu_add_binding(km, '.', km->keys[MAIN_DEFAULT_KEY].bind.cmd);
2222 menu_add_binding(km, ctrl('M'), km->keys[MAIN_DEFAULT_KEY].bind.cmd);
2223 menu_add_binding(km, ctrl('J'), km->keys[MAIN_DEFAULT_KEY].bind.cmd);
2225 if(F_ON(F_ARROW_NAV,ps_global))
2226 menu_add_binding(km, KEY_RIGHT, km->keys[MAIN_DEFAULT_KEY].bind.cmd);
2228 if(km_popped){
2229 FOOTER_ROWS(ps) = 3;
2230 clearfooter(ps);
2233 draw_keymenu(km, bitmap, ps_global->ttyo->screen_cols,
2234 1-FOOTER_ROWS(ps_global), 0, what);
2235 ps->mangled_footer = 0;
2236 if(km_popped){
2237 FOOTER_ROWS(ps) = 1;
2238 mark_keymenu_dirty();
2242 #ifdef _WINDOWS
2243 mswin_endupdate();
2244 #endif
2248 /*----------------------------------------------------------------------
2249 Actually display the main menu
2251 Args: quick_draw - just a next or prev command was typed so we only have
2252 to redraw the highlighting
2253 cursor_pos - a place to return a good value for cursor location
2255 Result: Main menu is displayed
2256 ---*/
2257 void
2258 do_menu(int quick_draw, Pos *cursor_pos, struct key_menu *km)
2260 struct pine *ps = ps_global;
2261 int dline, indent, longest = 0, cmd;
2262 char buf[4*MAX_SCREEN_COLS+1];
2263 char buf2[4*MAX_SCREEN_COLS+1];
2264 static int last_inverse = -1;
2265 Pos pos;
2267 /* find the longest command */
2268 for(cmd = 0; cmd < sizeof(mkeys)/(sizeof(mkeys[1])); cmd++){
2269 memset((void *) buf, ' ', sizeof(buf));
2270 snprintf(buf, sizeof(buf), mkeys[cmd].key_and_name[0] ? _(mkeys[cmd].key_and_name) : "",
2271 (F_OFF(F_USE_FK,ps)
2272 && km->keys[mkeys[cmd].key_index].name)
2273 ? km->keys[mkeys[cmd].key_index].name : "",
2274 (ps->VAR_NEWS_SPEC && mkeys[cmd].news_addition && mkeys[cmd].news_addition[0])
2275 ? _(mkeys[cmd].news_addition) : "");
2276 buf[sizeof(buf)-1] = '\0';
2278 if(longest < (indent = utf8_width(buf)))
2279 longest = indent;
2282 indent = MAX(((ps->ttyo->screen_cols - longest)/2) - 1, 0);
2284 dline = HEADER_ROWS(ps) + MNSKIP(ps);
2285 for(cmd = 0; cmd < sizeof(mkeys)/(sizeof(mkeys[1])); cmd++){
2286 /* leave room for copyright and footer */
2287 if(dline + MNSKIP(ps) + 1 + FOOTER_ROWS(ps) >= ps->ttyo->screen_rows)
2288 break;
2290 if(quick_draw && !(cmd == last_inverse || cmd == menu_index)){
2291 dline += (1 + MNSKIP(ps));
2292 continue;
2295 if(cmd == menu_index)
2296 StartInverse();
2298 memset((void *) buf, ' ', sizeof(buf));
2299 snprintf(buf, sizeof(buf), mkeys[cmd].key_and_name[0] ? _(mkeys[cmd].key_and_name) : "",
2300 (F_OFF(F_USE_FK,ps)
2301 && km->keys[mkeys[cmd].key_index].name)
2302 ? km->keys[mkeys[cmd].key_index].name : "",
2303 (ps->VAR_NEWS_SPEC && mkeys[cmd].news_addition && mkeys[cmd].news_addition[0])
2304 ? _(mkeys[cmd].news_addition) : "");
2305 buf[sizeof(buf)-1] = '\0';
2307 utf8_pad_to_width(buf2, buf, sizeof(buf2),
2308 MIN(ps->ttyo->screen_cols-indent,longest+1), 1);
2309 pos.row = dline++;
2310 pos.col = indent;
2311 PutLine0(pos.row, pos.col, buf2);
2313 if(MNSKIP(ps))
2314 dline++;
2316 if(cmd == menu_index){
2317 if(cursor_pos){
2318 cursor_pos->row = pos.row;
2319 /* 6 is 1 for the letter plus 5 spaces */
2320 cursor_pos->col = pos.col + 6;
2321 if(F_OFF(F_USE_FK,ps))
2322 cursor_pos->col++;
2324 cursor_pos->col = MIN(cursor_pos->col, ps->ttyo->screen_cols);
2327 EndInverse();
2332 last_inverse = menu_index;
2334 if(!quick_draw && FOOTER_ROWS(ps)+1 < ps->ttyo->screen_rows){
2335 utf8_to_width(buf2, LEGAL_NOTICE, sizeof(buf2),
2336 ps->ttyo->screen_cols-3, NULL);
2337 PutLine0(ps->ttyo->screen_rows - (FOOTER_ROWS(ps)+1),
2338 MAX(0, ((ps->ttyo->screen_cols-utf8_width(buf2))/2)),
2339 buf2);
2342 fflush(stdout);
2347 choose_setup_cmd(int cmd, MSGNO_S *msgmap, SCROLL_S *sparms)
2349 int rv = 1;
2350 SRV_S *srv;
2352 if(!(srv = (SRV_S *)sparms->proc.data.p)){
2353 sparms->proc.data.p = (SRV_S *)fs_get(sizeof(*srv));
2354 srv = (SRV_S *)sparms->proc.data.p;
2355 memset(srv, 0, sizeof(*srv));
2358 ps_global->next_screen = SCREEN_FUN_NULL;
2360 switch(cmd){
2361 case MC_PRINTER :
2362 srv->cmd = 'p';
2363 break;
2365 case MC_PASSWD :
2366 srv->cmd = 'n';
2367 break;
2369 case MC_CONFIG :
2370 srv->cmd = 'c';
2371 break;
2373 case MC_XOAUTH2 :
2374 srv->cmd = 'u';
2375 break;
2377 case MC_SIG :
2378 srv->cmd = 's';
2379 break;
2381 case MC_ABOOKS :
2382 srv->cmd = 'a';
2383 break;
2385 case MC_CLISTS :
2386 srv->cmd = 'l';
2387 break;
2389 case MC_RULES :
2390 srv->cmd = 'r';
2391 break;
2393 case MC_DIRECTORY :
2394 srv->cmd = 'd';
2395 break;
2397 case MC_KOLOR :
2398 srv->cmd = 'k';
2399 break;
2401 case MC_REMOTE :
2402 srv->cmd = 'z';
2403 break;
2405 case MC_SECURITY : /* S/MIME setup screen */
2406 srv->cmd = 'm';
2407 break;
2409 case MC_EXCEPT :
2410 srv->exc = !srv->exc;
2411 menu_clear_binding(sparms->keys.menu, 'x');
2412 if(srv->exc){
2413 if(sparms->bar.title) fs_give((void **)&sparms->bar.title);
2414 /* TRANSLATORS: screen title */
2415 sparms->bar.title = cpystr(_("SETUP EXCEPTIONS"));
2416 ps_global->mangled_header = 1;
2417 /* TRANSLATORS: The reason the X is upper case in eXceptions
2418 is because the command key is X. It isn't necessary, just
2419 nice if it works. */
2420 menu_init_binding(sparms->keys.menu, 'x', MC_EXCEPT, "X",
2421 N_("not eXceptions"), SETUP_EXCEPT);
2423 else{
2424 if(sparms->bar.title) fs_give((void **)&sparms->bar.title);
2425 /* TRANSLATORS: screen title */
2426 sparms->bar.title = cpystr(_("SETUP"));
2427 ps_global->mangled_header = 1;
2428 menu_init_binding(sparms->keys.menu, 'x', MC_EXCEPT, "X",
2429 N_("eXceptions"), SETUP_EXCEPT);
2432 if(sparms->keys.menu->which == 1)
2433 ps_global->mangled_footer = 1;
2435 rv = 0;
2436 break;
2438 case MC_NO_EXCEPT :
2439 #if defined(DOS) || defined(OS2)
2440 q_status_message(SM_ORDER, 0, 2, _("Need argument \"-x <except_config>\" or \"PINERCEX\" file to use eXceptions"));
2441 #else
2442 q_status_message(SM_ORDER, 0, 2, _("Need argument \"-x <except_config>\" or \".pinercex\" file to use eXceptions"));
2443 #endif
2444 rv = 0;
2445 break;
2447 default:
2448 alpine_panic("Unexpected command in choose_setup_cmd");
2449 break;
2452 return(rv);
2457 setup_menu(struct pine *ps)
2459 int ret = 0, exceptions = 0;
2460 int printer = 0, passwd = 0, config = 0, sig = 0, dir = 0, smime = 0, exc = 0;
2461 SCROLL_S sargs;
2462 SRV_S *srv;
2463 STORE_S *store;
2465 if(!(store = so_get(CharStar, NULL, EDIT_ACCESS))){
2466 q_status_message(SM_ORDER | SM_DING, 3, 3, _("Error allocating space."));
2467 return(ret);
2470 #if !defined(DOS)
2471 if(!ps_global->vars[V_PRINTER].is_fixed) /* printer can be changed */
2472 printer++;
2473 #endif
2475 #ifdef PASSWD_PROG
2476 if(F_OFF(F_DISABLE_PASSWORD_CMD,ps_global)) /* password is allowed */
2477 passwd++;
2478 #endif
2480 if(F_OFF(F_DISABLE_CONFIG_SCREEN,ps_global)) /* config allowed */
2481 config++;
2483 if(F_OFF(F_DISABLE_SIGEDIT_CMD,ps_global)) /* .sig editing is allowed */
2484 sig++;
2486 #ifdef ENABLE_LDAP
2487 dir++;
2488 #endif
2490 #ifdef SMIME
2491 smime++;
2492 #endif
2494 if(ps_global->post_prc)
2495 exc++;
2497 /* TRANSLATORS: starting here we have a whole screen of help text */
2498 so_puts(store, _("This is the Setup screen for Alpine. Choose from the following commands:\n"));
2500 so_puts(store, "\n");
2501 so_puts(store, _("(E) Exit Setup:\n"));
2502 so_puts(store, _(" This puts you back at the Main Menu.\n"));
2504 if(exc){
2505 so_puts(store, "\n");
2506 so_puts(store, _("(X) eXceptions:\n"));
2507 so_puts(store, _(" This command is different from the rest. It is not actually a command\n"));
2508 so_puts(store, _(" itself. Instead, it is a toggle which modifies the behavior of the\n"));
2509 so_puts(store, _(" other commands. You toggle Exceptions editing on and off with this\n"));
2510 so_puts(store, _(" command. When it is off you will be editing (changing) your regular\n"));
2511 so_puts(store, _(" configuration file. When it is on you will be editing your exceptions\n"));
2512 so_puts(store, _(" configuration file. For example, you might want to type the command \n"));
2513 so_puts(store, _(" \"eXceptions\" followed by \"Kolor\" to setup different screen colors\n"));
2514 so_puts(store, _(" on a particular platform.\n"));
2515 so_puts(store, _(" (Note: this command does not show up on the keymenu at the bottom of\n"));
2516 so_puts(store, _(" the screen unless you press \"O\" for \"Other Commands\" --but you don't\n"));
2517 so_puts(store, _(" need to press the \"O\" in order to invoke the command.)\n"));
2520 if(printer){
2521 so_puts(store, "\n");
2522 so_puts(store, _("(P) Printer:\n"));
2523 so_puts(store, _(" Allows you to set a default printer and to define custom\n"));
2524 so_puts(store, _(" print commands.\n"));
2527 if(passwd){
2528 so_puts(store, "\n");
2529 so_puts(store, _("(N) Newpassword:\n"));
2530 so_puts(store, _(" Change your password.\n"));
2533 if(config){
2534 so_puts(store, "\n");
2535 so_puts(store, _("(C) Config:\n"));
2536 so_puts(store, _(" Allows you to set or unset many features of Alpine.\n"));
2537 so_puts(store, _(" You may also set the values of many options with this command.\n"));
2540 if(sig){
2541 so_puts(store, "\n");
2542 so_puts(store, _("(S) Signature:\n"));
2543 so_puts(store, _(" Enter or edit a custom signature which will\n"));
2544 so_puts(store, _(" be included with each new message you send.\n"));
2547 so_puts(store, "\n");
2548 so_puts(store, _("(A) AddressBooks:\n"));
2549 so_puts(store, _(" Define a non-default address book.\n"));
2551 so_puts(store, "\n");
2552 so_puts(store, _("(L) collectionLists:\n"));
2553 so_puts(store, _(" You may define groups of folders to help you better organize your mail.\n"));
2555 so_puts(store, "\n");
2556 so_puts(store, _("(R) Rules:\n"));
2557 so_puts(store, _(" This has up to six sub-categories: Roles, Index Colors, Filters,\n"));
2558 so_puts(store, _(" SetScores, Search, and Other. If the Index Colors option is\n"));
2559 so_puts(store, _(" missing you may turn it on (if possible) with Setup/Kolor.\n"));
2560 so_puts(store, _(" If Roles is missing it has probably been administratively disabled.\n"));
2562 if(dir){
2563 so_puts(store, "\n");
2564 so_puts(store, _("(D) Directory:\n"));
2565 so_puts(store, _(" Define an LDAP Directory server for Alpine's use. A directory server is\n"));
2566 so_puts(store, _(" similar to an address book, but it is usually maintained by an\n"));
2567 so_puts(store, _(" organization. It is similar to a telephone directory.\n"));
2570 so_puts(store, "\n");
2571 so_puts(store, _("(K) Kolor:\n"));
2572 so_puts(store, _(" Set custom colors for various parts of the Alpine screens. For example, the\n"));
2573 so_puts(store, _(" command key labels, the titlebar at the top of each page, and quoted\n"));
2574 so_puts(store, _(" sections of messages you are viewing.\n"));
2576 if(smime){
2577 so_puts(store, "\n");
2578 so_puts(store, _("(M) S/MIME:\n"));
2579 so_puts(store, _(" Setup for using S/MIME to verify signed messages, decrypt\n"));
2580 so_puts(store, _(" encrypted messages, and to sign or encrypt outgoing messages.\n"));
2583 so_puts(store, "\n");
2584 so_puts(store, _("(U) xoaUth2:\n"));
2585 so_puts(store, _(" Set client-id and client-secret to use the XOAUTH2\n"));
2586 so_puts(store, _(" authenticator.\n"));
2588 so_puts(store, "\n");
2589 so_puts(store, _("(Z) RemoteConfigSetup:\n"));
2590 so_puts(store, _(" This is a command you will probably only want to use once, if at all.\n"));
2591 so_puts(store, _(" It helps you transfer your Alpine configuration data to an IMAP server,\n"));
2592 so_puts(store, _(" where it will be accessible from any of the computers you read mail\n"));
2593 so_puts(store, _(" from (using Alpine). The idea behind a remote configuration is that you\n"));
2594 so_puts(store, _(" can change your configuration in one place and have that change show\n"));
2595 so_puts(store, _(" up on all of the computers you use.\n"));
2596 so_puts(store, _(" (Note: this command does not show up on the keymenu at the bottom of\n"));
2597 so_puts(store, _(" the screen unless you press \"O\" for \"Other Commands\" --but you don't\n"));
2598 so_puts(store, _(" need to press the \"O\" in order to invoke the command.)\n"));
2600 /* put this down here for people who don't have exceptions */
2601 if(!exc){
2602 so_puts(store, "\n");
2603 so_puts(store, _("(X) eXceptions:\n"));
2604 so_puts(store, _(" This command is different from the rest. It is not actually a command\n"));
2605 so_puts(store, _(" itself. Instead, it is a toggle which modifies the behavior of the\n"));
2606 so_puts(store, _(" other commands. You toggle Exceptions editing on and off with this\n"));
2607 so_puts(store, _(" command. When it is off you will be editing (changing) your regular\n"));
2608 so_puts(store, _(" configuration file. When it is on you will be editing your exceptions\n"));
2609 so_puts(store, _(" configuration file. For example, you might want to type the command \n"));
2610 so_puts(store, _(" \"eXceptions\" followed by \"Kolor\" to setup different screen colors\n"));
2611 so_puts(store, _(" on a particular platform.\n"));
2612 so_puts(store, _(" (Note: this command does not do anything unless you have a configuration\n"));
2613 so_puts(store, _(" with exceptions enabled (you don't have that). Common ways to enable an\n"));
2614 so_puts(store, _(" exceptions config are the command line argument \"-x <exception_config>\";\n"));
2615 so_puts(store, _(" or the existence of the file \".pinercex\" for Unix Alpine, or \"PINERCEX\")\n"));
2616 so_puts(store, _(" for PC-Alpine.)\n"));
2617 so_puts(store, _(" (Another note: this command does not show up on the keymenu at the bottom\n"));
2618 so_puts(store, _(" of the screen unless you press \"O\" for \"Other Commands\" --but you\n"));
2619 so_puts(store, _(" don't need to press the \"O\" in order to invoke the command.)\n"));
2622 memset(&sargs, 0, sizeof(SCROLL_S));
2623 sargs.text.text = so_text(store);
2624 sargs.text.src = CharStar;
2625 sargs.text.desc = _("Information About Setup Command");
2626 sargs.bar.title = cpystr(_("SETUP"));
2627 sargs.proc.tool = choose_setup_cmd;
2628 sargs.help.text = NO_HELP;
2629 sargs.help.title = NULL;
2630 sargs.keys.menu = &choose_setup_keymenu;
2631 sargs.keys.menu->how_many = 2;
2633 setbitmap(sargs.keys.bitmap);
2634 if(!printer)
2635 clrbitn(SETUP_PRINTER, sargs.keys.bitmap);
2637 if(!passwd)
2638 clrbitn(SETUP_PASSWD, sargs.keys.bitmap);
2640 if(!config)
2641 clrbitn(SETUP_CONFIG, sargs.keys.bitmap);
2643 if(!sig)
2644 clrbitn(SETUP_SIG, sargs.keys.bitmap);
2646 if(!dir)
2647 clrbitn(SETUP_DIRECTORY, sargs.keys.bitmap);
2649 if(!smime)
2650 clrbitn(SETUP_SMIME, sargs.keys.bitmap);
2652 if(exc)
2653 menu_init_binding(sargs.keys.menu, 'x', MC_EXCEPT, "X",
2654 N_("eXceptions"), SETUP_EXCEPT);
2655 else
2656 menu_init_binding(sargs.keys.menu, 'x', MC_NO_EXCEPT, "X",
2657 N_("eXceptions"), SETUP_EXCEPT);
2660 scrolltool(&sargs);
2662 ps->mangled_screen = 1;
2664 srv = (SRV_S *)sargs.proc.data.p;
2666 exceptions = srv ? srv->exc : 0;
2668 so_give(&store);
2670 if(sargs.bar.title) fs_give((void**)&sargs.bar.title);
2671 if(srv){
2672 ret = srv->cmd;
2673 fs_give((void **)&sargs.proc.data.p);
2675 else
2676 ret = 'e';
2678 return(ret | (exceptions ? EDIT_EXCEPTION : 0));
2682 /*----------------------------------------------------------------------
2684 Args: command -- command char to perform
2686 ----*/
2687 void
2688 do_setup_task(int command)
2690 char *err = NULL;
2691 int rtype;
2692 int edit_exceptions = 0;
2693 int do_lit_sig = 0;
2695 if(command & EDIT_EXCEPTION){
2696 edit_exceptions = 1;
2697 command &= ~EDIT_EXCEPTION;
2700 switch(command) {
2701 /*----- EDIT SIGNATURE -----*/
2702 case 's':
2703 if(ps_global->VAR_LITERAL_SIG)
2704 do_lit_sig = 1;
2705 else {
2706 char sig_path[MAXPATH+1];
2708 if(!signature_path(ps_global->VAR_SIGNATURE_FILE, sig_path, MAXPATH))
2709 do_lit_sig = 1;
2710 else if((!IS_REMOTE(ps_global->VAR_SIGNATURE_FILE)
2711 && can_access(sig_path, READ_ACCESS) == 0)
2712 ||(IS_REMOTE(ps_global->VAR_SIGNATURE_FILE)
2713 && (folder_exists(NULL, sig_path) & FEX_ISFILE)))
2714 do_lit_sig = 0;
2715 else if(!ps_global->vars[V_SIGNATURE_FILE].main_user_val.p
2716 && !ps_global->vars[V_SIGNATURE_FILE].cmdline_val.p
2717 && !ps_global->vars[V_SIGNATURE_FILE].fixed_val.p)
2718 do_lit_sig = 1;
2719 else
2720 do_lit_sig = 0;
2723 if(do_lit_sig){
2724 char *result = NULL;
2725 char **apval;
2726 EditWhich ew;
2727 int readonly = 0;
2729 ew = edit_exceptions ? ps_global->ew_for_except_vars : Main;
2731 if(ps_global->restricted)
2732 readonly = 1;
2733 else switch(ew){
2734 case Main:
2735 readonly = ps_global->prc->readonly;
2736 break;
2737 case Post:
2738 readonly = ps_global->post_prc->readonly;
2739 break;
2740 default:
2741 break;
2744 if(readonly)
2745 err = cpystr(ps_global->restricted
2746 ? "Alpine demo can't change config file"
2747 : _("Config file not changeable"));
2749 if(!err){
2750 apval = APVAL(&ps_global->vars[V_LITERAL_SIG], ew);
2751 if(!apval)
2752 err = cpystr(_("Problem accessing configuration"));
2753 else{
2754 char *input;
2756 input = (char *)fs_get((strlen(*apval ? *apval : "")+1) *
2757 sizeof(char));
2758 input[0] = '\0';
2759 cstring_to_string(*apval, input);
2760 err = signature_edit_lit(input, &result,
2761 _("SIGNATURE EDITOR"),
2762 h_composer_sigedit);
2763 fs_give((void **)&input);
2767 if(!err){
2768 char *cstring_version;
2770 cstring_version = string_to_cstring(result);
2772 set_variable(V_LITERAL_SIG, cstring_version, 0, 0, ew);
2774 if(cstring_version)
2775 fs_give((void **)&cstring_version);
2778 if(result)
2779 fs_give((void **)&result);
2781 else
2782 err = signature_edit(ps_global->VAR_SIGNATURE_FILE,
2783 _("SIGNATURE EDITOR"));
2785 if(err){
2786 q_status_message(SM_ORDER, 3, 4, err);
2787 fs_give((void **)&err);
2790 ps_global->mangled_screen = 1;
2791 break;
2793 /*----- ADD ADDRESSBOOK ----*/
2794 case 'a':
2795 addr_book_config(ps_global, edit_exceptions);
2796 menu_index = ABOOK_MENU_ITEM;
2797 ps_global->mangled_screen = 1;
2798 break;
2800 #ifdef ENABLE_LDAP
2801 /*--- ADD DIRECTORY SERVER --*/
2802 case 'd':
2803 directory_config(ps_global, edit_exceptions);
2804 ps_global->mangled_screen = 1;
2805 break;
2806 #endif
2808 #ifdef SMIME
2809 /*--- S/MIME --*/
2810 case 'm':
2811 smime_config_screen(ps_global, edit_exceptions);
2812 ps_global->mangled_screen = 1;
2813 break;
2814 #endif
2816 /*----- CONFIGURE OPTIONS -----*/
2817 case 'c':
2818 option_screen(ps_global, edit_exceptions);
2819 ps_global->mangled_screen = 1;
2820 break;
2822 /*----- XOAUTH2 CLIENT CONFIGURATION -----*/
2823 case 'u':
2824 alpine_xoauth2_configuration(ps_global, edit_exceptions);
2825 ps_global->mangled_screen = 1;
2826 break;
2828 /*----- COLLECTION LIST -----*/
2829 case 'l':
2830 folder_config_screen(ps_global, edit_exceptions);
2831 ps_global->mangled_screen = 1;
2832 break;
2834 /*----- RULES -----*/
2835 case 'r':
2836 rtype = rule_setup_type(ps_global, RS_RULES | RS_INCFILTNOW,
2837 _("Type of rule setup : "));
2838 switch(rtype){
2839 case 'r':
2840 case 's':
2841 case 'i':
2842 case 'f':
2843 case 'o':
2844 case 'c':
2845 role_config_screen(ps_global, (rtype == 'r') ? ROLE_DO_ROLES :
2846 (rtype == 's') ? ROLE_DO_SCORES :
2847 (rtype == 'o') ? ROLE_DO_OTHER :
2848 (rtype == 'f') ? ROLE_DO_FILTER :
2849 (rtype == 'c') ? ROLE_DO_SRCH :
2850 ROLE_DO_INCOLS,
2851 edit_exceptions);
2852 break;
2854 case 'Z':
2855 q_status_message(SM_ORDER | SM_DING, 3, 5,
2856 _("Try turning on color with the Setup/Kolor command."));
2857 break;
2859 case 'n':
2860 role_process_filters();
2861 break;
2863 default:
2864 cmd_cancelled(NULL);
2865 break;
2868 ps_global->mangled_screen = 1;
2869 break;
2871 /*----- COLOR -----*/
2872 case 'k':
2873 color_config_screen(ps_global, edit_exceptions);
2874 ps_global->mangled_screen = 1;
2875 break;
2877 case 'z':
2878 convert_to_remote_config(ps_global, edit_exceptions);
2879 ps_global->mangled_screen = 1;
2880 break;
2882 /*----- EXIT -----*/
2883 case 'e':
2884 break;
2886 /*----- NEW PASSWORD -----*/
2887 case 'n':
2888 #ifdef PASSWD_PROG
2889 if(ps_global->restricted){
2890 q_status_message(SM_ORDER, 3, 5,
2891 "Password change unavailable in restricted demo version of Alpine.");
2892 }else {
2893 change_passwd();
2894 ClearScreen();
2895 ps_global->mangled_screen = 1;
2897 #else
2898 q_status_message(SM_ORDER, 0, 5,
2899 _("Password changing not configured for this version of Alpine."));
2900 display_message('x');
2901 #endif /* DOS */
2902 break;
2904 #if !defined(DOS)
2905 /*----- CHOOSE PRINTER ------*/
2906 case 'p':
2907 select_printer(ps_global, edit_exceptions);
2908 ps_global->mangled_screen = 1;
2909 break;
2910 #endif
2916 rule_setup_type(struct pine *ps, int flags, char *prompt)
2918 ESCKEY_S opts[9];
2919 int ekey_num = 0, deefault = 0;
2921 if(flags & RS_INCADDR){
2922 deefault = 'a';
2923 opts[ekey_num].ch = 'a';
2924 opts[ekey_num].rval = 'a';
2925 opts[ekey_num].name = "A";
2926 opts[ekey_num++].label = "Addrbook";
2929 if(flags & RS_RULES){
2931 if(F_OFF(F_DISABLE_ROLES_SETUP,ps)){ /* roles are allowed */
2932 if(deefault != 'a')
2933 deefault = 'r';
2935 opts[ekey_num].ch = 'r';
2936 opts[ekey_num].rval = 'r';
2937 opts[ekey_num].name = "R";
2938 opts[ekey_num++].label = "Roles";
2940 else if(deefault != 'a')
2941 deefault = 's';
2943 opts[ekey_num].ch = 's';
2944 opts[ekey_num].rval = 's';
2945 opts[ekey_num].name = "S";
2946 opts[ekey_num++].label = "SetScores";
2948 #ifndef _WINDOWS
2949 if(ps->color_style != COL_NONE && pico_hascolor()){
2950 #endif
2951 if(deefault != 'a')
2952 deefault = 'i';
2954 opts[ekey_num].ch = 'i';
2955 opts[ekey_num].rval = 'i';
2956 opts[ekey_num].name = "I";
2957 opts[ekey_num++].label = "Indexcolor";
2958 #ifndef _WINDOWS
2960 else{
2961 opts[ekey_num].ch = 'i';
2962 opts[ekey_num].rval = 'Z'; /* notice this rval! */
2963 opts[ekey_num].name = "I";
2964 opts[ekey_num++].label = "Indexcolor";
2966 #endif
2968 opts[ekey_num].ch = 'f';
2969 opts[ekey_num].rval = 'f';
2970 opts[ekey_num].name = "F";
2971 opts[ekey_num++].label = "Filters";
2973 opts[ekey_num].ch = 'o';
2974 opts[ekey_num].rval = 'o';
2975 opts[ekey_num].name = "O";
2976 opts[ekey_num++].label = "Other";
2978 opts[ekey_num].ch = 'c';
2979 opts[ekey_num].rval = 'c';
2980 opts[ekey_num].name = "C";
2981 opts[ekey_num++].label = "searCh";
2985 if(flags & RS_INCEXP){
2986 opts[ekey_num].ch = 'e';
2987 opts[ekey_num].rval = 'e';
2988 opts[ekey_num].name = "E";
2989 opts[ekey_num++].label = "Export";
2992 if(flags & RS_INCFILTNOW){
2993 opts[ekey_num].ch = 'n';
2994 opts[ekey_num].rval = 'n';
2995 opts[ekey_num].name = "N";
2996 opts[ekey_num++].label = "filterNow";
2999 opts[ekey_num].ch = -1;
3001 return(radio_buttons(prompt, -FOOTER_ROWS(ps), opts,
3002 deefault, 'x', NO_HELP, RB_NORM));
3008 * Process the command list, changing function key notation into
3009 * lexical equivalents.
3011 void
3012 process_init_cmds(struct pine *ps, char **list)
3014 char **p;
3015 int i = 0;
3016 int j;
3017 int lpm1;
3018 #define MAX_INIT_CMDS 500
3019 /* this is just a temporary stack array, the real one is allocated below */
3020 int i_cmds[MAX_INIT_CMDS];
3021 int fkeys = 0;
3022 int not_fkeys = 0;
3024 if(list){
3025 for(p = list; *p; p++){
3026 if(i >= MAX_INIT_CMDS){
3027 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
3028 "Initial keystroke list too long at \"%s\"", *p);
3029 init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
3030 break;
3034 /* regular character commands */
3035 if(strlen(*p) == 1){
3036 i_cmds[i++] = **p;
3037 not_fkeys++;
3040 /* special commands */
3041 else if(strucmp(*p, "SPACE") == 0)
3042 i_cmds[i++] = ' ';
3043 else if(strucmp(*p, "CR") == 0)
3044 i_cmds[i++] = '\n';
3045 else if(strucmp(*p, "TAB") == 0)
3046 i_cmds[i++] = '\t';
3047 else if(strucmp(*p, "UP") == 0)
3048 i_cmds[i++] = KEY_UP;
3049 else if(strucmp(*p, "DOWN") == 0)
3050 i_cmds[i++] = KEY_DOWN;
3051 else if(strucmp(*p, "LEFT") == 0)
3052 i_cmds[i++] = KEY_LEFT;
3053 else if(strucmp(*p, "RIGHT") == 0)
3054 i_cmds[i++] = KEY_RIGHT;
3056 /* control chars */
3057 else if(strlen(*p) == 2 && **p == '^')
3058 i_cmds[i++] = ctrl(*((*p)+1));
3060 /* function keys */
3061 else if(**p == 'F' || **p == 'f'){
3062 int v;
3064 fkeys++;
3065 v = atoi((*p)+1);
3066 if(v >= 1 && v <= 12)
3067 i_cmds[i++] = PF1 + v - 1;
3068 else
3069 i_cmds[i++] = KEY_JUNK;
3072 /* literal string */
3073 else if(**p == '"' && (*p)[lpm1 = strlen(*p) - 1] == '"'){
3074 if(lpm1 + i - 1 > MAX_INIT_CMDS){
3075 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
3076 "Initial keystroke list too long, truncated at %s\n", *p);
3077 init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
3078 break; /* Bail out of this loop! */
3079 } else
3080 for(j = 1; j < lpm1; j++)
3081 i_cmds[i++] = (*p)[j];
3083 else {
3084 snprintf(tmp_20k_buf,SIZEOF_20KBUF,
3085 "Bad initial keystroke \"%.500s\" (missing comma?)", *p);
3086 init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
3087 break;
3093 * We don't handle the case where function keys are used to specify the
3094 * commands but some non-function key input is also required. For example,
3095 * you might want to jump to a specific message number and view it
3096 * on start up. To do that, you need to use character commands instead
3097 * of function key commands in the initial-keystroke-list.
3099 if(fkeys && not_fkeys){
3100 init_error(ps, SM_ORDER | SM_DING, 3, 5,
3101 "Mixed characters and function keys in \"initial-keystroke-list\", skipping.");
3102 i = 0;
3105 if(fkeys && !not_fkeys)
3106 F_TURN_ON(F_USE_FK,ps);
3107 if(!fkeys && not_fkeys)
3108 F_TURN_OFF(F_USE_FK,ps);
3110 if(i > 0){
3111 ps->initial_cmds = (int *)fs_get((i+1) * sizeof(int));
3112 ps->free_initial_cmds = ps->initial_cmds;
3113 for(j = 0; j < i; j++)
3114 ps->initial_cmds[j] = i_cmds[j];
3116 ps->initial_cmds[i] = 0;
3117 ps->in_init_seq = ps->save_in_init_seq = 1;
3122 UCS *
3123 user_wordseps(char **list)
3125 char **p;
3126 int i = 0;
3127 int j;
3128 #define MAX_SEPARATORS 500
3130 * This is just a temporary stack array, the real one is allocated below.
3131 * This is supposed to be way large enough.
3133 UCS seps[MAX_SEPARATORS+1];
3134 UCS *u;
3135 UCS *return_array = NULL;
3136 size_t l;
3138 seps[0] = '\0';
3140 if(list){
3141 for(p = list; *p; p++){
3142 if(i >= MAX_SEPARATORS){
3143 q_status_message(SM_ORDER | SM_DING, 3, 3,
3144 "Warning: composer-word-separators list is too long");
3145 break;
3148 u = utf8_to_ucs4_cpystr(*p);
3150 if(u){
3151 if(ucs4_strlen(u) == 1)
3152 seps[i++] = *u;
3153 else if(*u == '"' && u[l = ucs4_strlen(u) - 1] == '"'){
3154 if(l + i - 1 > MAX_SEPARATORS){
3155 q_status_message(SM_ORDER | SM_DING, 3, 3,
3156 "Warning: composer-word-separators list is too long");
3157 break; /* Bail out of this loop! */
3159 else{
3160 for(j = 1; j < l; j++)
3161 seps[i++] = u[j];
3164 else{
3165 l = ucs4_strlen(u);
3166 if(l + i > MAX_SEPARATORS){
3167 q_status_message(SM_ORDER | SM_DING, 3, 3,
3168 "Warning: composer-word-separators list is too long");
3169 break; /* Bail out of this loop! */
3171 else{
3172 for(j = 0; j < l; j++)
3173 seps[i++] = u[j];
3177 fs_give((void **) &u);
3182 seps[i] = '\0';
3184 if(i > 0)
3185 return_array = ucs4_cpystr(seps);
3187 return(return_array);
3192 * Make sure any errors during initialization get queued for display
3194 void
3195 queue_init_errors(struct pine *ps)
3197 int i;
3199 if(ps->init_errs){
3200 for(i = 0; (ps->init_errs)[i].message; i++){
3201 q_status_message((ps->init_errs)[i].flags,
3202 (ps->init_errs)[i].min_time,
3203 (ps->init_errs)[i].max_time,
3204 (ps->init_errs)[i].message);
3205 fs_give((void **)&(ps->init_errs)[i].message);
3208 fs_give((void **)&ps->init_errs);
3213 /*----------------------------------------------------------------------
3214 Quit pine if the user wants to
3216 Args: The usual pine structure
3218 Result: User is asked if she wants to quit, if yes then execute quit.
3220 Q U I T S C R E E N
3222 Not really a full screen. Just count up deletions and ask if we really
3223 want to quit.
3224 ----*/
3225 void
3226 quit_screen(struct pine *pine_state)
3228 int quit = 0;
3230 dprint((1, "\n\n ---- QUIT SCREEN ----\n"));
3232 if(F_ON(F_CHECK_MAIL_ONQUIT,ps_global)
3233 && pine_state->mail_stream != NULL
3234 && new_mail(1, VeryBadTime, NM_STATUS_MSG | NM_DEFER_SORT) > 0
3235 && (quit = want_to(_("Quit even though new mail just arrived"), 'y', 0,
3236 NO_HELP, WT_NORM | WT_DING)) != 'y'){
3237 refresh_sort(pine_state->mail_stream, pine_state->msgmap, SRT_VRB);
3238 pine_state->next_screen = pine_state->prev_screen;
3239 return;
3242 if(quit != 'y'
3243 && F_OFF(F_QUIT_WO_CONFIRM,pine_state)
3244 && want_to(_("Really quit Alpine"), 'y', 0, NO_HELP, WT_NORM) != 'y'){
3245 pine_state->next_screen = pine_state->prev_screen;
3246 return;
3249 goodnight_gracey(pine_state, 0);
3253 /*----------------------------------------------------------------------
3254 The nuts and bolts of actually cleaning up and exitting pine
3256 Args: ps -- the usual pine structure,
3257 exit_val -- what to tell our parent
3259 Result: This never returns
3261 ----*/
3262 void
3263 goodnight_gracey(struct pine *pine_state, int exit_val)
3265 int i, cnt_user_streams = 0;
3266 char *final_msg = NULL;
3267 char msg[MAX_SCREEN_COLS+1];
3268 char *pf = _("Alpine finished");
3269 MAILSTREAM *m;
3270 extern KBESC_T *kbesc;
3272 dprint((2, "goodnight_gracey:\n"));
3274 /* We want to do this here before we close up the streams */
3275 trim_remote_adrbks();
3277 for(i = 0; i < ps_global->s_pool.nstream; i++){
3278 m = ps_global->s_pool.streams[i];
3279 if(m && sp_flagged(m, SP_LOCKED) && sp_flagged(m, SP_USERFLDR))
3280 cnt_user_streams++;
3283 /* clean up open streams */
3285 if(pine_state->mail_stream
3286 && sp_flagged(pine_state->mail_stream, SP_LOCKED)
3287 && sp_flagged(pine_state->mail_stream, SP_USERFLDR)){
3288 dprint((5, "goodnight_gracey: close current stream\n"));
3289 expunge_and_close(pine_state->mail_stream,
3290 (cnt_user_streams <= 1) ? &final_msg : NULL, EC_NONE);
3291 cnt_user_streams--;
3294 pine_state->mail_stream = NULL;
3295 pine_state->redrawer = (void (*)(void))NULL;
3297 dprint((5,
3298 "goodnight_gracey: close other stream pool streams\n"));
3299 for(i = 0; i < ps_global->s_pool.nstream; i++){
3300 m = ps_global->s_pool.streams[i];
3302 * fix global for functions that depend(ed) on it sort_folder.
3303 * Hopefully those will get phased out.
3305 ps_global->mail_stream = m;
3306 if(m && sp_flagged(m, SP_LOCKED) && sp_flagged(m, SP_USERFLDR)
3307 && !sp_flagged(m, SP_INBOX)){
3308 sp_set_expunge_count(m, 0L);
3309 expunge_and_close(m, (cnt_user_streams <= 1) ? &final_msg : NULL,
3310 EC_NONE);
3311 cnt_user_streams--;
3315 for(i = 0; i < ps_global->s_pool.nstream; i++){
3316 m = ps_global->s_pool.streams[i];
3318 * fix global for functions that depend(ed) on it (sort_folder).
3319 * Hopefully those will get phased out.
3321 ps_global->mail_stream = m;
3322 if(m && sp_flagged(m, SP_LOCKED) && sp_flagged(m, SP_USERFLDR)
3323 && sp_flagged(m, SP_INBOX)){
3324 dprint((5,
3325 "goodnight_gracey: close inbox stream stream\n"));
3326 sp_set_expunge_count(m, 0L);
3327 expunge_and_close(m, (cnt_user_streams <= 1) ? &final_msg : NULL,
3328 EC_NONE);
3329 cnt_user_streams--;
3333 #ifdef _WINDOWS
3334 if(ps_global->ttyo)
3335 (void)get_windsize(ps_global->ttyo);
3336 #endif
3338 dprint((7, "goodnight_gracey: close config files\n"));
3340 free_pinerc_strings(&pine_state);
3342 strncpy(msg, pf, sizeof(msg));
3343 msg[sizeof(msg)-1] = '\0';
3344 if(final_msg){
3345 strncat(msg, " -- ", sizeof(msg)-strlen(msg)-1);
3346 msg[sizeof(msg)-1] = '\0';
3347 strncat(msg, final_msg, sizeof(msg)-strlen(msg)-1);
3348 msg[sizeof(msg)-1] = '\0';
3349 fs_give((void **)&final_msg);
3352 dprint((7, "goodnight_gracey: sp_end\n"));
3353 ps_global->noshow_error = 1;
3354 sp_end();
3356 #ifdef SMIME
3357 smime_deinit();
3358 #endif
3360 /* after sp_end, which might call a filter */
3361 completely_done_with_adrbks();
3363 dprint((7, "goodnight_gracey: end_screen\n"));
3364 end_screen(msg, exit_val);
3365 dprint((7, "goodnight_gracey: end_titlebar\n"));
3366 end_titlebar();
3367 dprint((7, "goodnight_gracey: end_keymenu\n"));
3368 end_keymenu();
3370 dprint((7, "goodnight_gracey: end_keyboard\n"));
3371 end_keyboard(F_ON(F_USE_FK,pine_state));
3372 dprint((7, "goodnight_gracey: end_ttydriver\n"));
3373 end_tty_driver(pine_state);
3374 #if !defined(DOS) && !defined(OS2)
3375 kbdestroy(kbesc);
3376 #if !defined(LEAVEOUTFIFO)
3377 close_newmailfifo();
3378 #endif
3379 #endif
3380 end_signals(0);
3381 if(filter_data_file(0))
3382 our_unlink(filter_data_file(0));
3384 imap_flush_passwd_cache(TRUE);
3385 free_newsgrp_cache();
3386 mailcap_free();
3387 close_every_pattern();
3388 free_extra_hdrs();
3389 free_contexts(&ps_global->context_list);
3390 free_charsetchecker();
3391 dprint((7, "goodnight_gracey: free more memory\n"));
3392 #ifdef ENABLE_LDAP
3393 free_saved_query_parameters();
3394 #endif
3396 html_dir_clean(1); /* force remove of remaining files */
3397 free_pine_struct(&pine_state);
3399 free_histlist();
3401 free_alpine_module_globals(); /* should we have module globals? */
3402 free_pith_module_globals();
3403 free_pico_module_globals();
3404 free_c_client_module_globals();
3406 #ifdef DEBUG
3407 if(debugfile){
3408 if(debug >= 2)
3409 fputs("goodnight_gracey finished\n", debugfile);
3411 fclose(debugfile);
3413 #endif
3415 exit(exit_val);
3419 /*----------------------------------------------------------------------
3420 Call back for c-client to feed us back the progress of network reads
3422 Input:
3424 Result:
3425 ----*/
3426 void
3427 pine_read_progress(GETS_DATA *md, long unsigned int count)
3429 gets_bytes += count; /* update counter */
3433 /*----------------------------------------------------------------------
3434 Function to fish the current byte count from a c-client fetch.
3436 Input: reset -- flag telling us to reset the count
3438 Result: Returns the number of bytes read by the c-client so far
3439 ----*/
3440 unsigned long
3441 pine_gets_bytes(int reset)
3443 if(reset)
3444 gets_bytes = 0L;
3446 return(gets_bytes);
3450 /*----------------------------------------------------------------------
3451 Panic pine - call on detected programmatic errors to exit pine
3453 Args: message -- message to record in debug file and to be printed for user
3455 Result: The various tty modes are restored
3456 If debugging is active a core dump will be generated
3457 Exits Alpine
3459 This is also called from imap routines and fs_get and fs_resize.
3460 ----*/
3461 void
3462 alpine_panic(char *message)
3464 char buf[256];
3466 /* global variable in .../pico/edef.h */
3467 in_panic = 1;
3469 if(ps_global->ttyo){
3470 end_screen(NULL, -1);
3471 end_keyboard(ps_global != NULL ? F_ON(F_USE_FK,ps_global) : 0);
3472 end_tty_driver(ps_global);
3473 end_signals(1);
3475 if(filter_data_file(0))
3476 our_unlink(filter_data_file(0));
3478 dprint((1, "\n===========================================\n\n"));
3479 dprint((1, " Alpine Panic: %s\n\n", message ? message : "?"));
3480 dprint((1, "===========================================\n\n"));
3482 /* intercept c-client "free storage" errors */
3483 if(strstr(message, "free storage"))
3484 snprintf(buf, sizeof(buf), _("No more available memory.\nAlpine Exiting"));
3485 else
3486 snprintf(buf, sizeof(buf), _("Problem detected: \"%s\".\nAlpine Exiting."), message);
3488 buf[sizeof(buf)-1] = '\0';
3490 #ifdef _WINDOWS
3491 /* Put up a message box. */
3492 mswin_messagebox (buf, 1);
3493 #else
3494 fprintf(stderr, "\n\n%s\n", buf);
3495 #endif
3497 #ifdef DEBUG
3498 if(debugfile){
3499 save_debug_on_crash(debugfile, recent_keystroke);
3502 coredump(); /*--- If we're debugging get a core dump --*/
3503 #endif
3505 exit(-1);
3506 fatal("ffo"); /* BUG -- hack to get fatal out of library in right order*/
3511 * panicking - function to test whether or not we're exiting under stress.
3515 panicking(void)
3517 return(in_panic);
3521 /*----------------------------------------------------------------------
3522 exceptional_exit - called to exit under unusual conditions (with no core)
3524 Args: message -- message to record in debug file and to be printed for user
3525 ev -- exit value
3527 ----*/
3528 void
3529 exceptional_exit(char *message, int ev)
3531 fprintf(stderr, "%s\n", message);
3532 exit(ev);
3537 * PicoText Storage Object Support Routines
3540 STORE_S *
3541 pine_pico_get(void)
3543 return((STORE_S *)pico_get());
3547 pine_pico_give(STORE_S **sop)
3549 pico_give((void *)sop);
3550 return(1);
3554 pine_pico_writec(int c, STORE_S *so)
3556 unsigned char ch = (unsigned char) c;
3558 return(pico_writec(so->txt, ch, PICOREADC_NONE));
3562 pine_pico_writec_noucs(int c, STORE_S *so)
3564 unsigned char ch = (unsigned char) c;
3566 return(pico_writec(so->txt, ch, PICOREADC_NOUCS));
3570 pine_pico_readc(unsigned char *c, STORE_S *so)
3572 return(pico_readc(so->txt, c, PICOREADC_NONE));
3576 pine_pico_readc_noucs(unsigned char *c, STORE_S *so)
3578 return(pico_readc(so->txt, c, PICOREADC_NOUCS));
3582 pine_pico_puts(STORE_S *so, char *s)
3584 return(pico_puts(so->txt, s, PICOREADC_NONE));
3588 pine_pico_puts_noucs(STORE_S *so, char *s)
3590 return(pico_puts(so->txt, s, PICOREADC_NOUCS));
3594 pine_pico_seek(STORE_S *so, long pos, int orig)
3596 return(pico_seek((void *)so, pos, orig));
3601 remote_pinerc_failure(void)
3603 #ifdef _WINDOWS
3604 if(ps_global->install_flag) /* just exit silently */
3605 exit(0);
3606 #endif /* _WINDOWS */
3608 if(ps_global->exit_if_no_pinerc){
3609 exceptional_exit("Exiting because -bail option is set and config file not readable.", -1);
3612 if(want_to("Trouble reading remote configuration! Continue anyway ",
3613 'n', 'n', NO_HELP, WT_FLUSH_IN) != 'y'){
3614 return(0);
3617 return(1);
3621 void
3622 dump_supported_options(void)
3624 char **config;
3626 config = get_supported_options();
3627 if(config){
3628 display_args_err(NULL, config, 0);
3629 free_list_array(&config);
3634 /*----------------------------------------------------------------------
3635 Check pruned-folders for validity, making sure they are in the
3636 same context as sent-mail.
3638 ----*/
3640 prune_folders_ok(void)
3642 char **p;
3644 for(p = ps_global->VAR_PRUNED_FOLDERS; p && *p && **p; p++)
3645 if(!context_isambig(*p))
3646 return(0);
3648 return(1);
3651 void
3652 free_alpine_module_globals(void)
3654 #ifdef LOCAL_PASSWD_CACHE
3655 free_passfile_cache();
3656 #endif
3657 free_message_queue();
3658 free_titlebar_globals();
3661 #ifdef WIN32
3662 char *
3663 pine_user_callback()
3665 if(ps_global->VAR_USER_ID && ps_global->VAR_USER_ID[0]){
3666 return(ps_global->VAR_USER_ID);
3668 else{
3669 /* SHOULD PROMPT HERE! */
3670 return(NULL);
3673 #endif
3675 #ifdef _WINDOWS
3677 * windows callback to get/set function keys mode state
3680 fkey_mode_callback(set, args)
3681 int set;
3682 long args;
3684 return(F_ON(F_USE_FK, ps_global) != 0);
3688 void
3689 imap_telemetry_on()
3691 if(ps_global->mail_stream)
3692 mail_debug(ps_global->mail_stream);
3696 void
3697 imap_telemetry_off()
3699 if(ps_global->mail_stream)
3700 mail_nodebug(ps_global->mail_stream);
3704 char *
3705 pcpine_help_main(title)
3706 char *title;
3708 if(title)
3709 strncpy(title, _("PC-Alpine MAIN MENU Help"), 256);
3711 return(pcpine_help(main_menu_tx));
3716 pcpine_main_cursor(col, row)
3717 int col;
3718 long row;
3720 unsigned ndmi;
3722 if (row >= (HEADER_ROWS(ps_global) + MNSKIP(ps_global)))
3723 ndmi = (row+1 - HEADER_ROWS(ps_global) - (MNSKIP(ps_global)+1))/(MNSKIP(ps_global)+1);
3725 if (row >= (HEADER_ROWS(ps_global) + MNSKIP(ps_global))
3726 && !(MNSKIP(ps_global) && (row+1) & 0x01)
3727 && ndmi <= MAX_MENU_ITEM
3728 && FOOTER_ROWS(ps_global) + (ndmi+1)*(MNSKIP(ps_global)+1)
3729 + MNSKIP(ps_global) + FOOTER_ROWS(ps_global) <= ps_global->ttyo->screen_rows)
3730 return(MSWIN_CURSOR_HAND);
3731 else
3732 return(MSWIN_CURSOR_ARROW);
3734 #endif /* _WINDOWS */