* Patches from MichaƂ Dardas and Mateusz Kocielski from LogicalTrust
[alpine.git] / alpine / alpine.c
blobe0a914ae0c0ccd60ff4824a87f513c15eeed55f1
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-2018 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 "radio.h"
45 #include "folder.h"
46 #include "send.h"
47 #include "help.h"
48 #include "titlebar.h"
49 #include "takeaddr.h"
50 #include "dispfilt.h"
51 #include "init.h"
52 #include "remote.h"
53 #include "pattern.h"
54 #include "setup.h"
55 #include "newuser.h"
56 #include "adrbkcmd.h"
57 #include "signal.h"
58 #include "kblock.h"
59 #include "ldapconf.h"
60 #include "roleconf.h"
61 #include "colorconf.h"
62 #include "print.h"
63 #include "after.h"
64 #include "smime.h"
65 #include "newmail.h"
66 #ifndef _WINDOWS
67 #include "../pico/osdep/raw.h" /* for STD*_FD */
68 #endif
71 #define PIPED_FD 5 /* Some innocuous desc */
74 /* look for my_timer_period in pico directory for an explanation */
75 int my_timer_period = ((IDLE_TIMEOUT + 1)*1000);
77 /* byte count used by our gets routine to keep track */
78 static unsigned long gets_bytes;
82 * Internal prototypes
84 void convert_args_to_utf8(struct pine *, ARGDATA_S *);
85 void preopen_stayopen_folders(void);
86 int read_stdin_char(char *);
87 void main_redrawer(void);
88 void show_main_screen(struct pine *, int, OtherMenu, struct key_menu *, int, Pos *);
89 void do_menu(int, Pos *, struct key_menu *);
90 int choose_setup_cmd(int, MSGNO_S *, SCROLL_S *);
91 int setup_menu(struct pine *);
92 void do_setup_task(int);
93 void queue_init_errors(struct pine *);
94 void process_init_cmds(struct pine *, char **);
95 void goodnight_gracey(struct pine *, int);
96 void pine_read_progress(GETS_DATA *, unsigned long);
97 int remote_pinerc_failure(void);
98 void dump_supported_options(void);
99 int prune_folders_ok(void);
100 void free_alpine_module_globals(void);
101 #ifdef WIN32
102 char *pine_user_callback(void);
103 #endif
104 #ifdef _WINDOWS
105 int fkey_mode_callback(int, long);
106 void imap_telemetry_on(void);
107 void imap_telemetry_off(void);
108 char *pcpine_help_main(char *);
109 int pcpine_main_cursor(int, long);
110 #define main app_main
111 #endif
114 typedef struct setup_return_val {
115 int cmd;
116 int exc;
117 }SRV_S;
121 * strlen of longest label from keymenu, of labels corresponding to
122 * commands in the middle of the screen. 9 is length of ListFldrs
124 #define LONGEST_LABEL 9 /* length of longest label from keymenu */
126 #define EDIT_EXCEPTION (0x100)
129 static int in_panic = 0;
132 /*----------------------------------------------------------------------
133 main routine -- entry point
135 Args: argv, argc -- The command line arguments
138 Initialize pine, parse arguments and so on
140 If there is a user address on the command line go into send mode and exit,
141 otherwise loop executing the various screens in Alpine.
143 NOTE: The Windows port def's this to "app_main"
144 ----*/
147 main(int argc, char **argv)
149 ARGDATA_S args;
150 int rv;
151 long rvl;
152 struct pine *pine_state;
153 gf_io_t stdin_getc = NULL;
154 char *args_for_debug = NULL, *init_pinerc_debugging = NULL;
156 /*----------------------------------------------------------------------
157 Set up buffering and some data structures
158 ----------------------------------------------------------------------*/
160 pine_state = new_pine_struct();
161 pine_state->id = fs_get(sizeof(IDLIST));
162 pine_state->id->name = cpystr("name");
163 pine_state->id->value = cpystr(PACKAGE_NAME);
164 pine_state->id->next = fs_get(sizeof(IDLIST));
165 pine_state->id->next->name = cpystr("version");
166 pine_state->id->next->value = cpystr(PACKAGE_VERSION);
167 pine_state->id->next->next = NULL;
168 mail_parameters(NULL, SET_IDPARAMS, (void *) pine_state->id);
169 ps_global = pine_state;
172 * fill in optional pith-offered behavior hooks
174 pith_opt_read_msg_prompt = read_msg_prompt;
175 pith_opt_paint_index_hline = paint_index_hline;
176 pith_opt_rfc2369_editorial = rfc2369_editorial;
177 pith_opt_condense_thread_cue = condensed_thread_cue;
178 pith_opt_truncate_sfstr = truncate_subj_and_from_strings;
179 pith_opt_save_and_restore = save_and_restore;
180 pith_opt_newmail_announce = newmail_status_message;
181 pith_opt_newmail_check_cue = newmail_check_cue;
182 pith_opt_checkpoint_cue = newmail_check_point_cue;
183 pith_opt_icon_text = icon_text;
184 pith_opt_rd_metadata_name = rd_metadata_name;
185 pith_opt_remote_pinerc_failure = remote_pinerc_failure;
186 pith_opt_reopen_folder = ask_mailbox_reopen;
187 pith_opt_expunge_prompt = expunge_prompt;
188 pith_opt_begin_closing = expunge_and_close_begins;
189 pith_opt_replyto_prompt = reply_using_replyto_query;
190 pith_opt_reply_to_all_prompt = reply_to_all_query;
191 pith_opt_save_create_prompt = create_for_save_prompt;
192 pith_opt_daemon_confirm = confirm_daemon_send;
193 pith_opt_save_size_changed_prompt = save_size_changed_prompt;
194 pith_opt_save_index_state = setup_index_state;
195 pith_opt_filter_pattern_cmd = pattern_filter_command;
196 pith_opt_get_signature_file = get_signature_file;
197 pith_opt_pretty_var_name = pretty_var_name;
198 pith_opt_pretty_feature_name = pretty_feature_name;
199 pith_opt_closing_stream = titlebar_stream_closing;
200 pith_opt_current_expunged = mm_expunged_current;
201 #ifdef SMIME
202 pith_opt_smime_get_passphrase = smime_get_passphrase;
203 pith_smime_import_certificate = smime_import_certificate;
204 pith_smime_enter_password = alpine_get_password;
205 pith_smime_confirm_save = alpine_smime_confirm_save;
206 #endif
207 #ifdef ENABLE_LDAP
208 pith_opt_save_ldap_entry = save_ldap_entry;
209 #endif
211 status_message_lock_init();
212 inverse_itokens();
214 #if HAVE_SRANDOM
216 * Seed the random number generator with the date & pid. Random
217 * numbers are used for new mail notification and bug report id's
219 srandom(getpid() + time(0));
220 #endif
222 /* need home directory early */
223 get_user_info(&ps_global->ui);
225 if(!(pine_state->home_dir = our_getenv("HOME")))
226 pine_state->home_dir = cpystr(ps_global->ui.homedir);
228 #ifdef _WINDOWS
230 char *p;
232 /* normalize path delimiters */
233 for(p = pine_state->home_dir; p = strchr(p, '/'); p++)
234 *p='\\';
236 #endif /* _WINDOWS */
238 #ifdef DEBUG
239 { size_t len = 0;
240 int i;
241 char *p;
242 char *no_args = " <no args>";
244 for(i = 0; i < argc; i++)
245 len += (strlen(argv[i] ? argv[i] : "")+3);
247 if(argc == 1)
248 len += strlen(no_args);
250 p = args_for_debug = (char *)fs_get((len+2) * sizeof(char));
251 *p++ = '\n';
252 *p = '\0';
254 for(i = 0; i < argc; i++){
255 snprintf(p, len+2-(p-args_for_debug), "%s\"%s\"", i ? " " : "", argv[i] ? argv[i] : "");
256 args_for_debug[len+2-1] = '\0';
257 p += strlen(p);
260 if(argc == 1){
261 strncat(args_for_debug, no_args, len+2-strlen(args_for_debug)-1);
262 args_for_debug[len+2-1] = '\0';
265 #endif
267 /*----------------------------------------------------------------------
268 Parse arguments and initialize debugging
269 ----------------------------------------------------------------------*/
270 pine_args(pine_state, argc, argv, &args);
272 #ifndef _WINDOWS
273 if(!isatty(0)){
275 * monkey with descriptors so our normal tty i/o routines don't
276 * choke...
278 dup2(STDIN_FD, PIPED_FD); /* redirected stdin to new desc */
279 dup2(STDERR_FD, STDIN_FD); /* rebind stdin to the tty */
280 stdin_getc = read_stdin_char;
281 if(stdin_getc){
282 if(args.action == aaURL){
283 display_args_err(
284 "Cannot read stdin when using -url\nFor mailto URLs, use \'body=\' instead",
285 NULL, 1);
286 args_help();
287 exit(-1);
288 } else if (args.action == aaFolder){
289 display_args_err("Cannot take input from pipe when opening a folder", NULL, 1);
290 args_help();
291 exit(-1);
296 #else /* _WINDOWS */
298 * We now have enough information to do some of the basic registry settings.
300 if(ps_global->update_registry != UREG_NEVER_SET){
301 mswin_reg(MSWR_OP_SET
302 | ((ps_global->update_registry == UREG_ALWAYS_SET)
303 ? MSWR_OP_FORCE : 0),
304 MSWR_PINE_DIR, ps_global->pine_dir, (size_t)NULL);
305 mswin_reg(MSWR_OP_SET
306 | ((ps_global->update_registry == UREG_ALWAYS_SET)
307 ? MSWR_OP_FORCE : 0),
308 MSWR_PINE_EXE, ps_global->pine_name, (size_t)NULL);
311 #endif /* _WINDOWS */
313 if(ps_global->convert_sigs &&
314 (!ps_global->pinerc || !ps_global->pinerc[0])){
315 fprintf(stderr, "Use -p <pinerc> with -convert_sigs\n");
316 exit(-1);
319 /* Windows has its own functions to determine width of a character
320 * in the screen, so this is not necessary to do in Window, and
321 * using pith_ucs4width does not produce the correct result
323 #if !defined(_WINDOWS) && defined(LC_CTYPE)
324 { char *s;
325 if((s = setlocale(LC_CTYPE, "")) != NULL
326 && strlen(s) >= 5
327 && !strucmp(s+strlen(s)-5, "UTF-8"))
328 mail_parameters(NULL, SET_UCS4WIDTH, (void *) pith_ucs4width);
330 #endif /* !_WINDOWS && LC_CTYPE */
331 mail_parameters(NULL, SET_QUOTA, (void *) pine_parse_quota);
332 /* set some default timeouts in case pinerc is remote */
333 mail_parameters(NULL, SET_OPENTIMEOUT, (void *)(long)30);
334 mail_parameters(NULL, SET_READTIMEOUT, (void *)(long)15);
335 mail_parameters(NULL, SET_TIMEOUT, (void *) pine_tcptimeout);
336 /* could be TO_BAIL_THRESHOLD, 15 seems more appropriate for now */
337 pine_state->tcp_query_timeout = 15;
339 mail_parameters(NULL, SET_SENDCOMMAND, (void *) pine_imap_cmd_happened);
340 mail_parameters(NULL, SET_FREESTREAMSPAREP, (void *) sp_free_callback);
341 mail_parameters(NULL, SET_FREEELTSPAREP, (void *) free_pine_elt);
342 mail_parameters(NULL, SET_FREEBODYSPAREP, (void *) free_body_sparep);
344 init_pinerc(pine_state, &init_pinerc_debugging);
346 #ifdef DEBUG
347 /* Since this is specific debugging we don't mind if the
348 ifdef is the type of system.
350 #if defined(HAVE_SMALLOC) || defined(NXT)
351 if(ps_global->debug_malloc)
352 malloc_debug(ps_global->debug_malloc);
353 #endif
354 #ifdef CSRIMALLOC
355 if(ps_global->debug_malloc)
356 mal_debug(ps_global->debug_malloc);
357 #endif
359 if(!ps_global->convert_sigs
360 #ifdef _WINDOWS
361 && !ps_global->install_flag
362 #endif /* _WINDOWS */
364 init_debug();
366 if(args_for_debug){
367 dprint((0, " %s (PID=%ld)\n\n", args_for_debug,
368 (long) getpid()));
369 fs_give((void **)&args_for_debug);
373 char *env_to_free;
374 if((env_to_free = our_getenv("HOME")) != NULL){
375 dprint((2, "Setting home dir from $HOME: \"%s\"\n",
376 env_to_free));
377 fs_give((void **)&env_to_free);
379 else{
380 dprint((2, "Setting home dir: \"%s\"\n",
381 pine_state->home_dir ? pine_state->home_dir : "<?>"));
385 /* Watch out. Sensitive information in debug file. */
386 if(ps_global->debug_imap > 4)
387 mail_parameters(NULL, SET_DEBUGSENSITIVE, (void *) TRUE);
389 #ifndef DEBUGJOURNAL
390 if(ps_global->debug_tcp)
391 #endif
392 mail_parameters(NULL, SET_TCPDEBUG, (void *) TRUE);
394 #ifdef _WINDOWS
395 mswin_setdebug(debug, debugfile);
396 mswin_setdebugoncallback (imap_telemetry_on);
397 mswin_setdebugoffcallback (imap_telemetry_off);
398 mswin_enableimaptelemetry(ps_global->debug_imap != 0);
399 #endif
400 #endif /* DEBUG */
402 #ifdef _WINDOWS
403 mswin_setsortcallback(index_sort_callback);
404 mswin_setflagcallback(flag_callback);
405 mswin_sethdrmodecallback(header_mode_callback);
406 mswin_setselectedcallback(any_selected_callback);
407 mswin_setzoomodecallback(zoom_mode_callback);
408 mswin_setfkeymodecallback(fkey_mode_callback);
409 #endif
411 /*------- Set up c-client drivers -------*/
412 #include "../c-client/linkage.c"
414 /*------- ... then tune the drivers just installed -------*/
415 #ifdef _WINDOWS
416 if(_tgetenv(TEXT("HOME")))
417 mail_parameters(NULL, SET_HOMEDIR, (void *) pine_state->home_dir);
419 mail_parameters(NULL, SET_USERPROMPT, (void *) pine_user_callback);
422 * Sniff the environment for timezone offset. We need to do this
423 * here since Windows needs help figuring out UTC, and will adjust
424 * what time() returns based on TZ. THIS WILL SCREW US because
425 * we use time() differences to manage status messages. So, if
426 * rfc822_date, which calls localtime() and thus needs tzset(),
427 * is called while a status message is displayed, it's possible
428 * for time() to return a time *before* what we remember as the
429 * time we put the status message on the display. Sheesh.
431 tzset();
432 #else /* !_WINDOWS */
434 * We used to let c-client do this for us automatically, but it declines
435 * to do so for root. This forces c-client to establish an environment,
436 * even if the uid is 0.
438 env_init(ps_global->ui.login, ps_global->ui.homedir);
441 * Install callback to let us know the progress of network reads...
443 (void) mail_parameters(NULL, SET_READPROGRESS, (void *)pine_read_progress);
444 #endif /* !_WINDOWS */
447 * Install callback to handle certificate validation failures,
448 * allowing the user to continue if they wish.
450 mail_parameters(NULL, SET_SSLCERTIFICATEQUERY, (void *) pine_sslcertquery);
451 mail_parameters(NULL, SET_SSLFAILURE, (void *) pine_sslfailure);
453 if(init_pinerc_debugging){
454 dprint((2, "%s", init_pinerc_debugging));
455 fs_give((void **)&init_pinerc_debugging);
459 * Initial allocation of array of stream pool pointers.
460 * We do this before init_vars so that we can re-use streams used for
461 * remote config files. These sizes may get changed later.
463 ps_global->s_pool.max_remstream = 2;
464 dprint((9,
465 "Setting initial max_remstream to %d for remote config re-use\n",
466 ps_global->s_pool.max_remstream));
468 init_vars(pine_state, process_init_cmds);
470 #ifdef SMIME
471 if(F_ON(F_DONT_DO_SMIME, ps_global))
472 smime_deinit();
473 #endif /* SMIME */
475 #ifdef ENABLE_NLS
477 * LC_CTYPE is already set from the set_collation call above.
479 * We can't use gettext calls before we do this stuff so it doesn't
480 * help to translate strings that come before this in the program.
481 * Maybe we could rearrange things to accomodate that.
483 setlocale(LC_MESSAGES, "");
484 bindtextdomain(PACKAGE, LOCALEDIR);
485 bind_textdomain_codeset(PACKAGE, "UTF-8");
486 textdomain(PACKAGE);
487 #endif /* ENABLE_NLS */
489 convert_args_to_utf8(pine_state, &args);
491 if(args.action == aaFolder){
492 pine_state->beginning_of_month = first_run_of_month();
493 pine_state->beginning_of_year = first_run_of_year();
496 /* Set up optional for user-defined display filtering */
497 pine_state->tools.display_filter = dfilter;
498 pine_state->tools.display_filter_trigger = dfilter_trigger;
500 #ifdef _WINDOWS
501 if(ps_global->install_flag){
502 init_install_get_vars();
504 if(ps_global->prc)
505 free_pinerc_s(&ps_global->prc);
507 exit(0);
509 #endif
511 if(ps_global->convert_sigs){
512 if(convert_sigs_to_literal(ps_global, 0) == -1){
513 /* TRANSLATORS: sigs refers to signatures, which the user was trying to convert */
514 fprintf(stderr, _("trouble converting sigs\n"));
515 exit(-1);
518 if(ps_global->prc){
519 if(ps_global->prc->outstanding_pinerc_changes)
520 write_pinerc(ps_global, Main, WRP_NONE);
522 free_pinerc_s(&pine_state->prc);
525 exit(0);
529 * Set up a c-client read timeout and timeout handler. In general,
530 * it shouldn't happen, but a server crash or dead link can cause
531 * pine to appear wedged if we don't set this up...
533 rv = 30;
534 if(pine_state->VAR_TCPOPENTIMEO)
535 (void)SVAR_TCP_OPEN(pine_state, rv, tmp_20k_buf, SIZEOF_20KBUF);
536 mail_parameters(NULL, SET_OPENTIMEOUT, (void *)(long)rv);
538 rv = 15;
539 if(pine_state->VAR_TCPREADWARNTIMEO)
540 (void)SVAR_TCP_READWARN(pine_state, rv, tmp_20k_buf, SIZEOF_20KBUF);
541 mail_parameters(NULL, SET_READTIMEOUT, (void *)(long)rv);
543 rv = 0;
544 if(pine_state->VAR_TCPWRITEWARNTIMEO){
545 if(!SVAR_TCP_WRITEWARN(pine_state, rv, tmp_20k_buf, SIZEOF_20KBUF))
546 if(rv == 0 || rv > 4) /* making sure */
547 mail_parameters(NULL, SET_WRITETIMEOUT, (void *)(long)rv);
550 mail_parameters(NULL, SET_TIMEOUT, (void *) pine_tcptimeout);
552 rv = 15;
553 if(pine_state->VAR_RSHOPENTIMEO){
554 if(!SVAR_RSH_OPEN(pine_state, rv, tmp_20k_buf, SIZEOF_20KBUF))
555 if(rv == 0 || rv > 4) /* making sure */
556 mail_parameters(NULL, SET_RSHTIMEOUT, (void *)(long)rv);
559 rv = 15;
560 if(pine_state->VAR_SSHOPENTIMEO){
561 if(!SVAR_SSH_OPEN(pine_state, rv, tmp_20k_buf, SIZEOF_20KBUF))
562 if(rv == 0 || rv > 4) /* making sure */
563 mail_parameters(NULL, SET_SSHTIMEOUT, (void *)(long)rv);
566 rvl = 60L;
567 if(pine_state->VAR_MAILDROPCHECK){
568 if(!SVAR_MAILDCHK(pine_state, rvl, tmp_20k_buf, SIZEOF_20KBUF)){
569 if(rvl == 0L)
570 rvl = (60L * 60L * 24L * 100L); /* 100 days */
572 if(rvl >= 60L) /* making sure */
573 mail_parameters(NULL, SET_SNARFINTERVAL, (void *) rvl);
578 * Lookups of long login names which don't exist are very slow in aix.
579 * This would normally get set in system-wide config if not needed.
581 if(F_ON(F_DISABLE_SHARED_NAMESPACES, ps_global))
582 mail_parameters(NULL, SET_DISABLEAUTOSHAREDNS, (void *) TRUE);
584 if(F_ON(F_HIDE_NNTP_PATH, ps_global))
585 mail_parameters(NULL, SET_NNTPHIDEPATH, (void *) TRUE);
587 if(F_ON(F_MAILDROPS_PRESERVE_STATE, ps_global))
588 mail_parameters(NULL, SET_SNARFPRESERVE, (void *) TRUE);
590 rvl = 0L;
591 if(pine_state->VAR_NNTPRANGE){
592 if(!SVAR_NNTPRANGE(pine_state, rvl, tmp_20k_buf, SIZEOF_20KBUF))
593 if(rvl > 0L)
594 mail_parameters(NULL, SET_NNTPRANGE, (void *) rvl);
598 * Tell c-client not to be so aggressive about uid mappings
600 mail_parameters(NULL, SET_UIDLOOKAHEAD, (void *) 20);
603 * Setup referral handling
605 mail_parameters(NULL, SET_IMAPREFERRAL, (void *) imap_referral);
606 mail_parameters(NULL, SET_MAILPROXYCOPY, (void *) imap_proxycopy);
609 * Setup multiple newsrc transition
611 mail_parameters(NULL, SET_NEWSRCQUERY, (void *) pine_newsrcquery);
614 * Disable some drivers if requested.
616 if(ps_global->VAR_DISABLE_DRIVERS &&
617 ps_global->VAR_DISABLE_DRIVERS[0] &&
618 ps_global->VAR_DISABLE_DRIVERS[0][0]){
619 char **t;
621 for(t = ps_global->VAR_DISABLE_DRIVERS; t[0] && t[0][0]; t++)
622 if(mail_parameters(NULL, DISABLE_DRIVER, (void *)(*t))){
623 dprint((2, "Disabled mail driver \"%s\"\n", *t));
625 else{
626 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
627 _("Failed to disable mail driver \"%s\": name not found"),
628 *t);
629 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
630 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
635 * Disable some authenticators if requested.
637 if(ps_global->VAR_DISABLE_AUTHS &&
638 ps_global->VAR_DISABLE_AUTHS[0] &&
639 ps_global->VAR_DISABLE_AUTHS[0][0]){
640 char **t;
642 for(t = ps_global->VAR_DISABLE_AUTHS; t[0] && t[0][0]; t++)
643 if(mail_parameters(NULL, DISABLE_AUTHENTICATOR, (void *)(*t))){
644 dprint((2,"Disabled SASL authenticator \"%s\"\n", *t));
646 else{
647 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
648 _("Failed to disable SASL authenticator \"%s\": name not found"),
649 *t);
650 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
651 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
655 if(ps_global->VAR_ENCRYPTION_RANGE
656 && ps_global->VAR_ENCRYPTION_RANGE[0]){
657 char *min_s, *max_s, *s;
658 int min_v, max_v;
660 if((s = strchr(ps_global->VAR_ENCRYPTION_RANGE, ',')) == NULL){
661 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
662 _("Bad encryption range: \"%s\": resetting to default"),
663 ps_global->VAR_ENCRYPTION_RANGE);
664 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
665 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
666 fs_give((void **) &ps_global->VAR_ENCRYPTION_RANGE);
667 ps_global->VAR_ENCRYPTION_RANGE = cpystr(DF_ENCRYPTION_RANGE);
668 s = strchr(ps_global->VAR_ENCRYPTION_RANGE, ','); /* try again */
671 if(s == NULL){
672 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
673 _("Bad default encryption range: \"%s\""),
674 ps_global->VAR_ENCRYPTION_RANGE);
675 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
676 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
678 else {
679 *s = ' ';
680 get_pair(ps_global->VAR_ENCRYPTION_RANGE, &min_s, &max_s, 1, 0);
681 *s = ',';
683 min_v = pith_ssl_encryption_version(min_s);
684 max_v = pith_ssl_encryption_version(max_s);
686 if(min_v < 0 || max_v < 0){
687 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
688 _("Bad encryption range: \"%s\": resetting to default"),
689 ps_global->VAR_ENCRYPTION_RANGE);
690 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
691 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
692 min_v = max_v = 0;
695 if(min_v > max_v){
696 int bubble;
697 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
698 _("Minimum encryption protocol (%s) bigger than maximum value (%s). Reversing..."),
699 min_s, max_s);
700 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
701 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
702 bubble = min_v;
703 min_v = max_v;
704 max_v = bubble;
707 if(max_v > 0 && max_v < (long) pith_ssl_encryption_version("tls1")){
708 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
709 _("Security alert: SSL maximum encryption version was set to SSLv3."),
710 ps_global->VAR_ENCRYPTION_RANGE);
711 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
712 init_error(ps_global, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
715 mail_parameters(NULL, SET_ENCRYPTION_RANGE_MIN, (void *) &min_v);
716 mail_parameters(NULL, SET_ENCRYPTION_RANGE_MAX, (void *) &max_v);
721 * setup alternative authentication driver preference for IMAP opens
723 if(F_ON(F_PREFER_ALT_AUTH, ps_global))
724 mail_parameters(NULL, SET_IMAPTRYALT, (void *) TRUE);
727 * Install handler to let us know about potential delays
729 (void) mail_parameters(NULL, SET_BLOCKNOTIFY, (void *) pine_block_notify);
731 if(ps_global->dump_supported_options){
732 dump_supported_options();
733 exit(0);
737 * Install extra headers to fetch along with all the other stuff
738 * mail_fetch_structure and mail_fetch_overview requests.
740 calc_extra_hdrs();
741 if(get_extra_hdrs())
742 (void) mail_parameters(NULL, SET_IMAPEXTRAHEADERS,
743 (void *) get_extra_hdrs());
745 if(init_username(pine_state) < 0){
746 fprintf(stderr, _("Who are you? (Unable to look up login name)\n"));
747 exit(-1);
750 if(init_userdir(pine_state) < 0)
751 exit(-1);
753 if(init_hostname(pine_state) < 0)
754 exit(-1);
757 * Verify mail dir if we're not in send only mode...
759 if(args.action == aaFolder && init_mail_dir(pine_state) < 0)
760 exit(-1);
762 init_signals();
764 /*--- input side ---*/
765 if(init_tty_driver(pine_state)){
766 #ifndef _WINDOWS /* always succeeds under _WINDOWS */
767 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);
768 exit(-1);
769 #endif /* !_WINDOWS */
773 /*--- output side ---*/
774 rv = config_screen(&(pine_state->ttyo));
775 #ifndef _WINDOWS /* always succeeds under _WINDOWS */
776 if(rv){
777 switch(rv){
778 case -1:
779 printf(_("Terminal type (environment variable TERM) not set.\n"));
780 break;
781 case -2:
782 printf(_("Terminal type \"%s\" is unknown.\n"), getenv("TERM"));
783 break;
784 case -3:
785 printf(_("Can't open terminal capabilities database.\n"));
786 break;
787 case -4:
788 printf(_("Your terminal, of type \"%s\", is lacking functions needed to run alpine.\n"), getenv("TERM"));
789 break;
792 printf("\r");
793 end_tty_driver(pine_state);
794 exit(-1);
796 #endif /* !_WINDOWS */
798 if(F_ON(F_BLANK_KEYMENU,ps_global))
799 FOOTER_ROWS(ps_global) = 1;
801 init_screen();
802 init_keyboard(pine_state->orig_use_fkeys);
803 strncpy(pine_state->inbox_name, INBOX_NAME,
804 sizeof(pine_state->inbox_name)-1);
805 init_folders(pine_state); /* digest folder spec's */
807 pine_state->in_init_seq = 0; /* so output (& ClearScreen) show up */
808 pine_state->dont_use_init_cmds = 1; /* don't use up initial_commands yet */
809 ClearScreen();
811 /* initialize titlebar in case we use it */
812 set_titlebar("", NULL, NULL, NULL, NULL, 0, FolderName, 0, 0, NULL);
815 * Prep storage object driver for PicoText
817 so_register_external_driver(pine_pico_get, pine_pico_give, pine_pico_writec, pine_pico_readc,
818 pine_pico_puts, pine_pico_seek, NULL, NULL);
820 #ifdef DEBUG
821 if(ps_global->debug_imap > 4 || debug > 9){
822 q_status_message(SM_ORDER | SM_DING, 5, 9,
823 _("Warning: sensitive authentication data included in debug file"));
824 flush_status_messages(0);
826 #endif
828 if(args.action == aaPrcCopy || args.action == aaAbookCopy){
829 int exit_val = -1;
830 char *err_msg = NULL;
833 * Don't translate these into UTF-8 because we'll be using them
834 * before we translate next time. User should use ascii.
836 if(args.data.copy.local && args.data.copy.remote){
837 switch(args.action){
838 case aaPrcCopy:
839 exit_val = copy_pinerc(args.data.copy.local,
840 args.data.copy.remote, &err_msg);
841 break;
843 case aaAbookCopy:
844 exit_val = copy_abook(args.data.copy.local,
845 args.data.copy.remote, &err_msg);
846 break;
848 default:
849 break;
852 if(err_msg){
853 q_status_message(SM_ORDER | SM_DING, 3, 4, err_msg);
854 fs_give((void **)&err_msg);
856 goodnight_gracey(pine_state, exit_val);
859 if(args.action == aaFolder
860 && (pine_state->first_time_user || pine_state->show_new_version)){
861 pine_state->mangled_header = 1;
862 show_main_screen(pine_state, 0, FirstMenu, &main_keymenu, 0,
863 (Pos *) NULL);
864 new_user_or_version(pine_state);
865 ClearScreen();
868 /* put back in case we need to suppress output */
869 pine_state->in_init_seq = pine_state->save_in_init_seq;
871 /* queue any init errors so they get displayed in a screen below */
872 queue_init_errors(ps_global);
874 /* "Page" the given file? */
875 if(args.action == aaMore){
876 int dice = 1, redir = 0;
878 if(pine_state->in_init_seq){
879 pine_state->in_init_seq = pine_state->save_in_init_seq = 0;
880 clear_cursor_pos();
881 if(pine_state->free_initial_cmds)
882 fs_give((void **)&(pine_state->free_initial_cmds));
884 pine_state->initial_cmds = NULL;
887 /*======= Requested that we simply page the given file =======*/
888 if(args.data.file){ /* Open the requested file... */
889 SourceType src;
890 STORE_S *store = NULL;
891 char *decode_error = NULL;
892 char filename[MAILTMPLEN];
894 if(args.data.file[0] == '\0'){
895 HelpType help = NO_HELP;
897 pine_state->mangled_footer = 1;
898 filename[0] = '\0';
899 while(1){
900 int flags = OE_APPEND_CURRENT;
902 rv = optionally_enter(filename, -FOOTER_ROWS(pine_state),
903 0, sizeof(filename),
904 /* TRANSLATORS: file is computer data */
905 _("File to open : "),
906 NULL, help, &flags);
907 if(rv == 3){
908 help = (help == NO_HELP) ? h_no_F_arg : NO_HELP;
909 continue;
912 if(rv != 4)
913 break;
916 if(rv == 1){
917 q_status_message(SM_ORDER, 0, 2, _("Cancelled"));
918 goodnight_gracey(pine_state, -1);
921 if(*filename){
922 removing_trailing_white_space(filename);
923 removing_leading_white_space(filename);
924 if(is_absolute_path(filename))
925 fnexpand(filename, sizeof(filename));
927 args.data.file = filename;
930 if(!*filename){
931 /* TRANSLATORS: file is computer data */
932 q_status_message(SM_ORDER, 0, 2 ,_("No file to open"));
933 goodnight_gracey(pine_state, -1);
937 if(stdin_getc){
938 redir++;
939 src = CharStar;
940 if(isatty(0) && (store = so_get(src, NULL, EDIT_ACCESS))){
941 gf_io_t pc;
943 gf_set_so_writec(&pc, store);
944 gf_filter_init();
945 if((decode_error = gf_pipe(stdin_getc, pc)) != NULL){
946 dice = 0;
947 q_status_message1(SM_ORDER, 3, 4,
948 _("Problem reading standard input: %s"),
949 decode_error);
952 gf_clear_so_writec(store);
954 else
955 dice = 0;
957 else{
958 src = FileStar;
959 strncpy(ps_global->cur_folder, args.data.file,
960 sizeof(ps_global->cur_folder)-1);
961 ps_global->cur_folder[sizeof(ps_global->cur_folder)-1] = '\0';
962 if(!(store = so_get(src, args.data.file, READ_ACCESS|READ_FROM_LOCALE)))
963 dice = 0;
966 if(dice){
967 SCROLL_S sargs;
969 memset(&sargs, 0, sizeof(SCROLL_S));
970 sargs.text.text = so_text(store);
971 sargs.text.src = src;
972 /* TRANSLATORS: file is computer file being read by user */
973 sargs.text.desc = _("file");
974 /* TRANSLATORS: this is in the title bar at top of screen */
975 sargs.bar.title = _("FILE VIEW");
976 sargs.bar.style = FileTextPercent;
977 sargs.keys.menu = &simple_file_keymenu;
978 setbitmap(sargs.keys.bitmap);
979 scrolltool(&sargs);
981 printf("\n\n");
982 so_give(&store);
986 if(!dice){
987 q_status_message2(SM_ORDER, 3, 4,
988 _("Can't display \"%s\": %s"),
989 (redir) ? _("Standard Input")
990 : args.data.file ? args.data.file : "NULL",
991 error_description(errno));
994 goodnight_gracey(pine_state, 0);
996 else if(args.action == aaMail || (stdin_getc && (args.action != aaURL))){
997 /*======= address on command line/send one message mode ============*/
998 char *to = NULL, *error = NULL, *addr = NULL;
999 int len, good_addr = 1;
1000 int exit_val = 0;
1001 BUILDER_ARG fcc;
1003 if(pine_state->in_init_seq){
1004 pine_state->in_init_seq = pine_state->save_in_init_seq = 0;
1005 clear_cursor_pos();
1006 if(pine_state->free_initial_cmds)
1007 fs_give((void **) &(pine_state->free_initial_cmds));
1009 pine_state->initial_cmds = NULL;
1012 /*----- Format the To: line with commas for the composer ---*/
1013 if(args.data.mail.addrlist){
1014 STRLIST_S *p;
1016 for(p = args.data.mail.addrlist, len = 0; p; p = p->next)
1017 len += strlen(p->name) + 2;
1019 to = (char *) fs_get((len + 5) * sizeof(char));
1020 for(p = args.data.mail.addrlist, *to = '\0'; p; p = p->next){
1021 if(*to){
1022 strncat(to, ", ", len+5-strlen(to)-1);
1023 to[len+5-1] = '\0';
1026 strncat(to, p->name, len+5-strlen(to)-1);
1027 to[len+5-1] = '\0';
1030 memset((void *)&fcc, 0, sizeof(BUILDER_ARG));
1031 dprint((2, "building addr: -->%s<--\n", to ? to : "?"));
1032 good_addr = (build_address(to, &addr, &error, &fcc, NULL) >= 0);
1033 dprint((2, "mailing to: -->%s<--\n", addr ? addr : "?"));
1034 free_strlist(&args.data.mail.addrlist);
1036 else
1037 memset(&fcc, 0, sizeof(fcc));
1039 if(good_addr){
1040 compose_mail(addr, fcc.tptr, NULL,
1041 args.data.mail.attachlist, stdin_getc);
1043 else{
1044 /* TRANSLATORS: refers to bad email address */
1045 q_status_message1(SM_ORDER, 3, 4, _("Bad address: %s"), error);
1046 exit_val = -1;
1049 if(addr)
1050 fs_give((void **) &addr);
1052 if(fcc.tptr)
1053 fs_give((void **) &fcc.tptr);
1055 if(args.data.mail.attachlist)
1056 free_attachment_list(&args.data.mail.attachlist);
1058 if(to)
1059 fs_give((void **) &to);
1061 if(error)
1062 fs_give((void **) &error);
1064 goodnight_gracey(pine_state, exit_val);
1066 else{
1067 char int_mail[MAXPATH+1];
1068 struct key_menu *km = &main_keymenu;
1070 /*========== Normal pine mail reading mode ==========*/
1072 pine_state->mail_stream = NULL;
1073 pine_state->mangled_screen = 1;
1075 if(args.action == aaURL){
1076 url_tool_t f;
1078 if(pine_state->in_init_seq){
1079 pine_state->in_init_seq = pine_state->save_in_init_seq = 0;
1080 clear_cursor_pos();
1081 if(pine_state->free_initial_cmds)
1082 fs_give((void **) &(pine_state->free_initial_cmds));
1083 pine_state->initial_cmds = NULL;
1085 if((f = url_local_handler(args.url)) != NULL){
1086 if(args.data.mail.attachlist){
1087 if(f == url_local_mailto){
1088 if(!(url_local_mailto_and_atts(args.url,
1089 args.data.mail.attachlist)
1090 && pine_state->next_screen))
1091 free_attachment_list(&args.data.mail.attachlist);
1092 goodnight_gracey(pine_state, 0);
1094 else {
1095 q_status_message(SM_ORDER | SM_DING, 3, 4,
1096 _("Only mailto URLs are allowed with file attachments"));
1097 goodnight_gracey(pine_state, -1); /* no return */
1100 else if(!((*f)(args.url) && pine_state->next_screen))
1101 goodnight_gracey(pine_state, 0); /* no return */
1103 else{
1104 q_status_message1(SM_ORDER | SM_DING, 3, 4,
1105 _("Unrecognized URL \"%s\""), args.url);
1106 goodnight_gracey(pine_state, -1); /* no return */
1109 else if(!pine_state->start_in_index){
1110 /* flash message about executing initial commands */
1111 if(pine_state->in_init_seq){
1112 pine_state->in_init_seq = 0;
1113 clear_cursor_pos();
1114 pine_state->mangled_header = 1;
1115 pine_state->mangled_footer = 1;
1116 pine_state->mangled_screen = 0;
1117 /* show that this is Alpine */
1118 show_main_screen(pine_state, 0, FirstMenu, km, 0, (Pos *)NULL);
1119 pine_state->mangled_screen = 1;
1120 pine_state->painted_footer_on_startup = 1;
1121 if(MIN(4, pine_state->ttyo->screen_rows - 4) > 1){
1122 char buf1[6*MAX_SCREEN_COLS+1];
1123 char buf2[6*MAX_SCREEN_COLS+1];
1124 int wid;
1126 /* TRANSLATORS: Initial Keystroke List is the literal name of an option */
1127 strncpy(buf1, _("Executing Initial Keystroke List......"), sizeof(buf1));
1128 buf1[sizeof(buf1)-1] = '\0';
1129 wid = utf8_width(buf1);
1130 if(wid > ps_global->ttyo->screen_cols){
1131 utf8_pad_to_width(buf2, buf1, sizeof(buf2), ps_global->ttyo->screen_cols, 1);
1132 PutLine0(MIN(4, pine_state->ttyo->screen_rows - 4), 0, buf2);
1134 else{
1135 PutLine0(MIN(4, pine_state->ttyo->screen_rows - 4),
1136 MAX(MIN(11, pine_state->ttyo->screen_cols - wid), 0), buf1);
1140 pine_state->in_init_seq = 1;
1142 else{
1143 show_main_screen(pine_state, 0, FirstMenu, km, 0, (Pos *)NULL);
1144 pine_state->painted_body_on_startup = 1;
1145 pine_state->painted_footer_on_startup = 1;
1148 else{
1149 /* cancel any initial commands, overridden by cmd line */
1150 if(pine_state->in_init_seq){
1151 pine_state->in_init_seq = 0;
1152 pine_state->save_in_init_seq = 0;
1153 clear_cursor_pos();
1154 if(pine_state->initial_cmds){
1155 if(pine_state->free_initial_cmds)
1156 fs_give((void **)&(pine_state->free_initial_cmds));
1158 pine_state->initial_cmds = NULL;
1161 F_SET(F_USE_FK,pine_state, pine_state->orig_use_fkeys);
1164 (void) do_index_border(pine_state->context_current,
1165 pine_state->cur_folder,
1166 pine_state->mail_stream,
1167 pine_state->msgmap, MsgIndex, NULL,
1168 INDX_CLEAR|INDX_HEADER|INDX_FOOTER);
1169 pine_state->painted_footer_on_startup = 1;
1170 if(MIN(4, pine_state->ttyo->screen_rows - 4) > 1){
1171 char buf1[6*MAX_SCREEN_COLS+1];
1172 char buf2[6*MAX_SCREEN_COLS+1];
1173 int wid;
1175 strncpy(buf1, _("Please wait, opening mail folder......"), sizeof(buf1));
1176 buf1[sizeof(buf1)-1] = '\0';
1177 wid = utf8_width(buf1);
1178 if(wid > ps_global->ttyo->screen_cols){
1179 utf8_pad_to_width(buf2, buf1, sizeof(buf2), ps_global->ttyo->screen_cols, 1);
1180 PutLine0(MIN(4, pine_state->ttyo->screen_rows - 4), 0, buf2);
1182 else{
1183 PutLine0(MIN(4, pine_state->ttyo->screen_rows - 4),
1184 MAX(MIN(11, pine_state->ttyo->screen_cols - wid), 0), buf1);
1189 fflush(stdout);
1191 #if !defined(_WINDOWS) && !defined(LEAVEOUTFIFO)
1192 if(ps_global->VAR_FIFOPATH && ps_global->VAR_FIFOPATH[0])
1193 init_newmailfifo(ps_global->VAR_FIFOPATH);
1194 #endif
1196 if(pine_state->in_init_seq){
1197 pine_state->in_init_seq = 0;
1198 clear_cursor_pos();
1201 if(args.action == aaFolder && args.data.folder){
1202 CONTEXT_S *cntxt = NULL, *tc = NULL;
1203 char foldername[MAILTMPLEN];
1204 int notrealinbox = 0;
1206 if(args.data.folder[0] == '\0'){
1207 char *fldr;
1208 unsigned save_def_goto_rule;
1210 foldername[0] = '\0';
1211 save_def_goto_rule = pine_state->goto_default_rule;
1212 pine_state->goto_default_rule = GOTO_FIRST_CLCTN;
1213 tc = default_save_context(pine_state->context_list);
1214 fldr = broach_folder(-FOOTER_ROWS(pine_state), 1, &notrealinbox, &tc);
1215 pine_state->goto_default_rule = save_def_goto_rule;
1216 if(fldr){
1217 strncpy(foldername, fldr, sizeof(foldername)-1);
1218 foldername[sizeof(foldername)-1] = '\0';
1221 if(*foldername){
1222 removing_trailing_white_space(foldername);
1223 removing_leading_white_space(foldername);
1224 args.data.folder = cpystr(foldername);
1227 if(!*foldername){
1228 q_status_message(SM_ORDER, 0, 2 ,_("No folder to open"));
1229 goodnight_gracey(pine_state, -1);
1233 if(tc)
1234 cntxt = tc;
1235 else if((rv = pine_state->init_context) < 0)
1237 * As with almost all the folder vars in the pinerc,
1238 * we subvert the collection "breakout" here if the
1239 * folder name given looks like an asolute path on
1240 * this system...
1242 cntxt = (is_absolute_path(args.data.folder))
1243 ? NULL : pine_state->context_current;
1244 else if(rv == 0)
1245 cntxt = NULL;
1246 else
1247 for(cntxt = pine_state->context_list;
1248 rv > 1 && cntxt->next;
1249 rv--, cntxt = cntxt->next)
1252 if(pine_state && pine_state->ttyo){
1253 blank_keymenu(pine_state->ttyo->screen_rows - 2, 0);
1254 pine_state->painted_footer_on_startup = 0;
1255 pine_state->mangled_footer = 1;
1258 if(args.data.folder && *args.data.folder
1259 && !strucmp(args.data.folder, ps_global->inbox_name)
1260 && cntxt != ps_global->context_list)
1261 notrealinbox = 1;
1263 if(do_broach_folder(args.data.folder, cntxt, NULL, notrealinbox ? 0L : DB_INBOXWOCNTXT) <= 0){
1264 q_status_message1(SM_ORDER, 3, 4,
1265 _("Unable to open folder \"%s\""), args.data.folder);
1267 fs_give((void **) &args.data.folder);
1269 goodnight_gracey(pine_state, -1);
1272 else if(args.action == aaFolder){
1273 #ifdef _WINDOWS
1275 * need to ask for the inbox name if no default under DOS
1276 * since there is no "inbox"
1279 if(!pine_state->VAR_INBOX_PATH || !pine_state->VAR_INBOX_PATH[0]
1280 || strucmp(pine_state->VAR_INBOX_PATH, "inbox") == 0){
1281 HelpType help = NO_HELP;
1282 static ESCKEY_S ekey[] = {{ctrl(T), 2, "^T", "To Fldrs"},
1283 {-1, 0, NULL, NULL}};
1285 pine_state->mangled_footer = 1;
1286 int_mail[0] = '\0';
1287 while(1){
1288 int flags = OE_APPEND_CURRENT;
1290 rv = optionally_enter(int_mail, -FOOTER_ROWS(pine_state),
1291 0, sizeof(int_mail),
1292 _("No inbox! Folder to open as inbox : "),
1293 /* ekey */ NULL, help, &flags);
1294 if(rv == 3){
1295 help = (help == NO_HELP) ? h_sticky_inbox : NO_HELP;
1296 continue;
1299 if(rv != 4)
1300 break;
1303 if(rv == 1){
1304 q_status_message(SM_ORDER, 0, 2 ,_("Folder open cancelled"));
1305 rv = 0; /* reset rv */
1307 else if(rv == 2){
1308 show_main_screen(pine_state,0,FirstMenu,km,0,(Pos *)NULL);
1311 if(*int_mail){
1312 removing_trailing_white_space(int_mail);
1313 removing_leading_white_space(int_mail);
1314 if((!pine_state->VAR_INBOX_PATH
1315 || strucmp(pine_state->VAR_INBOX_PATH, "inbox") == 0)
1316 /* TRANSLATORS: Inbox-Path and PINERC are literal, not to be translated */
1317 && want_to(_("Preserve folder as \"Inbox-Path\" in PINERC"),
1318 'y', 'n', NO_HELP, WT_NORM) == 'y'){
1319 set_variable(V_INBOX_PATH, int_mail, 1, 1, Main);
1321 else{
1322 if(pine_state->VAR_INBOX_PATH)
1323 fs_give((void **)&pine_state->VAR_INBOX_PATH);
1325 pine_state->VAR_INBOX_PATH = cpystr(int_mail);
1328 if(pine_state && pine_state->ttyo){
1329 blank_keymenu(pine_state->ttyo->screen_rows - 2, 0);
1330 pine_state->painted_footer_on_startup = 0;
1331 pine_state->mangled_footer = 1;
1334 do_broach_folder(pine_state->inbox_name,
1335 pine_state->context_list, NULL, DB_INBOXWOCNTXT);
1337 else
1338 q_status_message(SM_ORDER, 0, 2 ,_("No folder opened"));
1341 else
1343 #endif /* _WINDOWS */
1344 if(F_ON(F_PREOPEN_STAYOPENS, ps_global))
1345 preopen_stayopen_folders();
1347 if(pine_state && pine_state->ttyo){
1348 blank_keymenu(pine_state->ttyo->screen_rows - 2, 0);
1349 pine_state->painted_footer_on_startup = 0;
1350 pine_state->mangled_footer = 1;
1353 /* open inbox */
1354 do_broach_folder(pine_state->inbox_name,
1355 pine_state->context_list, NULL, DB_INBOXWOCNTXT);
1358 if(pine_state->mangled_footer)
1359 pine_state->painted_footer_on_startup = 0;
1361 if(args.action == aaFolder
1362 && pine_state->mail_stream
1363 && expire_sent_mail())
1364 pine_state->painted_footer_on_startup = 0;
1367 * Initialize the defaults. Initializing here means that
1368 * if they're remote, the user isn't prompted for an imap login
1369 * before the display's drawn, AND there's the chance that
1370 * we can climb onto the already opened folder's stream...
1372 if(ps_global->first_time_user)
1373 init_save_defaults(); /* initialize default save folders */
1375 build_path(int_mail,
1376 ps_global->VAR_OPER_DIR ? ps_global->VAR_OPER_DIR
1377 : pine_state->home_dir,
1378 INTERRUPTED_MAIL, sizeof(int_mail));
1379 if(args.action == aaFolder
1380 && (folder_exists(NULL, int_mail) & FEX_ISFILE))
1381 q_status_message(SM_ORDER | SM_DING, 4, 5,
1382 _("Use Compose command to continue interrupted message."));
1384 if(args.action == aaFolder && args.data.folder)
1385 fs_give((void **) &args.data.folder);
1387 #if defined(USE_QUOTAS)
1389 long q;
1390 int over;
1391 q = disk_quota(pine_state->home_dir, &over);
1392 if(q > 0 && over){
1393 q_status_message2(SM_ASYNC | SM_DING, 4, 5,
1394 _("WARNING! Over your disk quota by %s bytes (%s)"),
1395 comatose(q),byte_string(q));
1398 #endif
1400 pine_state->in_init_seq = pine_state->save_in_init_seq;
1401 pine_state->dont_use_init_cmds = 0;
1402 clear_cursor_pos();
1404 if(pine_state->give_fixed_warning)
1405 q_status_message(SM_ASYNC, 0, 10,
1406 /* TRANSLATORS: config is an abbreviation for configuration */
1407 _("Note: some of your config options conflict with site policy and are ignored"));
1409 if(!prune_folders_ok())
1410 q_status_message(SM_ASYNC, 0, 10,
1411 /* TRANSLATORS: Pruned-Folders is literal */
1412 _("Note: ignoring Pruned-Folders outside of default collection for saves"));
1414 if(get_input_timeout() == 0 &&
1415 ps_global->VAR_INBOX_PATH &&
1416 ps_global->VAR_INBOX_PATH[0] == '{')
1417 q_status_message(SM_ASYNC, 0, 10,
1418 _("Note: Mail-Check-Interval=0 may cause IMAP server connection to time out"));
1420 #ifdef _WINDOWS
1421 mswin_setnewmailwidth(ps_global->nmw_width);
1422 #endif
1425 /*-------------------------------------------------------------------
1426 Loop executing the commands
1428 This is done like this so that one command screen can cause
1429 another one to execute it with out going through the main menu.
1430 ------------------------------------------------------------------*/
1431 if(!pine_state->next_screen)
1432 pine_state->next_screen = pine_state->start_in_index
1433 ? mail_index_screen : main_menu_screen;
1434 while(1){
1435 if(pine_state->next_screen == SCREEN_FUN_NULL)
1436 pine_state->next_screen = main_menu_screen;
1438 (*(pine_state->next_screen))(pine_state);
1442 exit(0);
1447 * The arguments need to be converted to UTF-8 for our internal use.
1448 * Not all arguments are converted because some are used before we
1449 * are able to do the conversion, like the pinerc name.
1451 void
1452 convert_args_to_utf8(struct pine *ps, ARGDATA_S *args)
1454 char *fromcharset = NULL;
1455 char *conv;
1457 if(args){
1458 if(ps->keyboard_charmap && strucmp(ps->keyboard_charmap, "UTF-8")
1459 && strucmp(ps->keyboard_charmap, "US-ASCII"))
1460 fromcharset = ps->keyboard_charmap;
1461 else if(ps->display_charmap && strucmp(ps->display_charmap, "UTF-8")
1462 && strucmp(ps->display_charmap, "US-ASCII"))
1463 fromcharset = ps->display_charmap;
1464 #ifndef _WINDOWS
1465 else if(ps->VAR_OLD_CHAR_SET && strucmp(ps->VAR_OLD_CHAR_SET, "UTF-8")
1466 && strucmp(ps->VAR_OLD_CHAR_SET, "US-ASCII"))
1467 fromcharset = ps->VAR_OLD_CHAR_SET;
1468 #endif /* ! _WINDOWS */
1470 if(args->action == aaURL && args->url){
1471 conv = convert_to_utf8(args->url, fromcharset, 0);
1472 if(conv){
1473 fs_give((void **) &args->url);
1474 args->url = conv;
1478 if(args->action == aaFolder && args->data.folder){
1479 conv = convert_to_utf8(args->data.folder, fromcharset, 0);
1480 if(conv){
1481 fs_give((void **) &args->data.folder);
1482 args->data.folder = conv;
1486 if(args->action == aaMore && args->data.file){
1487 conv = convert_to_utf8(args->data.file, fromcharset, 0);
1488 if(conv){
1489 fs_give((void **) &args->data.file);
1490 args->data.file = conv;
1494 if(args->action == aaURL || args->action == aaMail){
1495 if(args->data.mail.addrlist){
1496 STRLIST_S *p;
1498 for(p = args->data.mail.addrlist; p; p=p->next){
1499 if(p->name){
1500 conv = convert_to_utf8(p->name, fromcharset, 0);
1501 if(conv){
1502 fs_give((void **) &p->name);
1503 p->name = conv;
1509 if(args->data.mail.attachlist){
1510 PATMT *p;
1512 for(p = args->data.mail.attachlist; p; p=p->next){
1513 if(p->filename){
1514 conv = convert_to_utf8(p->filename, fromcharset, 0);
1515 if(conv){
1516 fs_give((void **) &p->filename);
1517 p->filename = conv;
1527 void
1528 preopen_stayopen_folders(void)
1530 char **open_these;
1532 for(open_these = ps_global->VAR_PERMLOCKED;
1533 open_these && *open_these; open_these++)
1534 (void) do_broach_folder(*open_these, ps_global->context_list,
1535 NULL, DB_NOVISIT);
1540 * read_stdin_char - simple function to return a character from
1541 * redirected stdin
1544 read_stdin_char(char *c)
1546 int rv;
1548 /* it'd probably be a good idea to fix this to pre-read blocks */
1549 while(1){
1550 rv = read(PIPED_FD, c, 1);
1551 if(rv < 0){
1552 if(errno == EINTR){
1553 dprint((2, "read_stdin_char: read interrupted, restarting\n"));
1554 continue;
1556 else
1557 dprint((1, "read_stdin_char: read FAILED: %s\n",
1558 error_description(errno)));
1560 break;
1562 return(rv);
1566 /* this default is from the array of structs below */
1567 #define DEFAULT_MENU_ITEM ((unsigned) 3) /* LIST FOLDERS */
1568 #define ABOOK_MENU_ITEM ((unsigned) 4) /* ADDRESS BOOK */
1569 #define MAX_MENU_ITEM ((unsigned) 6)
1571 * Skip this many spaces between rows of main menu screen.
1572 * We have MAX_MENU_ITEM+1 = # of commands in menu
1573 * 1 = copyright line
1574 * MAX_MENU_ITEM = rows between commands
1575 * 1 = extra row above commands
1576 * 1 = row between commands and copyright
1578 * To make it simple, if there is enough room for all of that include all the
1579 * extra space, if not, cut it all out.
1581 #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)
1583 static unsigned menu_index = DEFAULT_MENU_ITEM;
1586 * One of these for each line that gets printed in the middle of the
1587 * screen in the main menu.
1589 static struct menu_key {
1590 char *key_and_name,
1591 *news_addition;
1592 int key_index; /* index into keymenu array for this cmd */
1593 } mkeys[] = {
1595 * TRANSLATORS: These next few are headings on the Main alpine menu.
1596 * It's nice if the dashes can be made to line up vertically.
1598 {N_(" %s HELP - Get help using Alpine"),
1599 NULL, MAIN_HELP_KEY},
1600 {N_(" %s COMPOSE MESSAGE - Compose and send%s a message"),
1601 /* TRANSLATORS: We think of sending an email message or posting a news message.
1602 The message is shown as Compose and send/post a message */
1603 N_("/post"), MAIN_COMPOSE_KEY},
1604 {N_(" %s MESSAGE INDEX - View messages in current folder"),
1605 NULL, MAIN_INDEX_KEY},
1606 {N_(" %s FOLDER LIST - Select a folder%s to view"),
1607 /* TRANSLATORS: When news is supported the message above becomes
1608 Select a folder OR news group to view */
1609 N_(" OR news group"), MAIN_FOLDER_KEY},
1610 {N_(" %s ADDRESS BOOK - Update address book"),
1611 NULL, MAIN_ADDRESS_KEY},
1612 {N_(" %s SETUP - Configure Alpine Options"),
1613 NULL, MAIN_SETUP_KEY},
1614 /* TRANSLATORS: final Main menu line */
1615 {N_(" %s QUIT - Leave the Alpine program"),
1616 NULL, MAIN_QUIT_KEY}
1621 /*----------------------------------------------------------------------
1622 display main menu and execute main menu commands
1624 Args: The usual pine structure
1626 Result: main menu commands are executed
1629 M A I N M E N U S C R E E N
1631 Paint the main menu on the screen, get the commands and either execute
1632 the function or pass back the name of the function to execute for the menu
1633 selection. Only simple functions that always return here can be executed
1634 here.
1636 This functions handling of new mail, redrawing, errors and such can
1637 serve as a template for the other screen that do much the same thing.
1639 There is a loop that fetchs and executes commands until a command to leave
1640 this screen is given. Then the name of the next screen to display is
1641 stored in next_screen member of the structure and this function is exited
1642 with a return.
1644 First a check for new mail is performed. This might involve reading the new
1645 mail into the inbox which might then cause the screen to be repainted.
1647 Then the general screen painting is done. This is usually controlled
1648 by a few flags and some other position variables. If they change they
1649 tell this part of the code what to repaint. This will include cursor
1650 motion and so on.
1651 ----*/
1652 void
1653 main_menu_screen(struct pine *pine_state)
1655 UCS ch;
1656 int cmd, just_a_navigate_cmd, setup_command, km_popped;
1657 int notrealinbox;
1658 char *new_folder, *utf8str;
1659 CONTEXT_S *tc;
1660 struct key_menu *km;
1661 OtherMenu what;
1662 Pos curs_pos;
1664 ps_global = pine_state;
1665 just_a_navigate_cmd = 0;
1666 km_popped = 0;
1667 menu_index = DEFAULT_MENU_ITEM;
1668 what = FirstMenu; /* which keymenu to display */
1669 ch = 'x'; /* For display_message 1st time through */
1670 pine_state->next_screen = SCREEN_FUN_NULL;
1671 pine_state->prev_screen = main_menu_screen;
1672 curs_pos.row = pine_state->ttyo->screen_rows-FOOTER_ROWS(pine_state);
1673 curs_pos.col = 0;
1674 km = &main_keymenu;
1676 mailcap_free(); /* free resources we won't be using for a while */
1678 if(!pine_state->painted_body_on_startup
1679 && !pine_state->painted_footer_on_startup){
1680 pine_state->mangled_screen = 1;
1683 dprint((1, "\n\n ---- MAIN_MENU_SCREEN ----\n"));
1685 while(1){
1686 if(km_popped){
1687 km_popped--;
1688 if(km_popped == 0){
1689 clearfooter(pine_state);
1690 pine_state->mangled_body = 1;
1695 * fix up redrawer just in case some submenu caused it to get
1696 * reassigned...
1698 pine_state->redrawer = main_redrawer;
1700 /*----------- Check for new mail -----------*/
1701 if(new_mail(0, NM_TIMING(ch), NM_STATUS_MSG | NM_DEFER_SORT) >= 0)
1702 pine_state->mangled_header = 1;
1704 if(streams_died())
1705 pine_state->mangled_header = 1;
1707 show_main_screen(pine_state, just_a_navigate_cmd, what, km,
1708 km_popped, &curs_pos);
1709 just_a_navigate_cmd = 0;
1710 what = SameMenu;
1712 /*---- This displays new mail notification, or errors ---*/
1713 if(km_popped){
1714 FOOTER_ROWS(pine_state) = 3;
1715 mark_status_dirty();
1718 display_message(ch);
1719 if(km_popped){
1720 FOOTER_ROWS(pine_state) = 1;
1721 mark_status_dirty();
1724 if(F_OFF(F_SHOW_CURSOR, ps_global)){
1725 curs_pos.row =pine_state->ttyo->screen_rows-FOOTER_ROWS(pine_state);
1726 curs_pos.col =0;
1729 MoveCursor(curs_pos.row, curs_pos.col);
1731 /*------ Read the command from the keyboard ----*/
1732 #ifdef MOUSE
1733 mouse_in_content(KEY_MOUSE, -1, -1, 0, 0);
1734 register_mfunc(mouse_in_content, HEADER_ROWS(pine_state), 0,
1735 pine_state->ttyo->screen_rows-(FOOTER_ROWS(pine_state)+1),
1736 pine_state->ttyo->screen_cols);
1737 #endif
1738 #if defined(DOS) || defined(OS2)
1740 * AND pre-build header lines. This works just fine under
1741 * DOS since we wait for characters in a loop. Something will
1742 * will have to change under UNIX if we want to do the same.
1744 /* while_waiting = build_header_cache; */
1745 #ifdef _WINDOWS
1746 mswin_sethelptextcallback(pcpine_help_main);
1747 mswin_mousetrackcallback(pcpine_main_cursor);
1748 #endif
1749 #endif
1750 ch = READ_COMMAND(&utf8str);
1751 #ifdef MOUSE
1752 clear_mfunc(mouse_in_content);
1753 #endif
1754 #if defined(DOS) || defined(OS2)
1755 /* while_waiting = NULL; */
1756 #ifdef _WINDOWS
1757 mswin_sethelptextcallback(NULL);
1758 mswin_mousetrackcallback(NULL);
1759 #endif
1760 #endif
1762 /* No matter what, Quit here always works */
1763 if(ch == 'q' || ch == 'Q'){
1764 cmd = MC_QUIT;
1766 #ifdef DEBUG
1767 else if(debug && ch && ch < 0x80 && strchr("123456789", ch)){
1768 int olddebug;
1770 olddebug = debug;
1771 debug = ch - '0';
1772 if(debug > 7)
1773 ps_global->debug_timestamp = 1;
1774 else
1775 ps_global->debug_timestamp = 0;
1777 if(debug > 7)
1778 ps_global->debug_imap = 4;
1779 else if(debug > 6)
1780 ps_global->debug_imap = 3;
1781 else if(debug > 4)
1782 ps_global->debug_imap = 2;
1783 else if(debug > 2)
1784 ps_global->debug_imap = 1;
1785 else
1786 ps_global->debug_imap = 0;
1788 if(ps_global->mail_stream){
1789 if(ps_global->debug_imap > 0){
1790 mail_debug(ps_global->mail_stream);
1791 #ifdef _WINDOWS
1792 mswin_enableimaptelemetry(TRUE);
1793 #endif
1795 else{
1796 mail_nodebug(ps_global->mail_stream);
1797 #ifdef _WINDOWS
1798 mswin_enableimaptelemetry(FALSE);
1799 #endif
1803 if(debug > 7 && olddebug <= 7)
1804 mail_parameters(NULL, SET_TCPDEBUG, (void *) TRUE);
1805 else if(debug <= 7 && olddebug > 7 && !ps_global->debugmem)
1806 mail_parameters(NULL, SET_TCPDEBUG, (void *) FALSE);
1808 dprint((1, "*** Debug level set to %d ***\n", debug));
1809 if(debugfile)
1810 fflush(debugfile);
1812 q_status_message1(SM_ORDER, 0, 1, _("Debug level set to %s"),
1813 int2string(debug));
1814 continue;
1816 #endif /* DEBUG */
1817 else{
1818 cmd = menu_command(ch, km);
1820 if(km_popped)
1821 switch(cmd){
1822 case MC_NONE :
1823 case MC_OTHER :
1824 case MC_RESIZE :
1825 case MC_REPAINT :
1826 km_popped++;
1827 break;
1829 default:
1830 clearfooter(pine_state);
1831 break;
1835 /*------ Execute the command ------*/
1836 switch (cmd){
1837 help_case :
1838 /*------ HELP ------*/
1839 case MC_HELP :
1841 if(FOOTER_ROWS(pine_state) == 1 && km_popped == 0){
1842 km_popped = 2;
1843 pine_state->mangled_footer = 1;
1845 else{
1846 /* TRANSLATORS: This is a screen title */
1847 helper(main_menu_tx, _("HELP FOR MAIN MENU"), 0);
1848 pine_state->mangled_screen = 1;
1851 break;
1854 /*---------- display other key bindings ------*/
1855 case MC_OTHER :
1856 if(ch == 'o')
1857 warn_other_cmds();
1859 what = NextMenu;
1860 pine_state->mangled_footer = 1;
1861 break;
1864 /*---------- Previous item in menu ----------*/
1865 case MC_PREVITEM :
1866 if(menu_index > 0) {
1867 menu_index--;
1868 pine_state->mangled_body = 1;
1869 if(km->which == 0)
1870 pine_state->mangled_footer = 1;
1872 just_a_navigate_cmd++;
1874 else
1875 /* TRANSLATORS: list refers to list of commands in main menu */
1876 q_status_message(SM_ORDER, 0, 2, _("Already at top of list"));
1878 break;
1881 /*---------- Next item in menu ----------*/
1882 case MC_NEXTITEM :
1883 if(menu_index < MAX_MENU_ITEM){
1884 menu_index++;
1885 pine_state->mangled_body = 1;
1886 if(km->which == 0)
1887 pine_state->mangled_footer = 1;
1889 just_a_navigate_cmd++;
1891 else
1892 q_status_message(SM_ORDER, 0, 2, _("Already at bottom of list"));
1894 break;
1897 /*---------- Release Notes ----------*/
1898 case MC_RELNOTES :
1899 /* TRANSLATORS: This is a screen title */
1900 helper(h_news, _("ALPINE RELEASE NOTES"), 0);
1901 pine_state->mangled_screen = 1;
1902 break;
1905 #ifdef KEYBOARD_LOCK
1906 /*---------- Keyboard lock ----------*/
1907 case MC_KBLOCK :
1908 (void) lock_keyboard();
1909 pine_state->mangled_screen = 1;
1910 break;
1911 #endif /* KEYBOARD_LOCK */
1914 /*---------- Quit pine ----------*/
1915 case MC_QUIT :
1916 pine_state->next_screen = quit_screen;
1917 return;
1920 /*---------- Go to composer ----------*/
1921 case MC_COMPOSE :
1922 pine_state->next_screen = compose_screen;
1923 return;
1926 /*---- Go to alternate composer ------*/
1927 case MC_ROLE :
1928 pine_state->next_screen = alt_compose_screen;
1929 return;
1932 /*---------- Top of Folder list ----------*/
1933 case MC_COLLECTIONS :
1934 pine_state->next_screen = folder_screen;
1935 return;
1938 /*---------- Goto new folder ----------*/
1939 case MC_GOTO :
1940 tc = ps_global->context_current;
1941 new_folder = broach_folder(-FOOTER_ROWS(pine_state), 1, &notrealinbox, &tc);
1942 if(new_folder)
1943 visit_folder(ps_global, new_folder, tc, NULL, notrealinbox ? 0L : DB_INBOXWOCNTXT);
1945 return;
1948 /*---------- Go to index ----------*/
1949 case MC_INDEX :
1950 if(THREADING()
1951 && sp_viewing_a_thread(pine_state->mail_stream)
1952 && unview_thread(pine_state, pine_state->mail_stream,
1953 pine_state->msgmap)){
1954 pine_state->view_skipped_index = 0;
1955 pine_state->mangled_screen = 1;
1958 pine_state->next_screen = mail_index_screen;
1959 return;
1962 /*---------- Review Status Messages ----------*/
1963 case MC_JOURNAL :
1964 review_messages();
1965 pine_state->mangled_screen = 1;
1966 break;
1969 /*---------- Setup mini menu ----------*/
1970 case MC_SETUP :
1971 setup_case :
1972 setup_command = setup_menu(pine_state);
1973 pine_state->mangled_footer = 1;
1974 do_setup_task(setup_command);
1975 if(ps_global->next_screen != main_menu_screen)
1976 return;
1978 break;
1981 /*---------- Go to address book ----------*/
1982 case MC_ADDRBOOK :
1983 pine_state->next_screen = addr_book_screen;
1984 return;
1987 /*------ Repaint the works -------*/
1988 case MC_RESIZE :
1989 case MC_REPAINT :
1990 ClearScreen();
1991 pine_state->mangled_screen = 1;
1992 break;
1995 #ifdef MOUSE
1996 /*------- Mouse event ------*/
1997 case MC_MOUSE :
1999 MOUSEPRESS mp;
2000 unsigned ndmi;
2001 struct pine *ps = pine_state;
2003 mouse_get_last (NULL, &mp);
2005 #ifdef _WINDOWS
2006 if(mp.button == M_BUTTON_RIGHT){
2007 if(!mp.doubleclick){
2008 static MPopup main_popup[] = {
2009 {tQueue, {"Folder List", lNormal}, {'L'}},
2010 {tQueue, {"Message Index", lNormal}, {'I'}},
2011 {tSeparator},
2012 {tQueue, {"Address Book", lNormal}, {'A'}},
2013 {tQueue, {"Setup Options", lNormal}, {'S'}},
2014 {tTail}
2017 mswin_popup(main_popup);
2020 else {
2021 #endif
2022 if (mp.row >= (HEADER_ROWS(ps) + MNSKIP(ps)))
2023 ndmi = (mp.row+1 - HEADER_ROWS(ps) - (MNSKIP(ps)+1))/(MNSKIP(ps)+1);
2025 if (mp.row >= (HEADER_ROWS(ps) + MNSKIP(ps))
2026 && !(MNSKIP(ps) && (mp.row+1) & 0x01)
2027 && ndmi <= MAX_MENU_ITEM
2028 && FOOTER_ROWS(ps) + (ndmi+1)*(MNSKIP(ps)+1)
2029 + MNSKIP(ps) + FOOTER_ROWS(ps) <= ps->ttyo->screen_rows){
2030 if(mp.doubleclick){
2031 switch(ndmi){ /* fake main_screen request */
2032 case 0 :
2033 goto help_case;
2035 case 1 :
2036 pine_state->next_screen = compose_screen;
2037 return;
2039 case 2 :
2040 pine_state->next_screen = mail_index_screen;
2041 return;
2043 case 3 :
2044 pine_state->next_screen = folder_screen;
2045 return;
2047 case 4 :
2048 pine_state->next_screen = addr_book_screen;
2049 return;
2051 case 5 :
2052 goto setup_case;
2054 case 6 :
2055 pine_state->next_screen = quit_screen;
2056 return;
2058 default: /* no op */
2059 break;
2062 else{
2063 menu_index = ndmi;
2064 pine_state->mangled_body = 1;
2065 if(km->which == 0)
2066 pine_state->mangled_footer = 1;
2068 just_a_navigate_cmd++;
2071 #ifdef _WINDOWS
2073 #endif
2076 break;
2077 #endif
2080 /*------ Input timeout ------*/
2081 case MC_NONE :
2082 break; /* noop for timeout loop mail check */
2085 /*------ Bogus Input ------*/
2086 case MC_UNKNOWN :
2087 if(ch == 'm' || ch == 'M'){
2088 q_status_message(SM_ORDER, 0, 1, "Already in Main Menu");
2089 break;
2092 default:
2093 bogus_command(ch, F_ON(F_USE_FK,pine_state) ? "F1" : "?");
2094 break;
2096 case MC_UTF8:
2097 bogus_utf8_command(utf8str, F_ON(F_USE_FK, pine_state) ? "F1" : "?");
2098 break;
2099 } /* the switch */
2100 } /* the BIG while loop! */
2104 /*----------------------------------------------------------------------
2105 Re-Draw the main menu
2107 Args: none.
2109 Result: main menu is re-displayed
2110 ----*/
2111 void
2112 main_redrawer(void)
2114 struct key_menu *km = &main_keymenu;
2116 ps_global->mangled_screen = 1;
2117 show_main_screen(ps_global, 0, FirstMenu, km, 0, (Pos *)NULL);
2121 /*----------------------------------------------------------------------
2122 Draw the main menu
2124 Args: pine_state - the usual struct
2125 quick_draw - tells do_menu() it can skip some drawing
2126 what - tells which section of keymenu to draw
2127 km - the keymenu
2128 cursor_pos - returns a good position for the cursor to be located
2130 Result: main menu is displayed
2131 ----*/
2132 void
2133 show_main_screen(struct pine *ps, int quick_draw, OtherMenu what,
2134 struct key_menu *km, int km_popped, Pos *cursor_pos)
2136 if(ps->painted_body_on_startup || ps->painted_footer_on_startup){
2137 ps->mangled_screen = 0; /* only worry about it here */
2138 ps->mangled_header = 1; /* we have to redo header */
2139 if(!ps->painted_body_on_startup)
2140 ps->mangled_body = 1; /* make sure to paint body*/
2142 if(!ps->painted_footer_on_startup)
2143 ps->mangled_footer = 1; /* make sure to paint footer*/
2145 ps->painted_body_on_startup = 0;
2146 ps->painted_footer_on_startup = 0;
2149 if(ps->mangled_screen){
2150 ps->mangled_header = 1;
2151 ps->mangled_body = 1;
2152 ps->mangled_footer = 1;
2153 ps->mangled_screen = 0;
2156 #ifdef _WINDOWS
2157 /* Reset the scroll range. Main screen never scrolls. */
2158 scroll_setrange (0L, 0L);
2159 mswin_beginupdate();
2160 #endif
2162 /* paint the titlebar if needed */
2163 if(ps->mangled_header){
2164 /* TRANSLATORS: screen title */
2165 set_titlebar(_("MAIN MENU"), ps->mail_stream, ps->context_current,
2166 ps->cur_folder, ps->msgmap, 1, FolderName, 0, 0, NULL);
2167 ps->mangled_header = 0;
2170 /* paint the body if needed */
2171 if(ps->mangled_body){
2172 if(!quick_draw)
2173 ClearBody();
2175 do_menu(quick_draw, cursor_pos, km);
2176 ps->mangled_body = 0;
2179 /* paint the keymenu if needed */
2180 if(km && ps->mangled_footer){
2181 static char label[LONGEST_LABEL + 2 + 1], /* label + brackets + \0 */
2182 name[8];
2183 bitmap_t bitmap;
2185 setbitmap(bitmap);
2187 #ifdef KEYBOARD_LOCK
2188 if(ps_global->restricted || F_ON(F_DISABLE_KBLOCK_CMD,ps_global))
2189 #endif
2190 clrbitn(MAIN_KBLOCK_KEY, bitmap);
2192 menu_clear_binding(km, '>');
2193 menu_clear_binding(km, '.');
2194 menu_clear_binding(km, KEY_RIGHT);
2195 menu_clear_binding(km, ctrl('M'));
2196 menu_clear_binding(km, ctrl('J'));
2197 km->keys[MAIN_DEFAULT_KEY].bind
2198 = km->keys[mkeys[menu_index].key_index].bind;
2199 km->keys[MAIN_DEFAULT_KEY].label
2200 = km->keys[mkeys[menu_index].key_index].label;
2202 /* put brackets around the default action */
2203 snprintf(label, sizeof(label), "[%s]", km->keys[mkeys[menu_index].key_index].label);
2204 label[sizeof(label)-1] = '\0';
2205 strncpy(name, ">", sizeof(name));
2206 name[sizeof(name)-1] = '\0';
2207 km->keys[MAIN_DEFAULT_KEY].label = label;
2208 km->keys[MAIN_DEFAULT_KEY].name = name;
2209 menu_add_binding(km, '>', km->keys[MAIN_DEFAULT_KEY].bind.cmd);
2210 menu_add_binding(km, '.', km->keys[MAIN_DEFAULT_KEY].bind.cmd);
2211 menu_add_binding(km, ctrl('M'), km->keys[MAIN_DEFAULT_KEY].bind.cmd);
2212 menu_add_binding(km, ctrl('J'), km->keys[MAIN_DEFAULT_KEY].bind.cmd);
2214 if(F_ON(F_ARROW_NAV,ps_global))
2215 menu_add_binding(km, KEY_RIGHT, km->keys[MAIN_DEFAULT_KEY].bind.cmd);
2217 if(km_popped){
2218 FOOTER_ROWS(ps) = 3;
2219 clearfooter(ps);
2222 draw_keymenu(km, bitmap, ps_global->ttyo->screen_cols,
2223 1-FOOTER_ROWS(ps_global), 0, what);
2224 ps->mangled_footer = 0;
2225 if(km_popped){
2226 FOOTER_ROWS(ps) = 1;
2227 mark_keymenu_dirty();
2231 #ifdef _WINDOWS
2232 mswin_endupdate();
2233 #endif
2237 /*----------------------------------------------------------------------
2238 Actually display the main menu
2240 Args: quick_draw - just a next or prev command was typed so we only have
2241 to redraw the highlighting
2242 cursor_pos - a place to return a good value for cursor location
2244 Result: Main menu is displayed
2245 ---*/
2246 void
2247 do_menu(int quick_draw, Pos *cursor_pos, struct key_menu *km)
2249 struct pine *ps = ps_global;
2250 int dline, indent, longest = 0, cmd;
2251 char buf[4*MAX_SCREEN_COLS+1];
2252 char buf2[4*MAX_SCREEN_COLS+1];
2253 static int last_inverse = -1;
2254 Pos pos;
2256 /* find the longest command */
2257 for(cmd = 0; cmd < sizeof(mkeys)/(sizeof(mkeys[1])); cmd++){
2258 memset((void *) buf, ' ', sizeof(buf));
2259 snprintf(buf, sizeof(buf), mkeys[cmd].key_and_name[0] ? _(mkeys[cmd].key_and_name) : "",
2260 (F_OFF(F_USE_FK,ps)
2261 && km->keys[mkeys[cmd].key_index].name)
2262 ? km->keys[mkeys[cmd].key_index].name : "",
2263 (ps->VAR_NEWS_SPEC && mkeys[cmd].news_addition && mkeys[cmd].news_addition[0])
2264 ? _(mkeys[cmd].news_addition) : "");
2265 buf[sizeof(buf)-1] = '\0';
2267 if(longest < (indent = utf8_width(buf)))
2268 longest = indent;
2271 indent = MAX(((ps->ttyo->screen_cols - longest)/2) - 1, 0);
2273 dline = HEADER_ROWS(ps) + MNSKIP(ps);
2274 for(cmd = 0; cmd < sizeof(mkeys)/(sizeof(mkeys[1])); cmd++){
2275 /* leave room for copyright and footer */
2276 if(dline + MNSKIP(ps) + 1 + FOOTER_ROWS(ps) >= ps->ttyo->screen_rows)
2277 break;
2279 if(quick_draw && !(cmd == last_inverse || cmd == menu_index)){
2280 dline += (1 + MNSKIP(ps));
2281 continue;
2284 if(cmd == menu_index)
2285 StartInverse();
2287 memset((void *) buf, ' ', sizeof(buf));
2288 snprintf(buf, sizeof(buf), mkeys[cmd].key_and_name[0] ? _(mkeys[cmd].key_and_name) : "",
2289 (F_OFF(F_USE_FK,ps)
2290 && km->keys[mkeys[cmd].key_index].name)
2291 ? km->keys[mkeys[cmd].key_index].name : "",
2292 (ps->VAR_NEWS_SPEC && mkeys[cmd].news_addition && mkeys[cmd].news_addition[0])
2293 ? _(mkeys[cmd].news_addition) : "");
2294 buf[sizeof(buf)-1] = '\0';
2296 utf8_pad_to_width(buf2, buf, sizeof(buf2),
2297 MIN(ps->ttyo->screen_cols-indent,longest+1), 1);
2298 pos.row = dline++;
2299 pos.col = indent;
2300 PutLine0(pos.row, pos.col, buf2);
2302 if(MNSKIP(ps))
2303 dline++;
2305 if(cmd == menu_index){
2306 if(cursor_pos){
2307 cursor_pos->row = pos.row;
2308 /* 6 is 1 for the letter plus 5 spaces */
2309 cursor_pos->col = pos.col + 6;
2310 if(F_OFF(F_USE_FK,ps))
2311 cursor_pos->col++;
2313 cursor_pos->col = MIN(cursor_pos->col, ps->ttyo->screen_cols);
2316 EndInverse();
2321 last_inverse = menu_index;
2323 if(!quick_draw && FOOTER_ROWS(ps)+1 < ps->ttyo->screen_rows){
2324 utf8_to_width(buf2, LEGAL_NOTICE, sizeof(buf2),
2325 ps->ttyo->screen_cols-3, NULL);
2326 PutLine0(ps->ttyo->screen_rows - (FOOTER_ROWS(ps)+1),
2327 MAX(0, ((ps->ttyo->screen_cols-utf8_width(buf2))/2)),
2328 buf2);
2331 fflush(stdout);
2336 choose_setup_cmd(int cmd, MSGNO_S *msgmap, SCROLL_S *sparms)
2338 int rv = 1;
2339 SRV_S *srv;
2341 if(!(srv = (SRV_S *)sparms->proc.data.p)){
2342 sparms->proc.data.p = (SRV_S *)fs_get(sizeof(*srv));
2343 srv = (SRV_S *)sparms->proc.data.p;
2344 memset(srv, 0, sizeof(*srv));
2347 ps_global->next_screen = SCREEN_FUN_NULL;
2349 switch(cmd){
2350 case MC_PRINTER :
2351 srv->cmd = 'p';
2352 break;
2354 case MC_PASSWD :
2355 srv->cmd = 'n';
2356 break;
2358 case MC_CONFIG :
2359 srv->cmd = 'c';
2360 break;
2362 case MC_SIG :
2363 srv->cmd = 's';
2364 break;
2366 case MC_ABOOKS :
2367 srv->cmd = 'a';
2368 break;
2370 case MC_CLISTS :
2371 srv->cmd = 'l';
2372 break;
2374 case MC_RULES :
2375 srv->cmd = 'r';
2376 break;
2378 case MC_DIRECTORY :
2379 srv->cmd = 'd';
2380 break;
2382 case MC_KOLOR :
2383 srv->cmd = 'k';
2384 break;
2386 case MC_REMOTE :
2387 srv->cmd = 'z';
2388 break;
2390 case MC_SECURITY : /* S/MIME setup screen */
2391 srv->cmd = 'm';
2392 break;
2394 case MC_EXCEPT :
2395 srv->exc = !srv->exc;
2396 menu_clear_binding(sparms->keys.menu, 'x');
2397 if(srv->exc){
2398 if(sparms->bar.title) fs_give((void **)&sparms->bar.title);
2399 /* TRANSLATORS: screen title */
2400 sparms->bar.title = cpystr(_("SETUP EXCEPTIONS"));
2401 ps_global->mangled_header = 1;
2402 /* TRANSLATORS: The reason the X is upper case in eXceptions
2403 is because the command key is X. It isn't necessary, just
2404 nice if it works. */
2405 menu_init_binding(sparms->keys.menu, 'x', MC_EXCEPT, "X",
2406 N_("not eXceptions"), SETUP_EXCEPT);
2408 else{
2409 if(sparms->bar.title) fs_give((void **)&sparms->bar.title);
2410 /* TRANSLATORS: screen title */
2411 sparms->bar.title = cpystr(_("SETUP"));
2412 ps_global->mangled_header = 1;
2413 menu_init_binding(sparms->keys.menu, 'x', MC_EXCEPT, "X",
2414 N_("eXceptions"), SETUP_EXCEPT);
2417 if(sparms->keys.menu->which == 1)
2418 ps_global->mangled_footer = 1;
2420 rv = 0;
2421 break;
2423 case MC_NO_EXCEPT :
2424 #if defined(DOS) || defined(OS2)
2425 q_status_message(SM_ORDER, 0, 2, _("Need argument \"-x <except_config>\" or \"PINERCEX\" file to use eXceptions"));
2426 #else
2427 q_status_message(SM_ORDER, 0, 2, _("Need argument \"-x <except_config>\" or \".pinercex\" file to use eXceptions"));
2428 #endif
2429 rv = 0;
2430 break;
2432 default:
2433 alpine_panic("Unexpected command in choose_setup_cmd");
2434 break;
2437 return(rv);
2442 setup_menu(struct pine *ps)
2444 int ret = 0, exceptions = 0;
2445 int printer = 0, passwd = 0, config = 0, sig = 0, dir = 0, smime = 0, exc = 0;
2446 SCROLL_S sargs;
2447 SRV_S *srv;
2448 STORE_S *store;
2450 if(!(store = so_get(CharStar, NULL, EDIT_ACCESS))){
2451 q_status_message(SM_ORDER | SM_DING, 3, 3, _("Error allocating space."));
2452 return(ret);
2455 #if !defined(DOS)
2456 if(!ps_global->vars[V_PRINTER].is_fixed) /* printer can be changed */
2457 printer++;
2458 #endif
2460 #ifdef PASSWD_PROG
2461 if(F_OFF(F_DISABLE_PASSWORD_CMD,ps_global)) /* password is allowed */
2462 passwd++;
2463 #endif
2465 if(F_OFF(F_DISABLE_CONFIG_SCREEN,ps_global)) /* config allowed */
2466 config++;
2468 if(F_OFF(F_DISABLE_SIGEDIT_CMD,ps_global)) /* .sig editing is allowed */
2469 sig++;
2471 #ifdef ENABLE_LDAP
2472 dir++;
2473 #endif
2475 #ifdef SMIME
2476 smime++;
2477 #endif
2479 if(ps_global->post_prc)
2480 exc++;
2482 /* TRANSLATORS: starting here we have a whole screen of help text */
2483 so_puts(store, _("This is the Setup screen for Alpine. Choose from the following commands:\n"));
2485 so_puts(store, "\n");
2486 so_puts(store, _("(E) Exit Setup:\n"));
2487 so_puts(store, _(" This puts you back at the Main Menu.\n"));
2489 if(exc){
2490 so_puts(store, "\n");
2491 so_puts(store, _("(X) eXceptions:\n"));
2492 so_puts(store, _(" This command is different from the rest. It is not actually a command\n"));
2493 so_puts(store, _(" itself. Instead, it is a toggle which modifies the behavior of the\n"));
2494 so_puts(store, _(" other commands. You toggle Exceptions editing on and off with this\n"));
2495 so_puts(store, _(" command. When it is off you will be editing (changing) your regular\n"));
2496 so_puts(store, _(" configuration file. When it is on you will be editing your exceptions\n"));
2497 so_puts(store, _(" configuration file. For example, you might want to type the command \n"));
2498 so_puts(store, _(" \"eXceptions\" followed by \"Kolor\" to setup different screen colors\n"));
2499 so_puts(store, _(" on a particular platform.\n"));
2500 so_puts(store, _(" (Note: this command does not show up on the keymenu at the bottom of\n"));
2501 so_puts(store, _(" the screen unless you press \"O\" for \"Other Commands\" --but you don't\n"));
2502 so_puts(store, _(" need to press the \"O\" in order to invoke the command.)\n"));
2505 if(printer){
2506 so_puts(store, "\n");
2507 so_puts(store, _("(P) Printer:\n"));
2508 so_puts(store, _(" Allows you to set a default printer and to define custom\n"));
2509 so_puts(store, _(" print commands.\n"));
2512 if(passwd){
2513 so_puts(store, "\n");
2514 so_puts(store, _("(N) Newpassword:\n"));
2515 so_puts(store, _(" Change your password.\n"));
2518 if(config){
2519 so_puts(store, "\n");
2520 so_puts(store, _("(C) Config:\n"));
2521 so_puts(store, _(" Allows you to set or unset many features of Alpine.\n"));
2522 so_puts(store, _(" You may also set the values of many options with this command.\n"));
2525 if(sig){
2526 so_puts(store, "\n");
2527 so_puts(store, _("(S) Signature:\n"));
2528 so_puts(store, _(" Enter or edit a custom signature which will\n"));
2529 so_puts(store, _(" be included with each new message you send.\n"));
2532 so_puts(store, "\n");
2533 so_puts(store, _("(A) AddressBooks:\n"));
2534 so_puts(store, _(" Define a non-default address book.\n"));
2536 so_puts(store, "\n");
2537 so_puts(store, _("(L) collectionLists:\n"));
2538 so_puts(store, _(" You may define groups of folders to help you better organize your mail.\n"));
2540 so_puts(store, "\n");
2541 so_puts(store, _("(R) Rules:\n"));
2542 so_puts(store, _(" This has up to six sub-categories: Roles, Index Colors, Filters,\n"));
2543 so_puts(store, _(" SetScores, Search, and Other. If the Index Colors option is\n"));
2544 so_puts(store, _(" missing you may turn it on (if possible) with Setup/Kolor.\n"));
2545 so_puts(store, _(" If Roles is missing it has probably been administratively disabled.\n"));
2547 if(dir){
2548 so_puts(store, "\n");
2549 so_puts(store, _("(D) Directory:\n"));
2550 so_puts(store, _(" Define an LDAP Directory server for Alpine's use. A directory server is\n"));
2551 so_puts(store, _(" similar to an address book, but it is usually maintained by an\n"));
2552 so_puts(store, _(" organization. It is similar to a telephone directory.\n"));
2555 so_puts(store, "\n");
2556 so_puts(store, _("(K) Kolor:\n"));
2557 so_puts(store, _(" Set custom colors for various parts of the Alpine screens. For example, the\n"));
2558 so_puts(store, _(" command key labels, the titlebar at the top of each page, and quoted\n"));
2559 so_puts(store, _(" sections of messages you are viewing.\n"));
2561 if(smime){
2562 so_puts(store, "\n");
2563 so_puts(store, _("(M) S/MIME:\n"));
2564 so_puts(store, _(" Setup for using S/MIME to verify signed messages, decrypt\n"));
2565 so_puts(store, _(" encrypted messages, and to sign or encrypt outgoing messages.\n"));
2568 so_puts(store, "\n");
2569 so_puts(store, _("(Z) RemoteConfigSetup:\n"));
2570 so_puts(store, _(" This is a command you will probably only want to use once, if at all.\n"));
2571 so_puts(store, _(" It helps you transfer your Alpine configuration data to an IMAP server,\n"));
2572 so_puts(store, _(" where it will be accessible from any of the computers you read mail\n"));
2573 so_puts(store, _(" from (using Alpine). The idea behind a remote configuration is that you\n"));
2574 so_puts(store, _(" can change your configuration in one place and have that change show\n"));
2575 so_puts(store, _(" up on all of the computers you use.\n"));
2576 so_puts(store, _(" (Note: this command does not show up on the keymenu at the bottom of\n"));
2577 so_puts(store, _(" the screen unless you press \"O\" for \"Other Commands\" --but you don't\n"));
2578 so_puts(store, _(" need to press the \"O\" in order to invoke the command.)\n"));
2580 /* put this down here for people who don't have exceptions */
2581 if(!exc){
2582 so_puts(store, "\n");
2583 so_puts(store, _("(X) eXceptions:\n"));
2584 so_puts(store, _(" This command is different from the rest. It is not actually a command\n"));
2585 so_puts(store, _(" itself. Instead, it is a toggle which modifies the behavior of the\n"));
2586 so_puts(store, _(" other commands. You toggle Exceptions editing on and off with this\n"));
2587 so_puts(store, _(" command. When it is off you will be editing (changing) your regular\n"));
2588 so_puts(store, _(" configuration file. When it is on you will be editing your exceptions\n"));
2589 so_puts(store, _(" configuration file. For example, you might want to type the command \n"));
2590 so_puts(store, _(" \"eXceptions\" followed by \"Kolor\" to setup different screen colors\n"));
2591 so_puts(store, _(" on a particular platform.\n"));
2592 so_puts(store, _(" (Note: this command does not do anything unless you have a configuration\n"));
2593 so_puts(store, _(" with exceptions enabled (you don't have that). Common ways to enable an\n"));
2594 so_puts(store, _(" exceptions config are the command line argument \"-x <exception_config>\";\n"));
2595 so_puts(store, _(" or the existence of the file \".pinercex\" for Unix Alpine, or \"PINERCEX\")\n"));
2596 so_puts(store, _(" for PC-Alpine.)\n"));
2597 so_puts(store, _(" (Another note: this command does not show up on the keymenu at the bottom\n"));
2598 so_puts(store, _(" of the screen unless you press \"O\" for \"Other Commands\" --but you\n"));
2599 so_puts(store, _(" don't need to press the \"O\" in order to invoke the command.)\n"));
2602 memset(&sargs, 0, sizeof(SCROLL_S));
2603 sargs.text.text = so_text(store);
2604 sargs.text.src = CharStar;
2605 sargs.text.desc = _("Information About Setup Command");
2606 sargs.bar.title = cpystr(_("SETUP"));
2607 sargs.proc.tool = choose_setup_cmd;
2608 sargs.help.text = NO_HELP;
2609 sargs.help.title = NULL;
2610 sargs.keys.menu = &choose_setup_keymenu;
2611 sargs.keys.menu->how_many = 2;
2613 setbitmap(sargs.keys.bitmap);
2614 if(!printer)
2615 clrbitn(SETUP_PRINTER, sargs.keys.bitmap);
2617 if(!passwd)
2618 clrbitn(SETUP_PASSWD, sargs.keys.bitmap);
2620 if(!config)
2621 clrbitn(SETUP_CONFIG, sargs.keys.bitmap);
2623 if(!sig)
2624 clrbitn(SETUP_SIG, sargs.keys.bitmap);
2626 if(!dir)
2627 clrbitn(SETUP_DIRECTORY, sargs.keys.bitmap);
2629 if(!smime)
2630 clrbitn(SETUP_SMIME, sargs.keys.bitmap);
2632 if(exc)
2633 menu_init_binding(sargs.keys.menu, 'x', MC_EXCEPT, "X",
2634 N_("eXceptions"), SETUP_EXCEPT);
2635 else
2636 menu_init_binding(sargs.keys.menu, 'x', MC_NO_EXCEPT, "X",
2637 N_("eXceptions"), SETUP_EXCEPT);
2640 scrolltool(&sargs);
2642 ps->mangled_screen = 1;
2644 srv = (SRV_S *)sargs.proc.data.p;
2646 exceptions = srv ? srv->exc : 0;
2648 so_give(&store);
2650 if(sargs.bar.title) fs_give((void**)&sargs.bar.title);
2651 if(srv){
2652 ret = srv->cmd;
2653 fs_give((void **)&sargs.proc.data.p);
2655 else
2656 ret = 'e';
2658 return(ret | (exceptions ? EDIT_EXCEPTION : 0));
2662 /*----------------------------------------------------------------------
2664 Args: command -- command char to perform
2666 ----*/
2667 void
2668 do_setup_task(int command)
2670 char *err = NULL;
2671 int rtype;
2672 int edit_exceptions = 0;
2673 int do_lit_sig = 0;
2675 if(command & EDIT_EXCEPTION){
2676 edit_exceptions = 1;
2677 command &= ~EDIT_EXCEPTION;
2680 switch(command) {
2681 /*----- EDIT SIGNATURE -----*/
2682 case 's':
2683 if(ps_global->VAR_LITERAL_SIG)
2684 do_lit_sig = 1;
2685 else {
2686 char sig_path[MAXPATH+1];
2688 if(!signature_path(ps_global->VAR_SIGNATURE_FILE, sig_path, MAXPATH))
2689 do_lit_sig = 1;
2690 else if((!IS_REMOTE(ps_global->VAR_SIGNATURE_FILE)
2691 && can_access(sig_path, READ_ACCESS) == 0)
2692 ||(IS_REMOTE(ps_global->VAR_SIGNATURE_FILE)
2693 && (folder_exists(NULL, sig_path) & FEX_ISFILE)))
2694 do_lit_sig = 0;
2695 else if(!ps_global->vars[V_SIGNATURE_FILE].main_user_val.p
2696 && !ps_global->vars[V_SIGNATURE_FILE].cmdline_val.p
2697 && !ps_global->vars[V_SIGNATURE_FILE].fixed_val.p)
2698 do_lit_sig = 1;
2699 else
2700 do_lit_sig = 0;
2703 if(do_lit_sig){
2704 char *result = NULL;
2705 char **apval;
2706 EditWhich ew;
2707 int readonly = 0;
2709 ew = edit_exceptions ? ps_global->ew_for_except_vars : Main;
2711 if(ps_global->restricted)
2712 readonly = 1;
2713 else switch(ew){
2714 case Main:
2715 readonly = ps_global->prc->readonly;
2716 break;
2717 case Post:
2718 readonly = ps_global->post_prc->readonly;
2719 break;
2720 default:
2721 break;
2724 if(readonly)
2725 err = cpystr(ps_global->restricted
2726 ? "Alpine demo can't change config file"
2727 : _("Config file not changeable"));
2729 if(!err){
2730 apval = APVAL(&ps_global->vars[V_LITERAL_SIG], ew);
2731 if(!apval)
2732 err = cpystr(_("Problem accessing configuration"));
2733 else{
2734 char *input;
2736 input = (char *)fs_get((strlen(*apval ? *apval : "")+1) *
2737 sizeof(char));
2738 input[0] = '\0';
2739 cstring_to_string(*apval, input);
2740 err = signature_edit_lit(input, &result,
2741 _("SIGNATURE EDITOR"),
2742 h_composer_sigedit);
2743 fs_give((void **)&input);
2747 if(!err){
2748 char *cstring_version;
2750 cstring_version = string_to_cstring(result);
2752 set_variable(V_LITERAL_SIG, cstring_version, 0, 0, ew);
2754 if(cstring_version)
2755 fs_give((void **)&cstring_version);
2758 if(result)
2759 fs_give((void **)&result);
2761 else
2762 err = signature_edit(ps_global->VAR_SIGNATURE_FILE,
2763 _("SIGNATURE EDITOR"));
2765 if(err){
2766 q_status_message(SM_ORDER, 3, 4, err);
2767 fs_give((void **)&err);
2770 ps_global->mangled_screen = 1;
2771 break;
2773 /*----- ADD ADDRESSBOOK ----*/
2774 case 'a':
2775 addr_book_config(ps_global, edit_exceptions);
2776 menu_index = ABOOK_MENU_ITEM;
2777 ps_global->mangled_screen = 1;
2778 break;
2780 #ifdef ENABLE_LDAP
2781 /*--- ADD DIRECTORY SERVER --*/
2782 case 'd':
2783 directory_config(ps_global, edit_exceptions);
2784 ps_global->mangled_screen = 1;
2785 break;
2786 #endif
2788 #ifdef SMIME
2789 /*--- S/MIME --*/
2790 case 'm':
2791 smime_config_screen(ps_global, edit_exceptions);
2792 ps_global->mangled_screen = 1;
2793 break;
2794 #endif
2796 /*----- CONFIGURE OPTIONS -----*/
2797 case 'c':
2798 option_screen(ps_global, edit_exceptions);
2799 ps_global->mangled_screen = 1;
2800 break;
2802 /*----- COLLECTION LIST -----*/
2803 case 'l':
2804 folder_config_screen(ps_global, edit_exceptions);
2805 ps_global->mangled_screen = 1;
2806 break;
2808 /*----- RULES -----*/
2809 case 'r':
2810 rtype = rule_setup_type(ps_global, RS_RULES | RS_INCFILTNOW,
2811 _("Type of rule setup : "));
2812 switch(rtype){
2813 case 'r':
2814 case 's':
2815 case 'i':
2816 case 'f':
2817 case 'o':
2818 case 'c':
2819 role_config_screen(ps_global, (rtype == 'r') ? ROLE_DO_ROLES :
2820 (rtype == 's') ? ROLE_DO_SCORES :
2821 (rtype == 'o') ? ROLE_DO_OTHER :
2822 (rtype == 'f') ? ROLE_DO_FILTER :
2823 (rtype == 'c') ? ROLE_DO_SRCH :
2824 ROLE_DO_INCOLS,
2825 edit_exceptions);
2826 break;
2828 case 'Z':
2829 q_status_message(SM_ORDER | SM_DING, 3, 5,
2830 _("Try turning on color with the Setup/Kolor command."));
2831 break;
2833 case 'n':
2834 role_process_filters();
2835 break;
2837 default:
2838 cmd_cancelled(NULL);
2839 break;
2842 ps_global->mangled_screen = 1;
2843 break;
2845 /*----- COLOR -----*/
2846 case 'k':
2847 color_config_screen(ps_global, edit_exceptions);
2848 ps_global->mangled_screen = 1;
2849 break;
2851 case 'z':
2852 convert_to_remote_config(ps_global, edit_exceptions);
2853 ps_global->mangled_screen = 1;
2854 break;
2856 /*----- EXIT -----*/
2857 case 'e':
2858 break;
2860 /*----- NEW PASSWORD -----*/
2861 case 'n':
2862 #ifdef PASSWD_PROG
2863 if(ps_global->restricted){
2864 q_status_message(SM_ORDER, 3, 5,
2865 "Password change unavailable in restricted demo version of Alpine.");
2866 }else {
2867 change_passwd();
2868 ClearScreen();
2869 ps_global->mangled_screen = 1;
2871 #else
2872 q_status_message(SM_ORDER, 0, 5,
2873 _("Password changing not configured for this version of Alpine."));
2874 display_message('x');
2875 #endif /* DOS */
2876 break;
2878 #if !defined(DOS)
2879 /*----- CHOOSE PRINTER ------*/
2880 case 'p':
2881 select_printer(ps_global, edit_exceptions);
2882 ps_global->mangled_screen = 1;
2883 break;
2884 #endif
2890 rule_setup_type(struct pine *ps, int flags, char *prompt)
2892 ESCKEY_S opts[9];
2893 int ekey_num = 0, deefault = 0;
2895 if(flags & RS_INCADDR){
2896 deefault = 'a';
2897 opts[ekey_num].ch = 'a';
2898 opts[ekey_num].rval = 'a';
2899 opts[ekey_num].name = "A";
2900 opts[ekey_num++].label = "Addrbook";
2903 if(flags & RS_RULES){
2905 if(F_OFF(F_DISABLE_ROLES_SETUP,ps)){ /* roles are allowed */
2906 if(deefault != 'a')
2907 deefault = 'r';
2909 opts[ekey_num].ch = 'r';
2910 opts[ekey_num].rval = 'r';
2911 opts[ekey_num].name = "R";
2912 opts[ekey_num++].label = "Roles";
2914 else if(deefault != 'a')
2915 deefault = 's';
2917 opts[ekey_num].ch = 's';
2918 opts[ekey_num].rval = 's';
2919 opts[ekey_num].name = "S";
2920 opts[ekey_num++].label = "SetScores";
2922 #ifndef _WINDOWS
2923 if(ps->color_style != COL_NONE && pico_hascolor()){
2924 #endif
2925 if(deefault != 'a')
2926 deefault = 'i';
2928 opts[ekey_num].ch = 'i';
2929 opts[ekey_num].rval = 'i';
2930 opts[ekey_num].name = "I";
2931 opts[ekey_num++].label = "Indexcolor";
2932 #ifndef _WINDOWS
2934 else{
2935 opts[ekey_num].ch = 'i';
2936 opts[ekey_num].rval = 'Z'; /* notice this rval! */
2937 opts[ekey_num].name = "I";
2938 opts[ekey_num++].label = "Indexcolor";
2940 #endif
2942 opts[ekey_num].ch = 'f';
2943 opts[ekey_num].rval = 'f';
2944 opts[ekey_num].name = "F";
2945 opts[ekey_num++].label = "Filters";
2947 opts[ekey_num].ch = 'o';
2948 opts[ekey_num].rval = 'o';
2949 opts[ekey_num].name = "O";
2950 opts[ekey_num++].label = "Other";
2952 opts[ekey_num].ch = 'c';
2953 opts[ekey_num].rval = 'c';
2954 opts[ekey_num].name = "C";
2955 opts[ekey_num++].label = "searCh";
2959 if(flags & RS_INCEXP){
2960 opts[ekey_num].ch = 'e';
2961 opts[ekey_num].rval = 'e';
2962 opts[ekey_num].name = "E";
2963 opts[ekey_num++].label = "Export";
2966 if(flags & RS_INCFILTNOW){
2967 opts[ekey_num].ch = 'n';
2968 opts[ekey_num].rval = 'n';
2969 opts[ekey_num].name = "N";
2970 opts[ekey_num++].label = "filterNow";
2973 opts[ekey_num].ch = -1;
2975 return(radio_buttons(prompt, -FOOTER_ROWS(ps), opts,
2976 deefault, 'x', NO_HELP, RB_NORM));
2982 * Process the command list, changing function key notation into
2983 * lexical equivalents.
2985 void
2986 process_init_cmds(struct pine *ps, char **list)
2988 char **p;
2989 int i = 0;
2990 int j;
2991 int lpm1;
2992 #define MAX_INIT_CMDS 500
2993 /* this is just a temporary stack array, the real one is allocated below */
2994 int i_cmds[MAX_INIT_CMDS];
2995 int fkeys = 0;
2996 int not_fkeys = 0;
2998 if(list){
2999 for(p = list; *p; p++){
3000 if(i >= MAX_INIT_CMDS){
3001 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
3002 "Initial keystroke list too long at \"%s\"", *p);
3003 init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
3004 break;
3008 /* regular character commands */
3009 if(strlen(*p) == 1){
3010 i_cmds[i++] = **p;
3011 not_fkeys++;
3014 /* special commands */
3015 else if(strucmp(*p, "SPACE") == 0)
3016 i_cmds[i++] = ' ';
3017 else if(strucmp(*p, "CR") == 0)
3018 i_cmds[i++] = '\n';
3019 else if(strucmp(*p, "TAB") == 0)
3020 i_cmds[i++] = '\t';
3021 else if(strucmp(*p, "UP") == 0)
3022 i_cmds[i++] = KEY_UP;
3023 else if(strucmp(*p, "DOWN") == 0)
3024 i_cmds[i++] = KEY_DOWN;
3025 else if(strucmp(*p, "LEFT") == 0)
3026 i_cmds[i++] = KEY_LEFT;
3027 else if(strucmp(*p, "RIGHT") == 0)
3028 i_cmds[i++] = KEY_RIGHT;
3030 /* control chars */
3031 else if(strlen(*p) == 2 && **p == '^')
3032 i_cmds[i++] = ctrl(*((*p)+1));
3034 /* function keys */
3035 else if(**p == 'F' || **p == 'f'){
3036 int v;
3038 fkeys++;
3039 v = atoi((*p)+1);
3040 if(v >= 1 && v <= 12)
3041 i_cmds[i++] = PF1 + v - 1;
3042 else
3043 i_cmds[i++] = KEY_JUNK;
3046 /* literal string */
3047 else if(**p == '"' && (*p)[lpm1 = strlen(*p) - 1] == '"'){
3048 if(lpm1 + i - 1 > MAX_INIT_CMDS){
3049 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
3050 "Initial keystroke list too long, truncated at %s\n", *p);
3051 init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
3052 break; /* Bail out of this loop! */
3053 } else
3054 for(j = 1; j < lpm1; j++)
3055 i_cmds[i++] = (*p)[j];
3057 else {
3058 snprintf(tmp_20k_buf,SIZEOF_20KBUF,
3059 "Bad initial keystroke \"%.500s\" (missing comma?)", *p);
3060 init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
3061 break;
3067 * We don't handle the case where function keys are used to specify the
3068 * commands but some non-function key input is also required. For example,
3069 * you might want to jump to a specific message number and view it
3070 * on start up. To do that, you need to use character commands instead
3071 * of function key commands in the initial-keystroke-list.
3073 if(fkeys && not_fkeys){
3074 init_error(ps, SM_ORDER | SM_DING, 3, 5,
3075 "Mixed characters and function keys in \"initial-keystroke-list\", skipping.");
3076 i = 0;
3079 if(fkeys && !not_fkeys)
3080 F_TURN_ON(F_USE_FK,ps);
3081 if(!fkeys && not_fkeys)
3082 F_TURN_OFF(F_USE_FK,ps);
3084 if(i > 0){
3085 ps->initial_cmds = (int *)fs_get((i+1) * sizeof(int));
3086 ps->free_initial_cmds = ps->initial_cmds;
3087 for(j = 0; j < i; j++)
3088 ps->initial_cmds[j] = i_cmds[j];
3090 ps->initial_cmds[i] = 0;
3091 ps->in_init_seq = ps->save_in_init_seq = 1;
3096 UCS *
3097 user_wordseps(char **list)
3099 char **p;
3100 int i = 0;
3101 int j;
3102 #define MAX_SEPARATORS 500
3104 * This is just a temporary stack array, the real one is allocated below.
3105 * This is supposed to be way large enough.
3107 UCS seps[MAX_SEPARATORS+1];
3108 UCS *u;
3109 UCS *return_array = NULL;
3110 size_t l;
3112 seps[0] = '\0';
3114 if(list){
3115 for(p = list; *p; p++){
3116 if(i >= MAX_SEPARATORS){
3117 q_status_message(SM_ORDER | SM_DING, 3, 3,
3118 "Warning: composer-word-separators list is too long");
3119 break;
3122 u = utf8_to_ucs4_cpystr(*p);
3124 if(u){
3125 if(ucs4_strlen(u) == 1)
3126 seps[i++] = *u;
3127 else if(*u == '"' && u[l = ucs4_strlen(u) - 1] == '"'){
3128 if(l + i - 1 > MAX_SEPARATORS){
3129 q_status_message(SM_ORDER | SM_DING, 3, 3,
3130 "Warning: composer-word-separators list is too long");
3131 break; /* Bail out of this loop! */
3133 else{
3134 for(j = 1; j < l; j++)
3135 seps[i++] = u[j];
3138 else{
3139 l = ucs4_strlen(u);
3140 if(l + i > MAX_SEPARATORS){
3141 q_status_message(SM_ORDER | SM_DING, 3, 3,
3142 "Warning: composer-word-separators list is too long");
3143 break; /* Bail out of this loop! */
3145 else{
3146 for(j = 0; j < l; j++)
3147 seps[i++] = u[j];
3151 fs_give((void **) &u);
3156 seps[i] = '\0';
3158 if(i > 0)
3159 return_array = ucs4_cpystr(seps);
3161 return(return_array);
3166 * Make sure any errors during initialization get queued for display
3168 void
3169 queue_init_errors(struct pine *ps)
3171 int i;
3173 if(ps->init_errs){
3174 for(i = 0; (ps->init_errs)[i].message; i++){
3175 q_status_message((ps->init_errs)[i].flags,
3176 (ps->init_errs)[i].min_time,
3177 (ps->init_errs)[i].max_time,
3178 (ps->init_errs)[i].message);
3179 fs_give((void **)&(ps->init_errs)[i].message);
3182 fs_give((void **)&ps->init_errs);
3187 /*----------------------------------------------------------------------
3188 Quit pine if the user wants to
3190 Args: The usual pine structure
3192 Result: User is asked if she wants to quit, if yes then execute quit.
3194 Q U I T S C R E E N
3196 Not really a full screen. Just count up deletions and ask if we really
3197 want to quit.
3198 ----*/
3199 void
3200 quit_screen(struct pine *pine_state)
3202 int quit = 0;
3204 dprint((1, "\n\n ---- QUIT SCREEN ----\n"));
3206 if(F_ON(F_CHECK_MAIL_ONQUIT,ps_global)
3207 && new_mail(1, VeryBadTime, NM_STATUS_MSG | NM_DEFER_SORT) > 0
3208 && (quit = want_to(_("Quit even though new mail just arrived"), 'y', 0,
3209 NO_HELP, WT_NORM)) != 'y'){
3210 refresh_sort(pine_state->mail_stream, pine_state->msgmap, SRT_VRB);
3211 pine_state->next_screen = pine_state->prev_screen;
3212 return;
3215 if(quit != 'y'
3216 && F_OFF(F_QUIT_WO_CONFIRM,pine_state)
3217 && want_to(_("Really quit Alpine"), 'y', 0, NO_HELP, WT_NORM) != 'y'){
3218 pine_state->next_screen = pine_state->prev_screen;
3219 return;
3222 goodnight_gracey(pine_state, 0);
3226 /*----------------------------------------------------------------------
3227 The nuts and bolts of actually cleaning up and exitting pine
3229 Args: ps -- the usual pine structure,
3230 exit_val -- what to tell our parent
3232 Result: This never returns
3234 ----*/
3235 void
3236 goodnight_gracey(struct pine *pine_state, int exit_val)
3238 int i, cnt_user_streams = 0;
3239 char *final_msg = NULL;
3240 char msg[MAX_SCREEN_COLS+1];
3241 char *pf = _("Alpine finished");
3242 MAILSTREAM *m;
3243 extern KBESC_T *kbesc;
3245 dprint((2, "goodnight_gracey:\n"));
3247 /* We want to do this here before we close up the streams */
3248 trim_remote_adrbks();
3250 for(i = 0; i < ps_global->s_pool.nstream; i++){
3251 m = ps_global->s_pool.streams[i];
3252 if(m && sp_flagged(m, SP_LOCKED) && sp_flagged(m, SP_USERFLDR))
3253 cnt_user_streams++;
3256 /* clean up open streams */
3258 if(pine_state->mail_stream
3259 && sp_flagged(pine_state->mail_stream, SP_LOCKED)
3260 && sp_flagged(pine_state->mail_stream, SP_USERFLDR)){
3261 dprint((5, "goodnight_gracey: close current stream\n"));
3262 expunge_and_close(pine_state->mail_stream,
3263 (cnt_user_streams <= 1) ? &final_msg : NULL, EC_NONE);
3264 cnt_user_streams--;
3267 pine_state->mail_stream = NULL;
3268 pine_state->redrawer = (void (*)(void))NULL;
3270 dprint((5,
3271 "goodnight_gracey: close other stream pool streams\n"));
3272 for(i = 0; i < ps_global->s_pool.nstream; i++){
3273 m = ps_global->s_pool.streams[i];
3275 * fix global for functions that depend(ed) on it sort_folder.
3276 * Hopefully those will get phased out.
3278 ps_global->mail_stream = m;
3279 if(m && sp_flagged(m, SP_LOCKED) && sp_flagged(m, SP_USERFLDR)
3280 && !sp_flagged(m, SP_INBOX)){
3281 sp_set_expunge_count(m, 0L);
3282 expunge_and_close(m, (cnt_user_streams <= 1) ? &final_msg : NULL,
3283 EC_NONE);
3284 cnt_user_streams--;
3288 for(i = 0; i < ps_global->s_pool.nstream; i++){
3289 m = ps_global->s_pool.streams[i];
3291 * fix global for functions that depend(ed) on it (sort_folder).
3292 * Hopefully those will get phased out.
3294 ps_global->mail_stream = m;
3295 if(m && sp_flagged(m, SP_LOCKED) && sp_flagged(m, SP_USERFLDR)
3296 && sp_flagged(m, SP_INBOX)){
3297 dprint((5,
3298 "goodnight_gracey: close inbox stream stream\n"));
3299 sp_set_expunge_count(m, 0L);
3300 expunge_and_close(m, (cnt_user_streams <= 1) ? &final_msg : NULL,
3301 EC_NONE);
3302 cnt_user_streams--;
3306 #ifdef _WINDOWS
3307 if(ps_global->ttyo)
3308 (void)get_windsize(ps_global->ttyo);
3309 #endif
3311 dprint((7, "goodnight_gracey: close config files\n"));
3313 free_pinerc_strings(&pine_state);
3315 strncpy(msg, pf, sizeof(msg));
3316 msg[sizeof(msg)-1] = '\0';
3317 if(final_msg){
3318 strncat(msg, " -- ", sizeof(msg)-strlen(msg)-1);
3319 msg[sizeof(msg)-1] = '\0';
3320 strncat(msg, final_msg, sizeof(msg)-strlen(msg)-1);
3321 msg[sizeof(msg)-1] = '\0';
3322 fs_give((void **)&final_msg);
3325 dprint((7, "goodnight_gracey: sp_end\n"));
3326 ps_global->noshow_error = 1;
3327 sp_end();
3329 #ifdef SMIME
3330 smime_deinit();
3331 #endif
3333 /* after sp_end, which might call a filter */
3334 completely_done_with_adrbks();
3336 dprint((7, "goodnight_gracey: end_screen\n"));
3337 end_screen(msg, exit_val);
3338 dprint((7, "goodnight_gracey: end_titlebar\n"));
3339 end_titlebar();
3340 dprint((7, "goodnight_gracey: end_keymenu\n"));
3341 end_keymenu();
3343 dprint((7, "goodnight_gracey: end_keyboard\n"));
3344 end_keyboard(F_ON(F_USE_FK,pine_state));
3345 dprint((7, "goodnight_gracey: end_ttydriver\n"));
3346 end_tty_driver(pine_state);
3347 #if !defined(DOS) && !defined(OS2)
3348 kbdestroy(kbesc);
3349 #if !defined(LEAVEOUTFIFO)
3350 close_newmailfifo();
3351 #endif
3352 #endif
3353 end_signals(0);
3354 if(filter_data_file(0))
3355 our_unlink(filter_data_file(0));
3357 imap_flush_passwd_cache(TRUE);
3358 free_newsgrp_cache();
3359 mailcap_free();
3360 close_every_pattern();
3361 free_extra_hdrs();
3362 free_contexts(&ps_global->context_list);
3363 free_charsetchecker();
3364 dprint((7, "goodnight_gracey: free more memory\n"));
3365 #ifdef ENABLE_LDAP
3366 free_saved_query_parameters();
3367 #endif
3369 free_pine_struct(&pine_state);
3371 free_histlist();
3373 free_alpine_module_globals(); /* should we have module globals? */
3374 free_pith_module_globals();
3375 free_pico_module_globals();
3376 free_c_client_module_globals();
3378 #ifdef DEBUG
3379 if(debugfile){
3380 if(debug >= 2)
3381 fputs("goodnight_gracey finished\n", debugfile);
3383 fclose(debugfile);
3385 #endif
3387 exit(exit_val);
3391 /*----------------------------------------------------------------------
3392 Call back for c-client to feed us back the progress of network reads
3394 Input:
3396 Result:
3397 ----*/
3398 void
3399 pine_read_progress(GETS_DATA *md, long unsigned int count)
3401 gets_bytes += count; /* update counter */
3405 /*----------------------------------------------------------------------
3406 Function to fish the current byte count from a c-client fetch.
3408 Input: reset -- flag telling us to reset the count
3410 Result: Returns the number of bytes read by the c-client so far
3411 ----*/
3412 unsigned long
3413 pine_gets_bytes(int reset)
3415 if(reset)
3416 gets_bytes = 0L;
3418 return(gets_bytes);
3422 /*----------------------------------------------------------------------
3423 Panic pine - call on detected programmatic errors to exit pine
3425 Args: message -- message to record in debug file and to be printed for user
3427 Result: The various tty modes are restored
3428 If debugging is active a core dump will be generated
3429 Exits Alpine
3431 This is also called from imap routines and fs_get and fs_resize.
3432 ----*/
3433 void
3434 alpine_panic(char *message)
3436 char buf[256];
3438 /* global variable in .../pico/edef.h */
3439 in_panic = 1;
3441 if(ps_global->ttyo){
3442 end_screen(NULL, -1);
3443 end_keyboard(ps_global != NULL ? F_ON(F_USE_FK,ps_global) : 0);
3444 end_tty_driver(ps_global);
3445 end_signals(1);
3447 if(filter_data_file(0))
3448 our_unlink(filter_data_file(0));
3450 dprint((1, "\n===========================================\n\n"));
3451 dprint((1, " Alpine Panic: %s\n\n", message ? message : "?"));
3452 dprint((1, "===========================================\n\n"));
3454 /* intercept c-client "free storage" errors */
3455 if(strstr(message, "free storage"))
3456 snprintf(buf, sizeof(buf), _("No more available memory.\nAlpine Exiting"));
3457 else
3458 snprintf(buf, sizeof(buf), _("Problem detected: \"%s\".\nAlpine Exiting."), message);
3460 buf[sizeof(buf)-1] = '\0';
3462 #ifdef _WINDOWS
3463 /* Put up a message box. */
3464 mswin_messagebox (buf, 1);
3465 #else
3466 fprintf(stderr, "\n\n%s\n", buf);
3467 #endif
3469 #ifdef DEBUG
3470 if(debugfile){
3471 save_debug_on_crash(debugfile, recent_keystroke);
3474 coredump(); /*--- If we're debugging get a core dump --*/
3475 #endif
3477 exit(-1);
3478 fatal("ffo"); /* BUG -- hack to get fatal out of library in right order*/
3483 * panicking - function to test whether or not we're exiting under stress.
3487 panicking(void)
3489 return(in_panic);
3493 /*----------------------------------------------------------------------
3494 exceptional_exit - called to exit under unusual conditions (with no core)
3496 Args: message -- message to record in debug file and to be printed for user
3497 ev -- exit value
3499 ----*/
3500 void
3501 exceptional_exit(char *message, int ev)
3503 fprintf(stderr, "%s\n", message);
3504 exit(ev);
3509 * PicoText Storage Object Support Routines
3512 STORE_S *
3513 pine_pico_get(void)
3515 return((STORE_S *)pico_get());
3519 pine_pico_give(STORE_S **sop)
3521 pico_give((void *)sop);
3522 return(1);
3526 pine_pico_writec(int c, STORE_S *so)
3528 unsigned char ch = (unsigned char) c;
3530 return(pico_writec(so->txt, ch, PICOREADC_NONE));
3534 pine_pico_writec_noucs(int c, STORE_S *so)
3536 unsigned char ch = (unsigned char) c;
3538 return(pico_writec(so->txt, ch, PICOREADC_NOUCS));
3542 pine_pico_readc(unsigned char *c, STORE_S *so)
3544 return(pico_readc(so->txt, c, PICOREADC_NONE));
3548 pine_pico_readc_noucs(unsigned char *c, STORE_S *so)
3550 return(pico_readc(so->txt, c, PICOREADC_NOUCS));
3554 pine_pico_puts(STORE_S *so, char *s)
3556 return(pico_puts(so->txt, s, PICOREADC_NONE));
3560 pine_pico_puts_noucs(STORE_S *so, char *s)
3562 return(pico_puts(so->txt, s, PICOREADC_NOUCS));
3566 pine_pico_seek(STORE_S *so, long pos, int orig)
3568 return(pico_seek((void *)so, pos, orig));
3573 remote_pinerc_failure(void)
3575 #ifdef _WINDOWS
3576 if(ps_global->install_flag) /* just exit silently */
3577 exit(0);
3578 #endif /* _WINDOWS */
3580 if(ps_global->exit_if_no_pinerc){
3581 exceptional_exit("Exiting because -bail option is set and config file not readable.", -1);
3584 if(want_to("Trouble reading remote configuration! Continue anyway ",
3585 'n', 'n', NO_HELP, WT_FLUSH_IN) != 'y'){
3586 return(0);
3589 return(1);
3593 void
3594 dump_supported_options(void)
3596 char **config;
3598 config = get_supported_options();
3599 if(config){
3600 display_args_err(NULL, config, 0);
3601 free_list_array(&config);
3606 /*----------------------------------------------------------------------
3607 Check pruned-folders for validity, making sure they are in the
3608 same context as sent-mail.
3610 ----*/
3612 prune_folders_ok(void)
3614 char **p;
3616 for(p = ps_global->VAR_PRUNED_FOLDERS; p && *p && **p; p++)
3617 if(!context_isambig(*p))
3618 return(0);
3620 return(1);
3623 void
3624 free_alpine_module_globals(void)
3626 #ifdef LOCAL_PASSWD_CACHE
3627 free_passfile_cache();
3628 #endif
3629 free_message_queue();
3630 free_titlebar_globals();
3633 #ifdef WIN32
3634 char *
3635 pine_user_callback()
3637 if(ps_global->VAR_USER_ID && ps_global->VAR_USER_ID[0]){
3638 return(ps_global->VAR_USER_ID);
3640 else{
3641 /* SHOULD PROMPT HERE! */
3642 return(NULL);
3645 #endif
3647 #ifdef _WINDOWS
3649 * windows callback to get/set function keys mode state
3652 fkey_mode_callback(set, args)
3653 int set;
3654 long args;
3656 return(F_ON(F_USE_FK, ps_global) != 0);
3660 void
3661 imap_telemetry_on()
3663 if(ps_global->mail_stream)
3664 mail_debug(ps_global->mail_stream);
3668 void
3669 imap_telemetry_off()
3671 if(ps_global->mail_stream)
3672 mail_nodebug(ps_global->mail_stream);
3676 char *
3677 pcpine_help_main(title)
3678 char *title;
3680 if(title)
3681 strncpy(title, _("PC-Alpine MAIN MENU Help"), 256);
3683 return(pcpine_help(main_menu_tx));
3688 pcpine_main_cursor(col, row)
3689 int col;
3690 long row;
3692 unsigned ndmi;
3694 if (row >= (HEADER_ROWS(ps_global) + MNSKIP(ps_global)))
3695 ndmi = (row+1 - HEADER_ROWS(ps_global) - (MNSKIP(ps_global)+1))/(MNSKIP(ps_global)+1);
3697 if (row >= (HEADER_ROWS(ps_global) + MNSKIP(ps_global))
3698 && !(MNSKIP(ps_global) && (row+1) & 0x01)
3699 && ndmi <= MAX_MENU_ITEM
3700 && FOOTER_ROWS(ps_global) + (ndmi+1)*(MNSKIP(ps_global)+1)
3701 + MNSKIP(ps_global) + FOOTER_ROWS(ps_global) <= ps_global->ttyo->screen_rows)
3702 return(MSWIN_CURSOR_HAND);
3703 else
3704 return(MSWIN_CURSOR_ARROW);
3706 #endif /* _WINDOWS */