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