/*  C K C S I G . H  */

/*  Definitions and prototypes for signal handling  */

/*
  Author: Jeffrey E Altman (jaltman@secure-endpoints.com),
  Secure Endpoints Inc., New York City.

  Copyright (C) 1985, 2004,
    Trustees of Columbia University in the City of New York.
    All rights reserved.  See the C-Kermit COPYING.TXT file or the
    copyright text in the ckcmai.c module for disclaimer and permissions.
*/
#ifdef OS2
#ifndef NT
#ifndef __HEV__                 /* INCL_SEMAPHORE may also define HEV */
#define __HEV__
typedef  ULONG    HEV;                  /* hev */
typedef  HEV      *PHEV;
#endif /* __HEV__ */
#endif /* NT */
struct _threadinfo {
    int inuse;
    int child;
    int sibling;
#ifdef NT
    HANDLE id;
    HANDLE handle;
    HANDLE parent;
    HANDLE CompletionSem ;
    HANDLE DieSem ;
#else /* NT */
    TID id;
    TID parent;
    HEV CompletionSem;
    HEV DieSem;
#endif /* NT */
};
#endif /* OS2 */

#ifdef CK_ANSIC
typedef SIGTYP (*ck_sigfunc)(void *);
typedef SIGTYP (*ck_sighand)(int);
#else
typedef SIGTYP (*ck_sigfunc)();
typedef SIGTYP (*ck_sighand)();
#endif /* CK_ANSIC */

/* Macros for POSIX vs old-style signal handling. */

#ifdef CK_POSIX_SIG
typedef sigjmp_buf ckjmpbuf;
#else
#ifdef NT
#define NOCRYPT
#include <windows.h>
#ifdef NTASM
typedef struct {
    CONTEXT context;
    DWORD retcode;
} ckjmpbuf;
#else /* NTASM */
typedef jmp_buf ckjmpbuf;
#endif /* NTASM */
#else
typedef jmp_buf ckjmpbuf;
#endif
#endif /* CK_POSIX_SIG */
/*
  Suppose you want to pass the address of a jmp_buf bar to a function foo.
  Since jmp_buf is normally defined (typedef'd) as an array, you would do
  it like this:  foo(bar), where foo = foo(jmp_buf bar).  But suppose a
  jmp_buf is (say) a struct rather than an array.  Then you must do
  foo(&bar) where foo is foo(jmp_buf * bar).  This is controlled here in
  the traditional fashion, by ifdefs.  By default, we assume that jmp_buf
  is an array.  Define the symbol JBNOTARRAY if jmp_buf is not an array.
*/
#ifndef JBNOTARRAY
#ifdef NT
#define JBNOTARRAY
#endif /* NT */
#endif /* JBNOTARRAY */

#ifdef JBNOTARRAY
typedef ckjmpbuf * ckjptr;
#define ckjaddr(x) & x
#define ckjdref(x) * x
#ifdef CK_POSIX_SIG
#define cksetjmp(x) sigsetjmp(x,1)
#define cklongjmp(x,y) siglongjmp(x,y)
#else
#ifdef NT
__inline int
ck_ih(void) {
    extern int TlsIndex;
#ifdef NTSIG
    struct _threadinfo * threadinfo;
    threadinfo = (struct _threadinfo *) TlsGetValue(TlsIndex);
    if (threadinfo) {
        if (WaitAndResetSem(threadinfo->DieSem,0)) {
            ckThreadDie(threadinfo);
            return 1;                   /* This should never execute */
        }
    }
#ifdef COMMENT
    else debug( F100, "ck_ih() threadinfo is NULL","",0);
#endif /* COMMENT */
#endif /* NTSIG */
    return 0;
}
#ifdef NTSIG
#define cksetjmp(x) setjmp(x)
#define cklongjmp(x,y) longjmp(x,y)
#else /* NTSIG */
#ifdef NTASM
__inline DWORD
cksetjmp( ckjptr jmp ) {
    extern int isinterrupted;
    jmp->retcode = 0;
    memset( &jmp->context, 0, sizeof(CONTEXT) );
    jmp->context.ContextFlags = CONTEXT_FULL ;
    if ( !GetThreadContext( GetCurrentThread(), &jmp->context ) )
      debug( F101, "cksetjmp GetThreadContext failed","",GetLastError());
    debug(F101,"cksetjmp returns","",jmp->retcode);
    isinterrupted = 0;
    return (jmp->retcode);
}

