1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: alpine.c 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2013-2020 Eduardo Chappa
8 * Copyright 2006-2008 University of Washington
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
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"
44 #include "xoauth2conf.h"
62 #include "colorconf.h"
67 #include "xoauth2conf.h"
69 #include "../pico/osdep/raw.h" /* for STD*_FD */
73 #define PIPED_FD 5 /* Some innocuous desc */
76 /* look for my_timer_period in pico directory for an explanation */
77 int my_timer_period
= ((IDLE_TIMEOUT
+ 1)*1000);
79 /* byte count used by our gets routine to keep track */
80 static unsigned long gets_bytes
;
86 void convert_args_to_utf8(struct pine
*, ARGDATA_S
*);
87 void preopen_stayopen_folders(void);
88 int read_stdin_char(char *);
89 void main_redrawer(void);
90 void show_main_screen(struct pine
*, int, OtherMenu
, struct key_menu
*, int, Pos
*);
91 void do_menu(int, Pos
*, struct key_menu
*);
92 int choose_setup_cmd(int, MSGNO_S
*, SCROLL_S
*);
93 int setup_menu(struct pine
*);
94 void do_setup_task(int);
95 void queue_init_errors(struct pine
*);
96 void process_init_cmds(struct pine
*, char **);
97 void goodnight_gracey(struct pine
*, int);
98 void pine_read_progress(GETS_DATA
*, unsigned long);
99 int remote_pinerc_failure(void);
100 void dump_supported_options(void);
101 int prune_folders_ok(void);
102 void free_alpine_module_globals(void);
104 char *pine_user_callback(void);
107 int fkey_mode_callback(int, long);
108 void imap_telemetry_on(void);
109 void imap_telemetry_off(void);
110 char *pcpine_help_main(char *);
111 int pcpine_main_cursor(int, long);
112 #define main app_main
116 typedef struct setup_return_val
{
123 * strlen of longest label from keymenu, of labels corresponding to
124 * commands in the middle of the screen. 9 is length of ListFldrs
126 #define LONGEST_LABEL 9 /* length of longest label from keymenu */
128 #define EDIT_EXCEPTION (0x100)
131 static int in_panic
= 0;
134 /*----------------------------------------------------------------------
135 main routine -- entry point
137 Args: argv, argc -- The command line arguments
140 Initialize pine, parse arguments and so on
142 If there is a user address on the command line go into send mode and exit,
143 otherwise loop executing the various screens in Alpine.
145 NOTE: The Windows port def's this to "app_main"
149 main(int argc
, char **argv
)
154 struct pine
*pine_state
;
155 gf_io_t stdin_getc
= NULL
;
156 char *args_for_debug
= NULL
, *init_pinerc_debugging
= NULL
;
158 /*----------------------------------------------------------------------
159 Set up buffering and some data structures
160 ----------------------------------------------------------------------*/
162 pine_state
= new_pine_struct();
163 ps_global
= pine_state
;
166 * fill in optional pith-offered behavior hooks
168 pith_opt_read_msg_prompt
= read_msg_prompt
;
169 pith_opt_paint_index_hline
= paint_index_hline
;
170 pith_opt_rfc2369_editorial
= rfc2369_editorial
;
171 pith_opt_condense_thread_cue
= condensed_thread_cue
;
172 pith_opt_truncate_sfstr
= truncate_subj_and_from_strings
;
173 pith_opt_save_and_restore
= save_and_restore
;
174 pith_opt_newmail_announce
= newmail_status_message
;
175 pith_opt_newmail_check_cue
= newmail_check_cue
;
176 pith_opt_checkpoint_cue
= newmail_check_point_cue
;
177 pith_opt_icon_text
= icon_text
;
178 pith_opt_rd_metadata_name
= rd_metadata_name
;
179 pith_opt_remote_pinerc_failure
= remote_pinerc_failure
;
180 pith_opt_reopen_folder
= ask_mailbox_reopen
;
181 pith_opt_expunge_prompt
= expunge_prompt
;
182 pith_opt_begin_closing
= expunge_and_close_begins
;
183 pith_opt_replyto_prompt
= reply_using_replyto_query
;
184 pith_opt_reply_to_all_prompt
= reply_to_all_query
;
185 pith_opt_save_create_prompt
= create_for_save_prompt
;
186 pith_opt_daemon_confirm
= confirm_daemon_send
;
187 pith_opt_save_size_changed_prompt
= save_size_changed_prompt
;
188 pith_opt_save_index_state
= setup_index_state
;
189 pith_opt_filter_pattern_cmd
= pattern_filter_command
;
190 pith_opt_get_signature_file
= get_signature_file
;
191 pith_opt_pretty_var_name
= pretty_var_name
;
192 pith_opt_pretty_feature_name
= pretty_feature_name
;
193 pith_opt_closing_stream
= titlebar_stream_closing
;
194 pith_opt_current_expunged
= mm_expunged_current
;
196 pith_opt_smime_get_passphrase
= smime_get_passphrase
;
197 pith_smime_import_certificate
= smime_import_certificate
;
198 pith_smime_enter_password
= alpine_get_password
;
199 pith_smime_confirm_save
= alpine_smime_confirm_save
;
202 pith_opt_save_ldap_entry
= save_ldap_entry
;
205 status_message_lock_init();
210 * Seed the random number generator with the date & pid. Random
211 * numbers are used for new mail notification and bug report id's
213 srandom(getpid() + time(0));
216 /* need home directory early */
217 get_user_info(&ps_global
->ui
);
219 if(!(pine_state
->home_dir
= our_getenv("HOME")))
220 pine_state
->home_dir
= cpystr(ps_global
->ui
.homedir
);
226 /* normalize path delimiters */
227 for(p
= pine_state
->home_dir
; p
= strchr(p
, '/'); p
++)
230 #endif /* _WINDOWS */
236 char *no_args
= " <no args>";
238 for(i
= 0; i
< argc
; i
++)
239 len
+= (strlen(argv
[i
] ? argv
[i
] : "")+3);
242 len
+= strlen(no_args
);
244 p
= args_for_debug
= (char *)fs_get((len
+2) * sizeof(char));
248 for(i
= 0; i
< argc
; i
++){
249 snprintf(p
, len
+2-(p
-args_for_debug
), "%s\"%s\"", i
? " " : "", argv
[i
] ? argv
[i
] : "");
250 args_for_debug
[len
+2-1] = '\0';
255 strncat(args_for_debug
, no_args
, len
+2-strlen(args_for_debug
)-1);
256 args_for_debug
[len
+2-1] = '\0';
261 /*----------------------------------------------------------------------
262 Parse arguments and initialize debugging
263 ----------------------------------------------------------------------*/
264 pine_args(pine_state
, argc
, argv
, &args
);
269 * monkey with descriptors so our normal tty i/o routines don't
272 dup2(STDIN_FD
, PIPED_FD
); /* redirected stdin to new desc */
273 dup2(STDERR_FD
, STDIN_FD
); /* rebind stdin to the tty */
274 stdin_getc
= read_stdin_char
;
276 if(args
.action
== aaURL
){
278 "Cannot read stdin when using -url\nFor mailto URLs, use \'body=\' instead",
282 } else if (args
.action
== aaFolder
){
283 display_args_err("Cannot take input from pipe when opening a folder", NULL
, 1);
292 * We now have enough information to do some of the basic registry settings.
294 if(ps_global
->update_registry
!= UREG_NEVER_SET
){
295 mswin_reg(MSWR_OP_SET
296 | ((ps_global
->update_registry
== UREG_ALWAYS_SET
)
297 ? MSWR_OP_FORCE
: 0),
298 MSWR_PINE_DIR
, ps_global
->pine_dir
, (size_t)NULL
);
299 mswin_reg(MSWR_OP_SET
300 | ((ps_global
->update_registry
== UREG_ALWAYS_SET
)
301 ? MSWR_OP_FORCE
: 0),
302 MSWR_PINE_EXE
, ps_global
->pine_name
, (size_t)NULL
);
305 #endif /* _WINDOWS */
307 if(ps_global
->convert_sigs
&&
308 (!ps_global
->pinerc
|| !ps_global
->pinerc
[0])){
309 fprintf(stderr
, "Use -p <pinerc> with -convert_sigs\n");
313 /* Windows has its own functions to determine width of a character
314 * in the screen, so this is not necessary to do in Window, and
315 * using pith_ucs4width does not produce the correct result
317 #if !defined(_WINDOWS) && defined(LC_CTYPE)
319 if((s
= setlocale(LC_CTYPE
, "")) != NULL
321 && !strucmp(s
+strlen(s
)-5, "UTF-8"))
322 mail_parameters(NULL
, SET_UCS4WIDTH
, (void *) pith_ucs4width
);
324 #endif /* !_WINDOWS && LC_CTYPE */
325 mail_parameters(NULL
, SET_QUOTA
, (void *) pine_parse_quota
);
326 /* set some default timeouts in case pinerc is remote */
327 mail_parameters(NULL
, SET_OPENTIMEOUT
, (void *)(long)30);
328 mail_parameters(NULL
, SET_READTIMEOUT
, (void *)(long)15);
329 mail_parameters(NULL
, SET_TIMEOUT
, (void *) pine_tcptimeout
);
330 /* could be TO_BAIL_THRESHOLD, 15 seems more appropriate for now */
331 pine_state
->tcp_query_timeout
= 15;
333 mail_parameters(NULL
, SET_SENDCOMMAND
, (void *) pine_imap_cmd_happened
);
334 mail_parameters(NULL
, SET_FREESTREAMSPAREP
, (void *) sp_free_callback
);
335 mail_parameters(NULL
, SET_FREEELTSPAREP
, (void *) free_pine_elt
);
336 mail_parameters(NULL
, SET_FREEBODYSPAREP
, (void *) free_body_sparep
);
337 mail_parameters(NULL
, SET_OA2CLIENTGETACCESSCODE
, (void *) oauth2_get_access_code
);
338 mail_parameters(NULL
, SET_OA2CLIENTINFO
, (void *) oauth2_get_client_info
);
339 mail_parameters(NULL
, SET_OA2DEVICEINFO
, (void *) oauth2_set_device_info
);
341 init_pinerc(pine_state
, &init_pinerc_debugging
);
344 /* Since this is specific debugging we don't mind if the
345 ifdef is the type of system.
347 #if defined(HAVE_SMALLOC) || defined(NXT)
348 if(ps_global
->debug_malloc
)
349 malloc_debug(ps_global
->debug_malloc
);
352 if(ps_global
->debug_malloc
)
353 mal_debug(ps_global
->debug_malloc
);
356 if(!ps_global
->convert_sigs
358 && !ps_global
->install_flag
359 #endif /* _WINDOWS */
364 dprint((0, " %s (PID=%ld)\n\n", args_for_debug
,
366 fs_give((void **)&args_for_debug
);
371 if((env_to_free
= our_getenv("HOME")) != NULL
){
372 dprint((2, "Setting home dir from $HOME: \"%s\"\n",
374 fs_give((void **)&env_to_free
);
377 dprint((2, "Setting home dir: \"%s\"\n",
378 pine_state
->home_dir
? pine_state
->home_dir
: "<?>"));
382 /* Watch out. Sensitive information in debug file. */
383 if(ps_global
->debug_imap
> 4)
384 mail_parameters(NULL
, SET_DEBUGSENSITIVE
, (void *) TRUE
);
387 if(ps_global
->debug_tcp
)
389 mail_parameters(NULL
, SET_TCPDEBUG
, (void *) TRUE
);
392 mswin_setdebug(debug
, debugfile
);
393 mswin_setdebugoncallback (imap_telemetry_on
);
394 mswin_setdebugoffcallback (imap_telemetry_off
);
395 mswin_enableimaptelemetry(ps_global
->debug_imap
!= 0);
400 mswin_setsortcallback(index_sort_callback
);
401 mswin_setflagcallback(flag_callback
);
402 mswin_sethdrmodecallback(header_mode_callback
);
403 mswin_setselectedcallback(any_selected_callback
);
404 mswin_setzoomodecallback(zoom_mode_callback
);
405 mswin_setfkeymodecallback(fkey_mode_callback
);
408 /*------- Set up c-client drivers -------*/
409 #include "../c-client/linkage.c"
411 /*------- ... then tune the drivers just installed -------*/
413 if(_tgetenv(TEXT("HOME")))
414 mail_parameters(NULL
, SET_HOMEDIR
, (void *) pine_state
->home_dir
);
416 mail_parameters(NULL
, SET_USERPROMPT
, (void *) pine_user_callback
);
419 * Sniff the environment for timezone offset. We need to do this
420 * here since Windows needs help figuring out UTC, and will adjust
421 * what time() returns based on TZ. THIS WILL SCREW US because
422 * we use time() differences to manage status messages. So, if
423 * rfc822_date, which calls localtime() and thus needs tzset(),
424 * is called while a status message is displayed, it's possible
425 * for time() to return a time *before* what we remember as the
426 * time we put the status message on the display. Sheesh.
429 #else /* !_WINDOWS */
431 * We used to let c-client do this for us automatically, but it declines
432 * to do so for root. This forces c-client to establish an environment,
433 * even if the uid is 0.
435 env_init(ps_global
->ui
.login
, ps_global
->ui
.homedir
);
438 * Install callback to let us know the progress of network reads...
440 (void) mail_parameters(NULL
, SET_READPROGRESS
, (void *)pine_read_progress
);
441 #endif /* !_WINDOWS */
444 * Install callback to handle certificate validation failures,
445 * allowing the user to continue if they wish.
447 mail_parameters(NULL
, SET_SSLCERTIFICATEQUERY
, (void *) pine_sslcertquery
);
448 mail_parameters(NULL
, SET_SSLFAILURE
, (void *) pine_sslfailure
);
450 if(init_pinerc_debugging
){
451 dprint((2, "%s", init_pinerc_debugging
));
452 fs_give((void **)&init_pinerc_debugging
);
456 * Initial allocation of array of stream pool pointers.
457 * We do this before init_vars so that we can re-use streams used for
458 * remote config files. These sizes may get changed later.
460 ps_global
->s_pool
.max_remstream
= 2;
462 "Setting initial max_remstream to %d for remote config re-use\n",
463 ps_global
->s_pool
.max_remstream
));
465 init_vars(pine_state
, process_init_cmds
);
467 #if !defined(_WINDOWS) || defined(WINDOWS_UNIXSSL_CERTS)
468 set_system_certs_path(pine_state
);
469 set_system_certs_container(pine_state
);
470 set_user_certs_path(pine_state
);
471 set_user_certs_container(pine_state
);
475 if(F_ON(F_DONT_DO_SMIME
, ps_global
))
481 * LC_CTYPE is already set from the set_collation call above.
483 * We can't use gettext calls before we do this stuff so it doesn't
484 * help to translate strings that come before this in the program.
485 * Maybe we could rearrange things to accommodate that.
487 setlocale(LC_MESSAGES
, "");
488 bindtextdomain(PACKAGE
, LOCALEDIR
);
489 bind_textdomain_codeset(PACKAGE
, "UTF-8");
491 #endif /* ENABLE_NLS */
493 convert_args_to_utf8(pine_state
, &args
);
495 if(args
.action
== aaFolder
){
496 pine_state
->beginning_of_month
= first_run_of_month();
497 pine_state
->beginning_of_year
= first_run_of_year();
500 /* Set up optional for user-defined display filtering */
501 pine_state
->tools
.display_filter
= dfilter
;
502 pine_state
->tools
.display_filter_trigger
= dfilter_trigger
;
505 if(ps_global
->install_flag
){
506 init_install_get_vars();
509 free_pinerc_s(&ps_global
->prc
);
515 if(ps_global
->convert_sigs
){
516 if(convert_sigs_to_literal(ps_global
, 0) == -1){
517 /* TRANSLATORS: sigs refers to signatures, which the user was trying to convert */
518 fprintf(stderr
, _("trouble converting sigs\n"));
523 if(ps_global
->prc
->outstanding_pinerc_changes
)
524 write_pinerc(ps_global
, Main
, WRP_NONE
);
526 free_pinerc_s(&pine_state
->prc
);
533 * Set up a c-client read timeout and timeout handler. In general,
534 * it shouldn't happen, but a server crash or dead link can cause
535 * pine to appear wedged if we don't set this up...
538 if(pine_state
->VAR_TCPOPENTIMEO
)
539 (void)SVAR_TCP_OPEN(pine_state
, rv
, tmp_20k_buf
, SIZEOF_20KBUF
);
540 mail_parameters(NULL
, SET_OPENTIMEOUT
, (void *)(long)rv
);
543 if(pine_state
->VAR_TCPREADWARNTIMEO
)
544 (void)SVAR_TCP_READWARN(pine_state
, rv
, tmp_20k_buf
, SIZEOF_20KBUF
);
545 mail_parameters(NULL
, SET_READTIMEOUT
, (void *)(long)rv
);
548 if(pine_state
->VAR_TCPWRITEWARNTIMEO
){
549 if(!SVAR_TCP_WRITEWARN(pine_state
, rv
, tmp_20k_buf
, SIZEOF_20KBUF
))
550 if(rv
== 0 || rv
> 4) /* making sure */
551 mail_parameters(NULL
, SET_WRITETIMEOUT
, (void *)(long)rv
);
554 mail_parameters(NULL
, SET_TIMEOUT
, (void *) pine_tcptimeout
);
557 if(pine_state
->VAR_RSHOPENTIMEO
){
558 if(!SVAR_RSH_OPEN(pine_state
, rv
, tmp_20k_buf
, SIZEOF_20KBUF
))
559 if(rv
== 0 || rv
> 4) /* making sure */
560 mail_parameters(NULL
, SET_RSHTIMEOUT
, (void *)(long)rv
);
564 if(pine_state
->VAR_SSHOPENTIMEO
){
565 if(!SVAR_SSH_OPEN(pine_state
, rv
, tmp_20k_buf
, SIZEOF_20KBUF
))
566 if(rv
== 0 || rv
> 4) /* making sure */
567 mail_parameters(NULL
, SET_SSHTIMEOUT
, (void *)(long)rv
);
571 if(pine_state
->VAR_MAILDROPCHECK
){
572 if(!SVAR_MAILDCHK(pine_state
, rvl
, tmp_20k_buf
, SIZEOF_20KBUF
)){
574 rvl
= (60L * 60L * 24L * 100L); /* 100 days */
576 if(rvl
>= 60L) /* making sure */
577 mail_parameters(NULL
, SET_SNARFINTERVAL
, (void *) rvl
);
582 * Lookups of long login names which don't exist are very slow in aix.
583 * This would normally get set in system-wide config if not needed.
585 if(F_ON(F_DISABLE_SHARED_NAMESPACES
, ps_global
))
586 mail_parameters(NULL
, SET_DISABLEAUTOSHAREDNS
, (void *) TRUE
);
588 if(F_ON(F_HIDE_NNTP_PATH
, ps_global
))
589 mail_parameters(NULL
, SET_NNTPHIDEPATH
, (void *) TRUE
);
591 if(F_ON(F_MAILDROPS_PRESERVE_STATE
, ps_global
))
592 mail_parameters(NULL
, SET_SNARFPRESERVE
, (void *) TRUE
);
595 if(pine_state
->VAR_NNTPRANGE
){
596 if(!SVAR_NNTPRANGE(pine_state
, rvl
, tmp_20k_buf
, SIZEOF_20KBUF
))
598 mail_parameters(NULL
, SET_NNTPRANGE
, (void *) rvl
);
602 * Tell c-client not to be so aggressive about uid mappings
604 mail_parameters(NULL
, SET_UIDLOOKAHEAD
, (void *) 20);
607 * Setup referral handling
609 mail_parameters(NULL
, SET_IMAPREFERRAL
, (void *) imap_referral
);
610 mail_parameters(NULL
, SET_MAILPROXYCOPY
, (void *) imap_proxycopy
);
613 * Setup multiple newsrc transition
615 mail_parameters(NULL
, SET_NEWSRCQUERY
, (void *) pine_newsrcquery
);
618 * Disable some drivers if requested.
620 if(ps_global
->VAR_DISABLE_DRIVERS
&&
621 ps_global
->VAR_DISABLE_DRIVERS
[0] &&
622 ps_global
->VAR_DISABLE_DRIVERS
[0][0]){
625 for(t
= ps_global
->VAR_DISABLE_DRIVERS
; t
[0] && t
[0][0]; t
++)
626 if(mail_parameters(NULL
, DISABLE_DRIVER
, (void *)(*t
))){
627 dprint((2, "Disabled mail driver \"%s\"\n", *t
));
630 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
631 _("Failed to disable mail driver \"%s\": name not found"),
633 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
634 init_error(ps_global
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
639 * Disable some authenticators if requested.
641 if(ps_global
->VAR_DISABLE_AUTHS
&&
642 ps_global
->VAR_DISABLE_AUTHS
[0] &&
643 ps_global
->VAR_DISABLE_AUTHS
[0][0]){
646 for(t
= ps_global
->VAR_DISABLE_AUTHS
; t
[0] && t
[0][0]; t
++)
647 if(mail_parameters(NULL
, DISABLE_AUTHENTICATOR
, (void *)(*t
))){
648 dprint((2,"Disabled SASL authenticator \"%s\"\n", *t
));
651 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
652 _("Failed to disable SASL authenticator \"%s\": name not found"),
654 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
655 init_error(ps_global
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
659 if(ps_global
->VAR_ENCRYPTION_RANGE
660 && ps_global
->VAR_ENCRYPTION_RANGE
[0]){
661 char *min_s
, *max_s
, *s
;
664 if((s
= strchr(ps_global
->VAR_ENCRYPTION_RANGE
, ',')) == NULL
){
665 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
666 _("Bad encryption range: \"%s\": resetting to default"),
667 ps_global
->VAR_ENCRYPTION_RANGE
);
668 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
669 init_error(ps_global
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
670 fs_give((void **) &ps_global
->VAR_ENCRYPTION_RANGE
);
671 ps_global
->VAR_ENCRYPTION_RANGE
= cpystr(DF_ENCRYPTION_RANGE
);
672 s
= strchr(ps_global
->VAR_ENCRYPTION_RANGE
, ','); /* try again */
676 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
677 _("Bad default encryption range: \"%s\""),
678 ps_global
->VAR_ENCRYPTION_RANGE
);
679 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
680 init_error(ps_global
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
684 get_pair(ps_global
->VAR_ENCRYPTION_RANGE
, &min_s
, &max_s
, 1, 0);
687 min_v
= pith_ssl_encryption_version(min_s
);
688 max_v
= pith_ssl_encryption_version(max_s
);
690 if(min_v
< 0 || max_v
< 0){
691 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
692 _("Bad encryption range: \"%s\": resetting to default"),
693 ps_global
->VAR_ENCRYPTION_RANGE
);
694 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
695 init_error(ps_global
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
701 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
702 _("Minimum encryption protocol (%s) bigger than maximum value (%s). Reversing..."),
704 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
705 init_error(ps_global
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
711 if(max_v
> 0 && max_v
< (long) pith_ssl_encryption_version("tls1")){
712 strncpy(tmp_20k_buf
, _("Security alert: SSL maximum encryption version was set to SSLv3."), SIZEOF_20KBUF
);
713 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
714 init_error(ps_global
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
717 mail_parameters(NULL
, SET_ENCRYPTION_RANGE_MIN
, (void *) &min_v
);
718 mail_parameters(NULL
, SET_ENCRYPTION_RANGE_MAX
, (void *) &max_v
);
724 * setup alternative authentication driver preference for IMAP opens
726 if(F_ON(F_PREFER_ALT_AUTH
, ps_global
))
727 mail_parameters(NULL
, SET_IMAPTRYALT
, (void *) TRUE
);
730 * Install handler to let us know about potential delays
732 (void) mail_parameters(NULL
, SET_BLOCKNOTIFY
, (void *) pine_block_notify
);
734 if(ps_global
->dump_supported_options
){
735 dump_supported_options();
740 * Install extra headers to fetch along with all the other stuff
741 * mail_fetch_structure and mail_fetch_overview requests.
745 (void) mail_parameters(NULL
, SET_IMAPEXTRAHEADERS
,
746 (void *) get_extra_hdrs());
748 if(init_username(pine_state
) < 0){
749 fprintf(stderr
, _("Who are you? (Unable to look up login name)\n"));
753 if(init_userdir(pine_state
) < 0)
756 if(init_hostname(pine_state
) < 0)
760 * Verify mail dir if we're not in send only mode...
762 if(args
.action
== aaFolder
&& init_mail_dir(pine_state
) < 0)
767 /*--- input side ---*/
768 if(init_tty_driver(pine_state
)){
769 #ifndef _WINDOWS /* always succeeds under _WINDOWS */
770 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
);
772 #endif /* !_WINDOWS */
776 /*--- output side ---*/
777 rv
= config_screen(&(pine_state
->ttyo
));
778 #ifndef _WINDOWS /* always succeeds under _WINDOWS */
782 printf(_("Terminal type (environment variable TERM) not set.\n"));
785 printf(_("Terminal type \"%s\" is unknown.\n"), getenv("TERM"));
788 printf(_("Can't open terminal capabilities database.\n"));
791 printf(_("Your terminal, of type \"%s\", is lacking functions needed to run alpine.\n"), getenv("TERM"));
796 end_tty_driver(pine_state
);
799 #endif /* !_WINDOWS */
801 if(F_ON(F_BLANK_KEYMENU
,ps_global
))
802 FOOTER_ROWS(ps_global
) = 1;
805 init_keyboard(pine_state
->orig_use_fkeys
);
806 strncpy(pine_state
->inbox_name
, INBOX_NAME
,
807 sizeof(pine_state
->inbox_name
)-1);
808 init_folders(pine_state
); /* digest folder spec's */
810 pine_state
->in_init_seq
= 0; /* so output (& ClearScreen) show up */
811 pine_state
->dont_use_init_cmds
= 1; /* don't use up initial_commands yet */
814 /* initialize titlebar in case we use it */
815 set_titlebar("", NULL
, NULL
, NULL
, NULL
, 0, FolderName
, 0, 0, NULL
);
818 * Prep storage object driver for PicoText
820 so_register_external_driver(pine_pico_get
, pine_pico_give
, pine_pico_writec
, pine_pico_readc
,
821 pine_pico_puts
, pine_pico_seek
, NULL
, NULL
);
824 if(ps_global
->debug_imap
> 4 || debug
> 9){
825 q_status_message(SM_ORDER
| SM_DING
, 5, 9,
826 _("Warning: sensitive authentication data included in debug file"));
827 flush_status_messages(0);
831 if(args
.action
== aaPrcCopy
|| args
.action
== aaAbookCopy
){
833 char *err_msg
= NULL
;
836 * Don't translate these into UTF-8 because we'll be using them
837 * before we translate next time. User should use ascii.
839 if(args
.data
.copy
.local
&& args
.data
.copy
.remote
){
842 exit_val
= copy_pinerc(args
.data
.copy
.local
,
843 args
.data
.copy
.remote
, &err_msg
);
847 exit_val
= copy_abook(args
.data
.copy
.local
,
848 args
.data
.copy
.remote
, &err_msg
);
856 q_status_message(SM_ORDER
| SM_DING
, 3, 4, err_msg
);
857 fs_give((void **)&err_msg
);
859 goodnight_gracey(pine_state
, exit_val
);
862 if(args
.action
== aaFolder
863 && (pine_state
->first_time_user
|| pine_state
->show_new_version
)){
864 pine_state
->mangled_header
= 1;
865 show_main_screen(pine_state
, 0, FirstMenu
, &main_keymenu
, 0,
867 new_user_or_version(pine_state
);
871 /* put back in case we need to suppress output */
872 pine_state
->in_init_seq
= pine_state
->save_in_init_seq
;
874 /* queue any init errors so they get displayed in a screen below */
875 queue_init_errors(ps_global
);
877 /* "Page" the given file? */
878 if(args
.action
== aaMore
){
879 int dice
= 1, redir
= 0;
881 if(pine_state
->in_init_seq
){
882 pine_state
->in_init_seq
= pine_state
->save_in_init_seq
= 0;
884 if(pine_state
->free_initial_cmds
)
885 fs_give((void **)&(pine_state
->free_initial_cmds
));
887 pine_state
->initial_cmds
= NULL
;
890 /*======= Requested that we simply page the given file =======*/
891 if(args
.data
.file
){ /* Open the requested file... */
893 STORE_S
*store
= NULL
;
894 char *decode_error
= NULL
;
895 char filename
[MAILTMPLEN
];
897 if(args
.data
.file
[0] == '\0'){
898 HelpType help
= NO_HELP
;
900 pine_state
->mangled_footer
= 1;
903 int flags
= OE_APPEND_CURRENT
;
905 rv
= optionally_enter(filename
, -FOOTER_ROWS(pine_state
),
907 /* TRANSLATORS: file is computer data */
908 _("File to open : "),
911 help
= (help
== NO_HELP
) ? h_no_F_arg
: NO_HELP
;
920 q_status_message(SM_ORDER
, 0, 2, _("Cancelled"));
921 goodnight_gracey(pine_state
, -1);
925 removing_trailing_white_space(filename
);
926 removing_leading_white_space(filename
);
927 if(is_absolute_path(filename
))
928 fnexpand(filename
, sizeof(filename
));
930 args
.data
.file
= filename
;
934 /* TRANSLATORS: file is computer data */
935 q_status_message(SM_ORDER
, 0, 2 ,_("No file to open"));
936 goodnight_gracey(pine_state
, -1);
943 if(isatty(0) && (store
= so_get(src
, NULL
, EDIT_ACCESS
))){
946 gf_set_so_writec(&pc
, store
);
948 if((decode_error
= gf_pipe(stdin_getc
, pc
)) != NULL
){
950 q_status_message1(SM_ORDER
, 3, 4,
951 _("Problem reading standard input: %s"),
955 gf_clear_so_writec(store
);
962 strncpy(ps_global
->cur_folder
, args
.data
.file
,
963 sizeof(ps_global
->cur_folder
)-1);
964 ps_global
->cur_folder
[sizeof(ps_global
->cur_folder
)-1] = '\0';
965 if(!(store
= so_get(src
, args
.data
.file
, READ_ACCESS
|READ_FROM_LOCALE
)))
972 memset(&sargs
, 0, sizeof(SCROLL_S
));
973 sargs
.text
.text
= so_text(store
);
974 sargs
.text
.src
= src
;
975 /* TRANSLATORS: file is computer file being read by user */
976 sargs
.text
.desc
= _("file");
977 /* TRANSLATORS: this is in the title bar at top of screen */
978 sargs
.bar
.title
= _("FILE VIEW");
979 sargs
.bar
.style
= FileTextPercent
;
980 sargs
.keys
.menu
= &simple_file_keymenu
;
981 setbitmap(sargs
.keys
.bitmap
);
990 q_status_message2(SM_ORDER
, 3, 4,
991 _("Can't display \"%s\": %s"),
992 (redir
) ? _("Standard Input")
993 : args
.data
.file
? args
.data
.file
: "NULL",
994 error_description(errno
));
997 goodnight_gracey(pine_state
, 0);
999 else if(args
.action
== aaMail
|| (stdin_getc
&& (args
.action
!= aaURL
))){
1000 /*======= address on command line/send one message mode ============*/
1001 char *to
= NULL
, *error
= NULL
, *addr
= NULL
;
1002 int len
, good_addr
= 1;
1006 if(pine_state
->in_init_seq
){
1007 pine_state
->in_init_seq
= pine_state
->save_in_init_seq
= 0;
1009 if(pine_state
->free_initial_cmds
)
1010 fs_give((void **) &(pine_state
->free_initial_cmds
));
1012 pine_state
->initial_cmds
= NULL
;
1015 /*----- Format the To: line with commas for the composer ---*/
1016 if(args
.data
.mail
.addrlist
){
1019 for(p
= args
.data
.mail
.addrlist
, len
= 0; p
; p
= p
->next
)
1020 len
+= strlen(p
->name
) + 2;
1022 to
= (char *) fs_get((len
+ 5) * sizeof(char));
1023 for(p
= args
.data
.mail
.addrlist
, *to
= '\0'; p
; p
= p
->next
){
1025 strncat(to
, ", ", len
+5-strlen(to
)-1);
1029 strncat(to
, p
->name
, len
+5-strlen(to
)-1);
1033 memset((void *)&fcc
, 0, sizeof(BUILDER_ARG
));
1034 dprint((2, "building addr: -->%s<--\n", to
? to
: "?"));
1035 good_addr
= (build_address(to
, &addr
, &error
, &fcc
, NULL
) >= 0);
1036 dprint((2, "mailing to: -->%s<--\n", addr
? addr
: "?"));
1037 free_strlist(&args
.data
.mail
.addrlist
);
1040 memset(&fcc
, 0, sizeof(fcc
));
1043 compose_mail(addr
, fcc
.tptr
, NULL
,
1044 args
.data
.mail
.attachlist
, stdin_getc
);
1047 /* TRANSLATORS: refers to bad email address */
1048 q_status_message1(SM_ORDER
, 3, 4, _("Bad address: %s"), error
);
1053 fs_give((void **) &addr
);
1056 fs_give((void **) &fcc
.tptr
);
1058 if(args
.data
.mail
.attachlist
)
1059 free_attachment_list(&args
.data
.mail
.attachlist
);
1062 fs_give((void **) &to
);
1065 fs_give((void **) &error
);
1067 goodnight_gracey(pine_state
, exit_val
);
1070 char int_mail
[MAXPATH
+1];
1071 struct key_menu
*km
= &main_keymenu
;
1073 /*========== Normal pine mail reading mode ==========*/
1075 pine_state
->mail_stream
= NULL
;
1076 pine_state
->mangled_screen
= 1;
1078 if(args
.action
== aaURL
){
1081 if(pine_state
->in_init_seq
){
1082 pine_state
->in_init_seq
= pine_state
->save_in_init_seq
= 0;
1084 if(pine_state
->free_initial_cmds
)
1085 fs_give((void **) &(pine_state
->free_initial_cmds
));
1086 pine_state
->initial_cmds
= NULL
;
1088 if((f
= url_local_handler(args
.url
)) != NULL
){
1089 if(args
.data
.mail
.attachlist
){
1090 if(f
== url_local_mailto
){
1091 if(!(url_local_mailto_and_atts(args
.url
,
1092 args
.data
.mail
.attachlist
)
1093 && pine_state
->next_screen
))
1094 free_attachment_list(&args
.data
.mail
.attachlist
);
1095 goodnight_gracey(pine_state
, 0);
1098 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
1099 _("Only mailto URLs are allowed with file attachments"));
1100 goodnight_gracey(pine_state
, -1); /* no return */
1103 else if(!((*f
)(args
.url
) && pine_state
->next_screen
))
1104 goodnight_gracey(pine_state
, 0); /* no return */
1107 q_status_message1(SM_ORDER
| SM_DING
, 3, 4,
1108 _("Unrecognized URL \"%s\""), args
.url
);
1109 goodnight_gracey(pine_state
, -1); /* no return */
1112 else if(!pine_state
->start_in_index
){
1113 /* flash message about executing initial commands */
1114 if(pine_state
->in_init_seq
){
1115 pine_state
->in_init_seq
= 0;
1117 pine_state
->mangled_header
= 1;
1118 pine_state
->mangled_footer
= 1;
1119 pine_state
->mangled_screen
= 0;
1120 /* show that this is Alpine */
1121 show_main_screen(pine_state
, 0, FirstMenu
, km
, 0, (Pos
*)NULL
);
1122 pine_state
->mangled_screen
= 1;
1123 pine_state
->painted_footer_on_startup
= 1;
1124 if(MIN(4, pine_state
->ttyo
->screen_rows
- 4) > 1){
1125 char buf1
[6*MAX_SCREEN_COLS
+1];
1126 char buf2
[6*MAX_SCREEN_COLS
+1];
1129 /* TRANSLATORS: Initial Keystroke List is the literal name of an option */
1130 strncpy(buf1
, _("Executing Initial Keystroke List......"), sizeof(buf1
));
1131 buf1
[sizeof(buf1
)-1] = '\0';
1132 wid
= utf8_width(buf1
);
1133 if(wid
> ps_global
->ttyo
->screen_cols
){
1134 utf8_pad_to_width(buf2
, buf1
, sizeof(buf2
), ps_global
->ttyo
->screen_cols
, 1);
1135 PutLine0(MIN(4, pine_state
->ttyo
->screen_rows
- 4), 0, buf2
);
1138 PutLine0(MIN(4, pine_state
->ttyo
->screen_rows
- 4),
1139 MAX(MIN(11, pine_state
->ttyo
->screen_cols
- wid
), 0), buf1
);
1143 pine_state
->in_init_seq
= 1;
1146 show_main_screen(pine_state
, 0, FirstMenu
, km
, 0, (Pos
*)NULL
);
1147 pine_state
->painted_body_on_startup
= 1;
1148 pine_state
->painted_footer_on_startup
= 1;
1152 /* cancel any initial commands, overridden by cmd line */
1153 if(pine_state
->in_init_seq
){
1154 pine_state
->in_init_seq
= 0;
1155 pine_state
->save_in_init_seq
= 0;
1157 if(pine_state
->initial_cmds
){
1158 if(pine_state
->free_initial_cmds
)
1159 fs_give((void **)&(pine_state
->free_initial_cmds
));
1161 pine_state
->initial_cmds
= NULL
;
1164 F_SET(F_USE_FK
,pine_state
, pine_state
->orig_use_fkeys
);
1167 (void) do_index_border(pine_state
->context_current
,
1168 pine_state
->cur_folder
,
1169 pine_state
->mail_stream
,
1170 pine_state
->msgmap
, MsgIndex
, NULL
,
1171 INDX_CLEAR
|INDX_HEADER
|INDX_FOOTER
);
1172 pine_state
->painted_footer_on_startup
= 1;
1173 if(MIN(4, pine_state
->ttyo
->screen_rows
- 4) > 1){
1174 char buf1
[6*MAX_SCREEN_COLS
+1];
1175 char buf2
[6*MAX_SCREEN_COLS
+1];
1178 strncpy(buf1
, _("Please wait, opening mail folder......"), sizeof(buf1
));
1179 buf1
[sizeof(buf1
)-1] = '\0';
1180 wid
= utf8_width(buf1
);
1181 if(wid
> ps_global
->ttyo
->screen_cols
){
1182 utf8_pad_to_width(buf2
, buf1
, sizeof(buf2
), ps_global
->ttyo
->screen_cols
, 1);
1183 PutLine0(MIN(4, pine_state
->ttyo
->screen_rows
- 4), 0, buf2
);
1186 PutLine0(MIN(4, pine_state
->ttyo
->screen_rows
- 4),
1187 MAX(MIN(11, pine_state
->ttyo
->screen_cols
- wid
), 0), buf1
);
1194 #if !defined(_WINDOWS) && !defined(LEAVEOUTFIFO)
1195 if(ps_global
->VAR_FIFOPATH
&& ps_global
->VAR_FIFOPATH
[0])
1196 init_newmailfifo(ps_global
->VAR_FIFOPATH
);
1199 if(pine_state
->in_init_seq
){
1200 pine_state
->in_init_seq
= 0;
1204 if(args
.action
== aaFolder
&& args
.data
.folder
){
1205 CONTEXT_S
*cntxt
= NULL
, *tc
= NULL
;
1206 char foldername
[MAILTMPLEN
];
1207 int notrealinbox
= 0;
1209 if(args
.data
.folder
[0] == '\0'){
1211 unsigned save_def_goto_rule
;
1213 foldername
[0] = '\0';
1214 save_def_goto_rule
= pine_state
->goto_default_rule
;
1215 pine_state
->goto_default_rule
= GOTO_FIRST_CLCTN
;
1216 tc
= default_save_context(pine_state
->context_list
);
1217 fldr
= broach_folder(-FOOTER_ROWS(pine_state
), 1, ¬realinbox
, &tc
);
1218 pine_state
->goto_default_rule
= save_def_goto_rule
;
1220 strncpy(foldername
, fldr
, sizeof(foldername
)-1);
1221 foldername
[sizeof(foldername
)-1] = '\0';
1225 removing_trailing_white_space(foldername
);
1226 removing_leading_white_space(foldername
);
1227 args
.data
.folder
= cpystr(foldername
);
1231 q_status_message(SM_ORDER
, 0, 2 ,_("No folder to open"));
1232 goodnight_gracey(pine_state
, -1);
1238 else if((rv
= pine_state
->init_context
) < 0)
1240 * As with almost all the folder vars in the pinerc,
1241 * we subvert the collection "breakout" here if the
1242 * folder name given looks like an absolute path on
1245 cntxt
= (is_absolute_path(args
.data
.folder
))
1246 ? NULL
: pine_state
->context_current
;
1250 for(cntxt
= pine_state
->context_list
;
1251 rv
> 1 && cntxt
->next
;
1252 rv
--, cntxt
= cntxt
->next
)
1255 if(pine_state
&& pine_state
->ttyo
){
1256 blank_keymenu(pine_state
->ttyo
->screen_rows
- 2, 0);
1257 pine_state
->painted_footer_on_startup
= 0;
1258 pine_state
->mangled_footer
= 1;
1261 if(args
.data
.folder
&& *args
.data
.folder
1262 && !strucmp(args
.data
.folder
, ps_global
->inbox_name
)
1263 && cntxt
!= ps_global
->context_list
)
1266 if(do_broach_folder(args
.data
.folder
, cntxt
, NULL
, notrealinbox
? 0L : DB_INBOXWOCNTXT
) <= 0){
1267 q_status_message1(SM_ORDER
, 3, 4,
1268 _("Unable to open folder \"%s\""), args
.data
.folder
);
1270 fs_give((void **) &args
.data
.folder
);
1272 goodnight_gracey(pine_state
, -1);
1275 else if(args
.action
== aaFolder
){
1278 * need to ask for the inbox name if no default under DOS
1279 * since there is no "inbox"
1282 if(!pine_state
->VAR_INBOX_PATH
|| !pine_state
->VAR_INBOX_PATH
[0]
1283 || strucmp(pine_state
->VAR_INBOX_PATH
, "inbox") == 0){
1284 HelpType help
= NO_HELP
;
1285 static ESCKEY_S ekey
[] = {{ctrl(T
), 2, "^T", "To Fldrs"},
1286 {-1, 0, NULL
, NULL
}};
1288 pine_state
->mangled_footer
= 1;
1291 int flags
= OE_APPEND_CURRENT
;
1293 rv
= optionally_enter(int_mail
, -FOOTER_ROWS(pine_state
),
1294 0, sizeof(int_mail
),
1295 _("No inbox! Folder to open as inbox : "),
1296 /* ekey */ NULL
, help
, &flags
);
1298 help
= (help
== NO_HELP
) ? h_sticky_inbox
: NO_HELP
;
1307 q_status_message(SM_ORDER
, 0, 2 ,_("Folder open cancelled"));
1308 rv
= 0; /* reset rv */
1311 show_main_screen(pine_state
,0,FirstMenu
,km
,0,(Pos
*)NULL
);
1315 removing_trailing_white_space(int_mail
);
1316 removing_leading_white_space(int_mail
);
1317 if((!pine_state
->VAR_INBOX_PATH
1318 || strucmp(pine_state
->VAR_INBOX_PATH
, "inbox") == 0)
1319 /* TRANSLATORS: Inbox-Path and PINERC are literal, not to be translated */
1320 && want_to(_("Preserve folder as \"Inbox-Path\" in PINERC"),
1321 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
1322 set_variable(V_INBOX_PATH
, int_mail
, 1, 1, Main
);
1325 if(pine_state
->VAR_INBOX_PATH
)
1326 fs_give((void **)&pine_state
->VAR_INBOX_PATH
);
1328 pine_state
->VAR_INBOX_PATH
= cpystr(int_mail
);
1331 if(pine_state
&& pine_state
->ttyo
){
1332 blank_keymenu(pine_state
->ttyo
->screen_rows
- 2, 0);
1333 pine_state
->painted_footer_on_startup
= 0;
1334 pine_state
->mangled_footer
= 1;
1337 do_broach_folder(pine_state
->inbox_name
,
1338 pine_state
->context_list
, NULL
, DB_INBOXWOCNTXT
);
1341 q_status_message(SM_ORDER
, 0, 2 ,_("No folder opened"));
1346 #endif /* _WINDOWS */
1347 if(F_ON(F_PREOPEN_STAYOPENS
, ps_global
))
1348 preopen_stayopen_folders();
1350 if(pine_state
&& pine_state
->ttyo
){
1351 blank_keymenu(pine_state
->ttyo
->screen_rows
- 2, 0);
1352 pine_state
->painted_footer_on_startup
= 0;
1353 pine_state
->mangled_footer
= 1;
1357 do_broach_folder(pine_state
->inbox_name
,
1358 pine_state
->context_list
, NULL
, DB_INBOXWOCNTXT
);
1361 if(pine_state
->mangled_footer
)
1362 pine_state
->painted_footer_on_startup
= 0;
1364 if(args
.action
== aaFolder
1365 && pine_state
->mail_stream
1366 && expire_sent_mail())
1367 pine_state
->painted_footer_on_startup
= 0;
1370 * Initialize the defaults. Initializing here means that
1371 * if they're remote, the user isn't prompted for an imap login
1372 * before the display's drawn, AND there's the chance that
1373 * we can climb onto the already opened folder's stream...
1375 if(ps_global
->first_time_user
)
1376 init_save_defaults(); /* initialize default save folders */
1378 build_path(int_mail
,
1379 ps_global
->VAR_OPER_DIR
? ps_global
->VAR_OPER_DIR
1380 : pine_state
->home_dir
,
1381 INTERRUPTED_MAIL
, sizeof(int_mail
));
1382 if(args
.action
== aaFolder
1383 && (folder_exists(NULL
, int_mail
) & FEX_ISFILE
))
1384 q_status_message(SM_ORDER
| SM_DING
, 4, 5,
1385 _("Use Compose command to continue interrupted message."));
1387 if(args
.action
== aaFolder
&& args
.data
.folder
)
1388 fs_give((void **) &args
.data
.folder
);
1390 #if defined(USE_QUOTAS)
1394 q
= disk_quota(pine_state
->home_dir
, &over
);
1396 q_status_message2(SM_ASYNC
| SM_DING
, 4, 5,
1397 _("WARNING! Over your disk quota by %s bytes (%s)"),
1398 comatose(q
),byte_string(q
));
1403 pine_state
->in_init_seq
= pine_state
->save_in_init_seq
;
1404 pine_state
->dont_use_init_cmds
= 0;
1407 if(pine_state
->give_fixed_warning
)
1408 q_status_message(SM_ASYNC
, 0, 10,
1409 /* TRANSLATORS: config is an abbreviation for configuration */
1410 _("Note: some of your config options conflict with site policy and are ignored"));
1412 if(!prune_folders_ok())
1413 q_status_message(SM_ASYNC
, 0, 10,
1414 /* TRANSLATORS: Pruned-Folders is literal */
1415 _("Note: ignoring Pruned-Folders outside of default collection for saves"));
1417 if(get_input_timeout() == 0 &&
1418 ps_global
->VAR_INBOX_PATH
&&
1419 ps_global
->VAR_INBOX_PATH
[0] == '{')
1420 q_status_message(SM_ASYNC
, 0, 10,
1421 _("Note: Mail-Check-Interval=0 may cause IMAP server connection to time out"));
1424 mswin_setnewmailwidth(ps_global
->nmw_width
);
1428 /*-------------------------------------------------------------------
1429 Loop executing the commands
1431 This is done like this so that one command screen can cause
1432 another one to execute it with out going through the main menu.
1433 ------------------------------------------------------------------*/
1434 if(!pine_state
->next_screen
)
1435 pine_state
->next_screen
= pine_state
->start_in_index
1436 ? mail_index_screen
: main_menu_screen
;
1438 if(pine_state
->next_screen
== SCREEN_FUN_NULL
)
1439 pine_state
->next_screen
= main_menu_screen
;
1441 (*(pine_state
->next_screen
))(pine_state
);
1450 * The arguments need to be converted to UTF-8 for our internal use.
1451 * Not all arguments are converted because some are used before we
1452 * are able to do the conversion, like the pinerc name.
1455 convert_args_to_utf8(struct pine
*ps
, ARGDATA_S
*args
)
1457 char *fromcharset
= NULL
;
1461 if(ps
->keyboard_charmap
&& strucmp(ps
->keyboard_charmap
, "UTF-8")
1462 && strucmp(ps
->keyboard_charmap
, "US-ASCII"))
1463 fromcharset
= ps
->keyboard_charmap
;
1464 else if(ps
->display_charmap
&& strucmp(ps
->display_charmap
, "UTF-8")
1465 && strucmp(ps
->display_charmap
, "US-ASCII"))
1466 fromcharset
= ps
->display_charmap
;
1468 else if(ps
->VAR_OLD_CHAR_SET
&& strucmp(ps
->VAR_OLD_CHAR_SET
, "UTF-8")
1469 && strucmp(ps
->VAR_OLD_CHAR_SET
, "US-ASCII"))
1470 fromcharset
= ps
->VAR_OLD_CHAR_SET
;
1471 #endif /* ! _WINDOWS */
1473 if(args
->action
== aaURL
&& args
->url
){
1474 conv
= convert_to_utf8(args
->url
, fromcharset
, 0);
1476 fs_give((void **) &args
->url
);
1481 if(args
->action
== aaFolder
&& args
->data
.folder
){
1482 conv
= convert_to_utf8(args
->data
.folder
, fromcharset
, 0);
1484 fs_give((void **) &args
->data
.folder
);
1485 args
->data
.folder
= conv
;
1489 if(args
->action
== aaMore
&& args
->data
.file
){
1490 conv
= convert_to_utf8(args
->data
.file
, fromcharset
, 0);
1492 fs_give((void **) &args
->data
.file
);
1493 args
->data
.file
= conv
;
1497 if(args
->action
== aaURL
|| args
->action
== aaMail
){
1498 if(args
->data
.mail
.addrlist
){
1501 for(p
= args
->data
.mail
.addrlist
; p
; p
=p
->next
){
1503 conv
= convert_to_utf8(p
->name
, fromcharset
, 0);
1505 fs_give((void **) &p
->name
);
1512 if(args
->data
.mail
.attachlist
){
1515 for(p
= args
->data
.mail
.attachlist
; p
; p
=p
->next
){
1517 conv
= convert_to_utf8(p
->filename
, fromcharset
, 0);
1519 fs_give((void **) &p
->filename
);
1531 preopen_stayopen_folders(void)
1535 for(open_these
= ps_global
->VAR_PERMLOCKED
;
1536 open_these
&& *open_these
; open_these
++)
1537 (void) do_broach_folder(*open_these
, ps_global
->context_list
,
1543 * read_stdin_char - simple function to return a character from
1547 read_stdin_char(char *c
)
1551 /* it'd probably be a good idea to fix this to pre-read blocks */
1553 rv
= read(PIPED_FD
, c
, 1);
1556 dprint((2, "read_stdin_char: read interrupted, restarting\n"));
1560 dprint((1, "read_stdin_char: read FAILED: %s\n",
1561 error_description(errno
)));
1569 /* this default is from the array of structs below */
1570 #define DEFAULT_MENU_ITEM ((unsigned) 3) /* LIST FOLDERS */
1571 #define ABOOK_MENU_ITEM ((unsigned) 4) /* ADDRESS BOOK */
1572 #define MAX_MENU_ITEM ((unsigned) 6)
1574 * Skip this many spaces between rows of main menu screen.
1575 * We have MAX_MENU_ITEM+1 = # of commands in menu
1576 * 1 = copyright line
1577 * MAX_MENU_ITEM = rows between commands
1578 * 1 = extra row above commands
1579 * 1 = row between commands and copyright
1581 * To make it simple, if there is enough room for all of that include all the
1582 * extra space, if not, cut it all out.
1584 #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)
1586 static unsigned menu_index
= DEFAULT_MENU_ITEM
;
1589 * One of these for each line that gets printed in the middle of the
1590 * screen in the main menu.
1592 static struct menu_key
{
1595 int key_index
; /* index into keymenu array for this cmd */
1598 * TRANSLATORS: These next few are headings on the Main alpine menu.
1599 * It's nice if the dashes can be made to line up vertically.
1601 {N_(" %s HELP - Get help using Alpine"),
1602 NULL
, MAIN_HELP_KEY
},
1603 {N_(" %s COMPOSE MESSAGE - Compose and send%s a message"),
1604 /* TRANSLATORS: We think of sending an email message or posting a news message.
1605 The message is shown as Compose and send/post a message */
1606 N_("/post"), MAIN_COMPOSE_KEY
},
1607 {N_(" %s MESSAGE INDEX - View messages in current folder"),
1608 NULL
, MAIN_INDEX_KEY
},
1609 {N_(" %s FOLDER LIST - Select a folder%s to view"),
1610 /* TRANSLATORS: When news is supported the message above becomes
1611 Select a folder OR news group to view */
1612 N_(" OR news group"), MAIN_FOLDER_KEY
},
1613 {N_(" %s ADDRESS BOOK - Update address book"),
1614 NULL
, MAIN_ADDRESS_KEY
},
1615 {N_(" %s SETUP - Configure Alpine Options"),
1616 NULL
, MAIN_SETUP_KEY
},
1617 /* TRANSLATORS: final Main menu line */
1618 {N_(" %s QUIT - Leave the Alpine program"),
1619 NULL
, MAIN_QUIT_KEY
}
1624 /*----------------------------------------------------------------------
1625 display main menu and execute main menu commands
1627 Args: The usual pine structure
1629 Result: main menu commands are executed
1632 M A I N M E N U S C R E E N
1634 Paint the main menu on the screen, get the commands and either execute
1635 the function or pass back the name of the function to execute for the menu
1636 selection. Only simple functions that always return here can be executed
1639 This functions handling of new mail, redrawing, errors and such can
1640 serve as a template for the other screen that do much the same thing.
1642 There is a loop that fetches and executes commands until a command to leave
1643 this screen is given. Then the name of the next screen to display is
1644 stored in next_screen member of the structure and this function is exited
1647 First a check for new mail is performed. This might involve reading the new
1648 mail into the inbox which might then cause the screen to be repainted.
1650 Then the general screen painting is done. This is usually controlled
1651 by a few flags and some other position variables. If they change they
1652 tell this part of the code what to repaint. This will include cursor
1656 main_menu_screen(struct pine
*pine_state
)
1659 int cmd
, just_a_navigate_cmd
, setup_command
, km_popped
;
1661 char *new_folder
, *utf8str
;
1663 struct key_menu
*km
;
1667 ps_global
= pine_state
;
1668 just_a_navigate_cmd
= 0;
1670 menu_index
= DEFAULT_MENU_ITEM
;
1671 what
= FirstMenu
; /* which keymenu to display */
1672 ch
= 'x'; /* For display_message 1st time through */
1673 pine_state
->next_screen
= SCREEN_FUN_NULL
;
1674 pine_state
->prev_screen
= main_menu_screen
;
1675 curs_pos
.row
= pine_state
->ttyo
->screen_rows
-FOOTER_ROWS(pine_state
);
1679 mailcap_free(); /* free resources we won't be using for a while */
1681 if(!pine_state
->painted_body_on_startup
1682 && !pine_state
->painted_footer_on_startup
){
1683 pine_state
->mangled_screen
= 1;
1686 dprint((1, "\n\n ---- MAIN_MENU_SCREEN ----\n"));
1692 clearfooter(pine_state
);
1693 pine_state
->mangled_body
= 1;
1698 * fix up redrawer just in case some submenu caused it to get
1701 pine_state
->redrawer
= main_redrawer
;
1703 /*----------- Check for new mail -----------*/
1704 if(new_mail(0, NM_TIMING(ch
), NM_STATUS_MSG
| NM_DEFER_SORT
) >= 0)
1705 pine_state
->mangled_header
= 1;
1708 pine_state
->mangled_header
= 1;
1710 show_main_screen(pine_state
, just_a_navigate_cmd
, what
, km
,
1711 km_popped
, &curs_pos
);
1712 just_a_navigate_cmd
= 0;
1715 /*---- This displays new mail notification, or errors ---*/
1717 FOOTER_ROWS(pine_state
) = 3;
1718 mark_status_dirty();
1721 display_message(ch
);
1723 FOOTER_ROWS(pine_state
) = 1;
1724 mark_status_dirty();
1727 if(F_OFF(F_SHOW_CURSOR
, ps_global
)){
1728 curs_pos
.row
=pine_state
->ttyo
->screen_rows
-FOOTER_ROWS(pine_state
);
1732 MoveCursor(curs_pos
.row
, curs_pos
.col
);
1734 /*------ Read the command from the keyboard ----*/
1736 mouse_in_content(KEY_MOUSE
, -1, -1, 0, 0);
1737 register_mfunc(mouse_in_content
, HEADER_ROWS(pine_state
), 0,
1738 pine_state
->ttyo
->screen_rows
-(FOOTER_ROWS(pine_state
)+1),
1739 pine_state
->ttyo
->screen_cols
);
1741 #if defined(DOS) || defined(OS2)
1743 * AND pre-build header lines. This works just fine under
1744 * DOS since we wait for characters in a loop. Something will
1745 * will have to change under UNIX if we want to do the same.
1747 /* while_waiting = build_header_cache; */
1749 mswin_sethelptextcallback(pcpine_help_main
);
1750 mswin_mousetrackcallback(pcpine_main_cursor
);
1753 ch
= READ_COMMAND(&utf8str
);
1755 clear_mfunc(mouse_in_content
);
1757 #if defined(DOS) || defined(OS2)
1758 /* while_waiting = NULL; */
1760 mswin_sethelptextcallback(NULL
);
1761 mswin_mousetrackcallback(NULL
);
1765 /* No matter what, Quit here always works */
1766 if(ch
== 'q' || ch
== 'Q'){
1770 else if(debug
&& ch
&& ch
< 0x80 && strchr("123456789", ch
)){
1776 ps_global
->debug_timestamp
= 1;
1778 ps_global
->debug_timestamp
= 0;
1781 ps_global
->debug_imap
= 4;
1783 ps_global
->debug_imap
= 3;
1785 ps_global
->debug_imap
= 2;
1787 ps_global
->debug_imap
= 1;
1789 ps_global
->debug_imap
= 0;
1791 if(ps_global
->mail_stream
){
1792 if(ps_global
->debug_imap
> 0){
1793 mail_debug(ps_global
->mail_stream
);
1795 mswin_enableimaptelemetry(TRUE
);
1799 mail_nodebug(ps_global
->mail_stream
);
1801 mswin_enableimaptelemetry(FALSE
);
1806 if(debug
> 7 && olddebug
<= 7)
1807 mail_parameters(NULL
, SET_TCPDEBUG
, (void *) TRUE
);
1808 else if(debug
<= 7 && olddebug
> 7 && !ps_global
->debugmem
)
1809 mail_parameters(NULL
, SET_TCPDEBUG
, (void *) FALSE
);
1811 dprint((1, "*** Debug level set to %d ***\n", debug
));
1815 q_status_message1(SM_ORDER
, 0, 1, _("Debug level set to %s"),
1821 cmd
= menu_command(ch
, km
);
1833 clearfooter(pine_state
);
1838 /*------ Execute the command ------*/
1841 /*------ HELP ------*/
1844 if(FOOTER_ROWS(pine_state
) == 1 && km_popped
== 0){
1846 pine_state
->mangled_footer
= 1;
1849 /* TRANSLATORS: This is a screen title */
1850 helper(main_menu_tx
, _("HELP FOR MAIN MENU"), 0);
1851 pine_state
->mangled_screen
= 1;
1857 /*---------- display other key bindings ------*/
1863 pine_state
->mangled_footer
= 1;
1867 /*---------- Previous item in menu ----------*/
1869 if(menu_index
> 0) {
1871 pine_state
->mangled_body
= 1;
1873 pine_state
->mangled_footer
= 1;
1875 just_a_navigate_cmd
++;
1878 /* TRANSLATORS: list refers to list of commands in main menu */
1879 q_status_message(SM_ORDER
, 0, 2, _("Already at top of list"));
1884 /*---------- Next item in menu ----------*/
1886 if(menu_index
< MAX_MENU_ITEM
){
1888 pine_state
->mangled_body
= 1;
1890 pine_state
->mangled_footer
= 1;
1892 just_a_navigate_cmd
++;
1895 q_status_message(SM_ORDER
, 0, 2, _("Already at bottom of list"));
1900 /*---------- Release Notes ----------*/
1902 /* TRANSLATORS: This is a screen title */
1903 helper(h_news
, _("ALPINE RELEASE NOTES"), 0);
1904 pine_state
->mangled_screen
= 1;
1908 #ifdef KEYBOARD_LOCK
1909 /*---------- Keyboard lock ----------*/
1911 (void) lock_keyboard();
1912 pine_state
->mangled_screen
= 1;
1914 #endif /* KEYBOARD_LOCK */
1917 /*---------- Quit pine ----------*/
1919 pine_state
->next_screen
= quit_screen
;
1923 /*---------- Go to composer ----------*/
1925 pine_state
->next_screen
= compose_screen
;
1929 /*---- Go to alternate composer ------*/
1931 pine_state
->next_screen
= alt_compose_screen
;
1935 /*---------- Top of Folder list ----------*/
1936 case MC_COLLECTIONS
:
1937 pine_state
->next_screen
= folder_screen
;
1941 /*---------- Goto new folder ----------*/
1943 tc
= ps_global
->context_current
;
1944 new_folder
= broach_folder(-FOOTER_ROWS(pine_state
), 1, ¬realinbox
, &tc
);
1946 visit_folder(ps_global
, new_folder
, tc
, NULL
, notrealinbox
? 0L : DB_INBOXWOCNTXT
);
1951 /*---------- Go to index ----------*/
1954 && sp_viewing_a_thread(pine_state
->mail_stream
)
1955 && unview_thread(pine_state
, pine_state
->mail_stream
,
1956 pine_state
->msgmap
)){
1957 pine_state
->view_skipped_index
= 0;
1958 pine_state
->mangled_screen
= 1;
1961 pine_state
->next_screen
= mail_index_screen
;
1965 /*---------- Review Status Messages ----------*/
1968 pine_state
->mangled_screen
= 1;
1972 /*---------- Setup mini menu ----------*/
1975 setup_command
= setup_menu(pine_state
);
1976 pine_state
->mangled_footer
= 1;
1977 do_setup_task(setup_command
);
1978 if(ps_global
->next_screen
!= main_menu_screen
)
1984 /*---------- Go to address book ----------*/
1986 pine_state
->next_screen
= addr_book_screen
;
1990 /*------ Repaint the works -------*/
1994 pine_state
->mangled_screen
= 1;
1999 /*------- Mouse event ------*/
2004 struct pine
*ps
= pine_state
;
2006 mouse_get_last (NULL
, &mp
);
2009 if(mp
.button
== M_BUTTON_RIGHT
){
2010 if(!mp
.doubleclick
){
2011 static MPopup main_popup
[] = {
2012 {tQueue
, {"Folder List", lNormal
}, {'L'}},
2013 {tQueue
, {"Message Index", lNormal
}, {'I'}},
2015 {tQueue
, {"Address Book", lNormal
}, {'A'}},
2016 {tQueue
, {"Setup Options", lNormal
}, {'S'}},
2020 mswin_popup(main_popup
);
2025 if (mp
.row
>= (HEADER_ROWS(ps
) + MNSKIP(ps
)))
2026 ndmi
= (mp
.row
+1 - HEADER_ROWS(ps
) - (MNSKIP(ps
)+1))/(MNSKIP(ps
)+1);
2028 if (mp
.row
>= (HEADER_ROWS(ps
) + MNSKIP(ps
))
2029 && !(MNSKIP(ps
) && (mp
.row
+1) & 0x01)
2030 && ndmi
<= MAX_MENU_ITEM
2031 && FOOTER_ROWS(ps
) + (ndmi
+1)*(MNSKIP(ps
)+1)
2032 + MNSKIP(ps
) + FOOTER_ROWS(ps
) <= ps
->ttyo
->screen_rows
){
2034 switch(ndmi
){ /* fake main_screen request */
2039 pine_state
->next_screen
= compose_screen
;
2043 pine_state
->next_screen
= mail_index_screen
;
2047 pine_state
->next_screen
= folder_screen
;
2051 pine_state
->next_screen
= addr_book_screen
;
2058 pine_state
->next_screen
= quit_screen
;
2061 default: /* no op */
2067 pine_state
->mangled_body
= 1;
2069 pine_state
->mangled_footer
= 1;
2071 just_a_navigate_cmd
++;
2083 /*------ Input timeout ------*/
2085 break; /* noop for timeout loop mail check */
2088 /*------ Bogus Input ------*/
2090 if(ch
== 'm' || ch
== 'M'){
2091 q_status_message(SM_ORDER
, 0, 1, "Already in Main Menu");
2096 bogus_command(ch
, F_ON(F_USE_FK
,pine_state
) ? "F1" : "?");
2100 bogus_utf8_command(utf8str
, F_ON(F_USE_FK
, pine_state
) ? "F1" : "?");
2103 } /* the BIG while loop! */
2107 /*----------------------------------------------------------------------
2108 Re-Draw the main menu
2112 Result: main menu is re-displayed
2117 struct key_menu
*km
= &main_keymenu
;
2119 ps_global
->mangled_screen
= 1;
2120 show_main_screen(ps_global
, 0, FirstMenu
, km
, 0, (Pos
*)NULL
);
2124 /*----------------------------------------------------------------------
2127 Args: pine_state - the usual struct
2128 quick_draw - tells do_menu() it can skip some drawing
2129 what - tells which section of keymenu to draw
2131 cursor_pos - returns a good position for the cursor to be located
2133 Result: main menu is displayed
2136 show_main_screen(struct pine
*ps
, int quick_draw
, OtherMenu what
,
2137 struct key_menu
*km
, int km_popped
, Pos
*cursor_pos
)
2139 if(ps
->painted_body_on_startup
|| ps
->painted_footer_on_startup
){
2140 ps
->mangled_screen
= 0; /* only worry about it here */
2141 ps
->mangled_header
= 1; /* we have to redo header */
2142 if(!ps
->painted_body_on_startup
)
2143 ps
->mangled_body
= 1; /* make sure to paint body*/
2145 if(!ps
->painted_footer_on_startup
)
2146 ps
->mangled_footer
= 1; /* make sure to paint footer*/
2148 ps
->painted_body_on_startup
= 0;
2149 ps
->painted_footer_on_startup
= 0;
2152 if(ps
->mangled_screen
){
2153 ps
->mangled_header
= 1;
2154 ps
->mangled_body
= 1;
2155 ps
->mangled_footer
= 1;
2156 ps
->mangled_screen
= 0;
2160 /* Reset the scroll range. Main screen never scrolls. */
2161 scroll_setrange (0L, 0L);
2162 mswin_beginupdate();
2165 /* paint the titlebar if needed */
2166 if(ps
->mangled_header
){
2167 /* TRANSLATORS: screen title */
2168 set_titlebar(_("MAIN MENU"), ps
->mail_stream
, ps
->context_current
,
2169 ps
->cur_folder
, ps
->msgmap
, 1, FolderName
, 0, 0, NULL
);
2170 ps
->mangled_header
= 0;
2173 /* paint the body if needed */
2174 if(ps
->mangled_body
){
2178 do_menu(quick_draw
, cursor_pos
, km
);
2179 ps
->mangled_body
= 0;
2182 /* paint the keymenu if needed */
2183 if(km
&& ps
->mangled_footer
){
2184 static char label
[LONGEST_LABEL
+ 2 + 1], /* label + brackets + \0 */
2190 #ifdef KEYBOARD_LOCK
2191 if(ps_global
->restricted
|| F_ON(F_DISABLE_KBLOCK_CMD
,ps_global
))
2193 clrbitn(MAIN_KBLOCK_KEY
, bitmap
);
2195 menu_clear_binding(km
, '>');
2196 menu_clear_binding(km
, '.');
2197 menu_clear_binding(km
, KEY_RIGHT
);
2198 menu_clear_binding(km
, ctrl('M'));
2199 menu_clear_binding(km
, ctrl('J'));
2200 km
->keys
[MAIN_DEFAULT_KEY
].bind
2201 = km
->keys
[mkeys
[menu_index
].key_index
].bind
;
2202 km
->keys
[MAIN_DEFAULT_KEY
].label
2203 = km
->keys
[mkeys
[menu_index
].key_index
].label
;
2205 /* put brackets around the default action */
2206 snprintf(label
, sizeof(label
), "[%s]", km
->keys
[mkeys
[menu_index
].key_index
].label
);
2207 label
[sizeof(label
)-1] = '\0';
2208 strncpy(name
, ">", sizeof(name
));
2209 name
[sizeof(name
)-1] = '\0';
2210 km
->keys
[MAIN_DEFAULT_KEY
].label
= label
;
2211 km
->keys
[MAIN_DEFAULT_KEY
].name
= name
;
2212 menu_add_binding(km
, '>', km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2213 menu_add_binding(km
, '.', km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2214 menu_add_binding(km
, ctrl('M'), km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2215 menu_add_binding(km
, ctrl('J'), km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2217 if(F_ON(F_ARROW_NAV
,ps_global
))
2218 menu_add_binding(km
, KEY_RIGHT
, km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2221 FOOTER_ROWS(ps
) = 3;
2225 draw_keymenu(km
, bitmap
, ps_global
->ttyo
->screen_cols
,
2226 1-FOOTER_ROWS(ps_global
), 0, what
);
2227 ps
->mangled_footer
= 0;
2229 FOOTER_ROWS(ps
) = 1;
2230 mark_keymenu_dirty();
2240 /*----------------------------------------------------------------------
2241 Actually display the main menu
2243 Args: quick_draw - just a next or prev command was typed so we only have
2244 to redraw the highlighting
2245 cursor_pos - a place to return a good value for cursor location
2247 Result: Main menu is displayed
2250 do_menu(int quick_draw
, Pos
*cursor_pos
, struct key_menu
*km
)
2252 struct pine
*ps
= ps_global
;
2253 int dline
, indent
, longest
= 0, cmd
;
2254 char buf
[4*MAX_SCREEN_COLS
+1];
2255 char buf2
[4*MAX_SCREEN_COLS
+1];
2256 static int last_inverse
= -1;
2259 /* find the longest command */
2260 for(cmd
= 0; cmd
< sizeof(mkeys
)/(sizeof(mkeys
[1])); cmd
++){
2261 memset((void *) buf
, ' ', sizeof(buf
));
2262 snprintf(buf
, sizeof(buf
), mkeys
[cmd
].key_and_name
[0] ? _(mkeys
[cmd
].key_and_name
) : "",
2264 && km
->keys
[mkeys
[cmd
].key_index
].name
)
2265 ? km
->keys
[mkeys
[cmd
].key_index
].name
: "",
2266 (ps
->VAR_NEWS_SPEC
&& mkeys
[cmd
].news_addition
&& mkeys
[cmd
].news_addition
[0])
2267 ? _(mkeys
[cmd
].news_addition
) : "");
2268 buf
[sizeof(buf
)-1] = '\0';
2270 if(longest
< (indent
= utf8_width(buf
)))
2274 indent
= MAX(((ps
->ttyo
->screen_cols
- longest
)/2) - 1, 0);
2276 dline
= HEADER_ROWS(ps
) + MNSKIP(ps
);
2277 for(cmd
= 0; cmd
< sizeof(mkeys
)/(sizeof(mkeys
[1])); cmd
++){
2278 /* leave room for copyright and footer */
2279 if(dline
+ MNSKIP(ps
) + 1 + FOOTER_ROWS(ps
) >= ps
->ttyo
->screen_rows
)
2282 if(quick_draw
&& !(cmd
== last_inverse
|| cmd
== menu_index
)){
2283 dline
+= (1 + MNSKIP(ps
));
2287 if(cmd
== menu_index
)
2290 memset((void *) buf
, ' ', sizeof(buf
));
2291 snprintf(buf
, sizeof(buf
), mkeys
[cmd
].key_and_name
[0] ? _(mkeys
[cmd
].key_and_name
) : "",
2293 && km
->keys
[mkeys
[cmd
].key_index
].name
)
2294 ? km
->keys
[mkeys
[cmd
].key_index
].name
: "",
2295 (ps
->VAR_NEWS_SPEC
&& mkeys
[cmd
].news_addition
&& mkeys
[cmd
].news_addition
[0])
2296 ? _(mkeys
[cmd
].news_addition
) : "");
2297 buf
[sizeof(buf
)-1] = '\0';
2299 utf8_pad_to_width(buf2
, buf
, sizeof(buf2
),
2300 MIN(ps
->ttyo
->screen_cols
-indent
,longest
+1), 1);
2303 PutLine0(pos
.row
, pos
.col
, buf2
);
2308 if(cmd
== menu_index
){
2310 cursor_pos
->row
= pos
.row
;
2311 /* 6 is 1 for the letter plus 5 spaces */
2312 cursor_pos
->col
= pos
.col
+ 6;
2313 if(F_OFF(F_USE_FK
,ps
))
2316 cursor_pos
->col
= MIN(cursor_pos
->col
, ps
->ttyo
->screen_cols
);
2324 last_inverse
= menu_index
;
2326 if(!quick_draw
&& FOOTER_ROWS(ps
)+1 < ps
->ttyo
->screen_rows
){
2327 utf8_to_width(buf2
, LEGAL_NOTICE
, sizeof(buf2
),
2328 ps
->ttyo
->screen_cols
-3, NULL
);
2329 PutLine0(ps
->ttyo
->screen_rows
- (FOOTER_ROWS(ps
)+1),
2330 MAX(0, ((ps
->ttyo
->screen_cols
-utf8_width(buf2
))/2)),
2339 choose_setup_cmd(int cmd
, MSGNO_S
*msgmap
, SCROLL_S
*sparms
)
2344 if(!(srv
= (SRV_S
*)sparms
->proc
.data
.p
)){
2345 sparms
->proc
.data
.p
= (SRV_S
*)fs_get(sizeof(*srv
));
2346 srv
= (SRV_S
*)sparms
->proc
.data
.p
;
2347 memset(srv
, 0, sizeof(*srv
));
2350 ps_global
->next_screen
= SCREEN_FUN_NULL
;
2397 case MC_SECURITY
: /* S/MIME setup screen */
2402 srv
->exc
= !srv
->exc
;
2403 menu_clear_binding(sparms
->keys
.menu
, 'x');
2405 if(sparms
->bar
.title
) fs_give((void **)&sparms
->bar
.title
);
2406 /* TRANSLATORS: screen title */
2407 sparms
->bar
.title
= cpystr(_("SETUP EXCEPTIONS"));
2408 ps_global
->mangled_header
= 1;
2409 /* TRANSLATORS: The reason the X is upper case in eXceptions
2410 is because the command key is X. It isn't necessary, just
2411 nice if it works. */
2412 menu_init_binding(sparms
->keys
.menu
, 'x', MC_EXCEPT
, "X",
2413 N_("not eXceptions"), SETUP_EXCEPT
);
2416 if(sparms
->bar
.title
) fs_give((void **)&sparms
->bar
.title
);
2417 /* TRANSLATORS: screen title */
2418 sparms
->bar
.title
= cpystr(_("SETUP"));
2419 ps_global
->mangled_header
= 1;
2420 menu_init_binding(sparms
->keys
.menu
, 'x', MC_EXCEPT
, "X",
2421 N_("eXceptions"), SETUP_EXCEPT
);
2424 if(sparms
->keys
.menu
->which
== 1)
2425 ps_global
->mangled_footer
= 1;
2431 #if defined(DOS) || defined(OS2)
2432 q_status_message(SM_ORDER
, 0, 2, _("Need argument \"-x <except_config>\" or \"PINERCEX\" file to use eXceptions"));
2434 q_status_message(SM_ORDER
, 0, 2, _("Need argument \"-x <except_config>\" or \".pinercex\" file to use eXceptions"));
2440 alpine_panic("Unexpected command in choose_setup_cmd");
2449 setup_menu(struct pine
*ps
)
2451 int ret
= 0, exceptions
= 0;
2452 int printer
= 0, passwd
= 0, config
= 0, sig
= 0, dir
= 0, smime
= 0, exc
= 0;
2457 if(!(store
= so_get(CharStar
, NULL
, EDIT_ACCESS
))){
2458 q_status_message(SM_ORDER
| SM_DING
, 3, 3, _("Error allocating space."));
2463 if(!ps_global
->vars
[V_PRINTER
].is_fixed
) /* printer can be changed */
2468 if(F_OFF(F_DISABLE_PASSWORD_CMD
,ps_global
)) /* password is allowed */
2472 if(F_OFF(F_DISABLE_CONFIG_SCREEN
,ps_global
)) /* config allowed */
2475 if(F_OFF(F_DISABLE_SIGEDIT_CMD
,ps_global
)) /* .sig editing is allowed */
2486 if(ps_global
->post_prc
)
2489 /* TRANSLATORS: starting here we have a whole screen of help text */
2490 so_puts(store
, _("This is the Setup screen for Alpine. Choose from the following commands:\n"));
2492 so_puts(store
, "\n");
2493 so_puts(store
, _("(E) Exit Setup:\n"));
2494 so_puts(store
, _(" This puts you back at the Main Menu.\n"));
2497 so_puts(store
, "\n");
2498 so_puts(store
, _("(X) eXceptions:\n"));
2499 so_puts(store
, _(" This command is different from the rest. It is not actually a command\n"));
2500 so_puts(store
, _(" itself. Instead, it is a toggle which modifies the behavior of the\n"));
2501 so_puts(store
, _(" other commands. You toggle Exceptions editing on and off with this\n"));
2502 so_puts(store
, _(" command. When it is off you will be editing (changing) your regular\n"));
2503 so_puts(store
, _(" configuration file. When it is on you will be editing your exceptions\n"));
2504 so_puts(store
, _(" configuration file. For example, you might want to type the command \n"));
2505 so_puts(store
, _(" \"eXceptions\" followed by \"Kolor\" to setup different screen colors\n"));
2506 so_puts(store
, _(" on a particular platform.\n"));
2507 so_puts(store
, _(" (Note: this command does not show up on the keymenu at the bottom of\n"));
2508 so_puts(store
, _(" the screen unless you press \"O\" for \"Other Commands\" --but you don't\n"));
2509 so_puts(store
, _(" need to press the \"O\" in order to invoke the command.)\n"));
2513 so_puts(store
, "\n");
2514 so_puts(store
, _("(P) Printer:\n"));
2515 so_puts(store
, _(" Allows you to set a default printer and to define custom\n"));
2516 so_puts(store
, _(" print commands.\n"));
2520 so_puts(store
, "\n");
2521 so_puts(store
, _("(N) Newpassword:\n"));
2522 so_puts(store
, _(" Change your password.\n"));
2526 so_puts(store
, "\n");
2527 so_puts(store
, _("(C) Config:\n"));
2528 so_puts(store
, _(" Allows you to set or unset many features of Alpine.\n"));
2529 so_puts(store
, _(" You may also set the values of many options with this command.\n"));
2533 so_puts(store
, "\n");
2534 so_puts(store
, _("(S) Signature:\n"));
2535 so_puts(store
, _(" Enter or edit a custom signature which will\n"));
2536 so_puts(store
, _(" be included with each new message you send.\n"));
2539 so_puts(store
, "\n");
2540 so_puts(store
, _("(A) AddressBooks:\n"));
2541 so_puts(store
, _(" Define a non-default address book.\n"));
2543 so_puts(store
, "\n");
2544 so_puts(store
, _("(L) collectionLists:\n"));
2545 so_puts(store
, _(" You may define groups of folders to help you better organize your mail.\n"));
2547 so_puts(store
, "\n");
2548 so_puts(store
, _("(R) Rules:\n"));
2549 so_puts(store
, _(" This has up to six sub-categories: Roles, Index Colors, Filters,\n"));
2550 so_puts(store
, _(" SetScores, Search, and Other. If the Index Colors option is\n"));
2551 so_puts(store
, _(" missing you may turn it on (if possible) with Setup/Kolor.\n"));
2552 so_puts(store
, _(" If Roles is missing it has probably been administratively disabled.\n"));
2555 so_puts(store
, "\n");
2556 so_puts(store
, _("(D) Directory:\n"));
2557 so_puts(store
, _(" Define an LDAP Directory server for Alpine's use. A directory server is\n"));
2558 so_puts(store
, _(" similar to an address book, but it is usually maintained by an\n"));
2559 so_puts(store
, _(" organization. It is similar to a telephone directory.\n"));
2562 so_puts(store
, "\n");
2563 so_puts(store
, _("(K) Kolor:\n"));
2564 so_puts(store
, _(" Set custom colors for various parts of the Alpine screens. For example, the\n"));
2565 so_puts(store
, _(" command key labels, the titlebar at the top of each page, and quoted\n"));
2566 so_puts(store
, _(" sections of messages you are viewing.\n"));
2569 so_puts(store
, "\n");
2570 so_puts(store
, _("(M) S/MIME:\n"));
2571 so_puts(store
, _(" Setup for using S/MIME to verify signed messages, decrypt\n"));
2572 so_puts(store
, _(" encrypted messages, and to sign or encrypt outgoing messages.\n"));
2575 so_puts(store
, "\n");
2576 so_puts(store
, _("(U) xoaUth2:\n"));
2577 so_puts(store
, _(" Set client-id and client-secret to use the XOAUTH2\n"));
2578 so_puts(store
, _(" authenticator.\n"));
2580 so_puts(store
, "\n");
2581 so_puts(store
, _("(Z) RemoteConfigSetup:\n"));
2582 so_puts(store
, _(" This is a command you will probably only want to use once, if at all.\n"));
2583 so_puts(store
, _(" It helps you transfer your Alpine configuration data to an IMAP server,\n"));
2584 so_puts(store
, _(" where it will be accessible from any of the computers you read mail\n"));
2585 so_puts(store
, _(" from (using Alpine). The idea behind a remote configuration is that you\n"));
2586 so_puts(store
, _(" can change your configuration in one place and have that change show\n"));
2587 so_puts(store
, _(" up on all of the computers you use.\n"));
2588 so_puts(store
, _(" (Note: this command does not show up on the keymenu at the bottom of\n"));
2589 so_puts(store
, _(" the screen unless you press \"O\" for \"Other Commands\" --but you don't\n"));
2590 so_puts(store
, _(" need to press the \"O\" in order to invoke the command.)\n"));
2592 /* put this down here for people who don't have exceptions */
2594 so_puts(store
, "\n");
2595 so_puts(store
, _("(X) eXceptions:\n"));
2596 so_puts(store
, _(" This command is different from the rest. It is not actually a command\n"));
2597 so_puts(store
, _(" itself. Instead, it is a toggle which modifies the behavior of the\n"));
2598 so_puts(store
, _(" other commands. You toggle Exceptions editing on and off with this\n"));
2599 so_puts(store
, _(" command. When it is off you will be editing (changing) your regular\n"));
2600 so_puts(store
, _(" configuration file. When it is on you will be editing your exceptions\n"));
2601 so_puts(store
, _(" configuration file. For example, you might want to type the command \n"));
2602 so_puts(store
, _(" \"eXceptions\" followed by \"Kolor\" to setup different screen colors\n"));
2603 so_puts(store
, _(" on a particular platform.\n"));
2604 so_puts(store
, _(" (Note: this command does not do anything unless you have a configuration\n"));
2605 so_puts(store
, _(" with exceptions enabled (you don't have that). Common ways to enable an\n"));
2606 so_puts(store
, _(" exceptions config are the command line argument \"-x <exception_config>\";\n"));
2607 so_puts(store
, _(" or the existence of the file \".pinercex\" for Unix Alpine, or \"PINERCEX\")\n"));
2608 so_puts(store
, _(" for PC-Alpine.)\n"));
2609 so_puts(store
, _(" (Another note: this command does not show up on the keymenu at the bottom\n"));
2610 so_puts(store
, _(" of the screen unless you press \"O\" for \"Other Commands\" --but you\n"));
2611 so_puts(store
, _(" don't need to press the \"O\" in order to invoke the command.)\n"));
2614 memset(&sargs
, 0, sizeof(SCROLL_S
));
2615 sargs
.text
.text
= so_text(store
);
2616 sargs
.text
.src
= CharStar
;
2617 sargs
.text
.desc
= _("Information About Setup Command");
2618 sargs
.bar
.title
= cpystr(_("SETUP"));
2619 sargs
.proc
.tool
= choose_setup_cmd
;
2620 sargs
.help
.text
= NO_HELP
;
2621 sargs
.help
.title
= NULL
;
2622 sargs
.keys
.menu
= &choose_setup_keymenu
;
2623 sargs
.keys
.menu
->how_many
= 2;
2625 setbitmap(sargs
.keys
.bitmap
);
2627 clrbitn(SETUP_PRINTER
, sargs
.keys
.bitmap
);
2630 clrbitn(SETUP_PASSWD
, sargs
.keys
.bitmap
);
2633 clrbitn(SETUP_CONFIG
, sargs
.keys
.bitmap
);
2636 clrbitn(SETUP_SIG
, sargs
.keys
.bitmap
);
2639 clrbitn(SETUP_DIRECTORY
, sargs
.keys
.bitmap
);
2642 clrbitn(SETUP_SMIME
, sargs
.keys
.bitmap
);
2645 menu_init_binding(sargs
.keys
.menu
, 'x', MC_EXCEPT
, "X",
2646 N_("eXceptions"), SETUP_EXCEPT
);
2648 menu_init_binding(sargs
.keys
.menu
, 'x', MC_NO_EXCEPT
, "X",
2649 N_("eXceptions"), SETUP_EXCEPT
);
2654 ps
->mangled_screen
= 1;
2656 srv
= (SRV_S
*)sargs
.proc
.data
.p
;
2658 exceptions
= srv
? srv
->exc
: 0;
2662 if(sargs
.bar
.title
) fs_give((void**)&sargs
.bar
.title
);
2665 fs_give((void **)&sargs
.proc
.data
.p
);
2670 return(ret
| (exceptions
? EDIT_EXCEPTION
: 0));
2674 /*----------------------------------------------------------------------
2676 Args: command -- command char to perform
2680 do_setup_task(int command
)
2684 int edit_exceptions
= 0;
2687 if(command
& EDIT_EXCEPTION
){
2688 edit_exceptions
= 1;
2689 command
&= ~EDIT_EXCEPTION
;
2693 /*----- EDIT SIGNATURE -----*/
2695 if(ps_global
->VAR_LITERAL_SIG
)
2698 char sig_path
[MAXPATH
+1];
2700 if(!signature_path(ps_global
->VAR_SIGNATURE_FILE
, sig_path
, MAXPATH
))
2702 else if((!IS_REMOTE(ps_global
->VAR_SIGNATURE_FILE
)
2703 && can_access(sig_path
, READ_ACCESS
) == 0)
2704 ||(IS_REMOTE(ps_global
->VAR_SIGNATURE_FILE
)
2705 && (folder_exists(NULL
, sig_path
) & FEX_ISFILE
)))
2707 else if(!ps_global
->vars
[V_SIGNATURE_FILE
].main_user_val
.p
2708 && !ps_global
->vars
[V_SIGNATURE_FILE
].cmdline_val
.p
2709 && !ps_global
->vars
[V_SIGNATURE_FILE
].fixed_val
.p
)
2716 char *result
= NULL
;
2721 ew
= edit_exceptions
? ps_global
->ew_for_except_vars
: Main
;
2723 if(ps_global
->restricted
)
2727 readonly
= ps_global
->prc
->readonly
;
2730 readonly
= ps_global
->post_prc
->readonly
;
2737 err
= cpystr(ps_global
->restricted
2738 ? "Alpine demo can't change config file"
2739 : _("Config file not changeable"));
2742 apval
= APVAL(&ps_global
->vars
[V_LITERAL_SIG
], ew
);
2744 err
= cpystr(_("Problem accessing configuration"));
2748 input
= (char *)fs_get((strlen(*apval
? *apval
: "")+1) *
2751 cstring_to_string(*apval
, input
);
2752 err
= signature_edit_lit(input
, &result
,
2753 _("SIGNATURE EDITOR"),
2754 h_composer_sigedit
);
2755 fs_give((void **)&input
);
2760 char *cstring_version
;
2762 cstring_version
= string_to_cstring(result
);
2764 set_variable(V_LITERAL_SIG
, cstring_version
, 0, 0, ew
);
2767 fs_give((void **)&cstring_version
);
2771 fs_give((void **)&result
);
2774 err
= signature_edit(ps_global
->VAR_SIGNATURE_FILE
,
2775 _("SIGNATURE EDITOR"));
2778 q_status_message(SM_ORDER
, 3, 4, err
);
2779 fs_give((void **)&err
);
2782 ps_global
->mangled_screen
= 1;
2785 /*----- ADD ADDRESSBOOK ----*/
2787 addr_book_config(ps_global
, edit_exceptions
);
2788 menu_index
= ABOOK_MENU_ITEM
;
2789 ps_global
->mangled_screen
= 1;
2793 /*--- ADD DIRECTORY SERVER --*/
2795 directory_config(ps_global
, edit_exceptions
);
2796 ps_global
->mangled_screen
= 1;
2803 smime_config_screen(ps_global
, edit_exceptions
);
2804 ps_global
->mangled_screen
= 1;
2808 /*----- CONFIGURE OPTIONS -----*/
2810 option_screen(ps_global
, edit_exceptions
);
2811 ps_global
->mangled_screen
= 1;
2814 /*----- XOAUTH2 CLIENT CONFIGURATION -----*/
2816 alpine_xoauth2_configuration(ps_global
, edit_exceptions
);
2817 ps_global
->mangled_screen
= 1;
2820 /*----- COLLECTION LIST -----*/
2822 folder_config_screen(ps_global
, edit_exceptions
);
2823 ps_global
->mangled_screen
= 1;
2826 /*----- RULES -----*/
2828 rtype
= rule_setup_type(ps_global
, RS_RULES
| RS_INCFILTNOW
,
2829 _("Type of rule setup : "));
2837 role_config_screen(ps_global
, (rtype
== 'r') ? ROLE_DO_ROLES
:
2838 (rtype
== 's') ? ROLE_DO_SCORES
:
2839 (rtype
== 'o') ? ROLE_DO_OTHER
:
2840 (rtype
== 'f') ? ROLE_DO_FILTER
:
2841 (rtype
== 'c') ? ROLE_DO_SRCH
:
2847 q_status_message(SM_ORDER
| SM_DING
, 3, 5,
2848 _("Try turning on color with the Setup/Kolor command."));
2852 role_process_filters();
2856 cmd_cancelled(NULL
);
2860 ps_global
->mangled_screen
= 1;
2863 /*----- COLOR -----*/
2865 color_config_screen(ps_global
, edit_exceptions
);
2866 ps_global
->mangled_screen
= 1;
2870 convert_to_remote_config(ps_global
, edit_exceptions
);
2871 ps_global
->mangled_screen
= 1;
2874 /*----- EXIT -----*/
2878 /*----- NEW PASSWORD -----*/
2881 if(ps_global
->restricted
){
2882 q_status_message(SM_ORDER
, 3, 5,
2883 "Password change unavailable in restricted demo version of Alpine.");
2887 ps_global
->mangled_screen
= 1;
2890 q_status_message(SM_ORDER
, 0, 5,
2891 _("Password changing not configured for this version of Alpine."));
2892 display_message('x');
2897 /*----- CHOOSE PRINTER ------*/
2899 select_printer(ps_global
, edit_exceptions
);
2900 ps_global
->mangled_screen
= 1;
2908 rule_setup_type(struct pine
*ps
, int flags
, char *prompt
)
2911 int ekey_num
= 0, deefault
= 0;
2913 if(flags
& RS_INCADDR
){
2915 opts
[ekey_num
].ch
= 'a';
2916 opts
[ekey_num
].rval
= 'a';
2917 opts
[ekey_num
].name
= "A";
2918 opts
[ekey_num
++].label
= "Addrbook";
2921 if(flags
& RS_RULES
){
2923 if(F_OFF(F_DISABLE_ROLES_SETUP
,ps
)){ /* roles are allowed */
2927 opts
[ekey_num
].ch
= 'r';
2928 opts
[ekey_num
].rval
= 'r';
2929 opts
[ekey_num
].name
= "R";
2930 opts
[ekey_num
++].label
= "Roles";
2932 else if(deefault
!= 'a')
2935 opts
[ekey_num
].ch
= 's';
2936 opts
[ekey_num
].rval
= 's';
2937 opts
[ekey_num
].name
= "S";
2938 opts
[ekey_num
++].label
= "SetScores";
2941 if(ps
->color_style
!= COL_NONE
&& pico_hascolor()){
2946 opts
[ekey_num
].ch
= 'i';
2947 opts
[ekey_num
].rval
= 'i';
2948 opts
[ekey_num
].name
= "I";
2949 opts
[ekey_num
++].label
= "Indexcolor";
2953 opts
[ekey_num
].ch
= 'i';
2954 opts
[ekey_num
].rval
= 'Z'; /* notice this rval! */
2955 opts
[ekey_num
].name
= "I";
2956 opts
[ekey_num
++].label
= "Indexcolor";
2960 opts
[ekey_num
].ch
= 'f';
2961 opts
[ekey_num
].rval
= 'f';
2962 opts
[ekey_num
].name
= "F";
2963 opts
[ekey_num
++].label
= "Filters";
2965 opts
[ekey_num
].ch
= 'o';
2966 opts
[ekey_num
].rval
= 'o';
2967 opts
[ekey_num
].name
= "O";
2968 opts
[ekey_num
++].label
= "Other";
2970 opts
[ekey_num
].ch
= 'c';
2971 opts
[ekey_num
].rval
= 'c';
2972 opts
[ekey_num
].name
= "C";
2973 opts
[ekey_num
++].label
= "searCh";
2977 if(flags
& RS_INCEXP
){
2978 opts
[ekey_num
].ch
= 'e';
2979 opts
[ekey_num
].rval
= 'e';
2980 opts
[ekey_num
].name
= "E";
2981 opts
[ekey_num
++].label
= "Export";
2984 if(flags
& RS_INCFILTNOW
){
2985 opts
[ekey_num
].ch
= 'n';
2986 opts
[ekey_num
].rval
= 'n';
2987 opts
[ekey_num
].name
= "N";
2988 opts
[ekey_num
++].label
= "filterNow";
2991 opts
[ekey_num
].ch
= -1;
2993 return(radio_buttons(prompt
, -FOOTER_ROWS(ps
), opts
,
2994 deefault
, 'x', NO_HELP
, RB_NORM
));
3000 * Process the command list, changing function key notation into
3001 * lexical equivalents.
3004 process_init_cmds(struct pine
*ps
, char **list
)
3010 #define MAX_INIT_CMDS 500
3011 /* this is just a temporary stack array, the real one is allocated below */
3012 int i_cmds
[MAX_INIT_CMDS
];
3017 for(p
= list
; *p
; p
++){
3018 if(i
>= MAX_INIT_CMDS
){
3019 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
3020 "Initial keystroke list too long at \"%s\"", *p
);
3021 init_error(ps
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
3026 /* regular character commands */
3027 if(strlen(*p
) == 1){
3032 /* special commands */
3033 else if(strucmp(*p
, "SPACE") == 0)
3035 else if(strucmp(*p
, "CR") == 0)
3037 else if(strucmp(*p
, "TAB") == 0)
3039 else if(strucmp(*p
, "UP") == 0)
3040 i_cmds
[i
++] = KEY_UP
;
3041 else if(strucmp(*p
, "DOWN") == 0)
3042 i_cmds
[i
++] = KEY_DOWN
;
3043 else if(strucmp(*p
, "LEFT") == 0)
3044 i_cmds
[i
++] = KEY_LEFT
;
3045 else if(strucmp(*p
, "RIGHT") == 0)
3046 i_cmds
[i
++] = KEY_RIGHT
;
3049 else if(strlen(*p
) == 2 && **p
== '^')
3050 i_cmds
[i
++] = ctrl(*((*p
)+1));
3053 else if(**p
== 'F' || **p
== 'f'){
3058 if(v
>= 1 && v
<= 12)
3059 i_cmds
[i
++] = PF1
+ v
- 1;
3061 i_cmds
[i
++] = KEY_JUNK
;
3064 /* literal string */
3065 else if(**p
== '"' && (*p
)[lpm1
= strlen(*p
) - 1] == '"'){
3066 if(lpm1
+ i
- 1 > MAX_INIT_CMDS
){
3067 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
3068 "Initial keystroke list too long, truncated at %s\n", *p
);
3069 init_error(ps
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
3070 break; /* Bail out of this loop! */
3072 for(j
= 1; j
< lpm1
; j
++)
3073 i_cmds
[i
++] = (*p
)[j
];
3076 snprintf(tmp_20k_buf
,SIZEOF_20KBUF
,
3077 "Bad initial keystroke \"%.500s\" (missing comma?)", *p
);
3078 init_error(ps
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
3085 * We don't handle the case where function keys are used to specify the
3086 * commands but some non-function key input is also required. For example,
3087 * you might want to jump to a specific message number and view it
3088 * on start up. To do that, you need to use character commands instead
3089 * of function key commands in the initial-keystroke-list.
3091 if(fkeys
&& not_fkeys
){
3092 init_error(ps
, SM_ORDER
| SM_DING
, 3, 5,
3093 "Mixed characters and function keys in \"initial-keystroke-list\", skipping.");
3097 if(fkeys
&& !not_fkeys
)
3098 F_TURN_ON(F_USE_FK
,ps
);
3099 if(!fkeys
&& not_fkeys
)
3100 F_TURN_OFF(F_USE_FK
,ps
);
3103 ps
->initial_cmds
= (int *)fs_get((i
+1) * sizeof(int));
3104 ps
->free_initial_cmds
= ps
->initial_cmds
;
3105 for(j
= 0; j
< i
; j
++)
3106 ps
->initial_cmds
[j
] = i_cmds
[j
];
3108 ps
->initial_cmds
[i
] = 0;
3109 ps
->in_init_seq
= ps
->save_in_init_seq
= 1;
3115 user_wordseps(char **list
)
3120 #define MAX_SEPARATORS 500
3122 * This is just a temporary stack array, the real one is allocated below.
3123 * This is supposed to be way large enough.
3125 UCS seps
[MAX_SEPARATORS
+1];
3127 UCS
*return_array
= NULL
;
3133 for(p
= list
; *p
; p
++){
3134 if(i
>= MAX_SEPARATORS
){
3135 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3136 "Warning: composer-word-separators list is too long");
3140 u
= utf8_to_ucs4_cpystr(*p
);
3143 if(ucs4_strlen(u
) == 1)
3145 else if(*u
== '"' && u
[l
= ucs4_strlen(u
) - 1] == '"'){
3146 if(l
+ i
- 1 > MAX_SEPARATORS
){
3147 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3148 "Warning: composer-word-separators list is too long");
3149 break; /* Bail out of this loop! */
3152 for(j
= 1; j
< l
; j
++)
3158 if(l
+ i
> MAX_SEPARATORS
){
3159 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3160 "Warning: composer-word-separators list is too long");
3161 break; /* Bail out of this loop! */
3164 for(j
= 0; j
< l
; j
++)
3169 fs_give((void **) &u
);
3177 return_array
= ucs4_cpystr(seps
);
3179 return(return_array
);
3184 * Make sure any errors during initialization get queued for display
3187 queue_init_errors(struct pine
*ps
)
3192 for(i
= 0; (ps
->init_errs
)[i
].message
; i
++){
3193 q_status_message((ps
->init_errs
)[i
].flags
,
3194 (ps
->init_errs
)[i
].min_time
,
3195 (ps
->init_errs
)[i
].max_time
,
3196 (ps
->init_errs
)[i
].message
);
3197 fs_give((void **)&(ps
->init_errs
)[i
].message
);
3200 fs_give((void **)&ps
->init_errs
);
3205 /*----------------------------------------------------------------------
3206 Quit pine if the user wants to
3208 Args: The usual pine structure
3210 Result: User is asked if she wants to quit, if yes then execute quit.
3214 Not really a full screen. Just count up deletions and ask if we really
3218 quit_screen(struct pine
*pine_state
)
3222 dprint((1, "\n\n ---- QUIT SCREEN ----\n"));
3224 if(F_ON(F_CHECK_MAIL_ONQUIT
,ps_global
)
3225 && pine_state
->mail_stream
!= NULL
3226 && new_mail(1, VeryBadTime
, NM_STATUS_MSG
| NM_DEFER_SORT
) > 0
3227 && (quit
= want_to(_("Quit even though new mail just arrived"), 'y', 0,
3228 NO_HELP
, WT_NORM
| WT_DING
)) != 'y'){
3229 refresh_sort(pine_state
->mail_stream
, pine_state
->msgmap
, SRT_VRB
);
3230 pine_state
->next_screen
= pine_state
->prev_screen
;
3235 && F_OFF(F_QUIT_WO_CONFIRM
,pine_state
)
3236 && want_to(_("Really quit Alpine"), 'y', 0, NO_HELP
, WT_NORM
) != 'y'){
3237 pine_state
->next_screen
= pine_state
->prev_screen
;
3241 goodnight_gracey(pine_state
, 0);
3245 /*----------------------------------------------------------------------
3246 The nuts and bolts of actually cleaning up and exitting pine
3248 Args: ps -- the usual pine structure,
3249 exit_val -- what to tell our parent
3251 Result: This never returns
3255 goodnight_gracey(struct pine
*pine_state
, int exit_val
)
3257 int i
, cnt_user_streams
= 0;
3258 char *final_msg
= NULL
;
3259 char msg
[MAX_SCREEN_COLS
+1];
3260 char *pf
= _("Alpine finished");
3262 extern KBESC_T
*kbesc
;
3264 dprint((2, "goodnight_gracey:\n"));
3266 /* We want to do this here before we close up the streams */
3267 trim_remote_adrbks();
3269 for(i
= 0; i
< ps_global
->s_pool
.nstream
; i
++){
3270 m
= ps_global
->s_pool
.streams
[i
];
3271 if(m
&& sp_flagged(m
, SP_LOCKED
) && sp_flagged(m
, SP_USERFLDR
))
3275 /* clean up open streams */
3277 if(pine_state
->mail_stream
3278 && sp_flagged(pine_state
->mail_stream
, SP_LOCKED
)
3279 && sp_flagged(pine_state
->mail_stream
, SP_USERFLDR
)){
3280 dprint((5, "goodnight_gracey: close current stream\n"));
3281 expunge_and_close(pine_state
->mail_stream
,
3282 (cnt_user_streams
<= 1) ? &final_msg
: NULL
, EC_NONE
);
3286 pine_state
->mail_stream
= NULL
;
3287 pine_state
->redrawer
= (void (*)(void))NULL
;
3290 "goodnight_gracey: close other stream pool streams\n"));
3291 for(i
= 0; i
< ps_global
->s_pool
.nstream
; i
++){
3292 m
= ps_global
->s_pool
.streams
[i
];
3294 * fix global for functions that depend(ed) on it sort_folder.
3295 * Hopefully those will get phased out.
3297 ps_global
->mail_stream
= m
;
3298 if(m
&& sp_flagged(m
, SP_LOCKED
) && sp_flagged(m
, SP_USERFLDR
)
3299 && !sp_flagged(m
, SP_INBOX
)){
3300 sp_set_expunge_count(m
, 0L);
3301 expunge_and_close(m
, (cnt_user_streams
<= 1) ? &final_msg
: NULL
,
3307 for(i
= 0; i
< ps_global
->s_pool
.nstream
; i
++){
3308 m
= ps_global
->s_pool
.streams
[i
];
3310 * fix global for functions that depend(ed) on it (sort_folder).
3311 * Hopefully those will get phased out.
3313 ps_global
->mail_stream
= m
;
3314 if(m
&& sp_flagged(m
, SP_LOCKED
) && sp_flagged(m
, SP_USERFLDR
)
3315 && sp_flagged(m
, SP_INBOX
)){
3317 "goodnight_gracey: close inbox stream stream\n"));
3318 sp_set_expunge_count(m
, 0L);
3319 expunge_and_close(m
, (cnt_user_streams
<= 1) ? &final_msg
: NULL
,
3327 (void)get_windsize(ps_global
->ttyo
);
3330 dprint((7, "goodnight_gracey: close config files\n"));
3332 free_pinerc_strings(&pine_state
);
3334 strncpy(msg
, pf
, sizeof(msg
));
3335 msg
[sizeof(msg
)-1] = '\0';
3337 strncat(msg
, " -- ", sizeof(msg
)-strlen(msg
)-1);
3338 msg
[sizeof(msg
)-1] = '\0';
3339 strncat(msg
, final_msg
, sizeof(msg
)-strlen(msg
)-1);
3340 msg
[sizeof(msg
)-1] = '\0';
3341 fs_give((void **)&final_msg
);
3344 dprint((7, "goodnight_gracey: sp_end\n"));
3345 ps_global
->noshow_error
= 1;
3352 /* after sp_end, which might call a filter */
3353 completely_done_with_adrbks();
3355 dprint((7, "goodnight_gracey: end_screen\n"));
3356 end_screen(msg
, exit_val
);
3357 dprint((7, "goodnight_gracey: end_titlebar\n"));
3359 dprint((7, "goodnight_gracey: end_keymenu\n"));
3362 dprint((7, "goodnight_gracey: end_keyboard\n"));
3363 end_keyboard(F_ON(F_USE_FK
,pine_state
));
3364 dprint((7, "goodnight_gracey: end_ttydriver\n"));
3365 end_tty_driver(pine_state
);
3366 #if !defined(DOS) && !defined(OS2)
3368 #if !defined(LEAVEOUTFIFO)
3369 close_newmailfifo();
3373 if(filter_data_file(0))
3374 our_unlink(filter_data_file(0));
3376 imap_flush_passwd_cache(TRUE
);
3377 free_newsgrp_cache();
3379 close_every_pattern();
3381 free_contexts(&ps_global
->context_list
);
3382 free_charsetchecker();
3383 dprint((7, "goodnight_gracey: free more memory\n"));
3385 free_saved_query_parameters();
3388 html_dir_clean(1); /* force remove of remaining files */
3389 free_pine_struct(&pine_state
);
3393 free_alpine_module_globals(); /* should we have module globals? */
3394 free_pith_module_globals();
3395 free_pico_module_globals();
3396 free_c_client_module_globals();
3401 fputs("goodnight_gracey finished\n", debugfile
);
3411 /*----------------------------------------------------------------------
3412 Call back for c-client to feed us back the progress of network reads
3419 pine_read_progress(GETS_DATA
*md
, long unsigned int count
)
3421 gets_bytes
+= count
; /* update counter */
3425 /*----------------------------------------------------------------------
3426 Function to fish the current byte count from a c-client fetch.
3428 Input: reset -- flag telling us to reset the count
3430 Result: Returns the number of bytes read by the c-client so far
3433 pine_gets_bytes(int reset
)
3442 /*----------------------------------------------------------------------
3443 Panic pine - call on detected programmatic errors to exit pine
3445 Args: message -- message to record in debug file and to be printed for user
3447 Result: The various tty modes are restored
3448 If debugging is active a core dump will be generated
3451 This is also called from imap routines and fs_get and fs_resize.
3454 alpine_panic(char *message
)
3458 /* global variable in .../pico/edef.h */
3461 if(ps_global
->ttyo
){
3462 end_screen(NULL
, -1);
3463 end_keyboard(ps_global
!= NULL
? F_ON(F_USE_FK
,ps_global
) : 0);
3464 end_tty_driver(ps_global
);
3467 if(filter_data_file(0))
3468 our_unlink(filter_data_file(0));
3470 dprint((1, "\n===========================================\n\n"));
3471 dprint((1, " Alpine Panic: %s\n\n", message
? message
: "?"));
3472 dprint((1, "===========================================\n\n"));
3474 /* intercept c-client "free storage" errors */
3475 if(strstr(message
, "free storage"))
3476 snprintf(buf
, sizeof(buf
), _("No more available memory.\nAlpine Exiting"));
3478 snprintf(buf
, sizeof(buf
), _("Problem detected: \"%s\".\nAlpine Exiting."), message
);
3480 buf
[sizeof(buf
)-1] = '\0';
3483 /* Put up a message box. */
3484 mswin_messagebox (buf
, 1);
3486 fprintf(stderr
, "\n\n%s\n", buf
);
3491 save_debug_on_crash(debugfile
, recent_keystroke
);
3494 coredump(); /*--- If we're debugging get a core dump --*/
3498 fatal("ffo"); /* BUG -- hack to get fatal out of library in right order*/
3503 * panicking - function to test whether or not we're exiting under stress.
3513 /*----------------------------------------------------------------------
3514 exceptional_exit - called to exit under unusual conditions (with no core)
3516 Args: message -- message to record in debug file and to be printed for user
3521 exceptional_exit(char *message
, int ev
)
3523 fprintf(stderr
, "%s\n", message
);
3529 * PicoText Storage Object Support Routines
3535 return((STORE_S
*)pico_get());
3539 pine_pico_give(STORE_S
**sop
)
3541 pico_give((void *)sop
);
3546 pine_pico_writec(int c
, STORE_S
*so
)
3548 unsigned char ch
= (unsigned char) c
;
3550 return(pico_writec(so
->txt
, ch
, PICOREADC_NONE
));
3554 pine_pico_writec_noucs(int c
, STORE_S
*so
)
3556 unsigned char ch
= (unsigned char) c
;
3558 return(pico_writec(so
->txt
, ch
, PICOREADC_NOUCS
));
3562 pine_pico_readc(unsigned char *c
, STORE_S
*so
)
3564 return(pico_readc(so
->txt
, c
, PICOREADC_NONE
));
3568 pine_pico_readc_noucs(unsigned char *c
, STORE_S
*so
)
3570 return(pico_readc(so
->txt
, c
, PICOREADC_NOUCS
));
3574 pine_pico_puts(STORE_S
*so
, char *s
)
3576 return(pico_puts(so
->txt
, s
, PICOREADC_NONE
));
3580 pine_pico_puts_noucs(STORE_S
*so
, char *s
)
3582 return(pico_puts(so
->txt
, s
, PICOREADC_NOUCS
));
3586 pine_pico_seek(STORE_S
*so
, long pos
, int orig
)
3588 return(pico_seek((void *)so
, pos
, orig
));
3593 remote_pinerc_failure(void)
3596 if(ps_global
->install_flag
) /* just exit silently */
3598 #endif /* _WINDOWS */
3600 if(ps_global
->exit_if_no_pinerc
){
3601 exceptional_exit("Exiting because -bail option is set and config file not readable.", -1);
3604 if(want_to("Trouble reading remote configuration! Continue anyway ",
3605 'n', 'n', NO_HELP
, WT_FLUSH_IN
) != 'y'){
3614 dump_supported_options(void)
3618 config
= get_supported_options();
3620 display_args_err(NULL
, config
, 0);
3621 free_list_array(&config
);
3626 /*----------------------------------------------------------------------
3627 Check pruned-folders for validity, making sure they are in the
3628 same context as sent-mail.
3632 prune_folders_ok(void)
3636 for(p
= ps_global
->VAR_PRUNED_FOLDERS
; p
&& *p
&& **p
; p
++)
3637 if(!context_isambig(*p
))
3644 free_alpine_module_globals(void)
3646 #ifdef LOCAL_PASSWD_CACHE
3647 free_passfile_cache();
3649 free_message_queue();
3650 free_titlebar_globals();
3655 pine_user_callback()
3657 if(ps_global
->VAR_USER_ID
&& ps_global
->VAR_USER_ID
[0]){
3658 return(ps_global
->VAR_USER_ID
);
3661 /* SHOULD PROMPT HERE! */
3669 * windows callback to get/set function keys mode state
3672 fkey_mode_callback(set
, args
)
3676 return(F_ON(F_USE_FK
, ps_global
) != 0);
3683 if(ps_global
->mail_stream
)
3684 mail_debug(ps_global
->mail_stream
);
3689 imap_telemetry_off()
3691 if(ps_global
->mail_stream
)
3692 mail_nodebug(ps_global
->mail_stream
);
3697 pcpine_help_main(title
)
3701 strncpy(title
, _("PC-Alpine MAIN MENU Help"), 256);
3703 return(pcpine_help(main_menu_tx
));
3708 pcpine_main_cursor(col
, row
)
3714 if (row
>= (HEADER_ROWS(ps_global
) + MNSKIP(ps_global
)))
3715 ndmi
= (row
+1 - HEADER_ROWS(ps_global
) - (MNSKIP(ps_global
)+1))/(MNSKIP(ps_global
)+1);
3717 if (row
>= (HEADER_ROWS(ps_global
) + MNSKIP(ps_global
))
3718 && !(MNSKIP(ps_global
) && (row
+1) & 0x01)
3719 && ndmi
<= MAX_MENU_ITEM
3720 && FOOTER_ROWS(ps_global
) + (ndmi
+1)*(MNSKIP(ps_global
)+1)
3721 + MNSKIP(ps_global
) + FOOTER_ROWS(ps_global
) <= ps_global
->ttyo
->screen_rows
)
3722 return(MSWIN_CURSOR_HAND
);
3724 return(MSWIN_CURSOR_ARROW
);
3726 #endif /* _WINDOWS */