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