* Remove some compilation warnings given by clang7.
[alpine.git] / alpine / alpine.c
blob8155f54af6941d7e5fa0276652a0ed052ea2bc90
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);
348 init_pinerc(pine_state, &init_pinerc_debugging);
350 #ifdef DEBUG
351 /* Since this is specific debugging we don't mind if the
352 ifdef is the type of system.
354 #if defined(HAVE_SMALLOC) || defined(NXT)
355 if(ps_global->debug_malloc)
356 malloc_debug(ps_global->debug_malloc);
357 #endif
358 #ifdef CSRIMALLOC
359 if(ps_global->debug_malloc)
360 mal_debug(ps_global->debug_malloc);
361 #endif
363 if(!ps_global->convert_sigs
364 #ifdef _WINDOWS
365 && !ps_global->install_flag
366 #endif /* _WINDOWS */
368 init_debug();
370 if(args_for_debug){
371 dprint((0, " %s (PID=%ld)\n\n", args_for_debug,
372 (long) getpid()));
373 fs_give((void **)&args_for_debug);
377 char *env_to_free;
378 if((env_to_free = our_getenv("HOME")) != NULL){
379 dprint((2, "Setting home dir from $HOME: \"%s\"\n",
380 env_to_free));
381 fs_give((void **)&env_to_free);
383 else{
384 dprint((2, "Setting home dir: \"%s\"\n",
385 pine_state->home_dir ? pine_state->home_dir : "<?>"));
389 /* Watch out. Sensitive information in debug file. */
390 if(ps_global->debug_imap > 4)
391 mail_parameters(NULL, SET_DEBUGSENSITIVE, (void *) TRUE);
393 #ifndef DEBUGJOURNAL
394 if(ps_global->debug_tcp)
395 #endif
396 mail_parameters(NULL, SET_TCPDEBUG, (void *) TRUE);
398 #ifdef _WINDOWS
399 mswin_setdebug(debug, debugfile);
400 mswin_setdebugoncallback (imap_telemetry_on);
401 mswin_setdebugoffcallback (imap_telemetry_off);
402 mswin_enableimaptelemetry(ps_global->debug_imap != 0);
403 #endif
404 #endif /* DEBUG */
406 #ifdef _WINDOWS
407 mswin_setsortcallback(index_sort_callback);
408 mswin_setflagcallback(flag_callback);
409 mswin_sethdrmodecallback(header_mode_callback);
410 mswin_setselectedcallback(any_selected_callback);
411 mswin_setzoomodecallback(zoom_mode_callback);
412 mswin_setfkeymodecallback(fkey_mode_callback);
413 #endif
415 /*------- Set up c-client drivers -------*/
416 #include "../c-client/linkage.c"
418 /*------- ... then tune the drivers just installed -------*/
419 #ifdef _WINDOWS
420 if(_tgetenv(TEXT("HOME")))
421 mail_parameters(NULL, SET_HOMEDIR, (void *) pine_state->home_dir);
423 mail_parameters(NULL, SET_USERPROMPT, (void *) pine_user_callback);
426 * Sniff the environment for timezone offset. We need to do this
427 * here since Windows needs help figuring out UTC, and will adjust
428 * what time() returns based on TZ. THIS WILL SCREW US because
429 * we use time() differences to manage status messages. So, if
430 * rfc822_date, which calls localtime() and thus needs tzset(),
431 * is called while a status message is displayed, it's possible
432 * for time() to return a time *before* what we remember as the
433 * time we put the status message on the display. Sheesh.
435 tzset();
436 #else /* !_WINDOWS */
438 * We used to let c-client do this for us automatically, but it declines
439 * to do so for root. This forces c-client to establish an environment,
440 * even if the uid is 0.
442 env_init(ps_global->ui.login, ps_global->ui.homedir);
445 * Install callback to let us know the progress of network reads...
447 (void) mail_parameters(NULL, SET_READPROGRESS, (void *)pine_read_progress);
448 #endif /* !_WINDOWS */
451 * Install callback to handle certificate validation failures,
452 * allowing the user to continue if they wish.
454 mail_parameters(NULL, SET_SSLCERTIFICATEQUERY, (void *) pine_sslcertquery);
455 mail_parameters(NULL, SET_SSLFAILURE, (void *) pine_sslfailure);
457 if(init_pinerc_debugging){
458 dprint((2, "%s", init_pinerc_debugging));
459 fs_give((void **)&init_pinerc_debugging);
463 * Initial allocation of array of stream pool pointers.
464 * We do this before init_vars so that we can re-use streams used for
465 * remote config files. These sizes may get changed later.
467 ps_global->s_pool.max_remstream = 2;
468 dprint((9,
469 "Setting initial max_remstream to %d for remote config re-use\n",
470 ps_global->s_pool.max_remstream));
472 init_vars(pine_state, process_init_cmds);
474 #if !defined(_WINDOWS) || defined(WINDOWS_LIBRESSL_CERTS)
475 set_system_certs_path(pine_state);
476 set_system_certs_container(pine_state);
477 #endif
479 #ifdef SMIME
480 if(F_ON(F_DONT_DO_SMIME, ps_global))
481 smime_deinit();
482 #endif /* SMIME */
484 #ifdef ENABLE_NLS
486 * LC_CTYPE is already set from the set_collation call above.
488 * We can't use gettext calls before we do this stuff so it doesn't
489 * help to translate strings that come before this in the program.
490 * Maybe we could rearrange things to accommodate that.
492 setlocale(LC_MESSAGES, "");
493 bindtextdomain(PACKAGE, LOCALEDIR);
494 bind_textdomain_codeset(PACKAGE, "UTF-8");
495 textdomain(PACKAGE);
496 #endif /* ENABLE_NLS */
498 convert_args_to_utf8(pine_state, &args);
500 if(args.action == aaFolder){
501 pine_state->beginning_of_month = first_run_of_month();
502 pine_state->beginning_of_year = first_run_of_year();
505 /* Set up optional for user-defined display filtering */
506 pine_state->tools.display_filter = dfilter;
507 pine_state->tools.display_filter_trigger = dfilter_trigger;
509 #ifdef _WINDOWS
510 if(ps_global->install_flag){
511 init_install_get_vars();
513 if(ps_global->prc)
514 free_pinerc_s(&ps_global->prc);
516 exit(0);
518 #endif
520 if(ps_global->convert_sigs){
521 if(convert_sigs_to_literal(ps_global, 0) == -1){
522 /* TRANSLATORS: sigs refers to signatures, which the user was trying to convert */
523 fprintf(stderr, _("trouble converting sigs\n"));
524 exit(-1);
527 if(ps_global->prc){
528 if(ps_global->prc->outstanding_pinerc_changes)
529 write_pinerc(ps_global, Main, WRP_NONE);
531 free_pinerc_s(&pine_state->prc);
534 exit(0);
538 * Set up a c-client read timeout and timeout handler. In general,
539 * it shouldn't happen, but a server crash or dead link can cause
540 * pine to appear wedged if we don't set this up...
542 rv = 30;
543 if(pine_state->VAR_TCPOPENTIMEO)
544 (void)SVAR_TCP_OPEN(pine_state, rv, tmp_20k_buf, SIZEOF_20KBUF);
545 mail_parameters(NULL, SET_OPENTIMEOUT, (void *)(long)rv);
547 rv = 15;
548 if(pine_state->VAR_TCPREADWARNTIMEO)
549 (void)SVAR_TCP_READWARN(pine_state, rv, tmp_20k_buf, SIZEOF_20KBUF);
550 mail_parameters(NULL, SET_READTIMEOUT, (void *)(long)rv);
552 rv = 0;
553 if(pine_state->VAR_TCPWRITEWARNTIMEO){
554 if(!SVAR_TCP_WRITEWARN(pine_state, rv, tmp_20k_buf, SIZEOF_20KBUF))
555 if(rv == 0 || rv > 4) /* making sure */
556 mail_parameters(NULL, SET_WRITETIMEOUT, (void *)(long)rv);
559 mail_parameters(NULL, SET_TIMEOUT, (void *) pine_tcptimeout);
561 rv = 15;
562 if(pine_state->VAR_RSHOPENTIMEO){
563 if(!SVAR_RSH_OPEN(pine_state, rv, tmp_20k_buf, SIZEOF_20KBUF))
564 if(rv == 0 || rv > 4) /* making sure */
565 mail_parameters(NULL, SET_RSHTIMEOUT, (void *)(long)rv);
568 rv = 15;
569 if(pine_state->VAR_SSHOPENTIMEO){
570 if(!SVAR_SSH_OPEN(pine_state, rv, tmp_20k_buf, SIZEOF_20KBUF))
571 if(rv == 0 || rv > 4) /* making sure */
572 mail_parameters(NULL, SET_SSHTIMEOUT, (void *)(long)rv);
575 rvl = 60L;
576 if(pine_state->VAR_MAILDROPCHECK){
577 if(!SVAR_MAILDCHK(pine_state, rvl, tmp_20k_buf, SIZEOF_20KBUF)){
578 if(rvl == 0L)
579 rvl = (60L * 60L * 24L * 100L); /* 100 days */
581 if(rvl >= 60L) /* making sure */
582 mail_parameters(NULL, SET_SNARFINTERVAL, (void *) rvl);
587 * Lookups of long login names which don't exist are very slow in aix.
588 * This would normally get set in system-wide config if not needed.
590 if(F_ON(F_DISABLE_SHARED_NAMESPACES, ps_global))
591 mail_parameters(NULL, SET_DISABLEAUTOSHAREDNS, (void *) TRUE);
593 if(F_ON(F_HIDE_NNTP_PATH, ps_global))
594 mail_parameters(NULL, SET_NNTPHIDEPATH, (void *) TRUE);
596 if(F_ON(F_MAILDROPS_PRESERVE_STATE, ps_global))
597 mail_parameters(NULL, SET_SNARFPRESERVE, (void *) TRUE);
599 rvl = 0L;
600 if(pine_state->VAR_NNTPRANGE){
601 if(!SVAR_NNTPRANGE(pine_state, rvl, tmp_20k_buf, SIZEOF_20KBUF))
602 if(rvl > 0L)
603 mail_parameters(NULL, SET_NNTPRANGE, (void *) rvl);
607 * Tell c-client not to be so aggressive about uid mappings
609 mail_parameters(NULL, SET_UIDLOOKAHEAD, (void *) 20);
612 * Setup referral handling
614 mail_parameters(NULL, SET_IMAPREFERRAL, (void *) imap_referral);
615 mail_parameters(NULL, SET_MAILPROXYCOPY, (void *) imap_proxycopy);
618 * Setup multiple newsrc transition
620 mail_parameters(NULL, SET_NEWSRCQUERY, (void *) pine_newsrcquery);
623 * Disable some drivers if requested.
625 if(ps_global->VAR_DISABLE_DRIVERS &&
626 ps_global->VAR_DISABLE_DRIVERS[0] &&
627 ps_global->VAR_DISABLE_DRIVERS[0][0]){
628 char **t;
630 for(t = ps_global->VAR_DISABLE_DRIVERS; t[0] && t[0][0]; t++)
631 if(mail_parameters(NULL, DISABLE_DRIVER, (void *)(*t))){
632 dprint((2, "Disabled mail driver \"%s\"\n", *t));
634 else{
635 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
636 _("Failed to disable mail driver \"%s\": name not found"),
637 *t);
638 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
639 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
644 * Disable some authenticators if requested.
646 if(ps_global->VAR_DISABLE_AUTHS &&
647 ps_global->VAR_DISABLE_AUTHS[0] &&
648 ps_global->VAR_DISABLE_AUTHS[0][0]){
649 char **t;
651 for(t = ps_global->VAR_DISABLE_AUTHS; t[0] && t[0][0]; t++)
652 if(mail_parameters(NULL, DISABLE_AUTHENTICATOR, (void *)(*t))){
653 dprint((2,"Disabled SASL authenticator \"%s\"\n", *t));
655 else{
656 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
657 _("Failed to disable SASL authenticator \"%s\": name not found"),
658 *t);
659 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
660 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
664 #ifdef DF_ENCRYPTION_RANGE
665 if(ps_global->VAR_ENCRYPTION_RANGE
666 && ps_global->VAR_ENCRYPTION_RANGE[0]){
667 char *min_s, *max_s, *s;
668 int min_v, max_v;
670 if((s = strchr(ps_global->VAR_ENCRYPTION_RANGE, ',')) == NULL){
671 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
672 _("Bad encryption range: \"%s\": resetting to default"),
673 ps_global->VAR_ENCRYPTION_RANGE);
674 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
675 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
676 fs_give((void **) &ps_global->VAR_ENCRYPTION_RANGE);
677 ps_global->VAR_ENCRYPTION_RANGE = cpystr(DF_ENCRYPTION_RANGE);
678 s = strchr(ps_global->VAR_ENCRYPTION_RANGE, ','); /* try again */
681 if(s == NULL){
682 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
683 _("Bad default encryption range: \"%s\""),
684 ps_global->VAR_ENCRYPTION_RANGE);
685 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
686 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
688 else {
689 *s = ' ';
690 get_pair(ps_global->VAR_ENCRYPTION_RANGE, &min_s, &max_s, 1, 0);
691 *s = ',';
693 min_v = pith_ssl_encryption_version(min_s);
694 max_v = pith_ssl_encryption_version(max_s);
696 if(min_v < 0 || max_v < 0){
697 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
698 _("Bad encryption range: \"%s\": resetting to default"),
699 ps_global->VAR_ENCRYPTION_RANGE);
700 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
701 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
702 min_v = max_v = 0;
705 if(min_v > max_v){
706 int bubble;
707 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
708 _("Minimum encryption protocol (%s) bigger than maximum value (%s). Reversing..."),
709 min_s, max_s);
710 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
711 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
712 bubble = min_v;
713 min_v = max_v;
714 max_v = bubble;
717 if(max_v > 0 && max_v < (long) pith_ssl_encryption_version("tls1")){
718 strncpy(tmp_20k_buf, _("Security alert: SSL maximum encryption version was set to SSLv3."), SIZEOF_20KBUF);
719 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
720 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
723 mail_parameters(NULL, SET_ENCRYPTION_RANGE_MIN, (void *) &min_v);
724 mail_parameters(NULL, SET_ENCRYPTION_RANGE_MAX, (void *) &max_v);
727 #endif /* DF_ENCRYPTION_RANGE */
730 * setup alternative authentication driver preference for IMAP opens
732 if(F_ON(F_PREFER_ALT_AUTH, ps_global))
733 mail_parameters(NULL, SET_IMAPTRYALT, (void *) TRUE);
736 * Install handler to let us know about potential delays
738 (void) mail_parameters(NULL, SET_BLOCKNOTIFY, (void *) pine_block_notify);
740 if(ps_global->dump_supported_options){
741 dump_supported_options();
742 exit(0);
746 * Install extra headers to fetch along with all the other stuff
747 * mail_fetch_structure and mail_fetch_overview requests.
749 calc_extra_hdrs();
750 if(get_extra_hdrs())
751 (void) mail_parameters(NULL, SET_IMAPEXTRAHEADERS,
752 (void *) get_extra_hdrs());
754 if(init_username(pine_state) < 0){
755 fprintf(stderr, _("Who are you? (Unable to look up login name)\n"));
756 exit(-1);
759 if(init_userdir(pine_state) < 0)
760 exit(-1);
762 if(init_hostname(pine_state) < 0)
763 exit(-1);
766 * Verify mail dir if we're not in send only mode...
768 if(args.action == aaFolder && init_mail_dir(pine_state) < 0)
769 exit(-1);
771 init_signals();
773 /*--- input side ---*/
774 if(init_tty_driver(pine_state)){
775 #ifndef _WINDOWS /* always succeeds under _WINDOWS */
776 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);
777 exit(-1);
778 #endif /* !_WINDOWS */
782 /*--- output side ---*/
783 rv = config_screen(&(pine_state->ttyo));
784 #ifndef _WINDOWS /* always succeeds under _WINDOWS */
785 if(rv){
786 switch(rv){
787 case -1:
788 printf(_("Terminal type (environment variable TERM) not set.\n"));
789 break;
790 case -2:
791 printf(_("Terminal type \"%s\" is unknown.\n"), getenv("TERM"));
792 break;
793 case -3:
794 printf(_("Can't open terminal capabilities database.\n"));
795 break;
796 case -4:
797 printf(_("Your terminal, of type \"%s\", is lacking functions needed to run alpine.\n"), getenv("TERM"));
798 break;
801 printf("\r");
802 end_tty_driver(pine_state);
803 exit(-1);
805 #endif /* !_WINDOWS */
807 if(F_ON(F_BLANK_KEYMENU,ps_global))
808 FOOTER_ROWS(ps_global) = 1;
810 init_screen();
811 init_keyboard(pine_state->orig_use_fkeys);
812 strncpy(pine_state->inbox_name, INBOX_NAME,
813 sizeof(pine_state->inbox_name)-1);
814 init_folders(pine_state); /* digest folder spec's */
816 pine_state->in_init_seq = 0; /* so output (& ClearScreen) show up */
817 pine_state->dont_use_init_cmds = 1; /* don't use up initial_commands yet */
818 ClearScreen();
820 /* initialize titlebar in case we use it */
821 set_titlebar("", NULL, NULL, NULL, NULL, 0, FolderName, 0, 0, NULL);
824 * Prep storage object driver for PicoText
826 so_register_external_driver(pine_pico_get, pine_pico_give, pine_pico_writec, pine_pico_readc,
827 pine_pico_puts, pine_pico_seek, NULL, NULL);
829 #ifdef DEBUG
830 if(ps_global->debug_imap > 4 || debug > 9){
831 q_status_message(SM_ORDER | SM_DING, 5, 9,
832 _("Warning: sensitive authentication data included in debug file"));
833 flush_status_messages(0);
835 #endif
837 if(args.action == aaPrcCopy || args.action == aaAbookCopy){
838 int exit_val = -1;
839 char *err_msg = NULL;
842 * Don't translate these into UTF-8 because we'll be using them
843 * before we translate next time. User should use ascii.
845 if(args.data.copy.local && args.data.copy.remote){
846 switch(args.action){
847 case aaPrcCopy:
848 exit_val = copy_pinerc(args.data.copy.local,
849 args.data.copy.remote, &err_msg);
850 break;
852 case aaAbookCopy:
853 exit_val = copy_abook(args.data.copy.local,
854 args.data.copy.remote, &err_msg);
855 break;
857 default:
858 break;
861 if(err_msg){
862 q_status_message(SM_ORDER | SM_DING, 3, 4, err_msg);
863 fs_give((void **)&err_msg);
865 goodnight_gracey(pine_state, exit_val);
868 if(args.action == aaFolder
869 && (pine_state->first_time_user || pine_state->show_new_version)){
870 pine_state->mangled_header = 1;
871 show_main_screen(pine_state, 0, FirstMenu, &main_keymenu, 0,
872 (Pos *) NULL);
873 new_user_or_version(pine_state);
874 ClearScreen();
877 /* put back in case we need to suppress output */
878 pine_state->in_init_seq = pine_state->save_in_init_seq;
880 /* queue any init errors so they get displayed in a screen below */
881 queue_init_errors(ps_global);
883 /* "Page" the given file? */
884 if(args.action == aaMore){
885 int dice = 1, redir = 0;
887 if(pine_state->in_init_seq){
888 pine_state->in_init_seq = pine_state->save_in_init_seq = 0;
889 clear_cursor_pos();
890 if(pine_state->free_initial_cmds)
891 fs_give((void **)&(pine_state->free_initial_cmds));
893 pine_state->initial_cmds = NULL;
896 /*======= Requested that we simply page the given file =======*/
897 if(args.data.file){ /* Open the requested file... */
898 SourceType src;
899 STORE_S *store = NULL;
900 char *decode_error = NULL;
901 char filename[MAILTMPLEN];
903 if(args.data.file[0] == '\0'){
904 HelpType help = NO_HELP;
906 pine_state->mangled_footer = 1;
907 filename[0] = '\0';
908 while(1){
909 int flags = OE_APPEND_CURRENT;
911 rv = optionally_enter(filename, -FOOTER_ROWS(pine_state),
912 0, sizeof(filename),
913 /* TRANSLATORS: file is computer data */
914 _("File to open : "),
915 NULL, help, &flags);
916 if(rv == 3){
917 help = (help == NO_HELP) ? h_no_F_arg : NO_HELP;
918 continue;
921 if(rv != 4)
922 break;
925 if(rv == 1){
926 q_status_message(SM_ORDER, 0, 2, _("Cancelled"));
927 goodnight_gracey(pine_state, -1);
930 if(*filename){
931 removing_trailing_white_space(filename);
932 removing_leading_white_space(filename);
933 if(is_absolute_path(filename))
934 fnexpand(filename, sizeof(filename));
936 args.data.file = filename;
939 if(!*filename){
940 /* TRANSLATORS: file is computer data */
941 q_status_message(SM_ORDER, 0, 2 ,_("No file to open"));
942 goodnight_gracey(pine_state, -1);
946 if(stdin_getc){
947 redir++;
948 src = CharStar;
949 if(isatty(0) && (store = so_get(src, NULL, EDIT_ACCESS))){
950 gf_io_t pc;
952 gf_set_so_writec(&pc, store);
953 gf_filter_init();
954 if((decode_error = gf_pipe(stdin_getc, pc)) != NULL){
955 dice = 0;
956 q_status_message1(SM_ORDER, 3, 4,
957 _("Problem reading standard input: %s"),
958 decode_error);
961 gf_clear_so_writec(store);
963 else
964 dice = 0;
966 else{
967 src = FileStar;
968 strncpy(ps_global->cur_folder, args.data.file,
969 sizeof(ps_global->cur_folder)-1);
970 ps_global->cur_folder[sizeof(ps_global->cur_folder)-1] = '\0';
971 if(!(store = so_get(src, args.data.file, READ_ACCESS|READ_FROM_LOCALE)))
972 dice = 0;
975 if(dice){
976 SCROLL_S sargs;
978 memset(&sargs, 0, sizeof(SCROLL_S));
979 sargs.text.text = so_text(store);
980 sargs.text.src = src;
981 /* TRANSLATORS: file is computer file being read by user */
982 sargs.text.desc = _("file");
983 /* TRANSLATORS: this is in the title bar at top of screen */
984 sargs.bar.title = _("FILE VIEW");
985 sargs.bar.style = FileTextPercent;
986 sargs.keys.menu = &simple_file_keymenu;
987 setbitmap(sargs.keys.bitmap);
988 scrolltool(&sargs);
990 printf("\n\n");
991 so_give(&store);
995 if(!dice){
996 q_status_message2(SM_ORDER, 3, 4,
997 _("Can't display \"%s\": %s"),
998 (redir) ? _("Standard Input")
999 : args.data.file ? args.data.file : "NULL",
1000 error_description(errno));
1003 goodnight_gracey(pine_state, 0);
1005 else if(args.action == aaMail || (stdin_getc && (args.action != aaURL))){
1006 /*======= address on command line/send one message mode ============*/
1007 char *to = NULL, *error = NULL, *addr = NULL;
1008 int len, good_addr = 1;
1009 int exit_val = 0;
1010 BUILDER_ARG fcc;
1012 if(pine_state->in_init_seq){
1013 pine_state->in_init_seq = pine_state->save_in_init_seq = 0;
1014 clear_cursor_pos();
1015 if(pine_state->free_initial_cmds)
1016 fs_give((void **) &(pine_state->free_initial_cmds));
1018 pine_state->initial_cmds = NULL;
1021 /*----- Format the To: line with commas for the composer ---*/
1022 if(args.data.mail.addrlist){
1023 STRLIST_S *p;
1025 for(p = args.data.mail.addrlist, len = 0; p; p = p->next)
1026 len += strlen(p->name) + 2;
1028 to = (char *) fs_get((len + 5) * sizeof(char));
1029 for(p = args.data.mail.addrlist, *to = '\0'; p; p = p->next){
1030 if(*to){
1031 strncat(to, ", ", len+5-strlen(to)-1);
1032 to[len+5-1] = '\0';
1035 strncat(to, p->name, len+5-strlen(to)-1);
1036 to[len+5-1] = '\0';
1039 memset((void *)&fcc, 0, sizeof(BUILDER_ARG));
1040 dprint((2, "building addr: -->%s<--\n", to ? to : "?"));
1041 good_addr = (build_address(to, &addr, &error, &fcc, NULL) >= 0);
1042 dprint((2, "mailing to: -->%s<--\n", addr ? addr : "?"));
1043 free_strlist(&args.data.mail.addrlist);
1045 else
1046 memset(&fcc, 0, sizeof(fcc));
1048 if(good_addr){
1049 compose_mail(addr, fcc.tptr, NULL,
1050 args.data.mail.attachlist, stdin_getc);
1052 else{
1053 /* TRANSLATORS: refers to bad email address */
1054 q_status_message1(SM_ORDER, 3, 4, _("Bad address: %s"), error);
1055 exit_val = -1;
1058 if(addr)
1059 fs_give((void **) &addr);
1061 if(fcc.tptr)
1062 fs_give((void **) &fcc.tptr);
1064 if(args.data.mail.attachlist)
1065 free_attachment_list(&args.data.mail.attachlist);
1067 if(to)
1068 fs_give((void **) &to);
1070 if(error)
1071 fs_give((void **) &error);
1073 goodnight_gracey(pine_state, exit_val);
1075 else{
1076 char int_mail[MAXPATH+1];
1077 struct key_menu *km = &main_keymenu;
1079 /*========== Normal pine mail reading mode ==========*/
1081 pine_state->mail_stream = NULL;
1082 pine_state->mangled_screen = 1;
1084 if(args.action == aaURL){
1085 url_tool_t f;
1087 if(pine_state->in_init_seq){
1088 pine_state->in_init_seq = pine_state->save_in_init_seq = 0;
1089 clear_cursor_pos();
1090 if(pine_state->free_initial_cmds)
1091 fs_give((void **) &(pine_state->free_initial_cmds));
1092 pine_state->initial_cmds = NULL;
1094 if((f = url_local_handler(args.url)) != NULL){
1095 if(args.data.mail.attachlist){
1096 if(f == url_local_mailto){
1097 if(!(url_local_mailto_and_atts(args.url,
1098 args.data.mail.attachlist)
1099 && pine_state->next_screen))
1100 free_attachment_list(&args.data.mail.attachlist);
1101 goodnight_gracey(pine_state, 0);
1103 else {
1104 q_status_message(SM_ORDER | SM_DING, 3, 4,
1105 _("Only mailto URLs are allowed with file attachments"));
1106 goodnight_gracey(pine_state, -1); /* no return */
1109 else if(!((*f)(args.url) && pine_state->next_screen))
1110 goodnight_gracey(pine_state, 0); /* no return */
1112 else{
1113 q_status_message1(SM_ORDER | SM_DING, 3, 4,
1114 _("Unrecognized URL \"%s\""), args.url);
1115 goodnight_gracey(pine_state, -1); /* no return */
1118 else if(!pine_state->start_in_index){
1119 /* flash message about executing initial commands */
1120 if(pine_state->in_init_seq){
1121 pine_state->in_init_seq = 0;
1122 clear_cursor_pos();
1123 pine_state->mangled_header = 1;
1124 pine_state->mangled_footer = 1;
1125 pine_state->mangled_screen = 0;
1126 /* show that this is Alpine */
1127 show_main_screen(pine_state, 0, FirstMenu, km, 0, (Pos *)NULL);
1128 pine_state->mangled_screen = 1;
1129 pine_state->painted_footer_on_startup = 1;
1130 if(MIN(4, pine_state->ttyo->screen_rows - 4) > 1){
1131 char buf1[6*MAX_SCREEN_COLS+1];
1132 char buf2[6*MAX_SCREEN_COLS+1];
1133 int wid;
1135 /* TRANSLATORS: Initial Keystroke List is the literal name of an option */
1136 strncpy(buf1, _("Executing Initial Keystroke List......"), sizeof(buf1));
1137 buf1[sizeof(buf1)-1] = '\0';
1138 wid = utf8_width(buf1);
1139 if(wid > ps_global->ttyo->screen_cols){
1140 utf8_pad_to_width(buf2, buf1, sizeof(buf2), ps_global->ttyo->screen_cols, 1);
1141 PutLine0(MIN(4, pine_state->ttyo->screen_rows - 4), 0, buf2);
1143 else{
1144 PutLine0(MIN(4, pine_state->ttyo->screen_rows - 4),
1145 MAX(MIN(11, pine_state->ttyo->screen_cols - wid), 0), buf1);
1149 pine_state->in_init_seq = 1;
1151 else{
1152 show_main_screen(pine_state, 0, FirstMenu, km, 0, (Pos *)NULL);
1153 pine_state->painted_body_on_startup = 1;
1154 pine_state->painted_footer_on_startup = 1;
1157 else{
1158 /* cancel any initial commands, overridden by cmd line */
1159 if(pine_state->in_init_seq){
1160 pine_state->in_init_seq = 0;
1161 pine_state->save_in_init_seq = 0;
1162 clear_cursor_pos();
1163 if(pine_state->initial_cmds){
1164 if(pine_state->free_initial_cmds)
1165 fs_give((void **)&(pine_state->free_initial_cmds));
1167 pine_state->initial_cmds = NULL;
1170 F_SET(F_USE_FK,pine_state, pine_state->orig_use_fkeys);
1173 (void) do_index_border(pine_state->context_current,
1174 pine_state->cur_folder,
1175 pine_state->mail_stream,
1176 pine_state->msgmap, MsgIndex, NULL,
1177 INDX_CLEAR|INDX_HEADER|INDX_FOOTER);
1178 pine_state->painted_footer_on_startup = 1;
1179 if(MIN(4, pine_state->ttyo->screen_rows - 4) > 1){
1180 char buf1[6*MAX_SCREEN_COLS+1];
1181 char buf2[6*MAX_SCREEN_COLS+1];
1182 int wid;
1184 strncpy(buf1, _("Please wait, opening mail folder......"), sizeof(buf1));
1185 buf1[sizeof(buf1)-1] = '\0';
1186 wid = utf8_width(buf1);
1187 if(wid > ps_global->ttyo->screen_cols){
1188 utf8_pad_to_width(buf2, buf1, sizeof(buf2), ps_global->ttyo->screen_cols, 1);
1189 PutLine0(MIN(4, pine_state->ttyo->screen_rows - 4), 0, buf2);
1191 else{
1192 PutLine0(MIN(4, pine_state->ttyo->screen_rows - 4),
1193 MAX(MIN(11, pine_state->ttyo->screen_cols - wid), 0), buf1);
1198 fflush(stdout);
1200 #if !defined(_WINDOWS) && !defined(LEAVEOUTFIFO)
1201 if(ps_global->VAR_FIFOPATH && ps_global->VAR_FIFOPATH[0])
1202 init_newmailfifo(ps_global->VAR_FIFOPATH);
1203 #endif
1205 if(pine_state->in_init_seq){
1206 pine_state->in_init_seq = 0;
1207 clear_cursor_pos();
1210 if(args.action == aaFolder && args.data.folder){
1211 CONTEXT_S *cntxt = NULL, *tc = NULL;
1212 char foldername[MAILTMPLEN];
1213 int notrealinbox = 0;
1215 if(args.data.folder[0] == '\0'){
1216 char *fldr;
1217 unsigned save_def_goto_rule;
1219 foldername[0] = '\0';
1220 save_def_goto_rule = pine_state->goto_default_rule;
1221 pine_state->goto_default_rule = GOTO_FIRST_CLCTN;
1222 tc = default_save_context(pine_state->context_list);
1223 fldr = broach_folder(-FOOTER_ROWS(pine_state), 1, &notrealinbox, &tc);
1224 pine_state->goto_default_rule = save_def_goto_rule;
1225 if(fldr){
1226 strncpy(foldername, fldr, sizeof(foldername)-1);
1227 foldername[sizeof(foldername)-1] = '\0';
1230 if(*foldername){
1231 removing_trailing_white_space(foldername);
1232 removing_leading_white_space(foldername);
1233 args.data.folder = cpystr(foldername);
1236 if(!*foldername){
1237 q_status_message(SM_ORDER, 0, 2 ,_("No folder to open"));
1238 goodnight_gracey(pine_state, -1);
1242 if(tc)
1243 cntxt = tc;
1244 else if((rv = pine_state->init_context) < 0)
1246 * As with almost all the folder vars in the pinerc,
1247 * we subvert the collection "breakout" here if the
1248 * folder name given looks like an absolute path on
1249 * this system...
1251 cntxt = (is_absolute_path(args.data.folder))
1252 ? NULL : pine_state->context_current;
1253 else if(rv == 0)
1254 cntxt = NULL;
1255 else
1256 for(cntxt = pine_state->context_list;
1257 rv > 1 && cntxt->next;
1258 rv--, cntxt = cntxt->next)
1261 if(pine_state && pine_state->ttyo){
1262 blank_keymenu(pine_state->ttyo->screen_rows - 2, 0);
1263 pine_state->painted_footer_on_startup = 0;
1264 pine_state->mangled_footer = 1;
1267 if(args.data.folder && *args.data.folder
1268 && !strucmp(args.data.folder, ps_global->inbox_name)
1269 && cntxt != ps_global->context_list)
1270 notrealinbox = 1;
1272 if(do_broach_folder(args.data.folder, cntxt, NULL, notrealinbox ? 0L : DB_INBOXWOCNTXT) <= 0){
1273 q_status_message1(SM_ORDER, 3, 4,
1274 _("Unable to open folder \"%s\""), args.data.folder);
1276 fs_give((void **) &args.data.folder);
1278 goodnight_gracey(pine_state, -1);
1281 else if(args.action == aaFolder){
1282 #ifdef _WINDOWS
1284 * need to ask for the inbox name if no default under DOS
1285 * since there is no "inbox"
1288 if(!pine_state->VAR_INBOX_PATH || !pine_state->VAR_INBOX_PATH[0]
1289 || strucmp(pine_state->VAR_INBOX_PATH, "inbox") == 0){
1290 HelpType help = NO_HELP;
1291 static ESCKEY_S ekey[] = {{ctrl(T), 2, "^T", "To Fldrs"},
1292 {-1, 0, NULL, NULL}};
1294 pine_state->mangled_footer = 1;
1295 int_mail[0] = '\0';
1296 while(1){
1297 int flags = OE_APPEND_CURRENT;
1299 rv = optionally_enter(int_mail, -FOOTER_ROWS(pine_state),
1300 0, sizeof(int_mail),
1301 _("No inbox! Folder to open as inbox : "),
1302 /* ekey */ NULL, help, &flags);
1303 if(rv == 3){
1304 help = (help == NO_HELP) ? h_sticky_inbox : NO_HELP;
1305 continue;
1308 if(rv != 4)
1309 break;
1312 if(rv == 1){
1313 q_status_message(SM_ORDER, 0, 2 ,_("Folder open cancelled"));
1314 rv = 0; /* reset rv */
1316 else if(rv == 2){
1317 show_main_screen(pine_state,0,FirstMenu,km,0,(Pos *)NULL);
1320 if(*int_mail){
1321 removing_trailing_white_space(int_mail);
1322 removing_leading_white_space(int_mail);
1323 if((!pine_state->VAR_INBOX_PATH
1324 || strucmp(pine_state->VAR_INBOX_PATH, "inbox") == 0)
1325 /* TRANSLATORS: Inbox-Path and PINERC are literal, not to be translated */
1326 && want_to(_("Preserve folder as \"Inbox-Path\" in PINERC"),
1327 'y', 'n', NO_HELP, WT_NORM) == 'y'){
1328 set_variable(V_INBOX_PATH, int_mail, 1, 1, Main);
1330 else{
1331 if(pine_state->VAR_INBOX_PATH)
1332 fs_give((void **)&pine_state->VAR_INBOX_PATH);
1334 pine_state->VAR_INBOX_PATH = cpystr(int_mail);
1337 if(pine_state && pine_state->ttyo){
1338 blank_keymenu(pine_state->ttyo->screen_rows - 2, 0);
1339 pine_state->painted_footer_on_startup = 0;
1340 pine_state->mangled_footer = 1;
1343 do_broach_folder(pine_state->inbox_name,
1344 pine_state->context_list, NULL, DB_INBOXWOCNTXT);
1346 else
1347 q_status_message(SM_ORDER, 0, 2 ,_("No folder opened"));
1350 else
1352 #endif /* _WINDOWS */
1353 if(F_ON(F_PREOPEN_STAYOPENS, ps_global))
1354 preopen_stayopen_folders();
1356 if(pine_state && pine_state->ttyo){
1357 blank_keymenu(pine_state->ttyo->screen_rows - 2, 0);
1358 pine_state->painted_footer_on_startup = 0;
1359 pine_state->mangled_footer = 1;
1362 /* open inbox */
1363 do_broach_folder(pine_state->inbox_name,
1364 pine_state->context_list, NULL, DB_INBOXWOCNTXT);
1367 if(pine_state->mangled_footer)
1368 pine_state->painted_footer_on_startup = 0;
1370 if(args.action == aaFolder
1371 && pine_state->mail_stream
1372 && expire_sent_mail())
1373 pine_state->painted_footer_on_startup = 0;
1376 * Initialize the defaults. Initializing here means that
1377 * if they're remote, the user isn't prompted for an imap login
1378 * before the display's drawn, AND there's the chance that
1379 * we can climb onto the already opened folder's stream...
1381 if(ps_global->first_time_user)
1382 init_save_defaults(); /* initialize default save folders */
1384 build_path(int_mail,
1385 ps_global->VAR_OPER_DIR ? ps_global->VAR_OPER_DIR
1386 : pine_state->home_dir,
1387 INTERRUPTED_MAIL, sizeof(int_mail));
1388 if(args.action == aaFolder
1389 && (folder_exists(NULL, int_mail) & FEX_ISFILE))
1390 q_status_message(SM_ORDER | SM_DING, 4, 5,
1391 _("Use Compose command to continue interrupted message."));
1393 if(args.action == aaFolder && args.data.folder)
1394 fs_give((void **) &args.data.folder);
1396 #if defined(USE_QUOTAS)
1398 long q;
1399 int over;
1400 q = disk_quota(pine_state->home_dir, &over);
1401 if(q > 0 && over){
1402 q_status_message2(SM_ASYNC | SM_DING, 4, 5,
1403 _("WARNING! Over your disk quota by %s bytes (%s)"),
1404 comatose(q),byte_string(q));
1407 #endif
1409 pine_state->in_init_seq = pine_state->save_in_init_seq;
1410 pine_state->dont_use_init_cmds = 0;
1411 clear_cursor_pos();
1413 if(pine_state->give_fixed_warning)
1414 q_status_message(SM_ASYNC, 0, 10,
1415 /* TRANSLATORS: config is an abbreviation for configuration */
1416 _("Note: some of your config options conflict with site policy and are ignored"));
1418 if(!prune_folders_ok())
1419 q_status_message(SM_ASYNC, 0, 10,
1420 /* TRANSLATORS: Pruned-Folders is literal */
1421 _("Note: ignoring Pruned-Folders outside of default collection for saves"));
1423 if(get_input_timeout() == 0 &&
1424 ps_global->VAR_INBOX_PATH &&
1425 ps_global->VAR_INBOX_PATH[0] == '{')
1426 q_status_message(SM_ASYNC, 0, 10,
1427 _("Note: Mail-Check-Interval=0 may cause IMAP server connection to time out"));
1429 #ifdef _WINDOWS
1430 mswin_setnewmailwidth(ps_global->nmw_width);
1431 #endif
1434 /*-------------------------------------------------------------------
1435 Loop executing the commands
1437 This is done like this so that one command screen can cause
1438 another one to execute it with out going through the main menu.
1439 ------------------------------------------------------------------*/
1440 if(!pine_state->next_screen)
1441 pine_state->next_screen = pine_state->start_in_index
1442 ? mail_index_screen : main_menu_screen;
1443 while(1){
1444 if(pine_state->next_screen == SCREEN_FUN_NULL)
1445 pine_state->next_screen = main_menu_screen;
1447 (*(pine_state->next_screen))(pine_state);
1451 exit(0);
1456 * The arguments need to be converted to UTF-8 for our internal use.
1457 * Not all arguments are converted because some are used before we
1458 * are able to do the conversion, like the pinerc name.
1460 void
1461 convert_args_to_utf8(struct pine *ps, ARGDATA_S *args)
1463 char *fromcharset = NULL;
1464 char *conv;
1466 if(args){
1467 if(ps->keyboard_charmap && strucmp(ps->keyboard_charmap, "UTF-8")
1468 && strucmp(ps->keyboard_charmap, "US-ASCII"))
1469 fromcharset = ps->keyboard_charmap;
1470 else if(ps->display_charmap && strucmp(ps->display_charmap, "UTF-8")
1471 && strucmp(ps->display_charmap, "US-ASCII"))
1472 fromcharset = ps->display_charmap;
1473 #ifndef _WINDOWS
1474 else if(ps->VAR_OLD_CHAR_SET && strucmp(ps->VAR_OLD_CHAR_SET, "UTF-8")
1475 && strucmp(ps->VAR_OLD_CHAR_SET, "US-ASCII"))
1476 fromcharset = ps->VAR_OLD_CHAR_SET;
1477 #endif /* ! _WINDOWS */
1479 if(args->action == aaURL && args->url){
1480 conv = convert_to_utf8(args->url, fromcharset, 0);
1481 if(conv){
1482 fs_give((void **) &args->url);
1483 args->url = conv;
1487 if(args->action == aaFolder && args->data.folder){
1488 conv = convert_to_utf8(args->data.folder, fromcharset, 0);
1489 if(conv){
1490 fs_give((void **) &args->data.folder);
1491 args->data.folder = conv;
1495 if(args->action == aaMore && args->data.file){
1496 conv = convert_to_utf8(args->data.file, fromcharset, 0);
1497 if(conv){
1498 fs_give((void **) &args->data.file);
1499 args->data.file = conv;
1503 if(args->action == aaURL || args->action == aaMail){
1504 if(args->data.mail.addrlist){
1505 STRLIST_S *p;
1507 for(p = args->data.mail.addrlist; p; p=p->next){
1508 if(p->name){
1509 conv = convert_to_utf8(p->name, fromcharset, 0);
1510 if(conv){
1511 fs_give((void **) &p->name);
1512 p->name = conv;
1518 if(args->data.mail.attachlist){
1519 PATMT *p;
1521 for(p = args->data.mail.attachlist; p; p=p->next){
1522 if(p->filename){
1523 conv = convert_to_utf8(p->filename, fromcharset, 0);
1524 if(conv){
1525 fs_give((void **) &p->filename);
1526 p->filename = conv;
1536 void
1537 preopen_stayopen_folders(void)
1539 char **open_these;
1541 for(open_these = ps_global->VAR_PERMLOCKED;
1542 open_these && *open_these; open_these++)
1543 (void) do_broach_folder(*open_these, ps_global->context_list,
1544 NULL, DB_NOVISIT);
1549 * read_stdin_char - simple function to return a character from
1550 * redirected stdin
1553 read_stdin_char(char *c)
1555 int rv;
1557 /* it'd probably be a good idea to fix this to pre-read blocks */
1558 while(1){
1559 rv = read(PIPED_FD, c, 1);
1560 if(rv < 0){
1561 if(errno == EINTR){
1562 dprint((2, "read_stdin_char: read interrupted, restarting\n"));
1563 continue;
1565 else
1566 dprint((1, "read_stdin_char: read FAILED: %s\n",
1567 error_description(errno)));
1569 break;
1571 return(rv);
1575 /* this default is from the array of structs below */
1576 #define DEFAULT_MENU_ITEM ((unsigned) 3) /* LIST FOLDERS */
1577 #define ABOOK_MENU_ITEM ((unsigned) 4) /* ADDRESS BOOK */
1578 #define MAX_MENU_ITEM ((unsigned) 6)
1580 * Skip this many spaces between rows of main menu screen.
1581 * We have MAX_MENU_ITEM+1 = # of commands in menu
1582 * 1 = copyright line
1583 * MAX_MENU_ITEM = rows between commands
1584 * 1 = extra row above commands
1585 * 1 = row between commands and copyright
1587 * To make it simple, if there is enough room for all of that include all the
1588 * extra space, if not, cut it all out.
1590 #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)
1592 static unsigned menu_index = DEFAULT_MENU_ITEM;
1595 * One of these for each line that gets printed in the middle of the
1596 * screen in the main menu.
1598 static struct menu_key {
1599 char *key_and_name,
1600 *news_addition;
1601 int key_index; /* index into keymenu array for this cmd */
1602 } mkeys[] = {
1604 * TRANSLATORS: These next few are headings on the Main alpine menu.
1605 * It's nice if the dashes can be made to line up vertically.
1607 {N_(" %s HELP - Get help using Alpine"),
1608 NULL, MAIN_HELP_KEY},
1609 {N_(" %s COMPOSE MESSAGE - Compose and send%s a message"),
1610 /* TRANSLATORS: We think of sending an email message or posting a news message.
1611 The message is shown as Compose and send/post a message */
1612 N_("/post"), MAIN_COMPOSE_KEY},
1613 {N_(" %s MESSAGE INDEX - View messages in current folder"),
1614 NULL, MAIN_INDEX_KEY},
1615 {N_(" %s FOLDER LIST - Select a folder%s to view"),
1616 /* TRANSLATORS: When news is supported the message above becomes
1617 Select a folder OR news group to view */
1618 N_(" OR news group"), MAIN_FOLDER_KEY},
1619 {N_(" %s ADDRESS BOOK - Update address book"),
1620 NULL, MAIN_ADDRESS_KEY},
1621 {N_(" %s SETUP - Configure Alpine Options"),
1622 NULL, MAIN_SETUP_KEY},
1623 /* TRANSLATORS: final Main menu line */
1624 {N_(" %s QUIT - Leave the Alpine program"),
1625 NULL, MAIN_QUIT_KEY}
1630 /*----------------------------------------------------------------------
1631 display main menu and execute main menu commands
1633 Args: The usual pine structure
1635 Result: main menu commands are executed
1638 M A I N M E N U S C R E E N
1640 Paint the main menu on the screen, get the commands and either execute
1641 the function or pass back the name of the function to execute for the menu
1642 selection. Only simple functions that always return here can be executed
1643 here.
1645 This functions handling of new mail, redrawing, errors and such can
1646 serve as a template for the other screen that do much the same thing.
1648 There is a loop that fetches and executes commands until a command to leave
1649 this screen is given. Then the name of the next screen to display is
1650 stored in next_screen member of the structure and this function is exited
1651 with a return.
1653 First a check for new mail is performed. This might involve reading the new
1654 mail into the inbox which might then cause the screen to be repainted.
1656 Then the general screen painting is done. This is usually controlled
1657 by a few flags and some other position variables. If they change they
1658 tell this part of the code what to repaint. This will include cursor
1659 motion and so on.
1660 ----*/
1661 void
1662 main_menu_screen(struct pine *pine_state)
1664 UCS ch;
1665 int cmd, just_a_navigate_cmd, setup_command, km_popped;
1666 int notrealinbox;
1667 char *new_folder, *utf8str;
1668 CONTEXT_S *tc;
1669 struct key_menu *km;
1670 OtherMenu what;
1671 Pos curs_pos;
1673 ps_global = pine_state;
1674 just_a_navigate_cmd = 0;
1675 km_popped = 0;
1676 menu_index = DEFAULT_MENU_ITEM;
1677 what = FirstMenu; /* which keymenu to display */
1678 ch = 'x'; /* For display_message 1st time through */
1679 pine_state->next_screen = SCREEN_FUN_NULL;
1680 pine_state->prev_screen = main_menu_screen;
1681 curs_pos.row = pine_state->ttyo->screen_rows-FOOTER_ROWS(pine_state);
1682 curs_pos.col = 0;
1683 km = &main_keymenu;
1685 mailcap_free(); /* free resources we won't be using for a while */
1687 if(!pine_state->painted_body_on_startup
1688 && !pine_state->painted_footer_on_startup){
1689 pine_state->mangled_screen = 1;
1692 dprint((1, "\n\n ---- MAIN_MENU_SCREEN ----\n"));
1694 while(1){
1695 if(km_popped){
1696 km_popped--;
1697 if(km_popped == 0){
1698 clearfooter(pine_state);
1699 pine_state->mangled_body = 1;
1704 * fix up redrawer just in case some submenu caused it to get
1705 * reassigned...
1707 pine_state->redrawer = main_redrawer;
1709 /*----------- Check for new mail -----------*/
1710 if(new_mail(0, NM_TIMING(ch), NM_STATUS_MSG | NM_DEFER_SORT) >= 0)
1711 pine_state->mangled_header = 1;
1713 if(streams_died())
1714 pine_state->mangled_header = 1;
1716 show_main_screen(pine_state, just_a_navigate_cmd, what, km,
1717 km_popped, &curs_pos);
1718 just_a_navigate_cmd = 0;
1719 what = SameMenu;
1721 /*---- This displays new mail notification, or errors ---*/
1722 if(km_popped){
1723 FOOTER_ROWS(pine_state) = 3;
1724 mark_status_dirty();
1727 display_message(ch);
1728 if(km_popped){
1729 FOOTER_ROWS(pine_state) = 1;
1730 mark_status_dirty();
1733 if(F_OFF(F_SHOW_CURSOR, ps_global)){
1734 curs_pos.row =pine_state->ttyo->screen_rows-FOOTER_ROWS(pine_state);
1735 curs_pos.col =0;
1738 MoveCursor(curs_pos.row, curs_pos.col);
1740 /*------ Read the command from the keyboard ----*/
1741 #ifdef MOUSE
1742 mouse_in_content(KEY_MOUSE, -1, -1, 0, 0);
1743 register_mfunc(mouse_in_content, HEADER_ROWS(pine_state), 0,
1744 pine_state->ttyo->screen_rows-(FOOTER_ROWS(pine_state)+1),
1745 pine_state->ttyo->screen_cols);
1746 #endif
1747 #if defined(DOS) || defined(OS2)
1749 * AND pre-build header lines. This works just fine under
1750 * DOS since we wait for characters in a loop. Something will
1751 * will have to change under UNIX if we want to do the same.
1753 /* while_waiting = build_header_cache; */
1754 #ifdef _WINDOWS
1755 mswin_sethelptextcallback(pcpine_help_main);
1756 mswin_mousetrackcallback(pcpine_main_cursor);
1757 #endif
1758 #endif
1759 ch = READ_COMMAND(&utf8str);
1760 #ifdef MOUSE
1761 clear_mfunc(mouse_in_content);
1762 #endif
1763 #if defined(DOS) || defined(OS2)
1764 /* while_waiting = NULL; */
1765 #ifdef _WINDOWS
1766 mswin_sethelptextcallback(NULL);
1767 mswin_mousetrackcallback(NULL);
1768 #endif
1769 #endif
1771 /* No matter what, Quit here always works */
1772 if(ch == 'q' || ch == 'Q'){
1773 cmd = MC_QUIT;
1775 #ifdef DEBUG
1776 else if(debug && ch && ch < 0x80 && strchr("123456789", ch)){
1777 int olddebug;
1779 olddebug = debug;
1780 debug = ch - '0';
1781 if(debug > 7)
1782 ps_global->debug_timestamp = 1;
1783 else
1784 ps_global->debug_timestamp = 0;
1786 if(debug > 7)
1787 ps_global->debug_imap = 4;
1788 else if(debug > 6)
1789 ps_global->debug_imap = 3;
1790 else if(debug > 4)
1791 ps_global->debug_imap = 2;
1792 else if(debug > 2)
1793 ps_global->debug_imap = 1;
1794 else
1795 ps_global->debug_imap = 0;
1797 if(ps_global->mail_stream){
1798 if(ps_global->debug_imap > 0){
1799 mail_debug(ps_global->mail_stream);
1800 #ifdef _WINDOWS
1801 mswin_enableimaptelemetry(TRUE);
1802 #endif
1804 else{
1805 mail_nodebug(ps_global->mail_stream);
1806 #ifdef _WINDOWS
1807 mswin_enableimaptelemetry(FALSE);
1808 #endif
1812 if(debug > 7 && olddebug <= 7)
1813 mail_parameters(NULL, SET_TCPDEBUG, (void *) TRUE);
1814 else if(debug <= 7 && olddebug > 7 && !ps_global->debugmem)
1815 mail_parameters(NULL, SET_TCPDEBUG, (void *) FALSE);
1817 dprint((1, "*** Debug level set to %d ***\n", debug));
1818 if(debugfile)
1819 fflush(debugfile);
1821 q_status_message1(SM_ORDER, 0, 1, _("Debug level set to %s"),
1822 int2string(debug));
1823 continue;
1825 #endif /* DEBUG */
1826 else{
1827 cmd = menu_command(ch, km);
1829 if(km_popped)
1830 switch(cmd){
1831 case MC_NONE :
1832 case MC_OTHER :
1833 case MC_RESIZE :
1834 case MC_REPAINT :
1835 km_popped++;
1836 break;
1838 default:
1839 clearfooter(pine_state);
1840 break;
1844 /*------ Execute the command ------*/
1845 switch (cmd){
1846 help_case :
1847 /*------ HELP ------*/
1848 case MC_HELP :
1850 if(FOOTER_ROWS(pine_state) == 1 && km_popped == 0){
1851 km_popped = 2;
1852 pine_state->mangled_footer = 1;
1854 else{
1855 /* TRANSLATORS: This is a screen title */
1856 helper(main_menu_tx, _("HELP FOR MAIN MENU"), 0);
1857 pine_state->mangled_screen = 1;
1860 break;
1863 /*---------- display other key bindings ------*/
1864 case MC_OTHER :
1865 if(ch == 'o')
1866 warn_other_cmds();
1868 what = NextMenu;
1869 pine_state->mangled_footer = 1;
1870 break;
1873 /*---------- Previous item in menu ----------*/
1874 case MC_PREVITEM :
1875 if(menu_index > 0) {
1876 menu_index--;
1877 pine_state->mangled_body = 1;
1878 if(km->which == 0)
1879 pine_state->mangled_footer = 1;
1881 just_a_navigate_cmd++;
1883 else
1884 /* TRANSLATORS: list refers to list of commands in main menu */
1885 q_status_message(SM_ORDER, 0, 2, _("Already at top of list"));
1887 break;
1890 /*---------- Next item in menu ----------*/
1891 case MC_NEXTITEM :
1892 if(menu_index < MAX_MENU_ITEM){
1893 menu_index++;
1894 pine_state->mangled_body = 1;
1895 if(km->which == 0)
1896 pine_state->mangled_footer = 1;
1898 just_a_navigate_cmd++;
1900 else
1901 q_status_message(SM_ORDER, 0, 2, _("Already at bottom of list"));
1903 break;
1906 /*---------- Release Notes ----------*/
1907 case MC_RELNOTES :
1908 /* TRANSLATORS: This is a screen title */
1909 helper(h_news, _("ALPINE RELEASE NOTES"), 0);
1910 pine_state->mangled_screen = 1;
1911 break;
1914 #ifdef KEYBOARD_LOCK
1915 /*---------- Keyboard lock ----------*/
1916 case MC_KBLOCK :
1917 (void) lock_keyboard();
1918 pine_state->mangled_screen = 1;
1919 break;
1920 #endif /* KEYBOARD_LOCK */
1923 /*---------- Quit pine ----------*/
1924 case MC_QUIT :
1925 pine_state->next_screen = quit_screen;
1926 return;
1929 /*---------- Go to composer ----------*/
1930 case MC_COMPOSE :
1931 pine_state->next_screen = compose_screen;
1932 return;
1935 /*---- Go to alternate composer ------*/
1936 case MC_ROLE :
1937 pine_state->next_screen = alt_compose_screen;
1938 return;
1941 /*---------- Top of Folder list ----------*/
1942 case MC_COLLECTIONS :
1943 pine_state->next_screen = folder_screen;
1944 return;
1947 /*---------- Goto new folder ----------*/
1948 case MC_GOTO :
1949 tc = ps_global->context_current;
1950 new_folder = broach_folder(-FOOTER_ROWS(pine_state), 1, &notrealinbox, &tc);
1951 if(new_folder)
1952 visit_folder(ps_global, new_folder, tc, NULL, notrealinbox ? 0L : DB_INBOXWOCNTXT);
1954 return;
1957 /*---------- Go to index ----------*/
1958 case MC_INDEX :
1959 if(THREADING()
1960 && sp_viewing_a_thread(pine_state->mail_stream)
1961 && unview_thread(pine_state, pine_state->mail_stream,
1962 pine_state->msgmap)){
1963 pine_state->view_skipped_index = 0;
1964 pine_state->mangled_screen = 1;
1967 pine_state->next_screen = mail_index_screen;
1968 return;
1971 /*---------- Review Status Messages ----------*/
1972 case MC_JOURNAL :
1973 review_messages();
1974 pine_state->mangled_screen = 1;
1975 break;
1978 /*---------- Setup mini menu ----------*/
1979 case MC_SETUP :
1980 setup_case :
1981 setup_command = setup_menu(pine_state);
1982 pine_state->mangled_footer = 1;
1983 do_setup_task(setup_command);
1984 if(ps_global->next_screen != main_menu_screen)
1985 return;
1987 break;
1990 /*---------- Go to address book ----------*/
1991 case MC_ADDRBOOK :
1992 pine_state->next_screen = addr_book_screen;
1993 return;
1996 /*------ Repaint the works -------*/
1997 case MC_RESIZE :
1998 case MC_REPAINT :
1999 ClearScreen();
2000 pine_state->mangled_screen = 1;
2001 break;
2004 #ifdef MOUSE
2005 /*------- Mouse event ------*/
2006 case MC_MOUSE :
2008 MOUSEPRESS mp;
2009 unsigned ndmi;
2010 struct pine *ps = pine_state;
2012 mouse_get_last (NULL, &mp);
2014 #ifdef _WINDOWS
2015 if(mp.button == M_BUTTON_RIGHT){
2016 if(!mp.doubleclick){
2017 static MPopup main_popup[] = {
2018 {tQueue, {"Folder List", lNormal}, {'L'}},
2019 {tQueue, {"Message Index", lNormal}, {'I'}},
2020 {tSeparator},
2021 {tQueue, {"Address Book", lNormal}, {'A'}},
2022 {tQueue, {"Setup Options", lNormal}, {'S'}},
2023 {tTail}
2026 mswin_popup(main_popup);
2029 else {
2030 #endif
2031 if (mp.row >= (HEADER_ROWS(ps) + MNSKIP(ps)))
2032 ndmi = (mp.row+1 - HEADER_ROWS(ps) - (MNSKIP(ps)+1))/(MNSKIP(ps)+1);
2034 if (mp.row >= (HEADER_ROWS(ps) + MNSKIP(ps))
2035 && !(MNSKIP(ps) && (mp.row+1) & 0x01)
2036 && ndmi <= MAX_MENU_ITEM
2037 && FOOTER_ROWS(ps) + (ndmi+1)*(MNSKIP(ps)+1)
2038 + MNSKIP(ps) + FOOTER_ROWS(ps) <= ps->ttyo->screen_rows){
2039 if(mp.doubleclick){
2040 switch(ndmi){ /* fake main_screen request */
2041 case 0 :
2042 goto help_case;
2044 case 1 :
2045 pine_state->next_screen = compose_screen;
2046 return;
2048 case 2 :
2049 pine_state->next_screen = mail_index_screen;
2050 return;
2052 case 3 :
2053 pine_state->next_screen = folder_screen;
2054 return;
2056 case 4 :
2057 pine_state->next_screen = addr_book_screen;
2058 return;
2060 case 5 :
2061 goto setup_case;
2063 case 6 :
2064 pine_state->next_screen = quit_screen;
2065 return;
2067 default: /* no op */
2068 break;
2071 else{
2072 menu_index = ndmi;
2073 pine_state->mangled_body = 1;
2074 if(km->which == 0)
2075 pine_state->mangled_footer = 1;
2077 just_a_navigate_cmd++;
2080 #ifdef _WINDOWS
2082 #endif
2085 break;
2086 #endif
2089 /*------ Input timeout ------*/
2090 case MC_NONE :
2091 break; /* noop for timeout loop mail check */
2094 /*------ Bogus Input ------*/
2095 case MC_UNKNOWN :
2096 if(ch == 'm' || ch == 'M'){
2097 q_status_message(SM_ORDER, 0, 1, "Already in Main Menu");
2098 break;
2101 default:
2102 bogus_command(ch, F_ON(F_USE_FK,pine_state) ? "F1" : "?");
2103 break;
2105 case MC_UTF8:
2106 bogus_utf8_command(utf8str, F_ON(F_USE_FK, pine_state) ? "F1" : "?");
2107 break;
2108 } /* the switch */
2109 } /* the BIG while loop! */
2113 /*----------------------------------------------------------------------
2114 Re-Draw the main menu
2116 Args: none.
2118 Result: main menu is re-displayed
2119 ----*/
2120 void
2121 main_redrawer(void)
2123 struct key_menu *km = &main_keymenu;
2125 ps_global->mangled_screen = 1;
2126 show_main_screen(ps_global, 0, FirstMenu, km, 0, (Pos *)NULL);
2130 /*----------------------------------------------------------------------
2131 Draw the main menu
2133 Args: pine_state - the usual struct
2134 quick_draw - tells do_menu() it can skip some drawing
2135 what - tells which section of keymenu to draw
2136 km - the keymenu
2137 cursor_pos - returns a good position for the cursor to be located
2139 Result: main menu is displayed
2140 ----*/
2141 void
2142 show_main_screen(struct pine *ps, int quick_draw, OtherMenu what,
2143 struct key_menu *km, int km_popped, Pos *cursor_pos)
2145 if(ps->painted_body_on_startup || ps->painted_footer_on_startup){
2146 ps->mangled_screen = 0; /* only worry about it here */
2147 ps->mangled_header = 1; /* we have to redo header */
2148 if(!ps->painted_body_on_startup)
2149 ps->mangled_body = 1; /* make sure to paint body*/
2151 if(!ps->painted_footer_on_startup)
2152 ps->mangled_footer = 1; /* make sure to paint footer*/
2154 ps->painted_body_on_startup = 0;
2155 ps->painted_footer_on_startup = 0;
2158 if(ps->mangled_screen){
2159 ps->mangled_header = 1;
2160 ps->mangled_body = 1;
2161 ps->mangled_footer = 1;
2162 ps->mangled_screen = 0;
2165 #ifdef _WINDOWS
2166 /* Reset the scroll range. Main screen never scrolls. */
2167 scroll_setrange (0L, 0L);
2168 mswin_beginupdate();
2169 #endif
2171 /* paint the titlebar if needed */
2172 if(ps->mangled_header){
2173 /* TRANSLATORS: screen title */
2174 set_titlebar(_("MAIN MENU"), ps->mail_stream, ps->context_current,
2175 ps->cur_folder, ps->msgmap, 1, FolderName, 0, 0, NULL);
2176 ps->mangled_header = 0;
2179 /* paint the body if needed */
2180 if(ps->mangled_body){
2181 if(!quick_draw)
2182 ClearBody();
2184 do_menu(quick_draw, cursor_pos, km);
2185 ps->mangled_body = 0;
2188 /* paint the keymenu if needed */
2189 if(km && ps->mangled_footer){
2190 static char label[LONGEST_LABEL + 2 + 1], /* label + brackets + \0 */
2191 name[8];
2192 bitmap_t bitmap;
2194 setbitmap(bitmap);
2196 #ifdef KEYBOARD_LOCK
2197 if(ps_global->restricted || F_ON(F_DISABLE_KBLOCK_CMD,ps_global))
2198 #endif
2199 clrbitn(MAIN_KBLOCK_KEY, bitmap);
2201 menu_clear_binding(km, '>');
2202 menu_clear_binding(km, '.');
2203 menu_clear_binding(km, KEY_RIGHT);
2204 menu_clear_binding(km, ctrl('M'));
2205 menu_clear_binding(km, ctrl('J'));
2206 km->keys[MAIN_DEFAULT_KEY].bind
2207 = km->keys[mkeys[menu_index].key_index].bind;
2208 km->keys[MAIN_DEFAULT_KEY].label
2209 = km->keys[mkeys[menu_index].key_index].label;
2211 /* put brackets around the default action */
2212 snprintf(label, sizeof(label), "[%s]", km->keys[mkeys[menu_index].key_index].label);
2213 label[sizeof(label)-1] = '\0';
2214 strncpy(name, ">", sizeof(name));
2215 name[sizeof(name)-1] = '\0';
2216 km->keys[MAIN_DEFAULT_KEY].label = label;
2217 km->keys[MAIN_DEFAULT_KEY].name = name;
2218 menu_add_binding(km, '>', km->keys[MAIN_DEFAULT_KEY].bind.cmd);
2219 menu_add_binding(km, '.', km->keys[MAIN_DEFAULT_KEY].bind.cmd);
2220 menu_add_binding(km, ctrl('M'), km->keys[MAIN_DEFAULT_KEY].bind.cmd);
2221 menu_add_binding(km, ctrl('J'), km->keys[MAIN_DEFAULT_KEY].bind.cmd);
2223 if(F_ON(F_ARROW_NAV,ps_global))
2224 menu_add_binding(km, KEY_RIGHT, km->keys[MAIN_DEFAULT_KEY].bind.cmd);
2226 if(km_popped){
2227 FOOTER_ROWS(ps) = 3;
2228 clearfooter(ps);
2231 draw_keymenu(km, bitmap, ps_global->ttyo->screen_cols,
2232 1-FOOTER_ROWS(ps_global), 0, what);
2233 ps->mangled_footer = 0;
2234 if(km_popped){
2235 FOOTER_ROWS(ps) = 1;
2236 mark_keymenu_dirty();
2240 #ifdef _WINDOWS
2241 mswin_endupdate();
2242 #endif
2246 /*----------------------------------------------------------------------
2247 Actually display the main menu
2249 Args: quick_draw - just a next or prev command was typed so we only have
2250 to redraw the highlighting
2251 cursor_pos - a place to return a good value for cursor location
2253 Result: Main menu is displayed
2254 ---*/
2255 void
2256 do_menu(int quick_draw, Pos *cursor_pos, struct key_menu *km)
2258 struct pine *ps = ps_global;
2259 int dline, indent, longest = 0, cmd;
2260 char buf[4*MAX_SCREEN_COLS+1];
2261 char buf2[4*MAX_SCREEN_COLS+1];
2262 static int last_inverse = -1;
2263 Pos pos;
2265 /* find the longest command */
2266 for(cmd = 0; cmd < sizeof(mkeys)/(sizeof(mkeys[1])); cmd++){
2267 memset((void *) buf, ' ', sizeof(buf));
2268 snprintf(buf, sizeof(buf), mkeys[cmd].key_and_name[0] ? _(mkeys[cmd].key_and_name) : "",
2269 (F_OFF(F_USE_FK,ps)
2270 && km->keys[mkeys[cmd].key_index].name)
2271 ? km->keys[mkeys[cmd].key_index].name : "",
2272 (ps->VAR_NEWS_SPEC && mkeys[cmd].news_addition && mkeys[cmd].news_addition[0])
2273 ? _(mkeys[cmd].news_addition) : "");
2274 buf[sizeof(buf)-1] = '\0';
2276 if(longest < (indent = utf8_width(buf)))
2277 longest = indent;
2280 indent = MAX(((ps->ttyo->screen_cols - longest)/2) - 1, 0);
2282 dline = HEADER_ROWS(ps) + MNSKIP(ps);
2283 for(cmd = 0; cmd < sizeof(mkeys)/(sizeof(mkeys[1])); cmd++){
2284 /* leave room for copyright and footer */
2285 if(dline + MNSKIP(ps) + 1 + FOOTER_ROWS(ps) >= ps->ttyo->screen_rows)
2286 break;
2288 if(quick_draw && !(cmd == last_inverse || cmd == menu_index)){
2289 dline += (1 + MNSKIP(ps));
2290 continue;
2293 if(cmd == menu_index)
2294 StartInverse();
2296 memset((void *) buf, ' ', sizeof(buf));
2297 snprintf(buf, sizeof(buf), mkeys[cmd].key_and_name[0] ? _(mkeys[cmd].key_and_name) : "",
2298 (F_OFF(F_USE_FK,ps)
2299 && km->keys[mkeys[cmd].key_index].name)
2300 ? km->keys[mkeys[cmd].key_index].name : "",
2301 (ps->VAR_NEWS_SPEC && mkeys[cmd].news_addition && mkeys[cmd].news_addition[0])
2302 ? _(mkeys[cmd].news_addition) : "");
2303 buf[sizeof(buf)-1] = '\0';
2305 utf8_pad_to_width(buf2, buf, sizeof(buf2),
2306 MIN(ps->ttyo->screen_cols-indent,longest+1), 1);
2307 pos.row = dline++;
2308 pos.col = indent;
2309 PutLine0(pos.row, pos.col, buf2);
2311 if(MNSKIP(ps))
2312 dline++;
2314 if(cmd == menu_index){
2315 if(cursor_pos){
2316 cursor_pos->row = pos.row;
2317 /* 6 is 1 for the letter plus 5 spaces */
2318 cursor_pos->col = pos.col + 6;
2319 if(F_OFF(F_USE_FK,ps))
2320 cursor_pos->col++;
2322 cursor_pos->col = MIN(cursor_pos->col, ps->ttyo->screen_cols);
2325 EndInverse();
2330 last_inverse = menu_index;
2332 if(!quick_draw && FOOTER_ROWS(ps)+1 < ps->ttyo->screen_rows){
2333 utf8_to_width(buf2, LEGAL_NOTICE, sizeof(buf2),
2334 ps->ttyo->screen_cols-3, NULL);
2335 PutLine0(ps->ttyo->screen_rows - (FOOTER_ROWS(ps)+1),
2336 MAX(0, ((ps->ttyo->screen_cols-utf8_width(buf2))/2)),
2337 buf2);
2340 fflush(stdout);
2345 choose_setup_cmd(int cmd, MSGNO_S *msgmap, SCROLL_S *sparms)
2347 int rv = 1;
2348 SRV_S *srv;
2350 if(!(srv = (SRV_S *)sparms->proc.data.p)){
2351 sparms->proc.data.p = (SRV_S *)fs_get(sizeof(*srv));
2352 srv = (SRV_S *)sparms->proc.data.p;
2353 memset(srv, 0, sizeof(*srv));
2356 ps_global->next_screen = SCREEN_FUN_NULL;
2358 switch(cmd){
2359 case MC_PRINTER :
2360 srv->cmd = 'p';
2361 break;
2363 case MC_PASSWD :
2364 srv->cmd = 'n';
2365 break;
2367 case MC_CONFIG :
2368 srv->cmd = 'c';
2369 break;
2371 case MC_XOAUTH2 :
2372 srv->cmd = 'u';
2373 break;
2375 case MC_SIG :
2376 srv->cmd = 's';
2377 break;
2379 case MC_ABOOKS :
2380 srv->cmd = 'a';
2381 break;
2383 case MC_CLISTS :
2384 srv->cmd = 'l';
2385 break;
2387 case MC_RULES :
2388 srv->cmd = 'r';
2389 break;
2391 case MC_DIRECTORY :
2392 srv->cmd = 'd';
2393 break;
2395 case MC_KOLOR :
2396 srv->cmd = 'k';
2397 break;
2399 case MC_REMOTE :
2400 srv->cmd = 'z';
2401 break;
2403 case MC_SECURITY : /* S/MIME setup screen */
2404 srv->cmd = 'm';
2405 break;
2407 case MC_EXCEPT :
2408 srv->exc = !srv->exc;
2409 menu_clear_binding(sparms->keys.menu, 'x');
2410 if(srv->exc){
2411 if(sparms->bar.title) fs_give((void **)&sparms->bar.title);
2412 /* TRANSLATORS: screen title */
2413 sparms->bar.title = cpystr(_("SETUP EXCEPTIONS"));
2414 ps_global->mangled_header = 1;
2415 /* TRANSLATORS: The reason the X is upper case in eXceptions
2416 is because the command key is X. It isn't necessary, just
2417 nice if it works. */
2418 menu_init_binding(sparms->keys.menu, 'x', MC_EXCEPT, "X",
2419 N_("not eXceptions"), SETUP_EXCEPT);
2421 else{
2422 if(sparms->bar.title) fs_give((void **)&sparms->bar.title);
2423 /* TRANSLATORS: screen title */
2424 sparms->bar.title = cpystr(_("SETUP"));
2425 ps_global->mangled_header = 1;
2426 menu_init_binding(sparms->keys.menu, 'x', MC_EXCEPT, "X",
2427 N_("eXceptions"), SETUP_EXCEPT);
2430 if(sparms->keys.menu->which == 1)
2431 ps_global->mangled_footer = 1;
2433 rv = 0;
2434 break;
2436 case MC_NO_EXCEPT :
2437 #if defined(DOS) || defined(OS2)
2438 q_status_message(SM_ORDER, 0, 2, _("Need argument \"-x <except_config>\" or \"PINERCEX\" file to use eXceptions"));
2439 #else
2440 q_status_message(SM_ORDER, 0, 2, _("Need argument \"-x <except_config>\" or \".pinercex\" file to use eXceptions"));
2441 #endif
2442 rv = 0;
2443 break;
2445 default:
2446 alpine_panic("Unexpected command in choose_setup_cmd");
2447 break;
2450 return(rv);
2455 setup_menu(struct pine *ps)
2457 int ret = 0, exceptions = 0;
2458 int printer = 0, passwd = 0, config = 0, sig = 0, dir = 0, smime = 0, exc = 0;
2459 SCROLL_S sargs;
2460 SRV_S *srv;
2461 STORE_S *store;
2463 if(!(store = so_get(CharStar, NULL, EDIT_ACCESS))){
2464 q_status_message(SM_ORDER | SM_DING, 3, 3, _("Error allocating space."));
2465 return(ret);
2468 #if !defined(DOS)
2469 if(!ps_global->vars[V_PRINTER].is_fixed) /* printer can be changed */
2470 printer++;
2471 #endif
2473 #ifdef PASSWD_PROG
2474 if(F_OFF(F_DISABLE_PASSWORD_CMD,ps_global)) /* password is allowed */
2475 passwd++;
2476 #endif
2478 if(F_OFF(F_DISABLE_CONFIG_SCREEN,ps_global)) /* config allowed */
2479 config++;
2481 if(F_OFF(F_DISABLE_SIGEDIT_CMD,ps_global)) /* .sig editing is allowed */
2482 sig++;
2484 #ifdef ENABLE_LDAP
2485 dir++;
2486 #endif
2488 #ifdef SMIME
2489 smime++;
2490 #endif
2492 if(ps_global->post_prc)
2493 exc++;
2495 /* TRANSLATORS: starting here we have a whole screen of help text */
2496 so_puts(store, _("This is the Setup screen for Alpine. Choose from the following commands:\n"));
2498 so_puts(store, "\n");
2499 so_puts(store, _("(E) Exit Setup:\n"));
2500 so_puts(store, _(" This puts you back at the Main Menu.\n"));
2502 if(exc){
2503 so_puts(store, "\n");
2504 so_puts(store, _("(X) eXceptions:\n"));
2505 so_puts(store, _(" This command is different from the rest. It is not actually a command\n"));
2506 so_puts(store, _(" itself. Instead, it is a toggle which modifies the behavior of the\n"));
2507 so_puts(store, _(" other commands. You toggle Exceptions editing on and off with this\n"));
2508 so_puts(store, _(" command. When it is off you will be editing (changing) your regular\n"));
2509 so_puts(store, _(" configuration file. When it is on you will be editing your exceptions\n"));
2510 so_puts(store, _(" configuration file. For example, you might want to type the command \n"));
2511 so_puts(store, _(" \"eXceptions\" followed by \"Kolor\" to setup different screen colors\n"));
2512 so_puts(store, _(" on a particular platform.\n"));
2513 so_puts(store, _(" (Note: this command does not show up on the keymenu at the bottom of\n"));
2514 so_puts(store, _(" the screen unless you press \"O\" for \"Other Commands\" --but you don't\n"));
2515 so_puts(store, _(" need to press the \"O\" in order to invoke the command.)\n"));
2518 if(printer){
2519 so_puts(store, "\n");
2520 so_puts(store, _("(P) Printer:\n"));
2521 so_puts(store, _(" Allows you to set a default printer and to define custom\n"));
2522 so_puts(store, _(" print commands.\n"));
2525 if(passwd){
2526 so_puts(store, "\n");
2527 so_puts(store, _("(N) Newpassword:\n"));
2528 so_puts(store, _(" Change your password.\n"));
2531 if(config){
2532 so_puts(store, "\n");
2533 so_puts(store, _("(C) Config:\n"));
2534 so_puts(store, _(" Allows you to set or unset many features of Alpine.\n"));
2535 so_puts(store, _(" You may also set the values of many options with this command.\n"));
2538 if(sig){
2539 so_puts(store, "\n");
2540 so_puts(store, _("(S) Signature:\n"));
2541 so_puts(store, _(" Enter or edit a custom signature which will\n"));
2542 so_puts(store, _(" be included with each new message you send.\n"));
2545 so_puts(store, "\n");
2546 so_puts(store, _("(A) AddressBooks:\n"));
2547 so_puts(store, _(" Define a non-default address book.\n"));
2549 so_puts(store, "\n");
2550 so_puts(store, _("(L) collectionLists:\n"));
2551 so_puts(store, _(" You may define groups of folders to help you better organize your mail.\n"));
2553 so_puts(store, "\n");
2554 so_puts(store, _("(R) Rules:\n"));
2555 so_puts(store, _(" This has up to six sub-categories: Roles, Index Colors, Filters,\n"));
2556 so_puts(store, _(" SetScores, Search, and Other. If the Index Colors option is\n"));
2557 so_puts(store, _(" missing you may turn it on (if possible) with Setup/Kolor.\n"));
2558 so_puts(store, _(" If Roles is missing it has probably been administratively disabled.\n"));
2560 if(dir){
2561 so_puts(store, "\n");
2562 so_puts(store, _("(D) Directory:\n"));
2563 so_puts(store, _(" Define an LDAP Directory server for Alpine's use. A directory server is\n"));
2564 so_puts(store, _(" similar to an address book, but it is usually maintained by an\n"));
2565 so_puts(store, _(" organization. It is similar to a telephone directory.\n"));
2568 so_puts(store, "\n");
2569 so_puts(store, _("(K) Kolor:\n"));
2570 so_puts(store, _(" Set custom colors for various parts of the Alpine screens. For example, the\n"));
2571 so_puts(store, _(" command key labels, the titlebar at the top of each page, and quoted\n"));
2572 so_puts(store, _(" sections of messages you are viewing.\n"));
2574 if(smime){
2575 so_puts(store, "\n");
2576 so_puts(store, _("(M) S/MIME:\n"));
2577 so_puts(store, _(" Setup for using S/MIME to verify signed messages, decrypt\n"));
2578 so_puts(store, _(" encrypted messages, and to sign or encrypt outgoing messages.\n"));
2581 so_puts(store, "\n");
2582 so_puts(store, _("(U) xoaUth2:\n"));
2583 so_puts(store, _(" Set client-id and client-secret to use the XOAUTH2\n"));
2584 so_puts(store, _(" authenticator.\n"));
2586 so_puts(store, "\n");
2587 so_puts(store, _("(Z) RemoteConfigSetup:\n"));
2588 so_puts(store, _(" This is a command you will probably only want to use once, if at all.\n"));
2589 so_puts(store, _(" It helps you transfer your Alpine configuration data to an IMAP server,\n"));
2590 so_puts(store, _(" where it will be accessible from any of the computers you read mail\n"));
2591 so_puts(store, _(" from (using Alpine). The idea behind a remote configuration is that you\n"));
2592 so_puts(store, _(" can change your configuration in one place and have that change show\n"));
2593 so_puts(store, _(" up on all of the computers you use.\n"));
2594 so_puts(store, _(" (Note: this command does not show up on the keymenu at the bottom of\n"));
2595 so_puts(store, _(" the screen unless you press \"O\" for \"Other Commands\" --but you don't\n"));
2596 so_puts(store, _(" need to press the \"O\" in order to invoke the command.)\n"));
2598 /* put this down here for people who don't have exceptions */
2599 if(!exc){
2600 so_puts(store, "\n");
2601 so_puts(store, _("(X) eXceptions:\n"));
2602 so_puts(store, _(" This command is different from the rest. It is not actually a command\n"));
2603 so_puts(store, _(" itself. Instead, it is a toggle which modifies the behavior of the\n"));
2604 so_puts(store, _(" other commands. You toggle Exceptions editing on and off with this\n"));
2605 so_puts(store, _(" command. When it is off you will be editing (changing) your regular\n"));
2606 so_puts(store, _(" configuration file. When it is on you will be editing your exceptions\n"));
2607 so_puts(store, _(" configuration file. For example, you might want to type the command \n"));
2608 so_puts(store, _(" \"eXceptions\" followed by \"Kolor\" to setup different screen colors\n"));
2609 so_puts(store, _(" on a particular platform.\n"));
2610 so_puts(store, _(" (Note: this command does not do anything unless you have a configuration\n"));
2611 so_puts(store, _(" with exceptions enabled (you don't have that). Common ways to enable an\n"));
2612 so_puts(store, _(" exceptions config are the command line argument \"-x <exception_config>\";\n"));
2613 so_puts(store, _(" or the existence of the file \".pinercex\" for Unix Alpine, or \"PINERCEX\")\n"));
2614 so_puts(store, _(" for PC-Alpine.)\n"));
2615 so_puts(store, _(" (Another note: this command does not show up on the keymenu at the bottom\n"));
2616 so_puts(store, _(" of the screen unless you press \"O\" for \"Other Commands\" --but you\n"));
2617 so_puts(store, _(" don't need to press the \"O\" in order to invoke the command.)\n"));
2620 memset(&sargs, 0, sizeof(SCROLL_S));
2621 sargs.text.text = so_text(store);
2622 sargs.text.src = CharStar;
2623 sargs.text.desc = _("Information About Setup Command");
2624 sargs.bar.title = cpystr(_("SETUP"));
2625 sargs.proc.tool = choose_setup_cmd;
2626 sargs.help.text = NO_HELP;
2627 sargs.help.title = NULL;
2628 sargs.keys.menu = &choose_setup_keymenu;
2629 sargs.keys.menu->how_many = 2;
2631 setbitmap(sargs.keys.bitmap);
2632 if(!printer)
2633 clrbitn(SETUP_PRINTER, sargs.keys.bitmap);
2635 if(!passwd)
2636 clrbitn(SETUP_PASSWD, sargs.keys.bitmap);
2638 if(!config)
2639 clrbitn(SETUP_CONFIG, sargs.keys.bitmap);
2641 if(!sig)
2642 clrbitn(SETUP_SIG, sargs.keys.bitmap);
2644 if(!dir)
2645 clrbitn(SETUP_DIRECTORY, sargs.keys.bitmap);
2647 if(!smime)
2648 clrbitn(SETUP_SMIME, sargs.keys.bitmap);
2650 if(exc)
2651 menu_init_binding(sargs.keys.menu, 'x', MC_EXCEPT, "X",
2652 N_("eXceptions"), SETUP_EXCEPT);
2653 else
2654 menu_init_binding(sargs.keys.menu, 'x', MC_NO_EXCEPT, "X",
2655 N_("eXceptions"), SETUP_EXCEPT);
2658 scrolltool(&sargs);
2660 ps->mangled_screen = 1;
2662 srv = (SRV_S *)sargs.proc.data.p;
2664 exceptions = srv ? srv->exc : 0;
2666 so_give(&store);
2668 if(sargs.bar.title) fs_give((void**)&sargs.bar.title);
2669 if(srv){
2670 ret = srv->cmd;
2671 fs_give((void **)&sargs.proc.data.p);
2673 else
2674 ret = 'e';
2676 return(ret | (exceptions ? EDIT_EXCEPTION : 0));
2680 /*----------------------------------------------------------------------
2682 Args: command -- command char to perform
2684 ----*/
2685 void
2686 do_setup_task(int command)
2688 char *err = NULL;
2689 int rtype;
2690 int edit_exceptions = 0;
2691 int do_lit_sig = 0;
2693 if(command & EDIT_EXCEPTION){
2694 edit_exceptions = 1;
2695 command &= ~EDIT_EXCEPTION;
2698 switch(command) {
2699 /*----- EDIT SIGNATURE -----*/
2700 case 's':
2701 if(ps_global->VAR_LITERAL_SIG)
2702 do_lit_sig = 1;
2703 else {
2704 char sig_path[MAXPATH+1];
2706 if(!signature_path(ps_global->VAR_SIGNATURE_FILE, sig_path, MAXPATH))
2707 do_lit_sig = 1;
2708 else if((!IS_REMOTE(ps_global->VAR_SIGNATURE_FILE)
2709 && can_access(sig_path, READ_ACCESS) == 0)
2710 ||(IS_REMOTE(ps_global->VAR_SIGNATURE_FILE)
2711 && (folder_exists(NULL, sig_path) & FEX_ISFILE)))
2712 do_lit_sig = 0;
2713 else if(!ps_global->vars[V_SIGNATURE_FILE].main_user_val.p
2714 && !ps_global->vars[V_SIGNATURE_FILE].cmdline_val.p
2715 && !ps_global->vars[V_SIGNATURE_FILE].fixed_val.p)
2716 do_lit_sig = 1;
2717 else
2718 do_lit_sig = 0;
2721 if(do_lit_sig){
2722 char *result = NULL;
2723 char **apval;
2724 EditWhich ew;
2725 int readonly = 0;
2727 ew = edit_exceptions ? ps_global->ew_for_except_vars : Main;
2729 if(ps_global->restricted)
2730 readonly = 1;
2731 else switch(ew){
2732 case Main:
2733 readonly = ps_global->prc->readonly;
2734 break;
2735 case Post:
2736 readonly = ps_global->post_prc->readonly;
2737 break;
2738 default:
2739 break;
2742 if(readonly)
2743 err = cpystr(ps_global->restricted
2744 ? "Alpine demo can't change config file"
2745 : _("Config file not changeable"));
2747 if(!err){
2748 apval = APVAL(&ps_global->vars[V_LITERAL_SIG], ew);
2749 if(!apval)
2750 err = cpystr(_("Problem accessing configuration"));
2751 else{
2752 char *input;
2754 input = (char *)fs_get((strlen(*apval ? *apval : "")+1) *
2755 sizeof(char));
2756 input[0] = '\0';
2757 cstring_to_string(*apval, input);
2758 err = signature_edit_lit(input, &result,
2759 _("SIGNATURE EDITOR"),
2760 h_composer_sigedit);
2761 fs_give((void **)&input);
2765 if(!err){
2766 char *cstring_version;
2768 cstring_version = string_to_cstring(result);
2770 set_variable(V_LITERAL_SIG, cstring_version, 0, 0, ew);
2772 if(cstring_version)
2773 fs_give((void **)&cstring_version);
2776 if(result)
2777 fs_give((void **)&result);
2779 else
2780 err = signature_edit(ps_global->VAR_SIGNATURE_FILE,
2781 _("SIGNATURE EDITOR"));
2783 if(err){
2784 q_status_message(SM_ORDER, 3, 4, err);
2785 fs_give((void **)&err);
2788 ps_global->mangled_screen = 1;
2789 break;
2791 /*----- ADD ADDRESSBOOK ----*/
2792 case 'a':
2793 addr_book_config(ps_global, edit_exceptions);
2794 menu_index = ABOOK_MENU_ITEM;
2795 ps_global->mangled_screen = 1;
2796 break;
2798 #ifdef ENABLE_LDAP
2799 /*--- ADD DIRECTORY SERVER --*/
2800 case 'd':
2801 directory_config(ps_global, edit_exceptions);
2802 ps_global->mangled_screen = 1;
2803 break;
2804 #endif
2806 #ifdef SMIME
2807 /*--- S/MIME --*/
2808 case 'm':
2809 smime_config_screen(ps_global, edit_exceptions);
2810 ps_global->mangled_screen = 1;
2811 break;
2812 #endif
2814 /*----- CONFIGURE OPTIONS -----*/
2815 case 'c':
2816 option_screen(ps_global, edit_exceptions);
2817 ps_global->mangled_screen = 1;
2818 break;
2820 /*----- XOAUTH2 CLIENT CONFIGURATION -----*/
2821 case 'u':
2822 alpine_xoauth2_configuration(ps_global, edit_exceptions);
2823 ps_global->mangled_screen = 1;
2824 break;
2826 /*----- COLLECTION LIST -----*/
2827 case 'l':
2828 folder_config_screen(ps_global, edit_exceptions);
2829 ps_global->mangled_screen = 1;
2830 break;
2832 /*----- RULES -----*/
2833 case 'r':
2834 rtype = rule_setup_type(ps_global, RS_RULES | RS_INCFILTNOW,
2835 _("Type of rule setup : "));
2836 switch(rtype){
2837 case 'r':
2838 case 's':
2839 case 'i':
2840 case 'f':
2841 case 'o':
2842 case 'c':
2843 role_config_screen(ps_global, (rtype == 'r') ? ROLE_DO_ROLES :
2844 (rtype == 's') ? ROLE_DO_SCORES :
2845 (rtype == 'o') ? ROLE_DO_OTHER :
2846 (rtype == 'f') ? ROLE_DO_FILTER :
2847 (rtype == 'c') ? ROLE_DO_SRCH :
2848 ROLE_DO_INCOLS,
2849 edit_exceptions);
2850 break;
2852 case 'Z':
2853 q_status_message(SM_ORDER | SM_DING, 3, 5,
2854 _("Try turning on color with the Setup/Kolor command."));
2855 break;
2857 case 'n':
2858 role_process_filters();
2859 break;
2861 default:
2862 cmd_cancelled(NULL);
2863 break;
2866 ps_global->mangled_screen = 1;
2867 break;
2869 /*----- COLOR -----*/
2870 case 'k':
2871 color_config_screen(ps_global, edit_exceptions);
2872 ps_global->mangled_screen = 1;
2873 break;
2875 case 'z':
2876 convert_to_remote_config(ps_global, edit_exceptions);
2877 ps_global->mangled_screen = 1;
2878 break;
2880 /*----- EXIT -----*/
2881 case 'e':
2882 break;
2884 /*----- NEW PASSWORD -----*/
2885 case 'n':
2886 #ifdef PASSWD_PROG
2887 if(ps_global->restricted){
2888 q_status_message(SM_ORDER, 3, 5,
2889 "Password change unavailable in restricted demo version of Alpine.");
2890 }else {
2891 change_passwd();
2892 ClearScreen();
2893 ps_global->mangled_screen = 1;
2895 #else
2896 q_status_message(SM_ORDER, 0, 5,
2897 _("Password changing not configured for this version of Alpine."));
2898 display_message('x');
2899 #endif /* DOS */
2900 break;
2902 #if !defined(DOS)
2903 /*----- CHOOSE PRINTER ------*/
2904 case 'p':
2905 select_printer(ps_global, edit_exceptions);
2906 ps_global->mangled_screen = 1;
2907 break;
2908 #endif
2914 rule_setup_type(struct pine *ps, int flags, char *prompt)
2916 ESCKEY_S opts[9];
2917 int ekey_num = 0, deefault = 0;
2919 if(flags & RS_INCADDR){
2920 deefault = 'a';
2921 opts[ekey_num].ch = 'a';
2922 opts[ekey_num].rval = 'a';
2923 opts[ekey_num].name = "A";
2924 opts[ekey_num++].label = "Addrbook";
2927 if(flags & RS_RULES){
2929 if(F_OFF(F_DISABLE_ROLES_SETUP,ps)){ /* roles are allowed */
2930 if(deefault != 'a')
2931 deefault = 'r';
2933 opts[ekey_num].ch = 'r';
2934 opts[ekey_num].rval = 'r';
2935 opts[ekey_num].name = "R";
2936 opts[ekey_num++].label = "Roles";
2938 else if(deefault != 'a')
2939 deefault = 's';
2941 opts[ekey_num].ch = 's';
2942 opts[ekey_num].rval = 's';
2943 opts[ekey_num].name = "S";
2944 opts[ekey_num++].label = "SetScores";
2946 #ifndef _WINDOWS
2947 if(ps->color_style != COL_NONE && pico_hascolor()){
2948 #endif
2949 if(deefault != 'a')
2950 deefault = 'i';
2952 opts[ekey_num].ch = 'i';
2953 opts[ekey_num].rval = 'i';
2954 opts[ekey_num].name = "I";
2955 opts[ekey_num++].label = "Indexcolor";
2956 #ifndef _WINDOWS
2958 else{
2959 opts[ekey_num].ch = 'i';
2960 opts[ekey_num].rval = 'Z'; /* notice this rval! */
2961 opts[ekey_num].name = "I";
2962 opts[ekey_num++].label = "Indexcolor";
2964 #endif
2966 opts[ekey_num].ch = 'f';
2967 opts[ekey_num].rval = 'f';
2968 opts[ekey_num].name = "F";
2969 opts[ekey_num++].label = "Filters";
2971 opts[ekey_num].ch = 'o';
2972 opts[ekey_num].rval = 'o';
2973 opts[ekey_num].name = "O";
2974 opts[ekey_num++].label = "Other";
2976 opts[ekey_num].ch = 'c';
2977 opts[ekey_num].rval = 'c';
2978 opts[ekey_num].name = "C";
2979 opts[ekey_num++].label = "searCh";
2983 if(flags & RS_INCEXP){
2984 opts[ekey_num].ch = 'e';
2985 opts[ekey_num].rval = 'e';
2986 opts[ekey_num].name = "E";
2987 opts[ekey_num++].label = "Export";
2990 if(flags & RS_INCFILTNOW){
2991 opts[ekey_num].ch = 'n';
2992 opts[ekey_num].rval = 'n';
2993 opts[ekey_num].name = "N";
2994 opts[ekey_num++].label = "filterNow";
2997 opts[ekey_num].ch = -1;
2999 return(radio_buttons(prompt, -FOOTER_ROWS(ps), opts,
3000 deefault, 'x', NO_HELP, RB_NORM));
3006 * Process the command list, changing function key notation into
3007 * lexical equivalents.
3009 void
3010 process_init_cmds(struct pine *ps, char **list)
3012 char **p;
3013 int i = 0;
3014 int j;
3015 int lpm1;
3016 #define MAX_INIT_CMDS 500
3017 /* this is just a temporary stack array, the real one is allocated below */
3018 int i_cmds[MAX_INIT_CMDS];
3019 int fkeys = 0;
3020 int not_fkeys = 0;
3022 if(list){
3023 for(p = list; *p; p++){
3024 if(i >= MAX_INIT_CMDS){
3025 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
3026 "Initial keystroke list too long at \"%s\"", *p);
3027 init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
3028 break;
3032 /* regular character commands */
3033 if(strlen(*p) == 1){
3034 i_cmds[i++] = **p;
3035 not_fkeys++;
3038 /* special commands */
3039 else if(strucmp(*p, "SPACE") == 0)
3040 i_cmds[i++] = ' ';
3041 else if(strucmp(*p, "CR") == 0)
3042 i_cmds[i++] = '\n';
3043 else if(strucmp(*p, "TAB") == 0)
3044 i_cmds[i++] = '\t';
3045 else if(strucmp(*p, "UP") == 0)
3046 i_cmds[i++] = KEY_UP;
3047 else if(strucmp(*p, "DOWN") == 0)
3048 i_cmds[i++] = KEY_DOWN;
3049 else if(strucmp(*p, "LEFT") == 0)
3050 i_cmds[i++] = KEY_LEFT;
3051 else if(strucmp(*p, "RIGHT") == 0)
3052 i_cmds[i++] = KEY_RIGHT;
3054 /* control chars */
3055 else if(strlen(*p) == 2 && **p == '^')
3056 i_cmds[i++] = ctrl(*((*p)+1));
3058 /* function keys */
3059 else if(**p == 'F' || **p == 'f'){
3060 int v;
3062 fkeys++;
3063 v = atoi((*p)+1);
3064 if(v >= 1 && v <= 12)
3065 i_cmds[i++] = PF1 + v - 1;
3066 else
3067 i_cmds[i++] = KEY_JUNK;
3070 /* literal string */
3071 else if(**p == '"' && (*p)[lpm1 = strlen(*p) - 1] == '"'){
3072 if(lpm1 + i - 1 > MAX_INIT_CMDS){
3073 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
3074 "Initial keystroke list too long, truncated at %s\n", *p);
3075 init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
3076 break; /* Bail out of this loop! */
3077 } else
3078 for(j = 1; j < lpm1; j++)
3079 i_cmds[i++] = (*p)[j];
3081 else {
3082 snprintf(tmp_20k_buf,SIZEOF_20KBUF,
3083 "Bad initial keystroke \"%.500s\" (missing comma?)", *p);
3084 init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
3085 break;
3091 * We don't handle the case where function keys are used to specify the
3092 * commands but some non-function key input is also required. For example,
3093 * you might want to jump to a specific message number and view it
3094 * on start up. To do that, you need to use character commands instead
3095 * of function key commands in the initial-keystroke-list.
3097 if(fkeys && not_fkeys){
3098 init_error(ps, SM_ORDER | SM_DING, 3, 5,
3099 "Mixed characters and function keys in \"initial-keystroke-list\", skipping.");
3100 i = 0;
3103 if(fkeys && !not_fkeys)
3104 F_TURN_ON(F_USE_FK,ps);
3105 if(!fkeys && not_fkeys)
3106 F_TURN_OFF(F_USE_FK,ps);
3108 if(i > 0){
3109 ps->initial_cmds = (int *)fs_get((i+1) * sizeof(int));
3110 ps->free_initial_cmds = ps->initial_cmds;
3111 for(j = 0; j < i; j++)
3112 ps->initial_cmds[j] = i_cmds[j];
3114 ps->initial_cmds[i] = 0;
3115 ps->in_init_seq = ps->save_in_init_seq = 1;
3120 UCS *
3121 user_wordseps(char **list)
3123 char **p;
3124 int i = 0;
3125 int j;
3126 #define MAX_SEPARATORS 500
3128 * This is just a temporary stack array, the real one is allocated below.
3129 * This is supposed to be way large enough.
3131 UCS seps[MAX_SEPARATORS+1];
3132 UCS *u;
3133 UCS *return_array = NULL;
3134 size_t l;
3136 seps[0] = '\0';
3138 if(list){
3139 for(p = list; *p; p++){
3140 if(i >= MAX_SEPARATORS){
3141 q_status_message(SM_ORDER | SM_DING, 3, 3,
3142 "Warning: composer-word-separators list is too long");
3143 break;
3146 u = utf8_to_ucs4_cpystr(*p);
3148 if(u){
3149 if(ucs4_strlen(u) == 1)
3150 seps[i++] = *u;
3151 else if(*u == '"' && u[l = ucs4_strlen(u) - 1] == '"'){
3152 if(l + i - 1 > MAX_SEPARATORS){
3153 q_status_message(SM_ORDER | SM_DING, 3, 3,
3154 "Warning: composer-word-separators list is too long");
3155 break; /* Bail out of this loop! */
3157 else{
3158 for(j = 1; j < l; j++)
3159 seps[i++] = u[j];
3162 else{
3163 l = ucs4_strlen(u);
3164 if(l + i > MAX_SEPARATORS){
3165 q_status_message(SM_ORDER | SM_DING, 3, 3,
3166 "Warning: composer-word-separators list is too long");
3167 break; /* Bail out of this loop! */
3169 else{
3170 for(j = 0; j < l; j++)
3171 seps[i++] = u[j];
3175 fs_give((void **) &u);
3180 seps[i] = '\0';
3182 if(i > 0)
3183 return_array = ucs4_cpystr(seps);
3185 return(return_array);
3190 * Make sure any errors during initialization get queued for display
3192 void
3193 queue_init_errors(struct pine *ps)
3195 int i;
3197 if(ps->init_errs){
3198 for(i = 0; (ps->init_errs)[i].message; i++){
3199 q_status_message((ps->init_errs)[i].flags,
3200 (ps->init_errs)[i].min_time,
3201 (ps->init_errs)[i].max_time,
3202 (ps->init_errs)[i].message);
3203 fs_give((void **)&(ps->init_errs)[i].message);
3206 fs_give((void **)&ps->init_errs);
3211 /*----------------------------------------------------------------------
3212 Quit pine if the user wants to
3214 Args: The usual pine structure
3216 Result: User is asked if she wants to quit, if yes then execute quit.
3218 Q U I T S C R E E N
3220 Not really a full screen. Just count up deletions and ask if we really
3221 want to quit.
3222 ----*/
3223 void
3224 quit_screen(struct pine *pine_state)
3226 int quit = 0;
3228 dprint((1, "\n\n ---- QUIT SCREEN ----\n"));
3230 if(F_ON(F_CHECK_MAIL_ONQUIT,ps_global)
3231 && pine_state->mail_stream != NULL
3232 && new_mail(1, VeryBadTime, NM_STATUS_MSG | NM_DEFER_SORT) > 0
3233 && (quit = want_to(_("Quit even though new mail just arrived"), 'y', 0,
3234 NO_HELP, WT_NORM)) != 'y'){
3235 refresh_sort(pine_state->mail_stream, pine_state->msgmap, SRT_VRB);
3236 pine_state->next_screen = pine_state->prev_screen;
3237 return;
3240 if(quit != 'y'
3241 && F_OFF(F_QUIT_WO_CONFIRM,pine_state)
3242 && want_to(_("Really quit Alpine"), 'y', 0, NO_HELP, WT_NORM) != 'y'){
3243 pine_state->next_screen = pine_state->prev_screen;
3244 return;
3247 goodnight_gracey(pine_state, 0);
3251 /*----------------------------------------------------------------------
3252 The nuts and bolts of actually cleaning up and exitting pine
3254 Args: ps -- the usual pine structure,
3255 exit_val -- what to tell our parent
3257 Result: This never returns
3259 ----*/
3260 void
3261 goodnight_gracey(struct pine *pine_state, int exit_val)
3263 int i, cnt_user_streams = 0;
3264 char *final_msg = NULL;
3265 char msg[MAX_SCREEN_COLS+1];
3266 char *pf = _("Alpine finished");
3267 MAILSTREAM *m;
3268 extern KBESC_T *kbesc;
3270 dprint((2, "goodnight_gracey:\n"));
3272 /* We want to do this here before we close up the streams */
3273 trim_remote_adrbks();
3275 for(i = 0; i < ps_global->s_pool.nstream; i++){
3276 m = ps_global->s_pool.streams[i];
3277 if(m && sp_flagged(m, SP_LOCKED) && sp_flagged(m, SP_USERFLDR))
3278 cnt_user_streams++;
3281 /* clean up open streams */
3283 if(pine_state->mail_stream
3284 && sp_flagged(pine_state->mail_stream, SP_LOCKED)
3285 && sp_flagged(pine_state->mail_stream, SP_USERFLDR)){
3286 dprint((5, "goodnight_gracey: close current stream\n"));
3287 expunge_and_close(pine_state->mail_stream,
3288 (cnt_user_streams <= 1) ? &final_msg : NULL, EC_NONE);
3289 cnt_user_streams--;
3292 pine_state->mail_stream = NULL;
3293 pine_state->redrawer = (void (*)(void))NULL;
3295 dprint((5,
3296 "goodnight_gracey: close other stream pool streams\n"));
3297 for(i = 0; i < ps_global->s_pool.nstream; i++){
3298 m = ps_global->s_pool.streams[i];
3300 * fix global for functions that depend(ed) on it sort_folder.
3301 * Hopefully those will get phased out.
3303 ps_global->mail_stream = m;
3304 if(m && sp_flagged(m, SP_LOCKED) && sp_flagged(m, SP_USERFLDR)
3305 && !sp_flagged(m, SP_INBOX)){
3306 sp_set_expunge_count(m, 0L);
3307 expunge_and_close(m, (cnt_user_streams <= 1) ? &final_msg : NULL,
3308 EC_NONE);
3309 cnt_user_streams--;
3313 for(i = 0; i < ps_global->s_pool.nstream; i++){
3314 m = ps_global->s_pool.streams[i];
3316 * fix global for functions that depend(ed) on it (sort_folder).
3317 * Hopefully those will get phased out.
3319 ps_global->mail_stream = m;
3320 if(m && sp_flagged(m, SP_LOCKED) && sp_flagged(m, SP_USERFLDR)
3321 && sp_flagged(m, SP_INBOX)){
3322 dprint((5,
3323 "goodnight_gracey: close inbox stream stream\n"));
3324 sp_set_expunge_count(m, 0L);
3325 expunge_and_close(m, (cnt_user_streams <= 1) ? &final_msg : NULL,
3326 EC_NONE);
3327 cnt_user_streams--;
3331 #ifdef _WINDOWS
3332 if(ps_global->ttyo)
3333 (void)get_windsize(ps_global->ttyo);
3334 #endif
3336 dprint((7, "goodnight_gracey: close config files\n"));
3338 free_pinerc_strings(&pine_state);
3340 strncpy(msg, pf, sizeof(msg));
3341 msg[sizeof(msg)-1] = '\0';
3342 if(final_msg){
3343 strncat(msg, " -- ", sizeof(msg)-strlen(msg)-1);
3344 msg[sizeof(msg)-1] = '\0';
3345 strncat(msg, final_msg, sizeof(msg)-strlen(msg)-1);
3346 msg[sizeof(msg)-1] = '\0';
3347 fs_give((void **)&final_msg);
3350 dprint((7, "goodnight_gracey: sp_end\n"));
3351 ps_global->noshow_error = 1;
3352 sp_end();
3354 #ifdef SMIME
3355 smime_deinit();
3356 #endif
3358 /* after sp_end, which might call a filter */
3359 completely_done_with_adrbks();
3361 dprint((7, "goodnight_gracey: end_screen\n"));
3362 end_screen(msg, exit_val);
3363 dprint((7, "goodnight_gracey: end_titlebar\n"));
3364 end_titlebar();
3365 dprint((7, "goodnight_gracey: end_keymenu\n"));
3366 end_keymenu();
3368 dprint((7, "goodnight_gracey: end_keyboard\n"));
3369 end_keyboard(F_ON(F_USE_FK,pine_state));
3370 dprint((7, "goodnight_gracey: end_ttydriver\n"));
3371 end_tty_driver(pine_state);
3372 #if !defined(DOS) && !defined(OS2)
3373 kbdestroy(kbesc);
3374 #if !defined(LEAVEOUTFIFO)
3375 close_newmailfifo();
3376 #endif
3377 #endif
3378 end_signals(0);
3379 if(filter_data_file(0))
3380 our_unlink(filter_data_file(0));
3382 imap_flush_passwd_cache(TRUE);
3383 free_newsgrp_cache();
3384 mailcap_free();
3385 close_every_pattern();
3386 free_extra_hdrs();
3387 free_contexts(&ps_global->context_list);
3388 free_charsetchecker();
3389 dprint((7, "goodnight_gracey: free more memory\n"));
3390 #ifdef ENABLE_LDAP
3391 free_saved_query_parameters();
3392 #endif
3394 html_dir_clean(1); /* force remove of remaining files */
3395 free_pine_struct(&pine_state);
3397 free_histlist();
3399 free_alpine_module_globals(); /* should we have module globals? */
3400 free_pith_module_globals();
3401 free_pico_module_globals();
3402 free_c_client_module_globals();
3404 #ifdef DEBUG
3405 if(debugfile){
3406 if(debug >= 2)
3407 fputs("goodnight_gracey finished\n", debugfile);
3409 fclose(debugfile);
3411 #endif
3413 exit(exit_val);
3417 /*----------------------------------------------------------------------
3418 Call back for c-client to feed us back the progress of network reads
3420 Input:
3422 Result:
3423 ----*/
3424 void
3425 pine_read_progress(GETS_DATA *md, long unsigned int count)
3427 gets_bytes += count; /* update counter */
3431 /*----------------------------------------------------------------------
3432 Function to fish the current byte count from a c-client fetch.
3434 Input: reset -- flag telling us to reset the count
3436 Result: Returns the number of bytes read by the c-client so far
3437 ----*/
3438 unsigned long
3439 pine_gets_bytes(int reset)
3441 if(reset)
3442 gets_bytes = 0L;
3444 return(gets_bytes);
3448 /*----------------------------------------------------------------------
3449 Panic pine - call on detected programmatic errors to exit pine
3451 Args: message -- message to record in debug file and to be printed for user
3453 Result: The various tty modes are restored
3454 If debugging is active a core dump will be generated
3455 Exits Alpine
3457 This is also called from imap routines and fs_get and fs_resize.
3458 ----*/
3459 void
3460 alpine_panic(char *message)
3462 char buf[256];
3464 /* global variable in .../pico/edef.h */
3465 in_panic = 1;
3467 if(ps_global->ttyo){
3468 end_screen(NULL, -1);
3469 end_keyboard(ps_global != NULL ? F_ON(F_USE_FK,ps_global) : 0);
3470 end_tty_driver(ps_global);
3471 end_signals(1);
3473 if(filter_data_file(0))
3474 our_unlink(filter_data_file(0));
3476 dprint((1, "\n===========================================\n\n"));
3477 dprint((1, " Alpine Panic: %s\n\n", message ? message : "?"));
3478 dprint((1, "===========================================\n\n"));
3480 /* intercept c-client "free storage" errors */
3481 if(strstr(message, "free storage"))
3482 snprintf(buf, sizeof(buf), _("No more available memory.\nAlpine Exiting"));
3483 else
3484 snprintf(buf, sizeof(buf), _("Problem detected: \"%s\".\nAlpine Exiting."), message);
3486 buf[sizeof(buf)-1] = '\0';
3488 #ifdef _WINDOWS
3489 /* Put up a message box. */
3490 mswin_messagebox (buf, 1);
3491 #else
3492 fprintf(stderr, "\n\n%s\n", buf);
3493 #endif
3495 #ifdef DEBUG
3496 if(debugfile){
3497 save_debug_on_crash(debugfile, recent_keystroke);
3500 coredump(); /*--- If we're debugging get a core dump --*/
3501 #endif
3503 exit(-1);
3504 fatal("ffo"); /* BUG -- hack to get fatal out of library in right order*/
3509 * panicking - function to test whether or not we're exiting under stress.
3513 panicking(void)
3515 return(in_panic);
3519 /*----------------------------------------------------------------------
3520 exceptional_exit - called to exit under unusual conditions (with no core)
3522 Args: message -- message to record in debug file and to be printed for user
3523 ev -- exit value
3525 ----*/
3526 void
3527 exceptional_exit(char *message, int ev)
3529 fprintf(stderr, "%s\n", message);
3530 exit(ev);
3535 * PicoText Storage Object Support Routines
3538 STORE_S *
3539 pine_pico_get(void)
3541 return((STORE_S *)pico_get());
3545 pine_pico_give(STORE_S **sop)
3547 pico_give((void *)sop);
3548 return(1);
3552 pine_pico_writec(int c, STORE_S *so)
3554 unsigned char ch = (unsigned char) c;
3556 return(pico_writec(so->txt, ch, PICOREADC_NONE));
3560 pine_pico_writec_noucs(int c, STORE_S *so)
3562 unsigned char ch = (unsigned char) c;
3564 return(pico_writec(so->txt, ch, PICOREADC_NOUCS));
3568 pine_pico_readc(unsigned char *c, STORE_S *so)
3570 return(pico_readc(so->txt, c, PICOREADC_NONE));
3574 pine_pico_readc_noucs(unsigned char *c, STORE_S *so)
3576 return(pico_readc(so->txt, c, PICOREADC_NOUCS));
3580 pine_pico_puts(STORE_S *so, char *s)
3582 return(pico_puts(so->txt, s, PICOREADC_NONE));
3586 pine_pico_puts_noucs(STORE_S *so, char *s)
3588 return(pico_puts(so->txt, s, PICOREADC_NOUCS));
3592 pine_pico_seek(STORE_S *so, long pos, int orig)
3594 return(pico_seek((void *)so, pos, orig));
3599 remote_pinerc_failure(void)
3601 #ifdef _WINDOWS
3602 if(ps_global->install_flag) /* just exit silently */
3603 exit(0);
3604 #endif /* _WINDOWS */
3606 if(ps_global->exit_if_no_pinerc){
3607 exceptional_exit("Exiting because -bail option is set and config file not readable.", -1);
3610 if(want_to("Trouble reading remote configuration! Continue anyway ",
3611 'n', 'n', NO_HELP, WT_FLUSH_IN) != 'y'){
3612 return(0);
3615 return(1);
3619 void
3620 dump_supported_options(void)
3622 char **config;
3624 config = get_supported_options();
3625 if(config){
3626 display_args_err(NULL, config, 0);
3627 free_list_array(&config);
3632 /*----------------------------------------------------------------------
3633 Check pruned-folders for validity, making sure they are in the
3634 same context as sent-mail.
3636 ----*/
3638 prune_folders_ok(void)
3640 char **p;
3642 for(p = ps_global->VAR_PRUNED_FOLDERS; p && *p && **p; p++)
3643 if(!context_isambig(*p))
3644 return(0);
3646 return(1);
3649 void
3650 free_alpine_module_globals(void)
3652 #ifdef LOCAL_PASSWD_CACHE
3653 free_passfile_cache();
3654 #endif
3655 free_message_queue();
3656 free_titlebar_globals();
3659 #ifdef WIN32
3660 char *
3661 pine_user_callback()
3663 if(ps_global->VAR_USER_ID && ps_global->VAR_USER_ID[0]){
3664 return(ps_global->VAR_USER_ID);
3666 else{
3667 /* SHOULD PROMPT HERE! */
3668 return(NULL);
3671 #endif
3673 #ifdef _WINDOWS
3675 * windows callback to get/set function keys mode state
3678 fkey_mode_callback(set, args)
3679 int set;
3680 long args;
3682 return(F_ON(F_USE_FK, ps_global) != 0);
3686 void
3687 imap_telemetry_on()
3689 if(ps_global->mail_stream)
3690 mail_debug(ps_global->mail_stream);
3694 void
3695 imap_telemetry_off()
3697 if(ps_global->mail_stream)
3698 mail_nodebug(ps_global->mail_stream);
3702 char *
3703 pcpine_help_main(title)
3704 char *title;
3706 if(title)
3707 strncpy(title, _("PC-Alpine MAIN MENU Help"), 256);
3709 return(pcpine_help(main_menu_tx));
3714 pcpine_main_cursor(col, row)
3715 int col;
3716 long row;
3718 unsigned ndmi;
3720 if (row >= (HEADER_ROWS(ps_global) + MNSKIP(ps_global)))
3721 ndmi = (row+1 - HEADER_ROWS(ps_global) - (MNSKIP(ps_global)+1))/(MNSKIP(ps_global)+1);
3723 if (row >= (HEADER_ROWS(ps_global) + MNSKIP(ps_global))
3724 && !(MNSKIP(ps_global) && (row+1) & 0x01)
3725 && ndmi <= MAX_MENU_ITEM
3726 && FOOTER_ROWS(ps_global) + (ndmi+1)*(MNSKIP(ps_global)+1)
3727 + MNSKIP(ps_global) + FOOTER_ROWS(ps_global) <= ps_global->ttyo->screen_rows)
3728 return(MSWIN_CURSOR_HAND);
3729 else
3730 return(MSWIN_CURSOR_ARROW);
3732 #endif /* _WINDOWS */