/*----------------------------------------------------------------------

            T H E    P I N E    M A I L   S Y S T E M

   Laurence Lundblade and Mike Seibel
   Networks and Distributed Computing
   Computing and Communications
   University of Washington
   Administration Building, AG-44
   Seattle, Washington, 98195, USA
   Internet: lgl@CAC.Washington.EDU
             mikes@CAC.Washington.EDU

   Please address all bugs and comments to "pine-bugs@cac.washington.edu"

   Copyright 1989, 1990, 1991, 1992  University of Washington

    Permission to use, copy, modify, and distribute this software and its
   documentation for any purpose and without fee to the University of
   Washington is hereby granted, provided that the above copyright notice
   appears in all copies and that both the above copyright notice and this
   permission notice appear in supporting documentation, and that the name
   of the University of Washington not be used in advertising or publicity
   pertaining to distribution of the software without specific, written
   prior permission.  This software is made available "as is", and
   THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
   WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
   NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
   INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
   LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
   (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
   WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  

   Pine is in part based on The Elm Mail System:
    ***********************************************************************
    *  The Elm Mail System  -  $Revision: 2.13 $   $State: Exp $          *
    *                                                                     *
    * 			Copyright (c) 1986, 1987 Dave Taylor              *
    * 			Copyright (c) 1988, 1989 USENET Community Trust   *
    ***********************************************************************
 

  ----------------------------------------------------------------------*/

/*======================================================================
     signals.c
     Different signal handlers for different signals
       - Catches all the abort signals, cleans up tty modes and then coredumps
       - Not much to do for SIGHUP
       - turn SIGWINCH into a KEY_RESIZE command
       - No signals for ^Z/suspend, but do it here anyway
       - Also set up the signal handlers, and hold signals for
         critical imap sections of code.

 ====*/

#include "headers.h"


              /* SigType is defined in osdep.h and is either int or void */
static SigType auger_in_signal(), winch_signal(), quit_signal();

SigType hup_signal();
       


/*----------------------------------------------------------------------
    Install handlers for all the signals we care to catch

A couple of complications here. Most systems/debuggers can trace back 
the calling stack past something like a SIGBUS so we can trap the signal,
reset the tty modes and do other clean up and then call abort to get a useful
core dump. Ultrix can't do this so we don't try to catch the signals.
  ----------------------------------------------------------------------*/
void
init_signals()
{
#ifndef	DOS
#ifdef DEBUG
#ifdef ULT
    if(debug < 2)
/* most systems can traceback past the sig that causes that resulted from
   violation when we catch the sig and cushion the fall. Ultrix can't.*/
#else
    if(debug < 7) 
#endif
#endif
      {
          signal(SIGILL,  auger_in_signal); 
          signal(SIGTRAP, auger_in_signal);
          signal(SIGIOT,  auger_in_signal); 
#ifndef LINUX
          signal(SIGEMT,  auger_in_signal);
          signal(SIGBUS,  auger_in_signal);
#endif /* LINUX */
          signal(SIGSEGV, auger_in_signal);
#ifndef LINUX
          signal(SIGSYS,  auger_in_signal);
#endif /* LINUX */
          signal(SIGQUIT, quit_signal);
          /* Don't catch SIGFPE cause it's rare and we use it in a hack below*/
      }

#ifdef RESIZING
    signal(SIGWINCH, winch_signal);
#endif

    signal(SIGHUP, hup_signal);
    signal(SIGPIPE, SIG_IGN);

#ifdef HAVE_JOB_CONTROL
    /* Some unexplained behaviour on Ultrix 4.2 (Hardy) seems to be
       resulting in Pine getting sent a SIGTSTP. Ignore it here.
       probably better to ignore it than let it happen in any case
     */
    signal(SIGTSTP, SIG_IGN); 
#endif /* HAVE_JOB_CONTROL */
#endif	/* !DOS */
}



