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