Nico Golde:
[apps/madmutt.git] / signal.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
4  *
5  * This file is part of mutt-ng, see http://www.muttng.org/.
6  * It's licensed under the GNU General Public License,
7  * please see the file GPL in the top level source directory.
8  */
9
10 #if HAVE_CONFIG_H
11 # include "config.h"
12 #endif
13
14 #include "mutt.h"
15 #include "mutt_curses.h"
16
17 #include <signal.h>
18 #include <string.h>
19 #include <sys/wait.h>
20 #include <errno.h>
21
22 static sigset_t Sigset;
23 static sigset_t SigsetSys;
24 static struct sigaction SysOldInt;
25 static struct sigaction SysOldQuit;
26 static int IsEndwin = 0;
27
28 /* Attempt to catch "ordinary" signals and shut down gracefully. */
29 RETSIGTYPE exit_handler (int sig)
30 {
31   curs_set (1);
32   endwin ();                    /* just to be safe */
33 #if SYS_SIGLIST_DECLARED
34   printf (_("%s...  Exiting.\n"), sys_siglist[sig]);
35 #else
36 #if (__sun__ && __svr4__)
37   printf (_("Caught %s...  Exiting.\n"), _sys_siglist[sig]);
38 #else
39 #if (__alpha && __osf__)
40   printf (_("Caught %s...  Exiting.\n"), __sys_siglist[sig]);
41 #else
42   printf (_("Caught signal %d...  Exiting.\n"), sig);
43 #endif
44 #endif
45 #endif
46   exit (0);
47 }
48
49 RETSIGTYPE chld_handler (int sig)
50 {
51   /* empty */
52 }
53
54 RETSIGTYPE sighandler (int sig)
55 {
56   int save_errno = errno;
57
58   switch (sig) {
59   case SIGTSTP:                /* user requested a suspend */
60     if (!option (OPTSUSPEND))
61       break;
62     IsEndwin = isendwin ();
63     curs_set (1);
64     if (!IsEndwin)
65       endwin ();
66     kill (0, SIGSTOP);
67
68   case SIGCONT:
69     if (!IsEndwin)
70       refresh ();
71     mutt_curs_set (-1);
72 #if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
73     /* We don't receive SIGWINCH when suspended; however, no harm is done by
74      * just assuming we received one, and triggering the 'resize' anyway. */
75     SigWinch = 1;
76 #endif
77     break;
78
79 #if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
80   case SIGWINCH:
81     SigWinch = 1;
82     break;
83 #endif
84
85   case SIGINT:
86     SigInt = 1;
87     break;
88
89   }
90   errno = save_errno;
91 }
92
93 #ifdef USE_SLANG_CURSES
94 int mutt_intr_hook (void)
95 {
96   return (-1);
97 }
98 #endif /* USE_SLANG_CURSES */
99
100 void mutt_signal_init (void)
101 {
102   struct sigaction act;
103
104   sigemptyset (&act.sa_mask);
105   act.sa_flags = 0;
106   act.sa_handler = SIG_IGN;
107   sigaction (SIGPIPE, &act, NULL);
108
109   act.sa_handler = exit_handler;
110   sigaction (SIGTERM, &act, NULL);
111   sigaction (SIGHUP, &act, NULL);
112   sigaction (SIGQUIT, &act, NULL);
113
114   /* we want to avoid race conditions */
115   sigaddset (&act.sa_mask, SIGTSTP);
116
117   act.sa_handler = sighandler;
118
119   /* we want SIGALRM to abort the current syscall, so we do this before
120    * setting the SA_RESTART flag below.  currently this is only used to
121    * timeout on a connect() call in a reasonable amout of time.
122    */
123   sigaction (SIGALRM, &act, NULL);
124
125   /* we also don't want to mess with interrupted system calls */
126 #ifdef SA_RESTART
127   act.sa_flags = SA_RESTART;
128 #endif
129
130   sigaction (SIGCONT, &act, NULL);
131   sigaction (SIGTSTP, &act, NULL);
132   sigaction (SIGINT, &act, NULL);
133 #if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
134   sigaction (SIGWINCH, &act, NULL);
135 #endif
136
137   /* POSIX doesn't allow us to ignore SIGCHLD,
138    * so we just install a dummy handler for it
139    */
140   act.sa_handler = chld_handler;
141   /* don't need to block any other signals here */
142   sigemptyset (&act.sa_mask);
143   /* we don't want to mess with stopped children */
144   act.sa_flags |= SA_NOCLDSTOP;
145   sigaction (SIGCHLD, &act, NULL);
146
147 #ifdef USE_SLANG_CURSES
148   /* This bit of code is required because of the implementation of
149    * SLcurses_wgetch().  If a signal is received (like SIGWINCH) when we
150    * are in blocking mode, SLsys_getkey() will not return an error unless
151    * a handler function is defined and it returns -1.  This is needed so
152    * that if the user resizes the screen while at a prompt, it will just
153    * abort and go back to the main-menu.
154    */
155   SLang_getkey_intr_hook = mutt_intr_hook;
156 #endif
157 }
158
159 /* signals which are important to block while doing critical ops */
160 void mutt_block_signals (void)
161 {
162   if (!option (OPTSIGNALSBLOCKED)) {
163     sigemptyset (&Sigset);
164     sigaddset (&Sigset, SIGTERM);
165     sigaddset (&Sigset, SIGHUP);
166     sigaddset (&Sigset, SIGTSTP);
167     sigaddset (&Sigset, SIGINT);
168 #if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
169     sigaddset (&Sigset, SIGWINCH);
170 #endif
171     sigprocmask (SIG_BLOCK, &Sigset, 0);
172     set_option (OPTSIGNALSBLOCKED);
173   }
174 }
175
176 /* restore the previous signal mask */
177 void mutt_unblock_signals (void)
178 {
179   if (option (OPTSIGNALSBLOCKED)) {
180     sigprocmask (SIG_UNBLOCK, &Sigset, 0);
181     unset_option (OPTSIGNALSBLOCKED);
182   }
183 }
184
185 void mutt_block_signals_system (void)
186 {
187   struct sigaction sa;
188
189   if (!option (OPTSYSSIGNALSBLOCKED)) {
190     /* POSIX: ignore SIGINT and SIGQUIT & block SIGCHLD  before exec */
191     sa.sa_handler = SIG_IGN;
192     sa.sa_flags = 0;
193     sigemptyset (&sa.sa_mask);
194     sigaction (SIGINT, &sa, &SysOldInt);
195     sigaction (SIGQUIT, &sa, &SysOldQuit);
196
197     sigemptyset (&SigsetSys);
198     sigaddset (&SigsetSys, SIGCHLD);
199     sigprocmask (SIG_BLOCK, &SigsetSys, 0);
200     set_option (OPTSYSSIGNALSBLOCKED);
201   }
202 }
203
204 void mutt_unblock_signals_system (int catch)
205 {
206   if (option (OPTSYSSIGNALSBLOCKED)) {
207     sigprocmask (SIG_UNBLOCK, &SigsetSys, NULL);
208     if (catch) {
209       sigaction (SIGQUIT, &SysOldQuit, NULL);
210       sigaction (SIGINT, &SysOldInt, NULL);
211     }
212     else {
213       struct sigaction sa;
214
215       sa.sa_handler = SIG_DFL;
216       sigemptyset (&sa.sa_mask);
217       sa.sa_flags = 0;
218       sigaction (SIGQUIT, &sa, NULL);
219       sigaction (SIGINT, &sa, NULL);
220     }
221
222     unset_option (OPTSYSSIGNALSBLOCKED);
223   }
224 }
225
226 void mutt_allow_interrupt (int disposition)
227 {
228   struct sigaction sa;
229
230   memset (&sa, 0, sizeof sa);
231   sa.sa_handler = sighandler;
232 #ifdef SA_RESTART
233   if (disposition == 0)
234     sa.sa_flags |= SA_RESTART;
235 #endif
236   sigaction (SIGINT, &sa, NULL);
237 }