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-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 * ========================================================================
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"
61 #include "colorconf.h"
67 #include "../pico/osdep/raw.h" /* for STD*_FD */
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
;
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);
102 char *pine_user_callback(void);
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
114 typedef struct setup_return_val
{
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"
147 main(int argc
, char **argv
)
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
;
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
;
208 pith_opt_save_ldap_entry
= save_ldap_entry
;
211 status_message_lock_init();
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));
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
);
232 /* normalize path delimiters */
233 for(p
= pine_state
->home_dir
; p
= strchr(p
, '/'); p
++)
236 #endif /* _WINDOWS */
242 char *no_args
= " <no args>";
244 for(i
= 0; i
< argc
; i
++)
245 len
+= (strlen(argv
[i
] ? argv
[i
] : "")+3);
248 len
+= strlen(no_args
);
250 p
= args_for_debug
= (char *)fs_get((len
+2) * sizeof(char));
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';
261 strncat(args_for_debug
, no_args
, len
+2-strlen(args_for_debug
)-1);
262 args_for_debug
[len
+2-1] = '\0';
267 /*----------------------------------------------------------------------
268 Parse arguments and initialize debugging
269 ----------------------------------------------------------------------*/
270 pine_args(pine_state
, argc
, argv
, &args
);
275 * monkey with descriptors so our normal tty i/o routines don't
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
&& args
.action
== aaURL
){
283 "Cannot read stdin when using -url\nFor mailto URLs, use \'body=\' instead",
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
);
338 init_pinerc(pine_state
, &init_pinerc_debugging
);
341 /* Since this is specific debugging we don't mind if the
342 ifdef is the type of system.
344 #if defined(HAVE_SMALLOC) || defined(NXT)
345 if(ps_global
->debug_malloc
)
346 malloc_debug(ps_global
->debug_malloc
);
349 if(ps_global
->debug_malloc
)
350 mal_debug(ps_global
->debug_malloc
);
353 if(!ps_global
->convert_sigs
355 && !ps_global
->install_flag
356 #endif /* _WINDOWS */
361 dprint((0, " %s (PID=%ld)\n\n", args_for_debug
,
363 fs_give((void **)&args_for_debug
);
368 if((env_to_free
= our_getenv("HOME")) != NULL
){
369 dprint((2, "Setting home dir from $HOME: \"%s\"\n",
371 fs_give((void **)&env_to_free
);
374 dprint((2, "Setting home dir: \"%s\"\n",
375 pine_state
->home_dir
? pine_state
->home_dir
: "<?>"));
379 /* Watch out. Sensitive information in debug file. */
380 if(ps_global
->debug_imap
> 4)
381 mail_parameters(NULL
, SET_DEBUGSENSITIVE
, (void *) TRUE
);
384 if(ps_global
->debug_tcp
)
386 mail_parameters(NULL
, SET_TCPDEBUG
, (void *) TRUE
);
389 mswin_setdebug(debug
, debugfile
);
390 mswin_setdebugoncallback (imap_telemetry_on
);
391 mswin_setdebugoffcallback (imap_telemetry_off
);
392 mswin_enableimaptelemetry(ps_global
->debug_imap
!= 0);
397 mswin_setsortcallback(index_sort_callback
);
398 mswin_setflagcallback(flag_callback
);
399 mswin_sethdrmodecallback(header_mode_callback
);
400 mswin_setselectedcallback(any_selected_callback
);
401 mswin_setzoomodecallback(zoom_mode_callback
);
402 mswin_setfkeymodecallback(fkey_mode_callback
);
405 /*------- Set up c-client drivers -------*/
406 #include "../c-client/linkage.c"
408 /*------- ... then tune the drivers just installed -------*/
410 if(_tgetenv(TEXT("HOME")))
411 mail_parameters(NULL
, SET_HOMEDIR
, (void *) pine_state
->home_dir
);
413 mail_parameters(NULL
, SET_USERPROMPT
, (void *) pine_user_callback
);
416 * Sniff the environment for timezone offset. We need to do this
417 * here since Windows needs help figuring out UTC, and will adjust
418 * what time() returns based on TZ. THIS WILL SCREW US because
419 * we use time() differences to manage status messages. So, if
420 * rfc822_date, which calls localtime() and thus needs tzset(),
421 * is called while a status message is displayed, it's possible
422 * for time() to return a time *before* what we remember as the
423 * time we put the status message on the display. Sheesh.
426 #else /* !_WINDOWS */
428 * We used to let c-client do this for us automatically, but it declines
429 * to do so for root. This forces c-client to establish an environment,
430 * even if the uid is 0.
432 env_init(ps_global
->ui
.login
, ps_global
->ui
.homedir
);
435 * Install callback to let us know the progress of network reads...
437 (void) mail_parameters(NULL
, SET_READPROGRESS
, (void *)pine_read_progress
);
438 #endif /* !_WINDOWS */
441 * Install callback to handle certificate validation failures,
442 * allowing the user to continue if they wish.
444 mail_parameters(NULL
, SET_SSLCERTIFICATEQUERY
, (void *) pine_sslcertquery
);
445 mail_parameters(NULL
, SET_SSLFAILURE
, (void *) pine_sslfailure
);
447 if(init_pinerc_debugging
){
448 dprint((2, init_pinerc_debugging
));
449 fs_give((void **)&init_pinerc_debugging
);
453 * Initial allocation of array of stream pool pointers.
454 * We do this before init_vars so that we can re-use streams used for
455 * remote config files. These sizes may get changed later.
457 ps_global
->s_pool
.max_remstream
= 2;
459 "Setting initial max_remstream to %d for remote config re-use\n",
460 ps_global
->s_pool
.max_remstream
));
462 init_vars(pine_state
, process_init_cmds
);
465 if(F_ON(F_DONT_DO_SMIME
, ps_global
))
471 * LC_CTYPE is already set from the set_collation call above.
473 * We can't use gettext calls before we do this stuff so it doesn't
474 * help to translate strings that come before this in the program.
475 * Maybe we could rearrange things to accomodate that.
477 setlocale(LC_MESSAGES
, "");
478 bindtextdomain(PACKAGE
, LOCALEDIR
);
479 bind_textdomain_codeset(PACKAGE
, "UTF-8");
481 #endif /* ENABLE_NLS */
483 convert_args_to_utf8(pine_state
, &args
);
485 if(args
.action
== aaFolder
){
486 pine_state
->beginning_of_month
= first_run_of_month();
487 pine_state
->beginning_of_year
= first_run_of_year();
490 /* Set up optional for user-defined display filtering */
491 pine_state
->tools
.display_filter
= dfilter
;
492 pine_state
->tools
.display_filter_trigger
= dfilter_trigger
;
495 if(ps_global
->install_flag
){
496 init_install_get_vars();
499 free_pinerc_s(&ps_global
->prc
);
505 if(ps_global
->convert_sigs
){
506 if(convert_sigs_to_literal(ps_global
, 0) == -1){
507 /* TRANSLATORS: sigs refers to signatures, which the user was trying to convert */
508 fprintf(stderr
, _("trouble converting sigs\n"));
513 if(ps_global
->prc
->outstanding_pinerc_changes
)
514 write_pinerc(ps_global
, Main
, WRP_NONE
);
516 free_pinerc_s(&pine_state
->prc
);
523 * Set up a c-client read timeout and timeout handler. In general,
524 * it shouldn't happen, but a server crash or dead link can cause
525 * pine to appear wedged if we don't set this up...
528 if(pine_state
->VAR_TCPOPENTIMEO
)
529 (void)SVAR_TCP_OPEN(pine_state
, rv
, tmp_20k_buf
, SIZEOF_20KBUF
);
530 mail_parameters(NULL
, SET_OPENTIMEOUT
, (void *)(long)rv
);
533 if(pine_state
->VAR_TCPREADWARNTIMEO
)
534 (void)SVAR_TCP_READWARN(pine_state
, rv
, tmp_20k_buf
, SIZEOF_20KBUF
);
535 mail_parameters(NULL
, SET_READTIMEOUT
, (void *)(long)rv
);
538 if(pine_state
->VAR_TCPWRITEWARNTIMEO
){
539 if(!SVAR_TCP_WRITEWARN(pine_state
, rv
, tmp_20k_buf
, SIZEOF_20KBUF
))
540 if(rv
== 0 || rv
> 4) /* making sure */
541 mail_parameters(NULL
, SET_WRITETIMEOUT
, (void *)(long)rv
);
544 mail_parameters(NULL
, SET_TIMEOUT
, (void *) pine_tcptimeout
);
547 if(pine_state
->VAR_RSHOPENTIMEO
){
548 if(!SVAR_RSH_OPEN(pine_state
, rv
, tmp_20k_buf
, SIZEOF_20KBUF
))
549 if(rv
== 0 || rv
> 4) /* making sure */
550 mail_parameters(NULL
, SET_RSHTIMEOUT
, (void *)(long)rv
);
554 if(pine_state
->VAR_SSHOPENTIMEO
){
555 if(!SVAR_SSH_OPEN(pine_state
, rv
, tmp_20k_buf
, SIZEOF_20KBUF
))
556 if(rv
== 0 || rv
> 4) /* making sure */
557 mail_parameters(NULL
, SET_SSHTIMEOUT
, (void *)(long)rv
);
561 if(pine_state
->VAR_MAILDROPCHECK
){
562 if(!SVAR_MAILDCHK(pine_state
, rvl
, tmp_20k_buf
, SIZEOF_20KBUF
)){
564 rvl
= (60L * 60L * 24L * 100L); /* 100 days */
566 if(rvl
>= 60L) /* making sure */
567 mail_parameters(NULL
, SET_SNARFINTERVAL
, (void *) rvl
);
572 * Lookups of long login names which don't exist are very slow in aix.
573 * This would normally get set in system-wide config if not needed.
575 if(F_ON(F_DISABLE_SHARED_NAMESPACES
, ps_global
))
576 mail_parameters(NULL
, SET_DISABLEAUTOSHAREDNS
, (void *) TRUE
);
578 if(F_ON(F_HIDE_NNTP_PATH
, ps_global
))
579 mail_parameters(NULL
, SET_NNTPHIDEPATH
, (void *) TRUE
);
581 if(F_ON(F_MAILDROPS_PRESERVE_STATE
, ps_global
))
582 mail_parameters(NULL
, SET_SNARFPRESERVE
, (void *) TRUE
);
585 if(pine_state
->VAR_NNTPRANGE
){
586 if(!SVAR_NNTPRANGE(pine_state
, rvl
, tmp_20k_buf
, SIZEOF_20KBUF
))
588 mail_parameters(NULL
, SET_NNTPRANGE
, (void *) rvl
);
592 * Tell c-client not to be so aggressive about uid mappings
594 mail_parameters(NULL
, SET_UIDLOOKAHEAD
, (void *) 20);
597 * Setup referral handling
599 mail_parameters(NULL
, SET_IMAPREFERRAL
, (void *) imap_referral
);
600 mail_parameters(NULL
, SET_MAILPROXYCOPY
, (void *) imap_proxycopy
);
603 * Setup multiple newsrc transition
605 mail_parameters(NULL
, SET_NEWSRCQUERY
, (void *) pine_newsrcquery
);
608 * Disable some drivers if requested.
610 if(ps_global
->VAR_DISABLE_DRIVERS
&&
611 ps_global
->VAR_DISABLE_DRIVERS
[0] &&
612 ps_global
->VAR_DISABLE_DRIVERS
[0][0]){
615 for(t
= ps_global
->VAR_DISABLE_DRIVERS
; t
[0] && t
[0][0]; t
++)
616 if(mail_parameters(NULL
, DISABLE_DRIVER
, (void *)(*t
))){
617 dprint((2, "Disabled mail driver \"%s\"\n", *t
));
620 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
621 _("Failed to disable mail driver \"%s\": name not found"),
623 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
624 init_error(ps_global
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
629 * Disable some authenticators if requested.
631 if(ps_global
->VAR_DISABLE_AUTHS
&&
632 ps_global
->VAR_DISABLE_AUTHS
[0] &&
633 ps_global
->VAR_DISABLE_AUTHS
[0][0]){
636 for(t
= ps_global
->VAR_DISABLE_AUTHS
; t
[0] && t
[0][0]; t
++)
637 if(mail_parameters(NULL
, DISABLE_AUTHENTICATOR
, (void *)(*t
))){
638 dprint((2,"Disabled SASL authenticator \"%s\"\n", *t
));
641 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
642 _("Failed to disable SASL authenticator \"%s\": name not found"),
644 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
645 init_error(ps_global
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
649 if(ps_global
->VAR_ENCRYPTION_RANGE
650 && ps_global
->VAR_ENCRYPTION_RANGE
[0]){
651 char *min_s
, *max_s
, *s
;
654 if((s
= strchr(ps_global
->VAR_ENCRYPTION_RANGE
, ',')) == NULL
){
655 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
656 _("Bad encryption range: \"%s\": resetting to default"),
657 ps_global
->VAR_ENCRYPTION_RANGE
);
658 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
659 init_error(ps_global
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
660 fs_give((void **) &ps_global
->VAR_ENCRYPTION_RANGE
);
661 ps_global
->VAR_ENCRYPTION_RANGE
= cpystr(DF_ENCRYPTION_RANGE
);
662 s
= strchr(ps_global
->VAR_ENCRYPTION_RANGE
, ','); /* try again */
666 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
667 _("Bad default encryption range: \"%s\""),
668 ps_global
->VAR_ENCRYPTION_RANGE
);
669 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
670 init_error(ps_global
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
674 get_pair(ps_global
->VAR_ENCRYPTION_RANGE
, &min_s
, &max_s
, 1, 0);
677 min_v
= pith_ssl_encryption_version(min_s
);
678 max_v
= pith_ssl_encryption_version(max_s
);
680 if(min_v
< 0 || max_v
< 0){
681 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
682 _("Bad encryption range: \"%s\": resetting to default"),
683 ps_global
->VAR_ENCRYPTION_RANGE
);
684 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
685 init_error(ps_global
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
691 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
692 _("Minimum encryption protocol (%s) bigger than maximum value (%s). Reversing..."),
694 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
695 init_error(ps_global
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
701 if(max_v
> 0 && max_v
< (long) pith_ssl_encryption_version("tls1")){
702 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
703 _("Security alert: SSL maximum encryption version was set to SSLv3."),
704 ps_global
->VAR_ENCRYPTION_RANGE
);
705 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
706 init_error(ps_global
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
709 mail_parameters(NULL
, SET_ENCRYPTION_RANGE_MIN
, (void *) &min_v
);
710 mail_parameters(NULL
, SET_ENCRYPTION_RANGE_MAX
, (void *) &max_v
);
715 * setup alternative authentication driver preference for IMAP opens
717 if(F_ON(F_PREFER_ALT_AUTH
, ps_global
))
718 mail_parameters(NULL
, SET_IMAPTRYALT
, (void *) TRUE
);
721 * Install handler to let us know about potential delays
723 (void) mail_parameters(NULL
, SET_BLOCKNOTIFY
, (void *) pine_block_notify
);
725 if(ps_global
->dump_supported_options
){
726 dump_supported_options();
731 * Install extra headers to fetch along with all the other stuff
732 * mail_fetch_structure and mail_fetch_overview requests.
736 (void) mail_parameters(NULL
, SET_IMAPEXTRAHEADERS
,
737 (void *) get_extra_hdrs());
739 if(init_username(pine_state
) < 0){
740 fprintf(stderr
, _("Who are you? (Unable to look up login name)\n"));
744 if(init_userdir(pine_state
) < 0)
747 if(init_hostname(pine_state
) < 0)
751 * Verify mail dir if we're not in send only mode...
753 if(args
.action
== aaFolder
&& init_mail_dir(pine_state
) < 0)
758 /*--- input side ---*/
759 if(init_tty_driver(pine_state
)){
760 #ifndef _WINDOWS /* always succeeds under _WINDOWS */
761 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
);
763 #endif /* !_WINDOWS */
767 /*--- output side ---*/
768 rv
= config_screen(&(pine_state
->ttyo
));
769 #ifndef _WINDOWS /* always succeeds under _WINDOWS */
773 printf(_("Terminal type (environment variable TERM) not set.\n"));
776 printf(_("Terminal type \"%s\" is unknown.\n"), getenv("TERM"));
779 printf(_("Can't open terminal capabilities database.\n"));
782 printf(_("Your terminal, of type \"%s\", is lacking functions needed to run alpine.\n"), getenv("TERM"));
787 end_tty_driver(pine_state
);
790 #endif /* !_WINDOWS */
792 if(F_ON(F_BLANK_KEYMENU
,ps_global
))
793 FOOTER_ROWS(ps_global
) = 1;
796 init_keyboard(pine_state
->orig_use_fkeys
);
797 strncpy(pine_state
->inbox_name
, INBOX_NAME
,
798 sizeof(pine_state
->inbox_name
)-1);
799 init_folders(pine_state
); /* digest folder spec's */
801 pine_state
->in_init_seq
= 0; /* so output (& ClearScreen) show up */
802 pine_state
->dont_use_init_cmds
= 1; /* don't use up initial_commands yet */
805 /* initialize titlebar in case we use it */
806 set_titlebar("", NULL
, NULL
, NULL
, NULL
, 0, FolderName
, 0, 0, NULL
);
809 * Prep storage object driver for PicoText
811 so_register_external_driver(pine_pico_get
, pine_pico_give
, pine_pico_writec
, pine_pico_readc
,
812 pine_pico_puts
, pine_pico_seek
, NULL
, NULL
);
815 if(ps_global
->debug_imap
> 4 || debug
> 9){
816 q_status_message(SM_ORDER
| SM_DING
, 5, 9,
817 _("Warning: sensitive authentication data included in debug file"));
818 flush_status_messages(0);
822 if(args
.action
== aaPrcCopy
|| args
.action
== aaAbookCopy
){
824 char *err_msg
= NULL
;
827 * Don't translate these into UTF-8 because we'll be using them
828 * before we translate next time. User should use ascii.
830 if(args
.data
.copy
.local
&& args
.data
.copy
.remote
){
833 exit_val
= copy_pinerc(args
.data
.copy
.local
,
834 args
.data
.copy
.remote
, &err_msg
);
838 exit_val
= copy_abook(args
.data
.copy
.local
,
839 args
.data
.copy
.remote
, &err_msg
);
847 q_status_message(SM_ORDER
| SM_DING
, 3, 4, err_msg
);
848 fs_give((void **)&err_msg
);
850 goodnight_gracey(pine_state
, exit_val
);
853 if(args
.action
== aaFolder
854 && (pine_state
->first_time_user
|| pine_state
->show_new_version
)){
855 pine_state
->mangled_header
= 1;
856 show_main_screen(pine_state
, 0, FirstMenu
, &main_keymenu
, 0,
858 new_user_or_version(pine_state
);
862 /* put back in case we need to suppress output */
863 pine_state
->in_init_seq
= pine_state
->save_in_init_seq
;
865 /* queue any init errors so they get displayed in a screen below */
866 queue_init_errors(ps_global
);
868 /* "Page" the given file? */
869 if(args
.action
== aaMore
){
870 int dice
= 1, redir
= 0;
872 if(pine_state
->in_init_seq
){
873 pine_state
->in_init_seq
= pine_state
->save_in_init_seq
= 0;
875 if(pine_state
->free_initial_cmds
)
876 fs_give((void **)&(pine_state
->free_initial_cmds
));
878 pine_state
->initial_cmds
= NULL
;
881 /*======= Requested that we simply page the given file =======*/
882 if(args
.data
.file
){ /* Open the requested file... */
884 STORE_S
*store
= NULL
;
885 char *decode_error
= NULL
;
886 char filename
[MAILTMPLEN
];
888 if(args
.data
.file
[0] == '\0'){
889 HelpType help
= NO_HELP
;
891 pine_state
->mangled_footer
= 1;
894 int flags
= OE_APPEND_CURRENT
;
896 rv
= optionally_enter(filename
, -FOOTER_ROWS(pine_state
),
898 /* TRANSLATORS: file is computer data */
899 _("File to open : "),
902 help
= (help
== NO_HELP
) ? h_no_F_arg
: NO_HELP
;
911 q_status_message(SM_ORDER
, 0, 2, _("Cancelled"));
912 goodnight_gracey(pine_state
, -1);
916 removing_trailing_white_space(filename
);
917 removing_leading_white_space(filename
);
918 if(is_absolute_path(filename
))
919 fnexpand(filename
, sizeof(filename
));
921 args
.data
.file
= filename
;
925 /* TRANSLATORS: file is computer data */
926 q_status_message(SM_ORDER
, 0, 2 ,_("No file to open"));
927 goodnight_gracey(pine_state
, -1);
934 if(isatty(0) && (store
= so_get(src
, NULL
, EDIT_ACCESS
))){
937 gf_set_so_writec(&pc
, store
);
939 if((decode_error
= gf_pipe(stdin_getc
, pc
)) != NULL
){
941 q_status_message1(SM_ORDER
, 3, 4,
942 _("Problem reading standard input: %s"),
946 gf_clear_so_writec(store
);
953 strncpy(ps_global
->cur_folder
, args
.data
.file
,
954 sizeof(ps_global
->cur_folder
)-1);
955 ps_global
->cur_folder
[sizeof(ps_global
->cur_folder
)-1] = '\0';
956 if(!(store
= so_get(src
, args
.data
.file
, READ_ACCESS
|READ_FROM_LOCALE
)))
963 memset(&sargs
, 0, sizeof(SCROLL_S
));
964 sargs
.text
.text
= so_text(store
);
965 sargs
.text
.src
= src
;
966 /* TRANSLATORS: file is computer file being read by user */
967 sargs
.text
.desc
= _("file");
968 /* TRANSLATORS: this is in the title bar at top of screen */
969 sargs
.bar
.title
= _("FILE VIEW");
970 sargs
.bar
.style
= FileTextPercent
;
971 sargs
.keys
.menu
= &simple_file_keymenu
;
972 setbitmap(sargs
.keys
.bitmap
);
981 q_status_message2(SM_ORDER
, 3, 4,
982 _("Can't display \"%s\": %s"),
983 (redir
) ? _("Standard Input")
984 : args
.data
.file
? args
.data
.file
: "NULL",
985 error_description(errno
));
988 goodnight_gracey(pine_state
, 0);
990 else if(args
.action
== aaMail
|| (stdin_getc
&& (args
.action
!= aaURL
))){
991 /*======= address on command line/send one message mode ============*/
992 char *to
= NULL
, *error
= NULL
, *addr
= NULL
;
993 int len
, good_addr
= 1;
997 if(pine_state
->in_init_seq
){
998 pine_state
->in_init_seq
= pine_state
->save_in_init_seq
= 0;
1000 if(pine_state
->free_initial_cmds
)
1001 fs_give((void **) &(pine_state
->free_initial_cmds
));
1003 pine_state
->initial_cmds
= NULL
;
1006 /*----- Format the To: line with commas for the composer ---*/
1007 if(args
.data
.mail
.addrlist
){
1010 for(p
= args
.data
.mail
.addrlist
, len
= 0; p
; p
= p
->next
)
1011 len
+= strlen(p
->name
) + 2;
1013 to
= (char *) fs_get((len
+ 5) * sizeof(char));
1014 for(p
= args
.data
.mail
.addrlist
, *to
= '\0'; p
; p
= p
->next
){
1016 strncat(to
, ", ", len
+5-strlen(to
)-1);
1020 strncat(to
, p
->name
, len
+5-strlen(to
)-1);
1024 memset((void *)&fcc
, 0, sizeof(BUILDER_ARG
));
1025 dprint((2, "building addr: -->%s<--\n", to
? to
: "?"));
1026 good_addr
= (build_address(to
, &addr
, &error
, &fcc
, NULL
) >= 0);
1027 dprint((2, "mailing to: -->%s<--\n", addr
? addr
: "?"));
1028 free_strlist(&args
.data
.mail
.addrlist
);
1031 memset(&fcc
, 0, sizeof(fcc
));
1034 compose_mail(addr
, fcc
.tptr
, NULL
,
1035 args
.data
.mail
.attachlist
, stdin_getc
);
1038 /* TRANSLATORS: refers to bad email address */
1039 q_status_message1(SM_ORDER
, 3, 4, _("Bad address: %s"), error
);
1044 fs_give((void **) &addr
);
1047 fs_give((void **) &fcc
.tptr
);
1049 if(args
.data
.mail
.attachlist
)
1050 free_attachment_list(&args
.data
.mail
.attachlist
);
1053 fs_give((void **) &to
);
1056 fs_give((void **) &error
);
1058 goodnight_gracey(pine_state
, exit_val
);
1061 char int_mail
[MAXPATH
+1];
1062 struct key_menu
*km
= &main_keymenu
;
1064 /*========== Normal pine mail reading mode ==========*/
1066 pine_state
->mail_stream
= NULL
;
1067 pine_state
->mangled_screen
= 1;
1069 if(args
.action
== aaURL
){
1072 if(pine_state
->in_init_seq
){
1073 pine_state
->in_init_seq
= pine_state
->save_in_init_seq
= 0;
1075 if(pine_state
->free_initial_cmds
)
1076 fs_give((void **) &(pine_state
->free_initial_cmds
));
1077 pine_state
->initial_cmds
= NULL
;
1079 if((f
= url_local_handler(args
.url
)) != NULL
){
1080 if(args
.data
.mail
.attachlist
){
1081 if(f
== url_local_mailto
){
1082 if(!(url_local_mailto_and_atts(args
.url
,
1083 args
.data
.mail
.attachlist
)
1084 && pine_state
->next_screen
))
1085 free_attachment_list(&args
.data
.mail
.attachlist
);
1086 goodnight_gracey(pine_state
, 0);
1089 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
1090 _("Only mailto URLs are allowed with file attachments"));
1091 goodnight_gracey(pine_state
, -1); /* no return */
1094 else if(!((*f
)(args
.url
) && pine_state
->next_screen
))
1095 goodnight_gracey(pine_state
, 0); /* no return */
1098 q_status_message1(SM_ORDER
| SM_DING
, 3, 4,
1099 _("Unrecognized URL \"%s\""), args
.url
);
1100 goodnight_gracey(pine_state
, -1); /* no return */
1103 else if(!pine_state
->start_in_index
){
1104 /* flash message about executing initial commands */
1105 if(pine_state
->in_init_seq
){
1106 pine_state
->in_init_seq
= 0;
1108 pine_state
->mangled_header
= 1;
1109 pine_state
->mangled_footer
= 1;
1110 pine_state
->mangled_screen
= 0;
1111 /* show that this is Alpine */
1112 show_main_screen(pine_state
, 0, FirstMenu
, km
, 0, (Pos
*)NULL
);
1113 pine_state
->mangled_screen
= 1;
1114 pine_state
->painted_footer_on_startup
= 1;
1115 if(MIN(4, pine_state
->ttyo
->screen_rows
- 4) > 1){
1116 char buf1
[6*MAX_SCREEN_COLS
+1];
1117 char buf2
[6*MAX_SCREEN_COLS
+1];
1120 /* TRANSLATORS: Initial Keystroke List is the literal name of an option */
1121 strncpy(buf1
, _("Executing Initial Keystroke List......"), sizeof(buf1
));
1122 buf1
[sizeof(buf1
)-1] = '\0';
1123 wid
= utf8_width(buf1
);
1124 if(wid
> ps_global
->ttyo
->screen_cols
){
1125 utf8_pad_to_width(buf2
, buf1
, sizeof(buf2
), ps_global
->ttyo
->screen_cols
, 1);
1126 PutLine0(MIN(4, pine_state
->ttyo
->screen_rows
- 4), 0, buf2
);
1129 PutLine0(MIN(4, pine_state
->ttyo
->screen_rows
- 4),
1130 MAX(MIN(11, pine_state
->ttyo
->screen_cols
- wid
), 0), buf1
);
1134 pine_state
->in_init_seq
= 1;
1137 show_main_screen(pine_state
, 0, FirstMenu
, km
, 0, (Pos
*)NULL
);
1138 pine_state
->painted_body_on_startup
= 1;
1139 pine_state
->painted_footer_on_startup
= 1;
1143 /* cancel any initial commands, overridden by cmd line */
1144 if(pine_state
->in_init_seq
){
1145 pine_state
->in_init_seq
= 0;
1146 pine_state
->save_in_init_seq
= 0;
1148 if(pine_state
->initial_cmds
){
1149 if(pine_state
->free_initial_cmds
)
1150 fs_give((void **)&(pine_state
->free_initial_cmds
));
1152 pine_state
->initial_cmds
= NULL
;
1155 F_SET(F_USE_FK
,pine_state
, pine_state
->orig_use_fkeys
);
1158 (void) do_index_border(pine_state
->context_current
,
1159 pine_state
->cur_folder
,
1160 pine_state
->mail_stream
,
1161 pine_state
->msgmap
, MsgIndex
, NULL
,
1162 INDX_CLEAR
|INDX_HEADER
|INDX_FOOTER
);
1163 pine_state
->painted_footer_on_startup
= 1;
1164 if(MIN(4, pine_state
->ttyo
->screen_rows
- 4) > 1){
1165 char buf1
[6*MAX_SCREEN_COLS
+1];
1166 char buf2
[6*MAX_SCREEN_COLS
+1];
1169 strncpy(buf1
, _("Please wait, opening mail folder......"), sizeof(buf1
));
1170 buf1
[sizeof(buf1
)-1] = '\0';
1171 wid
= utf8_width(buf1
);
1172 if(wid
> ps_global
->ttyo
->screen_cols
){
1173 utf8_pad_to_width(buf2
, buf1
, sizeof(buf2
), ps_global
->ttyo
->screen_cols
, 1);
1174 PutLine0(MIN(4, pine_state
->ttyo
->screen_rows
- 4), 0, buf2
);
1177 PutLine0(MIN(4, pine_state
->ttyo
->screen_rows
- 4),
1178 MAX(MIN(11, pine_state
->ttyo
->screen_cols
- wid
), 0), buf1
);
1185 #if !defined(_WINDOWS) && !defined(LEAVEOUTFIFO)
1186 if(ps_global
->VAR_FIFOPATH
&& ps_global
->VAR_FIFOPATH
[0])
1187 init_newmailfifo(ps_global
->VAR_FIFOPATH
);
1190 if(pine_state
->in_init_seq
){
1191 pine_state
->in_init_seq
= 0;
1195 if(args
.action
== aaFolder
&& args
.data
.folder
){
1196 CONTEXT_S
*cntxt
= NULL
, *tc
= NULL
;
1197 char foldername
[MAILTMPLEN
];
1198 int notrealinbox
= 0;
1200 if(args
.data
.folder
[0] == '\0'){
1202 unsigned save_def_goto_rule
;
1204 foldername
[0] = '\0';
1205 save_def_goto_rule
= pine_state
->goto_default_rule
;
1206 pine_state
->goto_default_rule
= GOTO_FIRST_CLCTN
;
1207 tc
= default_save_context(pine_state
->context_list
);
1208 fldr
= broach_folder(-FOOTER_ROWS(pine_state
), 1, ¬realinbox
, &tc
);
1209 pine_state
->goto_default_rule
= save_def_goto_rule
;
1211 strncpy(foldername
, fldr
, sizeof(foldername
)-1);
1212 foldername
[sizeof(foldername
)-1] = '\0';
1216 removing_trailing_white_space(foldername
);
1217 removing_leading_white_space(foldername
);
1218 args
.data
.folder
= cpystr(foldername
);
1222 q_status_message(SM_ORDER
, 0, 2 ,_("No folder to open"));
1223 goodnight_gracey(pine_state
, -1);
1229 else if((rv
= pine_state
->init_context
) < 0)
1231 * As with almost all the folder vars in the pinerc,
1232 * we subvert the collection "breakout" here if the
1233 * folder name given looks like an asolute path on
1236 cntxt
= (is_absolute_path(args
.data
.folder
))
1237 ? NULL
: pine_state
->context_current
;
1241 for(cntxt
= pine_state
->context_list
;
1242 rv
> 1 && cntxt
->next
;
1243 rv
--, cntxt
= cntxt
->next
)
1246 if(pine_state
&& pine_state
->ttyo
){
1247 blank_keymenu(pine_state
->ttyo
->screen_rows
- 2, 0);
1248 pine_state
->painted_footer_on_startup
= 0;
1249 pine_state
->mangled_footer
= 1;
1252 if(args
.data
.folder
&& *args
.data
.folder
1253 && !strucmp(args
.data
.folder
, ps_global
->inbox_name
)
1254 && cntxt
!= ps_global
->context_list
)
1257 if(do_broach_folder(args
.data
.folder
, cntxt
, NULL
, notrealinbox
? 0L : DB_INBOXWOCNTXT
) <= 0){
1258 q_status_message1(SM_ORDER
, 3, 4,
1259 _("Unable to open folder \"%s\""), args
.data
.folder
);
1261 fs_give((void **) &args
.data
.folder
);
1263 goodnight_gracey(pine_state
, -1);
1266 else if(args
.action
== aaFolder
){
1269 * need to ask for the inbox name if no default under DOS
1270 * since there is no "inbox"
1273 if(!pine_state
->VAR_INBOX_PATH
|| !pine_state
->VAR_INBOX_PATH
[0]
1274 || strucmp(pine_state
->VAR_INBOX_PATH
, "inbox") == 0){
1275 HelpType help
= NO_HELP
;
1276 static ESCKEY_S ekey
[] = {{ctrl(T
), 2, "^T", "To Fldrs"},
1277 {-1, 0, NULL
, NULL
}};
1279 pine_state
->mangled_footer
= 1;
1282 int flags
= OE_APPEND_CURRENT
;
1284 rv
= optionally_enter(int_mail
, -FOOTER_ROWS(pine_state
),
1285 0, sizeof(int_mail
),
1286 _("No inbox! Folder to open as inbox : "),
1287 /* ekey */ NULL
, help
, &flags
);
1289 help
= (help
== NO_HELP
) ? h_sticky_inbox
: NO_HELP
;
1298 q_status_message(SM_ORDER
, 0, 2 ,_("Folder open cancelled"));
1299 rv
= 0; /* reset rv */
1302 show_main_screen(pine_state
,0,FirstMenu
,km
,0,(Pos
*)NULL
);
1306 removing_trailing_white_space(int_mail
);
1307 removing_leading_white_space(int_mail
);
1308 if((!pine_state
->VAR_INBOX_PATH
1309 || strucmp(pine_state
->VAR_INBOX_PATH
, "inbox") == 0)
1310 /* TRANSLATORS: Inbox-Path and PINERC are literal, not to be translated */
1311 && want_to(_("Preserve folder as \"Inbox-Path\" in PINERC"),
1312 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
1313 set_variable(V_INBOX_PATH
, int_mail
, 1, 1, Main
);
1316 if(pine_state
->VAR_INBOX_PATH
)
1317 fs_give((void **)&pine_state
->VAR_INBOX_PATH
);
1319 pine_state
->VAR_INBOX_PATH
= cpystr(int_mail
);
1322 if(pine_state
&& pine_state
->ttyo
){
1323 blank_keymenu(pine_state
->ttyo
->screen_rows
- 2, 0);
1324 pine_state
->painted_footer_on_startup
= 0;
1325 pine_state
->mangled_footer
= 1;
1328 do_broach_folder(pine_state
->inbox_name
,
1329 pine_state
->context_list
, NULL
, DB_INBOXWOCNTXT
);
1332 q_status_message(SM_ORDER
, 0, 2 ,_("No folder opened"));
1337 #endif /* _WINDOWS */
1338 if(F_ON(F_PREOPEN_STAYOPENS
, ps_global
))
1339 preopen_stayopen_folders();
1341 if(pine_state
&& pine_state
->ttyo
){
1342 blank_keymenu(pine_state
->ttyo
->screen_rows
- 2, 0);
1343 pine_state
->painted_footer_on_startup
= 0;
1344 pine_state
->mangled_footer
= 1;
1348 do_broach_folder(pine_state
->inbox_name
,
1349 pine_state
->context_list
, NULL
, DB_INBOXWOCNTXT
);
1352 if(pine_state
->mangled_footer
)
1353 pine_state
->painted_footer_on_startup
= 0;
1355 if(args
.action
== aaFolder
1356 && pine_state
->mail_stream
1357 && expire_sent_mail())
1358 pine_state
->painted_footer_on_startup
= 0;
1361 * Initialize the defaults. Initializing here means that
1362 * if they're remote, the user isn't prompted for an imap login
1363 * before the display's drawn, AND there's the chance that
1364 * we can climb onto the already opened folder's stream...
1366 if(ps_global
->first_time_user
)
1367 init_save_defaults(); /* initialize default save folders */
1369 build_path(int_mail
,
1370 ps_global
->VAR_OPER_DIR
? ps_global
->VAR_OPER_DIR
1371 : pine_state
->home_dir
,
1372 INTERRUPTED_MAIL
, sizeof(int_mail
));
1373 if(args
.action
== aaFolder
1374 && (folder_exists(NULL
, int_mail
) & FEX_ISFILE
))
1375 q_status_message(SM_ORDER
| SM_DING
, 4, 5,
1376 _("Use Compose command to continue interrupted message."));
1378 if(args
.action
== aaFolder
&& args
.data
.folder
)
1379 fs_give((void **) &args
.data
.folder
);
1381 #if defined(USE_QUOTAS)
1385 q
= disk_quota(pine_state
->home_dir
, &over
);
1387 q_status_message2(SM_ASYNC
| SM_DING
, 4, 5,
1388 _("WARNING! Over your disk quota by %s bytes (%s)"),
1389 comatose(q
),byte_string(q
));
1394 pine_state
->in_init_seq
= pine_state
->save_in_init_seq
;
1395 pine_state
->dont_use_init_cmds
= 0;
1398 if(pine_state
->give_fixed_warning
)
1399 q_status_message(SM_ASYNC
, 0, 10,
1400 /* TRANSLATORS: config is an abbreviation for configuration */
1401 _("Note: some of your config options conflict with site policy and are ignored"));
1403 if(!prune_folders_ok())
1404 q_status_message(SM_ASYNC
, 0, 10,
1405 /* TRANSLATORS: Pruned-Folders is literal */
1406 _("Note: ignoring Pruned-Folders outside of default collection for saves"));
1408 if(get_input_timeout() == 0 &&
1409 ps_global
->VAR_INBOX_PATH
&&
1410 ps_global
->VAR_INBOX_PATH
[0] == '{')
1411 q_status_message(SM_ASYNC
, 0, 10,
1412 _("Note: Mail-Check-Interval=0 may cause IMAP server connection to time out"));
1415 mswin_setnewmailwidth(ps_global
->nmw_width
);
1419 /*-------------------------------------------------------------------
1420 Loop executing the commands
1422 This is done like this so that one command screen can cause
1423 another one to execute it with out going through the main menu.
1424 ------------------------------------------------------------------*/
1425 if(!pine_state
->next_screen
)
1426 pine_state
->next_screen
= pine_state
->start_in_index
1427 ? mail_index_screen
: main_menu_screen
;
1429 if(pine_state
->next_screen
== SCREEN_FUN_NULL
)
1430 pine_state
->next_screen
= main_menu_screen
;
1432 (*(pine_state
->next_screen
))(pine_state
);
1441 * The arguments need to be converted to UTF-8 for our internal use.
1442 * Not all arguments are converted because some are used before we
1443 * are able to do the conversion, like the pinerc name.
1446 convert_args_to_utf8(struct pine
*ps
, ARGDATA_S
*args
)
1448 char *fromcharset
= NULL
;
1452 if(ps
->keyboard_charmap
&& strucmp(ps
->keyboard_charmap
, "UTF-8")
1453 && strucmp(ps
->keyboard_charmap
, "US-ASCII"))
1454 fromcharset
= ps
->keyboard_charmap
;
1455 else if(ps
->display_charmap
&& strucmp(ps
->display_charmap
, "UTF-8")
1456 && strucmp(ps
->display_charmap
, "US-ASCII"))
1457 fromcharset
= ps
->display_charmap
;
1459 else if(ps
->VAR_OLD_CHAR_SET
&& strucmp(ps
->VAR_OLD_CHAR_SET
, "UTF-8")
1460 && strucmp(ps
->VAR_OLD_CHAR_SET
, "US-ASCII"))
1461 fromcharset
= ps
->VAR_OLD_CHAR_SET
;
1462 #endif /* ! _WINDOWS */
1464 if(args
->action
== aaURL
&& args
->url
){
1465 conv
= convert_to_utf8(args
->url
, fromcharset
, 0);
1467 fs_give((void **) &args
->url
);
1472 if(args
->action
== aaFolder
&& args
->data
.folder
){
1473 conv
= convert_to_utf8(args
->data
.folder
, fromcharset
, 0);
1475 fs_give((void **) &args
->data
.folder
);
1476 args
->data
.folder
= conv
;
1480 if(args
->action
== aaMore
&& args
->data
.file
){
1481 conv
= convert_to_utf8(args
->data
.file
, fromcharset
, 0);
1483 fs_give((void **) &args
->data
.file
);
1484 args
->data
.file
= conv
;
1488 if(args
->action
== aaURL
|| args
->action
== aaMail
){
1489 if(args
->data
.mail
.addrlist
){
1492 for(p
= args
->data
.mail
.addrlist
; p
; p
=p
->next
){
1494 conv
= convert_to_utf8(p
->name
, fromcharset
, 0);
1496 fs_give((void **) &p
->name
);
1503 if(args
->data
.mail
.attachlist
){
1506 for(p
= args
->data
.mail
.attachlist
; p
; p
=p
->next
){
1508 conv
= convert_to_utf8(p
->filename
, fromcharset
, 0);
1510 fs_give((void **) &p
->filename
);
1522 preopen_stayopen_folders(void)
1526 for(open_these
= ps_global
->VAR_PERMLOCKED
;
1527 open_these
&& *open_these
; open_these
++)
1528 (void) do_broach_folder(*open_these
, ps_global
->context_list
,
1534 * read_stdin_char - simple function to return a character from
1538 read_stdin_char(char *c
)
1542 /* it'd probably be a good idea to fix this to pre-read blocks */
1544 rv
= read(PIPED_FD
, c
, 1);
1547 dprint((2, "read_stdin_char: read interrupted, restarting\n"));
1551 dprint((1, "read_stdin_char: read FAILED: %s\n",
1552 error_description(errno
)));
1560 /* this default is from the array of structs below */
1561 #define DEFAULT_MENU_ITEM ((unsigned) 3) /* LIST FOLDERS */
1562 #define ABOOK_MENU_ITEM ((unsigned) 4) /* ADDRESS BOOK */
1563 #define MAX_MENU_ITEM ((unsigned) 6)
1565 * Skip this many spaces between rows of main menu screen.
1566 * We have MAX_MENU_ITEM+1 = # of commands in menu
1567 * 1 = copyright line
1568 * MAX_MENU_ITEM = rows between commands
1569 * 1 = extra row above commands
1570 * 1 = row between commands and copyright
1572 * To make it simple, if there is enough room for all of that include all the
1573 * extra space, if not, cut it all out.
1575 #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)
1577 static unsigned menu_index
= DEFAULT_MENU_ITEM
;
1580 * One of these for each line that gets printed in the middle of the
1581 * screen in the main menu.
1583 static struct menu_key
{
1586 int key_index
; /* index into keymenu array for this cmd */
1589 * TRANSLATORS: These next few are headings on the Main alpine menu.
1590 * It's nice if the dashes can be made to line up vertically.
1592 {N_(" %s HELP - Get help using Alpine"),
1593 NULL
, MAIN_HELP_KEY
},
1594 {N_(" %s COMPOSE MESSAGE - Compose and send%s a message"),
1595 /* TRANSLATORS: We think of sending an email message or posting a news message.
1596 The message is shown as Compose and send/post a message */
1597 N_("/post"), MAIN_COMPOSE_KEY
},
1598 {N_(" %s MESSAGE INDEX - View messages in current folder"),
1599 NULL
, MAIN_INDEX_KEY
},
1600 {N_(" %s FOLDER LIST - Select a folder%s to view"),
1601 /* TRANSLATORS: When news is supported the message above becomes
1602 Select a folder OR news group to view */
1603 N_(" OR news group"), MAIN_FOLDER_KEY
},
1604 {N_(" %s ADDRESS BOOK - Update address book"),
1605 NULL
, MAIN_ADDRESS_KEY
},
1606 {N_(" %s SETUP - Configure Alpine Options"),
1607 NULL
, MAIN_SETUP_KEY
},
1608 /* TRANSLATORS: final Main menu line */
1609 {N_(" %s QUIT - Leave the Alpine program"),
1610 NULL
, MAIN_QUIT_KEY
}
1615 /*----------------------------------------------------------------------
1616 display main menu and execute main menu commands
1618 Args: The usual pine structure
1620 Result: main menu commands are executed
1623 M A I N M E N U S C R E E N
1625 Paint the main menu on the screen, get the commands and either execute
1626 the function or pass back the name of the function to execute for the menu
1627 selection. Only simple functions that always return here can be executed
1630 This functions handling of new mail, redrawing, errors and such can
1631 serve as a template for the other screen that do much the same thing.
1633 There is a loop that fetchs and executes commands until a command to leave
1634 this screen is given. Then the name of the next screen to display is
1635 stored in next_screen member of the structure and this function is exited
1638 First a check for new mail is performed. This might involve reading the new
1639 mail into the inbox which might then cause the screen to be repainted.
1641 Then the general screen painting is done. This is usually controlled
1642 by a few flags and some other position variables. If they change they
1643 tell this part of the code what to repaint. This will include cursor
1647 main_menu_screen(struct pine
*pine_state
)
1650 int cmd
, just_a_navigate_cmd
, setup_command
, km_popped
;
1652 char *new_folder
, *utf8str
;
1654 struct key_menu
*km
;
1658 ps_global
= pine_state
;
1659 just_a_navigate_cmd
= 0;
1661 menu_index
= DEFAULT_MENU_ITEM
;
1662 what
= FirstMenu
; /* which keymenu to display */
1663 ch
= 'x'; /* For display_message 1st time through */
1664 pine_state
->next_screen
= SCREEN_FUN_NULL
;
1665 pine_state
->prev_screen
= main_menu_screen
;
1666 curs_pos
.row
= pine_state
->ttyo
->screen_rows
-FOOTER_ROWS(pine_state
);
1670 mailcap_free(); /* free resources we won't be using for a while */
1672 if(!pine_state
->painted_body_on_startup
1673 && !pine_state
->painted_footer_on_startup
){
1674 pine_state
->mangled_screen
= 1;
1677 dprint((1, "\n\n ---- MAIN_MENU_SCREEN ----\n"));
1683 clearfooter(pine_state
);
1684 pine_state
->mangled_body
= 1;
1689 * fix up redrawer just in case some submenu caused it to get
1692 pine_state
->redrawer
= main_redrawer
;
1694 /*----------- Check for new mail -----------*/
1695 if(new_mail(0, NM_TIMING(ch
), NM_STATUS_MSG
| NM_DEFER_SORT
) >= 0)
1696 pine_state
->mangled_header
= 1;
1699 pine_state
->mangled_header
= 1;
1701 show_main_screen(pine_state
, just_a_navigate_cmd
, what
, km
,
1702 km_popped
, &curs_pos
);
1703 just_a_navigate_cmd
= 0;
1706 /*---- This displays new mail notification, or errors ---*/
1708 FOOTER_ROWS(pine_state
) = 3;
1709 mark_status_dirty();
1712 display_message(ch
);
1714 FOOTER_ROWS(pine_state
) = 1;
1715 mark_status_dirty();
1718 if(F_OFF(F_SHOW_CURSOR
, ps_global
)){
1719 curs_pos
.row
=pine_state
->ttyo
->screen_rows
-FOOTER_ROWS(pine_state
);
1723 MoveCursor(curs_pos
.row
, curs_pos
.col
);
1725 /*------ Read the command from the keyboard ----*/
1727 mouse_in_content(KEY_MOUSE
, -1, -1, 0, 0);
1728 register_mfunc(mouse_in_content
, HEADER_ROWS(pine_state
), 0,
1729 pine_state
->ttyo
->screen_rows
-(FOOTER_ROWS(pine_state
)+1),
1730 pine_state
->ttyo
->screen_cols
);
1732 #if defined(DOS) || defined(OS2)
1734 * AND pre-build header lines. This works just fine under
1735 * DOS since we wait for characters in a loop. Something will
1736 * will have to change under UNIX if we want to do the same.
1738 /* while_waiting = build_header_cache; */
1740 mswin_sethelptextcallback(pcpine_help_main
);
1741 mswin_mousetrackcallback(pcpine_main_cursor
);
1744 ch
= READ_COMMAND(&utf8str
);
1746 clear_mfunc(mouse_in_content
);
1748 #if defined(DOS) || defined(OS2)
1749 /* while_waiting = NULL; */
1751 mswin_sethelptextcallback(NULL
);
1752 mswin_mousetrackcallback(NULL
);
1756 /* No matter what, Quit here always works */
1757 if(ch
== 'q' || ch
== 'Q'){
1761 else if(debug
&& ch
&& ch
< 0x80 && strchr("123456789", ch
)){
1767 ps_global
->debug_timestamp
= 1;
1769 ps_global
->debug_timestamp
= 0;
1772 ps_global
->debug_imap
= 4;
1774 ps_global
->debug_imap
= 3;
1776 ps_global
->debug_imap
= 2;
1778 ps_global
->debug_imap
= 1;
1780 ps_global
->debug_imap
= 0;
1782 if(ps_global
->mail_stream
){
1783 if(ps_global
->debug_imap
> 0){
1784 mail_debug(ps_global
->mail_stream
);
1786 mswin_enableimaptelemetry(TRUE
);
1790 mail_nodebug(ps_global
->mail_stream
);
1792 mswin_enableimaptelemetry(FALSE
);
1797 if(debug
> 7 && olddebug
<= 7)
1798 mail_parameters(NULL
, SET_TCPDEBUG
, (void *) TRUE
);
1799 else if(debug
<= 7 && olddebug
> 7 && !ps_global
->debugmem
)
1800 mail_parameters(NULL
, SET_TCPDEBUG
, (void *) FALSE
);
1802 dprint((1, "*** Debug level set to %d ***\n", debug
));
1806 q_status_message1(SM_ORDER
, 0, 1, _("Debug level set to %s"),
1812 cmd
= menu_command(ch
, km
);
1824 clearfooter(pine_state
);
1829 /*------ Execute the command ------*/
1832 /*------ HELP ------*/
1835 if(FOOTER_ROWS(pine_state
) == 1 && km_popped
== 0){
1837 pine_state
->mangled_footer
= 1;
1840 /* TRANSLATORS: This is a screen title */
1841 helper(main_menu_tx
, _("HELP FOR MAIN MENU"), 0);
1842 pine_state
->mangled_screen
= 1;
1848 /*---------- display other key bindings ------*/
1854 pine_state
->mangled_footer
= 1;
1858 /*---------- Previous item in menu ----------*/
1860 if(menu_index
> 0) {
1862 pine_state
->mangled_body
= 1;
1864 pine_state
->mangled_footer
= 1;
1866 just_a_navigate_cmd
++;
1869 /* TRANSLATORS: list refers to list of commands in main menu */
1870 q_status_message(SM_ORDER
, 0, 2, _("Already at top of list"));
1875 /*---------- Next item in menu ----------*/
1877 if(menu_index
< MAX_MENU_ITEM
){
1879 pine_state
->mangled_body
= 1;
1881 pine_state
->mangled_footer
= 1;
1883 just_a_navigate_cmd
++;
1886 q_status_message(SM_ORDER
, 0, 2, _("Already at bottom of list"));
1891 /*---------- Release Notes ----------*/
1893 /* TRANSLATORS: This is a screen title */
1894 helper(h_news
, _("ALPINE RELEASE NOTES"), 0);
1895 pine_state
->mangled_screen
= 1;
1899 #ifdef KEYBOARD_LOCK
1900 /*---------- Keyboard lock ----------*/
1902 (void) lock_keyboard();
1903 pine_state
->mangled_screen
= 1;
1905 #endif /* KEYBOARD_LOCK */
1908 /*---------- Quit pine ----------*/
1910 pine_state
->next_screen
= quit_screen
;
1914 /*---------- Go to composer ----------*/
1916 pine_state
->next_screen
= compose_screen
;
1920 /*---- Go to alternate composer ------*/
1922 pine_state
->next_screen
= alt_compose_screen
;
1926 /*---------- Top of Folder list ----------*/
1927 case MC_COLLECTIONS
:
1928 pine_state
->next_screen
= folder_screen
;
1932 /*---------- Goto new folder ----------*/
1934 tc
= ps_global
->context_current
;
1935 new_folder
= broach_folder(-FOOTER_ROWS(pine_state
), 1, ¬realinbox
, &tc
);
1937 visit_folder(ps_global
, new_folder
, tc
, NULL
, notrealinbox
? 0L : DB_INBOXWOCNTXT
);
1942 /*---------- Go to index ----------*/
1945 && sp_viewing_a_thread(pine_state
->mail_stream
)
1946 && unview_thread(pine_state
, pine_state
->mail_stream
,
1947 pine_state
->msgmap
)){
1948 pine_state
->view_skipped_index
= 0;
1949 pine_state
->mangled_screen
= 1;
1952 pine_state
->next_screen
= mail_index_screen
;
1956 /*---------- Review Status Messages ----------*/
1959 pine_state
->mangled_screen
= 1;
1963 /*---------- Setup mini menu ----------*/
1966 setup_command
= setup_menu(pine_state
);
1967 pine_state
->mangled_footer
= 1;
1968 do_setup_task(setup_command
);
1969 if(ps_global
->next_screen
!= main_menu_screen
)
1975 /*---------- Go to address book ----------*/
1977 pine_state
->next_screen
= addr_book_screen
;
1981 /*------ Repaint the works -------*/
1985 pine_state
->mangled_screen
= 1;
1990 /*------- Mouse event ------*/
1995 struct pine
*ps
= pine_state
;
1997 mouse_get_last (NULL
, &mp
);
2000 if(mp
.button
== M_BUTTON_RIGHT
){
2001 if(!mp
.doubleclick
){
2002 static MPopup main_popup
[] = {
2003 {tQueue
, {"Folder List", lNormal
}, {'L'}},
2004 {tQueue
, {"Message Index", lNormal
}, {'I'}},
2006 {tQueue
, {"Address Book", lNormal
}, {'A'}},
2007 {tQueue
, {"Setup Options", lNormal
}, {'S'}},
2011 mswin_popup(main_popup
);
2016 if (mp
.row
>= (HEADER_ROWS(ps
) + MNSKIP(ps
)))
2017 ndmi
= (mp
.row
+1 - HEADER_ROWS(ps
) - (MNSKIP(ps
)+1))/(MNSKIP(ps
)+1);
2019 if (mp
.row
>= (HEADER_ROWS(ps
) + MNSKIP(ps
))
2020 && !(MNSKIP(ps
) && (mp
.row
+1) & 0x01)
2021 && ndmi
<= MAX_MENU_ITEM
2022 && FOOTER_ROWS(ps
) + (ndmi
+1)*(MNSKIP(ps
)+1)
2023 + MNSKIP(ps
) + FOOTER_ROWS(ps
) <= ps
->ttyo
->screen_rows
){
2025 switch(ndmi
){ /* fake main_screen request */
2030 pine_state
->next_screen
= compose_screen
;
2034 pine_state
->next_screen
= mail_index_screen
;
2038 pine_state
->next_screen
= folder_screen
;
2042 pine_state
->next_screen
= addr_book_screen
;
2049 pine_state
->next_screen
= quit_screen
;
2052 default: /* no op */
2058 pine_state
->mangled_body
= 1;
2060 pine_state
->mangled_footer
= 1;
2062 just_a_navigate_cmd
++;
2074 /*------ Input timeout ------*/
2076 break; /* noop for timeout loop mail check */
2079 /*------ Bogus Input ------*/
2081 if(ch
== 'm' || ch
== 'M'){
2082 q_status_message(SM_ORDER
, 0, 1, "Already in Main Menu");
2087 bogus_command(ch
, F_ON(F_USE_FK
,pine_state
) ? "F1" : "?");
2091 bogus_utf8_command(utf8str
, F_ON(F_USE_FK
, pine_state
) ? "F1" : "?");
2094 } /* the BIG while loop! */
2098 /*----------------------------------------------------------------------
2099 Re-Draw the main menu
2103 Result: main menu is re-displayed
2108 struct key_menu
*km
= &main_keymenu
;
2110 ps_global
->mangled_screen
= 1;
2111 show_main_screen(ps_global
, 0, FirstMenu
, km
, 0, (Pos
*)NULL
);
2115 /*----------------------------------------------------------------------
2118 Args: pine_state - the usual struct
2119 quick_draw - tells do_menu() it can skip some drawing
2120 what - tells which section of keymenu to draw
2122 cursor_pos - returns a good position for the cursor to be located
2124 Result: main menu is displayed
2127 show_main_screen(struct pine
*ps
, int quick_draw
, OtherMenu what
,
2128 struct key_menu
*km
, int km_popped
, Pos
*cursor_pos
)
2130 if(ps
->painted_body_on_startup
|| ps
->painted_footer_on_startup
){
2131 ps
->mangled_screen
= 0; /* only worry about it here */
2132 ps
->mangled_header
= 1; /* we have to redo header */
2133 if(!ps
->painted_body_on_startup
)
2134 ps
->mangled_body
= 1; /* make sure to paint body*/
2136 if(!ps
->painted_footer_on_startup
)
2137 ps
->mangled_footer
= 1; /* make sure to paint footer*/
2139 ps
->painted_body_on_startup
= 0;
2140 ps
->painted_footer_on_startup
= 0;
2143 if(ps
->mangled_screen
){
2144 ps
->mangled_header
= 1;
2145 ps
->mangled_body
= 1;
2146 ps
->mangled_footer
= 1;
2147 ps
->mangled_screen
= 0;
2151 /* Reset the scroll range. Main screen never scrolls. */
2152 scroll_setrange (0L, 0L);
2153 mswin_beginupdate();
2156 /* paint the titlebar if needed */
2157 if(ps
->mangled_header
){
2158 /* TRANSLATORS: screen title */
2159 set_titlebar(_("MAIN MENU"), ps
->mail_stream
, ps
->context_current
,
2160 ps
->cur_folder
, ps
->msgmap
, 1, FolderName
, 0, 0, NULL
);
2161 ps
->mangled_header
= 0;
2164 /* paint the body if needed */
2165 if(ps
->mangled_body
){
2169 do_menu(quick_draw
, cursor_pos
, km
);
2170 ps
->mangled_body
= 0;
2173 /* paint the keymenu if needed */
2174 if(km
&& ps
->mangled_footer
){
2175 static char label
[LONGEST_LABEL
+ 2 + 1], /* label + brackets + \0 */
2181 #ifdef KEYBOARD_LOCK
2182 if(ps_global
->restricted
|| F_ON(F_DISABLE_KBLOCK_CMD
,ps_global
))
2184 clrbitn(MAIN_KBLOCK_KEY
, bitmap
);
2186 menu_clear_binding(km
, '>');
2187 menu_clear_binding(km
, '.');
2188 menu_clear_binding(km
, KEY_RIGHT
);
2189 menu_clear_binding(km
, ctrl('M'));
2190 menu_clear_binding(km
, ctrl('J'));
2191 km
->keys
[MAIN_DEFAULT_KEY
].bind
2192 = km
->keys
[mkeys
[menu_index
].key_index
].bind
;
2193 km
->keys
[MAIN_DEFAULT_KEY
].label
2194 = km
->keys
[mkeys
[menu_index
].key_index
].label
;
2196 /* put brackets around the default action */
2197 snprintf(label
, sizeof(label
), "[%s]", km
->keys
[mkeys
[menu_index
].key_index
].label
);
2198 label
[sizeof(label
)-1] = '\0';
2199 strncpy(name
, ">", sizeof(name
));
2200 name
[sizeof(name
)-1] = '\0';
2201 km
->keys
[MAIN_DEFAULT_KEY
].label
= label
;
2202 km
->keys
[MAIN_DEFAULT_KEY
].name
= name
;
2203 menu_add_binding(km
, '>', km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2204 menu_add_binding(km
, '.', km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2205 menu_add_binding(km
, ctrl('M'), km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2206 menu_add_binding(km
, ctrl('J'), km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2208 if(F_ON(F_ARROW_NAV
,ps_global
))
2209 menu_add_binding(km
, KEY_RIGHT
, km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2212 FOOTER_ROWS(ps
) = 3;
2216 draw_keymenu(km
, bitmap
, ps_global
->ttyo
->screen_cols
,
2217 1-FOOTER_ROWS(ps_global
), 0, what
);
2218 ps
->mangled_footer
= 0;
2220 FOOTER_ROWS(ps
) = 1;
2221 mark_keymenu_dirty();
2231 /*----------------------------------------------------------------------
2232 Actually display the main menu
2234 Args: quick_draw - just a next or prev command was typed so we only have
2235 to redraw the highlighting
2236 cursor_pos - a place to return a good value for cursor location
2238 Result: Main menu is displayed
2241 do_menu(int quick_draw
, Pos
*cursor_pos
, struct key_menu
*km
)
2243 struct pine
*ps
= ps_global
;
2244 int dline
, indent
, longest
= 0, cmd
;
2245 char buf
[4*MAX_SCREEN_COLS
+1];
2246 char buf2
[4*MAX_SCREEN_COLS
+1];
2247 static int last_inverse
= -1;
2250 /* find the longest command */
2251 for(cmd
= 0; cmd
< sizeof(mkeys
)/(sizeof(mkeys
[1])); cmd
++){
2252 memset((void *) buf
, ' ', sizeof(buf
));
2253 snprintf(buf
, sizeof(buf
), mkeys
[cmd
].key_and_name
[0] ? _(mkeys
[cmd
].key_and_name
) : "",
2255 && km
->keys
[mkeys
[cmd
].key_index
].name
)
2256 ? km
->keys
[mkeys
[cmd
].key_index
].name
: "",
2257 (ps
->VAR_NEWS_SPEC
&& mkeys
[cmd
].news_addition
&& mkeys
[cmd
].news_addition
[0])
2258 ? _(mkeys
[cmd
].news_addition
) : "");
2259 buf
[sizeof(buf
)-1] = '\0';
2261 if(longest
< (indent
= utf8_width(buf
)))
2265 indent
= MAX(((ps
->ttyo
->screen_cols
- longest
)/2) - 1, 0);
2267 dline
= HEADER_ROWS(ps
) + MNSKIP(ps
);
2268 for(cmd
= 0; cmd
< sizeof(mkeys
)/(sizeof(mkeys
[1])); cmd
++){
2269 /* leave room for copyright and footer */
2270 if(dline
+ MNSKIP(ps
) + 1 + FOOTER_ROWS(ps
) >= ps
->ttyo
->screen_rows
)
2273 if(quick_draw
&& !(cmd
== last_inverse
|| cmd
== menu_index
)){
2274 dline
+= (1 + MNSKIP(ps
));
2278 if(cmd
== menu_index
)
2281 memset((void *) buf
, ' ', sizeof(buf
));
2282 snprintf(buf
, sizeof(buf
), mkeys
[cmd
].key_and_name
[0] ? _(mkeys
[cmd
].key_and_name
) : "",
2284 && km
->keys
[mkeys
[cmd
].key_index
].name
)
2285 ? km
->keys
[mkeys
[cmd
].key_index
].name
: "",
2286 (ps
->VAR_NEWS_SPEC
&& mkeys
[cmd
].news_addition
&& mkeys
[cmd
].news_addition
[0])
2287 ? _(mkeys
[cmd
].news_addition
) : "");
2288 buf
[sizeof(buf
)-1] = '\0';
2290 utf8_pad_to_width(buf2
, buf
, sizeof(buf2
),
2291 MIN(ps
->ttyo
->screen_cols
-indent
,longest
+1), 1);
2294 PutLine0(pos
.row
, pos
.col
, buf2
);
2299 if(cmd
== menu_index
){
2301 cursor_pos
->row
= pos
.row
;
2302 /* 6 is 1 for the letter plus 5 spaces */
2303 cursor_pos
->col
= pos
.col
+ 6;
2304 if(F_OFF(F_USE_FK
,ps
))
2307 cursor_pos
->col
= MIN(cursor_pos
->col
, ps
->ttyo
->screen_cols
);
2315 last_inverse
= menu_index
;
2317 if(!quick_draw
&& FOOTER_ROWS(ps
)+1 < ps
->ttyo
->screen_rows
){
2318 utf8_to_width(buf2
, LEGAL_NOTICE
, sizeof(buf2
),
2319 ps
->ttyo
->screen_cols
-3, NULL
);
2320 PutLine0(ps
->ttyo
->screen_rows
- (FOOTER_ROWS(ps
)+1),
2321 MAX(0, ((ps
->ttyo
->screen_cols
-utf8_width(buf2
))/2)),
2330 choose_setup_cmd(int cmd
, MSGNO_S
*msgmap
, SCROLL_S
*sparms
)
2335 if(!(srv
= (SRV_S
*)sparms
->proc
.data
.p
)){
2336 sparms
->proc
.data
.p
= (SRV_S
*)fs_get(sizeof(*srv
));
2337 srv
= (SRV_S
*)sparms
->proc
.data
.p
;
2338 memset(srv
, 0, sizeof(*srv
));
2341 ps_global
->next_screen
= SCREEN_FUN_NULL
;
2384 case MC_SECURITY
: /* S/MIME setup screen */
2389 srv
->exc
= !srv
->exc
;
2390 menu_clear_binding(sparms
->keys
.menu
, 'x');
2392 if(sparms
->bar
.title
) fs_give((void **)&sparms
->bar
.title
);
2393 /* TRANSLATORS: screen title */
2394 sparms
->bar
.title
= cpystr(_("SETUP EXCEPTIONS"));
2395 ps_global
->mangled_header
= 1;
2396 /* TRANSLATORS: The reason the X is upper case in eXceptions
2397 is because the command key is X. It isn't necessary, just
2398 nice if it works. */
2399 menu_init_binding(sparms
->keys
.menu
, 'x', MC_EXCEPT
, "X",
2400 N_("not eXceptions"), SETUP_EXCEPT
);
2403 if(sparms
->bar
.title
) fs_give((void **)&sparms
->bar
.title
);
2404 /* TRANSLATORS: screen title */
2405 sparms
->bar
.title
= cpystr(_("SETUP"));
2406 ps_global
->mangled_header
= 1;
2407 menu_init_binding(sparms
->keys
.menu
, 'x', MC_EXCEPT
, "X",
2408 N_("eXceptions"), SETUP_EXCEPT
);
2411 if(sparms
->keys
.menu
->which
== 1)
2412 ps_global
->mangled_footer
= 1;
2418 #if defined(DOS) || defined(OS2)
2419 q_status_message(SM_ORDER
, 0, 2, _("Need argument \"-x <except_config>\" or \"PINERCEX\" file to use eXceptions"));
2421 q_status_message(SM_ORDER
, 0, 2, _("Need argument \"-x <except_config>\" or \".pinercex\" file to use eXceptions"));
2427 alpine_panic("Unexpected command in choose_setup_cmd");
2436 setup_menu(struct pine
*ps
)
2438 int ret
= 0, exceptions
= 0;
2439 int printer
= 0, passwd
= 0, config
= 0, sig
= 0, dir
= 0, smime
= 0, exc
= 0;
2444 if(!(store
= so_get(CharStar
, NULL
, EDIT_ACCESS
))){
2445 q_status_message(SM_ORDER
| SM_DING
, 3, 3, _("Error allocating space."));
2450 if(!ps_global
->vars
[V_PRINTER
].is_fixed
) /* printer can be changed */
2455 if(F_OFF(F_DISABLE_PASSWORD_CMD
,ps_global
)) /* password is allowed */
2459 if(F_OFF(F_DISABLE_CONFIG_SCREEN
,ps_global
)) /* config allowed */
2462 if(F_OFF(F_DISABLE_SIGEDIT_CMD
,ps_global
)) /* .sig editing is allowed */
2473 if(ps_global
->post_prc
)
2476 /* TRANSLATORS: starting here we have a whole screen of help text */
2477 so_puts(store
, _("This is the Setup screen for Alpine. Choose from the following commands:\n"));
2479 so_puts(store
, "\n");
2480 so_puts(store
, _("(E) Exit Setup:\n"));
2481 so_puts(store
, _(" This puts you back at the Main Menu.\n"));
2484 so_puts(store
, "\n");
2485 so_puts(store
, _("(X) eXceptions:\n"));
2486 so_puts(store
, _(" This command is different from the rest. It is not actually a command\n"));
2487 so_puts(store
, _(" itself. Instead, it is a toggle which modifies the behavior of the\n"));
2488 so_puts(store
, _(" other commands. You toggle Exceptions editing on and off with this\n"));
2489 so_puts(store
, _(" command. When it is off you will be editing (changing) your regular\n"));
2490 so_puts(store
, _(" configuration file. When it is on you will be editing your exceptions\n"));
2491 so_puts(store
, _(" configuration file. For example, you might want to type the command \n"));
2492 so_puts(store
, _(" \"eXceptions\" followed by \"Kolor\" to setup different screen colors\n"));
2493 so_puts(store
, _(" on a particular platform.\n"));
2494 so_puts(store
, _(" (Note: this command does not show up on the keymenu at the bottom of\n"));
2495 so_puts(store
, _(" the screen unless you press \"O\" for \"Other Commands\" --but you don't\n"));
2496 so_puts(store
, _(" need to press the \"O\" in order to invoke the command.)\n"));
2500 so_puts(store
, "\n");
2501 so_puts(store
, _("(P) Printer:\n"));
2502 so_puts(store
, _(" Allows you to set a default printer and to define custom\n"));
2503 so_puts(store
, _(" print commands.\n"));
2507 so_puts(store
, "\n");
2508 so_puts(store
, _("(N) Newpassword:\n"));
2509 so_puts(store
, _(" Change your password.\n"));
2513 so_puts(store
, "\n");
2514 so_puts(store
, _("(C) Config:\n"));
2515 so_puts(store
, _(" Allows you to set or unset many features of Alpine.\n"));
2516 so_puts(store
, _(" You may also set the values of many options with this command.\n"));
2520 so_puts(store
, "\n");
2521 so_puts(store
, _("(S) Signature:\n"));
2522 so_puts(store
, _(" Enter or edit a custom signature which will\n"));
2523 so_puts(store
, _(" be included with each new message you send.\n"));
2526 so_puts(store
, "\n");
2527 so_puts(store
, _("(A) AddressBooks:\n"));
2528 so_puts(store
, _(" Define a non-default address book.\n"));
2530 so_puts(store
, "\n");
2531 so_puts(store
, _("(L) collectionLists:\n"));
2532 so_puts(store
, _(" You may define groups of folders to help you better organize your mail.\n"));
2534 so_puts(store
, "\n");
2535 so_puts(store
, _("(R) Rules:\n"));
2536 so_puts(store
, _(" This has up to six sub-categories: Roles, Index Colors, Filters,\n"));
2537 so_puts(store
, _(" SetScores, Search, and Other. If the Index Colors option is\n"));
2538 so_puts(store
, _(" missing you may turn it on (if possible) with Setup/Kolor.\n"));
2539 so_puts(store
, _(" If Roles is missing it has probably been administratively disabled.\n"));
2542 so_puts(store
, "\n");
2543 so_puts(store
, _("(D) Directory:\n"));
2544 so_puts(store
, _(" Define an LDAP Directory server for Alpine's use. A directory server is\n"));
2545 so_puts(store
, _(" similar to an address book, but it is usually maintained by an\n"));
2546 so_puts(store
, _(" organization. It is similar to a telephone directory.\n"));
2549 so_puts(store
, "\n");
2550 so_puts(store
, _("(K) Kolor:\n"));
2551 so_puts(store
, _(" Set custom colors for various parts of the Alpine screens. For example, the\n"));
2552 so_puts(store
, _(" command key labels, the titlebar at the top of each page, and quoted\n"));
2553 so_puts(store
, _(" sections of messages you are viewing.\n"));
2556 so_puts(store
, "\n");
2557 so_puts(store
, _("(M) S/MIME:\n"));
2558 so_puts(store
, _(" Setup for using S/MIME to verify signed messages, decrypt\n"));
2559 so_puts(store
, _(" encrypted messages, and to sign or encrypt outgoing messages.\n"));
2562 so_puts(store
, "\n");
2563 so_puts(store
, _("(Z) RemoteConfigSetup:\n"));
2564 so_puts(store
, _(" This is a command you will probably only want to use once, if at all.\n"));
2565 so_puts(store
, _(" It helps you transfer your Alpine configuration data to an IMAP server,\n"));
2566 so_puts(store
, _(" where it will be accessible from any of the computers you read mail\n"));
2567 so_puts(store
, _(" from (using Alpine). The idea behind a remote configuration is that you\n"));
2568 so_puts(store
, _(" can change your configuration in one place and have that change show\n"));
2569 so_puts(store
, _(" up on all of the computers you use.\n"));
2570 so_puts(store
, _(" (Note: this command does not show up on the keymenu at the bottom of\n"));
2571 so_puts(store
, _(" the screen unless you press \"O\" for \"Other Commands\" --but you don't\n"));
2572 so_puts(store
, _(" need to press the \"O\" in order to invoke the command.)\n"));
2574 /* put this down here for people who don't have exceptions */
2576 so_puts(store
, "\n");
2577 so_puts(store
, _("(X) eXceptions:\n"));
2578 so_puts(store
, _(" This command is different from the rest. It is not actually a command\n"));
2579 so_puts(store
, _(" itself. Instead, it is a toggle which modifies the behavior of the\n"));
2580 so_puts(store
, _(" other commands. You toggle Exceptions editing on and off with this\n"));
2581 so_puts(store
, _(" command. When it is off you will be editing (changing) your regular\n"));
2582 so_puts(store
, _(" configuration file. When it is on you will be editing your exceptions\n"));
2583 so_puts(store
, _(" configuration file. For example, you might want to type the command \n"));
2584 so_puts(store
, _(" \"eXceptions\" followed by \"Kolor\" to setup different screen colors\n"));
2585 so_puts(store
, _(" on a particular platform.\n"));
2586 so_puts(store
, _(" (Note: this command does not do anything unless you have a configuration\n"));
2587 so_puts(store
, _(" with exceptions enabled (you don't have that). Common ways to enable an\n"));
2588 so_puts(store
, _(" exceptions config are the command line argument \"-x <exception_config>\";\n"));
2589 so_puts(store
, _(" or the existence of the file \".pinercex\" for Unix Alpine, or \"PINERCEX\")\n"));
2590 so_puts(store
, _(" for PC-Alpine.)\n"));
2591 so_puts(store
, _(" (Another note: this command does not show up on the keymenu at the bottom\n"));
2592 so_puts(store
, _(" of the screen unless you press \"O\" for \"Other Commands\" --but you\n"));
2593 so_puts(store
, _(" don't need to press the \"O\" in order to invoke the command.)\n"));
2596 memset(&sargs
, 0, sizeof(SCROLL_S
));
2597 sargs
.text
.text
= so_text(store
);
2598 sargs
.text
.src
= CharStar
;
2599 sargs
.text
.desc
= _("Information About Setup Command");
2600 sargs
.bar
.title
= cpystr(_("SETUP"));
2601 sargs
.proc
.tool
= choose_setup_cmd
;
2602 sargs
.help
.text
= NO_HELP
;
2603 sargs
.help
.title
= NULL
;
2604 sargs
.keys
.menu
= &choose_setup_keymenu
;
2605 sargs
.keys
.menu
->how_many
= 2;
2607 setbitmap(sargs
.keys
.bitmap
);
2609 clrbitn(SETUP_PRINTER
, sargs
.keys
.bitmap
);
2612 clrbitn(SETUP_PASSWD
, sargs
.keys
.bitmap
);
2615 clrbitn(SETUP_CONFIG
, sargs
.keys
.bitmap
);
2618 clrbitn(SETUP_SIG
, sargs
.keys
.bitmap
);
2621 clrbitn(SETUP_DIRECTORY
, sargs
.keys
.bitmap
);
2624 clrbitn(SETUP_SMIME
, sargs
.keys
.bitmap
);
2627 menu_init_binding(sargs
.keys
.menu
, 'x', MC_EXCEPT
, "X",
2628 N_("eXceptions"), SETUP_EXCEPT
);
2630 menu_init_binding(sargs
.keys
.menu
, 'x', MC_NO_EXCEPT
, "X",
2631 N_("eXceptions"), SETUP_EXCEPT
);
2636 ps
->mangled_screen
= 1;
2638 srv
= (SRV_S
*)sargs
.proc
.data
.p
;
2640 exceptions
= srv
? srv
->exc
: 0;
2644 if(sargs
.bar
.title
) fs_give((void**)&sargs
.bar
.title
);
2647 fs_give((void **)&sargs
.proc
.data
.p
);
2652 return(ret
| (exceptions
? EDIT_EXCEPTION
: 0));
2656 /*----------------------------------------------------------------------
2658 Args: command -- command char to perform
2662 do_setup_task(int command
)
2666 int edit_exceptions
= 0;
2669 if(command
& EDIT_EXCEPTION
){
2670 edit_exceptions
= 1;
2671 command
&= ~EDIT_EXCEPTION
;
2675 /*----- EDIT SIGNATURE -----*/
2677 if(ps_global
->VAR_LITERAL_SIG
)
2680 char sig_path
[MAXPATH
+1];
2682 if(!signature_path(ps_global
->VAR_SIGNATURE_FILE
, sig_path
, MAXPATH
))
2684 else if((!IS_REMOTE(ps_global
->VAR_SIGNATURE_FILE
)
2685 && can_access(sig_path
, READ_ACCESS
) == 0)
2686 ||(IS_REMOTE(ps_global
->VAR_SIGNATURE_FILE
)
2687 && (folder_exists(NULL
, sig_path
) & FEX_ISFILE
)))
2689 else if(!ps_global
->vars
[V_SIGNATURE_FILE
].main_user_val
.p
2690 && !ps_global
->vars
[V_SIGNATURE_FILE
].cmdline_val
.p
2691 && !ps_global
->vars
[V_SIGNATURE_FILE
].fixed_val
.p
)
2698 char *result
= NULL
;
2703 ew
= edit_exceptions
? ps_global
->ew_for_except_vars
: Main
;
2705 if(ps_global
->restricted
)
2709 readonly
= ps_global
->prc
->readonly
;
2712 readonly
= ps_global
->post_prc
->readonly
;
2719 err
= cpystr(ps_global
->restricted
2720 ? "Alpine demo can't change config file"
2721 : _("Config file not changeable"));
2724 apval
= APVAL(&ps_global
->vars
[V_LITERAL_SIG
], ew
);
2726 err
= cpystr(_("Problem accessing configuration"));
2730 input
= (char *)fs_get((strlen(*apval
? *apval
: "")+1) *
2733 cstring_to_string(*apval
, input
);
2734 err
= signature_edit_lit(input
, &result
,
2735 _("SIGNATURE EDITOR"),
2736 h_composer_sigedit
);
2737 fs_give((void **)&input
);
2742 char *cstring_version
;
2744 cstring_version
= string_to_cstring(result
);
2746 set_variable(V_LITERAL_SIG
, cstring_version
, 0, 0, ew
);
2749 fs_give((void **)&cstring_version
);
2753 fs_give((void **)&result
);
2756 err
= signature_edit(ps_global
->VAR_SIGNATURE_FILE
,
2757 _("SIGNATURE EDITOR"));
2760 q_status_message(SM_ORDER
, 3, 4, err
);
2761 fs_give((void **)&err
);
2764 ps_global
->mangled_screen
= 1;
2767 /*----- ADD ADDRESSBOOK ----*/
2769 addr_book_config(ps_global
, edit_exceptions
);
2770 menu_index
= ABOOK_MENU_ITEM
;
2771 ps_global
->mangled_screen
= 1;
2775 /*--- ADD DIRECTORY SERVER --*/
2777 directory_config(ps_global
, edit_exceptions
);
2778 ps_global
->mangled_screen
= 1;
2785 smime_config_screen(ps_global
, edit_exceptions
);
2786 ps_global
->mangled_screen
= 1;
2790 /*----- CONFIGURE OPTIONS -----*/
2792 option_screen(ps_global
, edit_exceptions
);
2793 ps_global
->mangled_screen
= 1;
2796 /*----- COLLECTION LIST -----*/
2798 folder_config_screen(ps_global
, edit_exceptions
);
2799 ps_global
->mangled_screen
= 1;
2802 /*----- RULES -----*/
2804 rtype
= rule_setup_type(ps_global
, RS_RULES
| RS_INCFILTNOW
,
2805 _("Type of rule setup : "));
2813 role_config_screen(ps_global
, (rtype
== 'r') ? ROLE_DO_ROLES
:
2814 (rtype
== 's') ? ROLE_DO_SCORES
:
2815 (rtype
== 'o') ? ROLE_DO_OTHER
:
2816 (rtype
== 'f') ? ROLE_DO_FILTER
:
2817 (rtype
== 'c') ? ROLE_DO_SRCH
:
2823 q_status_message(SM_ORDER
| SM_DING
, 3, 5,
2824 _("Try turning on color with the Setup/Kolor command."));
2828 role_process_filters();
2832 cmd_cancelled(NULL
);
2836 ps_global
->mangled_screen
= 1;
2839 /*----- COLOR -----*/
2841 color_config_screen(ps_global
, edit_exceptions
);
2842 ps_global
->mangled_screen
= 1;
2846 convert_to_remote_config(ps_global
, edit_exceptions
);
2847 ps_global
->mangled_screen
= 1;
2850 /*----- EXIT -----*/
2854 /*----- NEW PASSWORD -----*/
2857 if(ps_global
->restricted
){
2858 q_status_message(SM_ORDER
, 3, 5,
2859 "Password change unavailable in restricted demo version of Alpine.");
2863 ps_global
->mangled_screen
= 1;
2866 q_status_message(SM_ORDER
, 0, 5,
2867 _("Password changing not configured for this version of Alpine."));
2868 display_message('x');
2873 /*----- CHOOSE PRINTER ------*/
2875 select_printer(ps_global
, edit_exceptions
);
2876 ps_global
->mangled_screen
= 1;
2884 rule_setup_type(struct pine
*ps
, int flags
, char *prompt
)
2887 int ekey_num
= 0, deefault
= 0;
2889 if(flags
& RS_INCADDR
){
2891 opts
[ekey_num
].ch
= 'a';
2892 opts
[ekey_num
].rval
= 'a';
2893 opts
[ekey_num
].name
= "A";
2894 opts
[ekey_num
++].label
= "Addrbook";
2897 if(flags
& RS_RULES
){
2899 if(F_OFF(F_DISABLE_ROLES_SETUP
,ps
)){ /* roles are allowed */
2903 opts
[ekey_num
].ch
= 'r';
2904 opts
[ekey_num
].rval
= 'r';
2905 opts
[ekey_num
].name
= "R";
2906 opts
[ekey_num
++].label
= "Roles";
2908 else if(deefault
!= 'a')
2911 opts
[ekey_num
].ch
= 's';
2912 opts
[ekey_num
].rval
= 's';
2913 opts
[ekey_num
].name
= "S";
2914 opts
[ekey_num
++].label
= "SetScores";
2917 if(ps
->color_style
!= COL_NONE
&& pico_hascolor()){
2922 opts
[ekey_num
].ch
= 'i';
2923 opts
[ekey_num
].rval
= 'i';
2924 opts
[ekey_num
].name
= "I";
2925 opts
[ekey_num
++].label
= "Indexcolor";
2929 opts
[ekey_num
].ch
= 'i';
2930 opts
[ekey_num
].rval
= 'Z'; /* notice this rval! */
2931 opts
[ekey_num
].name
= "I";
2932 opts
[ekey_num
++].label
= "Indexcolor";
2936 opts
[ekey_num
].ch
= 'f';
2937 opts
[ekey_num
].rval
= 'f';
2938 opts
[ekey_num
].name
= "F";
2939 opts
[ekey_num
++].label
= "Filters";
2941 opts
[ekey_num
].ch
= 'o';
2942 opts
[ekey_num
].rval
= 'o';
2943 opts
[ekey_num
].name
= "O";
2944 opts
[ekey_num
++].label
= "Other";
2946 opts
[ekey_num
].ch
= 'c';
2947 opts
[ekey_num
].rval
= 'c';
2948 opts
[ekey_num
].name
= "C";
2949 opts
[ekey_num
++].label
= "searCh";
2953 if(flags
& RS_INCEXP
){
2954 opts
[ekey_num
].ch
= 'e';
2955 opts
[ekey_num
].rval
= 'e';
2956 opts
[ekey_num
].name
= "E";
2957 opts
[ekey_num
++].label
= "Export";
2960 if(flags
& RS_INCFILTNOW
){
2961 opts
[ekey_num
].ch
= 'n';
2962 opts
[ekey_num
].rval
= 'n';
2963 opts
[ekey_num
].name
= "N";
2964 opts
[ekey_num
++].label
= "filterNow";
2967 opts
[ekey_num
].ch
= -1;
2969 return(radio_buttons(prompt
, -FOOTER_ROWS(ps
), opts
,
2970 deefault
, 'x', NO_HELP
, RB_NORM
));
2976 * Process the command list, changing function key notation into
2977 * lexical equivalents.
2980 process_init_cmds(struct pine
*ps
, char **list
)
2986 #define MAX_INIT_CMDS 500
2987 /* this is just a temporary stack array, the real one is allocated below */
2988 int i_cmds
[MAX_INIT_CMDS
];
2993 for(p
= list
; *p
; p
++){
2994 if(i
>= MAX_INIT_CMDS
){
2995 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
2996 "Initial keystroke list too long at \"%s\"", *p
);
2997 init_error(ps
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
3002 /* regular character commands */
3003 if(strlen(*p
) == 1){
3008 /* special commands */
3009 else if(strucmp(*p
, "SPACE") == 0)
3011 else if(strucmp(*p
, "CR") == 0)
3013 else if(strucmp(*p
, "TAB") == 0)
3015 else if(strucmp(*p
, "UP") == 0)
3016 i_cmds
[i
++] = KEY_UP
;
3017 else if(strucmp(*p
, "DOWN") == 0)
3018 i_cmds
[i
++] = KEY_DOWN
;
3019 else if(strucmp(*p
, "LEFT") == 0)
3020 i_cmds
[i
++] = KEY_LEFT
;
3021 else if(strucmp(*p
, "RIGHT") == 0)
3022 i_cmds
[i
++] = KEY_RIGHT
;
3025 else if(strlen(*p
) == 2 && **p
== '^')
3026 i_cmds
[i
++] = ctrl(*((*p
)+1));
3029 else if(**p
== 'F' || **p
== 'f'){
3034 if(v
>= 1 && v
<= 12)
3035 i_cmds
[i
++] = PF1
+ v
- 1;
3037 i_cmds
[i
++] = KEY_JUNK
;
3040 /* literal string */
3041 else if(**p
== '"' && (*p
)[lpm1
= strlen(*p
) - 1] == '"'){
3042 if(lpm1
+ i
- 1 > MAX_INIT_CMDS
){
3043 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
3044 "Initial keystroke list too long, truncated at %s\n", *p
);
3045 init_error(ps
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
3046 break; /* Bail out of this loop! */
3048 for(j
= 1; j
< lpm1
; j
++)
3049 i_cmds
[i
++] = (*p
)[j
];
3052 snprintf(tmp_20k_buf
,SIZEOF_20KBUF
,
3053 "Bad initial keystroke \"%.500s\" (missing comma?)", *p
);
3054 init_error(ps
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
3061 * We don't handle the case where function keys are used to specify the
3062 * commands but some non-function key input is also required. For example,
3063 * you might want to jump to a specific message number and view it
3064 * on start up. To do that, you need to use character commands instead
3065 * of function key commands in the initial-keystroke-list.
3067 if(fkeys
&& not_fkeys
){
3068 init_error(ps
, SM_ORDER
| SM_DING
, 3, 5,
3069 "Mixed characters and function keys in \"initial-keystroke-list\", skipping.");
3073 if(fkeys
&& !not_fkeys
)
3074 F_TURN_ON(F_USE_FK
,ps
);
3075 if(!fkeys
&& not_fkeys
)
3076 F_TURN_OFF(F_USE_FK
,ps
);
3079 ps
->initial_cmds
= (int *)fs_get((i
+1) * sizeof(int));
3080 ps
->free_initial_cmds
= ps
->initial_cmds
;
3081 for(j
= 0; j
< i
; j
++)
3082 ps
->initial_cmds
[j
] = i_cmds
[j
];
3084 ps
->initial_cmds
[i
] = 0;
3085 ps
->in_init_seq
= ps
->save_in_init_seq
= 1;
3091 user_wordseps(char **list
)
3096 #define MAX_SEPARATORS 500
3098 * This is just a temporary stack array, the real one is allocated below.
3099 * This is supposed to be way large enough.
3101 UCS seps
[MAX_SEPARATORS
+1];
3103 UCS
*return_array
= NULL
;
3109 for(p
= list
; *p
; p
++){
3110 if(i
>= MAX_SEPARATORS
){
3111 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3112 "Warning: composer-word-separators list is too long");
3116 u
= utf8_to_ucs4_cpystr(*p
);
3119 if(ucs4_strlen(u
) == 1)
3121 else if(*u
== '"' && u
[l
= ucs4_strlen(u
) - 1] == '"'){
3122 if(l
+ i
- 1 > MAX_SEPARATORS
){
3123 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3124 "Warning: composer-word-separators list is too long");
3125 break; /* Bail out of this loop! */
3128 for(j
= 1; j
< l
; j
++)
3134 if(l
+ i
> MAX_SEPARATORS
){
3135 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3136 "Warning: composer-word-separators list is too long");
3137 break; /* Bail out of this loop! */
3140 for(j
= 0; j
< l
; j
++)
3145 fs_give((void **) &u
);
3153 return_array
= ucs4_cpystr(seps
);
3155 return(return_array
);
3160 * Make sure any errors during initialization get queued for display
3163 queue_init_errors(struct pine
*ps
)
3168 for(i
= 0; (ps
->init_errs
)[i
].message
; i
++){
3169 q_status_message((ps
->init_errs
)[i
].flags
,
3170 (ps
->init_errs
)[i
].min_time
,
3171 (ps
->init_errs
)[i
].max_time
,
3172 (ps
->init_errs
)[i
].message
);
3173 fs_give((void **)&(ps
->init_errs
)[i
].message
);
3176 fs_give((void **)&ps
->init_errs
);
3181 /*----------------------------------------------------------------------
3182 Quit pine if the user wants to
3184 Args: The usual pine structure
3186 Result: User is asked if she wants to quit, if yes then execute quit.
3190 Not really a full screen. Just count up deletions and ask if we really
3194 quit_screen(struct pine
*pine_state
)
3198 dprint((1, "\n\n ---- QUIT SCREEN ----\n"));
3200 if(F_ON(F_CHECK_MAIL_ONQUIT
,ps_global
)
3201 && new_mail(1, VeryBadTime
, NM_STATUS_MSG
| NM_DEFER_SORT
) > 0
3202 && (quit
= want_to(_("Quit even though new mail just arrived"), 'y', 0,
3203 NO_HELP
, WT_NORM
)) != 'y'){
3204 refresh_sort(pine_state
->mail_stream
, pine_state
->msgmap
, SRT_VRB
);
3205 pine_state
->next_screen
= pine_state
->prev_screen
;
3210 && F_OFF(F_QUIT_WO_CONFIRM
,pine_state
)
3211 && want_to(_("Really quit Alpine"), 'y', 0, NO_HELP
, WT_NORM
) != 'y'){
3212 pine_state
->next_screen
= pine_state
->prev_screen
;
3216 goodnight_gracey(pine_state
, 0);
3220 /*----------------------------------------------------------------------
3221 The nuts and bolts of actually cleaning up and exitting pine
3223 Args: ps -- the usual pine structure,
3224 exit_val -- what to tell our parent
3226 Result: This never returns
3230 goodnight_gracey(struct pine
*pine_state
, int exit_val
)
3232 int i
, cnt_user_streams
= 0;
3233 char *final_msg
= NULL
;
3234 char msg
[MAX_SCREEN_COLS
+1];
3235 char *pf
= _("Alpine finished");
3237 extern KBESC_T
*kbesc
;
3239 dprint((2, "goodnight_gracey:\n"));
3241 /* We want to do this here before we close up the streams */
3242 trim_remote_adrbks();
3244 for(i
= 0; i
< ps_global
->s_pool
.nstream
; i
++){
3245 m
= ps_global
->s_pool
.streams
[i
];
3246 if(m
&& sp_flagged(m
, SP_LOCKED
) && sp_flagged(m
, SP_USERFLDR
))
3250 /* clean up open streams */
3252 if(pine_state
->mail_stream
3253 && sp_flagged(pine_state
->mail_stream
, SP_LOCKED
)
3254 && sp_flagged(pine_state
->mail_stream
, SP_USERFLDR
)){
3255 dprint((5, "goodnight_gracey: close current stream\n"));
3256 expunge_and_close(pine_state
->mail_stream
,
3257 (cnt_user_streams
<= 1) ? &final_msg
: NULL
, EC_NONE
);
3261 pine_state
->mail_stream
= NULL
;
3262 pine_state
->redrawer
= (void (*)(void))NULL
;
3265 "goodnight_gracey: close other stream pool streams\n"));
3266 for(i
= 0; i
< ps_global
->s_pool
.nstream
; i
++){
3267 m
= ps_global
->s_pool
.streams
[i
];
3269 * fix global for functions that depend(ed) on it sort_folder.
3270 * Hopefully those will get phased out.
3272 ps_global
->mail_stream
= m
;
3273 if(m
&& sp_flagged(m
, SP_LOCKED
) && sp_flagged(m
, SP_USERFLDR
)
3274 && !sp_flagged(m
, SP_INBOX
)){
3275 sp_set_expunge_count(m
, 0L);
3276 expunge_and_close(m
, (cnt_user_streams
<= 1) ? &final_msg
: NULL
,
3282 for(i
= 0; i
< ps_global
->s_pool
.nstream
; i
++){
3283 m
= ps_global
->s_pool
.streams
[i
];
3285 * fix global for functions that depend(ed) on it (sort_folder).
3286 * Hopefully those will get phased out.
3288 ps_global
->mail_stream
= m
;
3289 if(m
&& sp_flagged(m
, SP_LOCKED
) && sp_flagged(m
, SP_USERFLDR
)
3290 && sp_flagged(m
, SP_INBOX
)){
3292 "goodnight_gracey: close inbox stream stream\n"));
3293 sp_set_expunge_count(m
, 0L);
3294 expunge_and_close(m
, (cnt_user_streams
<= 1) ? &final_msg
: NULL
,
3302 (void)get_windsize(ps_global
->ttyo
);
3305 dprint((7, "goodnight_gracey: close config files\n"));
3307 free_pinerc_strings(&pine_state
);
3309 strncpy(msg
, pf
, sizeof(msg
));
3310 msg
[sizeof(msg
)-1] = '\0';
3312 strncat(msg
, " -- ", sizeof(msg
)-strlen(msg
)-1);
3313 msg
[sizeof(msg
)-1] = '\0';
3314 strncat(msg
, final_msg
, sizeof(msg
)-strlen(msg
)-1);
3315 msg
[sizeof(msg
)-1] = '\0';
3316 fs_give((void **)&final_msg
);
3319 dprint((7, "goodnight_gracey: sp_end\n"));
3320 ps_global
->noshow_error
= 1;
3327 /* after sp_end, which might call a filter */
3328 completely_done_with_adrbks();
3330 dprint((7, "goodnight_gracey: end_screen\n"));
3331 end_screen(msg
, exit_val
);
3332 dprint((7, "goodnight_gracey: end_titlebar\n"));
3334 dprint((7, "goodnight_gracey: end_keymenu\n"));
3337 dprint((7, "goodnight_gracey: end_keyboard\n"));
3338 end_keyboard(F_ON(F_USE_FK
,pine_state
));
3339 dprint((7, "goodnight_gracey: end_ttydriver\n"));
3340 end_tty_driver(pine_state
);
3341 #if !defined(DOS) && !defined(OS2)
3343 #if !defined(LEAVEOUTFIFO)
3344 close_newmailfifo();
3348 if(filter_data_file(0))
3349 our_unlink(filter_data_file(0));
3351 imap_flush_passwd_cache(TRUE
);
3352 free_newsgrp_cache();
3354 close_every_pattern();
3356 free_contexts(&ps_global
->context_list
);
3357 free_charsetchecker();
3358 dprint((7, "goodnight_gracey: free more memory\n"));
3360 free_saved_query_parameters();
3363 free_pine_struct(&pine_state
);
3367 free_alpine_module_globals(); /* should we have module globals? */
3368 free_pith_module_globals();
3369 free_pico_module_globals();
3370 free_c_client_module_globals();
3375 fputs("goodnight_gracey finished\n", debugfile
);
3385 /*----------------------------------------------------------------------
3386 Call back for c-client to feed us back the progress of network reads
3393 pine_read_progress(GETS_DATA
*md
, long unsigned int count
)
3395 gets_bytes
+= count
; /* update counter */
3399 /*----------------------------------------------------------------------
3400 Function to fish the current byte count from a c-client fetch.
3402 Input: reset -- flag telling us to reset the count
3404 Result: Returns the number of bytes read by the c-client so far
3407 pine_gets_bytes(int reset
)
3416 /*----------------------------------------------------------------------
3417 Panic pine - call on detected programmatic errors to exit pine
3419 Args: message -- message to record in debug file and to be printed for user
3421 Result: The various tty modes are restored
3422 If debugging is active a core dump will be generated
3425 This is also called from imap routines and fs_get and fs_resize.
3428 alpine_panic(char *message
)
3432 /* global variable in .../pico/edef.h */
3435 if(ps_global
->ttyo
){
3436 end_screen(NULL
, -1);
3437 end_keyboard(ps_global
!= NULL
? F_ON(F_USE_FK
,ps_global
) : 0);
3438 end_tty_driver(ps_global
);
3441 if(filter_data_file(0))
3442 our_unlink(filter_data_file(0));
3444 dprint((1, "\n===========================================\n\n"));
3445 dprint((1, " Alpine Panic: %s\n\n", message
? message
: "?"));
3446 dprint((1, "===========================================\n\n"));
3448 /* intercept c-client "free storage" errors */
3449 if(strstr(message
, "free storage"))
3450 snprintf(buf
, sizeof(buf
), _("No more available memory.\nAlpine Exiting"));
3452 snprintf(buf
, sizeof(buf
), _("Problem detected: \"%s\".\nAlpine Exiting."), message
);
3454 buf
[sizeof(buf
)-1] = '\0';
3457 /* Put up a message box. */
3458 mswin_messagebox (buf
, 1);
3460 fprintf(stderr
, "\n\n%s\n", buf
);
3465 save_debug_on_crash(debugfile
, recent_keystroke
);
3468 coredump(); /*--- If we're debugging get a core dump --*/
3472 fatal("ffo"); /* BUG -- hack to get fatal out of library in right order*/
3477 * panicking - function to test whether or not we're exiting under stress.
3487 /*----------------------------------------------------------------------
3488 exceptional_exit - called to exit under unusual conditions (with no core)
3490 Args: message -- message to record in debug file and to be printed for user
3495 exceptional_exit(char *message
, int ev
)
3497 fprintf(stderr
, "%s\n", message
);
3503 * PicoText Storage Object Support Routines
3509 return((STORE_S
*)pico_get());
3513 pine_pico_give(STORE_S
**sop
)
3515 pico_give((void *)sop
);
3520 pine_pico_writec(int c
, STORE_S
*so
)
3522 unsigned char ch
= (unsigned char) c
;
3524 return(pico_writec(so
->txt
, ch
, PICOREADC_NONE
));
3528 pine_pico_writec_noucs(int c
, STORE_S
*so
)
3530 unsigned char ch
= (unsigned char) c
;
3532 return(pico_writec(so
->txt
, ch
, PICOREADC_NOUCS
));
3536 pine_pico_readc(unsigned char *c
, STORE_S
*so
)
3538 return(pico_readc(so
->txt
, c
, PICOREADC_NONE
));
3542 pine_pico_readc_noucs(unsigned char *c
, STORE_S
*so
)
3544 return(pico_readc(so
->txt
, c
, PICOREADC_NOUCS
));
3548 pine_pico_puts(STORE_S
*so
, char *s
)
3550 return(pico_puts(so
->txt
, s
, PICOREADC_NONE
));
3554 pine_pico_puts_noucs(STORE_S
*so
, char *s
)
3556 return(pico_puts(so
->txt
, s
, PICOREADC_NOUCS
));
3560 pine_pico_seek(STORE_S
*so
, long pos
, int orig
)
3562 return(pico_seek((void *)so
, pos
, orig
));
3567 remote_pinerc_failure(void)
3570 if(ps_global
->install_flag
) /* just exit silently */
3572 #endif /* _WINDOWS */
3574 if(ps_global
->exit_if_no_pinerc
){
3575 exceptional_exit("Exiting because -bail option is set and config file not readable.", -1);
3578 if(want_to("Trouble reading remote configuration! Continue anyway ",
3579 'n', 'n', NO_HELP
, WT_FLUSH_IN
) != 'y'){
3588 dump_supported_options(void)
3592 config
= get_supported_options();
3594 display_args_err(NULL
, config
, 0);
3595 free_list_array(&config
);
3600 /*----------------------------------------------------------------------
3601 Check pruned-folders for validity, making sure they are in the
3602 same context as sent-mail.
3606 prune_folders_ok(void)
3610 for(p
= ps_global
->VAR_PRUNED_FOLDERS
; p
&& *p
&& **p
; p
++)
3611 if(!context_isambig(*p
))
3618 free_alpine_module_globals(void)
3620 #ifdef LOCAL_PASSWD_CACHE
3621 free_passfile_cache();
3623 free_message_queue();
3624 free_titlebar_globals();
3629 pine_user_callback()
3631 if(ps_global
->VAR_USER_ID
&& ps_global
->VAR_USER_ID
[0]){
3632 return(ps_global
->VAR_USER_ID
);
3635 /* SHOULD PROMPT HERE! */
3643 * windows callback to get/set function keys mode state
3646 fkey_mode_callback(set
, args
)
3650 return(F_ON(F_USE_FK
, ps_global
) != 0);
3657 if(ps_global
->mail_stream
)
3658 mail_debug(ps_global
->mail_stream
);
3663 imap_telemetry_off()
3665 if(ps_global
->mail_stream
)
3666 mail_nodebug(ps_global
->mail_stream
);
3671 pcpine_help_main(title
)
3675 strncpy(title
, _("PC-Alpine MAIN MENU Help"), 256);
3677 return(pcpine_help(main_menu_tx
));
3682 pcpine_main_cursor(col
, row
)
3688 if (row
>= (HEADER_ROWS(ps_global
) + MNSKIP(ps_global
)))
3689 ndmi
= (row
+1 - HEADER_ROWS(ps_global
) - (MNSKIP(ps_global
)+1))/(MNSKIP(ps_global
)+1);
3691 if (row
>= (HEADER_ROWS(ps_global
) + MNSKIP(ps_global
))
3692 && !(MNSKIP(ps_global
) && (row
+1) & 0x01)
3693 && ndmi
<= MAX_MENU_ITEM
3694 && FOOTER_ROWS(ps_global
) + (ndmi
+1)*(MNSKIP(ps_global
)+1)
3695 + MNSKIP(ps_global
) + FOOTER_ROWS(ps_global
) <= ps_global
->ttyo
->screen_rows
)
3696 return(MSWIN_CURSOR_HAND
);
3698 return(MSWIN_CURSOR_ARROW
);
3700 #endif /* _WINDOWS */