* Fix an error in compilation when Alpine is not built with S/MIME
[alpine.git] / alpine / signal.c
blob158612d24fcca0adfb1bfcb17859f0bca9f7d302
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: signal.c 1025 2008-04-08 22:59:38Z hubert@u.washington.edu $";
3 #endif
5 /* ========================================================================
6 * Copyright 2006-2008 University of Washington
7 * Copyright 2013-2016 Eduardo Chappa
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * ========================================================================
18 /*======================================================================
19 Different signal handlers for different signals
20 - Catches all the abort signals, cleans up tty modes and then coredumps
21 - Not much to do for SIGHUP
22 - Not much to do for SIGTERM
23 - turn SIGWINCH into a KEY_RESIZE command
24 - No signals for ^Z/suspend, but do it here anyway
25 - Also set up the signal handlers, and hold signals for
26 critical imap sections of code.
27 ====*/
30 #include "headers.h"
31 #include "alpine.h"
32 #include "signal.h"
33 #include "status.h"
34 #include "dispfilt.h"
35 #include "keymenu.h"
36 #include "titlebar.h"
37 #include "mailcmd.h"
38 #include "../pith/state.h"
39 #include "../pith/conf.h"
40 #include "../pith/detach.h"
41 #include "../pith/pipe.h"
42 #include "../pith/util.h"
43 #include "../pith/icache.h"
44 #include "../pith/newmail.h"
45 #include "../pith/imap.h"
46 #include "../pith/adrbklib.h"
47 #include "../pith/remote.h"
48 #include "../pith/osdep/pipe.h"
52 * Internal Prototypes
54 static RETSIGTYPE auger_in_signal(int);
55 void init_sighup(void);
56 void end_sighup(void);
57 RETSIGTYPE term_signal(void);
58 void fast_clean_up(void);
59 static RETSIGTYPE usr2_signal(int);
60 static RETSIGTYPE winch_signal(int);
61 static RETSIGTYPE intr_signal(int);
62 void suspend_notice(char *);
63 void suspend_warning(void);
67 static int cleanup_called_from_sig_handler;
71 /*----------------------------------------------------------------------
72 Install handlers for all the signals we care to catch
73 ----------------------------------------------------------------------*/
74 void
75 init_signals(void)
77 dprint((9, "init_signals()\n"));
78 init_sighup();
80 #ifdef _WINDOWS
81 #else
82 # ifdef DEBUG
83 # define CUSHION_SIG (debug < 7)
84 # else
85 # define CUSHION_SIG (1)
86 # endif
88 if(CUSHION_SIG){
89 signal(SIGILL, auger_in_signal);
90 signal(SIGTRAP, auger_in_signal);
91 # ifdef SIGEMT
92 signal(SIGEMT, auger_in_signal);
93 # endif
94 signal(SIGBUS, auger_in_signal);
95 signal(SIGSEGV, auger_in_signal);
96 signal(SIGSYS, auger_in_signal);
97 signal(SIGQUIT, auger_in_signal);
98 /* Don't catch SIGFPE cause it's rare and we use it in a hack below*/
101 init_sigwinch();
104 * Set up SIGUSR2 to catch signal from other software using the
105 * c-client to tell us that other access to the folder is being
106 * attempted. THIS IS A TEST: if it turns out that simply
107 * going R/O when another pine is started or the same folder is opened,
108 * then we may want to install a smarter handler that uses idle time
109 * or even prompts the user to see if it's ok to give up R/O access...
111 signal(SIGUSR2, usr2_signal);
113 signal(SIGPIPE, SIG_IGN);
114 signal(SIGINT, SIG_IGN);
116 # ifdef SIGTSTP
117 /* Some unexplained behaviour on Ultrix 4.2 (Hardy) seems to be
118 resulting in Pine getting sent a SIGTSTP. Ignore it here.
119 probably better to ignore it than let it happen in any case
121 signal(SIGTSTP, SIG_IGN);
122 # endif /* SIGTSTP */
124 # ifdef SIGCHLD
125 signal(SIGCHLD, child_signal);
126 # endif
127 #endif /* !_WINDOWS */
131 /*----------------------------------------------------------------------
132 Return all signal handling back to normal
133 ----------------------------------------------------------------------*/
134 void
135 end_signals(int blockem)
137 #ifdef _WINDOWS
139 signal(SIGHUP, blockem ? SIG_IGN : SIG_DFL);
141 #else
142 #ifndef SIG_ERR
143 #define SIG_ERR (RETSIGTYPE (*)())-1
144 #endif
146 dprint((5, "end_signals(%d)\n", blockem));
147 if(signal(SIGILL, blockem ? SIG_IGN : SIG_DFL) == SIG_ERR){
148 fprintf(stderr, "Error resetting signals: %s\n",
149 error_description(errno));
150 exit(-1);
153 signal(SIGTRAP, blockem ? SIG_IGN : SIG_DFL);
154 #ifdef SIGEMT
155 signal(SIGEMT, blockem ? SIG_IGN : SIG_DFL);
156 #endif
157 signal(SIGBUS, blockem ? SIG_IGN : SIG_DFL);
158 signal(SIGSEGV, blockem ? SIG_IGN : SIG_DFL);
159 signal(SIGSYS, blockem ? SIG_IGN : SIG_DFL);
160 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
161 signal(SIGWINCH, blockem ? SIG_IGN : SIG_DFL);
162 #endif
163 signal(SIGQUIT, blockem ? SIG_IGN : SIG_DFL);
164 #ifdef SIGTSTP
165 signal(SIGTSTP, blockem ? SIG_IGN : SIG_DFL);
166 #endif /* SIGTSTP */
167 signal(SIGHUP, blockem ? SIG_IGN : SIG_DFL);
168 signal(SIGTERM, blockem ? SIG_IGN : SIG_DFL);
169 signal(SIGINT, blockem ? SIG_IGN : SIG_DFL);
171 #endif /* !_WINDOWS */
175 /*----------------------------------------------------------------------
176 Handle signals caused by aborts -- SIGSEGV, SIGILL, etc
178 Call panic which cleans up tty modes and then core dumps
179 ----------------------------------------------------------------------*/
180 static RETSIGTYPE
181 auger_in_signal(int sig)
183 char buf[100];
185 end_signals(1); /* don't catch any more signals */
186 imap_flush_passwd_cache(FALSE);
188 snprintf(buf, sizeof(buf), "Received abort signal(sig=%d)", sig);
189 buf[sizeof(buf)-1] = '\0';
191 alpine_panic(buf); /* clean up and get out */
193 exit(-1); /* in case panic doesn't kill us */
197 /*----------------------------------------------------------------------
198 Install signal handler to deal with hang up signals -- SIGHUP, SIGTERM
200 ----------------------------------------------------------------------*/
201 void
202 init_sighup(void)
204 #if !(defined(DOS) && !defined(_WINDOWS))
205 #if defined(_WINDOWS) || defined(OS2)
206 signal(SIGHUP, (void *) hup_signal);
207 #else
208 signal(SIGHUP, hup_signal);
209 #endif
210 #endif
211 #if !(defined(DOS) || defined(OS2))
212 signal(SIGTERM, term_signal);
213 #endif
217 /*----------------------------------------------------------------------
218 De-Install signal handler to deal with hang up signals -- SIGHUP, SIGTERM
220 ----------------------------------------------------------------------*/
221 void
222 end_sighup(void)
224 #if !(defined(DOS) && !defined(_WINDOWS))
225 signal(SIGHUP, SIG_IGN);
226 #endif
227 #if !(defined(DOS) || defined(OS2))
228 signal(SIGTERM, SIG_IGN);
229 #endif
233 /*----------------------------------------------------------------------
234 handle hang up signal -- SIGHUP
236 Not much to do. Rely on periodic mail file check pointing.
237 ----------------------------------------------------------------------*/
238 RETSIGTYPE
239 hup_signal(void)
241 end_signals(1); /* don't catch any more signals */
242 dprint((1, "\n\n** Received SIGHUP **\n\n\n\n"));
243 cleanup_called_from_sig_handler = 1;
244 fast_clean_up();
245 #if defined(DEBUG)
246 if(debugfile)
247 fclose(debugfile);
248 #endif
250 _exit(0); /* cleaning up can crash */
254 /*----------------------------------------------------------------------
255 Timeout when no user input for a long, long time.
256 Treat it pretty much the same as if we got a HUP.
257 Only difference is we sometimes turns the timeout off (when composing).
258 ----------------------------------------------------------------------*/
259 void
260 user_input_timeout_exit(int to_hours)
262 char msg[80];
264 dprint((1,
265 "\n\n** Exiting: user input timeout (%d hours) **\n\n\n\n",
266 to_hours));
267 snprintf(msg, sizeof(msg), _("\n\nAlpine timed out (No user input for %d %s)\n"), to_hours,
268 to_hours > 1 ? "hours" : "hour");
269 msg[sizeof(msg)-1] = '\0';
270 fast_clean_up();
271 end_screen(msg, 0);
272 end_titlebar();
273 end_keymenu();
274 end_keyboard(F_ON(F_USE_FK,ps_global));
275 end_tty_driver(ps_global);
276 end_signals(0);
277 #if defined(DEBUG) && (!defined(DOS) || defined(_WINDOWS))
278 if(debugfile)
279 fclose(debugfile);
280 #endif
281 exit(0);
285 /*----------------------------------------------------------------------
286 handle terminate signal -- SIGTERM
288 Not much to do. Rely on periodic mail file check pointing.
289 ----------------------------------------------------------------------*/
290 RETSIGTYPE
291 term_signal(void)
293 #if !defined(DOS) && !defined(OS2)
294 end_signals(1); /* don't catch any more signals */
295 dprint((1, "\n\n** Received SIGTERM **\n\n\n\n"));
296 cleanup_called_from_sig_handler = 1;
297 fast_clean_up();
298 #if defined(DEBUG) && (!defined(DOS) || defined(_WINDOWS))
299 if(debugfile)
300 fclose(debugfile);
301 #endif
302 printf(_("\n\nAlpine finished. Received terminate signal\n\n"));
303 #endif /* !DOS */
304 exit(0);
308 /*----------------------------------------------------------------------
309 Handle cleaning up mail streams and tty modes...
310 Not much to do. Rely on periodic mail file check pointing. Don't try
311 cleaning up screen or flushing output since stdout is likely already
312 gone. To be safe, though, we'll at least restore the original tty mode.
313 Also delete any remnant _DATAFILE_ from sending-filters.
314 ----------------------------------------------------------------------*/
315 void
316 fast_clean_up(void)
318 #if !defined(DOS) && !defined(OS2)
319 int i;
320 MAILSTREAM *m;
321 #endif
323 dprint((1, "fast_clean_up()\n"));
325 if(ps_global->expunge_in_progress){
326 PineRaw(0);
327 return;
331 * This gets rid of temporary cache files for remote addrbooks.
333 completely_done_with_adrbks();
336 * This flushes out deferred changes and gets rid of temporary cache
337 * files for remote config files.
339 if(ps_global->prc){
340 if(ps_global->prc->outstanding_pinerc_changes)
341 write_pinerc(ps_global, Main,
342 cleanup_called_from_sig_handler ? WRP_NOUSER : WRP_NONE);
344 if(ps_global->prc->rd)
345 rd_close_remdata(&ps_global->prc->rd);
347 free_pinerc_s(&ps_global->prc);
350 /* as does this */
351 if(ps_global->post_prc){
352 if(ps_global->post_prc->outstanding_pinerc_changes)
353 write_pinerc(ps_global, Post,
354 cleanup_called_from_sig_handler ? WRP_NOUSER : WRP_NONE);
356 if(ps_global->post_prc->rd)
357 rd_close_remdata(&ps_global->post_prc->rd);
359 free_pinerc_s(&ps_global->post_prc);
363 * Can't figure out why this section is inside the ifdef, but no
364 * harm leaving it that way, I guess.
366 #if !defined(DOS) && !defined(OS2)
367 for(i = 0; i < ps_global->s_pool.nstream; i++){
368 m = ps_global->s_pool.streams[i];
369 if(m && !m->lock)
370 pine_mail_actually_close(m);
373 PineRaw(0);
375 #endif /* !DOS */
377 imap_flush_passwd_cache(TRUE);
379 dprint((1, "done with fast_clean_up\n"));
383 #if !defined(DOS) && !defined(OS2)
384 /*----------------------------------------------------------------------
385 handle hang up signal -- SIGUSR2
387 Not much to do. Rely on periodic mail file check pointing.
388 ----------------------------------------------------------------------*/
389 static RETSIGTYPE
390 usr2_signal(int sig)
392 char c, *mbox, mboxbuf[20];
393 int i;
394 MAILSTREAM *stream;
395 NETMBX mb;
397 for(i = 0; i < ps_global->s_pool.nstream; i++){
398 stream = ps_global->s_pool.streams[i];
399 if(stream
400 && sp_flagged(stream, SP_LOCKED)
401 && !sp_dead_stream(stream)
402 && !stream->lock
403 && !stream->rdonly
404 && stream->mailbox
405 && (c = *stream->mailbox) != '{' && c != '*'){
406 pine_mail_check(stream); /* write latest state */
407 stream->rdonly = 1; /* and become read-only */
408 (void) pine_mail_ping(stream);
409 mbox = stream->mailbox;
410 if(!strucmp(stream->mailbox, ps_global->inbox_name)
411 || !strcmp(stream->mailbox, ps_global->VAR_INBOX_PATH)
412 || !strucmp(stream->original_mailbox, ps_global->inbox_name)
413 || !strcmp(stream->original_mailbox, ps_global->VAR_INBOX_PATH))
414 mbox = "INBOX";
415 else if(mail_valid_net_parse(stream->mailbox, &mb) && mb.mailbox)
416 mbox = mb.mailbox;
418 q_status_message1(SM_ASYNC, 3, 7,
419 _("Another email program is accessing %s. Session now Read-Only."),
420 short_str((mbox && *mbox) ? mbox : "folder",
421 mboxbuf, sizeof(mboxbuf), 19, FrontDots));
422 dprint((1, "** folder %s went read-only **\n\n",
423 stream->mailbox));
427 #endif
430 /*----------------------------------------------------------------------
431 Install signal handler to deal with window resize signal -- SIGWINCH
433 ----------------------------------------------------------------------*/
434 void
435 init_sigwinch (void)
437 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
438 signal(SIGWINCH, winch_signal);
439 #endif
443 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
444 /*----------------------------------------------------------------------
445 Handle window resize signal -- SIGWINCH
447 The planned strategy is just force a redraw command. This is similar
448 to new mail handling which forces a noop command. The signals are
449 help until pine reads input. Then a KEY_RESIZE is forced into the command
450 stream .
451 Note that ready_for_winch is only non-zero inside the read_char function,
452 so the longjmp only ever happens there, and it is really just a jump
453 from lower down in the function up to the top of that function. Its
454 purpose is to return a KEY_RESIZE from read_char when interrupted
455 out of the select lower down in read_char.
456 ----------------------------------------------------------------------*/
457 extern jmp_buf winch_state;
458 extern int ready_for_winch, winch_occured;
460 static RETSIGTYPE
461 winch_signal(int sig)
463 clear_cursor_pos();
464 init_sigwinch();
465 winch_cleanup();
467 #endif
471 * winch_cleanup -
473 void
474 winch_cleanup(void)
476 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
477 if(ready_for_winch)
478 longjmp(winch_state, 1);
479 else
480 winch_occured = 1;
481 #endif
485 #ifdef SIGCHLD
486 /*----------------------------------------------------------------------
487 Handle child status change -- SIGCHLD
489 The strategy here is to install the handler when we spawn a child, and
490 to let the system tell us when the child's state has changed. In the
491 mean time, we can do whatever. Typically, "whatever" is spinning in a
492 loop alternating between sleep and new_mail calls intended to keep the
493 IMAP stream alive.
495 ----------------------------------------------------------------------*/
496 static short child_signalled, child_jump;
497 static jmp_buf child_state;
499 RETSIGTYPE
500 child_signal(int sig)
502 #ifdef BACKGROUND_POST
504 * reap background posting process
506 if(ps_global->post && ps_global->post->pid){
507 pid_t pid;
508 int es;
510 pid = process_reap(ps_global->post->pid, &es, PR_NOHANG);
511 if(pid == ps_global->post->pid){
512 ps_global->post->status = es;
513 ps_global->post->pid = 0;
514 return;
516 else if(pid < 0 && errno != EINTR){
517 fs_give((void **) &ps_global->post);
520 #endif /* BACKGROUND_POST */
522 child_signalled = 1;
523 if(child_jump)
524 longjmp(child_state, 1);
526 #endif /* SIGCHLD */
530 * pipe_callback - handle pine-specific pipe setup like child
531 * signal handler and possibly any display stuff
532 * BUG: this function should probably be in a "alpine/pipe.c"
534 void
535 pipe_callback(PIPE_S *syspipe, int flags, void *data)
537 #ifdef _WINDOWS
538 bitmap_t bitmap;
539 #endif
540 if(flags & OSB_PRE_OPEN){
541 dprint((5, "Opening pipe: (%s%s%s%s%s%s)\n",
542 (syspipe->mode & PIPE_WRITE) ? "W":"", (syspipe->mode & PIPE_READ) ? "R":"",
543 (syspipe->mode & PIPE_NOSHELL) ? "N":"", (syspipe->mode & PIPE_PROT) ? "P":"",
544 (syspipe->mode & PIPE_USER) ? "U":"", (syspipe->mode & PIPE_RESET) ? "T":""));
546 #ifdef _WINDOWS
547 q_status_message(SM_ORDER, 0, 0,
548 "Waiting for called program to finish...");
550 flush_status_messages(1);
551 setbitmap(bitmap);
552 draw_keymenu(&pipe_cancel_keymenu, bitmap, ps_global->ttyo->screen_cols,
553 1-FOOTER_ROWS(ps_global), 0, FirstMenu);
554 #else /* UNIX */
556 if(!(syspipe->mode & (PIPE_WRITE | PIPE_READ)) && !(syspipe->mode & PIPE_SILENT)){
557 flush_status_messages(0); /* just clean up display */
558 ClearScreen();
559 fflush(stdout);
562 if(syspipe->mode & PIPE_RESET)
563 ttyfix(0);
565 #ifdef SIGCHLD
567 * Prepare for demise of child. Use SIGCHLD if it's available so
568 * we can do useful things, like keep the IMAP stream alive, while
569 * we're waiting on the child. The handler may have been changed by
570 * something in the composer, in particular, by an alt_editor call.
571 * So we need to re-set it to child_signal and then set it back
572 * when we're done.
574 child_signalled = child_jump = 0;
575 syspipe->chld = signal(SIGCHLD, child_signal);
576 #endif
577 #endif /* UNIX */
579 else if(flags & OSB_POST_OPEN){
580 #ifdef _WINDOWS
582 clearfooter(ps_global);
583 ps_global->mangled_footer = 1;
585 if((int) data == -2)
586 q_status_message1(SM_ORDER, 2, 3, "Ignoring completion of %s", syspipe->command);
588 #else /* UNIX */
589 if(!(syspipe->mode & (PIPE_WRITE | PIPE_READ)) && !(syspipe->mode & PIPE_SILENT)){
590 ClearScreen();
591 ps_global->mangled_screen = 1;
594 if(syspipe->mode & PIPE_RESET){
595 ttyfix(1);
596 ps_global->mangled_screen = 1;
599 #ifdef SIGCHLD
600 (void) signal(SIGCHLD, SIG_DFL);
601 #endif
602 #endif /* UNIX */
604 else if(flags & OSB_PRE_CLOSE){
605 #ifdef SIGCHLD
607 * this is here so close_system_pipe so it has something
608 * to do while we're waiting on the other end of the
609 * pipe to complete. When we're in the background for
610 * a shell, the the side effect is pinging
612 RETSIGTYPE (*alarm_sig)();
613 int old_cue = F_ON(F_SHOW_DELAY_CUE, ps_global);
616 * remember the current SIGALRM handler, and make sure it's
617 * installed when we're finished just in case the longjmp
618 * out of the SIGCHLD handler caused sleep() to lose it.
619 * Don't pay any attention to that man behind the curtain.
621 alarm_sig = signal(SIGALRM, SIG_IGN);
622 (void) F_SET(F_SHOW_DELAY_CUE, ps_global, 0);
623 ps_global->noshow_timeout = 1;
624 while(!child_signalled){
625 /* wake up and prod server */
626 if(!(syspipe->mode & PIPE_NONEWMAIL))
627 new_mail(0, 2,
628 (syspipe->mode & PIPE_RESET) ? NM_NONE : NM_DEFER_SORT);
630 if(!child_signalled){
631 if(setjmp(child_state) == 0){
632 child_jump = 1; /* prepare to wake up */
633 sleep(600); /* give it 5mins to happend */
635 else
636 our_sigunblock(SIGCHLD);
639 child_jump = 0;
642 ps_global->noshow_timeout = 0;
643 F_SET(F_SHOW_DELAY_CUE, ps_global, old_cue);
644 (void) signal(SIGALRM, alarm_sig);
645 (void) signal(SIGCHLD, syspipe->chld);
646 #endif
648 else if(flags & OSB_POST_CLOSE){
649 if(syspipe->mode & PIPE_RESET){ /* restore our tty modes */
650 ttyfix(1);
651 ps_global->mangled_screen = 1;
654 if(!(syspipe->mode & (PIPE_WRITE | PIPE_READ | PIPE_SILENT))){
655 ClearScreen(); /* No I/O to forked child */
656 ps_global->mangled_screen = 1;
663 * Command interrupt support.
666 static RETSIGTYPE
667 intr_signal(int sig)
669 ps_global->intr_pending = 1;
674 intr_handling_on(void)
676 #ifdef _WINDOWS
677 return 0; /* No interrupts in Windows */
678 #else /* UNIX */
679 if(signal(SIGINT, intr_signal) == intr_signal)
680 return 0; /* already installed */
682 intr_proc(1);
683 if(ps_global && ps_global->ttyo)
684 draw_cancel_keymenu();
686 return 1;
687 #endif /* UNIX */
691 void
692 intr_handling_off(void)
694 #ifdef _WINDOWS
695 #else /* UNIX */
696 if(signal(SIGINT, SIG_IGN) == SIG_IGN) /* already off! */
697 return;
699 ps_global->intr_pending = 0;
700 intr_proc(0);
701 if(ps_global && ps_global->ttyo)
702 blank_keymenu(ps_global->ttyo->screen_rows - 2, 0);
704 ps_global->mangled_footer = 1;
705 #endif /* UNIX */
709 /*----------------------------------------------------------------------
710 Set or reset what needs to be set when coming out of pico to run
711 an alternate editor.
713 Args: come_back -- If come_back is 0 we're going out of our environment
714 to set up for an external editor.
715 If come_back is 1 we're coming back into pine.
716 ----------------------------------------------------------------------*/
718 ttyfix(int come_back)
720 #if defined(DEBUG) && (!defined(DOS) || defined(_WINDOWS))
721 if(debugfile)
722 fflush(debugfile);
723 #endif
725 if(come_back){
726 #ifdef OS2
727 enter_text_mode(NULL);
728 #endif
729 init_screen();
730 init_tty_driver(ps_global);
731 init_keyboard(F_ON(F_USE_FK,ps_global));
732 #ifdef OS2
733 dont_interrupt();
734 #endif
735 fix_windsize(ps_global);
737 else{
738 EndInverse();
739 end_keyboard(F_ON(F_USE_FK,ps_global));
740 end_tty_driver(ps_global);
741 end_screen(NULL, 0);
742 #ifdef OS2
743 interrupt_ok();
744 #endif
747 return(0);
751 /*----------------------------------------------------------------------
752 Suspend Pine. Reset tty and suspend. Suspend is finished when this returns
754 Args: The pine structure
756 Result: Execution suspended for a while. Screen will need redrawing
757 after this is done.
759 Instead of the usual handling of ^Z by catching a signal, we actually read
760 the ^Z and then clean up the tty driver, then kill ourself to stop, and
761 pick up where we left off when execution resumes.
762 ----------------------------------------------------------------------*/
764 do_suspend(void)
766 struct pine *pine = ps_global;
767 time_t now;
768 UCS retval;
769 #if defined(DOS) || defined(OS2)
770 int result, orig_cols, orig_rows;
771 #else
772 int isremote;
773 #endif
774 #ifdef DOS
775 static char *shell = NULL;
776 #define STD_SHELL "COMMAND.COM"
777 #else
778 #ifdef OS2
779 static char *shell = NULL;
780 #define STD_SHELL "CMD.EXE"
781 #endif
782 #endif
784 if(!have_job_control()){
785 bogus_command(ctrl('Z'), F_ON(F_USE_FK, pine) ? "F1" : "?");
786 return(NO_OP_COMMAND);
789 if(F_OFF(F_CAN_SUSPEND, pine)){
790 q_status_message(SM_ORDER | SM_DING, 3, 3,
791 _("Alpine suspension not enabled - see help text"));
792 return(NO_OP_COMMAND);
795 #ifdef _WINDOWS
796 mswin_minimize();
797 return(NO_OP_COMMAND);
798 #else
800 isremote = (ps_global->mail_stream && ps_global->mail_stream->mailbox
801 && (*ps_global->mail_stream->mailbox == '{'
802 || (*ps_global->mail_stream->mailbox == '*'
803 && *(ps_global->mail_stream->mailbox + 1) == '{')));
805 now = time((time_t *)0);
806 dprint((1, "\n\n --- %s - SUSPEND ---- %s",
807 isremote ? "REMOTE" : "LOCAL", ctime(&now)));
808 ttyfix(0);
810 #if defined(DOS) || defined(OS2)
811 suspend_notice("exit");
812 if (!shell){
813 char *p;
815 if (!((shell = getenv("SHELL")) || (shell = getenv("COMSPEC"))))
816 shell = STD_SHELL;
818 shell = cpystr(shell); /* copy in free storage */
819 for(p = shell; (p = strchr(p, '/')); p++)
820 *p = '\\';
823 result = system(shell);
824 #else
825 if(F_ON(F_SUSPEND_SPAWNS, ps_global)){
826 PIPE_S *syspipe;
827 int flag = some_stream_is_locked() ? PIPE_NONEWMAIL : 0;
829 flag |= PIPE_USER|PIPE_RESET;
830 if((syspipe = open_system_pipe(NULL, NULL, NULL, flag,
831 0, pipe_callback, pipe_report_error)) != NULL){
832 suspend_notice("exit");
833 #ifndef SIGCHLD
834 if(isremote)
835 suspend_warning();
836 #endif
837 (void) close_system_pipe(&syspipe, NULL, pipe_callback);
840 else{
841 suspend_notice("fg");
843 if(isremote)
844 suspend_warning();
846 stop_process();
848 #endif /* DOS */
850 now = time((time_t *)0);
851 dprint((1, "\n\n ---- RETURN FROM SUSPEND ---- %s",
852 ctime(&now)));
854 ttyfix(1);
856 #if defined(DOS) || defined(OS2)
857 orig_cols = pine->ttyo->screen_cols;
858 orig_rows = pine->ttyo->screen_rows;
859 #endif
861 fix_windsize(pine);
863 #if defined(DOS) || defined(OS2)
864 if(orig_cols != pine->ttyo->screen_cols ||
865 orig_rows != pine->ttyo->screen_rows)
866 retval = KEY_RESIZE;
867 else
868 #endif
869 retval = ctrl('L');;
871 #if defined(DOS) || defined(OS2)
872 if(result == -1)
873 q_status_message1(SM_ORDER | SM_DING, 3, 4,
874 _("Error loading \"%s\""), shell);
875 #endif
877 if(isremote && !ps_global->mail_stream->lock
878 && !pine_mail_ping(ps_global->mail_stream))
879 q_status_message(SM_ORDER | SM_DING, 4, 9,
880 _("Suspended for too long, IMAP connection broken"));
882 return(retval);
883 #endif /* !_WINDOWS */
888 /*----------------------------------------------------------------------
889 ----*/
890 void
891 suspend_notice(char *s)
893 printf(_("\nAlpine suspended. Give the \"%s\" command to come back.\n"), s);
894 fflush(stdout);
898 /*----------------------------------------------------------------------
899 ----*/
900 void
901 suspend_warning(void)
903 puts(_("Warning: Your IMAP connection will be closed if Alpine"));
904 puts(_("is suspended for more than 30 minutes\n"));
905 fflush(stdout);
909 /*----------------------------------------------------------------------
910 ----*/
911 void
912 fix_windsize(struct pine *pine)
914 int old_width = pine->ttyo->screen_cols;
916 dprint((9, "fix_windsize()\n"));
917 mark_keymenu_dirty();
918 mark_status_dirty();
919 mark_titlebar_dirty();
920 clear_cursor_pos();
921 get_windsize(pine->ttyo);
923 if(old_width != pine->ttyo->screen_cols)
924 clear_index_cache(pine->mail_stream, 0);