Add support for tab-completion when selecting by rule
[alpine.git] / alpine / signal.c
blobb254a9d8bd476190663d60610997dd26ea708fd3
1 /* ========================================================================
2 * Copyright 2006-2008 University of Washington
3 * Copyright 2013-2022 Eduardo Chappa
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * ========================================================================
14 /*======================================================================
15 Different signal handlers for different signals
16 - Catches all the abort signals, cleans up tty modes and then coredumps
17 - Not much to do for SIGHUP
18 - Not much to do for SIGTERM
19 - turn SIGWINCH into a KEY_RESIZE command
20 - No signals for ^Z/suspend, but do it here anyway
21 - Also set up the signal handlers, and hold signals for
22 critical imap sections of code.
23 ====*/
26 #include "headers.h"
27 #include "alpine.h"
28 #include "signal.h"
29 #include "status.h"
30 #include "dispfilt.h"
31 #include "keymenu.h"
32 #include "titlebar.h"
33 #include "mailcmd.h"
34 #include "../pith/state.h"
35 #include "../pith/conf.h"
36 #include "../pith/detach.h"
37 #include "../pith/pipe.h"
38 #include "../pith/util.h"
39 #include "../pith/icache.h"
40 #include "../pith/newmail.h"
41 #include "../pith/imap.h"
42 #include "../pith/adrbklib.h"
43 #include "../pith/remote.h"
44 #include "../pith/osdep/pipe.h"
48 * Internal Prototypes
50 static RETSIGTYPE auger_in_signal(int);
51 void init_sighup(void);
52 void end_sighup(void);
53 RETSIGTYPE term_signal(void);
54 void fast_clean_up(void);
55 static RETSIGTYPE usr2_signal(int);
56 static RETSIGTYPE winch_signal(int);
57 static RETSIGTYPE intr_signal(int);
58 void suspend_notice(char *);
59 void suspend_warning(void);
63 static int cleanup_called_from_sig_handler;
67 /*----------------------------------------------------------------------
68 Install handlers for all the signals we care to catch
69 ----------------------------------------------------------------------*/
70 void
71 init_signals(void)
73 dprint((9, "init_signals()\n"));
74 init_sighup();
76 #ifdef _WINDOWS
77 #else
78 # ifdef DEBUG
79 # define CUSHION_SIG (debug < 7)
80 # else
81 # define CUSHION_SIG (1)
82 # endif
84 if(CUSHION_SIG){
85 signal(SIGILL, auger_in_signal);
86 signal(SIGTRAP, auger_in_signal);
87 # ifdef SIGEMT
88 signal(SIGEMT, auger_in_signal);
89 # endif
90 signal(SIGBUS, auger_in_signal);
91 signal(SIGSEGV, auger_in_signal);
92 signal(SIGSYS, auger_in_signal);
93 signal(SIGQUIT, auger_in_signal);
94 /* Don't catch SIGFPE cause it's rare and we use it in a hack below*/
97 init_sigwinch();
100 * Set up SIGUSR2 to catch signal from other software using the
101 * c-client to tell us that other access to the folder is being
102 * attempted. THIS IS A TEST: if it turns out that simply
103 * going R/O when another pine is started or the same folder is opened,
104 * then we may want to install a smarter handler that uses idle time
105 * or even prompts the user to see if it's ok to give up R/O access...
107 signal(SIGUSR2, usr2_signal);
109 signal(SIGPIPE, SIG_IGN);
110 signal(SIGINT, SIG_IGN);
112 # ifdef SIGTSTP
113 /* Some unexplained behaviour on Ultrix 4.2 (Hardy) seems to be
114 resulting in Pine getting sent a SIGTSTP. Ignore it here.
115 probably better to ignore it than let it happen in any case
117 signal(SIGTSTP, SIG_IGN);
118 # endif /* SIGTSTP */
120 # ifdef SIGCHLD
121 signal(SIGCHLD, child_signal);
122 # endif
123 #endif /* !_WINDOWS */
127 /*----------------------------------------------------------------------
128 Return all signal handling back to normal
129 ----------------------------------------------------------------------*/
130 void
131 end_signals(int blockem)
133 #ifdef _WINDOWS
135 signal(SIGHUP, blockem ? SIG_IGN : SIG_DFL);
137 #else
138 #ifndef SIG_ERR
139 #define SIG_ERR (RETSIGTYPE (*)())-1
140 #endif
142 dprint((5, "end_signals(%d)\n", blockem));
143 if(signal(SIGILL, blockem ? SIG_IGN : SIG_DFL) == SIG_ERR){
144 fprintf(stderr, "Error resetting signals: %s\n",
145 error_description(errno));
146 exit(-1);
149 signal(SIGTRAP, blockem ? SIG_IGN : SIG_DFL);
150 #ifdef SIGEMT
151 signal(SIGEMT, blockem ? SIG_IGN : SIG_DFL);
152 #endif
153 signal(SIGBUS, blockem ? SIG_IGN : SIG_DFL);
154 signal(SIGSEGV, blockem ? SIG_IGN : SIG_DFL);
155 signal(SIGSYS, blockem ? SIG_IGN : SIG_DFL);
156 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
157 signal(SIGWINCH, blockem ? SIG_IGN : SIG_DFL);
158 #endif
159 signal(SIGQUIT, blockem ? SIG_IGN : SIG_DFL);
160 #ifdef SIGTSTP
161 signal(SIGTSTP, blockem ? SIG_IGN : SIG_DFL);
162 #endif /* SIGTSTP */
163 signal(SIGHUP, blockem ? SIG_IGN : SIG_DFL);
164 signal(SIGTERM, blockem ? SIG_IGN : SIG_DFL);
165 signal(SIGINT, blockem ? SIG_IGN : SIG_DFL);
167 #endif /* !_WINDOWS */
171 /*----------------------------------------------------------------------
172 Handle signals caused by aborts -- SIGSEGV, SIGILL, etc
174 Call panic which cleans up tty modes and then core dumps
175 ----------------------------------------------------------------------*/
176 static RETSIGTYPE
177 auger_in_signal(int sig)
179 char buf[100];
181 end_signals(1); /* don't catch any more signals */
182 imap_flush_passwd_cache(FALSE);
184 snprintf(buf, sizeof(buf), "Received abort signal(sig=%d)", sig);
185 buf[sizeof(buf)-1] = '\0';
187 alpine_panic(buf); /* clean up and get out */
189 exit(-1); /* in case panic doesn't kill us */
193 /*----------------------------------------------------------------------
194 Install signal handler to deal with hang up signals -- SIGHUP, SIGTERM
196 ----------------------------------------------------------------------*/
197 void
198 init_sighup(void)
200 #if !(defined(DOS) && !defined(_WINDOWS))
201 #if defined(_WINDOWS) || defined(OS2)
202 signal(SIGHUP, (void *) hup_signal);
203 #else
204 signal(SIGHUP, hup_signal);
205 #endif
206 #endif
207 #if !(defined(DOS) || defined(OS2))
208 signal(SIGTERM, term_signal);
209 #endif
213 /*----------------------------------------------------------------------
214 De-Install signal handler to deal with hang up signals -- SIGHUP, SIGTERM
216 ----------------------------------------------------------------------*/
217 void
218 end_sighup(void)
220 #if !(defined(DOS) && !defined(_WINDOWS))
221 signal(SIGHUP, SIG_IGN);
222 #endif
223 #if !(defined(DOS) || defined(OS2))
224 signal(SIGTERM, SIG_IGN);
225 #endif
229 /*----------------------------------------------------------------------
230 handle hang up signal -- SIGHUP
232 Not much to do. Rely on periodic mail file check pointing.
233 ----------------------------------------------------------------------*/
234 RETSIGTYPE
235 hup_signal(void)
237 if(ps_global)
238 ps_global->signal_in_progress = 1;
239 end_signals(1); /* don't catch any more signals */
240 dprint((1, "\n\n** Received SIGHUP **\n\n\n\n"));
241 cleanup_called_from_sig_handler = 1;
242 fast_clean_up();
243 #if defined(DEBUG)
244 if(debugfile)
245 fclose(debugfile);
246 #endif
248 _exit(0); /* cleaning up can crash */
252 /*----------------------------------------------------------------------
253 Timeout when no user input for a long, long time.
254 Treat it pretty much the same as if we got a HUP.
255 Only difference is we sometimes turns the timeout off (when composing).
256 ----------------------------------------------------------------------*/
257 void
258 user_input_timeout_exit(int to_hours)
260 char msg[80];
262 dprint((1,
263 "\n\n** Exiting: user input timeout (%d hours) **\n\n\n\n",
264 to_hours));
265 snprintf(msg, sizeof(msg), _("\n\nAlpine timed out (No user input for %d %s)\n"), to_hours,
266 to_hours > 1 ? "hours" : "hour");
267 msg[sizeof(msg)-1] = '\0';
268 fast_clean_up();
269 end_screen(msg, 0);
270 end_titlebar();
271 end_keymenu();
272 end_keyboard(F_ON(F_USE_FK,ps_global));
273 end_tty_driver(ps_global);
274 end_signals(0);
275 #if defined(DEBUG) && (!defined(DOS) || defined(_WINDOWS))
276 if(debugfile)
277 fclose(debugfile);
278 #endif
279 exit(0);
283 /*----------------------------------------------------------------------
284 handle terminate signal -- SIGTERM
286 Not much to do. Rely on periodic mail file check pointing.
287 ----------------------------------------------------------------------*/
288 RETSIGTYPE
289 term_signal(void)
291 #if !defined(DOS) && !defined(OS2)
292 end_signals(1); /* don't catch any more signals */
293 dprint((1, "\n\n** Received SIGTERM **\n\n\n\n"));
294 cleanup_called_from_sig_handler = 1;
295 fast_clean_up();
296 #if defined(DEBUG) && (!defined(DOS) || defined(_WINDOWS))
297 if(debugfile)
298 fclose(debugfile);
299 #endif
300 printf(_("\n\nAlpine finished. Received terminate signal\n\n"));
301 #endif /* !DOS */
302 exit(0);
306 /*----------------------------------------------------------------------
307 Handle cleaning up mail streams and tty modes...
308 Not much to do. Rely on periodic mail file check pointing. Don't try
309 cleaning up screen or flushing output since stdout is likely already
310 gone. To be safe, though, we'll at least restore the original tty mode.
311 Also delete any remnant _DATAFILE_ from sending-filters.
312 ----------------------------------------------------------------------*/
313 void
314 fast_clean_up(void)
316 #if !defined(DOS) && !defined(OS2)
317 int i;
318 MAILSTREAM *m;
319 #endif
321 dprint((1, "fast_clean_up()\n"));
323 if(ps_global->expunge_in_progress){
324 PineRaw(0);
325 return;
329 * This gets rid of temporary cache files for remote addrbooks.
331 completely_done_with_adrbks();
334 * This flushes out deferred changes and gets rid of temporary cache
335 * files for remote config files.
337 if(ps_global->prc){
338 if(ps_global->prc->outstanding_pinerc_changes)
339 write_pinerc(ps_global, Main,
340 cleanup_called_from_sig_handler ? WRP_NOUSER : WRP_NONE);
342 if(ps_global->prc->rd)
343 rd_close_remdata(&ps_global->prc->rd);
345 free_pinerc_s(&ps_global->prc);
348 /* as does this */
349 if(ps_global->post_prc){
350 if(ps_global->post_prc->outstanding_pinerc_changes)
351 write_pinerc(ps_global, Post,
352 cleanup_called_from_sig_handler ? WRP_NOUSER : WRP_NONE);
354 if(ps_global->post_prc->rd)
355 rd_close_remdata(&ps_global->post_prc->rd);
357 free_pinerc_s(&ps_global->post_prc);
361 * Can't figure out why this section is inside the ifdef, but no
362 * harm leaving it that way, I guess.
364 #if !defined(DOS) && !defined(OS2)
365 for(i = 0; i < ps_global->s_pool.nstream; i++){
366 m = ps_global->s_pool.streams[i];
367 if(m && !m->lock)
368 pine_mail_actually_close(m);
371 PineRaw(0);
373 #endif /* !DOS */
375 imap_flush_passwd_cache(TRUE);
377 dprint((1, "done with fast_clean_up\n"));
381 #if !defined(DOS) && !defined(OS2)
382 /*----------------------------------------------------------------------
383 handle hang up signal -- SIGUSR2
385 Not much to do. Rely on periodic mail file check pointing.
386 ----------------------------------------------------------------------*/
387 static RETSIGTYPE
388 usr2_signal(int sig)
390 char c, *mbox, mboxbuf[20];
391 int i;
392 MAILSTREAM *stream;
393 NETMBX mb;
395 for(i = 0; i < ps_global->s_pool.nstream; i++){
396 stream = ps_global->s_pool.streams[i];
397 if(stream
398 && sp_flagged(stream, SP_LOCKED)
399 && !sp_dead_stream(stream)
400 && !stream->lock
401 && !stream->rdonly
402 && stream->mailbox
403 && (c = *stream->mailbox) != '{' && c != '*'){
404 pine_mail_check(stream); /* write latest state */
405 stream->rdonly = 1; /* and become read-only */
406 (void) pine_mail_ping(stream);
407 mbox = stream->mailbox;
408 if(!strucmp(stream->mailbox, ps_global->inbox_name)
409 || !strcmp(stream->mailbox, ps_global->VAR_INBOX_PATH)
410 || !strucmp(stream->original_mailbox, ps_global->inbox_name)
411 || !strcmp(stream->original_mailbox, ps_global->VAR_INBOX_PATH))
412 mbox = "INBOX";
413 else if(mail_valid_net_parse(stream->mailbox, &mb) && mb.mailbox)
414 mbox = mb.mailbox;
416 q_status_message1(SM_ASYNC, 3, 7,
417 _("Another email program is accessing %s. Session now Read-Only."),
418 short_str((mbox && *mbox) ? mbox : "folder",
419 mboxbuf, sizeof(mboxbuf), 19, FrontDots));
420 dprint((1, "** folder %s went read-only **\n\n",
421 stream->mailbox));
425 #endif
428 /*----------------------------------------------------------------------
429 Install signal handler to deal with window resize signal -- SIGWINCH
431 ----------------------------------------------------------------------*/
432 void
433 init_sigwinch (void)
435 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
436 signal(SIGWINCH, winch_signal);
437 #endif
441 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
442 /*----------------------------------------------------------------------
443 Handle window resize signal -- SIGWINCH
445 The planned strategy is just force a redraw command. This is similar
446 to new mail handling which forces a noop command. The signals are
447 help until pine reads input. Then a KEY_RESIZE is forced into the command
448 stream .
449 Note that ready_for_winch is only non-zero inside the read_char function,
450 so the longjmp only ever happens there, and it is really just a jump
451 from lower down in the function up to the top of that function. Its
452 purpose is to return a KEY_RESIZE from read_char when interrupted
453 out of the select lower down in read_char.
454 ----------------------------------------------------------------------*/
455 extern jmp_buf winch_state;
456 extern int ready_for_winch, winch_occured;
458 static RETSIGTYPE
459 winch_signal(int sig)
461 clear_cursor_pos();
462 init_sigwinch();
463 winch_cleanup();
465 #endif
469 * winch_cleanup -
471 void
472 winch_cleanup(void)
474 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
475 if(ready_for_winch)
476 longjmp(winch_state, 1);
477 else
478 winch_occured = 1;
479 #endif
483 #ifdef SIGCHLD
484 /*----------------------------------------------------------------------
485 Handle child status change -- SIGCHLD
487 The strategy here is to install the handler when we spawn a child, and
488 to let the system tell us when the child's state has changed. In the
489 mean time, we can do whatever. Typically, "whatever" is spinning in a
490 loop alternating between sleep and new_mail calls intended to keep the
491 IMAP stream alive.
493 ----------------------------------------------------------------------*/
494 static short child_signalled, child_jump;
495 static jmp_buf child_state;
497 RETSIGTYPE
498 child_signal(int sig)
500 #ifdef BACKGROUND_POST
502 * reap background posting process
504 if(ps_global->post && ps_global->post->pid){
505 pid_t pid;
506 int es;
508 pid = process_reap(ps_global->post->pid, &es, PR_NOHANG);
509 if(pid == ps_global->post->pid){
510 ps_global->post->status = es;
511 ps_global->post->pid = 0;
512 return;
514 else if(pid < 0 && errno != EINTR){
515 fs_give((void **) &ps_global->post);
518 #endif /* BACKGROUND_POST */
520 child_signalled = 1;
521 if(child_jump)
522 longjmp(child_state, 1);
524 #endif /* SIGCHLD */
528 * pipe_callback - handle pine-specific pipe setup like child
529 * signal handler and possibly any display stuff
530 * BUG: this function should probably be in a "alpine/pipe.c"
532 void
533 pipe_callback(PIPE_S *syspipe, int flags, void *data)
535 #ifdef _WINDOWS
536 bitmap_t bitmap;
537 #endif
538 if(flags & OSB_PRE_OPEN){
539 dprint((5, "Opening pipe: (%s%s%s%s%s%s)\n",
540 (syspipe->mode & PIPE_WRITE) ? "W":"", (syspipe->mode & PIPE_READ) ? "R":"",
541 (syspipe->mode & PIPE_NOSHELL) ? "N":"", (syspipe->mode & PIPE_PROT) ? "P":"",
542 (syspipe->mode & PIPE_USER) ? "U":"", (syspipe->mode & PIPE_RESET) ? "T":""));
544 #ifdef _WINDOWS
545 q_status_message(SM_ORDER, 0, 0,
546 "Waiting for called program to finish...");
548 flush_status_messages(1);
549 setbitmap(bitmap);
550 draw_keymenu(&pipe_cancel_keymenu, bitmap, ps_global->ttyo->screen_cols,
551 1-FOOTER_ROWS(ps_global), 0, FirstMenu);
552 #else /* UNIX */
554 if(!(syspipe->mode & (PIPE_WRITE | PIPE_READ)) && !(syspipe->mode & PIPE_SILENT)){
555 flush_status_messages(0); /* just clean up display */
556 ClearScreen();
557 fflush(stdout);
560 if(syspipe->mode & PIPE_RESET)
561 ttyfix(0);
563 #ifdef SIGCHLD
565 * Prepare for demise of child. Use SIGCHLD if it's available so
566 * we can do useful things, like keep the IMAP stream alive, while
567 * we're waiting on the child. The handler may have been changed by
568 * something in the composer, in particular, by an alt_editor call.
569 * So we need to re-set it to child_signal and then set it back
570 * when we're done.
572 child_signalled = child_jump = 0;
573 syspipe->chld = signal(SIGCHLD, child_signal);
574 #endif
575 #endif /* UNIX */
577 else if(flags & OSB_POST_OPEN){
578 #ifdef _WINDOWS
580 clearfooter(ps_global);
581 ps_global->mangled_footer = 1;
583 if((int) data == -2)
584 q_status_message1(SM_ORDER, 2, 3, "Ignoring completion of %s", syspipe->command);
586 #else /* UNIX */
587 if(!(syspipe->mode & (PIPE_WRITE | PIPE_READ)) && !(syspipe->mode & PIPE_SILENT)){
588 ClearScreen();
589 ps_global->mangled_screen = 1;
592 if(syspipe->mode & PIPE_RESET){
593 ttyfix(1);
594 ps_global->mangled_screen = 1;
597 #ifdef SIGCHLD
598 (void) signal(SIGCHLD, SIG_DFL);
599 #endif
600 #endif /* UNIX */
602 else if(flags & OSB_PRE_CLOSE){
603 #ifdef SIGCHLD
605 * this is here so close_system_pipe so it has something
606 * to do while we're waiting on the other end of the
607 * pipe to complete. When we're in the background for
608 * a shell, the the side effect is pinging
610 RETSIGTYPE (*alarm_sig)();
611 int old_cue = F_ON(F_SHOW_DELAY_CUE, ps_global);
614 * remember the current SIGALRM handler, and make sure it's
615 * installed when we're finished just in case the longjmp
616 * out of the SIGCHLD handler caused sleep() to lose it.
617 * Don't pay any attention to that man behind the curtain.
619 alarm_sig = signal(SIGALRM, SIG_IGN);
620 (void) F_SET(F_SHOW_DELAY_CUE, ps_global, 0);
621 ps_global->noshow_timeout = 1;
622 while(!child_signalled){
623 /* wake up and prod server */
624 if(!(syspipe->mode & PIPE_NONEWMAIL))
625 new_mail(0, 2,
626 (syspipe->mode & PIPE_RESET) ? NM_NONE : NM_DEFER_SORT);
628 if(!child_signalled){
629 if(setjmp(child_state) == 0){
630 child_jump = 1; /* prepare to wake up */
631 sleep(600); /* give it 5mins to happen */
633 else
634 our_sigunblock(SIGCHLD);
637 child_jump = 0;
640 ps_global->noshow_timeout = 0;
641 F_SET(F_SHOW_DELAY_CUE, ps_global, old_cue);
642 (void) signal(SIGALRM, alarm_sig);
643 (void) signal(SIGCHLD, syspipe->chld);
644 #endif
646 else if(flags & OSB_POST_CLOSE){
647 if(syspipe->mode & PIPE_RESET){ /* restore our tty modes */
648 ttyfix(1);
649 ps_global->mangled_screen = 1;
652 if(!(syspipe->mode & (PIPE_WRITE | PIPE_READ | PIPE_SILENT))){
653 ClearScreen(); /* No I/O to forked child */
654 ps_global->mangled_screen = 1;
661 * Command interrupt support.
664 static RETSIGTYPE
665 intr_signal(int sig)
667 ps_global->intr_pending = 1;
672 intr_handling_on(void)
674 #ifdef _WINDOWS
675 return 0; /* No interrupts in Windows */
676 #else /* UNIX */
677 if(signal(SIGINT, intr_signal) == intr_signal)
678 return 0; /* already installed */
680 intr_proc(1);
681 if(ps_global && ps_global->ttyo)
682 draw_cancel_keymenu();
684 return 1;
685 #endif /* UNIX */
689 void
690 intr_handling_off(void)
692 #ifdef _WINDOWS
693 #else /* UNIX */
694 if(signal(SIGINT, SIG_IGN) == SIG_IGN) /* already off! */
695 return;
697 ps_global->intr_pending = 0;
698 intr_proc(0);
699 if(ps_global && ps_global->ttyo)
700 blank_keymenu(ps_global->ttyo->screen_rows - 2, 0);
702 ps_global->mangled_footer = 1;
703 #endif /* UNIX */
707 /*----------------------------------------------------------------------
708 Set or reset what needs to be set when coming out of pico to run
709 an alternate editor.
711 Args: come_back -- If come_back is 0 we're going out of our environment
712 to set up for an external editor.
713 If come_back is 1 we're coming back into pine.
714 ----------------------------------------------------------------------*/
716 ttyfix(int come_back)
718 #if defined(DEBUG) && (!defined(DOS) || defined(_WINDOWS))
719 if(debugfile)
720 fflush(debugfile);
721 #endif
723 if(come_back){
724 #ifdef OS2
725 enter_text_mode(NULL);
726 #endif
727 init_screen();
728 init_tty_driver(ps_global);
729 init_keyboard(F_ON(F_USE_FK,ps_global));
730 #ifdef OS2
731 dont_interrupt();
732 #endif
733 fix_windsize(ps_global);
735 else{
736 EndInverse();
737 end_keyboard(F_ON(F_USE_FK,ps_global));
738 end_tty_driver(ps_global);
739 end_screen(NULL, 0);
740 #ifdef OS2
741 interrupt_ok();
742 #endif
745 return(0);
749 /*----------------------------------------------------------------------
750 Suspend Pine. Reset tty and suspend. Suspend is finished when this returns
752 Args: The pine structure
754 Result: Execution suspended for a while. Screen will need redrawing
755 after this is done.
757 Instead of the usual handling of ^Z by catching a signal, we actually read
758 the ^Z and then clean up the tty driver, then kill ourself to stop, and
759 pick up where we left off when execution resumes.
760 ----------------------------------------------------------------------*/
762 do_suspend(void)
764 struct pine *pine = ps_global;
765 time_t now;
766 UCS retval;
767 #if defined(DOS) || defined(OS2)
768 int result, orig_cols, orig_rows;
769 #else
770 int isremote;
771 #endif
772 #ifdef DOS
773 static char *shell = NULL;
774 #define STD_SHELL "COMMAND.COM"
775 #else
776 #ifdef OS2
777 static char *shell = NULL;
778 #define STD_SHELL "CMD.EXE"
779 #endif
780 #endif
782 if(!have_job_control()){
783 bogus_command(ctrl('Z'), F_ON(F_USE_FK, pine) ? "F1" : "?");
784 return(NO_OP_COMMAND);
787 if(F_OFF(F_CAN_SUSPEND, pine)){
788 q_status_message(SM_ORDER | SM_DING, 3, 3,
789 _("Alpine suspension not enabled - see help text"));
790 return(NO_OP_COMMAND);
793 #ifdef _WINDOWS
794 mswin_minimize();
795 return(NO_OP_COMMAND);
796 #else
798 isremote = (ps_global->mail_stream && ps_global->mail_stream->mailbox
799 && (*ps_global->mail_stream->mailbox == '{'
800 || (*ps_global->mail_stream->mailbox == '*'
801 && *(ps_global->mail_stream->mailbox + 1) == '{')));
803 now = time((time_t *)0);
804 dprint((1, "\n\n --- %s - SUSPEND ---- %s",
805 isremote ? "REMOTE" : "LOCAL", ctime(&now)));
806 ttyfix(0);
808 #if defined(DOS) || defined(OS2)
809 suspend_notice("exit");
810 if (!shell){
811 char *p;
813 if (!((shell = getenv("SHELL")) || (shell = getenv("COMSPEC"))))
814 shell = STD_SHELL;
816 shell = cpystr(shell); /* copy in free storage */
817 for(p = shell; (p = strchr(p, '/')); p++)
818 *p = '\\';
821 result = system(shell);
822 #else
823 if(F_ON(F_SUSPEND_SPAWNS, ps_global)){
824 PIPE_S *syspipe;
825 int flag = some_stream_is_locked() ? PIPE_NONEWMAIL : 0;
827 flag |= PIPE_USER|PIPE_RESET;
828 if((syspipe = open_system_pipe(NULL, NULL, NULL, flag,
829 0, pipe_callback, pipe_report_error)) != NULL){
830 suspend_notice("exit");
831 #ifndef SIGCHLD
832 if(isremote)
833 suspend_warning();
834 #endif
835 (void) close_system_pipe(&syspipe, NULL, pipe_callback);
838 else{
839 suspend_notice("fg");
841 if(isremote)
842 suspend_warning();
844 stop_process();
846 #endif /* DOS */
848 now = time((time_t *)0);
849 dprint((1, "\n\n ---- RETURN FROM SUSPEND ---- %s",
850 ctime(&now)));
852 ttyfix(1);
854 #if defined(DOS) || defined(OS2)
855 orig_cols = pine->ttyo->screen_cols;
856 orig_rows = pine->ttyo->screen_rows;
857 #endif
859 fix_windsize(pine);
861 #if defined(DOS) || defined(OS2)
862 if(orig_cols != pine->ttyo->screen_cols ||
863 orig_rows != pine->ttyo->screen_rows)
864 retval = KEY_RESIZE;
865 else
866 #endif
867 retval = ctrl('L');;
869 #if defined(DOS) || defined(OS2)
870 if(result == -1)
871 q_status_message1(SM_ORDER | SM_DING, 3, 4,
872 _("Error loading \"%s\""), shell);
873 #endif
875 if(isremote && !ps_global->mail_stream->lock
876 && !pine_mail_ping(ps_global->mail_stream))
877 q_status_message(SM_ORDER | SM_DING, 4, 9,
878 _("Suspended for too long, IMAP connection broken"));
880 return(retval);
881 #endif /* !_WINDOWS */
886 /*----------------------------------------------------------------------
887 ----*/
888 void
889 suspend_notice(char *s)
891 printf(_("\nAlpine suspended. Give the \"%s\" command to come back.\n"), s);
892 fflush(stdout);
896 /*----------------------------------------------------------------------
897 ----*/
898 void
899 suspend_warning(void)
901 puts(_("Warning: Your IMAP connection will be closed if Alpine"));
902 puts(_("is suspended for more than 30 minutes\n"));
903 fflush(stdout);
907 /*----------------------------------------------------------------------
908 ----*/
909 void
910 fix_windsize(struct pine *pine)
912 int old_width = pine->ttyo->screen_cols;
914 dprint((9, "fix_windsize()\n"));
915 mark_keymenu_dirty();
916 mark_status_dirty();
917 mark_titlebar_dirty();
918 clear_cursor_pos();
919 get_windsize(pine->ttyo);
921 if(old_width != pine->ttyo->screen_cols)
922 clear_index_cache(pine->mail_stream, 0);