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