* The instruction to remove the double quotes from the processing of
[alpine.git] / alpine / signal.c
blobf4a95d93fd8aa00346d1b078f9f40cbcc75c2ff4
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-2020 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 if(ps_global)
242 ps_global->signal_in_progress = 1;
243 end_signals(1); /* don't catch any more signals */
244 dprint((1, "\n\n** Received SIGHUP **\n\n\n\n"));
245 cleanup_called_from_sig_handler = 1;
246 fast_clean_up();
247 #if defined(DEBUG)
248 if(debugfile)
249 fclose(debugfile);
250 #endif
252 _exit(0); /* cleaning up can crash */
256 /*----------------------------------------------------------------------
257 Timeout when no user input for a long, long time.
258 Treat it pretty much the same as if we got a HUP.
259 Only difference is we sometimes turns the timeout off (when composing).
260 ----------------------------------------------------------------------*/
261 void
262 user_input_timeout_exit(int to_hours)
264 char msg[80];
266 dprint((1,
267 "\n\n** Exiting: user input timeout (%d hours) **\n\n\n\n",
268 to_hours));
269 snprintf(msg, sizeof(msg), _("\n\nAlpine timed out (No user input for %d %s)\n"), to_hours,
270 to_hours > 1 ? "hours" : "hour");
271 msg[sizeof(msg)-1] = '\0';
272 fast_clean_up();
273 end_screen(msg, 0);
274 end_titlebar();
275 end_keymenu();
276 end_keyboard(F_ON(F_USE_FK,ps_global));
277 end_tty_driver(ps_global);
278 end_signals(0);
279 #if defined(DEBUG) && (!defined(DOS) || defined(_WINDOWS))
280 if(debugfile)
281 fclose(debugfile);
282 #endif
283 exit(0);
287 /*----------------------------------------------------------------------
288 handle terminate signal -- SIGTERM
290 Not much to do. Rely on periodic mail file check pointing.
291 ----------------------------------------------------------------------*/
292 RETSIGTYPE
293 term_signal(void)
295 #if !defined(DOS) && !defined(OS2)
296 end_signals(1); /* don't catch any more signals */
297 dprint((1, "\n\n** Received SIGTERM **\n\n\n\n"));
298 cleanup_called_from_sig_handler = 1;
299 fast_clean_up();
300 #if defined(DEBUG) && (!defined(DOS) || defined(_WINDOWS))
301 if(debugfile)
302 fclose(debugfile);
303 #endif
304 printf(_("\n\nAlpine finished. Received terminate signal\n\n"));
305 #endif /* !DOS */
306 exit(0);
310 /*----------------------------------------------------------------------
311 Handle cleaning up mail streams and tty modes...
312 Not much to do. Rely on periodic mail file check pointing. Don't try
313 cleaning up screen or flushing output since stdout is likely already
314 gone. To be safe, though, we'll at least restore the original tty mode.
315 Also delete any remnant _DATAFILE_ from sending-filters.
316 ----------------------------------------------------------------------*/
317 void
318 fast_clean_up(void)
320 #if !defined(DOS) && !defined(OS2)
321 int i;
322 MAILSTREAM *m;
323 #endif
325 dprint((1, "fast_clean_up()\n"));
327 if(ps_global->expunge_in_progress){
328 PineRaw(0);
329 return;
333 * This gets rid of temporary cache files for remote addrbooks.
335 completely_done_with_adrbks();
338 * This flushes out deferred changes and gets rid of temporary cache
339 * files for remote config files.
341 if(ps_global->prc){
342 if(ps_global->prc->outstanding_pinerc_changes)
343 write_pinerc(ps_global, Main,
344 cleanup_called_from_sig_handler ? WRP_NOUSER : WRP_NONE);
346 if(ps_global->prc->rd)
347 rd_close_remdata(&ps_global->prc->rd);
349 free_pinerc_s(&ps_global->prc);
352 /* as does this */
353 if(ps_global->post_prc){
354 if(ps_global->post_prc->outstanding_pinerc_changes)
355 write_pinerc(ps_global, Post,
356 cleanup_called_from_sig_handler ? WRP_NOUSER : WRP_NONE);
358 if(ps_global->post_prc->rd)
359 rd_close_remdata(&ps_global->post_prc->rd);
361 free_pinerc_s(&ps_global->post_prc);
365 * Can't figure out why this section is inside the ifdef, but no
366 * harm leaving it that way, I guess.
368 #if !defined(DOS) && !defined(OS2)
369 for(i = 0; i < ps_global->s_pool.nstream; i++){
370 m = ps_global->s_pool.streams[i];
371 if(m && !m->lock)
372 pine_mail_actually_close(m);
375 PineRaw(0);
377 #endif /* !DOS */
379 imap_flush_passwd_cache(TRUE);
381 dprint((1, "done with fast_clean_up\n"));
385 #if !defined(DOS) && !defined(OS2)
386 /*----------------------------------------------------------------------
387 handle hang up signal -- SIGUSR2
389 Not much to do. Rely on periodic mail file check pointing.
390 ----------------------------------------------------------------------*/
391 static RETSIGTYPE
392 usr2_signal(int sig)
394 char c, *mbox, mboxbuf[20];
395 int i;
396 MAILSTREAM *stream;
397 NETMBX mb;
399 for(i = 0; i < ps_global->s_pool.nstream; i++){
400 stream = ps_global->s_pool.streams[i];
401 if(stream
402 && sp_flagged(stream, SP_LOCKED)
403 && !sp_dead_stream(stream)
404 && !stream->lock
405 && !stream->rdonly
406 && stream->mailbox
407 && (c = *stream->mailbox) != '{' && c != '*'){
408 pine_mail_check(stream); /* write latest state */
409 stream->rdonly = 1; /* and become read-only */
410 (void) pine_mail_ping(stream);
411 mbox = stream->mailbox;
412 if(!strucmp(stream->mailbox, ps_global->inbox_name)
413 || !strcmp(stream->mailbox, ps_global->VAR_INBOX_PATH)
414 || !strucmp(stream->original_mailbox, ps_global->inbox_name)
415 || !strcmp(stream->original_mailbox, ps_global->VAR_INBOX_PATH))
416 mbox = "INBOX";
417 else if(mail_valid_net_parse(stream->mailbox, &mb) && mb.mailbox)
418 mbox = mb.mailbox;
420 q_status_message1(SM_ASYNC, 3, 7,
421 _("Another email program is accessing %s. Session now Read-Only."),
422 short_str((mbox && *mbox) ? mbox : "folder",
423 mboxbuf, sizeof(mboxbuf), 19, FrontDots));
424 dprint((1, "** folder %s went read-only **\n\n",
425 stream->mailbox));
429 #endif
432 /*----------------------------------------------------------------------
433 Install signal handler to deal with window resize signal -- SIGWINCH
435 ----------------------------------------------------------------------*/
436 void
437 init_sigwinch (void)
439 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
440 signal(SIGWINCH, winch_signal);
441 #endif
445 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
446 /*----------------------------------------------------------------------
447 Handle window resize signal -- SIGWINCH
449 The planned strategy is just force a redraw command. This is similar
450 to new mail handling which forces a noop command. The signals are
451 help until pine reads input. Then a KEY_RESIZE is forced into the command
452 stream .
453 Note that ready_for_winch is only non-zero inside the read_char function,
454 so the longjmp only ever happens there, and it is really just a jump
455 from lower down in the function up to the top of that function. Its
456 purpose is to return a KEY_RESIZE from read_char when interrupted
457 out of the select lower down in read_char.
458 ----------------------------------------------------------------------*/
459 extern jmp_buf winch_state;
460 extern int ready_for_winch, winch_occured;
462 static RETSIGTYPE
463 winch_signal(int sig)
465 clear_cursor_pos();
466 init_sigwinch();
467 winch_cleanup();
469 #endif
473 * winch_cleanup -
475 void
476 winch_cleanup(void)
478 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
479 if(ready_for_winch)
480 longjmp(winch_state, 1);
481 else
482 winch_occured = 1;
483 #endif
487 #ifdef SIGCHLD
488 /*----------------------------------------------------------------------
489 Handle child status change -- SIGCHLD
491 The strategy here is to install the handler when we spawn a child, and
492 to let the system tell us when the child's state has changed. In the
493 mean time, we can do whatever. Typically, "whatever" is spinning in a
494 loop alternating between sleep and new_mail calls intended to keep the
495 IMAP stream alive.
497 ----------------------------------------------------------------------*/
498 static short child_signalled, child_jump;
499 static jmp_buf child_state;
501 RETSIGTYPE
502 child_signal(int sig)
504 #ifdef BACKGROUND_POST
506 * reap background posting process
508 if(ps_global->post && ps_global->post->pid){
509 pid_t pid;
510 int es;
512 pid = process_reap(ps_global->post->pid, &es, PR_NOHANG);
513 if(pid == ps_global->post->pid){
514 ps_global->post->status = es;
515 ps_global->post->pid = 0;
516 return;
518 else if(pid < 0 && errno != EINTR){
519 fs_give((void **) &ps_global->post);
522 #endif /* BACKGROUND_POST */
524 child_signalled = 1;
525 if(child_jump)
526 longjmp(child_state, 1);
528 #endif /* SIGCHLD */
532 * pipe_callback - handle pine-specific pipe setup like child
533 * signal handler and possibly any display stuff
534 * BUG: this function should probably be in a "alpine/pipe.c"
536 void
537 pipe_callback(PIPE_S *syspipe, int flags, void *data)
539 #ifdef _WINDOWS
540 bitmap_t bitmap;
541 #endif
542 if(flags & OSB_PRE_OPEN){
543 dprint((5, "Opening pipe: (%s%s%s%s%s%s)\n",
544 (syspipe->mode & PIPE_WRITE) ? "W":"", (syspipe->mode & PIPE_READ) ? "R":"",
545 (syspipe->mode & PIPE_NOSHELL) ? "N":"", (syspipe->mode & PIPE_PROT) ? "P":"",
546 (syspipe->mode & PIPE_USER) ? "U":"", (syspipe->mode & PIPE_RESET) ? "T":""));
548 #ifdef _WINDOWS
549 q_status_message(SM_ORDER, 0, 0,
550 "Waiting for called program to finish...");
552 flush_status_messages(1);
553 setbitmap(bitmap);
554 draw_keymenu(&pipe_cancel_keymenu, bitmap, ps_global->ttyo->screen_cols,
555 1-FOOTER_ROWS(ps_global), 0, FirstMenu);
556 #else /* UNIX */
558 if(!(syspipe->mode & (PIPE_WRITE | PIPE_READ)) && !(syspipe->mode & PIPE_SILENT)){
559 flush_status_messages(0); /* just clean up display */
560 ClearScreen();
561 fflush(stdout);
564 if(syspipe->mode & PIPE_RESET)
565 ttyfix(0);
567 #ifdef SIGCHLD
569 * Prepare for demise of child. Use SIGCHLD if it's available so
570 * we can do useful things, like keep the IMAP stream alive, while
571 * we're waiting on the child. The handler may have been changed by
572 * something in the composer, in particular, by an alt_editor call.
573 * So we need to re-set it to child_signal and then set it back
574 * when we're done.
576 child_signalled = child_jump = 0;
577 syspipe->chld = signal(SIGCHLD, child_signal);
578 #endif
579 #endif /* UNIX */
581 else if(flags & OSB_POST_OPEN){
582 #ifdef _WINDOWS
584 clearfooter(ps_global);
585 ps_global->mangled_footer = 1;
587 if((int) data == -2)
588 q_status_message1(SM_ORDER, 2, 3, "Ignoring completion of %s", syspipe->command);
590 #else /* UNIX */
591 if(!(syspipe->mode & (PIPE_WRITE | PIPE_READ)) && !(syspipe->mode & PIPE_SILENT)){
592 ClearScreen();
593 ps_global->mangled_screen = 1;
596 if(syspipe->mode & PIPE_RESET){
597 ttyfix(1);
598 ps_global->mangled_screen = 1;
601 #ifdef SIGCHLD
602 (void) signal(SIGCHLD, SIG_DFL);
603 #endif
604 #endif /* UNIX */
606 else if(flags & OSB_PRE_CLOSE){
607 #ifdef SIGCHLD
609 * this is here so close_system_pipe so it has something
610 * to do while we're waiting on the other end of the
611 * pipe to complete. When we're in the background for
612 * a shell, the the side effect is pinging
614 RETSIGTYPE (*alarm_sig)();
615 int old_cue = F_ON(F_SHOW_DELAY_CUE, ps_global);
618 * remember the current SIGALRM handler, and make sure it's
619 * installed when we're finished just in case the longjmp
620 * out of the SIGCHLD handler caused sleep() to lose it.
621 * Don't pay any attention to that man behind the curtain.
623 alarm_sig = signal(SIGALRM, SIG_IGN);
624 (void) F_SET(F_SHOW_DELAY_CUE, ps_global, 0);
625 ps_global->noshow_timeout = 1;
626 while(!child_signalled){
627 /* wake up and prod server */
628 if(!(syspipe->mode & PIPE_NONEWMAIL))
629 new_mail(0, 2,
630 (syspipe->mode & PIPE_RESET) ? NM_NONE : NM_DEFER_SORT);
632 if(!child_signalled){
633 if(setjmp(child_state) == 0){
634 child_jump = 1; /* prepare to wake up */
635 sleep(600); /* give it 5mins to happen */
637 else
638 our_sigunblock(SIGCHLD);
641 child_jump = 0;
644 ps_global->noshow_timeout = 0;
645 F_SET(F_SHOW_DELAY_CUE, ps_global, old_cue);
646 (void) signal(SIGALRM, alarm_sig);
647 (void) signal(SIGCHLD, syspipe->chld);
648 #endif
650 else if(flags & OSB_POST_CLOSE){
651 if(syspipe->mode & PIPE_RESET){ /* restore our tty modes */
652 ttyfix(1);
653 ps_global->mangled_screen = 1;
656 if(!(syspipe->mode & (PIPE_WRITE | PIPE_READ | PIPE_SILENT))){
657 ClearScreen(); /* No I/O to forked child */
658 ps_global->mangled_screen = 1;
665 * Command interrupt support.
668 static RETSIGTYPE
669 intr_signal(int sig)
671 ps_global->intr_pending = 1;
676 intr_handling_on(void)
678 #ifdef _WINDOWS
679 return 0; /* No interrupts in Windows */
680 #else /* UNIX */
681 if(signal(SIGINT, intr_signal) == intr_signal)
682 return 0; /* already installed */
684 intr_proc(1);
685 if(ps_global && ps_global->ttyo)
686 draw_cancel_keymenu();
688 return 1;
689 #endif /* UNIX */
693 void
694 intr_handling_off(void)
696 #ifdef _WINDOWS
697 #else /* UNIX */
698 if(signal(SIGINT, SIG_IGN) == SIG_IGN) /* already off! */
699 return;
701 ps_global->intr_pending = 0;
702 intr_proc(0);
703 if(ps_global && ps_global->ttyo)
704 blank_keymenu(ps_global->ttyo->screen_rows - 2, 0);
706 ps_global->mangled_footer = 1;
707 #endif /* UNIX */
711 /*----------------------------------------------------------------------
712 Set or reset what needs to be set when coming out of pico to run
713 an alternate editor.
715 Args: come_back -- If come_back is 0 we're going out of our environment
716 to set up for an external editor.
717 If come_back is 1 we're coming back into pine.
718 ----------------------------------------------------------------------*/
720 ttyfix(int come_back)
722 #if defined(DEBUG) && (!defined(DOS) || defined(_WINDOWS))
723 if(debugfile)
724 fflush(debugfile);
725 #endif
727 if(come_back){
728 #ifdef OS2
729 enter_text_mode(NULL);
730 #endif
731 init_screen();
732 init_tty_driver(ps_global);
733 init_keyboard(F_ON(F_USE_FK,ps_global));
734 #ifdef OS2
735 dont_interrupt();
736 #endif
737 fix_windsize(ps_global);
739 else{
740 EndInverse();
741 end_keyboard(F_ON(F_USE_FK,ps_global));
742 end_tty_driver(ps_global);
743 end_screen(NULL, 0);
744 #ifdef OS2
745 interrupt_ok();
746 #endif
749 return(0);
753 /*----------------------------------------------------------------------
754 Suspend Pine. Reset tty and suspend. Suspend is finished when this returns
756 Args: The pine structure
758 Result: Execution suspended for a while. Screen will need redrawing
759 after this is done.
761 Instead of the usual handling of ^Z by catching a signal, we actually read
762 the ^Z and then clean up the tty driver, then kill ourself to stop, and
763 pick up where we left off when execution resumes.
764 ----------------------------------------------------------------------*/
766 do_suspend(void)
768 struct pine *pine = ps_global;
769 time_t now;
770 UCS retval;
771 #if defined(DOS) || defined(OS2)
772 int result, orig_cols, orig_rows;
773 #else
774 int isremote;
775 #endif
776 #ifdef DOS
777 static char *shell = NULL;
778 #define STD_SHELL "COMMAND.COM"
779 #else
780 #ifdef OS2
781 static char *shell = NULL;
782 #define STD_SHELL "CMD.EXE"
783 #endif
784 #endif
786 if(!have_job_control()){
787 bogus_command(ctrl('Z'), F_ON(F_USE_FK, pine) ? "F1" : "?");
788 return(NO_OP_COMMAND);
791 if(F_OFF(F_CAN_SUSPEND, pine)){
792 q_status_message(SM_ORDER | SM_DING, 3, 3,
793 _("Alpine suspension not enabled - see help text"));
794 return(NO_OP_COMMAND);
797 #ifdef _WINDOWS
798 mswin_minimize();
799 return(NO_OP_COMMAND);
800 #else
802 isremote = (ps_global->mail_stream && ps_global->mail_stream->mailbox
803 && (*ps_global->mail_stream->mailbox == '{'
804 || (*ps_global->mail_stream->mailbox == '*'
805 && *(ps_global->mail_stream->mailbox + 1) == '{')));
807 now = time((time_t *)0);
808 dprint((1, "\n\n --- %s - SUSPEND ---- %s",
809 isremote ? "REMOTE" : "LOCAL", ctime(&now)));
810 ttyfix(0);
812 #if defined(DOS) || defined(OS2)
813 suspend_notice("exit");
814 if (!shell){
815 char *p;
817 if (!((shell = getenv("SHELL")) || (shell = getenv("COMSPEC"))))
818 shell = STD_SHELL;
820 shell = cpystr(shell); /* copy in free storage */
821 for(p = shell; (p = strchr(p, '/')); p++)
822 *p = '\\';
825 result = system(shell);
826 #else
827 if(F_ON(F_SUSPEND_SPAWNS, ps_global)){
828 PIPE_S *syspipe;
829 int flag = some_stream_is_locked() ? PIPE_NONEWMAIL : 0;
831 flag |= PIPE_USER|PIPE_RESET;
832 if((syspipe = open_system_pipe(NULL, NULL, NULL, flag,
833 0, pipe_callback, pipe_report_error)) != NULL){
834 suspend_notice("exit");
835 #ifndef SIGCHLD
836 if(isremote)
837 suspend_warning();
838 #endif
839 (void) close_system_pipe(&syspipe, NULL, pipe_callback);
842 else{
843 suspend_notice("fg");
845 if(isremote)
846 suspend_warning();
848 stop_process();
850 #endif /* DOS */
852 now = time((time_t *)0);
853 dprint((1, "\n\n ---- RETURN FROM SUSPEND ---- %s",
854 ctime(&now)));
856 ttyfix(1);
858 #if defined(DOS) || defined(OS2)
859 orig_cols = pine->ttyo->screen_cols;
860 orig_rows = pine->ttyo->screen_rows;
861 #endif
863 fix_windsize(pine);
865 #if defined(DOS) || defined(OS2)
866 if(orig_cols != pine->ttyo->screen_cols ||
867 orig_rows != pine->ttyo->screen_rows)
868 retval = KEY_RESIZE;
869 else
870 #endif
871 retval = ctrl('L');;
873 #if defined(DOS) || defined(OS2)
874 if(result == -1)
875 q_status_message1(SM_ORDER | SM_DING, 3, 4,
876 _("Error loading \"%s\""), shell);
877 #endif
879 if(isremote && !ps_global->mail_stream->lock
880 && !pine_mail_ping(ps_global->mail_stream))
881 q_status_message(SM_ORDER | SM_DING, 4, 9,
882 _("Suspended for too long, IMAP connection broken"));
884 return(retval);
885 #endif /* !_WINDOWS */
890 /*----------------------------------------------------------------------
891 ----*/
892 void
893 suspend_notice(char *s)
895 printf(_("\nAlpine suspended. Give the \"%s\" command to come back.\n"), s);
896 fflush(stdout);
900 /*----------------------------------------------------------------------
901 ----*/
902 void
903 suspend_warning(void)
905 puts(_("Warning: Your IMAP connection will be closed if Alpine"));
906 puts(_("is suspended for more than 30 minutes\n"));
907 fflush(stdout);
911 /*----------------------------------------------------------------------
912 ----*/
913 void
914 fix_windsize(struct pine *pine)
916 int old_width = pine->ttyo->screen_cols;
918 dprint((9, "fix_windsize()\n"));
919 mark_keymenu_dirty();
920 mark_status_dirty();
921 mark_titlebar_dirty();
922 clear_cursor_pos();
923 get_windsize(pine->ttyo);
925 if(old_width != pine->ttyo->screen_cols)
926 clear_index_cache(pine->mail_stream, 0);