__inline void
cklongjmp( ckjptr jmp, int retval ) {
    extern HANDLE tidCommand;
    extern int ttyfd, mdmtyp ;
    extern DWORD CommandID;
    extern int isinterrupted;

    connoi();
    isinterrupted = 1;
    jmp->retcode = ( retval ? retval : 1 );
    debug(F101,"about to SetThreadContext for thread","", CommandID);
    debug(F101,"from Thread","",GetCurrentThreadId());
    if ( mdmtyp >= 0 ) {
        PurgeComm( (HANDLE) ttyfd, PURGE_TXABORT | PURGE_RXABORT );
    }
    if (SetThreadContext( tidCommand, &jmp->context ))
      debug(F100,"cklongjmp SetThreadContext success","",0);
    else
      debug(F101,"cklongjmp SetThreadContext failed","",GetLastError());
    msleep(50);
    cmini(1);                           /* Reset command parser */
    putkey(13);                         /* Stuff a carriage return */
   /* PostEventAvailSem(); */
}
#else /* NTASM */
void crash( void ) ;
#define cksetjmp(x) setjmp(x)
__inline void
cklongjmp( ckjptr jmp, int retval ) {
    extern HANDLE tidCommand;
    extern int ttyfd, mdmtyp;
    extern DWORD CommandID;
    CONTEXT context;

    if ( mdmtyp >= 0 ) {
        PurgeComm( (HANDLE) ttyfd, PURGE_TXABORT | PURGE_RXABORT ) ;
    }
    memset( &context, 0, sizeof(CONTEXT) );
    context.ContextFlags = CONTEXT_FULL;
    if ( !GetThreadContext( tidCommand, &context ) )
      debug( F101, "cklongjmp GetThreadContext failed","",GetLastError());

    /* Invalidate the instruction pointer */
    context.Eip =  (unsigned long) crash;

    debug(F101,"about to SetThreadContext for thread","", CommandID);
    debug(F101,"from Thread","",GetCurrentThreadId());
    if (SetThreadContext( tidCommand, &context ))
      debug(F100,"cklongjmp SetThreadContext success","",0);
    else
      debug(F101,"cklongjmp SetThreadContext failed","",GetLastError());
}
#endif /* NTASM */
#endif /* NTSIG */
#else /* NT */
#define cksetjmp(x) setjmp(x)
#define cklongjmp(x,y) longjmp(x,y)
#endif /* NT */
#endif /* CK_POSIX_SIG */
#else  /* jmp_buf is an array */
typedef ckjmpbuf ckjptr;
#define ckjaddr(x) x
#define ckjdref(x) x
#ifdef CK_POSIX_SIG
#define cksetjmp(x) sigsetjmp(x,1)
#define cklongjmp(x,y) siglongjmp(x,y)
#else
#define cksetjmp(x) setjmp(x)
#define cklongjmp(x,y) longjmp(x,y)
#endif /* CK_POSIX_SIG */
#endif /* JBNOTARRAY */

_PROTOTYP( int cc_execute, (ckjptr, ck_sigfunc, ck_sigfunc) );
_PROTOTYP( int alrm_execute,
          (ckjptr,
           int /* timo */,
           ck_sighand /* handler */,
           ck_sigfunc, ck_sigfunc) );
_PROTOTYP( int cc_alrm_execute,
          (ckjptr,
           int /* timo */,
           ck_sighand /* handler */,
           ck_sigfunc,
           ck_sigfunc) );

/* End of ckusig.h */