/*----------------------------------------------------------------------
    Return all signal handling back to normal
  ----------------------------------------------------------------------*/
void
end_signals()
{
#ifndef	DOS
    dprint(5, (debugfile, "end_signals\n"));
    if((int)signal(SIGILL,  SIG_DFL) < 0) {
        fprintf(stderr, "Error resetting signals: %s\n",
                error_description(errno));
        exit(-1);
    }
    signal(SIGTRAP, SIG_DFL);
    signal(SIGIOT,  SIG_DFL);
#ifndef LINUX
    signal(SIGEMT,  SIG_DFL);
#endif /* LINUX */
    signal(SIGFPE,  SIG_DFL);
#ifndef LINUX
    signal(SIGBUS,  SIG_DFL);
#endif /* LINUX */
    signal(SIGSEGV, SIG_DFL);
#ifndef LINUX
    signal(SIGSYS,  SIG_DFL);
#endif /* LINUX */
#ifdef RESIZING
    signal(SIGWINCH, SIG_DFL);
#endif
    signal(SIGQUIT, SIG_DFL);
#ifdef HAVE_JOB_CONTROL
    signal(SIGTSTP, SIG_DFL);
#endif
#endif	/* !DOS */
}




/*----------------------------------------------------------------------
     Handle signals caused by aborts -- SIGSEGV, SIGILL
Call panic which cleans up tty modes and then core dumps
  ----------------------------------------------------------------------*/
static SigType
auger_in_signal()
{
    dprint(5, (debugfile, "auger_in_signal()\n"));
    panic("Received abort signal");
    /* No return from panic */
}




/*----------------------------------------------------------------------
  Catch the quit signal and log in .debug file so we can know if a core
file is the result of the user typing ^\. Otherwise do minimum
processing here.
  ----------------------------------------------------------------------*/

static SigType
quit_signal()
{
    dprint(1, (debugfile, "\n\n  *** Received QUIT signal ***  \n\n"));
#ifndef	DOS
    if(want_to("\007Pine emergency exit. REALLY ABORT PINE RIGHT NOW", 'n',
               h_wt_auger_in, 0) == 'n') {
        q_status_message(0, 2,3,
          "Type ^L (control-L) to repaint the screen and continue with Pine");
        do {
            display_message('x');
        } while(messages_queued() > 0);
        return;
    }
#ifdef DEBUG
    if(debug)
      fflush(debugfile);
#endif
    fprintf(stderr, "\n\nPine aborting and dumping core\n\n");
    dprint(1, (debugfile, "\n *** Dumping Core ***\n"));
    coredump();
#endif	/* !DOS */
}



/*----------------------------------------------------------------------
      handle hang up signal -- SIGHUP

Not much to do. Rely on periodic mail file check pointing.
  ----------------------------------------------------------------------*/
SigType
hup_signal()
{
    dprint(1, (debugfile, "\n\n** Received SIGHUP **\n\n\n\n"));
#ifndef	DOS

    if(ps_global->inbox_stream != NULL && !ps_global->inbox_stream->lock){
        if(ps_global->inbox_stream == ps_global->mail_stream)
          ps_global->mail_stream = NULL; 
        mail_close(ps_global->inbox_stream);
    }

    if(ps_global->mail_stream != NULL &&
       ps_global->mail_stream != ps_global->inbox_stream &&
       !ps_global->mail_stream->lock)
      mail_close(ps_global->mail_stream);

    end_screen();
    end_keyboard(ps_global->use_fkeys);
    end_tty_driver(ps_global);


#ifdef DEBUG
    fclose(debugfile);
#endif    
#endif	/* !DOS */
    printf("\n\nPine finished. Received hang up signal\n\n");

    exit(0);
}




