--- /dev/null
+/*
+ * Copyright notice from original mutt:
+ * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
+ *
+ * This file is part of mutt-ng, see http://www.muttng.org/.
+ * It's licensed under the GNU General Public License,
+ * please see the file GPL in the top level source directory.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <signal.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+#include <lib-lib/macros.h>
+
+#include <lib-ui/curses.h>
+
+#include "mutt_signal.h"
+
+static sigset_t Sigset;
+static sigset_t SigsetSys;
+static struct sigaction SysOldInt;
+static struct sigaction SysOldQuit;
+static int IsEndwin = 0;
+
+/* Attempt to catch "ordinary" signals and shut down gracefully. */
+RETSIGTYPE exit_handler (int sig)
+{
+ curs_set (1);
+ endwin (); /* just to be safe */
+#ifdef SYS_SIGLIST_DECLARED
+ printf (_("%s... Exiting.\n"), sys_siglist[sig]);
+#else
+#if defined(__sun__) && defined(__svr4__)
+ printf (_("Caught %s... Exiting.\n"), _sys_siglist[sig]);
+#else
+#if defined(__alpha) && defined(__osf__)
+ printf (_("Caught %s... Exiting.\n"), __sys_siglist[sig]);
+#else
+ printf (_("Caught signal %d... Exiting.\n"), sig);
+#endif
+#endif
+#endif
+ exit (0);
+}
+
+RETSIGTYPE chld_handler(int sig __attribute__((unused)))
+{
+ /* empty */
+}
+
+RETSIGTYPE sighandler (int sig)
+{
+ int save_errno = errno;
+
+ switch (sig) {
+ case SIGTSTP: /* user requested a suspend */
+ if (!option (OPTSUSPEND))
+ break;
+ IsEndwin = isendwin ();
+ curs_set (1);
+ if (!IsEndwin)
+ endwin ();
+ kill (0, SIGSTOP);
+
+ case SIGCONT:
+ if (!IsEndwin)
+ refresh ();
+ mutt_curs_set (-1);
+#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
+ /* We don't receive SIGWINCH when suspended; however, no harm is done by
+ * just assuming we received one, and triggering the 'resize' anyway. */
+ SigWinch = 1;
+#endif
+ break;
+
+#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
+ case SIGWINCH:
+ SigWinch = 1;
+ break;
+#endif
+
+ case SIGINT:
+ SigInt = 1;
+ break;
+
+ }
+ errno = save_errno;
+}
+
+#ifdef USE_SLANG_CURSES
+int mutt_intr_hook (void)
+{
+ return (-1);
+}
+#endif /* USE_SLANG_CURSES */
+
+void mutt_signal_initialize (void)
+{
+ struct sigaction act;
+
+ sigemptyset (&act.sa_mask);
+ act.sa_flags = 0;
+ act.sa_handler = SIG_IGN;
+ sigaction (SIGPIPE, &act, NULL);
+
+ act.sa_handler = exit_handler;
+ sigaction (SIGTERM, &act, NULL);
+ sigaction (SIGHUP, &act, NULL);
+ sigaction (SIGQUIT, &act, NULL);
+
+ /* we want to avoid race conditions */
+ sigaddset (&act.sa_mask, SIGTSTP);
+
+ act.sa_handler = sighandler;
+
+ /* we want SIGALRM to abort the current syscall, so we do this before
+ * setting the SA_RESTART flag below. currently this is only used to
+ * timeout on a connect() call in a reasonable amout of time.
+ */
+ sigaction (SIGALRM, &act, NULL);
+
+ /* we also don't want to mess with interrupted system calls */
+#ifdef SA_RESTART
+ act.sa_flags = SA_RESTART;
+#endif
+
+ sigaction (SIGCONT, &act, NULL);
+ sigaction (SIGTSTP, &act, NULL);
+ sigaction (SIGINT, &act, NULL);
+#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
+ sigaction (SIGWINCH, &act, NULL);
+#endif
+
+ /* POSIX doesn't allow us to ignore SIGCHLD,
+ * so we just install a dummy handler for it
+ */
+ act.sa_handler = chld_handler;
+ /* don't need to block any other signals here */
+ sigemptyset (&act.sa_mask);
+ /* we don't want to mess with stopped children */
+ act.sa_flags |= SA_NOCLDSTOP;
+ sigaction (SIGCHLD, &act, NULL);
+
+#ifdef USE_SLANG_CURSES
+ /* This bit of code is required because of the implementation of
+ * SLcurses_wgetch(). If a signal is received (like SIGWINCH) when we
+ * are in blocking mode, SLsys_getkey() will not return an error unless
+ * a handler function is defined and it returns -1. This is needed so
+ * that if the user resizes the screen while at a prompt, it will just
+ * abort and go back to the main-menu.
+ */
+ SLang_getkey_intr_hook = mutt_intr_hook;
+#endif
+}
+
+/* signals which are important to block while doing critical ops */
+void mutt_block_signals (void)
+{
+ if (!option (OPTSIGNALSBLOCKED)) {
+ sigemptyset (&Sigset);
+ sigaddset (&Sigset, SIGTERM);
+ sigaddset (&Sigset, SIGHUP);
+ sigaddset (&Sigset, SIGTSTP);
+ sigaddset (&Sigset, SIGINT);
+#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
+ sigaddset (&Sigset, SIGWINCH);
+#endif
+ sigprocmask (SIG_BLOCK, &Sigset, 0);
+ set_option (OPTSIGNALSBLOCKED);
+ }
+}
+
+/* restore the previous signal mask */
+void mutt_unblock_signals (void)
+{
+ if (option (OPTSIGNALSBLOCKED)) {
+ sigprocmask (SIG_UNBLOCK, &Sigset, 0);
+ unset_option (OPTSIGNALSBLOCKED);
+ }
+}
+
+void mutt_block_signals_system (void)
+{
+ struct sigaction sa;
+
+ if (!option (OPTSYSSIGNALSBLOCKED)) {
+ /* POSIX: ignore SIGINT and SIGQUIT & block SIGCHLD before exec */
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = 0;
+ sigemptyset (&sa.sa_mask);
+ sigaction (SIGINT, &sa, &SysOldInt);
+ sigaction (SIGQUIT, &sa, &SysOldQuit);
+
+ sigemptyset (&SigsetSys);
+ sigaddset (&SigsetSys, SIGCHLD);
+ sigprocmask (SIG_BLOCK, &SigsetSys, 0);
+ set_option (OPTSYSSIGNALSBLOCKED);
+ }
+}
+
+void mutt_unblock_signals_system (int catch)
+{
+ if (option (OPTSYSSIGNALSBLOCKED)) {
+ sigprocmask (SIG_UNBLOCK, &SigsetSys, NULL);
+ if (catch) {
+ sigaction (SIGQUIT, &SysOldQuit, NULL);
+ sigaction (SIGINT, &SysOldInt, NULL);
+ }
+ else {
+ struct sigaction sa;
+
+ sa.sa_handler = SIG_DFL;
+ sigemptyset (&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction (SIGQUIT, &sa, NULL);
+ sigaction (SIGINT, &sa, NULL);
+ }
+
+ unset_option (OPTSYSSIGNALSBLOCKED);
+ }
+}
+
+void mutt_allow_interrupt (int disposition)
+{
+ struct sigaction sa;
+
+ p_clear(&sa, 1);
+ sa.sa_handler = sighandler;
+#ifdef SA_RESTART
+ if (disposition == 0)
+ sa.sa_flags |= SA_RESTART;
+#endif
+ sigaction (SIGINT, &sa, NULL);
+}