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-2016 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(do_broach_folder(args
.data
.folder
, cntxt
, NULL
, notrealinbox
? 0L : DB_INBOXWOCNTXT
) <= 0){
1183 q_status_message1(SM_ORDER
, 3, 4,
1184 _("Unable to open folder \"%s\""), args
.data
.folder
);
1186 goodnight_gracey(pine_state
, -1);
1189 else if(args
.action
== aaFolder
){
1192 * need to ask for the inbox name if no default under DOS
1193 * since there is no "inbox"
1196 if(!pine_state
->VAR_INBOX_PATH
|| !pine_state
->VAR_INBOX_PATH
[0]
1197 || strucmp(pine_state
->VAR_INBOX_PATH
, "inbox") == 0){
1198 HelpType help
= NO_HELP
;
1199 static ESCKEY_S ekey
[] = {{ctrl(T
), 2, "^T", "To Fldrs"},
1200 {-1, 0, NULL
, NULL
}};
1202 pine_state
->mangled_footer
= 1;
1205 int flags
= OE_APPEND_CURRENT
;
1207 rv
= optionally_enter(int_mail
, -FOOTER_ROWS(pine_state
),
1208 0, sizeof(int_mail
),
1209 _("No inbox! Folder to open as inbox : "),
1210 /* ekey */ NULL
, help
, &flags
);
1212 help
= (help
== NO_HELP
) ? h_sticky_inbox
: NO_HELP
;
1221 q_status_message(SM_ORDER
, 0, 2 ,_("Folder open cancelled"));
1222 rv
= 0; /* reset rv */
1225 show_main_screen(pine_state
,0,FirstMenu
,km
,0,(Pos
*)NULL
);
1229 removing_trailing_white_space(int_mail
);
1230 removing_leading_white_space(int_mail
);
1231 if((!pine_state
->VAR_INBOX_PATH
1232 || strucmp(pine_state
->VAR_INBOX_PATH
, "inbox") == 0)
1233 /* TRANSLATORS: Inbox-Path and PINERC are literal, not to be translated */
1234 && want_to(_("Preserve folder as \"Inbox-Path\" in PINERC"),
1235 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
1236 set_variable(V_INBOX_PATH
, int_mail
, 1, 1, Main
);
1239 if(pine_state
->VAR_INBOX_PATH
)
1240 fs_give((void **)&pine_state
->VAR_INBOX_PATH
);
1242 pine_state
->VAR_INBOX_PATH
= cpystr(int_mail
);
1245 if(pine_state
&& pine_state
->ttyo
){
1246 blank_keymenu(pine_state
->ttyo
->screen_rows
- 2, 0);
1247 pine_state
->painted_footer_on_startup
= 0;
1248 pine_state
->mangled_footer
= 1;
1251 do_broach_folder(pine_state
->inbox_name
,
1252 pine_state
->context_list
, NULL
, DB_INBOXWOCNTXT
);
1255 q_status_message(SM_ORDER
, 0, 2 ,_("No folder opened"));
1260 #endif /* _WINDOWS */
1261 if(F_ON(F_PREOPEN_STAYOPENS
, ps_global
))
1262 preopen_stayopen_folders();
1264 if(pine_state
&& pine_state
->ttyo
){
1265 blank_keymenu(pine_state
->ttyo
->screen_rows
- 2, 0);
1266 pine_state
->painted_footer_on_startup
= 0;
1267 pine_state
->mangled_footer
= 1;
1271 do_broach_folder(pine_state
->inbox_name
,
1272 pine_state
->context_list
, NULL
, DB_INBOXWOCNTXT
);
1275 if(pine_state
->mangled_footer
)
1276 pine_state
->painted_footer_on_startup
= 0;
1278 if(args
.action
== aaFolder
1279 && pine_state
->mail_stream
1280 && expire_sent_mail())
1281 pine_state
->painted_footer_on_startup
= 0;
1284 * Initialize the defaults. Initializing here means that
1285 * if they're remote, the user isn't prompted for an imap login
1286 * before the display's drawn, AND there's the chance that
1287 * we can climb onto the already opened folder's stream...
1289 if(ps_global
->first_time_user
)
1290 init_save_defaults(); /* initialize default save folders */
1292 build_path(int_mail
,
1293 ps_global
->VAR_OPER_DIR
? ps_global
->VAR_OPER_DIR
1294 : pine_state
->home_dir
,
1295 INTERRUPTED_MAIL
, sizeof(int_mail
));
1296 if(args
.action
== aaFolder
1297 && (folder_exists(NULL
, int_mail
) & FEX_ISFILE
))
1298 q_status_message(SM_ORDER
| SM_DING
, 4, 5,
1299 _("Use Compose command to continue interrupted message."));
1301 #if defined(USE_QUOTAS)
1305 q
= disk_quota(pine_state
->home_dir
, &over
);
1307 q_status_message2(SM_ASYNC
| SM_DING
, 4, 5,
1308 _("WARNING! Over your disk quota by %s bytes (%s)"),
1309 comatose(q
),byte_string(q
));
1314 pine_state
->in_init_seq
= pine_state
->save_in_init_seq
;
1315 pine_state
->dont_use_init_cmds
= 0;
1318 if(pine_state
->give_fixed_warning
)
1319 q_status_message(SM_ASYNC
, 0, 10,
1320 /* TRANSLATORS: config is an abbreviation for configuration */
1321 _("Note: some of your config options conflict with site policy and are ignored"));
1323 if(!prune_folders_ok())
1324 q_status_message(SM_ASYNC
, 0, 10,
1325 /* TRANSLATORS: Pruned-Folders is literal */
1326 _("Note: ignoring Pruned-Folders outside of default collection for saves"));
1328 if(get_input_timeout() == 0 &&
1329 ps_global
->VAR_INBOX_PATH
&&
1330 ps_global
->VAR_INBOX_PATH
[0] == '{')
1331 q_status_message(SM_ASYNC
, 0, 10,
1332 _("Note: Mail-Check-Interval=0 may cause IMAP server connection to time out"));
1335 mswin_setnewmailwidth(ps_global
->nmw_width
);
1339 /*-------------------------------------------------------------------
1340 Loop executing the commands
1342 This is done like this so that one command screen can cause
1343 another one to execute it with out going through the main menu.
1344 ------------------------------------------------------------------*/
1345 if(!pine_state
->next_screen
)
1346 pine_state
->next_screen
= pine_state
->start_in_index
1347 ? mail_index_screen
: main_menu_screen
;
1349 if(pine_state
->next_screen
== SCREEN_FUN_NULL
)
1350 pine_state
->next_screen
= main_menu_screen
;
1352 (*(pine_state
->next_screen
))(pine_state
);
1361 * The arguments need to be converted to UTF-8 for our internal use.
1362 * Not all arguments are converted because some are used before we
1363 * are able to do the conversion, like the pinerc name.
1366 convert_args_to_utf8(struct pine
*ps
, ARGDATA_S
*args
)
1368 char *fromcharset
= NULL
;
1372 if(ps
->keyboard_charmap
&& strucmp(ps
->keyboard_charmap
, "UTF-8")
1373 && strucmp(ps
->keyboard_charmap
, "US-ASCII"))
1374 fromcharset
= ps
->keyboard_charmap
;
1375 else if(ps
->display_charmap
&& strucmp(ps
->display_charmap
, "UTF-8")
1376 && strucmp(ps
->display_charmap
, "US-ASCII"))
1377 fromcharset
= ps
->display_charmap
;
1379 else if(ps
->VAR_OLD_CHAR_SET
&& strucmp(ps
->VAR_OLD_CHAR_SET
, "UTF-8")
1380 && strucmp(ps
->VAR_OLD_CHAR_SET
, "US-ASCII"))
1381 fromcharset
= ps
->VAR_OLD_CHAR_SET
;
1382 #endif /* ! _WINDOWS */
1384 if(args
->action
== aaURL
&& args
->url
){
1385 conv
= convert_to_utf8(args
->url
, fromcharset
, 0);
1387 fs_give((void **) &args
->url
);
1392 if(args
->action
== aaFolder
&& args
->data
.folder
){
1393 conv
= convert_to_utf8(args
->data
.folder
, fromcharset
, 0);
1395 fs_give((void **) &args
->data
.folder
);
1396 args
->data
.folder
= conv
;
1400 if(args
->action
== aaMore
&& args
->data
.file
){
1401 conv
= convert_to_utf8(args
->data
.file
, fromcharset
, 0);
1403 fs_give((void **) &args
->data
.file
);
1404 args
->data
.file
= conv
;
1408 if(args
->action
== aaURL
|| args
->action
== aaMail
){
1409 if(args
->data
.mail
.addrlist
){
1412 for(p
= args
->data
.mail
.addrlist
; p
; p
=p
->next
){
1414 conv
= convert_to_utf8(p
->name
, fromcharset
, 0);
1416 fs_give((void **) &p
->name
);
1423 if(args
->data
.mail
.attachlist
){
1426 for(p
= args
->data
.mail
.attachlist
; p
; p
=p
->next
){
1428 conv
= convert_to_utf8(p
->filename
, fromcharset
, 0);
1430 fs_give((void **) &p
->filename
);
1442 preopen_stayopen_folders(void)
1446 for(open_these
= ps_global
->VAR_PERMLOCKED
;
1447 open_these
&& *open_these
; open_these
++)
1448 (void) do_broach_folder(*open_these
, ps_global
->context_list
,
1454 * read_stdin_char - simple function to return a character from
1458 read_stdin_char(char *c
)
1462 /* it'd probably be a good idea to fix this to pre-read blocks */
1464 rv
= read(PIPED_FD
, c
, 1);
1467 dprint((2, "read_stdin_char: read interrupted, restarting\n"));
1471 dprint((1, "read_stdin_char: read FAILED: %s\n",
1472 error_description(errno
)));
1480 /* this default is from the array of structs below */
1481 #define DEFAULT_MENU_ITEM ((unsigned) 3) /* LIST FOLDERS */
1482 #define ABOOK_MENU_ITEM ((unsigned) 4) /* ADDRESS BOOK */
1483 #define MAX_MENU_ITEM ((unsigned) 6)
1485 * Skip this many spaces between rows of main menu screen.
1486 * We have MAX_MENU_ITEM+1 = # of commands in menu
1487 * 1 = copyright line
1488 * MAX_MENU_ITEM = rows between commands
1489 * 1 = extra row above commands
1490 * 1 = row between commands and copyright
1492 * To make it simple, if there is enough room for all of that include all the
1493 * extra space, if not, cut it all out.
1495 #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)
1497 static unsigned menu_index
= DEFAULT_MENU_ITEM
;
1500 * One of these for each line that gets printed in the middle of the
1501 * screen in the main menu.
1503 static struct menu_key
{
1506 int key_index
; /* index into keymenu array for this cmd */
1509 * TRANSLATORS: These next few are headings on the Main alpine menu.
1510 * It's nice if the dashes can be made to line up vertically.
1512 {N_(" %s HELP - Get help using Alpine"),
1513 NULL
, MAIN_HELP_KEY
},
1514 {N_(" %s COMPOSE MESSAGE - Compose and send%s a message"),
1515 /* TRANSLATORS: We think of sending an email message or posting a news message.
1516 The message is shown as Compose and send/post a message */
1517 N_("/post"), MAIN_COMPOSE_KEY
},
1518 {N_(" %s MESSAGE INDEX - View messages in current folder"),
1519 NULL
, MAIN_INDEX_KEY
},
1520 {N_(" %s FOLDER LIST - Select a folder%s to view"),
1521 /* TRANSLATORS: When news is supported the message above becomes
1522 Select a folder OR news group to view */
1523 N_(" OR news group"), MAIN_FOLDER_KEY
},
1524 {N_(" %s ADDRESS BOOK - Update address book"),
1525 NULL
, MAIN_ADDRESS_KEY
},
1526 {N_(" %s SETUP - Configure Alpine Options"),
1527 NULL
, MAIN_SETUP_KEY
},
1528 /* TRANSLATORS: final Main menu line */
1529 {N_(" %s QUIT - Leave the Alpine program"),
1530 NULL
, MAIN_QUIT_KEY
}
1535 /*----------------------------------------------------------------------
1536 display main menu and execute main menu commands
1538 Args: The usual pine structure
1540 Result: main menu commands are executed
1543 M A I N M E N U S C R E E N
1545 Paint the main menu on the screen, get the commands and either execute
1546 the function or pass back the name of the function to execute for the menu
1547 selection. Only simple functions that always return here can be executed
1550 This functions handling of new mail, redrawing, errors and such can
1551 serve as a template for the other screen that do much the same thing.
1553 There is a loop that fetchs and executes commands until a command to leave
1554 this screen is given. Then the name of the next screen to display is
1555 stored in next_screen member of the structure and this function is exited
1558 First a check for new mail is performed. This might involve reading the new
1559 mail into the inbox which might then cause the screen to be repainted.
1561 Then the general screen painting is done. This is usually controlled
1562 by a few flags and some other position variables. If they change they
1563 tell this part of the code what to repaint. This will include cursor
1567 main_menu_screen(struct pine
*pine_state
)
1570 int cmd
, just_a_navigate_cmd
, setup_command
, km_popped
;
1572 char *new_folder
, *utf8str
;
1574 struct key_menu
*km
;
1578 ps_global
= pine_state
;
1579 just_a_navigate_cmd
= 0;
1581 menu_index
= DEFAULT_MENU_ITEM
;
1582 what
= FirstMenu
; /* which keymenu to display */
1583 ch
= 'x'; /* For display_message 1st time through */
1584 pine_state
->next_screen
= SCREEN_FUN_NULL
;
1585 pine_state
->prev_screen
= main_menu_screen
;
1586 curs_pos
.row
= pine_state
->ttyo
->screen_rows
-FOOTER_ROWS(pine_state
);
1590 mailcap_free(); /* free resources we won't be using for a while */
1592 if(!pine_state
->painted_body_on_startup
1593 && !pine_state
->painted_footer_on_startup
){
1594 pine_state
->mangled_screen
= 1;
1597 dprint((1, "\n\n ---- MAIN_MENU_SCREEN ----\n"));
1603 clearfooter(pine_state
);
1604 pine_state
->mangled_body
= 1;
1609 * fix up redrawer just in case some submenu caused it to get
1612 pine_state
->redrawer
= main_redrawer
;
1614 /*----------- Check for new mail -----------*/
1615 if(new_mail(0, NM_TIMING(ch
), NM_STATUS_MSG
| NM_DEFER_SORT
) >= 0)
1616 pine_state
->mangled_header
= 1;
1619 pine_state
->mangled_header
= 1;
1621 show_main_screen(pine_state
, just_a_navigate_cmd
, what
, km
,
1622 km_popped
, &curs_pos
);
1623 just_a_navigate_cmd
= 0;
1626 /*---- This displays new mail notification, or errors ---*/
1628 FOOTER_ROWS(pine_state
) = 3;
1629 mark_status_dirty();
1632 display_message(ch
);
1634 FOOTER_ROWS(pine_state
) = 1;
1635 mark_status_dirty();
1638 if(F_OFF(F_SHOW_CURSOR
, ps_global
)){
1639 curs_pos
.row
=pine_state
->ttyo
->screen_rows
-FOOTER_ROWS(pine_state
);
1643 MoveCursor(curs_pos
.row
, curs_pos
.col
);
1645 /*------ Read the command from the keyboard ----*/
1647 mouse_in_content(KEY_MOUSE
, -1, -1, 0, 0);
1648 register_mfunc(mouse_in_content
, HEADER_ROWS(pine_state
), 0,
1649 pine_state
->ttyo
->screen_rows
-(FOOTER_ROWS(pine_state
)+1),
1650 pine_state
->ttyo
->screen_cols
);
1652 #if defined(DOS) || defined(OS2)
1654 * AND pre-build header lines. This works just fine under
1655 * DOS since we wait for characters in a loop. Something will
1656 * will have to change under UNIX if we want to do the same.
1658 /* while_waiting = build_header_cache; */
1660 mswin_sethelptextcallback(pcpine_help_main
);
1661 mswin_mousetrackcallback(pcpine_main_cursor
);
1664 ch
= READ_COMMAND(&utf8str
);
1666 clear_mfunc(mouse_in_content
);
1668 #if defined(DOS) || defined(OS2)
1669 /* while_waiting = NULL; */
1671 mswin_sethelptextcallback(NULL
);
1672 mswin_mousetrackcallback(NULL
);
1676 /* No matter what, Quit here always works */
1677 if(ch
== 'q' || ch
== 'Q'){
1681 else if(debug
&& ch
&& ch
< 0x80 && strchr("123456789", ch
)){
1687 ps_global
->debug_timestamp
= 1;
1689 ps_global
->debug_timestamp
= 0;
1692 ps_global
->debug_imap
= 4;
1694 ps_global
->debug_imap
= 3;
1696 ps_global
->debug_imap
= 2;
1698 ps_global
->debug_imap
= 1;
1700 ps_global
->debug_imap
= 0;
1702 if(ps_global
->mail_stream
){
1703 if(ps_global
->debug_imap
> 0){
1704 mail_debug(ps_global
->mail_stream
);
1706 mswin_enableimaptelemetry(TRUE
);
1710 mail_nodebug(ps_global
->mail_stream
);
1712 mswin_enableimaptelemetry(FALSE
);
1717 if(debug
> 7 && olddebug
<= 7)
1718 mail_parameters(NULL
, SET_TCPDEBUG
, (void *) TRUE
);
1719 else if(debug
<= 7 && olddebug
> 7 && !ps_global
->debugmem
)
1720 mail_parameters(NULL
, SET_TCPDEBUG
, (void *) FALSE
);
1722 dprint((1, "*** Debug level set to %d ***\n", debug
));
1726 q_status_message1(SM_ORDER
, 0, 1, _("Debug level set to %s"),
1732 cmd
= menu_command(ch
, km
);
1744 clearfooter(pine_state
);
1749 /*------ Execute the command ------*/
1752 /*------ HELP ------*/
1755 if(FOOTER_ROWS(pine_state
) == 1 && km_popped
== 0){
1757 pine_state
->mangled_footer
= 1;
1760 /* TRANSLATORS: This is a screen title */
1761 helper(main_menu_tx
, _("HELP FOR MAIN MENU"), 0);
1762 pine_state
->mangled_screen
= 1;
1768 /*---------- display other key bindings ------*/
1774 pine_state
->mangled_footer
= 1;
1778 /*---------- Previous item in menu ----------*/
1780 if(menu_index
> 0) {
1782 pine_state
->mangled_body
= 1;
1784 pine_state
->mangled_footer
= 1;
1786 just_a_navigate_cmd
++;
1789 /* TRANSLATORS: list refers to list of commands in main menu */
1790 q_status_message(SM_ORDER
, 0, 2, _("Already at top of list"));
1795 /*---------- Next item in menu ----------*/
1797 if(menu_index
< MAX_MENU_ITEM
){
1799 pine_state
->mangled_body
= 1;
1801 pine_state
->mangled_footer
= 1;
1803 just_a_navigate_cmd
++;
1806 q_status_message(SM_ORDER
, 0, 2, _("Already at bottom of list"));
1811 /*---------- Release Notes ----------*/
1813 /* TRANSLATORS: This is a screen title */
1814 helper(h_news
, _("ALPINE RELEASE NOTES"), 0);
1815 pine_state
->mangled_screen
= 1;
1819 #ifdef KEYBOARD_LOCK
1820 /*---------- Keyboard lock ----------*/
1822 (void) lock_keyboard();
1823 pine_state
->mangled_screen
= 1;
1825 #endif /* KEYBOARD_LOCK */
1828 /*---------- Quit pine ----------*/
1830 pine_state
->next_screen
= quit_screen
;
1834 /*---------- Go to composer ----------*/
1836 pine_state
->next_screen
= compose_screen
;
1840 /*---- Go to alternate composer ------*/
1842 pine_state
->next_screen
= alt_compose_screen
;
1846 /*---------- Top of Folder list ----------*/
1847 case MC_COLLECTIONS
:
1848 pine_state
->next_screen
= folder_screen
;
1852 /*---------- Goto new folder ----------*/
1854 tc
= ps_global
->context_current
;
1855 new_folder
= broach_folder(-FOOTER_ROWS(pine_state
), 1, ¬realinbox
, &tc
);
1857 visit_folder(ps_global
, new_folder
, tc
, NULL
, notrealinbox
? 0L : DB_INBOXWOCNTXT
);
1862 /*---------- Go to index ----------*/
1865 && sp_viewing_a_thread(pine_state
->mail_stream
)
1866 && unview_thread(pine_state
, pine_state
->mail_stream
,
1867 pine_state
->msgmap
)){
1868 pine_state
->view_skipped_index
= 0;
1869 pine_state
->mangled_screen
= 1;
1872 pine_state
->next_screen
= mail_index_screen
;
1876 /*---------- Review Status Messages ----------*/
1879 pine_state
->mangled_screen
= 1;
1883 /*---------- Setup mini menu ----------*/
1886 setup_command
= setup_menu(pine_state
);
1887 pine_state
->mangled_footer
= 1;
1888 do_setup_task(setup_command
);
1889 if(ps_global
->next_screen
!= main_menu_screen
)
1895 /*---------- Go to address book ----------*/
1897 pine_state
->next_screen
= addr_book_screen
;
1901 /*------ Repaint the works -------*/
1905 pine_state
->mangled_screen
= 1;
1910 /*------- Mouse event ------*/
1915 struct pine
*ps
= pine_state
;
1917 mouse_get_last (NULL
, &mp
);
1920 if(mp
.button
== M_BUTTON_RIGHT
){
1921 if(!mp
.doubleclick
){
1922 static MPopup main_popup
[] = {
1923 {tQueue
, {"Folder List", lNormal
}, {'L'}},
1924 {tQueue
, {"Message Index", lNormal
}, {'I'}},
1926 {tQueue
, {"Address Book", lNormal
}, {'A'}},
1927 {tQueue
, {"Setup Options", lNormal
}, {'S'}},
1931 mswin_popup(main_popup
);
1936 if (mp
.row
>= (HEADER_ROWS(ps
) + MNSKIP(ps
)))
1937 ndmi
= (mp
.row
+1 - HEADER_ROWS(ps
) - (MNSKIP(ps
)+1))/(MNSKIP(ps
)+1);
1939 if (mp
.row
>= (HEADER_ROWS(ps
) + MNSKIP(ps
))
1940 && !(MNSKIP(ps
) && (mp
.row
+1) & 0x01)
1941 && ndmi
<= MAX_MENU_ITEM
1942 && FOOTER_ROWS(ps
) + (ndmi
+1)*(MNSKIP(ps
)+1)
1943 + MNSKIP(ps
) + FOOTER_ROWS(ps
) <= ps
->ttyo
->screen_rows
){
1945 switch(ndmi
){ /* fake main_screen request */
1950 pine_state
->next_screen
= compose_screen
;
1954 pine_state
->next_screen
= mail_index_screen
;
1958 pine_state
->next_screen
= folder_screen
;
1962 pine_state
->next_screen
= addr_book_screen
;
1969 pine_state
->next_screen
= quit_screen
;
1972 default: /* no op */
1978 pine_state
->mangled_body
= 1;
1980 pine_state
->mangled_footer
= 1;
1982 just_a_navigate_cmd
++;
1994 /*------ Input timeout ------*/
1996 break; /* noop for timeout loop mail check */
1999 /*------ Bogus Input ------*/
2001 if(ch
== 'm' || ch
== 'M'){
2002 q_status_message(SM_ORDER
, 0, 1, "Already in Main Menu");
2007 bogus_command(ch
, F_ON(F_USE_FK
,pine_state
) ? "F1" : "?");
2011 bogus_utf8_command(utf8str
, F_ON(F_USE_FK
, pine_state
) ? "F1" : "?");
2014 } /* the BIG while loop! */
2018 /*----------------------------------------------------------------------
2019 Re-Draw the main menu
2023 Result: main menu is re-displayed
2028 struct key_menu
*km
= &main_keymenu
;
2030 ps_global
->mangled_screen
= 1;
2031 show_main_screen(ps_global
, 0, FirstMenu
, km
, 0, (Pos
*)NULL
);
2035 /*----------------------------------------------------------------------
2038 Args: pine_state - the usual struct
2039 quick_draw - tells do_menu() it can skip some drawing
2040 what - tells which section of keymenu to draw
2042 cursor_pos - returns a good position for the cursor to be located
2044 Result: main menu is displayed
2047 show_main_screen(struct pine
*ps
, int quick_draw
, OtherMenu what
,
2048 struct key_menu
*km
, int km_popped
, Pos
*cursor_pos
)
2050 if(ps
->painted_body_on_startup
|| ps
->painted_footer_on_startup
){
2051 ps
->mangled_screen
= 0; /* only worry about it here */
2052 ps
->mangled_header
= 1; /* we have to redo header */
2053 if(!ps
->painted_body_on_startup
)
2054 ps
->mangled_body
= 1; /* make sure to paint body*/
2056 if(!ps
->painted_footer_on_startup
)
2057 ps
->mangled_footer
= 1; /* make sure to paint footer*/
2059 ps
->painted_body_on_startup
= 0;
2060 ps
->painted_footer_on_startup
= 0;
2063 if(ps
->mangled_screen
){
2064 ps
->mangled_header
= 1;
2065 ps
->mangled_body
= 1;
2066 ps
->mangled_footer
= 1;
2067 ps
->mangled_screen
= 0;
2071 /* Reset the scroll range. Main screen never scrolls. */
2072 scroll_setrange (0L, 0L);
2073 mswin_beginupdate();
2076 /* paint the titlebar if needed */
2077 if(ps
->mangled_header
){
2078 /* TRANSLATORS: screen title */
2079 set_titlebar(_("MAIN MENU"), ps
->mail_stream
, ps
->context_current
,
2080 ps
->cur_folder
, ps
->msgmap
, 1, FolderName
, 0, 0, NULL
);
2081 ps
->mangled_header
= 0;
2084 /* paint the body if needed */
2085 if(ps
->mangled_body
){
2089 do_menu(quick_draw
, cursor_pos
, km
);
2090 ps
->mangled_body
= 0;
2093 /* paint the keymenu if needed */
2094 if(km
&& ps
->mangled_footer
){
2095 static char label
[LONGEST_LABEL
+ 2 + 1], /* label + brackets + \0 */
2101 #ifdef KEYBOARD_LOCK
2102 if(ps_global
->restricted
|| F_ON(F_DISABLE_KBLOCK_CMD
,ps_global
))
2104 clrbitn(MAIN_KBLOCK_KEY
, bitmap
);
2106 menu_clear_binding(km
, '>');
2107 menu_clear_binding(km
, '.');
2108 menu_clear_binding(km
, KEY_RIGHT
);
2109 menu_clear_binding(km
, ctrl('M'));
2110 menu_clear_binding(km
, ctrl('J'));
2111 km
->keys
[MAIN_DEFAULT_KEY
].bind
2112 = km
->keys
[mkeys
[menu_index
].key_index
].bind
;
2113 km
->keys
[MAIN_DEFAULT_KEY
].label
2114 = km
->keys
[mkeys
[menu_index
].key_index
].label
;
2116 /* put brackets around the default action */
2117 snprintf(label
, sizeof(label
), "[%s]", km
->keys
[mkeys
[menu_index
].key_index
].label
);
2118 label
[sizeof(label
)-1] = '\0';
2119 strncpy(name
, ">", sizeof(name
));
2120 name
[sizeof(name
)-1] = '\0';
2121 km
->keys
[MAIN_DEFAULT_KEY
].label
= label
;
2122 km
->keys
[MAIN_DEFAULT_KEY
].name
= name
;
2123 menu_add_binding(km
, '>', km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2124 menu_add_binding(km
, '.', km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2125 menu_add_binding(km
, ctrl('M'), km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2126 menu_add_binding(km
, ctrl('J'), km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2128 if(F_ON(F_ARROW_NAV
,ps_global
))
2129 menu_add_binding(km
, KEY_RIGHT
, km
->keys
[MAIN_DEFAULT_KEY
].bind
.cmd
);
2132 FOOTER_ROWS(ps
) = 3;
2136 draw_keymenu(km
, bitmap
, ps_global
->ttyo
->screen_cols
,
2137 1-FOOTER_ROWS(ps_global
), 0, what
);
2138 ps
->mangled_footer
= 0;
2140 FOOTER_ROWS(ps
) = 1;
2141 mark_keymenu_dirty();
2151 /*----------------------------------------------------------------------
2152 Actually display the main menu
2154 Args: quick_draw - just a next or prev command was typed so we only have
2155 to redraw the highlighting
2156 cursor_pos - a place to return a good value for cursor location
2158 Result: Main menu is displayed
2161 do_menu(int quick_draw
, Pos
*cursor_pos
, struct key_menu
*km
)
2163 struct pine
*ps
= ps_global
;
2164 int dline
, indent
, longest
= 0, cmd
;
2165 char buf
[4*MAX_SCREEN_COLS
+1];
2166 char buf2
[4*MAX_SCREEN_COLS
+1];
2167 static int last_inverse
= -1;
2170 /* find the longest command */
2171 for(cmd
= 0; cmd
< sizeof(mkeys
)/(sizeof(mkeys
[1])); cmd
++){
2172 memset((void *) buf
, ' ', sizeof(buf
));
2173 snprintf(buf
, sizeof(buf
), mkeys
[cmd
].key_and_name
[0] ? _(mkeys
[cmd
].key_and_name
) : "",
2175 && km
->keys
[mkeys
[cmd
].key_index
].name
)
2176 ? km
->keys
[mkeys
[cmd
].key_index
].name
: "",
2177 (ps
->VAR_NEWS_SPEC
&& mkeys
[cmd
].news_addition
&& mkeys
[cmd
].news_addition
[0])
2178 ? _(mkeys
[cmd
].news_addition
) : "");
2179 buf
[sizeof(buf
)-1] = '\0';
2181 if(longest
< (indent
= utf8_width(buf
)))
2185 indent
= MAX(((ps
->ttyo
->screen_cols
- longest
)/2) - 1, 0);
2187 dline
= HEADER_ROWS(ps
) + MNSKIP(ps
);
2188 for(cmd
= 0; cmd
< sizeof(mkeys
)/(sizeof(mkeys
[1])); cmd
++){
2189 /* leave room for copyright and footer */
2190 if(dline
+ MNSKIP(ps
) + 1 + FOOTER_ROWS(ps
) >= ps
->ttyo
->screen_rows
)
2193 if(quick_draw
&& !(cmd
== last_inverse
|| cmd
== menu_index
)){
2194 dline
+= (1 + MNSKIP(ps
));
2198 if(cmd
== menu_index
)
2201 memset((void *) buf
, ' ', sizeof(buf
));
2202 snprintf(buf
, sizeof(buf
), mkeys
[cmd
].key_and_name
[0] ? _(mkeys
[cmd
].key_and_name
) : "",
2204 && km
->keys
[mkeys
[cmd
].key_index
].name
)
2205 ? km
->keys
[mkeys
[cmd
].key_index
].name
: "",
2206 (ps
->VAR_NEWS_SPEC
&& mkeys
[cmd
].news_addition
&& mkeys
[cmd
].news_addition
[0])
2207 ? _(mkeys
[cmd
].news_addition
) : "");
2208 buf
[sizeof(buf
)-1] = '\0';
2210 utf8_pad_to_width(buf2
, buf
, sizeof(buf2
),
2211 MIN(ps
->ttyo
->screen_cols
-indent
,longest
+1), 1);
2214 PutLine0(pos
.row
, pos
.col
, buf2
);
2219 if(cmd
== menu_index
){
2221 cursor_pos
->row
= pos
.row
;
2222 /* 6 is 1 for the letter plus 5 spaces */
2223 cursor_pos
->col
= pos
.col
+ 6;
2224 if(F_OFF(F_USE_FK
,ps
))
2227 cursor_pos
->col
= MIN(cursor_pos
->col
, ps
->ttyo
->screen_cols
);
2235 last_inverse
= menu_index
;
2237 if(!quick_draw
&& FOOTER_ROWS(ps
)+1 < ps
->ttyo
->screen_rows
){
2238 utf8_to_width(buf2
, LEGAL_NOTICE
, sizeof(buf2
),
2239 ps
->ttyo
->screen_cols
-3, NULL
);
2240 PutLine0(ps
->ttyo
->screen_rows
- (FOOTER_ROWS(ps
)+1),
2241 MAX(0, ((ps
->ttyo
->screen_cols
-utf8_width(buf2
))/2)),
2250 choose_setup_cmd(int cmd
, MSGNO_S
*msgmap
, SCROLL_S
*sparms
)
2255 if(!(srv
= (SRV_S
*)sparms
->proc
.data
.p
)){
2256 sparms
->proc
.data
.p
= (SRV_S
*)fs_get(sizeof(*srv
));
2257 srv
= (SRV_S
*)sparms
->proc
.data
.p
;
2258 memset(srv
, 0, sizeof(*srv
));
2261 ps_global
->next_screen
= SCREEN_FUN_NULL
;
2304 case MC_SECURITY
: /* S/MIME setup screen */
2309 srv
->exc
= !srv
->exc
;
2310 menu_clear_binding(sparms
->keys
.menu
, 'x');
2312 if(sparms
->bar
.title
) fs_give((void **)&sparms
->bar
.title
);
2313 /* TRANSLATORS: screen title */
2314 sparms
->bar
.title
= cpystr(_("SETUP EXCEPTIONS"));
2315 ps_global
->mangled_header
= 1;
2316 /* TRANSLATORS: The reason the X is upper case in eXceptions
2317 is because the command key is X. It isn't necessary, just
2318 nice if it works. */
2319 menu_init_binding(sparms
->keys
.menu
, 'x', MC_EXCEPT
, "X",
2320 N_("not eXceptions"), SETUP_EXCEPT
);
2323 if(sparms
->bar
.title
) fs_give((void **)&sparms
->bar
.title
);
2324 /* TRANSLATORS: screen title */
2325 sparms
->bar
.title
= cpystr(_("SETUP"));
2326 ps_global
->mangled_header
= 1;
2327 menu_init_binding(sparms
->keys
.menu
, 'x', MC_EXCEPT
, "X",
2328 N_("eXceptions"), SETUP_EXCEPT
);
2331 if(sparms
->keys
.menu
->which
== 1)
2332 ps_global
->mangled_footer
= 1;
2338 #if defined(DOS) || defined(OS2)
2339 q_status_message(SM_ORDER
, 0, 2, _("Need argument \"-x <except_config>\" or \"PINERCEX\" file to use eXceptions"));
2341 q_status_message(SM_ORDER
, 0, 2, _("Need argument \"-x <except_config>\" or \".pinercex\" file to use eXceptions"));
2347 alpine_panic("Unexpected command in choose_setup_cmd");
2356 setup_menu(struct pine
*ps
)
2358 int ret
= 0, exceptions
= 0;
2359 int printer
= 0, passwd
= 0, config
= 0, sig
= 0, dir
= 0, smime
= 0, exc
= 0;
2364 if(!(store
= so_get(CharStar
, NULL
, EDIT_ACCESS
))){
2365 q_status_message(SM_ORDER
| SM_DING
, 3, 3, _("Error allocating space."));
2370 if(!ps_global
->vars
[V_PRINTER
].is_fixed
) /* printer can be changed */
2375 if(F_OFF(F_DISABLE_PASSWORD_CMD
,ps_global
)) /* password is allowed */
2379 if(F_OFF(F_DISABLE_CONFIG_SCREEN
,ps_global
)) /* config allowed */
2382 if(F_OFF(F_DISABLE_SIGEDIT_CMD
,ps_global
)) /* .sig editing is allowed */
2393 if(ps_global
->post_prc
)
2396 /* TRANSLATORS: starting here we have a whole screen of help text */
2397 so_puts(store
, _("This is the Setup screen for Alpine. Choose from the following commands:\n"));
2399 so_puts(store
, "\n");
2400 so_puts(store
, _("(E) Exit Setup:\n"));
2401 so_puts(store
, _(" This puts you back at the Main Menu.\n"));
2404 so_puts(store
, "\n");
2405 so_puts(store
, _("(X) eXceptions:\n"));
2406 so_puts(store
, _(" This command is different from the rest. It is not actually a command\n"));
2407 so_puts(store
, _(" itself. Instead, it is a toggle which modifies the behavior of the\n"));
2408 so_puts(store
, _(" other commands. You toggle Exceptions editing on and off with this\n"));
2409 so_puts(store
, _(" command. When it is off you will be editing (changing) your regular\n"));
2410 so_puts(store
, _(" configuration file. When it is on you will be editing your exceptions\n"));
2411 so_puts(store
, _(" configuration file. For example, you might want to type the command \n"));
2412 so_puts(store
, _(" \"eXceptions\" followed by \"Kolor\" to setup different screen colors\n"));
2413 so_puts(store
, _(" on a particular platform.\n"));
2414 so_puts(store
, _(" (Note: this command does not show up on the keymenu at the bottom of\n"));
2415 so_puts(store
, _(" the screen unless you press \"O\" for \"Other Commands\" --but you don't\n"));
2416 so_puts(store
, _(" need to press the \"O\" in order to invoke the command.)\n"));
2420 so_puts(store
, "\n");
2421 so_puts(store
, _("(P) Printer:\n"));
2422 so_puts(store
, _(" Allows you to set a default printer and to define custom\n"));
2423 so_puts(store
, _(" print commands.\n"));
2427 so_puts(store
, "\n");
2428 so_puts(store
, _("(N) Newpassword:\n"));
2429 so_puts(store
, _(" Change your password.\n"));
2433 so_puts(store
, "\n");
2434 so_puts(store
, _("(C) Config:\n"));
2435 so_puts(store
, _(" Allows you to set or unset many features of Alpine.\n"));
2436 so_puts(store
, _(" You may also set the values of many options with this command.\n"));
2440 so_puts(store
, "\n");
2441 so_puts(store
, _("(S) Signature:\n"));
2442 so_puts(store
, _(" Enter or edit a custom signature which will\n"));
2443 so_puts(store
, _(" be included with each new message you send.\n"));
2446 so_puts(store
, "\n");
2447 so_puts(store
, _("(A) AddressBooks:\n"));
2448 so_puts(store
, _(" Define a non-default address book.\n"));
2450 so_puts(store
, "\n");
2451 so_puts(store
, _("(L) collectionLists:\n"));
2452 so_puts(store
, _(" You may define groups of folders to help you better organize your mail.\n"));
2454 so_puts(store
, "\n");
2455 so_puts(store
, _("(R) Rules:\n"));
2456 so_puts(store
, _(" This has up to six sub-categories: Roles, Index Colors, Filters,\n"));
2457 so_puts(store
, _(" SetScores, Search, and Other. If the Index Colors option is\n"));
2458 so_puts(store
, _(" missing you may turn it on (if possible) with Setup/Kolor.\n"));
2459 so_puts(store
, _(" If Roles is missing it has probably been administratively disabled.\n"));
2462 so_puts(store
, "\n");
2463 so_puts(store
, _("(D) Directory:\n"));
2464 so_puts(store
, _(" Define an LDAP Directory server for Alpine's use. A directory server is\n"));
2465 so_puts(store
, _(" similar to an address book, but it is usually maintained by an\n"));
2466 so_puts(store
, _(" organization. It is similar to a telephone directory.\n"));
2469 so_puts(store
, "\n");
2470 so_puts(store
, _("(K) Kolor:\n"));
2471 so_puts(store
, _(" Set custom colors for various parts of the Alpine screens. For example, the\n"));
2472 so_puts(store
, _(" command key labels, the titlebar at the top of each page, and quoted\n"));
2473 so_puts(store
, _(" sections of messages you are viewing.\n"));
2476 so_puts(store
, "\n");
2477 so_puts(store
, _("(M) S/MIME:\n"));
2478 so_puts(store
, _(" Setup for using S/MIME to verify signed messages, decrypt\n"));
2479 so_puts(store
, _(" encrypted messages, and to sign or encrypt outgoing messages.\n"));
2482 so_puts(store
, "\n");
2483 so_puts(store
, _("(Z) RemoteConfigSetup:\n"));
2484 so_puts(store
, _(" This is a command you will probably only want to use once, if at all.\n"));
2485 so_puts(store
, _(" It helps you transfer your Alpine configuration data to an IMAP server,\n"));
2486 so_puts(store
, _(" where it will be accessible from any of the computers you read mail\n"));
2487 so_puts(store
, _(" from (using Alpine). The idea behind a remote configuration is that you\n"));
2488 so_puts(store
, _(" can change your configuration in one place and have that change show\n"));
2489 so_puts(store
, _(" up on all of the computers you use.\n"));
2490 so_puts(store
, _(" (Note: this command does not show up on the keymenu at the bottom of\n"));
2491 so_puts(store
, _(" the screen unless you press \"O\" for \"Other Commands\" --but you don't\n"));
2492 so_puts(store
, _(" need to press the \"O\" in order to invoke the command.)\n"));
2494 /* put this down here for people who don't have exceptions */
2496 so_puts(store
, "\n");
2497 so_puts(store
, _("(X) eXceptions:\n"));
2498 so_puts(store
, _(" This command is different from the rest. It is not actually a command\n"));
2499 so_puts(store
, _(" itself. Instead, it is a toggle which modifies the behavior of the\n"));
2500 so_puts(store
, _(" other commands. You toggle Exceptions editing on and off with this\n"));
2501 so_puts(store
, _(" command. When it is off you will be editing (changing) your regular\n"));
2502 so_puts(store
, _(" configuration file. When it is on you will be editing your exceptions\n"));
2503 so_puts(store
, _(" configuration file. For example, you might want to type the command \n"));
2504 so_puts(store
, _(" \"eXceptions\" followed by \"Kolor\" to setup different screen colors\n"));
2505 so_puts(store
, _(" on a particular platform.\n"));
2506 so_puts(store
, _(" (Note: this command does not do anything unless you have a configuration\n"));
2507 so_puts(store
, _(" with exceptions enabled (you don't have that). Common ways to enable an\n"));
2508 so_puts(store
, _(" exceptions config are the command line argument \"-x <exception_config>\";\n"));
2509 so_puts(store
, _(" or the existence of the file \".pinercex\" for Unix Alpine, or \"PINERCEX\")\n"));
2510 so_puts(store
, _(" for PC-Alpine.)\n"));
2511 so_puts(store
, _(" (Another note: this command does not show up on the keymenu at the bottom\n"));
2512 so_puts(store
, _(" of the screen unless you press \"O\" for \"Other Commands\" --but you\n"));
2513 so_puts(store
, _(" don't need to press the \"O\" in order to invoke the command.)\n"));
2516 memset(&sargs
, 0, sizeof(SCROLL_S
));
2517 sargs
.text
.text
= so_text(store
);
2518 sargs
.text
.src
= CharStar
;
2519 sargs
.text
.desc
= _("Information About Setup Command");
2520 sargs
.bar
.title
= cpystr(_("SETUP"));
2521 sargs
.proc
.tool
= choose_setup_cmd
;
2522 sargs
.help
.text
= NO_HELP
;
2523 sargs
.help
.title
= NULL
;
2524 sargs
.keys
.menu
= &choose_setup_keymenu
;
2525 sargs
.keys
.menu
->how_many
= 2;
2527 setbitmap(sargs
.keys
.bitmap
);
2529 clrbitn(SETUP_PRINTER
, sargs
.keys
.bitmap
);
2532 clrbitn(SETUP_PASSWD
, sargs
.keys
.bitmap
);
2535 clrbitn(SETUP_CONFIG
, sargs
.keys
.bitmap
);
2538 clrbitn(SETUP_SIG
, sargs
.keys
.bitmap
);
2541 clrbitn(SETUP_DIRECTORY
, sargs
.keys
.bitmap
);
2544 clrbitn(SETUP_SMIME
, sargs
.keys
.bitmap
);
2547 menu_init_binding(sargs
.keys
.menu
, 'x', MC_EXCEPT
, "X",
2548 N_("eXceptions"), SETUP_EXCEPT
);
2550 menu_init_binding(sargs
.keys
.menu
, 'x', MC_NO_EXCEPT
, "X",
2551 N_("eXceptions"), SETUP_EXCEPT
);
2556 ps
->mangled_screen
= 1;
2558 srv
= (SRV_S
*)sargs
.proc
.data
.p
;
2560 exceptions
= srv
? srv
->exc
: 0;
2564 if(sargs
.bar
.title
) fs_give((void**)&sargs
.bar
.title
);
2567 fs_give((void **)&sargs
.proc
.data
.p
);
2572 return(ret
| (exceptions
? EDIT_EXCEPTION
: 0));
2576 /*----------------------------------------------------------------------
2578 Args: command -- command char to perform
2582 do_setup_task(int command
)
2586 int edit_exceptions
= 0;
2589 if(command
& EDIT_EXCEPTION
){
2590 edit_exceptions
= 1;
2591 command
&= ~EDIT_EXCEPTION
;
2595 /*----- EDIT SIGNATURE -----*/
2597 if(ps_global
->VAR_LITERAL_SIG
)
2600 char sig_path
[MAXPATH
+1];
2602 if(!signature_path(ps_global
->VAR_SIGNATURE_FILE
, sig_path
, MAXPATH
))
2604 else if((!IS_REMOTE(ps_global
->VAR_SIGNATURE_FILE
)
2605 && can_access(sig_path
, READ_ACCESS
) == 0)
2606 ||(IS_REMOTE(ps_global
->VAR_SIGNATURE_FILE
)
2607 && (folder_exists(NULL
, sig_path
) & FEX_ISFILE
)))
2609 else if(!ps_global
->vars
[V_SIGNATURE_FILE
].main_user_val
.p
2610 && !ps_global
->vars
[V_SIGNATURE_FILE
].cmdline_val
.p
2611 && !ps_global
->vars
[V_SIGNATURE_FILE
].fixed_val
.p
)
2618 char *result
= NULL
;
2623 ew
= edit_exceptions
? ps_global
->ew_for_except_vars
: Main
;
2625 if(ps_global
->restricted
)
2629 readonly
= ps_global
->prc
->readonly
;
2632 readonly
= ps_global
->post_prc
->readonly
;
2639 err
= cpystr(ps_global
->restricted
2640 ? "Alpine demo can't change config file"
2641 : _("Config file not changeable"));
2644 apval
= APVAL(&ps_global
->vars
[V_LITERAL_SIG
], ew
);
2646 err
= cpystr(_("Problem accessing configuration"));
2650 input
= (char *)fs_get((strlen(*apval
? *apval
: "")+1) *
2653 cstring_to_string(*apval
, input
);
2654 err
= signature_edit_lit(input
, &result
,
2655 _("SIGNATURE EDITOR"),
2656 h_composer_sigedit
);
2657 fs_give((void **)&input
);
2662 char *cstring_version
;
2664 cstring_version
= string_to_cstring(result
);
2666 set_variable(V_LITERAL_SIG
, cstring_version
, 0, 0, ew
);
2669 fs_give((void **)&cstring_version
);
2673 fs_give((void **)&result
);
2676 err
= signature_edit(ps_global
->VAR_SIGNATURE_FILE
,
2677 _("SIGNATURE EDITOR"));
2680 q_status_message(SM_ORDER
, 3, 4, err
);
2681 fs_give((void **)&err
);
2684 ps_global
->mangled_screen
= 1;
2687 /*----- ADD ADDRESSBOOK ----*/
2689 addr_book_config(ps_global
, edit_exceptions
);
2690 menu_index
= ABOOK_MENU_ITEM
;
2691 ps_global
->mangled_screen
= 1;
2695 /*--- ADD DIRECTORY SERVER --*/
2697 directory_config(ps_global
, edit_exceptions
);
2698 ps_global
->mangled_screen
= 1;
2705 smime_config_screen(ps_global
, edit_exceptions
);
2706 ps_global
->mangled_screen
= 1;
2710 /*----- CONFIGURE OPTIONS -----*/
2712 option_screen(ps_global
, edit_exceptions
);
2713 ps_global
->mangled_screen
= 1;
2716 /*----- COLLECTION LIST -----*/
2718 folder_config_screen(ps_global
, edit_exceptions
);
2719 ps_global
->mangled_screen
= 1;
2722 /*----- RULES -----*/
2724 rtype
= rule_setup_type(ps_global
, RS_RULES
| RS_INCFILTNOW
,
2725 _("Type of rule setup : "));
2733 role_config_screen(ps_global
, (rtype
== 'r') ? ROLE_DO_ROLES
:
2734 (rtype
== 's') ? ROLE_DO_SCORES
:
2735 (rtype
== 'o') ? ROLE_DO_OTHER
:
2736 (rtype
== 'f') ? ROLE_DO_FILTER
:
2737 (rtype
== 'c') ? ROLE_DO_SRCH
:
2743 q_status_message(SM_ORDER
| SM_DING
, 3, 5,
2744 _("Try turning on color with the Setup/Kolor command."));
2748 role_process_filters();
2752 cmd_cancelled(NULL
);
2756 ps_global
->mangled_screen
= 1;
2759 /*----- COLOR -----*/
2761 color_config_screen(ps_global
, edit_exceptions
);
2762 ps_global
->mangled_screen
= 1;
2766 convert_to_remote_config(ps_global
, edit_exceptions
);
2767 ps_global
->mangled_screen
= 1;
2770 /*----- EXIT -----*/
2774 /*----- NEW PASSWORD -----*/
2777 if(ps_global
->restricted
){
2778 q_status_message(SM_ORDER
, 3, 5,
2779 "Password change unavailable in restricted demo version of Alpine.");
2783 ps_global
->mangled_screen
= 1;
2786 q_status_message(SM_ORDER
, 0, 5,
2787 _("Password changing not configured for this version of Alpine."));
2788 display_message('x');
2793 /*----- CHOOSE PRINTER ------*/
2795 select_printer(ps_global
, edit_exceptions
);
2796 ps_global
->mangled_screen
= 1;
2804 rule_setup_type(struct pine
*ps
, int flags
, char *prompt
)
2807 int ekey_num
= 0, deefault
= 0;
2809 if(flags
& RS_INCADDR
){
2811 opts
[ekey_num
].ch
= 'a';
2812 opts
[ekey_num
].rval
= 'a';
2813 opts
[ekey_num
].name
= "A";
2814 opts
[ekey_num
++].label
= "Addrbook";
2817 if(flags
& RS_RULES
){
2819 if(F_OFF(F_DISABLE_ROLES_SETUP
,ps
)){ /* roles are allowed */
2823 opts
[ekey_num
].ch
= 'r';
2824 opts
[ekey_num
].rval
= 'r';
2825 opts
[ekey_num
].name
= "R";
2826 opts
[ekey_num
++].label
= "Roles";
2828 else if(deefault
!= 'a')
2831 opts
[ekey_num
].ch
= 's';
2832 opts
[ekey_num
].rval
= 's';
2833 opts
[ekey_num
].name
= "S";
2834 opts
[ekey_num
++].label
= "SetScores";
2837 if(ps
->color_style
!= COL_NONE
&& pico_hascolor()){
2842 opts
[ekey_num
].ch
= 'i';
2843 opts
[ekey_num
].rval
= 'i';
2844 opts
[ekey_num
].name
= "I";
2845 opts
[ekey_num
++].label
= "Indexcolor";
2849 opts
[ekey_num
].ch
= 'i';
2850 opts
[ekey_num
].rval
= 'Z'; /* notice this rval! */
2851 opts
[ekey_num
].name
= "I";
2852 opts
[ekey_num
++].label
= "Indexcolor";
2856 opts
[ekey_num
].ch
= 'f';
2857 opts
[ekey_num
].rval
= 'f';
2858 opts
[ekey_num
].name
= "F";
2859 opts
[ekey_num
++].label
= "Filters";
2861 opts
[ekey_num
].ch
= 'o';
2862 opts
[ekey_num
].rval
= 'o';
2863 opts
[ekey_num
].name
= "O";
2864 opts
[ekey_num
++].label
= "Other";
2866 opts
[ekey_num
].ch
= 'c';
2867 opts
[ekey_num
].rval
= 'c';
2868 opts
[ekey_num
].name
= "C";
2869 opts
[ekey_num
++].label
= "searCh";
2873 if(flags
& RS_INCEXP
){
2874 opts
[ekey_num
].ch
= 'e';
2875 opts
[ekey_num
].rval
= 'e';
2876 opts
[ekey_num
].name
= "E";
2877 opts
[ekey_num
++].label
= "Export";
2880 if(flags
& RS_INCFILTNOW
){
2881 opts
[ekey_num
].ch
= 'n';
2882 opts
[ekey_num
].rval
= 'n';
2883 opts
[ekey_num
].name
= "N";
2884 opts
[ekey_num
++].label
= "filterNow";
2887 opts
[ekey_num
].ch
= -1;
2889 return(radio_buttons(prompt
, -FOOTER_ROWS(ps
), opts
,
2890 deefault
, 'x', NO_HELP
, RB_NORM
));
2896 * Process the command list, changing function key notation into
2897 * lexical equivalents.
2900 process_init_cmds(struct pine
*ps
, char **list
)
2906 #define MAX_INIT_CMDS 500
2907 /* this is just a temporary stack array, the real one is allocated below */
2908 int i_cmds
[MAX_INIT_CMDS
];
2913 for(p
= list
; *p
; p
++){
2914 if(i
>= MAX_INIT_CMDS
){
2915 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
2916 "Initial keystroke list too long at \"%s\"", *p
);
2917 init_error(ps
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
2922 /* regular character commands */
2923 if(strlen(*p
) == 1){
2928 /* special commands */
2929 else if(strucmp(*p
, "SPACE") == 0)
2931 else if(strucmp(*p
, "CR") == 0)
2933 else if(strucmp(*p
, "TAB") == 0)
2935 else if(strucmp(*p
, "UP") == 0)
2936 i_cmds
[i
++] = KEY_UP
;
2937 else if(strucmp(*p
, "DOWN") == 0)
2938 i_cmds
[i
++] = KEY_DOWN
;
2939 else if(strucmp(*p
, "LEFT") == 0)
2940 i_cmds
[i
++] = KEY_LEFT
;
2941 else if(strucmp(*p
, "RIGHT") == 0)
2942 i_cmds
[i
++] = KEY_RIGHT
;
2945 else if(strlen(*p
) == 2 && **p
== '^')
2946 i_cmds
[i
++] = ctrl(*((*p
)+1));
2949 else if(**p
== 'F' || **p
== 'f'){
2954 if(v
>= 1 && v
<= 12)
2955 i_cmds
[i
++] = PF1
+ v
- 1;
2957 i_cmds
[i
++] = KEY_JUNK
;
2960 /* literal string */
2961 else if(**p
== '"' && (*p
)[lpm1
= strlen(*p
) - 1] == '"'){
2962 if(lpm1
+ i
- 1 > MAX_INIT_CMDS
){
2963 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
2964 "Initial keystroke list too long, truncated at %s\n", *p
);
2965 init_error(ps
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
2966 break; /* Bail out of this loop! */
2968 for(j
= 1; j
< lpm1
; j
++)
2969 i_cmds
[i
++] = (*p
)[j
];
2972 snprintf(tmp_20k_buf
,SIZEOF_20KBUF
,
2973 "Bad initial keystroke \"%.500s\" (missing comma?)", *p
);
2974 init_error(ps
, SM_ORDER
| SM_DING
, 3, 5, tmp_20k_buf
);
2981 * We don't handle the case where function keys are used to specify the
2982 * commands but some non-function key input is also required. For example,
2983 * you might want to jump to a specific message number and view it
2984 * on start up. To do that, you need to use character commands instead
2985 * of function key commands in the initial-keystroke-list.
2987 if(fkeys
&& not_fkeys
){
2988 init_error(ps
, SM_ORDER
| SM_DING
, 3, 5,
2989 "Mixed characters and function keys in \"initial-keystroke-list\", skipping.");
2993 if(fkeys
&& !not_fkeys
)
2994 F_TURN_ON(F_USE_FK
,ps
);
2995 if(!fkeys
&& not_fkeys
)
2996 F_TURN_OFF(F_USE_FK
,ps
);
2999 ps
->initial_cmds
= (int *)fs_get((i
+1) * sizeof(int));
3000 ps
->free_initial_cmds
= ps
->initial_cmds
;
3001 for(j
= 0; j
< i
; j
++)
3002 ps
->initial_cmds
[j
] = i_cmds
[j
];
3004 ps
->initial_cmds
[i
] = 0;
3005 ps
->in_init_seq
= ps
->save_in_init_seq
= 1;
3011 user_wordseps(char **list
)
3016 #define MAX_SEPARATORS 500
3018 * This is just a temporary stack array, the real one is allocated below.
3019 * This is supposed to be way large enough.
3021 UCS seps
[MAX_SEPARATORS
+1];
3023 UCS
*return_array
= NULL
;
3029 for(p
= list
; *p
; p
++){
3030 if(i
>= MAX_SEPARATORS
){
3031 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3032 "Warning: composer-word-separators list is too long");
3036 u
= utf8_to_ucs4_cpystr(*p
);
3039 if(ucs4_strlen(u
) == 1)
3041 else if(*u
== '"' && u
[l
= ucs4_strlen(u
) - 1] == '"'){
3042 if(l
+ i
- 1 > MAX_SEPARATORS
){
3043 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3044 "Warning: composer-word-separators list is too long");
3045 break; /* Bail out of this loop! */
3048 for(j
= 1; j
< l
; j
++)
3054 if(l
+ i
> MAX_SEPARATORS
){
3055 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3056 "Warning: composer-word-separators list is too long");
3057 break; /* Bail out of this loop! */
3060 for(j
= 0; j
< l
; j
++)
3065 fs_give((void **) &u
);
3073 return_array
= ucs4_cpystr(seps
);
3075 return(return_array
);
3080 * Make sure any errors during initialization get queued for display
3083 queue_init_errors(struct pine
*ps
)
3088 for(i
= 0; (ps
->init_errs
)[i
].message
; i
++){
3089 q_status_message((ps
->init_errs
)[i
].flags
,
3090 (ps
->init_errs
)[i
].min_time
,
3091 (ps
->init_errs
)[i
].max_time
,
3092 (ps
->init_errs
)[i
].message
);
3093 fs_give((void **)&(ps
->init_errs
)[i
].message
);
3096 fs_give((void **)&ps
->init_errs
);
3101 /*----------------------------------------------------------------------
3102 Quit pine if the user wants to
3104 Args: The usual pine structure
3106 Result: User is asked if she wants to quit, if yes then execute quit.
3110 Not really a full screen. Just count up deletions and ask if we really
3114 quit_screen(struct pine
*pine_state
)
3118 dprint((1, "\n\n ---- QUIT SCREEN ----\n"));
3120 if(F_ON(F_CHECK_MAIL_ONQUIT
,ps_global
)
3121 && new_mail(1, VeryBadTime
, NM_STATUS_MSG
| NM_DEFER_SORT
) > 0
3122 && (quit
= want_to(_("Quit even though new mail just arrived"), 'y', 0,
3123 NO_HELP
, WT_NORM
)) != 'y'){
3124 refresh_sort(pine_state
->mail_stream
, pine_state
->msgmap
, SRT_VRB
);
3125 pine_state
->next_screen
= pine_state
->prev_screen
;
3130 && F_OFF(F_QUIT_WO_CONFIRM
,pine_state
)
3131 && want_to(_("Really quit Alpine"), 'y', 0, NO_HELP
, WT_NORM
) != 'y'){
3132 pine_state
->next_screen
= pine_state
->prev_screen
;
3136 goodnight_gracey(pine_state
, 0);
3140 /*----------------------------------------------------------------------
3141 The nuts and bolts of actually cleaning up and exitting pine
3143 Args: ps -- the usual pine structure,
3144 exit_val -- what to tell our parent
3146 Result: This never returns
3150 goodnight_gracey(struct pine
*pine_state
, int exit_val
)
3152 int i
, cnt_user_streams
= 0;
3153 char *final_msg
= NULL
;
3154 char msg
[MAX_SCREEN_COLS
+1];
3155 char *pf
= _("Alpine finished");
3157 extern KBESC_T
*kbesc
;
3159 dprint((2, "goodnight_gracey:\n"));
3161 /* We want to do this here before we close up the streams */
3162 trim_remote_adrbks();
3164 for(i
= 0; i
< ps_global
->s_pool
.nstream
; i
++){
3165 m
= ps_global
->s_pool
.streams
[i
];
3166 if(m
&& sp_flagged(m
, SP_LOCKED
) && sp_flagged(m
, SP_USERFLDR
))
3170 /* clean up open streams */
3172 if(pine_state
->mail_stream
3173 && sp_flagged(pine_state
->mail_stream
, SP_LOCKED
)
3174 && sp_flagged(pine_state
->mail_stream
, SP_USERFLDR
)){
3175 dprint((5, "goodnight_gracey: close current stream\n"));
3176 expunge_and_close(pine_state
->mail_stream
,
3177 (cnt_user_streams
<= 1) ? &final_msg
: NULL
, EC_NONE
);
3181 pine_state
->mail_stream
= NULL
;
3182 pine_state
->redrawer
= (void (*)(void))NULL
;
3185 "goodnight_gracey: close other stream pool streams\n"));
3186 for(i
= 0; i
< ps_global
->s_pool
.nstream
; i
++){
3187 m
= ps_global
->s_pool
.streams
[i
];
3189 * fix global for functions that depend(ed) on it sort_folder.
3190 * Hopefully those will get phased out.
3192 ps_global
->mail_stream
= m
;
3193 if(m
&& sp_flagged(m
, SP_LOCKED
) && sp_flagged(m
, SP_USERFLDR
)
3194 && !sp_flagged(m
, SP_INBOX
)){
3195 sp_set_expunge_count(m
, 0L);
3196 expunge_and_close(m
, (cnt_user_streams
<= 1) ? &final_msg
: NULL
,
3202 for(i
= 0; i
< ps_global
->s_pool
.nstream
; i
++){
3203 m
= ps_global
->s_pool
.streams
[i
];
3205 * fix global for functions that depend(ed) on it (sort_folder).
3206 * Hopefully those will get phased out.
3208 ps_global
->mail_stream
= m
;
3209 if(m
&& sp_flagged(m
, SP_LOCKED
) && sp_flagged(m
, SP_USERFLDR
)
3210 && sp_flagged(m
, SP_INBOX
)){
3212 "goodnight_gracey: close inbox stream stream\n"));
3213 sp_set_expunge_count(m
, 0L);
3214 expunge_and_close(m
, (cnt_user_streams
<= 1) ? &final_msg
: NULL
,
3222 (void)get_windsize(ps_global
->ttyo
);
3225 dprint((7, "goodnight_gracey: close config files\n"));
3231 free_pinerc_strings(&pine_state
);
3233 strncpy(msg
, pf
, sizeof(msg
));
3234 msg
[sizeof(msg
)-1] = '\0';
3236 strncat(msg
, " -- ", sizeof(msg
)-strlen(msg
)-1);
3237 msg
[sizeof(msg
)-1] = '\0';
3238 strncat(msg
, final_msg
, sizeof(msg
)-strlen(msg
)-1);
3239 msg
[sizeof(msg
)-1] = '\0';
3240 fs_give((void **)&final_msg
);
3243 dprint((7, "goodnight_gracey: sp_end\n"));
3244 ps_global
->noshow_error
= 1;
3247 /* after sp_end, which might call a filter */
3248 completely_done_with_adrbks();
3250 dprint((7, "goodnight_gracey: end_screen\n"));
3251 end_screen(msg
, exit_val
);
3252 dprint((7, "goodnight_gracey: end_titlebar\n"));
3254 dprint((7, "goodnight_gracey: end_keymenu\n"));
3257 dprint((7, "goodnight_gracey: end_keyboard\n"));
3258 end_keyboard(F_ON(F_USE_FK
,pine_state
));
3259 dprint((7, "goodnight_gracey: end_ttydriver\n"));
3260 end_tty_driver(pine_state
);
3261 #if !defined(DOS) && !defined(OS2)
3263 #if !defined(LEAVEOUTFIFO)
3264 close_newmailfifo();
3268 if(filter_data_file(0))
3269 our_unlink(filter_data_file(0));
3271 imap_flush_passwd_cache(TRUE
);
3272 free_newsgrp_cache();
3274 close_every_pattern();
3276 free_contexts(&ps_global
->context_list
);
3277 free_charsetchecker();
3278 dprint((7, "goodnight_gracey: free more memory\n"));
3280 free_saved_query_parameters();
3283 free_pine_struct(&pine_state
);
3290 fputs("goodnight_gracey finished\n", debugfile
);
3300 /*----------------------------------------------------------------------
3301 Call back for c-client to feed us back the progress of network reads
3308 pine_read_progress(GETS_DATA
*md
, long unsigned int count
)
3310 gets_bytes
+= count
; /* update counter */
3314 /*----------------------------------------------------------------------
3315 Function to fish the current byte count from a c-client fetch.
3317 Input: reset -- flag telling us to reset the count
3319 Result: Returns the number of bytes read by the c-client so far
3322 pine_gets_bytes(int reset
)
3331 /*----------------------------------------------------------------------
3332 Panic pine - call on detected programmatic errors to exit pine
3334 Args: message -- message to record in debug file and to be printed for user
3336 Result: The various tty modes are restored
3337 If debugging is active a core dump will be generated
3340 This is also called from imap routines and fs_get and fs_resize.
3343 alpine_panic(char *message
)
3347 /* global variable in .../pico/edef.h */
3350 if(ps_global
->ttyo
){
3351 end_screen(NULL
, -1);
3352 end_keyboard(ps_global
!= NULL
? F_ON(F_USE_FK
,ps_global
) : 0);
3353 end_tty_driver(ps_global
);
3356 if(filter_data_file(0))
3357 our_unlink(filter_data_file(0));
3359 dprint((1, "\n===========================================\n\n"));
3360 dprint((1, " Alpine Panic: %s\n\n", message
? message
: "?"));
3361 dprint((1, "===========================================\n\n"));
3363 /* intercept c-client "free storage" errors */
3364 if(strstr(message
, "free storage"))
3365 snprintf(buf
, sizeof(buf
), _("No more available memory.\nAlpine Exiting"));
3367 snprintf(buf
, sizeof(buf
), _("Problem detected: \"%s\".\nAlpine Exiting."), message
);
3369 buf
[sizeof(buf
)-1] = '\0';
3372 /* Put up a message box. */
3373 mswin_messagebox (buf
, 1);
3375 fprintf(stderr
, "\n\n%s\n", buf
);
3380 save_debug_on_crash(debugfile
, recent_keystroke
);
3383 coredump(); /*--- If we're debugging get a core dump --*/
3387 fatal("ffo"); /* BUG -- hack to get fatal out of library in right order*/
3392 * panicking - function to test whether or not we're exiting under stress.
3402 /*----------------------------------------------------------------------
3403 exceptional_exit - called to exit under unusual conditions (with no core)
3405 Args: message -- message to record in debug file and to be printed for user
3410 exceptional_exit(char *message
, int ev
)
3412 fprintf(stderr
, "%s\n", message
);
3418 * PicoText Storage Object Support Routines
3424 return((STORE_S
*)pico_get());
3428 pine_pico_give(STORE_S
**sop
)
3430 pico_give((void *)sop
);
3435 pine_pico_writec(int c
, STORE_S
*so
)
3437 unsigned char ch
= (unsigned char) c
;
3439 return(pico_writec(so
->txt
, ch
, PICOREADC_NONE
));
3443 pine_pico_writec_noucs(int c
, STORE_S
*so
)
3445 unsigned char ch
= (unsigned char) c
;
3447 return(pico_writec(so
->txt
, ch
, PICOREADC_NOUCS
));
3451 pine_pico_readc(unsigned char *c
, STORE_S
*so
)
3453 return(pico_readc(so
->txt
, c
, PICOREADC_NONE
));
3457 pine_pico_readc_noucs(unsigned char *c
, STORE_S
*so
)
3459 return(pico_readc(so
->txt
, c
, PICOREADC_NOUCS
));
3463 pine_pico_puts(STORE_S
*so
, char *s
)
3465 return(pico_puts(so
->txt
, s
, PICOREADC_NONE
));
3469 pine_pico_puts_noucs(STORE_S
*so
, char *s
)
3471 return(pico_puts(so
->txt
, s
, PICOREADC_NOUCS
));
3475 pine_pico_seek(STORE_S
*so
, long pos
, int orig
)
3477 return(pico_seek((void *)so
, pos
, orig
));
3482 remote_pinerc_failure(void)
3485 if(ps_global
->install_flag
) /* just exit silently */
3487 #endif /* _WINDOWS */
3489 if(ps_global
->exit_if_no_pinerc
){
3490 exceptional_exit("Exiting because -bail option is set and config file not readable.", -1);
3493 if(want_to("Trouble reading remote configuration! Continue anyway ",
3494 'n', 'n', NO_HELP
, WT_FLUSH_IN
) != 'y'){
3503 dump_supported_options(void)
3507 config
= get_supported_options();
3509 display_args_err(NULL
, config
, 0);
3510 free_list_array(&config
);
3515 /*----------------------------------------------------------------------
3516 Check pruned-folders for validity, making sure they are in the
3517 same context as sent-mail.
3521 prune_folders_ok(void)
3525 for(p
= ps_global
->VAR_PRUNED_FOLDERS
; p
&& *p
&& **p
; p
++)
3526 if(!context_isambig(*p
))
3535 pine_user_callback()
3537 if(ps_global
->VAR_USER_ID
&& ps_global
->VAR_USER_ID
[0]){
3538 return(ps_global
->VAR_USER_ID
);
3541 /* SHOULD PROMPT HERE! */
3549 * windows callback to get/set function keys mode state
3552 fkey_mode_callback(set
, args
)
3556 return(F_ON(F_USE_FK
, ps_global
) != 0);
3563 if(ps_global
->mail_stream
)
3564 mail_debug(ps_global
->mail_stream
);
3569 imap_telemetry_off()
3571 if(ps_global
->mail_stream
)
3572 mail_nodebug(ps_global
->mail_stream
);
3577 pcpine_help_main(title
)
3581 strncpy(title
, _("PC-Alpine MAIN MENU Help"), 256);
3583 return(pcpine_help(main_menu_tx
));
3588 pcpine_main_cursor(col
, row
)
3594 if (row
>= (HEADER_ROWS(ps_global
) + MNSKIP(ps_global
)))
3595 ndmi
= (row
+1 - HEADER_ROWS(ps_global
) - (MNSKIP(ps_global
)+1))/(MNSKIP(ps_global
)+1);
3597 if (row
>= (HEADER_ROWS(ps_global
) + MNSKIP(ps_global
))
3598 && !(MNSKIP(ps_global
) && (row
+1) & 0x01)
3599 && ndmi
<= MAX_MENU_ITEM
3600 && FOOTER_ROWS(ps_global
) + (ndmi
+1)*(MNSKIP(ps_global
)+1)
3601 + MNSKIP(ps_global
) + FOOTER_ROWS(ps_global
) <= ps_global
->ttyo
->screen_rows
)
3602 return(MSWIN_CURSOR_HAND
);
3604 return(MSWIN_CURSOR_ARROW
);
3606 #endif /* _WINDOWS */