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-2017 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"
28 #include "osdep/debuging.h"
29 #include "osdep/termout.gen.h"
30 #include "osdep/chnge_pw.h"
60 #include "colorconf.h"
66 #include "../pico/osdep/raw.h" /* for STD*_FD */
70 #define PIPED_FD 5 /* Some innocuous desc */
73 /* look for my_timer_period in pico directory for an explanation */
74 int my_timer_period
= ((IDLE_TIMEOUT
+ 1)*1000);
76 /* byte count used by our gets routine to keep track */
77 static unsigned long gets_bytes
;
83 void convert_args_to_utf8(struct pine
*, ARGDATA_S
*);
84 void preopen_stayopen_folders(void);
85 int read_stdin_char(char *);
86 void main_redrawer(void);
87 void show_main_screen(struct pine
*, int, OtherMenu
, struct key_menu
*, int, Pos
*);
88 void do_menu(int, Pos
*, struct key_menu
*);
89 int choose_setup_cmd(int, MSGNO_S
*, SCROLL_S
*);
90 int setup_menu(struct pine
*);
91 void do_setup_task(int);
92 void queue_init_errors(struct pine
*);
93 void process_init_cmds(struct pine
*, char **);
94 void goodnight_gracey(struct pine
*, int);
95 void pine_read_progress(GETS_DATA
*, unsigned long);
96 int remote_pinerc_failure(void);
97 void dump_supported_options(void);
98 int prune_folders_ok(void);
100 char *pine_user_callback(void);
103 int fkey_mode_callback(int, long);
104 void imap_telemetry_on(void);
105 void imap_telemetry_off(void);
106 char *pcpine_help_main(char *);
107 int pcpine_main_cursor(int, long);
108 #define main app_main
112 typedef struct setup_return_val
{
119 * strlen of longest label from keymenu, of labels corresponding to
120 * commands in the middle of the screen. 9 is length of ListFldrs
122 #define LONGEST_LABEL 9 /* length of longest label from keymenu */
124 #define EDIT_EXCEPTION (0x100)
127 static int in_panic
= 0;
130 /*----------------------------------------------------------------------
131 main routine -- entry point
133 Args: argv, argc -- The command line arguments
136 Initialize pine, parse arguments and so on
138 If there is a user address on the command line go into send mode and exit,
139 otherwise loop executing the various screens in Alpine.
141 NOTE: The Windows port def's this to "app_main"
145 main(int argc
, char **argv
)
150 struct pine
*pine_state
;
151 gf_io_t stdin_getc
= NULL
;
152 char *args_for_debug
= NULL
, *init_pinerc_debugging
= NULL
;
154 /*----------------------------------------------------------------------
155 Set up buffering and some data structures
156 ----------------------------------------------------------------------*/
158 pine_state
= new_pine_struct();
159 pine_state
->id
= fs_get(sizeof(IDLIST
));
160 pine_state
->id
->name
= cpystr("name");
161 pine_state
->id
->value
= cpystr(PACKAGE_NAME
);
162 pine_state
->id
->next
= fs_get(sizeof(IDLIST
));
163 pine_state
->id
->next
->name
= cpystr("version");
164 pine_state
->id
->next
->value
= cpystr(PACKAGE_VERSION
);
165 pine_state
->id
->next
->next
= NULL
;
166 mail_parameters(NULL
, SET_IDPARAMS
, (void *) pine_state
->id
);
167 ps_global
= pine_state
;
170 * fill in optional pith-offered behavior hooks
172 pith_opt_read_msg_prompt
= read_msg_prompt
;
173 pith_opt_paint_index_hline
= paint_index_hline
;
174 pith_opt_rfc2369_editorial
= rfc2369_editorial
;
175 pith_opt_condense_thread_cue
= condensed_thread_cue
;
176 pith_opt_truncate_sfstr
= truncate_subj_and_from_strings
;
177 pith_opt_save_and_restore
= save_and_restore
;
178 pith_opt_newmail_announce
= newmail_status_message
;
179 pith_opt_newmail_check_cue
= newmail_check_cue
;
180 pith_opt_checkpoint_cue
= newmail_check_point_cue
;
181 pith_opt_icon_text
= icon_text
;
182 pith_opt_rd_metadata_name
= rd_metadata_name
;
183 pith_opt_remote_pinerc_failure
= remote_pinerc_failure
;
184 pith_opt_reopen_folder
= ask_mailbox_reopen
;
185 pith_opt_expunge_prompt
= expunge_prompt
;
186 pith_opt_begin_closing
= expunge_and_close_begins
;
187 pith_opt_replyto_prompt
= reply_using_replyto_query
;
188 pith_opt_reply_to_all_prompt
= reply_to_all_query
;
189 pith_opt_save_create_prompt
= create_for_save_prompt
;
190 pith_opt_daemon_confirm
= confirm_daemon_send
;
191 pith_opt_save_size_changed_prompt
= save_size_changed_prompt
;
192 pith_opt_save_index_state
= setup_index_state
;
193 pith_opt_filter_pattern_cmd
= pattern_filter_command
;
194 pith_opt_get_signature_file
= get_signature_file
;
195 pith_opt_pretty_var_name
= pretty_var_name
;
196 pith_opt_pretty_feature_name
= pretty_feature_name
;
197 pith_opt_closing_stream
= titlebar_stream_closing
;
198 pith_opt_current_expunged
= mm_expunged_current
;
200 pith_opt_smime_get_passphrase
= smime_get_passphrase
;
201 pith_smime_import_certificate
= smime_import_certificate
;
202 pith_smime_enter_password
= alpine_get_password
;
203 pith_smime_confirm_save
= alpine_smime_confirm_save
;
206 pith_opt_save_ldap_entry
= save_ldap_entry
;
209 status_message_lock_init();
214 * Seed the random number generator with the date & pid. Random
215 * numbers are used for new mail notification and bug report id's
217 srandom(getpid() + time(0));
220 /* need home directory early */
221 get_user_info(&ps_global
->ui
);
223 if(!(pine_state
->home_dir
= our_getenv("HOME")))
224 pine_state
->home_dir
= cpystr(ps_global
->ui
.homedir
);
230 /* normalize path delimiters */
231 for(p
= pine_state
->home_dir
; p
= strchr(p
, '/'); p
++)
234 #endif /* _WINDOWS */
240 char *no_args
= " <no args>";
242 for(i
= 0; i
< argc
; i
++)
243 len
+= (strlen(argv
[i
] ? argv
[i
] : "")+3);
246 len
+= strlen(no_args
);
248 p
= args_for_debug
= (char *)fs_get((len
+2) * sizeof(char));
252 for(i
= 0; i
< argc
; i
++){
253 snprintf(p
, len
+2-(p
-args_for_debug
), "%s\"%s\"", i
? " " : "", argv
[i
] ? argv
[i
] : "");
254 args_for_debug
[len
+2-1] = '\0';
259 strncat(args_for_debug
, no_args
, len
+2-strlen(args_for_debug
)-1);
260 args_for_debug
[len
+2-1] = '\0';
265 /*----------------------------------------------------------------------
266 Parse arguments and initialize debugging
267 ----------------------------------------------------------------------*/
268 pine_args(pine_state
, argc
, argv
, &args
);
273 * monkey with descriptors so our normal tty i/o routines don't
276 dup2(STDIN_FD
, PIPED_FD
); /* redirected stdin to new desc */
277 dup2(STDERR_FD
, STDIN_FD
); /* rebind stdin to the tty */
278 stdin_getc
= read_stdin_char
;
279 if(stdin_getc
&& args
.action
== aaURL
){
281 "Cannot read stdin when using -url\nFor mailto URLs, use \'body=\' instead",
290 * We now have enough information to do some of the basic registry settings.
292 if(ps_global
->update_registry
!= UREG_NEVER_SET
){
293 mswin_reg(MSWR_OP_SET
294 | ((ps_global
->update_registry
== UREG_ALWAYS_SET
)
295 ? MSWR_OP_FORCE
: 0),
296 MSWR_PINE_DIR
, ps_global
->pine_dir
, (size_t)NULL
);
297 mswin_reg(MSWR_OP_SET
298 | ((ps_global
->update_registry
== UREG_ALWAYS_SET
)
299 ? MSWR_OP_FORCE
: 0),
300 MSWR_PINE_EXE
, ps_global
->pine_name
, (size_t)NULL
);
303 #endif /* _WINDOWS */
305 if(ps_global
->convert_sigs
&&
306 (!ps_global
->pinerc
|| !ps_global
->pinerc
[0])){
307 fprintf(stderr
, "Use -p <pinerc> with -convert_sigs\n");
311 /* Windows has its own functions to determine width of a character
312 * in the screen, so this is not necessary to do in Window, and
313 * using pith_ucs4width does not produce the correct result
316 mail_parameters(NULL
, SET_UCS4WIDTH
, (void *) pith_ucs4width
);
317 #endif /* _WINDOWS */
318 mail_parameters(NULL
, SET_QUOTA
, (void *) pine_parse_quota
);
319 /* set some default timeouts in case pinerc is remote */
320 mail_parameters(NULL
, SET_OPENTIMEOUT
, (void *)(long)30);
321 mail_parameters(NULL
, SET_READTIMEOUT
, (void *)(long)15);
322 mail_parameters(NULL
, SET_TIMEOUT
, (void *) pine_tcptimeout
);
323 /* could be TO_BAIL_THRESHOLD, 15 seems more appropriate for now */
324 pine_state
->tcp_query_timeout
= 15;
326 mail_parameters(NULL
, SET_SENDCOMMAND
, (void *) pine_imap_cmd_happened
);
327 mail_parameters(NULL
, SET_FREESTREAMSPAREP
, (void *) sp_free_callback
);
328 mail_parameters(NULL
, SET_FREEELTSPAREP
, (void *) free_pine_elt
);
330 mail_parameters(NULL
, SET_FREEBODYSPAREP
, (void *) free_smime_body_sparep
);
333 init_pinerc(pine_state
, &init_pinerc_debugging
);
336 /* Since this is specific debugging we don't mind if the
337 ifdef is the type of system.
339 #if defined(HAVE_SMALLOC) || defined(NXT)
340 if(ps_global
->debug_malloc
)
341 malloc_debug(ps_global
->debug_malloc
);
344 if(ps_global
->debug_malloc
)
345 mal_debug(ps_global
->debug_malloc
);
348 if(!ps_global
->convert_sigs
350 && !ps_global
->install_flag
351 #endif /* _WINDOWS */
356 dprint((0, " %s (PID=%ld)\n\n", args_for_debug
,
358 fs_give((void **)&args_for_debug
);
363 if((env_to_free
= our_getenv("HOME")) != NULL
){
364 dprint((2, "Setting home dir from $HOME: \"%s\"\n",
366 fs_give((void **)&env_to_free
);
369 dprint((2, "Setting home dir: \"%s\"\n",
370 pine_state
->home_dir
? pine_state
->home_dir
: "<?>"));
374 /* Watch out. Sensitive information in debug file. */
375 if(ps_global
->debug_imap
> 4)
376 mail_parameters(NULL
, SET_DEBUGSENSITIVE
, (void *) TRUE
);
379 if(ps_global
->debug_tcp
)
381 mail_parameters(NULL
, SET_TCPDEBUG
, (void *) TRUE
);
384 mswin_setdebug(debug
, debugfile
);
385 mswin_setdebugoncallback (imap_telemetry_on
);
386 mswin_setdebugoffcallback (imap_telemetry_off
);
387 mswin_enableimaptelemetry(ps_global
->debug_imap
!= 0);
392 mswin_setsortcallback(index_sort_callback
);
393 mswin_setflagcallback(flag_callback
);
394 mswin_sethdrmodecallback(header_mode_callback
);
395 mswin_setselectedcallback(any_selected_callback
);
396 mswin_setzoomodecallback(zoom_mode_callback
);
397 mswin_setfkeymodecallback(fkey_mode_callback
);
400 /*------- Set up c-client drivers -------*/
401 #include "../c-client/linkage.c"
403 /*------- ... then tune the drivers just installed -------*/
405 if(_tgetenv(TEXT("HOME")))
406 mail_parameters(NULL
, SET_HOMEDIR
, (void *) pine_state
->home_dir
);
408 mail_parameters(NULL
, SET_USERPROMPT
, (void *) pine_user_callback
);
411 * Sniff the environment for timezone offset. We need to do this
412 * here since Windows needs help figuring out UTC, and will adjust
413 * what time() returns based on TZ. THIS WILL SCREW US because
414 * we use time() differences to manage status messages. So, if
415 * rfc822_date, which calls localtime() and thus needs tzset(),
416 * is called while a status message is displayed, it's possible
417 * for time() to return a time *before* what we remember as the
418 * time we put the status message on the display. Sheesh.
421 #else /* !_WINDOWS */
423 * We used to let c-client do this for us automatically, but it declines
424 * to do so for root. This forces c-client to establish an environment,
425 * even if the uid is 0.
427 env_init(ps_global
->ui
.login
, ps_global
->ui
.homedir
);
430 * Install callback to let us know the progress of network reads...
432 (void) mail_parameters(NULL
, SET_READPROGRESS
, (void *)pine_read_progress
);
433 #endif /* !_WINDOWS */
436 * Install callback to handle certificate validation failures,
437 * allowing the user to continue if they wish.
439 mail_parameters(NULL
, SET_SSLCERTIFICATEQUERY
, (void *) pine_sslcertquery
);
440 mail_parameters(NULL
, SET_SSLFAILURE
, (void *) pine_sslfailure
);
442 if(init_pinerc_debugging
){
443 dprint((2, init_pinerc_debugging
));
444 fs_give((void **)&init_pinerc_debugging
);
448 * Initial allocation of array of stream pool pointers.
449 * We do this before init_vars so that we can re-use streams used for
450 * remote config files. These sizes may get changed later.
452 ps_global
->s_pool
.max_remstream
= 2;
454 "Setting initial max_remstream to %d for remote config re-use\n",
455 ps_global
->s_pool
.max_remstream
));
457 init_vars(pine_state
, process_init_cmds
);
460 if(F_ON(F_DONT_DO_SMIME
, ps_global
))
466 * LC_CTYPE is already set from the set_collation call above.
468 * We can't use gettext calls before we do this stuff so it doesn't
469 * help to translate strings that come before this in the program.
470 * Maybe we could rearrange things to accomodate that.
472 setlocale(LC_MESSAGES
, "");
473 bindtextdomain(PACKAGE
, LOCALEDIR
);
474 bind_textdomain_codeset(PACKAGE
, "UTF-8");
476 #endif /* ENABLE_NLS */
478 convert_args_to_utf8(pine_state
, &args
);
480 if(args
.action
== aaFolder
){
481 pine_state
->beginning_of_month
= first_run_of_month();
482 pine_state
->beginning_of_year
= first_run_of_year();
485 /* Set up optional for user-defined display filtering */
486 pine_state
->tools
.display_filter
= dfilter
;
487 pine_state
->tools
.display_filter_trigger
= dfilter_trigger
;
490 if(ps_global
->install_flag
){
491 init_install_get_vars();
494 free_pinerc_s(&ps_global
->prc
);
500 if(ps_global
->convert_sigs
){
501 if(convert_sigs_to_literal(ps_global
, 0) == -1){
502 /* TRANSLATORS: sigs refers to signatures, which the user was trying to convert */
503 fprintf(stderr
, _("trouble converting sigs\n"));
508 if(ps_global
->prc
->outstanding_pinerc_changes
)
509 write_pinerc(ps_global
, Main
, WRP_NONE
);
511 free_pinerc_s(&pine_state
->prc
);
518 * Set up a c-client read timeout and timeout handler. In general,
519 * it shouldn't happen, but a server crash or dead link can cause
520 * pine to appear wedged if we don't set this up...
523 if(pine_state
->VAR_TCPOPENTIMEO
)
524 (void)SVAR_TCP_OPEN(pine_state
, rv
, tmp_20k_buf
, SIZEOF_20KBUF
);
525 mail_parameters(NULL
, SET_OPENTIMEOUT
, (void *)(long)rv
);
528 if(pine_state
->VAR_TCPREADWARNTIMEO
)
529 (void)SVAR_TCP_READWARN(pine_state
, rv
, tmp_20k_buf
, SIZEOF_20KBUF
);
530 mail_parameters(NULL
, SET_READTIMEOUT
, (void *)(long)rv
);
533 if(pine_state
->VAR_TCPWRITEWARNTIMEO
){
534 if(!SVAR_TCP_WRITEWARN(pine_state
, rv
, tmp_20k_buf
, SIZEOF_20KBUF
))
535 if(rv
== 0 || rv
> 4) /* making sure */
536 mail_parameters(NULL
, SET_WRITETIMEOUT
, (void *)(long)rv
);
539 mail_parameters(NULL
, SET_TIMEOUT
, (void *) pine_tcptimeout
);
542 if(pine_state
->VAR_RSHOPENTIMEO
){
543 if(!SVAR_RSH_OPEN(pine_state
, rv
, tmp_20k_buf
, SIZEOF_20KBUF
))
544 if(rv
== 0 || rv
> 4) /* making sure */
545 mail_parameters(NULL
, SET_RSHTIMEOUT
, (void *)(long)rv
);
549 if(pine_state
->VAR_SSHOPENTIMEO
){
550 if(!SVAR_SSH_OPEN(pine_state
, rv
, tmp_20k_buf
, SIZEOF_20KBUF
))
551 if(rv
== 0 || rv
> 4) /* making sure */
552 mail_parameters(NULL
, SET_SSHTIMEOUT
, (void *)(long)rv
);
556 if(pine_state
->VAR_MAILDROPCHECK
){
557 if(!SVAR_MAILDCHK(pine_state
, rvl
, tmp_20k_buf
, SIZEOF_20KBUF
)){
559 rvl
= (60L * 60L * 24L * 100L); /* 100 days */
561 if(rvl
>= 60L) /* making sure */
562 mail_parameters(NULL
, SET_SNARFINTERVAL
, (void *) rvl
);
567 * Lookups of long login names which don't exist are very slow in aix.
568 * This would normally get set in system-wide config if not needed.
570 if(F_ON(F_DISABLE_SHARED_NAMESPACES
, ps_global
))
571 mail_parameters(NULL
, SET_DISABLEAUTOSHAREDNS
, (void *) TRUE
);
573 if(F_ON(F_HIDE_NNTP_PATH
, ps_global
))
574 mail_parameters(NULL
, SET_NNTPHIDEPATH
, (void *) TRUE
);
576 if(F_ON(F_MAILDROPS_PRESERVE_STATE
, ps_global
))
577 mail_parameters(NULL
, SET_SNARFPRESERVE
, (void *) TRUE
);
580 if(pine_state
->VAR_NNTPRANGE
){
581 if(!SVAR_NNTPRANGE(pine_state
, rvl
, tmp_20k_buf
, SIZEOF_20KBUF
))
583 mail_parameters(NULL
, SET_NNTPRANGE
, (void *) rvl
);
587 * Tell c-client not to be so aggressive about uid mappings
589 mail_parameters(NULL
, SET_UIDLOOKAHEAD
, (void *) 20);
592 * Setup referral handling
594 mail_parameters(NULL
, SET_IMAPREFERRAL
, (void *) imap_referral
);
595 mail_parameters(NULL
, SET_MAILPROXYCOPY
, (void *) imap_proxycopy
);
598 * Setup multiple newsrc transition
600 mail_parameters(NULL
, SET_NEWSRCQUERY
, (void *) pine_newsrcquery
);
603 * Disable some drivers if requested.
605 if(ps_global
->VAR_DISABLE_DRIVERS
&&
606 ps_global
->VAR_DISABLE_DRIVERS
[0] &&
607 ps_global
->VAR_DISABLE_DRIVERS
[0][0]){
610 for(t
= ps_global
->VAR_DISABLE_DRIVERS
; t
[0] && t
[0][0]; t
++)
611 if(mail_parameters(NULL
, DISABLE_DRIVER
, (void *)(*t
))){
612 dprint((2, "Disabled mail driver \"%s\"\n", *t
));
615 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
616 _("Failed to disable mail driver \"%s\": name not found"),
618 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
619 init_error(ps_global
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
624 * Disable some authenticators if requested.
626 if(ps_global
->VAR_DISABLE_AUTHS
&&
627 ps_global
->VAR_DISABLE_AUTHS
[0] &&
628 ps_global
->VAR_DISABLE_AUTHS
[0][0]){
631 for(t
= ps_global
->VAR_DISABLE_AUTHS
; t
[0] && t
[0][0]; t
++)
632 if(mail_parameters(NULL
, DISABLE_AUTHENTICATOR
, (void *)(*t
))){
633 dprint((2,"Disabled SASL authenticator \"%s\"\n", *t
));
636 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
637 _("Failed to disable SASL authenticator \"%s\": name not found"),
639 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
640 init_error(ps_global
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
645 * setup alternative authentication driver preference for IMAP opens
647 if(F_ON(F_PREFER_ALT_AUTH
, ps_global
))
648 mail_parameters(NULL
, SET_IMAPTRYALT
, (void *) TRUE
);
651 * Install handler to let us know about potential delays
653 (void) mail_parameters(NULL
, SET_BLOCKNOTIFY
, (void *) pine_block_notify
);
655 if(ps_global
->dump_supported_options
){
656 dump_supported_options();
661 * Install extra headers to fetch along with all the other stuff
662 * mail_fetch_structure and mail_fetch_overview requests.
666 (void) mail_parameters(NULL
, SET_IMAPEXTRAHEADERS
,
667 (void *) get_extra_hdrs());
669 if(init_username(pine_state
) < 0){
670 fprintf(stderr
, _("Who are you? (Unable to look up login name)\n"));
674 if(init_userdir(pine_state
) < 0)
677 if(init_hostname(pine_state
) < 0)
681 * Verify mail dir if we're not in send only mode...
683 if(args
.action
== aaFolder
&& init_mail_dir(pine_state
) < 0)
688 /*--- input side ---*/
689 if(init_tty_driver(pine_state
)){
690 #ifndef _WINDOWS /* always succeeds under _WINDOWS */
691 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
);
693 #endif /* !_WINDOWS */
697 /*--- output side ---*/
698 rv
= config_screen(&(pine_state
->ttyo
));
699 #ifndef _WINDOWS /* always succeeds under _WINDOWS */
703 printf(_("Terminal type (environment variable TERM) not set.\n"));
706 printf(_("Terminal type \"%s\" is unknown.\n"), getenv("TERM"));
709 printf(_("Can't open terminal capabilities database.\n"));
712 printf(_("Your terminal, of type \"%s\", is lacking functions needed to run alpine.\n"), getenv("TERM"));
717 end_tty_driver(pine_state
);
720 #endif /* !_WINDOWS */
722 if(F_ON(F_BLANK_KEYMENU
,ps_global
))
723 FOOTER_ROWS(ps_global
) = 1;
726 init_keyboard(pine_state
->orig_use_fkeys
);
727 strncpy(pine_state
->inbox_name
, INBOX_NAME
,
728 sizeof(pine_state
->inbox_name
)-1);
729 init_folders(pine_state
); /* digest folder spec's */
731 pine_state
->in_init_seq
= 0; /* so output (& ClearScreen) show up */
732 pine_state
->dont_use_init_cmds
= 1; /* don't use up initial_commands yet */
735 /* initialize titlebar in case we use it */
736 set_titlebar("", NULL
, NULL
, NULL
, NULL
, 0, FolderName
, 0, 0, NULL
);
739 * Prep storage object driver for PicoText
741 so_register_external_driver(pine_pico_get
, pine_pico_give
, pine_pico_writec
, pine_pico_readc
,
742 pine_pico_puts
, pine_pico_seek
, NULL
, NULL
);
745 if(ps_global
->debug_imap
> 4 || debug
> 9){
746 q_status_message(SM_ORDER
| SM_DING
, 5, 9,
747 _("Warning: sensitive authentication data included in debug file"));
748 flush_status_messages(0);
752 if(args
.action
== aaPrcCopy
|| args
.action
== aaAbookCopy
){
754 char *err_msg
= NULL
;
757 * Don't translate these into UTF-8 because we'll be using them
758 * before we translate next time. User should use ascii.
760 if(args
.data
.copy
.local
&& args
.data
.copy
.remote
){
763 exit_val
= copy_pinerc(args
.data
.copy
.local
,
764 args
.data
.copy
.remote
, &err_msg
);
768 exit_val
= copy_abook(args
.data
.copy
.local
,
769 args
.data
.copy
.remote
, &err_msg
);
777 q_status_message(SM_ORDER
| SM_DING
, 3, 4, err_msg
);
778 fs_give((void **)&err_msg
);
780 goodnight_gracey(pine_state
, exit_val
);
783 if(args
.action
== aaFolder
784 && (pine_state
->first_time_user
|| pine_state
->show_new_version
)){
785 pine_state
->mangled_header
= 1;
786 show_main_screen(pine_state
, 0, FirstMenu
, &main_keymenu
, 0,
788 new_user_or_version(pine_state
);
792 /* put back in case we need to suppress output */
793 pine_state
->in_init_seq
= pine_state
->save_in_init_seq
;
795 /* queue any init errors so they get displayed in a screen below */
796 queue_init_errors(ps_global
);
798 /* "Page" the given file? */
799 if(args
.action
== aaMore
){
800 int dice
= 1, redir
= 0;
802 if(pine_state
->in_init_seq
){
803 pine_state
->in_init_seq
= pine_state
->save_in_init_seq
= 0;
805 if(pine_state
->free_initial_cmds
)
806 fs_give((void **)&(pine_state
->free_initial_cmds
));
808 pine_state
->initial_cmds
= NULL
;
811 /*======= Requested that we simply page the given file =======*/
812 if(args
.data
.file
){ /* Open the requested file... */
814 STORE_S
*store
= NULL
;
815 char *decode_error
= NULL
;
816 char filename
[MAILTMPLEN
];
818 if(args
.data
.file
[0] == '\0'){
819 HelpType help
= NO_HELP
;
821 pine_state
->mangled_footer
= 1;
824 int flags
= OE_APPEND_CURRENT
;
826 rv
= optionally_enter(filename
, -FOOTER_ROWS(pine_state
),
828 /* TRANSLATORS: file is computer data */
829 _("File to open : "),
832 help
= (help
== NO_HELP
) ? h_no_F_arg
: NO_HELP
;
841 q_status_message(SM_ORDER
, 0, 2, _("Cancelled"));
842 goodnight_gracey(pine_state
, -1);
846 removing_trailing_white_space(filename
);
847 removing_leading_white_space(filename
);
848 if(is_absolute_path(filename
))
849 fnexpand(filename
, sizeof(filename
));
851 args
.data
.file
= filename
;
855 /* TRANSLATORS: file is computer data */
856 q_status_message(SM_ORDER
, 0, 2 ,_("No file to open"));
857 goodnight_gracey(pine_state
, -1);
864 if(isatty(0) && (store
= so_get(src
, NULL
, EDIT_ACCESS
))){
867 gf_set_so_writec(&pc
, store
);
869 if((decode_error
= gf_pipe(stdin_getc
, pc
)) != NULL
){
871 q_status_message1(SM_ORDER
, 3, 4,
872 _("Problem reading standard input: %s"),
876 gf_clear_so_writec(store
);
883 strncpy(ps_global
->cur_folder
, args
.data
.file
,
884 sizeof(ps_global
->cur_folder
)-1);
885 ps_global
->cur_folder
[sizeof(ps_global
->cur_folder
)-1] = '\0';
886 if(!(store
= so_get(src
, args
.data
.file
, READ_ACCESS
|READ_FROM_LOCALE
)))
893 memset(&sargs
, 0, sizeof(SCROLL_S
));
894 sargs
.text
.text
= so_text(store
);
895 sargs
.text
.src
= src
;
896 /* TRANSLATORS: file is computer file being read by user */
897 sargs
.text
.desc
= _("file");
898 /* TRANSLATORS: this is in the title bar at top of screen */
899 sargs
.bar
.title
= _("FILE VIEW");
900 sargs
.bar
.style
= FileTextPercent
;
901 sargs
.keys
.menu
= &simple_file_keymenu
;
902 setbitmap(sargs
.keys
.bitmap
);
911 q_status_message2(SM_ORDER
, 3, 4,
912 _("Can't display \"%s\": %s"),
913 (redir
) ? _("Standard Input")
914 : args
.data
.file
? args
.data
.file
: "NULL",
915 error_description(errno
));
918 goodnight_gracey(pine_state
, 0);
920 else if(args
.action
== aaMail
|| (stdin_getc
&& (args
.action
!= aaURL
))){
921 /*======= address on command line/send one message mode ============*/
922 char *to
= NULL
, *error
= NULL
, *addr
= NULL
;
923 int len
, good_addr
= 1;
927 if(pine_state
->in_init_seq
){
928 pine_state
->in_init_seq
= pine_state
->save_in_init_seq
= 0;
930 if(pine_state
->free_initial_cmds
)
931 fs_give((void **) &(pine_state
->free_initial_cmds
));
933 pine_state
->initial_cmds
= NULL
;
936 /*----- Format the To: line with commas for the composer ---*/
937 if(args
.data
.mail
.addrlist
){
940 for(p
= args
.data
.mail
.addrlist
, len
= 0; p
; p
= p
->next
)
941 len
+= strlen(p
->name
) + 2;
943 to
= (char *) fs_get((len
+ 5) * sizeof(char));
944 for(p
= args
.data
.mail
.addrlist
, *to
= '\0'; p
; p
= p
->next
){
946 strncat(to
, ", ", len
+5-strlen(to
)-1);
950 strncat(to
, p
->name
, len
+5-strlen(to
)-1);
954 memset((void *)&fcc
, 0, sizeof(BUILDER_ARG
));
955 dprint((2, "building addr: -->%s<--\n", to
? to
: "?"));
956 good_addr
= (build_address(to
, &addr
, &error
, &fcc
, NULL
) >= 0);
957 dprint((2, "mailing to: -->%s<--\n", addr
? addr
: "?"));
958 free_strlist(&args
.data
.mail
.addrlist
);
961 memset(&fcc
, 0, sizeof(fcc
));
964 compose_mail(addr
, fcc
.tptr
, NULL
,
965 args
.data
.mail
.attachlist
, stdin_getc
);
968 /* TRANSLATORS: refers to bad email address */
969 q_status_message1(SM_ORDER
, 3, 4, _("Bad address: %s"), error
);
974 fs_give((void **) &addr
);
977 fs_give((void **) &fcc
.tptr
);
979 if(args
.data
.mail
.attachlist
)
980 free_attachment_list(&args
.data
.mail
.attachlist
);
983 fs_give((void **) &to
);
986 fs_give((void **) &error
);
988 goodnight_gracey(pine_state
, exit_val
);
991 char int_mail
[MAXPATH
+1];
992 struct key_menu
*km
= &main_keymenu
;
994 /*========== Normal pine mail reading mode ==========*/
996 pine_state
->mail_stream
= NULL
;
997 pine_state
->mangled_screen
= 1;
999 if(args
.action
== aaURL
){
1002 if(pine_state
->in_init_seq
){
1003 pine_state
->in_init_seq
= pine_state
->save_in_init_seq
= 0;
1005 if(pine_state
->free_initial_cmds
)
1006 fs_give((void **) &(pine_state
->free_initial_cmds
));
1007 pine_state
->initial_cmds
= NULL
;
1009 if((f
= url_local_handler(args
.url
)) != NULL
){
1010 if(args
.data
.mail
.attachlist
){
1011 if(f
== url_local_mailto
){
1012 if(!(url_local_mailto_and_atts(args
.url
,
1013 args
.data
.mail
.attachlist
)
1014 && pine_state
->next_screen
))
1015 free_attachment_list(&args
.data
.mail
.attachlist
);
1016 goodnight_gracey(pine_state
, 0);
1019 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
1020 _("Only mailto URLs are allowed with file attachments"));
1021 goodnight_gracey(pine_state
, -1); /* no return */
1024 else if(!((*f
)(args
.url
) && pine_state
->next_screen
))
1025 goodnight_gracey(pine_state
, 0); /* no return */
1028 q_status_message1(SM_ORDER
| SM_DING
, 3, 4,
1029 _("Unrecognized URL \"%s\""), args
.url
);
1030 goodnight_gracey(pine_state
, -1); /* no return */
1033 else if(!pine_state
->start_in_index
){
1034 /* flash message about executing initial commands */
1035 if(pine_state
->in_init_seq
){
1036 pine_state
->in_init_seq
= 0;
1038 pine_state
->mangled_header
= 1;
1039 pine_state
->mangled_footer
= 1;
1040 pine_state
->mangled_screen
= 0;
1041 /* show that this is Alpine */
1042 show_main_screen(pine_state
, 0, FirstMenu
, km
, 0, (Pos
*)NULL
);
1043 pine_state
->mangled_screen
= 1;
1044 pine_state
->painted_footer_on_startup
= 1;
1045 if(MIN(4, pine_state
->ttyo
->screen_rows
- 4) > 1){
1046 char buf1
[6*MAX_SCREEN_COLS
+1];
1047 char buf2
[6*MAX_SCREEN_COLS
+1];
1050 /* TRANSLATORS: Initial Keystroke List is the literal name of an option */
1051 strncpy(buf1
, _("Executing Initial Keystroke List......"), sizeof(buf1
));
1052 buf1
[sizeof(buf1
)-1] = '\0';
1053 wid
= utf8_width(buf1
);
1054 if(wid
> ps_global
->ttyo
->screen_cols
){
1055 utf8_pad_to_width(buf2
, buf1
, sizeof(buf2
), ps_global
->ttyo
->screen_cols
, 1);
1056 PutLine0(MIN(4, pine_state
->ttyo
->screen_rows
- 4), 0, buf2
);
1059 PutLine0(MIN(4, pine_state
->ttyo
->screen_rows
- 4),
1060 MAX(MIN(11, pine_state
->ttyo
->screen_cols
- wid
), 0), buf1
);
1064 pine_state
->in_init_seq
= 1;
1067 show_main_screen(pine_state
, 0, FirstMenu
, km
, 0, (Pos
*)NULL
);
1068 pine_state
->painted_body_on_startup
= 1;
1069 pine_state
->painted_footer_on_startup
= 1;
1073 /* cancel any initial commands, overridden by cmd line */
1074 if(pine_state
->in_init_seq
){
1075 pine_state
->in_init_seq
= 0;
1076 pine_state
->save_in_init_seq
= 0;
1078 if(pine_state
->initial_cmds
){
1079 if(pine_state
->free_initial_cmds
)
1080 fs_give((void **)&(pine_state
->free_initial_cmds
));
1082 pine_state
->initial_cmds
= NULL
;
1085 F_SET(F_USE_FK
,pine_state
, pine_state
->orig_use_fkeys
);
1088 (void) do_index_border(pine_state
->context_current
,
1089 pine_state
->cur_folder
,
1090 pine_state
->mail_stream
,
1091 pine_state
->msgmap
, MsgIndex
, NULL
,
1092 INDX_CLEAR
|INDX_HEADER
|INDX_FOOTER
);
1093 pine_state
->painted_footer_on_startup
= 1;
1094 if(MIN(4, pine_state
->ttyo
->screen_rows
- 4) > 1){
1095 char buf1
[6*MAX_SCREEN_COLS
+1];
1096 char buf2
[6*MAX_SCREEN_COLS
+1];
1099 strncpy(buf1
, _("Please wait, opening mail folder......"), sizeof(buf1
));
1100 buf1
[sizeof(buf1
)-1] = '\0';
1101 wid
= utf8_width(buf1
);
1102 if(wid
> ps_global
->ttyo
->screen_cols
){
1103 utf8_pad_to_width(buf2
, buf1
, sizeof(buf2
), ps_global
->ttyo
->screen_cols
, 1);
1104 PutLine0(MIN(4, pine_state
->ttyo
->screen_rows
- 4), 0, buf2
);
1107 PutLine0(MIN(4, pine_state
->ttyo
->screen_rows
- 4),
1108 MAX(MIN(11, pine_state
->ttyo
->screen_cols
- wid
), 0), buf1
);
1115 #if !defined(_WINDOWS) && !defined(LEAVEOUTFIFO)
1116 if(ps_global
->VAR_FIFOPATH
&& ps_global
->VAR_FIFOPATH
[0])
1117 init_newmailfifo(ps_global
->VAR_FIFOPATH
);
1120 if(pine_state
->in_init_seq
){
1121 pine_state
->in_init_seq
= 0;
1125 if(args
.action
== aaFolder
&& args
.data
.folder
){
1126 CONTEXT_S
*cntxt
= NULL
, *tc
= NULL
;
1127 char foldername
[MAILTMPLEN
];
1128 int notrealinbox
= 0;
1130 if(args
.data
.folder
[0] == '\0'){
1132 unsigned save_def_goto_rule
;
1134 foldername
[0] = '\0';
1135 save_def_goto_rule
= pine_state
->goto_default_rule
;
1136 pine_state
->goto_default_rule
= GOTO_FIRST_CLCTN
;
1137 tc
= default_save_context(pine_state
->context_list
);
1138 fldr
= broach_folder(-FOOTER_ROWS(pine_state
), 1, ¬realinbox
, &tc
);
1139 pine_state
->goto_default_rule
= save_def_goto_rule
;
1141 strncpy(foldername
, fldr
, sizeof(foldername
)-1);
1142 foldername
[sizeof(foldername
)-1] = '\0';
1146 removing_trailing_white_space(foldername
);
1147 removing_leading_white_space(foldername
);
1148 args
.data
.folder
= cpystr(foldername
);
1152 q_status_message(SM_ORDER
, 0, 2 ,_("No folder to open"));
1153 goodnight_gracey(pine_state
, -1);
1159 else if((rv
= pine_state
->init_context
) < 0)
1161 * As with almost all the folder vars in the pinerc,
1162 * we subvert the collection "breakout" here if the
1163 * folder name given looks like an asolute path on
1166 cntxt
= (is_absolute_path(args
.data
.folder
))
1167 ? NULL
: pine_state
->context_current
;
1171 for(cntxt
= pine_state
->context_list
;
1172 rv
> 1 && cntxt
->next
;
1173 rv
--, cntxt
= cntxt
->next
)
1176 if(pine_state
&& pine_state
->ttyo
){
1177 blank_keymenu(pine_state
->ttyo
->screen_rows
- 2, 0);
1178 pine_state
->painted_footer_on_startup
= 0;
1179 pine_state
->mangled_footer
= 1;
1182 if(args
.data
.folder
&& *args
.data
.folder
1183 && !strucmp(args
.data
.folder
, ps_global
->inbox_name
)
1184 && cntxt
!= ps_global
->context_list
)
1187 if(do_broach_folder(args
.data
.folder
, cntxt
, NULL
, notrealinbox
? 0L : DB_INBOXWOCNTXT
) <= 0){
1188 q_status_message1(SM_ORDER
, 3, 4,
1189 _("Unable to open folder \"%s\""), args
.data
.folder
);
1191 goodnight_gracey(pine_state
, -1);
1194 else if(args
.action
== aaFolder
){
1197 * need to ask for the inbox name if no default under DOS
1198 * since there is no "inbox"
1201 if(!pine_state
->VAR_INBOX_PATH
|| !pine_state
->VAR_INBOX_PATH
[0]
1202 || strucmp(pine_state
->VAR_INBOX_PATH
, "inbox") == 0){
1203 HelpType help
= NO_HELP
;
1204 static ESCKEY_S ekey
[] = {{ctrl(T
), 2, "^T", "To Fldrs"},
1205 {-1, 0, NULL
, NULL
}};
1207 pine_state
->mangled_footer
= 1;
1210 int flags
= OE_APPEND_CURRENT
;
1212 rv
= optionally_enter(int_mail
, -FOOTER_ROWS(pine_state
),
1213 0, sizeof(int_mail
),
1214 _("No inbox! Folder to open as inbox : "),
1215 /* ekey */ NULL
, help
, &flags
);
1217 help
= (help
== NO_HELP
) ? h_sticky_inbox
: NO_HELP
;
1226 q_status_message(SM_ORDER
, 0, 2 ,_("Folder open cancelled"));
1227 rv
= 0; /* reset rv */
1230 show_main_screen(pine_state
,0,FirstMenu
,km
,0,(Pos
*)NULL
);
1234 removing_trailing_white_space(int_mail
);
1235 removing_leading_white_space(int_mail
);
1236 if((!pine_state
->VAR_INBOX_PATH
1237 || strucmp(pine_state
->VAR_INBOX_PATH
, "inbox") == 0)
1238 /* TRANSLATORS: Inbox-Path and PINERC are literal, not to be translated */
1239 && want_to(_("Preserve folder as \"Inbox-Path\" in PINERC"),
1240 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
1241 set_variable(V_INBOX_PATH
, int_mail
, 1, 1, Main
);
1244 if(pine_state
->VAR_INBOX_PATH
)
1245 fs_give((void **)&pine_state
->VAR_INBOX_PATH
);
1247 pine_state
->VAR_INBOX_PATH
= cpystr(int_mail
);
1250 if(pine_state
&& pine_state
->ttyo
){
1251 blank_keymenu(pine_state
->ttyo
->screen_rows
- 2, 0);
1252 pine_state
->painted_footer_on_startup
= 0;
1253 pine_state
->mangled_footer
= 1;
1256 do_broach_folder(pine_state
->inbox_name
,
1257 pine_state
->context_list
, NULL
, DB_INBOXWOCNTXT
);
1260 q_status_message(SM_ORDER
, 0, 2 ,_("No folder opened"));
1265 #endif /* _WINDOWS */
1266 if(F_ON(F_PREOPEN_STAYOPENS
, ps_global
))
1267 preopen_stayopen_folders();
1269 if(pine_state
&& pine_state
->ttyo
){
1270 blank_keymenu(pine_state
->ttyo
->screen_rows
- 2, 0);
1271 pine_state
->painted_footer_on_startup
= 0;
1272 pine_state
->mangled_footer
= 1;
1276 do_broach_folder(pine_state
->inbox_name
,
1277 pine_state
->context_list
, NULL
, DB_INBOXWOCNTXT
);
1280 if(pine_state
->mangled_footer
)
1281 pine_state
->painted_footer_on_startup
= 0;
1283 if(args
.action
== aaFolder
1284 && pine_state
->mail_stream
1285 && expire_sent_mail())
1286 pine_state
->painted_footer_on_startup
= 0;
1289 * Initialize the defaults. Initializing here means that
1290 * if they're remote, the user isn't prompted for an imap login
1291 * before the display's drawn, AND there's the chance that
1292 * we can climb onto the already opened folder's stream...
1294 if(ps_global
->first_time_user
)
1295 init_save_defaults(); /* initialize default save folders */
1297 build_path(int_mail
,
1298 ps_global
->VAR_OPER_DIR
? ps_global
->VAR_OPER_DIR
1299 : pine_state
->home_dir
,
1300 INTERRUPTED_MAIL
, sizeof(int_mail
));
1301 if(args
.action
== aaFolder
1302 && (folder_exists(NULL
, int_mail
) & FEX_ISFILE
))
1303 q_status_message(SM_ORDER
| SM_DING
, 4, 5,
1304 _("Use Compose command to continue interrupted message."));
1306 #if defined(USE_QUOTAS)
1310 q
= disk_quota(pine_state
->home_dir
, &over
);
1312 q_status_message2(SM_ASYNC
| SM_DING
, 4, 5,
1313 _("WARNING! Over your disk quota by %s bytes (%s)"),
1314 comatose(q
),byte_string(q
));
1319 pine_state
->in_init_seq
= pine_state
->save_in_init_seq
;
1320 pine_state
->dont_use_init_cmds
= 0;
1323 if(pine_state
->give_fixed_warning
)
1324 q_status_message(SM_ASYNC
, 0, 10,
1325 /* TRANSLATORS: config is an abbreviation for configuration */
1326 _("Note: some of your config options conflict with site policy and are ignored"));
1328 if(!prune_folders_ok())
1329 q_status_message(SM_ASYNC
, 0, 10,
1330 /* TRANSLATORS: Pruned-Folders is literal */
1331 _("Note: ignoring Pruned-Folders outside of default collection for saves"));
1333 if(get_input_timeout() == 0 &&
1334 ps_global
->VAR_INBOX_PATH
&&
1335 ps_global
->VAR_INBOX_PATH
[0] == '{')
1336 q_status_message(SM_ASYNC
, 0, 10,
1337 _("Note: Mail-Check-Interval=0 may cause IMAP server connection to time out"));
1340 mswin_setnewmailwidth(ps_global
->nmw_width
);
1344 /*-------------------------------------------------------------------
1345 Loop executing the commands
1347 This is done like this so that one command screen can cause
1348 another one to execute it with out going through the main menu.
1349 ------------------------------------------------------------------*/
1350 if(!pine_state
->next_screen
)
1351 pine_state
->next_screen
= pine_state
->start_in_index
1352 ? mail_index_screen
: main_menu_screen
;
1354 if(pine_state
->next_screen
== SCREEN_FUN_NULL
)
1355 pine_state
->next_screen
= main_menu_screen
;
1357 (*(pine_state
->next_screen
))(pine_state
);
1366 * The arguments need to be converted to UTF-8 for our internal use.
1367 * Not all arguments are converted because some are used before we
1368 * are able to do the conversion, like the pinerc name.
1371 convert_args_to_utf8(struct pine
*ps
, ARGDATA_S
*args
)
1373 char *fromcharset
= NULL
;
1377 if(ps
->keyboard_charmap
&& strucmp(ps
->keyboard_charmap
, "UTF-8")
1378 && strucmp(ps
->keyboard_charmap
, "US-ASCII"))
1379 fromcharset
= ps
->keyboard_charmap
;
1380 else if(ps
->display_charmap
&& strucmp(ps
->display_charmap
, "UTF-8")
1381 && strucmp(ps
->display_charmap
, "US-ASCII"))
1382 fromcharset
= ps
->display_charmap
;
1384 else if(ps
->VAR_OLD_CHAR_SET
&& strucmp(ps
->VAR_OLD_CHAR_SET
, "UTF-8")
1385 && strucmp(ps
->VAR_OLD_CHAR_SET
, "US-ASCII"))
1386 fromcharset
= ps
->VAR_OLD_CHAR_SET
;
1387 #endif /* ! _WINDOWS */
1389 if(args
->action
== aaURL
&& args
->url
){
1390 conv
= convert_to_utf8(args
->url
, fromcharset
, 0);
1392 fs_give((void **) &args
->url
);
1397 if(args
->action
== aaFolder
&& args
->data
.folder
){
1398 conv
= convert_to_utf8(args
->data
.folder
, fromcharset
, 0);
1400 fs_give((void **) &args
->data
.folder
);
1401 args
->data
.folder
= conv
;
1405 if(args
->action
== aaMore
&& args
->data
.file
){
1406 conv
= convert_to_utf8(args
->data
.file
, fromcharset
, 0);
1408 fs_give((void **) &args
->data
.file
);
1409 args
->data
.file
= conv
;
1413 if(args
->action
== aaURL
|| args
->action
== aaMail
){
1414 if(args
->data
.mail
.addrlist
){
1417 for(p
= args
->data
.mail
.addrlist
; p
; p
=p
->next
){
1419 conv
= convert_to_utf8(p
->name
, fromcharset
, 0);
1421 fs_give((void **) &p
->name
);
1428 if(args
->data
.mail
.attachlist
){
1431 for(p
= args
->data
.mail
.attachlist
; p
; p
=p
->next
){
1433 conv
= convert_to_utf8(p
->filename
, fromcharset
, 0);
1435 fs_give((void **) &p
->filename
);
1447 preopen_stayopen_folders(void)
1451 for(open_these
= ps_global
->VAR_PERMLOCKED
;
1452 open_these
&& *open_these
; open_these
++)
1453 (void) do_broach_folder(*open_these
, ps_global
->context_list
,
1459 * read_stdin_char - simple function to return a character from
1463 read_stdin_char(char *c
)
1467 /* it'd probably be a good idea to fix this to pre-read blocks */
1469 rv
= read(PIPED_FD
, c
, 1);
1472 dprint((2, "read_stdin_char: read interrupted, restarting\n"));
1476 dprint((1, "read_stdin_char: read FAILED: %s\n",
1477 error_description(errno
)));
1485 /* this default is from the array of structs below */
1486 #define DEFAULT_MENU_ITEM ((unsigned) 3) /* LIST FOLDERS */
1487 #define ABOOK_MENU_ITEM ((unsigned) 4) /* ADDRESS BOOK */
1488 #define MAX_MENU_ITEM ((unsigned) 6)
1490 * Skip this many spaces between rows of main menu screen.
1491 * We have MAX_MENU_ITEM+1 = # of commands in menu
1492 * 1 = copyright line
1493 * MAX_MENU_ITEM = rows between commands
1494 * 1 = extra row above commands
1495 * 1 = row between commands and copyright
1497 * To make it simple, if there is enough room for all of that include all the
1498 * extra space, if not, cut it all out.
1500 #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)
1502 static unsigned menu_index
= DEFAULT_MENU_ITEM
;
1505 * One of these for each line that gets printed in the middle of the
1506 * screen in the main menu.
1508 static struct menu_key
{
1511 int key_index
; /* index into keymenu array for this cmd */
1514 * TRANSLATORS: These next few are headings on the Main alpine menu.
1515 * It's nice if the dashes can be made to line up vertically.
1517 {N_(" %s HELP - Get help using Alpine"),
1518 NULL
, MAIN_HELP_KEY
},
1519 {N_(" %s COMPOSE MESSAGE - Compose and send%s a message"),
1520 /* TRANSLATORS: We think of sending an email message or posting a news message.
1521 The message is shown as Compose and send/post a message */
1522 N_("/post"), MAIN_COMPOSE_KEY
},
1523 {N_(" %s MESSAGE INDEX - View messages in current folder"),
1524 NULL
, MAIN_INDEX_KEY
},
1525 {N_(" %s FOLDER LIST - Select a folder%s to view"),
1526 /* TRANSLATORS: When news is supported the message above becomes
1527 Select a folder OR news group to view */
1528 N_(" OR news group"), MAIN_FOLDER_KEY
},
1529 {N_(" %s ADDRESS BOOK - Update address book"),
1530 NULL
, MAIN_ADDRESS_KEY
},
1531 {N_(" %s SETUP - Configure Alpine Options"),
1532 NULL
, MAIN_SETUP_KEY
},
1533 /* TRANSLATORS: final Main menu line */
1534 {N_(" %s QUIT - Leave the Alpine program"),
1535 NULL
, MAIN_QUIT_KEY
}
1540 /*----------------------------------------------------------------------
1541 display main menu and execute main menu commands
1543 Args: The usual pine structure
1545 Result: main menu commands are executed
1548 M A I N M E N U S C R E E N
1550 Paint the main menu on the screen, get the commands and either execute
1551 the function or pass back the name of the function to execute for the menu
1552 selection. Only simple functions that always return here can be executed
1555 This functions handling of new mail, redrawing, errors and such can
1556 serve as a template for the other screen that do much the same thing.
1558 There is a loop that fetchs and executes commands until a command to leave
1559 this screen is given. Then the name of the next screen to display is
1560 stored in next_screen member of the structure and this function is exited
1563 First a check for new mail is performed. This might involve reading the new
1564 mail into the inbox which might then cause the screen to be repainted.
1566 Then the general screen painting is done. This is usually controlled
1567 by a few flags and some other position variables. If they change they
1568 tell this part of the code what to repaint. This will include cursor
1572 main_menu_screen(struct pine
*pine_state
)
1575 int cmd
, just_a_navigate_cmd
, setup_command
, km_popped
;
1577 char *new_folder
, *utf8str
;
1579 struct key_menu
*km
;
1583 ps_global
= pine_state
;
1584 just_a_navigate_cmd
= 0;
1586 menu_index
= DEFAULT_MENU_ITEM
;
1587 what
= FirstMenu
; /* which keymenu to display */
1588 ch
= 'x'; /* For display_message 1st time through */
1589 pine_state
->next_screen
= SCREEN_FUN_NULL
;
1590 pine_state
->prev_screen
= main_menu_screen
;
1591 curs_pos
.row
= pine_state
->ttyo
->screen_rows
-FOOTER_ROWS(pine_state
);
1595 mailcap_free(); /* free resources we won't be using for a while */
1597 if(!pine_state
->painted_body_on_startup
1598 && !pine_state
->painted_footer_on_startup
){
1599 pine_state
->mangled_screen
= 1;
1602 dprint((1, "\n\n ---- MAIN_MENU_SCREEN ----\n"));
1608 clearfooter(pine_state
);
1609 pine_state
->mangled_body
= 1;
1614 * fix up redrawer just in case some submenu caused it to get
1617 pine_state
->redrawer
= main_redrawer
;
1619 /*----------- Check for new mail -----------*/
1620 if(new_mail(0, NM_TIMING(ch
), NM_STATUS_MSG
| NM_DEFER_SORT
) >= 0)
1621 pine_state
->mangled_header
= 1;
1624 pine_state
->mangled_header
= 1;
1626 show_main_screen(pine_state
, just_a_navigate_cmd
, what
, km
,
1627 km_popped
, &curs_pos
);
1628 just_a_navigate_cmd
= 0;
1631 /*---- This displays new mail notification, or errors ---*/
1633 FOOTER_ROWS(pine_state
) = 3;
1634 mark_status_dirty();
1637 display_message(ch
);
1639 FOOTER_ROWS(pine_state
) = 1;
1640 mark_status_dirty();
1643 if(F_OFF(F_SHOW_CURSOR
, ps_global
)){
1644 curs_pos
.row
=pine_state
->ttyo
->screen_rows
-FOOTER_ROWS(pine_state
);
1648 MoveCursor(curs_pos
.row
, curs_pos
.col
);
1650 /*------ Read the command from the keyboard ----*/
1652 mouse_in_content(KEY_MOUSE
, -1, -1, 0, 0);
1653 register_mfunc(mouse_in_content
, HEADER_ROWS(pine_state
), 0,
1654 pine_state
->ttyo
->screen_rows
-(FOOTER_ROWS(pine_state
)+1),
1655 pine_state
->ttyo
->screen_cols
);
1657 #if defined(DOS) || defined(OS2)
1659 * AND pre-build header lines. This works just fine under
1660 * DOS since we wait for characters in a loop. Something will
1661 * will have to change under UNIX if we want to do the same.
1663 /* while_waiting = build_header_cache; */
1665 mswin_sethelptextcallback(pcpine_help_main
);
1666 mswin_mousetrackcallback(pcpine_main_cursor
);
1669 ch
= READ_COMMAND(&utf8str
);
1671 clear_mfunc(mouse_in_content
);
1673 #if defined(DOS) || defined(OS2)
1674 /* while_waiting = NULL; */
1676 mswin_sethelptextcallback(NULL
);
1677 mswin_mousetrackcallback(NULL
);
1681 /* No matter what, Quit here always works */
1682 if(ch
== 'q' || ch
== 'Q'){
1686 else if(debug
&& ch
&& ch
< 0x80 && strchr("123456789", ch
)){
1692 ps_global
->debug_timestamp
= 1;
1694 ps_global
->debug_timestamp
= 0;
1697 ps_global
->debug_imap
= 4;
1699 ps_global
->debug_imap
= 3;
1701 ps_global
->debug_imap
= 2;
1703 ps_global
->debug_imap
= 1;
1705 ps_global
->debug_imap
= 0;
1707 if(ps_global
->mail_stream
){
1708 if(ps_global
->debug_imap
> 0){
1709 mail_debug(ps_global
->mail_stream
);
1711 mswin_enableimaptelemetry(TRUE
);
1715 mail_nodebug(ps_global
->mail_stream
);
1717 mswin_enableimaptelemetry(FALSE
);
1722 if(debug
> 7 && olddebug
<= 7)
1723 mail_parameters(NULL
, SET_TCPDEBUG
, (void *) TRUE
);
1724 else if(debug
<= 7 && olddebug
> 7 && !ps_global
->debugmem
)
1725 mail_parameters(NULL
, SET_TCPDEBUG
, (void *) FALSE
);
1727 dprint((1, "*** Debug level set to %d ***\n", debug
));
1731 q_status_message1(SM_ORDER
, 0, 1, _("Debug level set to %s"),
1737 cmd
= menu_command(ch
, km
);
1749 clearfooter(pine_state
);
1754 /*------ Execute the command ------*/
1757 /*------ HELP ------*/
1760 if(FOOTER_ROWS(pine_state
) == 1 && km_popped
== 0){
1762 pine_state
->mangled_footer
= 1;
1765 /* TRANSLATORS: This is a screen title */
1766 helper(main_menu_tx
, _("HELP FOR MAIN MENU"), 0);
1767 pine_state
->mangled_screen
= 1;
1773 /*---------- display other key bindings ------*/
1779 pine_state
->mangled_footer
= 1;
1783 /*---------- Previous item in menu ----------*/
1785 if(menu_index
> 0) {
1787 pine_state
->mangled_body
= 1;
1789 pine_state
->mangled_footer
= 1;
1791 just_a_navigate_cmd
++;
1794 /* TRANSLATORS: list refers to list of commands in main menu */
1795 q_status_message(SM_ORDER
, 0, 2, _("Already at top of list"));
1800 /*---------- Next item in menu ----------*/
1802 if(menu_index
< MAX_MENU_ITEM
){
1804 pine_state
->mangled_body
= 1;
1806 pine_state
->mangled_footer
= 1;
1808 just_a_navigate_cmd
++;
1811 q_status_message(SM_ORDER
, 0, 2, _("Already at bottom of list"));
1816 /*---------- Release Notes ----------*/
1818 /* TRANSLATORS: This is a screen title */
1819 helper(h_news
, _("ALPINE RELEASE NOTES"), 0);
1820 pine_state
->mangled_screen
= 1;
1824 #ifdef KEYBOARD_LOCK
1825 /*---------- Keyboard lock ----------*/
1827 (void) lock_keyboard();
1828 pine_state
->mangled_screen
= 1;
1830 #endif /* KEYBOARD_LOCK */
1833 /*---------- Quit pine ----------*/
1835 pine_state
->next_screen
= quit_screen
;
1839 /*---------- Go to composer ----------*/
1841 pine_state
->next_screen
= compose_screen
;
1845 /*---- Go to alternate composer ------*/
1847 pine_state
->next_screen
= alt_compose_screen
;
1851 /*---------- Top of Folder list ----------*/
1852 case MC_COLLECTIONS
:
1853 pine_state
->next_screen
= folder_screen
;
1857 /*---------- Goto new folder ----------*/
1859 tc
= ps_global
->context_current
;
1860 new_folder
= broach_folder(-FOOTER_ROWS(pine_state
), 1, ¬realinbox
, &tc
);
1862 visit_folder(ps_global
, new_folder
, tc
, NULL
, notrealinbox
? 0L : DB_INBOXWOCNTXT
);
1867 /*---------- Go to index ----------*/
1870 && sp_viewing_a_thread(pine_state
->mail_stream
)
1871 && unview_thread(pine_state
, pine_state
->mail_stream
,
1872 pine_state
->msgmap
)){
1873 pine_state
->view_skipped_index
= 0;
1874 pine_state
->mangled_screen
= 1;
1877 pine_state
->next_screen
= mail_index_screen
;
1881 /*---------- Review Status Messages ----------*/
1884 pine_state
->mangled_screen
= 1;
1888 /*---------- Setup mini menu ----------*/
1891 setup_command
= setup_menu(pine_state
);
1892 pine_state
->mangled_footer
= 1;
1893 do_setup_task(setup_command
);
1894 if(ps_global
->next_screen
!= main_menu_screen
)
1900 /*---------- Go to address book ----------*/
1902 pine_state
->next_screen
= addr_book_screen
;
1906 /*------ Repaint the works -------*/
1910 pine_state
->mangled_screen
= 1;
1915 /*------- Mouse event ------*/
1920 struct pine
*ps
= pine_state
;
1922 mouse_get_last (NULL
, &mp
);
1925 if(mp
.button
== M_BUTTON_RIGHT
){
1926 if(!mp
.doubleclick
){
1927 static MPopup main_popup
[] = {
1928 {tQueue
, {"Folder List", lNormal
}, {'L'}},
1929 {tQueue
, {"Message Index", lNormal
}, {'I'}},
1931 {tQueue
, {"Address Book", lNormal
}, {'A'}},
1932 {tQueue
, {"Setup Options", lNormal
}, {'S'}},
1936 mswin_popup(main_popup
);
1941 if (mp
.row
>= (HEADER_ROWS(ps
) + MNSKIP(ps
)))
1942 ndmi
= (mp
.row
+1 - HEADER_ROWS(ps
) - (MNSKIP(ps
)+1))/(MNSKIP(ps
)+1);
1944 if (mp
.row
>= (HEADER_ROWS(ps
) + MNSKIP(ps
))
1945 && !(MNSKIP(ps
) && (mp
.row
+1) & 0x01)
1946 && ndmi
<= MAX_MENU_ITEM
1947 && FOOTER_ROWS(ps
) + (ndmi
+1)*(MNSKIP(ps
)+1)
1948 + MNSKIP(ps
) + FOOTER_ROWS(ps
) <= ps
->ttyo
->screen_rows
){
1950 switch(ndmi
){ /* fake main_screen request */
1955 pine_state
->next_screen
= compose_screen
;
1959 pine_state
->next_screen
= mail_index_screen
;
1963 pine_state
->next_screen
= folder_screen
;
1967 pine_state
->next_screen
= addr_book_screen
;
1974 pine_state
->next_screen
= quit_screen
;
1977 default: /* no op */
1983 pine_state
->mangled_body
= 1;
1985 pine_state
->mangled_footer
= 1;
1987 just_a_navigate_cmd
++;
1999 /*------ Input timeout ------*/
2001 break; /* noop for timeout loop mail check */
2004 /*------ Bogus Input ------*/
2006 if(ch
== 'm' || ch
== 'M'){
2007 q_status_message(SM_ORDER
, 0, 1, "Already in Main Menu");
2012 bogus_command(ch
, F_ON(F_USE_FK
,pine_state
) ? "F1" : "?");
2016 bogus_utf8_command(utf8str
, F_ON(F_USE_FK
, pine_state
) ? "F1" : "?");
2019 } /* the BIG while loop! */
2023 /*----------------------------------------------------------------------
2024 Re-Draw the main menu
2028 Result: main menu is re-displayed
2033 struct key_menu
*km
= &main_keymenu
;
2035 ps_global
->mangled_screen
= 1;
2036 show_main_screen(ps_global
, 0, FirstMenu
, km
, 0, (Pos
*)NULL
);
2040 /*----------------------------------------------------------------------
2043 Args: pine_state - the usual struct
2044 quick_draw - tells do_menu() it can skip some drawing
2045 what - tells which section of keymenu to draw
2047 cursor_pos - returns a good position for the cursor to be located
2049 Result: main menu is displayed
2052 show_main_screen(struct pine
*ps
, int quick_draw
, OtherMenu what
,
2053 struct key_menu
*km
, int km_popped
, Pos
*cursor_pos
)
2055 if(ps
->painted_body_on_startup
|| ps
->painted_footer_on_startup
){
2056 ps
->mangled_screen
= 0; /* only worry about it here */
2057 ps
->mangled_header
= 1; /* we have to redo header */
2058 if(!ps
->painted_body_on_startup
)
2059 ps
->mangled_body
= 1; /* make sure to paint body*/
2061 if(!ps
->painted_footer_on_startup
)
2062 ps
->mangled_footer
= 1; /* make sure to paint footer*/
2064 ps
->painted_body_on_startup
= 0;
2065 ps
->painted_footer_on_startup
= 0;
2068 if(ps
->mangled_screen
){
2069 ps
->mangled_header
= 1;
2070 ps
->mangled_body
= 1;
2071 ps
->mangled_footer
= 1;
2072 ps
->mangled_screen
= 0;
2076 /* Reset the scroll range. Main screen never scrolls. */
2077 scroll_setrange (0L, 0L);
2078 mswin_beginupdate();
2081 /* paint the titlebar if needed */
2082 if(ps
->mangled_header
){
2083 /* TRANSLATORS: screen title */
2084 set_titlebar(_("MAIN MENU"), ps
->mail_stream
, ps
->context_current
,
2085 ps
->cur_folder
, ps
->msgmap
, 1, FolderName
, 0, 0, NULL
);
2086 ps
->mangled_header
= 0;
2089 /* paint the body if needed */
2090 if(ps
->mangled_body
){
2094 do_menu(quick_draw
, cursor_pos
, km
);
2095 ps
->mangled_body
= 0;
2098 /* paint the keymenu if needed */
2099 if(km
&& ps
->mangled_footer
){
2100 static char label
[LONGEST_LABEL
+ 2 + 1], /* label + brackets + \0 */
2106 #ifdef KEYBOARD_LOCK
2107 if(ps_global
->restricted
|| F_ON(F_DISABLE_KBLOCK_CMD
,ps_global
))
2109 clrbitn(MAIN_KBLOCK_KEY
, bitmap
);
2111 menu_clear_binding(km
, '>');
2112 menu_clear_binding(km
, '.');
2113 menu_clear_binding(km
, KEY_RIGHT
);
2114 menu_clear_binding(km
, ctrl('M'));
2115 menu_clear_binding(km
, ctrl('J'));
2116 km
->keys
[MAIN_DEFAULT_KEY
].bind
2117 = km
->keys
[mkeys
[menu_index
].key_index
].bind
;
2118 km
->keys
[MAIN_DEFAULT_KEY
].label
2119 = km
->keys
[mkeys
[menu_index
].key_index
].label
;
2121 /* put brackets around the default action */
2122 snprintf(label
, sizeof(label
), "[%s]", km
->keys
[mkeys
[menu_index
].key_index
].label
);
2123 label
[sizeof(label
)-1] = '\0';
2124 strncpy(name
, ">", sizeof(name
));
2125 name
[sizeof(name
)-1] = '\0';
2126 km
->keys
[MAIN_DEFAULT_KEY
].label
= label
;
2127 km
->keys
[MAIN_DEFAULT_KEY
].name
= name
;
2128 menu_add_binding(km
, '>', km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2129 menu_add_binding(km
, '.', km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2130 menu_add_binding(km
, ctrl('M'), km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2131 menu_add_binding(km
, ctrl('J'), km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2133 if(F_ON(F_ARROW_NAV
,ps_global
))
2134 menu_add_binding(km
, KEY_RIGHT
, km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2137 FOOTER_ROWS(ps
) = 3;
2141 draw_keymenu(km
, bitmap
, ps_global
->ttyo
->screen_cols
,
2142 1-FOOTER_ROWS(ps_global
), 0, what
);
2143 ps
->mangled_footer
= 0;
2145 FOOTER_ROWS(ps
) = 1;
2146 mark_keymenu_dirty();
2156 /*----------------------------------------------------------------------
2157 Actually display the main menu
2159 Args: quick_draw - just a next or prev command was typed so we only have
2160 to redraw the highlighting
2161 cursor_pos - a place to return a good value for cursor location
2163 Result: Main menu is displayed
2166 do_menu(int quick_draw
, Pos
*cursor_pos
, struct key_menu
*km
)
2168 struct pine
*ps
= ps_global
;
2169 int dline
, indent
, longest
= 0, cmd
;
2170 char buf
[4*MAX_SCREEN_COLS
+1];
2171 char buf2
[4*MAX_SCREEN_COLS
+1];
2172 static int last_inverse
= -1;
2175 /* find the longest command */
2176 for(cmd
= 0; cmd
< sizeof(mkeys
)/(sizeof(mkeys
[1])); cmd
++){
2177 memset((void *) buf
, ' ', sizeof(buf
));
2178 snprintf(buf
, sizeof(buf
), mkeys
[cmd
].key_and_name
[0] ? _(mkeys
[cmd
].key_and_name
) : "",
2180 && km
->keys
[mkeys
[cmd
].key_index
].name
)
2181 ? km
->keys
[mkeys
[cmd
].key_index
].name
: "",
2182 (ps
->VAR_NEWS_SPEC
&& mkeys
[cmd
].news_addition
&& mkeys
[cmd
].news_addition
[0])
2183 ? _(mkeys
[cmd
].news_addition
) : "");
2184 buf
[sizeof(buf
)-1] = '\0';
2186 if(longest
< (indent
= utf8_width(buf
)))
2190 indent
= MAX(((ps
->ttyo
->screen_cols
- longest
)/2) - 1, 0);
2192 dline
= HEADER_ROWS(ps
) + MNSKIP(ps
);
2193 for(cmd
= 0; cmd
< sizeof(mkeys
)/(sizeof(mkeys
[1])); cmd
++){
2194 /* leave room for copyright and footer */
2195 if(dline
+ MNSKIP(ps
) + 1 + FOOTER_ROWS(ps
) >= ps
->ttyo
->screen_rows
)
2198 if(quick_draw
&& !(cmd
== last_inverse
|| cmd
== menu_index
)){
2199 dline
+= (1 + MNSKIP(ps
));
2203 if(cmd
== menu_index
)
2206 memset((void *) buf
, ' ', sizeof(buf
));
2207 snprintf(buf
, sizeof(buf
), mkeys
[cmd
].key_and_name
[0] ? _(mkeys
[cmd
].key_and_name
) : "",
2209 && km
->keys
[mkeys
[cmd
].key_index
].name
)
2210 ? km
->keys
[mkeys
[cmd
].key_index
].name
: "",
2211 (ps
->VAR_NEWS_SPEC
&& mkeys
[cmd
].news_addition
&& mkeys
[cmd
].news_addition
[0])
2212 ? _(mkeys
[cmd
].news_addition
) : "");
2213 buf
[sizeof(buf
)-1] = '\0';
2215 utf8_pad_to_width(buf2
, buf
, sizeof(buf2
),
2216 MIN(ps
->ttyo
->screen_cols
-indent
,longest
+1), 1);
2219 PutLine0(pos
.row
, pos
.col
, buf2
);
2224 if(cmd
== menu_index
){
2226 cursor_pos
->row
= pos
.row
;
2227 /* 6 is 1 for the letter plus 5 spaces */
2228 cursor_pos
->col
= pos
.col
+ 6;
2229 if(F_OFF(F_USE_FK
,ps
))
2232 cursor_pos
->col
= MIN(cursor_pos
->col
, ps
->ttyo
->screen_cols
);
2240 last_inverse
= menu_index
;
2242 if(!quick_draw
&& FOOTER_ROWS(ps
)+1 < ps
->ttyo
->screen_rows
){
2243 utf8_to_width(buf2
, LEGAL_NOTICE
, sizeof(buf2
),
2244 ps
->ttyo
->screen_cols
-3, NULL
);
2245 PutLine0(ps
->ttyo
->screen_rows
- (FOOTER_ROWS(ps
)+1),
2246 MAX(0, ((ps
->ttyo
->screen_cols
-utf8_width(buf2
))/2)),
2255 choose_setup_cmd(int cmd
, MSGNO_S
*msgmap
, SCROLL_S
*sparms
)
2260 if(!(srv
= (SRV_S
*)sparms
->proc
.data
.p
)){
2261 sparms
->proc
.data
.p
= (SRV_S
*)fs_get(sizeof(*srv
));
2262 srv
= (SRV_S
*)sparms
->proc
.data
.p
;
2263 memset(srv
, 0, sizeof(*srv
));
2266 ps_global
->next_screen
= SCREEN_FUN_NULL
;
2309 case MC_SECURITY
: /* S/MIME setup screen */
2314 srv
->exc
= !srv
->exc
;
2315 menu_clear_binding(sparms
->keys
.menu
, 'x');
2317 if(sparms
->bar
.title
) fs_give((void **)&sparms
->bar
.title
);
2318 /* TRANSLATORS: screen title */
2319 sparms
->bar
.title
= cpystr(_("SETUP EXCEPTIONS"));
2320 ps_global
->mangled_header
= 1;
2321 /* TRANSLATORS: The reason the X is upper case in eXceptions
2322 is because the command key is X. It isn't necessary, just
2323 nice if it works. */
2324 menu_init_binding(sparms
->keys
.menu
, 'x', MC_EXCEPT
, "X",
2325 N_("not eXceptions"), SETUP_EXCEPT
);
2328 if(sparms
->bar
.title
) fs_give((void **)&sparms
->bar
.title
);
2329 /* TRANSLATORS: screen title */
2330 sparms
->bar
.title
= cpystr(_("SETUP"));
2331 ps_global
->mangled_header
= 1;
2332 menu_init_binding(sparms
->keys
.menu
, 'x', MC_EXCEPT
, "X",
2333 N_("eXceptions"), SETUP_EXCEPT
);
2336 if(sparms
->keys
.menu
->which
== 1)
2337 ps_global
->mangled_footer
= 1;
2343 #if defined(DOS) || defined(OS2)
2344 q_status_message(SM_ORDER
, 0, 2, _("Need argument \"-x <except_config>\" or \"PINERCEX\" file to use eXceptions"));
2346 q_status_message(SM_ORDER
, 0, 2, _("Need argument \"-x <except_config>\" or \".pinercex\" file to use eXceptions"));
2352 alpine_panic("Unexpected command in choose_setup_cmd");
2361 setup_menu(struct pine
*ps
)
2363 int ret
= 0, exceptions
= 0;
2364 int printer
= 0, passwd
= 0, config
= 0, sig
= 0, dir
= 0, smime
= 0, exc
= 0;
2369 if(!(store
= so_get(CharStar
, NULL
, EDIT_ACCESS
))){
2370 q_status_message(SM_ORDER
| SM_DING
, 3, 3, _("Error allocating space."));
2375 if(!ps_global
->vars
[V_PRINTER
].is_fixed
) /* printer can be changed */
2380 if(F_OFF(F_DISABLE_PASSWORD_CMD
,ps_global
)) /* password is allowed */
2384 if(F_OFF(F_DISABLE_CONFIG_SCREEN
,ps_global
)) /* config allowed */
2387 if(F_OFF(F_DISABLE_SIGEDIT_CMD
,ps_global
)) /* .sig editing is allowed */
2398 if(ps_global
->post_prc
)
2401 /* TRANSLATORS: starting here we have a whole screen of help text */
2402 so_puts(store
, _("This is the Setup screen for Alpine. Choose from the following commands:\n"));
2404 so_puts(store
, "\n");
2405 so_puts(store
, _("(E) Exit Setup:\n"));
2406 so_puts(store
, _(" This puts you back at the Main Menu.\n"));
2409 so_puts(store
, "\n");
2410 so_puts(store
, _("(X) eXceptions:\n"));
2411 so_puts(store
, _(" This command is different from the rest. It is not actually a command\n"));
2412 so_puts(store
, _(" itself. Instead, it is a toggle which modifies the behavior of the\n"));
2413 so_puts(store
, _(" other commands. You toggle Exceptions editing on and off with this\n"));
2414 so_puts(store
, _(" command. When it is off you will be editing (changing) your regular\n"));
2415 so_puts(store
, _(" configuration file. When it is on you will be editing your exceptions\n"));
2416 so_puts(store
, _(" configuration file. For example, you might want to type the command \n"));
2417 so_puts(store
, _(" \"eXceptions\" followed by \"Kolor\" to setup different screen colors\n"));
2418 so_puts(store
, _(" on a particular platform.\n"));
2419 so_puts(store
, _(" (Note: this command does not show up on the keymenu at the bottom of\n"));
2420 so_puts(store
, _(" the screen unless you press \"O\" for \"Other Commands\" --but you don't\n"));
2421 so_puts(store
, _(" need to press the \"O\" in order to invoke the command.)\n"));
2425 so_puts(store
, "\n");
2426 so_puts(store
, _("(P) Printer:\n"));
2427 so_puts(store
, _(" Allows you to set a default printer and to define custom\n"));
2428 so_puts(store
, _(" print commands.\n"));
2432 so_puts(store
, "\n");
2433 so_puts(store
, _("(N) Newpassword:\n"));
2434 so_puts(store
, _(" Change your password.\n"));
2438 so_puts(store
, "\n");
2439 so_puts(store
, _("(C) Config:\n"));
2440 so_puts(store
, _(" Allows you to set or unset many features of Alpine.\n"));
2441 so_puts(store
, _(" You may also set the values of many options with this command.\n"));
2445 so_puts(store
, "\n");
2446 so_puts(store
, _("(S) Signature:\n"));
2447 so_puts(store
, _(" Enter or edit a custom signature which will\n"));
2448 so_puts(store
, _(" be included with each new message you send.\n"));
2451 so_puts(store
, "\n");
2452 so_puts(store
, _("(A) AddressBooks:\n"));
2453 so_puts(store
, _(" Define a non-default address book.\n"));
2455 so_puts(store
, "\n");
2456 so_puts(store
, _("(L) collectionLists:\n"));
2457 so_puts(store
, _(" You may define groups of folders to help you better organize your mail.\n"));
2459 so_puts(store
, "\n");
2460 so_puts(store
, _("(R) Rules:\n"));
2461 so_puts(store
, _(" This has up to six sub-categories: Roles, Index Colors, Filters,\n"));
2462 so_puts(store
, _(" SetScores, Search, and Other. If the Index Colors option is\n"));
2463 so_puts(store
, _(" missing you may turn it on (if possible) with Setup/Kolor.\n"));
2464 so_puts(store
, _(" If Roles is missing it has probably been administratively disabled.\n"));
2467 so_puts(store
, "\n");
2468 so_puts(store
, _("(D) Directory:\n"));
2469 so_puts(store
, _(" Define an LDAP Directory server for Alpine's use. A directory server is\n"));
2470 so_puts(store
, _(" similar to an address book, but it is usually maintained by an\n"));
2471 so_puts(store
, _(" organization. It is similar to a telephone directory.\n"));
2474 so_puts(store
, "\n");
2475 so_puts(store
, _("(K) Kolor:\n"));
2476 so_puts(store
, _(" Set custom colors for various parts of the Alpine screens. For example, the\n"));
2477 so_puts(store
, _(" command key labels, the titlebar at the top of each page, and quoted\n"));
2478 so_puts(store
, _(" sections of messages you are viewing.\n"));
2481 so_puts(store
, "\n");
2482 so_puts(store
, _("(M) S/MIME:\n"));
2483 so_puts(store
, _(" Setup for using S/MIME to verify signed messages, decrypt\n"));
2484 so_puts(store
, _(" encrypted messages, and to sign or encrypt outgoing messages.\n"));
2487 so_puts(store
, "\n");
2488 so_puts(store
, _("(Z) RemoteConfigSetup:\n"));
2489 so_puts(store
, _(" This is a command you will probably only want to use once, if at all.\n"));
2490 so_puts(store
, _(" It helps you transfer your Alpine configuration data to an IMAP server,\n"));
2491 so_puts(store
, _(" where it will be accessible from any of the computers you read mail\n"));
2492 so_puts(store
, _(" from (using Alpine). The idea behind a remote configuration is that you\n"));
2493 so_puts(store
, _(" can change your configuration in one place and have that change show\n"));
2494 so_puts(store
, _(" up on all of the computers you use.\n"));
2495 so_puts(store
, _(" (Note: this command does not show up on the keymenu at the bottom of\n"));
2496 so_puts(store
, _(" the screen unless you press \"O\" for \"Other Commands\" --but you don't\n"));
2497 so_puts(store
, _(" need to press the \"O\" in order to invoke the command.)\n"));
2499 /* put this down here for people who don't have exceptions */
2501 so_puts(store
, "\n");
2502 so_puts(store
, _("(X) eXceptions:\n"));
2503 so_puts(store
, _(" This command is different from the rest. It is not actually a command\n"));
2504 so_puts(store
, _(" itself. Instead, it is a toggle which modifies the behavior of the\n"));
2505 so_puts(store
, _(" other commands. You toggle Exceptions editing on and off with this\n"));
2506 so_puts(store
, _(" command. When it is off you will be editing (changing) your regular\n"));
2507 so_puts(store
, _(" configuration file. When it is on you will be editing your exceptions\n"));
2508 so_puts(store
, _(" configuration file. For example, you might want to type the command \n"));
2509 so_puts(store
, _(" \"eXceptions\" followed by \"Kolor\" to setup different screen colors\n"));
2510 so_puts(store
, _(" on a particular platform.\n"));
2511 so_puts(store
, _(" (Note: this command does not do anything unless you have a configuration\n"));
2512 so_puts(store
, _(" with exceptions enabled (you don't have that). Common ways to enable an\n"));
2513 so_puts(store
, _(" exceptions config are the command line argument \"-x <exception_config>\";\n"));
2514 so_puts(store
, _(" or the existence of the file \".pinercex\" for Unix Alpine, or \"PINERCEX\")\n"));
2515 so_puts(store
, _(" for PC-Alpine.)\n"));
2516 so_puts(store
, _(" (Another note: this command does not show up on the keymenu at the bottom\n"));
2517 so_puts(store
, _(" of the screen unless you press \"O\" for \"Other Commands\" --but you\n"));
2518 so_puts(store
, _(" don't need to press the \"O\" in order to invoke the command.)\n"));
2521 memset(&sargs
, 0, sizeof(SCROLL_S
));
2522 sargs
.text
.text
= so_text(store
);
2523 sargs
.text
.src
= CharStar
;
2524 sargs
.text
.desc
= _("Information About Setup Command");
2525 sargs
.bar
.title
= cpystr(_("SETUP"));
2526 sargs
.proc
.tool
= choose_setup_cmd
;
2527 sargs
.help
.text
= NO_HELP
;
2528 sargs
.help
.title
= NULL
;
2529 sargs
.keys
.menu
= &choose_setup_keymenu
;
2530 sargs
.keys
.menu
->how_many
= 2;
2532 setbitmap(sargs
.keys
.bitmap
);
2534 clrbitn(SETUP_PRINTER
, sargs
.keys
.bitmap
);
2537 clrbitn(SETUP_PASSWD
, sargs
.keys
.bitmap
);
2540 clrbitn(SETUP_CONFIG
, sargs
.keys
.bitmap
);
2543 clrbitn(SETUP_SIG
, sargs
.keys
.bitmap
);
2546 clrbitn(SETUP_DIRECTORY
, sargs
.keys
.bitmap
);
2549 clrbitn(SETUP_SMIME
, sargs
.keys
.bitmap
);
2552 menu_init_binding(sargs
.keys
.menu
, 'x', MC_EXCEPT
, "X",
2553 N_("eXceptions"), SETUP_EXCEPT
);
2555 menu_init_binding(sargs
.keys
.menu
, 'x', MC_NO_EXCEPT
, "X",
2556 N_("eXceptions"), SETUP_EXCEPT
);
2561 ps
->mangled_screen
= 1;
2563 srv
= (SRV_S
*)sargs
.proc
.data
.p
;
2565 exceptions
= srv
? srv
->exc
: 0;
2569 if(sargs
.bar
.title
) fs_give((void**)&sargs
.bar
.title
);
2572 fs_give((void **)&sargs
.proc
.data
.p
);
2577 return(ret
| (exceptions
? EDIT_EXCEPTION
: 0));
2581 /*----------------------------------------------------------------------
2583 Args: command -- command char to perform
2587 do_setup_task(int command
)
2591 int edit_exceptions
= 0;
2594 if(command
& EDIT_EXCEPTION
){
2595 edit_exceptions
= 1;
2596 command
&= ~EDIT_EXCEPTION
;
2600 /*----- EDIT SIGNATURE -----*/
2602 if(ps_global
->VAR_LITERAL_SIG
)
2605 char sig_path
[MAXPATH
+1];
2607 if(!signature_path(ps_global
->VAR_SIGNATURE_FILE
, sig_path
, MAXPATH
))
2609 else if((!IS_REMOTE(ps_global
->VAR_SIGNATURE_FILE
)
2610 && can_access(sig_path
, READ_ACCESS
) == 0)
2611 ||(IS_REMOTE(ps_global
->VAR_SIGNATURE_FILE
)
2612 && (folder_exists(NULL
, sig_path
) & FEX_ISFILE
)))
2614 else if(!ps_global
->vars
[V_SIGNATURE_FILE
].main_user_val
.p
2615 && !ps_global
->vars
[V_SIGNATURE_FILE
].cmdline_val
.p
2616 && !ps_global
->vars
[V_SIGNATURE_FILE
].fixed_val
.p
)
2623 char *result
= NULL
;
2628 ew
= edit_exceptions
? ps_global
->ew_for_except_vars
: Main
;
2630 if(ps_global
->restricted
)
2634 readonly
= ps_global
->prc
->readonly
;
2637 readonly
= ps_global
->post_prc
->readonly
;
2644 err
= cpystr(ps_global
->restricted
2645 ? "Alpine demo can't change config file"
2646 : _("Config file not changeable"));
2649 apval
= APVAL(&ps_global
->vars
[V_LITERAL_SIG
], ew
);
2651 err
= cpystr(_("Problem accessing configuration"));
2655 input
= (char *)fs_get((strlen(*apval
? *apval
: "")+1) *
2658 cstring_to_string(*apval
, input
);
2659 err
= signature_edit_lit(input
, &result
,
2660 _("SIGNATURE EDITOR"),
2661 h_composer_sigedit
);
2662 fs_give((void **)&input
);
2667 char *cstring_version
;
2669 cstring_version
= string_to_cstring(result
);
2671 set_variable(V_LITERAL_SIG
, cstring_version
, 0, 0, ew
);
2674 fs_give((void **)&cstring_version
);
2678 fs_give((void **)&result
);
2681 err
= signature_edit(ps_global
->VAR_SIGNATURE_FILE
,
2682 _("SIGNATURE EDITOR"));
2685 q_status_message(SM_ORDER
, 3, 4, err
);
2686 fs_give((void **)&err
);
2689 ps_global
->mangled_screen
= 1;
2692 /*----- ADD ADDRESSBOOK ----*/
2694 addr_book_config(ps_global
, edit_exceptions
);
2695 menu_index
= ABOOK_MENU_ITEM
;
2696 ps_global
->mangled_screen
= 1;
2700 /*--- ADD DIRECTORY SERVER --*/
2702 directory_config(ps_global
, edit_exceptions
);
2703 ps_global
->mangled_screen
= 1;
2710 smime_config_screen(ps_global
, edit_exceptions
);
2711 ps_global
->mangled_screen
= 1;
2715 /*----- CONFIGURE OPTIONS -----*/
2717 option_screen(ps_global
, edit_exceptions
);
2718 ps_global
->mangled_screen
= 1;
2721 /*----- COLLECTION LIST -----*/
2723 folder_config_screen(ps_global
, edit_exceptions
);
2724 ps_global
->mangled_screen
= 1;
2727 /*----- RULES -----*/
2729 rtype
= rule_setup_type(ps_global
, RS_RULES
| RS_INCFILTNOW
,
2730 _("Type of rule setup : "));
2738 role_config_screen(ps_global
, (rtype
== 'r') ? ROLE_DO_ROLES
:
2739 (rtype
== 's') ? ROLE_DO_SCORES
:
2740 (rtype
== 'o') ? ROLE_DO_OTHER
:
2741 (rtype
== 'f') ? ROLE_DO_FILTER
:
2742 (rtype
== 'c') ? ROLE_DO_SRCH
:
2748 q_status_message(SM_ORDER
| SM_DING
, 3, 5,
2749 _("Try turning on color with the Setup/Kolor command."));
2753 role_process_filters();
2757 cmd_cancelled(NULL
);
2761 ps_global
->mangled_screen
= 1;
2764 /*----- COLOR -----*/
2766 color_config_screen(ps_global
, edit_exceptions
);
2767 ps_global
->mangled_screen
= 1;
2771 convert_to_remote_config(ps_global
, edit_exceptions
);
2772 ps_global
->mangled_screen
= 1;
2775 /*----- EXIT -----*/
2779 /*----- NEW PASSWORD -----*/
2782 if(ps_global
->restricted
){
2783 q_status_message(SM_ORDER
, 3, 5,
2784 "Password change unavailable in restricted demo version of Alpine.");
2788 ps_global
->mangled_screen
= 1;
2791 q_status_message(SM_ORDER
, 0, 5,
2792 _("Password changing not configured for this version of Alpine."));
2793 display_message('x');
2798 /*----- CHOOSE PRINTER ------*/
2800 select_printer(ps_global
, edit_exceptions
);
2801 ps_global
->mangled_screen
= 1;
2809 rule_setup_type(struct pine
*ps
, int flags
, char *prompt
)
2812 int ekey_num
= 0, deefault
= 0;
2814 if(flags
& RS_INCADDR
){
2816 opts
[ekey_num
].ch
= 'a';
2817 opts
[ekey_num
].rval
= 'a';
2818 opts
[ekey_num
].name
= "A";
2819 opts
[ekey_num
++].label
= "Addrbook";
2822 if(flags
& RS_RULES
){
2824 if(F_OFF(F_DISABLE_ROLES_SETUP
,ps
)){ /* roles are allowed */
2828 opts
[ekey_num
].ch
= 'r';
2829 opts
[ekey_num
].rval
= 'r';
2830 opts
[ekey_num
].name
= "R";
2831 opts
[ekey_num
++].label
= "Roles";
2833 else if(deefault
!= 'a')
2836 opts
[ekey_num
].ch
= 's';
2837 opts
[ekey_num
].rval
= 's';
2838 opts
[ekey_num
].name
= "S";
2839 opts
[ekey_num
++].label
= "SetScores";
2842 if(ps
->color_style
!= COL_NONE
&& pico_hascolor()){
2847 opts
[ekey_num
].ch
= 'i';
2848 opts
[ekey_num
].rval
= 'i';
2849 opts
[ekey_num
].name
= "I";
2850 opts
[ekey_num
++].label
= "Indexcolor";
2854 opts
[ekey_num
].ch
= 'i';
2855 opts
[ekey_num
].rval
= 'Z'; /* notice this rval! */
2856 opts
[ekey_num
].name
= "I";
2857 opts
[ekey_num
++].label
= "Indexcolor";
2861 opts
[ekey_num
].ch
= 'f';
2862 opts
[ekey_num
].rval
= 'f';
2863 opts
[ekey_num
].name
= "F";
2864 opts
[ekey_num
++].label
= "Filters";
2866 opts
[ekey_num
].ch
= 'o';
2867 opts
[ekey_num
].rval
= 'o';
2868 opts
[ekey_num
].name
= "O";
2869 opts
[ekey_num
++].label
= "Other";
2871 opts
[ekey_num
].ch
= 'c';
2872 opts
[ekey_num
].rval
= 'c';
2873 opts
[ekey_num
].name
= "C";
2874 opts
[ekey_num
++].label
= "searCh";
2878 if(flags
& RS_INCEXP
){
2879 opts
[ekey_num
].ch
= 'e';
2880 opts
[ekey_num
].rval
= 'e';
2881 opts
[ekey_num
].name
= "E";
2882 opts
[ekey_num
++].label
= "Export";
2885 if(flags
& RS_INCFILTNOW
){
2886 opts
[ekey_num
].ch
= 'n';
2887 opts
[ekey_num
].rval
= 'n';
2888 opts
[ekey_num
].name
= "N";
2889 opts
[ekey_num
++].label
= "filterNow";
2892 opts
[ekey_num
].ch
= -1;
2894 return(radio_buttons(prompt
, -FOOTER_ROWS(ps
), opts
,
2895 deefault
, 'x', NO_HELP
, RB_NORM
));
2901 * Process the command list, changing function key notation into
2902 * lexical equivalents.
2905 process_init_cmds(struct pine
*ps
, char **list
)
2911 #define MAX_INIT_CMDS 500
2912 /* this is just a temporary stack array, the real one is allocated below */
2913 int i_cmds
[MAX_INIT_CMDS
];
2918 for(p
= list
; *p
; p
++){
2919 if(i
>= MAX_INIT_CMDS
){
2920 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
2921 "Initial keystroke list too long at \"%s\"", *p
);
2922 init_error(ps
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
2927 /* regular character commands */
2928 if(strlen(*p
) == 1){
2933 /* special commands */
2934 else if(strucmp(*p
, "SPACE") == 0)
2936 else if(strucmp(*p
, "CR") == 0)
2938 else if(strucmp(*p
, "TAB") == 0)
2940 else if(strucmp(*p
, "UP") == 0)
2941 i_cmds
[i
++] = KEY_UP
;
2942 else if(strucmp(*p
, "DOWN") == 0)
2943 i_cmds
[i
++] = KEY_DOWN
;
2944 else if(strucmp(*p
, "LEFT") == 0)
2945 i_cmds
[i
++] = KEY_LEFT
;
2946 else if(strucmp(*p
, "RIGHT") == 0)
2947 i_cmds
[i
++] = KEY_RIGHT
;
2950 else if(strlen(*p
) == 2 && **p
== '^')
2951 i_cmds
[i
++] = ctrl(*((*p
)+1));
2954 else if(**p
== 'F' || **p
== 'f'){
2959 if(v
>= 1 && v
<= 12)
2960 i_cmds
[i
++] = PF1
+ v
- 1;
2962 i_cmds
[i
++] = KEY_JUNK
;
2965 /* literal string */
2966 else if(**p
== '"' && (*p
)[lpm1
= strlen(*p
) - 1] == '"'){
2967 if(lpm1
+ i
- 1 > MAX_INIT_CMDS
){
2968 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
2969 "Initial keystroke list too long, truncated at %s\n", *p
);
2970 init_error(ps
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
2971 break; /* Bail out of this loop! */
2973 for(j
= 1; j
< lpm1
; j
++)
2974 i_cmds
[i
++] = (*p
)[j
];
2977 snprintf(tmp_20k_buf
,SIZEOF_20KBUF
,
2978 "Bad initial keystroke \"%.500s\" (missing comma?)", *p
);
2979 init_error(ps
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
2986 * We don't handle the case where function keys are used to specify the
2987 * commands but some non-function key input is also required. For example,
2988 * you might want to jump to a specific message number and view it
2989 * on start up. To do that, you need to use character commands instead
2990 * of function key commands in the initial-keystroke-list.
2992 if(fkeys
&& not_fkeys
){
2993 init_error(ps
, SM_ORDER
| SM_DING
, 3, 5,
2994 "Mixed characters and function keys in \"initial-keystroke-list\", skipping.");
2998 if(fkeys
&& !not_fkeys
)
2999 F_TURN_ON(F_USE_FK
,ps
);
3000 if(!fkeys
&& not_fkeys
)
3001 F_TURN_OFF(F_USE_FK
,ps
);
3004 ps
->initial_cmds
= (int *)fs_get((i
+1) * sizeof(int));
3005 ps
->free_initial_cmds
= ps
->initial_cmds
;
3006 for(j
= 0; j
< i
; j
++)
3007 ps
->initial_cmds
[j
] = i_cmds
[j
];
3009 ps
->initial_cmds
[i
] = 0;
3010 ps
->in_init_seq
= ps
->save_in_init_seq
= 1;
3016 user_wordseps(char **list
)
3021 #define MAX_SEPARATORS 500
3023 * This is just a temporary stack array, the real one is allocated below.
3024 * This is supposed to be way large enough.
3026 UCS seps
[MAX_SEPARATORS
+1];
3028 UCS
*return_array
= NULL
;
3034 for(p
= list
; *p
; p
++){
3035 if(i
>= MAX_SEPARATORS
){
3036 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3037 "Warning: composer-word-separators list is too long");
3041 u
= utf8_to_ucs4_cpystr(*p
);
3044 if(ucs4_strlen(u
) == 1)
3046 else if(*u
== '"' && u
[l
= ucs4_strlen(u
) - 1] == '"'){
3047 if(l
+ i
- 1 > MAX_SEPARATORS
){
3048 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3049 "Warning: composer-word-separators list is too long");
3050 break; /* Bail out of this loop! */
3053 for(j
= 1; j
< l
; j
++)
3059 if(l
+ i
> MAX_SEPARATORS
){
3060 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3061 "Warning: composer-word-separators list is too long");
3062 break; /* Bail out of this loop! */
3065 for(j
= 0; j
< l
; j
++)
3070 fs_give((void **) &u
);
3078 return_array
= ucs4_cpystr(seps
);
3080 return(return_array
);
3085 * Make sure any errors during initialization get queued for display
3088 queue_init_errors(struct pine
*ps
)
3093 for(i
= 0; (ps
->init_errs
)[i
].message
; i
++){
3094 q_status_message((ps
->init_errs
)[i
].flags
,
3095 (ps
->init_errs
)[i
].min_time
,
3096 (ps
->init_errs
)[i
].max_time
,
3097 (ps
->init_errs
)[i
].message
);
3098 fs_give((void **)&(ps
->init_errs
)[i
].message
);
3101 fs_give((void **)&ps
->init_errs
);
3106 /*----------------------------------------------------------------------
3107 Quit pine if the user wants to
3109 Args: The usual pine structure
3111 Result: User is asked if she wants to quit, if yes then execute quit.
3115 Not really a full screen. Just count up deletions and ask if we really
3119 quit_screen(struct pine
*pine_state
)
3123 dprint((1, "\n\n ---- QUIT SCREEN ----\n"));
3125 if(F_ON(F_CHECK_MAIL_ONQUIT
,ps_global
)
3126 && new_mail(1, VeryBadTime
, NM_STATUS_MSG
| NM_DEFER_SORT
) > 0
3127 && (quit
= want_to(_("Quit even though new mail just arrived"), 'y', 0,
3128 NO_HELP
, WT_NORM
)) != 'y'){
3129 refresh_sort(pine_state
->mail_stream
, pine_state
->msgmap
, SRT_VRB
);
3130 pine_state
->next_screen
= pine_state
->prev_screen
;
3135 && F_OFF(F_QUIT_WO_CONFIRM
,pine_state
)
3136 && want_to(_("Really quit Alpine"), 'y', 0, NO_HELP
, WT_NORM
) != 'y'){
3137 pine_state
->next_screen
= pine_state
->prev_screen
;
3141 goodnight_gracey(pine_state
, 0);
3145 /*----------------------------------------------------------------------
3146 The nuts and bolts of actually cleaning up and exitting pine
3148 Args: ps -- the usual pine structure,
3149 exit_val -- what to tell our parent
3151 Result: This never returns
3155 goodnight_gracey(struct pine
*pine_state
, int exit_val
)
3157 int i
, cnt_user_streams
= 0;
3158 char *final_msg
= NULL
;
3159 char msg
[MAX_SCREEN_COLS
+1];
3160 char *pf
= _("Alpine finished");
3162 extern KBESC_T
*kbesc
;
3164 dprint((2, "goodnight_gracey:\n"));
3166 /* We want to do this here before we close up the streams */
3167 trim_remote_adrbks();
3169 for(i
= 0; i
< ps_global
->s_pool
.nstream
; i
++){
3170 m
= ps_global
->s_pool
.streams
[i
];
3171 if(m
&& sp_flagged(m
, SP_LOCKED
) && sp_flagged(m
, SP_USERFLDR
))
3175 /* clean up open streams */
3177 if(pine_state
->mail_stream
3178 && sp_flagged(pine_state
->mail_stream
, SP_LOCKED
)
3179 && sp_flagged(pine_state
->mail_stream
, SP_USERFLDR
)){
3180 dprint((5, "goodnight_gracey: close current stream\n"));
3181 expunge_and_close(pine_state
->mail_stream
,
3182 (cnt_user_streams
<= 1) ? &final_msg
: NULL
, EC_NONE
);
3186 pine_state
->mail_stream
= NULL
;
3187 pine_state
->redrawer
= (void (*)(void))NULL
;
3190 "goodnight_gracey: close other stream pool streams\n"));
3191 for(i
= 0; i
< ps_global
->s_pool
.nstream
; i
++){
3192 m
= ps_global
->s_pool
.streams
[i
];
3194 * fix global for functions that depend(ed) on it sort_folder.
3195 * Hopefully those will get phased out.
3197 ps_global
->mail_stream
= m
;
3198 if(m
&& sp_flagged(m
, SP_LOCKED
) && sp_flagged(m
, SP_USERFLDR
)
3199 && !sp_flagged(m
, SP_INBOX
)){
3200 sp_set_expunge_count(m
, 0L);
3201 expunge_and_close(m
, (cnt_user_streams
<= 1) ? &final_msg
: NULL
,
3207 for(i
= 0; i
< ps_global
->s_pool
.nstream
; i
++){
3208 m
= ps_global
->s_pool
.streams
[i
];
3210 * fix global for functions that depend(ed) on it (sort_folder).
3211 * Hopefully those will get phased out.
3213 ps_global
->mail_stream
= m
;
3214 if(m
&& sp_flagged(m
, SP_LOCKED
) && sp_flagged(m
, SP_USERFLDR
)
3215 && sp_flagged(m
, SP_INBOX
)){
3217 "goodnight_gracey: close inbox stream stream\n"));
3218 sp_set_expunge_count(m
, 0L);
3219 expunge_and_close(m
, (cnt_user_streams
<= 1) ? &final_msg
: NULL
,
3227 (void)get_windsize(ps_global
->ttyo
);
3230 dprint((7, "goodnight_gracey: close config files\n"));
3236 free_pinerc_strings(&pine_state
);
3238 strncpy(msg
, pf
, sizeof(msg
));
3239 msg
[sizeof(msg
)-1] = '\0';
3241 strncat(msg
, " -- ", sizeof(msg
)-strlen(msg
)-1);
3242 msg
[sizeof(msg
)-1] = '\0';
3243 strncat(msg
, final_msg
, sizeof(msg
)-strlen(msg
)-1);
3244 msg
[sizeof(msg
)-1] = '\0';
3245 fs_give((void **)&final_msg
);
3248 dprint((7, "goodnight_gracey: sp_end\n"));
3249 ps_global
->noshow_error
= 1;
3252 /* after sp_end, which might call a filter */
3253 completely_done_with_adrbks();
3255 dprint((7, "goodnight_gracey: end_screen\n"));
3256 end_screen(msg
, exit_val
);
3257 dprint((7, "goodnight_gracey: end_titlebar\n"));
3259 dprint((7, "goodnight_gracey: end_keymenu\n"));
3262 dprint((7, "goodnight_gracey: end_keyboard\n"));
3263 end_keyboard(F_ON(F_USE_FK
,pine_state
));
3264 dprint((7, "goodnight_gracey: end_ttydriver\n"));
3265 end_tty_driver(pine_state
);
3266 #if !defined(DOS) && !defined(OS2)
3268 #if !defined(LEAVEOUTFIFO)
3269 close_newmailfifo();
3273 if(filter_data_file(0))
3274 our_unlink(filter_data_file(0));
3276 imap_flush_passwd_cache(TRUE
);
3277 free_newsgrp_cache();
3279 close_every_pattern();
3281 free_contexts(&ps_global
->context_list
);
3282 free_charsetchecker();
3283 dprint((7, "goodnight_gracey: free more memory\n"));
3285 free_saved_query_parameters();
3288 free_pine_struct(&pine_state
);
3295 fputs("goodnight_gracey finished\n", debugfile
);
3305 /*----------------------------------------------------------------------
3306 Call back for c-client to feed us back the progress of network reads
3313 pine_read_progress(GETS_DATA
*md
, long unsigned int count
)
3315 gets_bytes
+= count
; /* update counter */
3319 /*----------------------------------------------------------------------
3320 Function to fish the current byte count from a c-client fetch.
3322 Input: reset -- flag telling us to reset the count
3324 Result: Returns the number of bytes read by the c-client so far
3327 pine_gets_bytes(int reset
)
3336 /*----------------------------------------------------------------------
3337 Panic pine - call on detected programmatic errors to exit pine
3339 Args: message -- message to record in debug file and to be printed for user
3341 Result: The various tty modes are restored
3342 If debugging is active a core dump will be generated
3345 This is also called from imap routines and fs_get and fs_resize.
3348 alpine_panic(char *message
)
3352 /* global variable in .../pico/edef.h */
3355 if(ps_global
->ttyo
){
3356 end_screen(NULL
, -1);
3357 end_keyboard(ps_global
!= NULL
? F_ON(F_USE_FK
,ps_global
) : 0);
3358 end_tty_driver(ps_global
);
3361 if(filter_data_file(0))
3362 our_unlink(filter_data_file(0));
3364 dprint((1, "\n===========================================\n\n"));
3365 dprint((1, " Alpine Panic: %s\n\n", message
? message
: "?"));
3366 dprint((1, "===========================================\n\n"));
3368 /* intercept c-client "free storage" errors */
3369 if(strstr(message
, "free storage"))
3370 snprintf(buf
, sizeof(buf
), _("No more available memory.\nAlpine Exiting"));
3372 snprintf(buf
, sizeof(buf
), _("Problem detected: \"%s\".\nAlpine Exiting."), message
);
3374 buf
[sizeof(buf
)-1] = '\0';
3377 /* Put up a message box. */
3378 mswin_messagebox (buf
, 1);
3380 fprintf(stderr
, "\n\n%s\n", buf
);
3385 save_debug_on_crash(debugfile
, recent_keystroke
);
3388 coredump(); /*--- If we're debugging get a core dump --*/
3392 fatal("ffo"); /* BUG -- hack to get fatal out of library in right order*/
3397 * panicking - function to test whether or not we're exiting under stress.
3407 /*----------------------------------------------------------------------
3408 exceptional_exit - called to exit under unusual conditions (with no core)
3410 Args: message -- message to record in debug file and to be printed for user
3415 exceptional_exit(char *message
, int ev
)
3417 fprintf(stderr
, "%s\n", message
);
3423 * PicoText Storage Object Support Routines
3429 return((STORE_S
*)pico_get());
3433 pine_pico_give(STORE_S
**sop
)
3435 pico_give((void *)sop
);
3440 pine_pico_writec(int c
, STORE_S
*so
)
3442 unsigned char ch
= (unsigned char) c
;
3444 return(pico_writec(so
->txt
, ch
, PICOREADC_NONE
));
3448 pine_pico_writec_noucs(int c
, STORE_S
*so
)
3450 unsigned char ch
= (unsigned char) c
;
3452 return(pico_writec(so
->txt
, ch
, PICOREADC_NOUCS
));
3456 pine_pico_readc(unsigned char *c
, STORE_S
*so
)
3458 return(pico_readc(so
->txt
, c
, PICOREADC_NONE
));
3462 pine_pico_readc_noucs(unsigned char *c
, STORE_S
*so
)
3464 return(pico_readc(so
->txt
, c
, PICOREADC_NOUCS
));
3468 pine_pico_puts(STORE_S
*so
, char *s
)
3470 return(pico_puts(so
->txt
, s
, PICOREADC_NONE
));
3474 pine_pico_puts_noucs(STORE_S
*so
, char *s
)
3476 return(pico_puts(so
->txt
, s
, PICOREADC_NOUCS
));
3480 pine_pico_seek(STORE_S
*so
, long pos
, int orig
)
3482 return(pico_seek((void *)so
, pos
, orig
));
3487 remote_pinerc_failure(void)
3490 if(ps_global
->install_flag
) /* just exit silently */
3492 #endif /* _WINDOWS */
3494 if(ps_global
->exit_if_no_pinerc
){
3495 exceptional_exit("Exiting because -bail option is set and config file not readable.", -1);
3498 if(want_to("Trouble reading remote configuration! Continue anyway ",
3499 'n', 'n', NO_HELP
, WT_FLUSH_IN
) != 'y'){
3508 dump_supported_options(void)
3512 config
= get_supported_options();
3514 display_args_err(NULL
, config
, 0);
3515 free_list_array(&config
);
3520 /*----------------------------------------------------------------------
3521 Check pruned-folders for validity, making sure they are in the
3522 same context as sent-mail.
3526 prune_folders_ok(void)
3530 for(p
= ps_global
->VAR_PRUNED_FOLDERS
; p
&& *p
&& **p
; p
++)
3531 if(!context_isambig(*p
))
3540 pine_user_callback()
3542 if(ps_global
->VAR_USER_ID
&& ps_global
->VAR_USER_ID
[0]){
3543 return(ps_global
->VAR_USER_ID
);
3546 /* SHOULD PROMPT HERE! */
3554 * windows callback to get/set function keys mode state
3557 fkey_mode_callback(set
, args
)
3561 return(F_ON(F_USE_FK
, ps_global
) != 0);
3568 if(ps_global
->mail_stream
)
3569 mail_debug(ps_global
->mail_stream
);
3574 imap_telemetry_off()
3576 if(ps_global
->mail_stream
)
3577 mail_nodebug(ps_global
->mail_stream
);
3582 pcpine_help_main(title
)
3586 strncpy(title
, _("PC-Alpine MAIN MENU Help"), 256);
3588 return(pcpine_help(main_menu_tx
));
3593 pcpine_main_cursor(col
, row
)
3599 if (row
>= (HEADER_ROWS(ps_global
) + MNSKIP(ps_global
)))
3600 ndmi
= (row
+1 - HEADER_ROWS(ps_global
) - (MNSKIP(ps_global
)+1))/(MNSKIP(ps_global
)+1);
3602 if (row
>= (HEADER_ROWS(ps_global
) + MNSKIP(ps_global
))
3603 && !(MNSKIP(ps_global
) && (row
+1) & 0x01)
3604 && ndmi
<= MAX_MENU_ITEM
3605 && FOOTER_ROWS(ps_global
) + (ndmi
+1)*(MNSKIP(ps_global
)+1)
3606 + MNSKIP(ps_global
) + FOOTER_ROWS(ps_global
) <= ps_global
->ttyo
->screen_rows
)
3607 return(MSWIN_CURSOR_HAND
);
3609 return(MSWIN_CURSOR_ARROW
);
3611 #endif /* _WINDOWS */