#ifdef RESIZING
/*----------------------------------------------------------------------
   Handle window resize signal -- SIGWINCH
  
   The planned strategy is just force a redraw command. This is similar
  to new mail handling which forces a noop command. The signals are
  help until pine reads input. Then a KEY_RESIZE is forced into the command
  stream .
  ----------------------------------------------------------------------*/
extern jmp_buf  winch_state;
extern int      ready_for_winch, winch_occured;

static SigType
winch_signal()
{
	dprint(9,(debugfile, "SIGWINCH ready_for_winch: %d winch_occured:%d\n",
                   ready_for_winch, winch_occured));
        get_windsize(ps_global->ttyo);
        if(ready_for_winch)
          longjmp(winch_state, 1);
        else
          winch_occured = 1;
}
#endif



/*----------------------------------------------------------------------
     Suspend Pine. Reset tty and suspend. Suspend is done when this returns

   Args:  The pine structure

 Result:  Execution suspended for a while. Screen will need redrawing 
          after this is done.

 Instead of the usual handling of ^Z by catching a signal, we actually read
the ^Z and then clean up the tty driver, then kill ourself to stop, and 
pick up where we left off when execution resumes.
  ----------------------------------------------------------------------*/
void
do_suspend(pine) 
    struct pine *pine;
{
#ifdef	DOS
    int  result;
#endif
    long now, then;
    char curf[MAXPATH+1];

    if(!have_job_control())
      return;

    strcpy(curf, ps_global->cur_folder);
    expand_foldername(curf);
    then = time(0);
    dprint(1, (debugfile, "\n\n - %s --- SUSPEND ----  %s",curf,ctime(&then)));
    end_keyboard(pine->use_fkeys);
    end_tty_driver(pine);
    end_screen();
    printf("\nPine suspended. Give the \"fg\" command to come back.\n");
    if(curf[0] == '{') 
      printf("Warning: Your IMAP connection will be closed if Pine\nis suspended for more than 30 minutes\n\n");
    fflush(stdout);

#ifdef	DOS
    result = system("command");
    /* redraw */
    if(result == -1){
	("Error loading COMMAND.COM");
    }
#else
    stop_process();
#endif	/* DOS */
    now = time(0);
    dprint(1, (debugfile, "\n\n ---- RETURN FROM SUSPEND ----  %s",
               ctime(&now)));
    init_screen();
    init_tty_driver(pine);
    init_keyboard(pine->use_fkeys);
 
    if(curf[0] == '{' &&
       (char *)mail_ping(ps_global->mail_stream) == NULL) {
        q_status_message(1, 3, 6,
                         "\007Suspended for too long, IMAP connection broken");
    }
}


#ifdef	DOS
SigType (*hold_int)(), (*hold_term)();
#else
SigType (*hold_hup)(), (*hold_int)(), (*hold_term)();
#endif

/*----------------------------------------------------------------------
     Ignore signals when imap is running through critical code

 Args: stream -- The stream on which critical operation is proceeding
 ----*/

void 
mm_critical(stream)
     MAILSTREAM *stream;
{
    dprint(9, (debugfile, "Going IMAP critical on %s\n",
              stream ? stream->mailbox : "<no folder>" ));
    stream = stream; /* For compiler complaints that this isn't used */
#ifndef	DOS
    hold_hup  = signal(SIGHUP,SIG_IGN);
#endif
    hold_int  = signal(SIGINT,SIG_IGN);
    hold_term = signal(SIGTERM,SIG_IGN);
}



/*----------------------------------------------------------------------
   Reset signals after critical imap code
 ----*/
void
mm_nocritical(stream)
     MAILSTREAM *stream;
{ 
    stream = stream; /* For compiler complaints that this isn't used */

#ifndef	DOS
    (void)signal(SIGHUP, hold_hup);
#endif
    (void)signal(SIGINT, hold_int);
    (void)signal(SIGTERM, hold_term);
    dprint(9, (debugfile, "Done with IMAP critical on %s\n",
              stream ? stream->mailbox : "<no folder>" ));

}

