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