static char rcsid[] = "@(#)$Id: cancel.c,v 1.6 2006/07/24 18:45:00 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.6 $   $State: Exp $
 *
 *  Author: Kari Hurtta <hurtta+elm@posti.FMI.FI> 
 *****************************************************************************/


#include "headers.h"
#include "s_me.h"

DEBUG_VAR(Debug,__FILE__,"ui");

static void cancel_set_ttysig_d P_((void));
static void cancel_set_ttysig_d()
{
    /* NULL */
}

static cancel_set_ttysig_f  * SET_TTYSIG = &cancel_set_ttysig_d;

static void cancel_reset_ttysig_d P_((void));
static void cancel_reset_ttysig_d()
{
    /* NULL */
}

static cancel_reset_ttysig_f * RESET_TTYSIG = &cancel_reset_ttysig_d;

static void cancel_transient_d P_((struct string *x));
static void cancel_transient_d(x)   
     struct string *x;
{
    lib_transient(FRM("%S"),x);
}

static cancel_transient_f   * TRANSIENT = &cancel_transient_d;

static void cancel_clear_d P_((void));
static void cancel_clear_d()
{
    lib_transient(FRM(""));
}

static cancel_clear_f       * CLEAR     = &cancel_clear_d;

extern void setup_cancel_cb(cancel_set_ttysig,cancel_reset_ttysig,
			    cancel_transient,cancel_clear)
     cancel_set_ttysig_f *cancel_set_ttysig;
     cancel_reset_ttysig_f *cancel_reset_ttysig;
     cancel_transient_f  *cancel_transient;
     cancel_clear_f      *cancel_clear;
{
    SET_TTYSIG    = cancel_set_ttysig;
    RESET_TTYSIG  = cancel_reset_ttysig;
    TRANSIENT     = cancel_transient;
    CLEAR         = cancel_clear;
}

#define CANCEL_magic            0xF903

struct chancel_data {
    unsigned short              magic;    /* CANCEL_magic */

    struct string         *msg;
    VOLATILE int          is_canceled;
    struct chancel_data * previous;

} * new_cancel P_((const char * format, const char *msg, ...));

static struct chancel_data  * VOLATILE current = NULL;

#ifdef POSIX_SIGNALS
static struct sigaction saved_state;
static              int state_set = 0;

static void SA_HANDLER P_((int sig));
static void SA_HANDLER(sig)
     int sig;
{
    SIGDPRINT(Debug,1,(&Debug,"Got SIGINT ...\n"));

    if (!current) {
	panic("CANCEL PANIC",__FILE__,__LINE__,
	      "SA_HANDLER",
	      "current pointer is not set",1);
	return;
    }

    if (CANCEL_magic != current->magic)
	panic("CANCEL PANIC",__FILE__,__LINE__,
	      "SA_HANDLER",
	      "Bad current pointer",1);

    current->is_canceled = 1;
}

#endif

struct chancel_data * new_cancel (
#if ANSI_C
				  const char * format, 
				  const char *msg, 
				  ...
#else
				  format,msg, va_alist
#endif
)
#if !ANSI_C
     CONST char * format; 
     CONST char *msg;
     va_dcl
#endif
{
    va_list vl;

    struct string  *store;
    struct chancel_data *ret;

    Va_start(vl, msg);           /* defined in defs.h */

    store = elm_smessage(160,format,msg,vl);

    va_end(vl);

    TRANSIENT(store);

    ret = safe_malloc(sizeof (*ret));

    bzero((void *)ret,sizeof (*ret));

    ret->magic         = CANCEL_magic;
    ret->msg           = store;
    ret->is_canceled   = 0;
    ret->previous      = NULL;

    if (current) {
	if (CANCEL_magic != current->magic)
	    panic("CANCEL PANIC",__FILE__,__LINE__,
		  "new_cancel",
		  "Bad current pointer",0);

	ret->previous = current;
    } else {
#ifdef POSIX_SIGNALS
	struct sigaction act;

	bzero((void *)&act,sizeof (act));

	act.sa_handler = &SA_HANDLER;
	sigemptyset(&(act.sa_mask)); /* No signal to mask while in handler */
	act.sa_flags = 0;
#ifdef SA_INTERRUPT
	act.sa_flags |= SA_INTERRUPT;           /* SunOS */
#endif

	state_set = 0;
	bzero((void *)&saved_state,sizeof (saved_state));
	
	current = ret;

	if (0 == sigaction(SIGINT,&act,&saved_state)) {
	    DPRINT(Debug,10,(&Debug,"SIGINT handler installed\n"));
	    state_set = 1;
	} else {
	    DPRINT(Debug,10,(&Debug,"Failed to set SIGINT handler\n"));
	}

#endif
	SET_TTYSIG();
    }
    current = ret;

    return ret;
}


int is_canceled(cd)
     struct chancel_data *cd;
{
    int ret;
    if (CANCEL_magic != cd->magic)
	panic("CANCEL PANIC",__FILE__,__LINE__,
	      "is_canceled",
	      "Bad pointer (magic)",0);

    ret = cd->is_canceled;
    if (ret) {
	struct string * X = 
	    format_string(CATGETS(elm_msg_cat, MeSet, MeCanceled,
				  "%S canceled"),
			  cd->msg);
	TRANSIENT(X);
	free_string(&X);
    }
    return ret; 
}

void free_cancel(cd)
     struct chancel_data **cd;
{
    struct chancel_data *x = *cd;

    if (CANCEL_magic != x->magic)
	panic("CANCEL PANIC",__FILE__,__LINE__,
	      "free_cancel",
	      "Bad pointer (magic)",0);

    if (current != x)
	panic("CANCEL PANIC",__FILE__,__LINE__,
	      "free_cancel",
	      "pointer not current",0);
	
    if (x->previous &&
	CANCEL_magic != x->previous->magic)
	panic("CANCEL PANIC",__FILE__,__LINE__,
	      "free_cancel",
	      "bad previous pointer",0);

    if (x->previous) {
	TRANSIENT(x->previous->msg);
    } else {
	RESET_TTYSIG();
	CLEAR();

#ifdef POSIX_SIGNALS
	if (!state_set) {
	    DPRINT(Debug,10,(&Debug,"SIGINT was not handler installed\n"));
	} else if (0 == sigaction(SIGINT,&saved_state,NULL)) {
	    DPRINT(Debug,10,(&Debug,"SIGINT handler is reset\n"));
	} else {
	    DPRINT(Debug,1,(&Debug,"failed to reset SIGINT handler\n"));
	}
	state_set = 0;
#endif	
    } 

    current = x->previous;    
  
    free_string (& (x->msg) );
    x->magic = 0;
    free(x);
    x = NULL;

    *cd =  x;
}



/*
 * Local Variables:
 *  mode:c
 *  c-basic-offset:4
 *  buffer-file-coding-system: iso-8859-1
 * End:
 */


syntax highlighted by Code2HTML, v. 0.9.1