char *ckxv = "OS/2 Communications I/O, 5A(141), 1 Oct 94"; /* Define this symbol to allow setting the title bar... */ /* Not recommended because the call to do this is undocumented. */ /* #define CK_SETTITLE */ /* C K O T I O -- Kermit communications I/O support for OS/2 systems */ /* Also contains code to emulate the UNIX alarm() function under OS/2 and a set of opendir/readdir/closedir, etc, functions. */ /* Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET), Columbia University Academic Information Systems, New York City. Copyright (C) 1985, 1993, Trustees of Columbia University in the City of New York. The C-Kermit software may not be, in whole or in part, licensed or sold for profit as a software product itself, nor may it be included in or distributed with commercial products or otherwise distributed by commercial concerns to their clients or customers without written permission of the Office of Kermit Development and Distribution, Columbia University. This copyright notice must not be removed, altered, or obscured. Originally adapted to OS/2 by Chris Adie , Edinburgh University Computing Service, 1988. Adapted to C-Kermit 5A by Kai Uwe Rommel , 1992-93. Many contributions by Jeffrey Altman for 5A(190), 1993-94. */ /* Includes */ #include "ckcdeb.h" /* Typedefs, debug formats, etc */ #include "ckcasc.h" /* ASCII character names */ #include "ckcker.h" /* Kermit definitions */ #include "ckcnet.h" /* Kermit definitions */ #include "ckuxla.h" /* Translation tables */ #include /* Character types */ #include /* Standard i/o */ #include /* File io function declarations */ #include #include /* Process-control functions */ #include /* String manipulation declarations */ #include /* Standard library declarations */ #include #include #include /* Time functions */ #include #include #include #include "ckodir.h" /* Version herald(s) */ #include "ckuver.h" char ckxsystem[64] = HERALD; char *ckxsys = ckxsystem; #ifdef __32BIT__ static char *ckxrev = "32-bit"; #else static char *ckxrev = "16-bit"; #endif /* OS/2 system header files & related stuff */ #ifndef __32BIT__ #ifdef OS2PM #undef OS2PM #endif /* OS2PM */ #define far _far #define near _near #define pascal _pascal #endif #define INCL_WINSWITCHLIST #define INCL_ERRORS #define INCL_KBD #ifdef OS2MOUSE #define INCL_MOU #endif /* OS2MOUSE */ #define INCL_VIO #define INCL_DOSMISC #define INCL_DOSPROCESS #define INCL_DOSSEMAPHORES #define INCL_DOSQUEUES #define INCL_DOSSIGNALS #define INCL_DOSDEVICES #define INCL_DOSDEVIOCTL #define INCL_DOSNLS #ifdef __32BIT__ #define INCL_DOSASYNCTIMER #define INCL_DOSDATETIME #endif /* __32BIT__ */ #ifdef OS2PM #define INCL_DOSNMPIPES #endif /* OS2PM */ #include /* This pulls in a whole load of stuff */ #ifdef CK_REXX #define INCL_REXXSAA #include #endif /* CK_REXX */ #undef COMMENT #ifdef CHAR #undef CHAR #endif /* CHAR */ /* Variables available to outside world: dftty -- Pointer to default tty name string, like "/dev/tty". dfloc -- 0 if dftty is console, 1 if external line. dfprty -- Default parity dfflow -- Default flow control ckxech -- Flag for who echoes console typein: 1 - The program (system echo is turned off) 0 - The system (or front end, or terminal). functions that want to do their own echoing should check this flag before doing so. Functions for assigned communication line (either external or console tty): sysinit() -- System dependent program initialization syscleanup() -- System dependent program shutdown ttopen(ttname,local,mdmtyp) -- Open the named tty for exclusive access. ttclos() -- Close & reset the tty, releasing any access lock. ttpkt(speed,flow,parity)-- Put the tty in packet mode or in DIALING or CONNECT modem control state. ttvt(speed,flow) -- Put the tty in virtual terminal mode. ttinl(dest,max,timo,...) -- Timed read packet from the tty. ttinc(timo) -- Timed read character from tty. ttchk() -- See how many characters in tty input buffer. ttxin(n,buf) -- Read n characters from tty (untimed). ttol(string,length) -- Write a string to the tty. ttoc(c) -- Write a character to the tty. ttflui() -- Flush tty input buffer. ttgspd() -- Speed of tty line. Functions for console terminal: conraw() -- Set console into Raw mode concooked() -- Set console into Cooked mode conoc(c) -- Unbuffered output, one character to console. conol(s) -- Unbuffered output, null-terminated string to the console. conola(s) -- Unbuffered output, array of strings to the console. conxo(n,s) -- Unbuffered output, n characters to the console. conchk() -- Check if characters available at console (bsd 4.2). Check if escape char (^\) typed at console (System III/V). coninc(timo) -- Timed get a character from the console. Following routines are dummies: congm() -- Get console terminal mode. concb() -- Put console into single char mode with no echo. conres() -- Restore console to congm mode. conint() -- Enable console terminal interrupts. connoi() -- No console interrupts. Time functions sleep(t) -- Like UNIX sleep msleep(m) -- Millisecond sleep ztime(&s) -- Return pointer to date/time string rtimer() -- Reset timer gtimer() -- Get elapsed time since last call to rtimer() */ /* Defines */ #define HUPTIME 1000 /* Milliseconds for hangup */ #ifdef NETCONN /* Allow for long network hostnames */ #define DEVNAMLEN 128 #else /* No networks, applies to OS/2 device names only. */ #define DEVNAMLEN 14 #endif /* NETCONN */ /* definitions hiding 32-bit / 16-bit differences */ #ifdef __32BIT__ USHORT DosDevIOCtl32(PVOID pData, USHORT cbData, PVOID pParms, USHORT cbParms, USHORT usFunction, USHORT usCategory, HFILE hDevice) { ULONG ulParmLengthInOut = cbParms, ulDataLengthInOut = cbData; return (USHORT) DosDevIOCtl(hDevice, usCategory, usFunction, pParms, cbParms, &ulParmLengthInOut, pData, cbData, &ulDataLengthInOut); } typedef ULONG U_INT; #define FILEFINDBUF FILEFINDBUF3 #define FSQBUFFER FSQBUFFER2 #define DosFindFirst(p1, p2, p3, p4, p5, p6) \ DosFindFirst(p1, p2, p3, p4, p5, p6, 1) #define DosDevIOCtl DosDevIOCtl32 #else /* Not 32-bit ... */ typedef USHORT U_INT; #define DosFindFirst(p1, p2, p3, p4, p5, p6) \ DosFindFirst(p1, p2, p3, p4, p5, p6, 0) #define DosQueryFSAttach(p1, p2, p3, p4, p5) \ DosQFSAttach(p1, p2, p3, p4, p5, 0) #define DosQueryCurrentDisk DosQCurDisk #define DosQueryFSInfo DosQFSInfo #define DosSetFHState DosSetFHandState #define DosWaitChild DosCwait #define DosDevIOCtl DosDevIOCtl2 #define DosQueryCp DosGetCp #define DosSetProcessCp(x) DosSetProcCp(x, 0) #endif /* Declarations */ /* dftty is the device name of the default device for file transfer */ /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */ extern long speed; extern int parity, fcharset, flow, ttcarr; extern KEY *keymap; extern MACRO *macrotab; #ifdef OS2PM extern int os2pm ; #endif /* OS2PM */ #ifdef COMMENT /* This is to allow remote operation */ char *dftty = "0"; /* stdin */ int dfloc = 0; #else char *dftty = "com1"; /* COM1 */ int dfloc = 1; #endif /* COMMENT */ int ttyfd = -1; /* TTY file descriptor (not open yet) */ int dfprty = 0; /* Default parity (0 = none) */ int ttprty = 0; /* Parity in use. */ int ttmdm = 0; /* Modem in use. */ int dfflow = FLO_NONE; /* Default flow is KEEP = no change */ int backgrd = 0; /* Assume in foreground */ int ttcarr = CAR_AUT; /* Carrier handling mode. */ int ckxech = 1; /* 0 if system normally echoes console characters, else 1 */ char startupdir[CCHMAXPATH] = "."; /* Declarations of variables global within this module */ static struct rdchbuf_rec { /* Buffer for serial characters */ unsigned char buffer[256]; U_INT length, index; } rdchbuf; static long tcount; /* Elapsed time counter */ static int conmode, consaved; static int ttpmsk = 0377; /* Parity stripping mask. */ int ttpflg = 0; /* Parity not sensed yet */ static char ttnmsv[DEVNAMLEN+1]; static int islocal, ishandle; int pid = 0; static DCBINFO ttydcb; static int nOldCP; static char szOldTitle[80]; #ifdef __32BIT__ HMTX hmtxAlarmSem = (HMTX) 0 ; HMTX hmtxScreenSem = (HMTX) 0 ; HEV hevKeyAvail = (HEV) 0 ; HEV hevAlarmTimer = (HEV) 0 ; HTIMER hAlarmTimer = 0 ; #define THRDSTKSIZ 32768 TID KbdHandlerThreadID = (TID) 0 ; #endif /* __32BIT__ */ /* Forward declarations */ _PROTOTYP( static int os2setdtr, (int) ); _PROTOTYP( static int os2setflow, (int) ); _PROTOTYP( static int os2setcarr, (int) ); _PROTOTYP( static int ttsettings, (int, int) ); _PROTOTYP( int ttsetspd, (long) ); _PROTOTYP( int concooked, (void) ); _PROTOTYP( int os2rexxinit, (void) ); _PROTOTYP( int os2setcp, (int) ); _PROTOTYP( int os2getcplist, (int *, int) ); _PROTOTYP( int os2getcp, (void) ); _PROTOTYP( int os2settitle, (char *) ); _PROTOTYP( int os2gettitle, (char *, int) ); _PROTOTYP( void keybufinit, (void) ) ; _PROTOTYP( void keybufcleanup, (void) ) ; _PROTOTYP( int KbdHandlerInit, (void) ) ; _PROTOTYP( int KbdHandlerCleanup, ( void ) ) ; _PROTOTYP( void KbdHandlerThread, ( void * ) ) ; #ifdef OS2PM _PROTOTYP( APIRET ConnectToPM, (void) ); _PROTOTYP( APIRET ReadFromPM, (void) ); #endif /* OS2PM */ /* Control-C interrupt handler */ void cc_trap(int sig) { signal(sig, cc_trap); #ifdef __EMX__ signal(sig, SIG_ACK); #endif } /* Saving/restoring of hot handles */ static int savedtty = 0; static long savedspeed; static LINECONTROL savedlc; static DCBINFO saveddcb; static BYTE savedstat; savetty() { if (ttyfd != -1) { savedspeed = ttgspd(); DosDevIOCtl(&savedlc,sizeof(savedlc),NULL,0, ASYNC_GETLINECTRL,IOCTL_ASYNC,ttyfd); DosDevIOCtl(&saveddcb,sizeof(saveddcb),NULL,0, ASYNC_GETDCBINFO,IOCTL_ASYNC,ttyfd); DosDevIOCtl(&savedstat,sizeof(savedstat),NULL,0, ASYNC_GETMODEMOUTPUT,IOCTL_ASYNC,ttyfd); savedtty = 1; } return 0; } restoretty() { MODEMSTATUS ms; UINT cmd = 0, data = 0 ; if (savedtty) { ttsetspd(savedspeed); DosDevIOCtl(&data,sizeof(data),&cmd,sizeof(cmd), DEV_FLUSHOUTPUT,IOCTL_GENERAL,ttyfd); DosDevIOCtl(NULL,0,&savedlc,sizeof(savedlc), ASYNC_SETLINECTRL,IOCTL_ASYNC,ttyfd); ms.fbModemOn = 0; ms.fbModemOff = 255; if (savedstat & DTR_ON) ms.fbModemOn |= DTR_ON; else ms.fbModemOff &= DTR_OFF; if (savedstat & RTS_ON) ms.fbModemOn |= RTS_ON; else ms.fbModemOff &= RTS_OFF; DosDevIOCtl(&data,sizeof(data),&ms,sizeof(ms), ASYNC_SETMODEMCTRL,IOCTL_ASYNC,ttyfd); DosDevIOCtl(NULL,0,&saveddcb,sizeof(saveddcb), ASYNC_SETDCBINFO,IOCTL_ASYNC,ttyfd); savedtty = 0; } return 0; } /* Code Page functions */ int os2getcp() { U_INT cbData, nCodePage[8]; return (DosQueryCp(sizeof(nCodePage), nCodePage, &cbData) == 0) ? nCodePage[0] : 0; } #ifdef COMMENT int os2checkcp(cp) int cp; { U_INT cbData, nCodePage[8], nCnt; if (DosQueryCp(sizeof(nCodePage), nCodePage, &cbData)) return FALSE; for (nCnt = 1; nCnt < cbData / sizeof(nCodePage[0]); nCnt++) if (nCodePage[nCnt] == cp) return TRUE; return FALSE; } #endif /* COMMENT */ int os2getcplist(cplist, size) int *cplist; int size; { U_INT cbData; if (DosQueryCp(size, (U_INT *) cplist, &cbData)) return 0; return cbData / sizeof(int); } int /* Change code page */ os2setcp(cp) int cp; { return((VioSetCp(0, cp, 0) == 0) && (KbdSetCp(0, cp, 0) == 0) && (DosSetProcessCp(cp) == 0)); } /* S Y S I N I T -- System-dependent program initialization. */ sysinit() { char *ptr; int n; #ifdef __32BIT__ PTIB pptib; PPIB pppib; DosGetInfoBlocks(&pptib, &pppib); pid = pppib -> pib_ulpid; DosError(FERR_DISABLEHARDERR | FERR_DISABLEEXCEPTION); DosCreateMutexSem( 0, &hmtxAlarmSem, 0, 0 ) ; DosCreateMutexSem( 0, &hmtxScreenSem, 0, 0 ) ; DosCreateEventSem( 0, &hevAlarmTimer, DC_SEM_SHARED, 0 ) ; keybufinit() ; /* Must come before the KbdHandler */ KbdHandlerInit() ; #else PIDINFO pi; DosGetPID(&pi); pid = pi.pid; DosError(HARDERROR_DISABLE | EXCEPTION_DISABLE); #endif signal(SIGINT, cc_trap); signal(SIGBREAK, cc_trap); os2gettitle(szOldTitle, sizeof(szOldTitle)); nOldCP = os2getcp(); switch (nOldCP) { case 437: fcharset = FC_CP437; break; case 850: fcharset = FC_CP850; break; case 852: fcharset = FC_CP852; break; } sprintf(ckxsystem, " OS/2 %1d.%02d %s", _osmajor / 10, _osminor, ckxrev); #ifdef __IBMC__ setvbuf(stdout, NULL, _IONBF, 0); setmode(1, O_TEXT); #endif /* __IBMC__ */ strcpy(startupdir, GetLoadPath()); if ( (ptr = strrchr(startupdir, '\\')) != NULL ) *ptr = 0; for (ptr = startupdir; *ptr; ptr++) /* Convert backslashes to slashes */ if (*ptr == '\\') *ptr = '/'; n = (int)strlen(startupdir); /* Add slash to end if necessary */ if (n > -1 && n < CCHMAXPATH) if (startupdir[n-1] != '/') { startupdir[n] = '/'; startupdir[n+1] = '\0'; } strcpy(ttnmsv, dftty); islocal = isatty(0) && !ttiscom(0); if (!islocal) { os2setdtr(1); ttsettings(ttprty,0); os2setflow(flow); os2setcarr(ttcarr == CAR_ON); } else concooked(); /* Initialize keyboard */ #ifdef NETCONN netinit(); #endif /* NETCONN */ #ifdef CK_REXX os2rexxinit() ; #endif /* CK_REXX */ return(0); } /* S Y S C L E A N U P -- System-dependent program cleanup. */ syscleanup() { #ifdef __32BIT__ DosCloseMutexSem( hmtxAlarmSem ) ; DosCloseMutexSem( hmtxScreenSem ) ; DosCloseEventSem( hevAlarmTimer ) ; KbdHandlerCleanup() ; keybufcleanup() ; #endif /* __32BIT__ */ #ifdef NETCONN netcleanup() ; #endif /* NETCONN */ os2settitle(szOldTitle); os2setcp(nOldCP); signal(SIGINT, SIG_DFL); signal(SIGBREAK, SIG_DFL); return(0); } /* Timeout handler for communication line input functions */ static jmp_buf kbbuf; /* Timeout longjmp targets */ static jmp_buf sjbuf; #ifndef __EMX__ unsigned alarm(unsigned); /* Prototype */ #endif /* __EMX__ */ SIGTYP (*saval)(int) = NULL; /* For saving alarm() handler */ SIGTYP timerh(foo) int foo; { /* For ttinl() timeout */ ttimoff(); longjmp(sjbuf,1); } VOID ttimoff() { /* Turn off any timer interrupts */ int xx; xx = alarm(0); if (saval) { /* Restore any previous */ signal(SIGALRM,saval); /* alarm handler. */ saval = NULL; } else { signal(SIGALRM,SIG_IGN); } } /* O S 2 S E T F L O W -- set flow state of tty */ static int os2setflow(int nflow) { /* Get the current settings */ if (DosDevIOCtl(&ttydcb,sizeof(ttydcb),NULL,0, ASYNC_GETDCBINFO,IOCTL_ASYNC,ttyfd)) return(-1); ttydcb.fbCtlHndShake = MODE_DTR_CONTROL; ttydcb.fbFlowReplace &= ~(MODE_AUTO_RECEIVE | MODE_AUTO_TRANSMIT | /* clear only a few */ MODE_RTS_CONTROL | MODE_RTS_HANDSHAKE); if (nflow == FLO_XONX) { ttydcb.fbFlowReplace |= (MODE_AUTO_RECEIVE | MODE_AUTO_TRANSMIT | MODE_RTS_CONTROL); } else if (nflow == FLO_RTSC) { ttydcb.fbCtlHndShake |= MODE_CTS_HANDSHAKE; ttydcb.fbFlowReplace |= MODE_RTS_HANDSHAKE; } else if ( nflow != FLO_KEEP ) { ttydcb.fbFlowReplace |= MODE_RTS_CONTROL; } /* set write timeout */ ttydcb.fbTimeout &= ~MODE_NO_WRITE_TIMEOUT; ttydcb.usWriteTimeout = 15 * 100; /* 15-second timeout */ /* Read "some" data from line mode */ ttydcb.fbTimeout &= ~MODE_NOWAIT_READ_TIMEOUT; ttydcb.fbTimeout |= MODE_WAIT_READ_TIMEOUT; /* Set DCB */ if (DosDevIOCtl(NULL,0,&ttydcb,sizeof(ttydcb), ASYNC_SETDCBINFO,IOCTL_ASYNC,ttyfd)) return(-1); if (nflow != FLO_RTSC && nflow != FLO_KEEP) {/* keep RTS permanently on */ MODEMSTATUS ms; UINT data; ms.fbModemOn = RTS_ON; ms.fbModemOff = 255; DosDevIOCtl(&data,sizeof(data),&ms,sizeof(ms), ASYNC_SETMODEMCTRL,IOCTL_ASYNC,ttyfd); } return(0); } static int os2setcarr(int ncarr) { /* Get the current settings */ if (DosDevIOCtl(&ttydcb,sizeof(ttydcb),NULL,0, ASYNC_GETDCBINFO,IOCTL_ASYNC,ttyfd)) return(-1); if (ncarr) ttydcb.fbCtlHndShake |= MODE_DCD_HANDSHAKE; else ttydcb.fbCtlHndShake &= ~MODE_DCD_HANDSHAKE; /* Set DCB */ if (DosDevIOCtl(NULL,0,&ttydcb,sizeof(ttydcb), ASYNC_SETDCBINFO,IOCTL_ASYNC,ttyfd)) return(-1); return(0); } /* O S 2 S E T D T R -- set state of DTR signal */ static int os2setdtr(int on) { MODEMSTATUS ms; UINT data; if (ttyfd == -1) return(0); ms.fbModemOn = on ? DTR_ON : 0; ms.fbModemOff = on ? 255 : DTR_OFF; return(DosDevIOCtl(&data,sizeof(data),&ms,sizeof(ms), ASYNC_SETMODEMCTRL,IOCTL_ASYNC,ttyfd)); } /* T T S E T T I N G S -- Set the device driver parity and stop bits */ static int ttsettings(int par, int stop) { LINECONTROL lc; if (DosDevIOCtl(&lc,sizeof(lc),NULL,0, ASYNC_GETLINECTRL,IOCTL_ASYNC,ttyfd)) return(-1); /* Get line */ #ifdef COMMENT switch (par) { case 'o': lc.bDataBits = 7; /* Data bits */ lc.bParity = 1; break; case 'e': lc.bDataBits = 7; /* Data bits */ lc.bParity = 2; break; case 'm': lc.bDataBits = 7; /* Data bits */ lc.bParity = 3; break; case 's': lc.bDataBits = 7; /* Data bits */ lc.bParity = 4; break; default : lc.bDataBits = 8; /* Data bits */ lc.bParity = 0; /* No parity */ } #else /* Always let Kermit handle parity itself */ lc.bDataBits = 8; /* Data bits */ lc.bParity = 0; /* No parity */ #endif /* COMMENT */ switch (stop) { case 2: lc.bStopBits = 2; /* Two stop bits */ break; case 1: lc.bStopBits = 0; /* One stop bit */ break; default: /* No change */ break; } if (DosDevIOCtl(NULL,0,&lc,sizeof(lc), ASYNC_SETLINECTRL,IOCTL_ASYNC,ttyfd)) return(-1); /* Set line */ return(0); } /* T T O P E N -- Open a tty for exclusive access. */ /* Returns 0 on success, -1 on failure. */ /* If called with lcl < 0, sets value of lcl as follows: 0: the terminal named by ttname is the job's controlling terminal. 1: the terminal named by ttname is not the job's controlling terminal. But watch out: if a line is already open, or if requested line can't be opened, then lcl remains (and is returned as) -1. */ ttopen(char *ttname, int *lcl, int modem, int spare) { char *x; extern char* ttyname(); U_INT action, res; debug(F111,"ttopen DEVNAMLEN","",DEVNAMLEN); debug(F111,"ttopen entry modem",ttname,modem); debug(F101," ttyfd","",ttyfd); rdchbuf.length = rdchbuf.index = 0; if (ttyfd > -1) { /* if device already opened */ if (strncmp(ttname,ttnmsv,DEVNAMLEN)) { /* new & old names equal? */ debug(F111,"ttopen closing",ttname,ttyfd); ttclos(ttyfd); /* no, close old ttname, open new */ } else { /* else same, ignore this call, */ debug(F111,"ttopen already open",ttname,ttyfd); return(0); /* and return. */ } } if (*lcl == 0) return(-1); /* Won't open in local mode */ ishandle = 0; ttmdm = modem; /* Make this available to other fns */ debug(F111,"ttname",ttname,(int) strlen(ttname)); strncpy(ttnmsv, ttname, DEVNAMLEN); /* Keep copy of name locally. */ #ifdef NETCONN if (modem < 0) return os2_netopen(ttname, lcl, -modem); #endif /* NETCONN */ /* This code lets you give Kermit an open file descriptor for a serial communication device, rather than a device name. Kermit assumes that the line is already open, conditioned with the right parameters, etc. */ for (x = ttname; isdigit(*x); x++) ; /* Check for all digits */ if (*x == '\0') { ttyfd = atoi(ttname); ishandle = 1; *lcl = 1; /* Assume it's local. */ if (ttiscom(ttyfd)) return savetty(); ttyfd = -1; return(-4); } if (res = DosOpen(ttname,(PHFILE)&ttyfd,&action,0L,0,FILE_OPEN, OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE | OPEN_FLAGS_FAIL_ON_ERROR ,0L)) { ttyfd = -1; return((res == ERROR_SHARING_VIOLATION) ? -5 : -1); } debug(F111,"ttopen ok",ttname,*lcl); /* Caller wants us to figure out if line is controlling tty */ if (*lcl == -1) { *lcl = 1; /* Can never transfer with console */ } if (!ttiscom(ttyfd)) { /* Not a serial port */ ttclos(0); return(-4); } savetty(); ttprty = dfprty; /* Make parity the default parity */ if (ttsettings(ttprty,0)) return(-1); return(ttflui()); } /* T T I S C O M -- Is the given handle an open COM port? */ ttiscom(int f) { DCBINFO testdcb; /* Read DCB */ if (DosDevIOCtl(&testdcb,sizeof(testdcb),NULL,0, ASYNC_GETDCBINFO,IOCTL_ASYNC,f)) { return( 0 ); /* Bad, not a serial port */ } return( 1 ); /* Good */ } /* T T C L O S -- Close the TTY. */ ttclos(int spare) { #ifdef NETCONN if (ttmdm < 0) return os2_netclos(); #endif /* NETCONN */ if (ttyfd == -1) return(0); /* Wasn't open. */ if (savedtty) restoretty(); if (!ishandle) DosClose(ttyfd); ishandle = 0; ttyfd = -1; return(0); } /* T T G S P D -- return speed of COM port, or of default line */ long ttgspd() { long sp = 0; struct { long current_rate; char current_fract; long minimum_rate; char minimum_fract; long maximum_rate; char maximum_fract; } speed; if (ttyfd == -1) return(-1); if (DosDevIOCtl(&speed,sizeof(speed),NULL,0,0x0063,IOCTL_ASYNC,ttyfd) == 0) return speed.current_rate; else if (DosDevIOCtl(&sp,sizeof(sp),NULL,0, ASYNC_GETBAUDRATE,IOCTL_ASYNC,ttyfd) == 0) return sp; else return -1; } ttsetspd(long sp) { struct { long rate; char fract; } speed; if (ttyfd == -1) return(-1); /* Not open */ if (sp > 65535L) { speed.rate = sp; speed.fract = 0; return DosDevIOCtl(NULL,0,&speed,sizeof(speed),0x0043,IOCTL_ASYNC,ttyfd); } else return DosDevIOCtl(NULL,0,&sp,sizeof(sp), ASYNC_SETBAUDRATE,IOCTL_ASYNC,ttyfd); } /* T T H A N G -- Hangup phone line */ tthang() { #ifdef NETCONN if (ttmdm < 0) return os2_netclos(); #endif /* NETCONN */ /* Perhaps better to either let user specify the hangup interval, or else do something with carrier -- e.g. if CD was on when we entered this routine, then cancel the sleep as soon as it goes down, so we don't sleep longer than we need to. */ if (os2setdtr(0)) return -1; msleep(HUPTIME); os2setdtr(1); return 1; } /* T T R E S -- Restore terminal to "normal" mode. */ ttres() { /* Restore the tty to normal. */ if (ttyfd == -1) return(-1); /* Not open */ return(0); } /* T T P K T -- Condition the communication line for packets. */ /* or for modem dialing */ /* If called with speed > -1, also set the speed. */ /* Returns 0 on success, -1 on failure. */ ttpkt(long speed, int flow, int parity) { int s; if (ttmdm < 0) return(0); if (ttyfd < 0) return(-1); /* Not open. */ if (speed < 0) return(-1); ttprty = parity; ttpflg = 0; ttpmsk = ttprty ? 0177 : 0377; /* Parity stripping mask */ os2setdtr(1); if (ttsetspd(speed)) return(-1); if (ttsettings(ttprty,0)) return(-1); if (os2setflow(flow)) return(-1); if (os2setcarr(ttcarr == CAR_ON && flow != FLO_DIAL)) return(-1); DosSetPrty(PRTYS_THREAD, PRTYC_FOREGROUNDSERVER, 0, 0); return(0); } /* T T V T -- Condition communication line for use as virtual terminal */ ttvt(long speed, int flow) { if (ttmdm < 0) return(0); if (ttyfd < 0) return(-1); /* Not open. */ if (speed < 0) return(-1); ttprty = parity; os2setdtr(1); if (ttsetspd(speed)) return(-1); if (ttsettings(ttprty,0)) return(-1); if (os2setflow(flow)) return (-1); if (os2setcarr(ttcarr == CAR_ON || ttcarr == CAR_AUT)) return(-1); return(0); } /* T T S S P D -- Return the speed if OK, otherwise -1 */ int ttsspd(int speed) { long s; if (speed < 0) return(-1); s = (long) speed * 10L; ttsetspd(s); return(0); } /* T T F L U I -- Flush tty input buffer */ ttflui() { char parm=0; long int data; int i; #ifdef NETCONN if (ttmdm < 0) return os2_netflui() ; #endif /* NETCONN */ rdchbuf.index = rdchbuf.length = 0; /* Flush internal buffer */ DosDevIOCtl(&data,sizeof(data),&parm,sizeof(parm), DEV_FLUSHINPUT,IOCTL_GENERAL,ttyfd); /* Flush driver */ return(0); } /* T T C H K -- Tell how many characters are waiting in tty input buffer */ ttchk() { USHORT data[2]; #ifdef NETCONN if (ttmdm < 0) return os2_nettchk(); #endif /* NETCONN */ if(DosDevIOCtl(data,sizeof(data),NULL,0, ASYNC_GETINQUECOUNT,IOCTL_ASYNC,ttyfd)) return(0); else return((rdchbuf.length-rdchbuf.index)+data[0]); } /* T T X I N -- Get n characters from tty input buffer */ /* Returns number of characters actually gotten, or -1 on failure */ /* Intended for use only when it is known that n characters are actually */ /* available in the input buffer. */ ttxin(int n, CHAR *buf) { int i, j; if (ttyfd < 0) return(-1); /* Not open. */ i = 0; while (i < n) { if ((j = ttinc(0)) < 0) break; buf[i++] = j; } return(i); } /* T T O L -- Similar to "ttinl", but for writing. */ /* Outputs all n characters of s, or else fails with -2 if the connection is broken, or with -1 upon some other kind of error. */ int ttol(CHAR *s, int n) { UINT i; int rc = 0 ; int charsleft = n ; CHAR *chars = s ; while ( rc >= 0 && charsleft ) { #ifdef NETCONN if (ttmdm < 0) { rc = os2_nettol(chars,charsleft); } else { #endif /* NETCONN */ if (ttyfd < 0) rc = -1 ; /* Not open. */ if(DosWrite(ttyfd,s,n,(PVOID)&i)) rc = -1 ; else rc = i ; #ifdef NETCONN } #endif /* NETCONN */ if ( rc >= 0 ) { charsleft -= rc ; chars += rc ; } } return rc ; } /* T T O C -- Output a character to the communication line */ ttoc(char c) { UINT i; #ifdef NETCONN if (ttmdm < 0) return os2_nettoc(c); #endif /* NETCONN */ if (ttyfd < 0) return(-1); /* Not open. */ if(DosWrite(ttyfd,&c,1,(PVOID)&i)) return(-1); else return(i); } #ifndef NOTTOCI #define NEWTTOCI /* T T O C I -- Output a character to the communication line immediately */ #ifdef NEWTTOCI int ttoci(char c) { int x; BYTE i; ULONG Data = 0L ; #ifdef NETCONN if (ttmdm < 0) return os2_nettoc(c); #endif /* NETCONN */ if (ttyfd < 0) return(-1); /* Not open. */ x = DosDevIOCtl(&Data,sizeof(Data),0,0,ASYNC_GETCOMMSTATUS,IOCTL_ASYNC,ttyfd); if ( Data ) { debug( F101,"ttoci: Query COM Status","",Data) ; return(Data) ; } x = DosWrite(ttyfd,&c,1,(PVOID)&i) ; if (x) { debug(F101,"ttoci failure status","",x); return(x); } else return(0); } #else /* NEWTTOCI */ int ttoci(char c) { int x; #ifdef NETCONN if (ttmdm < 0) return os2_nettoc(c); #endif /* NETCONN */ if (ttyfd < 0) return(-1); /* Not open. */ x = DosDevIOCtl(NULL,0,&c,sizeof(c),ASYNC_TRANSMITIMM,IOCTL_ASYNC,ttyfd); if (x) { debug(F101,"ttoci failure status","",x); return(x); } else return(0); } #endif /* NEWTTOCI */ #endif /* NOTTOCI */ /* T T I N L -- Read a packet from the communication device. */ /* blah blah */ ttinl(CHAR *dest, int max, int timo, CHAR eol, CHAR start, int turn) { int x = 0, c, i, m; #ifdef COMMENT /* old code -- worked, but no parity detection, no DDK */ if (ttyfd < 0) return(-1); /* Not open. */ *dest = '\0'; /* Clear destination buffer */ i = 0; /* Next char to process */ while (1) { if ((c = ttinc(timo)) == -1) { x = -1; break; } dest[i] = c; /* Got one. */ if (dest[i] == eol) { dest[++i] = '\0'; return(i); } if (i++ > max) { debug(F101,"ttinl buffer overflow","",i); x = -1; break; } } debug(F100,"ttinl timout","",0); /* Get here on timeout. */ debug(F111," with",dest,i); return(x); /* and return error code. */ #else /* !COMMENT */ /* New code, lifted from the UNIX version */ unsigned char ch; int pktlen = -1; int lplen = 0; int havelen = 0; if (ttyfd < 0) return(-1); /* Not open. */ debug(F101,"ttinl max","",max); debug(F101,"ttinl timo","",timo); *dest = '\0'; /* Clear destination buffer */ if (timo < 0) timo = 0; /* Safety */ if (timo) { /* Don't time out if timo == 0 */ int xx; saval = signal(SIGALRM,timerh); /* Enable timer interrupt */ xx = alarm(timo); /* Set it. */ debug(F101,"ttinl alarm","",xx); } if (setjmp(sjbuf)) { /* Timer went off? */ debug(F100,"ttinl timout","",0); /* Get here on timeout. */ /* debug(F110," with",(char *) dest,0); */ ttimoff(); /* Turn off timer */ return(-1); /* and return error code. */ } else { /* Timer didn't go off yet, start. */ register int i, m, n; /* Local variables */ int flag = 0; debug(F000,"ttinl start","",start); flag = 0; /* Start of packet flag */ ttpmsk = m = (ttprty) ? 0177 : 0377; /* Set parity stripping mask. */ /* Now read into destination, stripping parity and looking for the */ /* the packet terminator, and also for two Ctrl-C's typed in a row. */ i = 0; /* Destination index */ debug(F101,"ttinl eol","",eol); while ((i < max-1) && (n = ttinc(0)) >= 0) { if (n == 0) { /* For some reason, ttinc() sometimes delivers */ /* a spurious NUL. Discarding it effectively */ /* works around the problem. */ debug(F100,"ttinc got NUL","",0); continue; } ch = n & 0xff; /* Here, if OS/2 C-Kermit is ever taught to run in remote mode, we would need to check for transfer cancellation (e.g. user types 3 Ctrl-C's in a row while Kermit is trying to read a packet). See ckutio.c for the code. */ if ((flag == 0) && ((n & 0x7f) == start)) flag = 1; if (flag) { dest[i++] = n & ttpmsk; if (i == 2) { pktlen = xunchar(dest[1] & 0x7f); havelen = (pktlen > 1); debug(F101,"ttinl length","",pktlen); } else if (i == 5 && pktlen == 0) { lplen = xunchar(dest[4] & 0x7f); } else if (i == 6 && pktlen == 0) { pktlen = lplen * 95 + xunchar(dest[5] & 0x7f) + 5; havelen = 1; debug(F101,"ttinl length","",pktlen); } } else { debug(F101,"ttinl skipping","",n); continue; } /* Check for end of packet */ if ((havelen && (i > pktlen+1) && (!turn || (turn && (n & 0x7f) == eol))) ) { if (deblog) { if ((n & 0x7f) != eol) { debug(F101,"ttinl EOP length","",pktlen); debug(F101,"ttinl i","",i); } else debug(F101,"ttinl got eol","",eol); } dest[i] = '\0'; /* Terminate the string, */ /* Parity checked yet? */ debug(F101,"ttinl ttpflg","",ttpflg); debug(F101,"ttinl ttprty","",ttprty); debug(F101,"ttinl ttpmsk","",ttpmsk); if (ttpflg++ == 0 && ttprty == 0) { if ((ttprty = parchk(dest,start,i)) > 0) { /* No, check. */ int j; debug(F101,"ttinl senses parity","",ttprty); debug(F110,"ttinl packet before",dest,0); ttpmsk = 0x7f; for (j = 0; j < i; j++) dest[j] &= 0x7f; /* Strip parity from packet */ debug(F110,"ttinl packet after ",dest,0); } else ttprty = 0; /* restore if parchk error */ } if (timo) { /* Turn off timer. */ ttimoff(); } debug(F111,"ttinl got", dest,i); return(i); } } /* end of while() */ ttimoff(); return(-1); } #endif /* COMMENT */ } /* T T I N C -- Read a character from the communication line */ /* The time should be in secs for consistency with the other modules in */ /* kermit. To retain the option of using times of less than 1s a negative */ /* parameter is interpreted as meaning multiples of 0.01s */ static rdch(void); ttinc(timo) int timo; { int m, i; char ch = 0; #ifdef NETCONN if (ttmdm < 0) return os2_netinc(timo); #endif /* NETCONN */ m = (ttprty) ? 0177 : 0377; /* Parity stripping mask. */ if (ttyfd < 0) return(-1); /* Not open. */ if (timo == 0) { /* Untimed. */ if (ttydcb.usReadTimeout != 9) { ttydcb.usReadTimeout = 9; /* Test every 0.1s per call */ if (DosDevIOCtl(NULL,0,&ttydcb,sizeof(ttydcb), ASYNC_SETDCBINFO,1,ttyfd)) return(-1); } do i = rdch(); while (i < 0); /* Wait for a character. */ return(i & m); } if (timo < 0) timo= -timo - 1; else timo = timo * 100 - 1; if (ttydcb.usReadTimeout != timo) { /* Set timeout value */ ttydcb.usReadTimeout = timo; if (DosDevIOCtl(NULL,0,&ttydcb,sizeof(ttydcb), ASYNC_SETDCBINFO,IOCTL_ASYNC,ttyfd)) return(-1); } i = rdch(); if (i < 0) return(-1); else return(i & m); } /* RDCH -- Read characters from the serial port, maintaining an internal buffer of characters for the sake of efficiency. */ static rdch() { if (rdchbuf.index == rdchbuf.length) { rdchbuf.index = 0; if (DosRead(ttyfd,rdchbuf.buffer,sizeof(rdchbuf.buffer), &rdchbuf.length)) { rdchbuf.length = 0; return(-1); } } return( (rdchbuf.index < rdchbuf.length) ? rdchbuf.buffer[rdchbuf.index++] : -1 ); } /* T T S C A R R -- Set ttcarr variable, controlling carrier handling. * * 0 = Off: Always ignore carrier. E.g. you can connect without carrier. * 1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect. * 2 = Auto: For "modem direct": The same as "Off". * For real modem types: Heed carrier during connect, but ignore * it anytime else. Compatible with pre-5A C-Kermit versions. */ int ttscarr(carrier) int carrier; { ttcarr = carrier; debug(F101, "ttscarr","",ttcarr); return(ttcarr); } /* T T G M D M -- Get modem signals */ /* Looks for the modem signals CTS, DSR, and CTS, and returns those that are on in as its return value, in a bit mask as described for ttwmdm. Returns: -3 Not implemented -2 if the line does not have modem control -1 on error. >= 0 on success, with a bit mask containing the modem signals that are on. */ int ttgmdm() { BYTE instat, outstat; int modem = 0; if(DosDevIOCtl(&instat,sizeof(instat),NULL,0, ASYNC_GETMODEMINPUT,IOCTL_ASYNC,ttyfd)) return(-1); if(DosDevIOCtl(&outstat,sizeof(outstat),NULL,0, ASYNC_GETMODEMOUTPUT,IOCTL_ASYNC,ttyfd)) return(-1); /* Clear To Send */ if (instat & CTS_ON) modem |= BM_CTS; /* Data Set Ready */ if (instat & DSR_ON) modem |= BM_DSR; /* Carrier */ if (instat & DCD_ON) modem |= BM_DCD; /* Ring Indicate */ if (instat & RI_ON) modem |= BM_RNG; /* Data Terminal Ready */ if (outstat & DTR_ON) modem |= BM_DTR; /* Request To Send */ if (outstat & RTS_ON) modem |= BM_RTS; return(modem); } /* T T S N D B -- Send a BREAK signal */ ttsndb() { MODEMSTATUS ms; UINT data, i; #ifdef NETCONN if (ttmdm < 0) return os2_netbreak(); #endif /* NETCONN */ ms.fbModemOn = RTS_ON; ms.fbModemOff = 255; DosDevIOCtl(&data,sizeof(data),&ms,sizeof(ms), ASYNC_SETMODEMCTRL,IOCTL_ASYNC,ttyfd); DosDevIOCtl(&i,sizeof(i),NULL,0, ASYNC_SETBREAKON,IOCTL_ASYNC,ttyfd); /* Break on */ DosSleep(275L); /* ZZZzzz */ DosDevIOCtl(&i,sizeof(i),NULL,0, ASYNC_SETBREAKOFF,IOCTL_ASYNC,ttyfd); /* Break off */ } /* T T S N D L B -- Send a LONG BREAK signal */ ttsndlb() { MODEMSTATUS ms; UINT data, i; #ifdef NETCONN if (ttmdm < 0) return os2_netbreak(); #endif /* NETCONN */ ms.fbModemOn = RTS_ON; ms.fbModemOff = 255; DosDevIOCtl(&data,sizeof(data),&ms,sizeof(ms), ASYNC_SETMODEMCTRL,IOCTL_ASYNC,ttyfd); DosDevIOCtl(&i,sizeof(i),NULL,0, ASYNC_SETBREAKON,IOCTL_ASYNC,ttyfd); /* Break on */ DosSleep(1800L); /* ZZZzzz */ DosDevIOCtl(&i,sizeof(i),NULL,0, ASYNC_SETBREAKOFF,IOCTL_ASYNC,ttyfd); /* Break off */ } #ifndef __EMX__ /* S L E E P -- Emulate the Unix sleep function */ unsigned sleep(t) unsigned t; { DosSleep((long)t*1000); } #endif /* M S L E E P -- Millisecond version of sleep(). */ /* Intended only for small intervals. For big ones, just use sleep(). */ msleep(m) int m; { DosSleep((long)m); } /* R T I M E R -- Reset elapsed time counter */ void rtimer() { tcount = time((long *)NULL); } /* G T I M E R -- Get current value of elapsed time counter in seconds */ int gtimer(void) { int x; x = (int) (time( (long *) 0 ) - tcount); return( (x < 0) ? 0 : x ); } /* Z T I M E -- Return date/time string */ void ztime(char **s) { long clock_storage; clock_storage = time( (long *) 0 ); *s = ctime( &clock_storage ); } /* C O N O C -- Output a character to the console terminal */ int conoc(char c) { write(1,&c,1); } /* C O N X O -- Write x characters to the console terminal */ int conxo(int x, char *s) { write(1,s,x); } /* C O N O L -- Write a line to the console terminal */ int conol(char *s) { int len; len = strlen(s); write(1,s,len); } /* C O N O L A -- Write an array of lines to the console terminal */ conola(s) char *s[]; { int i; for (i=0 ; *s[i] ; i++) conol(s[i]); } /* C O N O L L -- Output a string followed by CRLF */ conoll(s) char *s; { conol(s); write(1,"\r\n",2); } /* C O N C H K -- Return how many characters available at console */ int conchk() { KBDKEYINFO k; #ifdef __32BIT__ return keyinbuf() ; #else KbdPeek(&k,0); return( (k.fbStatus & 0x40) ? 1 : 0 ); #endif /* __32BIT__ */ } /* C O N I N C -- Get a character from the console */ int coninc(timo) int timo; { int c; extern int what; while ( (c = congks(timo)) >= 0x100 ) { if ( c > 0x200 && isdigit(c & 0xFF) || c == 0x109 /* TAB */ ) { break; } else { /* This allows up- and down-arrow for command recall. */ if (c == 584 || c == 328) { /* Up arrow = Ctrl-B */ if (what == W_COMMAND) return(2); } else if (c == 592 || c == 336) { /* Down arrow = Ctrl-N */ if (what == W_COMMAND) return(14); } } } return (c & 0xFF); } SIGTYP kbdtimo(int sig) { #ifdef __EMX__ signal(SIGALRM, SIG_ACK); #endif signal(SIGALRM, saval); longjmp(kbbuf, 1); } #ifndef SHIFT_KEY_IN #define SHIFT_KEY_IN KBDTRF_SHIFT_KEY_IN #endif /* SHIFT_KEY_IN */ #ifndef CONTROL #define CONTROL KBDSTF_CONTROL #define SCROLLLOCK KBDSTF_SCROLLLOCK #define SCROLLLOCK_ON KBDSTF_SCROLLLOCK_ON #define NUMLOCK KBDSTF_NUMLOCK #define NUMLOCK_ON KBDSTF_NUMLOCK_ON #define LEFTSHIFT KBDSTF_LEFTSHIFT #define RIGHTSHIFT KBDSTF_RIGHTSHIFT #endif /* CONTROL */ int congks(timo) int timo; { KBDKEYINFO k; int c ; #ifdef __32BIT__ APIRET rc ; int timeout ; #endif /* __32BIT__ */ #ifdef OS2PM static int pipeopen = 0 ; #endif /* OS2PM */ if (!islocal) { c = 0; if ( read(ttyfd, &c, 1) < 1 ) return -1; return c; } for (;;) { #ifdef __32BIT__ #ifdef OS2PM if ( !os2pm ) { #endif /* OS2PM */ if ( timo < -1 ) timeout = -timo * 10 ; if ( timo == -1 || timo == 0 ) timeout = SEM_INDEFINITE_WAIT ; if ( timo > 0 ) timeout = timo * 1000 ; rc = DosWaitEventSem( hevKeyAvail, timeout ) ; switch ( rc ) { case NO_ERROR: getkey( &c ) ; return c ; case ERROR_TIMEOUT: return -1 ; default: return -1 ; } #ifdef OS2PM } else { if ( !pipeopen ) if ( !ConnectToPM() ) pipeopen = 1 ; else { os2pm = 0 ; return -1 ; } return ReadFromPM() ; } #endif /* OS2PM */ #else /* not __32BIT__ */ if (timo <= 0) KbdCharIn(&k, IO_WAIT, 0); else { saval = signal(SIGALRM, kbdtimo); alarm(timo); if (setjmp(kbbuf)) return -1; /* What about signal(SIGALRM, saval)? */ else KbdCharIn(&k, IO_WAIT, 0); alarm(0); signal(SIGALRM, saval); } if ( k.chChar || k.chScan ) { c = k.chChar; if (c == 0x00) c = 0x100 | k.chScan; if (c == 0xE0) c = 0x200 | k.chScan; switch (c) { /* Handle ambiguous keypad and space keys */ case '\t': return k.chScan == 0x0F ? 0x100 | c : c; case '\b': return k.chScan == 0x0E ? DEL : c; case ESC: return ((k.fsState & LEFTSHIFT) || (k.fsState & RIGHTSHIFT) ? 0x100 | c : c); case DEL: return 0x200 | c; case ' ': return (k.fsState & CONTROL) ? 0x200 | c : c; case '+': return k.chScan == 0x4E ? 0x200 | c : c; case '-': return k.chScan == 0x4A ? 0x200 | c : c; case '*': return k.chScan == 0x37 ? 0x200 | c : c; case '/': return k.chScan == 0xE0 ? 0x200 | c : c; case '\r': case '\n': return k.chScan == 0xE0 ? 0x200 | c : c; case '.': case ',': return k.chScan == 0x53 ? 0x200 | c : c; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return k.chScan >= 0x47 ? 0x200 | c : c; default: return c; } } if ( (k.fbStatus & SHIFT_KEY_IN) && (k.fsState & NUMLOCK) ) return (k.fsState & NUMLOCK_ON) ? 0x2FE : 0x1FE; if ( (k.fbStatus & SHIFT_KEY_IN) && (k.fsState & SCROLLLOCK) ) return (k.fsState & SCROLLLOCK_ON) ? 0x2FF : 0x1FF; #endif /* __32BIT__ */ } } int conraw() { KBDINFO k; if (!islocal) return(0); conmode = 1; k.cb = sizeof(k); KbdGetStatus(&k,0); k.fsMask &= ~(KEYBOARD_ECHO_ON | KEYBOARD_ASCII_MODE); k.fsMask |= (KEYBOARD_ECHO_OFF | KEYBOARD_BINARY_MODE | KEYBOARD_SHIFT_REPORT); /* Generates excessive key reports */ return(KbdSetStatus(&k,0)); /* But lets us see ScrollLock, Ctrl, Alt */ } int concooked() { KBDINFO k; if (!islocal) return(0); conmode = 0; k.cb = sizeof(k); KbdGetStatus(&k,0); k.fsMask &= ~(KEYBOARD_ECHO_OFF | KEYBOARD_BINARY_MODE | KEYBOARD_SHIFT_REPORT); k.fsMask |= (KEYBOARD_ECHO_ON | KEYBOARD_ASCII_MODE); return(KbdSetStatus(&k,0)); } /* C O N B I N -- Put console in binary mode */ /* Returns 0 if ok, -1 if not */ conbin(char esc) { if (!islocal) return(0); /* only for real ttys */ conraw(); } /* C O N C B -- Put console into single char mode with no echo. */ concb(char esc) { if (!islocal) return(0); /* only for real ttys */ concooked(); } /* C O N G M -- Get console terminal mode. */ congm() {} /* C O N R E S -- Restore console to congm mode. */ conres() {} /* C O N I N T -- Enable console terminal interrupts. */ void conint(f, s) SIGTYP (*f)(int), (*s)(int); { signal(SIGINT, f); signal(SIGBREAK, f); } /* C O N N O I -- No console interrupts. */ void connoi() { signal(SIGINT, cc_trap); signal(SIGBREAK, cc_trap); } /* privilege dummy */ int priv_chk() {return 0;} #ifndef __EMX__ /* alarm() implementation for all others, emx/gcc already has it built-in */ #ifdef __32BIT__ #define STACK static BOOL alrm, running, isalarm; static UINT delay; static VOID alarm_thread(VOID *args) { ULONG post_count ; for (;;) { DosWaitEventSem( hevAlarmTimer, SEM_INDEFINITE_WAIT ) ; DosRequestMutexSem( hmtxAlarmSem, SEM_INDEFINITE_WAIT ) ; DosResetEventSem( hevAlarmTimer, &post_count ) ; if ( alrm ) { debug( F100, "alarm() triggered", "", 0 ) ; alrm = FALSE; isalarm = TRUE; DosKillProcess(DKP_PROCESS, pid); } DosReleaseMutexSem( hmtxAlarmSem ) ; } running = FALSE; _endthread(); } static void alarm_signal(int sig) { signal(SIGTERM, SIG_DFL); if (isalarm) { isalarm = FALSE; /* signal(SIGTERM, SIG_DFL); */ raise(SIGALRM); } else { /* signal(SIGTERM, SIG_DFL); */ DosKillProcess(DKP_PROCESS, pid); } } unsigned alarm(unsigned sec) { TID tid; unsigned old; APIRET rc = 0 ; ULONG TimeInterval = sec * 1000 ; DosRequestMutexSem( hmtxAlarmSem, SEM_INDEFINITE_WAIT ) ; if ( delay ) { rc = DosStopTimer( hAlarmTimer ) ; debug(F101,"alarm(0) DosStopTimer","",rc) ; hAlarmTimer = 0 ; } old = delay; delay = sec; if ( alrm = (delay > 0) ) { signal(SIGTERM, alarm_signal); rc = DosAsyncTimer( TimeInterval, (HSEM) hevAlarmTimer, &hAlarmTimer ) ; debug(F101,"alarm(t) DosAsyncTimer: t","",TimeInterval) ; } else debug(F100,"alarm() reset","",0); DosReleaseMutexSem( hmtxAlarmSem ) ; if ( !running ) { running = TRUE; tid = _beginthread( &alarm_thread, 0, THRDSTKSIZ, 0 ) ; DosSetPrty(PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, tid); } return old; } #else #define STACK 2048 static PBYTE pstack; static BOOL alrm, running; static USHORT delay; #pragma check_stack(off) static VOID FAR alarm_thread(VOID) { for (;;) { DosSleep(1000L); DosEnterCritSec(); if ( alrm ) if ( --delay == 0 ) { alrm = FALSE; DosFlagProcess(pid, FLGP_PID, PFLG_A, 1); } DosExitCritSec(); } running = FALSE; DosExit(EXIT_THREAD, 0); } #pragma check_stack() static VOID PASCAL FAR alarm_signal(USHORT sigarg, USHORT signum) { PFNSIGHANDLER prev; USHORT action; DosSetSigHandler(alarm_signal, &prev, &action, SIGA_ACKNOWLEDGE, SIG_PFLG_A); raise(SIGALRM); } unsigned alarm(unsigned sec) { PFNSIGHANDLER prev; USHORT action; TID tid; unsigned old; if ( pstack == NULL ) { pstack = malloc(STACK); assert(pstack != NULL); DosSetSigHandler(alarm_signal, &prev, &action, SIGA_ACCEPT, SIG_PFLG_A); } DosEnterCritSec(); old = delay; delay = sec; alrm = (delay > 0); DosExitCritSec(); if ( !running ) { running = TRUE; DosCreateThread(alarm_thread, &tid, pstack + STACK); DosSetPrty(PRTYS_THREAD, PRTYC_REGULAR, 0, tid); } return old; } #endif /* * A public domain implementation of BSD directory routines for * MS-DOS. Written by Michael Rendell ({uunet,utai}michael@garfield), * August 1897 * Ported to OS/2 by Kai Uwe Rommel * December 1989, February 1990 * Change for HPFS support, October 1990 */ int attributes = A_DIR | A_HIDDEN | A_RONLY | A_SYSTEM | A_ARCHIVE ; static char *getdirent(char *); static void free_dircontents(struct _dircontents *); static HDIR hdir; static U_INT count; static FILEFINDBUF find; int IsFileSystemFAT(char *dir) { static USHORT nLastDrive = -1, nResult; ULONG lMap; BYTE bData[64], bName[3]; U_INT nDrive, cbData; FSQBUFFER *pData = (FSQBUFFER *) bData; /* We separate FAT and HPFS file systems here. */ if ( isalpha(dir[0]) && (dir[1] == ':') ) nDrive = toupper(dir[0]) - '@'; else DosQueryCurrentDisk(&nDrive, &lMap); if ( nDrive == nLastDrive ) return nResult; bName[0] = (char) (nDrive + '@'); bName[1] = ':'; bName[2] = 0; nLastDrive = nDrive; cbData = sizeof(bData); if ( !DosQueryFSAttach(bName, 0, FSAIL_QUERYNAME, (PVOID) pData, &cbData) ) nResult = !strcmp(pData -> szFSDName + pData -> cbName, "FAT"); else nResult = FALSE; return nResult; } DIR *opendir(char *name) { struct stat statb; DIR *dirp; char c; char *s; struct _dircontents *dp; char nbuf[MAXPATHLEN + 1]; int len; strcpy(nbuf, name); if ((len = strlen(nbuf)) == 0) return NULL; if ( ((c = nbuf[len - 1]) == '\\' || c == '/') && (len > 1) ) { nbuf[len - 1] = 0; --len; if ( nbuf[len - 1] == ':' ) { strcpy(nbuf + len, "\\."); len += 2; } } else if ( nbuf[len - 1] == ':' ) { strcpy(nbuf+len, "."); ++len; } if (stat(nbuf, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR) return NULL; if ( (dirp = malloc(sizeof(DIR))) == NULL ) return NULL; if ( nbuf[len - 1] == '.' && (len == 1 || nbuf[len - 2] != '.') ) strcpy(nbuf + len - 1, "*"); else if ( ((c = nbuf[len - 1]) == '\\' || c == '/') && (len == 1) ) strcpy(nbuf + len, "*"); else strcpy(nbuf + len, "\\*"); dirp -> dd_loc = 0; dirp -> dd_contents = dirp -> dd_cp = NULL; if ((s = getdirent(nbuf)) == NULL) return dirp; do { if (((dp = malloc(sizeof(struct _dircontents))) == NULL) || ((dp -> _d_entry = malloc(strlen(s) + 1)) == NULL) ) { if (dp) free(dp); free_dircontents(dirp -> dd_contents); return NULL; } if (dirp -> dd_contents) { dirp -> dd_cp -> _d_next = dp; dirp -> dd_cp = dirp -> dd_cp -> _d_next; } else dirp -> dd_contents = dirp -> dd_cp = dp; strcpy(dp -> _d_entry, s); dp -> _d_next = NULL; dp -> _d_size = find.cbFile; dp -> _d_mode = find.attrFile; dp -> _d_time = *(unsigned *) &(find.ftimeLastWrite); dp -> _d_date = *(unsigned *) &(find.fdateLastWrite); } while ((s = getdirent(NULL)) != NULL); dirp -> dd_cp = dirp -> dd_contents; return dirp; } void closedir(DIR * dirp) { free_dircontents(dirp -> dd_contents); free(dirp); } struct dirent *readdir(DIR * dirp) { static struct dirent dp; if (dirp -> dd_cp == NULL) return NULL; dp.d_namlen = dp.d_reclen = strlen(strcpy(dp.d_name, dirp -> dd_cp -> _d_entry)); dp.d_ino = 1; dp.d_size = dirp -> dd_cp -> _d_size; dp.d_mode = dirp -> dd_cp -> _d_mode; dp.d_time = dirp -> dd_cp -> _d_time; dp.d_date = dirp -> dd_cp -> _d_date; dirp -> dd_cp = dirp -> dd_cp -> _d_next; dirp -> dd_loc++; return &dp; } void seekdir(DIR * dirp, long off) { long i = off; struct _dircontents *dp; if (off >= 0) { for (dp = dirp -> dd_contents; --i >= 0 && dp; dp = dp -> _d_next); dirp -> dd_loc = off - (i + 1); dirp -> dd_cp = dp; } } long telldir(DIR * dirp) { return dirp -> dd_loc; } static void free_dircontents(struct _dircontents * dp) { struct _dircontents *odp; while (dp) { if (dp -> _d_entry) free(dp -> _d_entry); dp = (odp = dp) -> _d_next; free(odp); } } char *getdirent(char *dir) { int done; static int lower = TRUE; if (dir != NULL) { /* get first entry */ lower = IsFileSystemFAT(dir); hdir = HDIR_CREATE; count = 1; done = DosFindFirst(dir, &hdir, attributes, &find, sizeof(find), &count); } else /* get next entry */ done = DosFindNext(hdir, &find, sizeof(find), &count); if (done == 0) { if ( lower ) strlwr(find.achName); return find.achName; } else { DosFindClose(hdir); return NULL; } } #endif /* __EMX__ */ #ifdef __IBMC__ /* quick hack because IBM C lacks popen() and pclose() */ int pids[64]; FILE * popen(char *cmd, char *mode) { HFILE end1, end2, std, old1, old2, temp; FILE *file; char fail[256], cmd_line[256], *cmd_exe, *args; RESULTCODES res; int rc; if (DosCreatePipe(&end1, &end2, 4096)) return NULL; std = (*mode == 'w') ? 0 /* stdin */ : 1 /* stdout */; if (std == 0) { temp = end1; end1 = end2; end2 = temp; } old1 = -1; /* save stdin or stdout */ DosDupHandle(std, &old1); DosSetFHState(old1, OPEN_FLAGS_NOINHERIT); temp = std; /* redirect stdin or stdout */ DosDupHandle(end2, &temp); if ( std == 1 ) { old2 = -1; /* save stderr */ DosDupHandle(2, &old2); DosSetFHState(old2, OPEN_FLAGS_NOINHERIT); temp = 2; /* redirect stderr */ DosDupHandle(end2, &temp); } DosClose(end2); DosSetFHState(end1, OPEN_FLAGS_NOINHERIT); if ( (cmd_exe = getenv("COMSPEC")) == NULL ) cmd_exe = "cmd.exe"; strcpy(cmd_line, cmd_exe); args = cmd_line + strlen(cmd_line) + 1; /* skip zero */ strcpy(args, "/c "); strcat(args, cmd); args[strlen(args) + 1] = '\0'; /* two zeroes */ rc = DosExecPgm(fail, sizeof(fail), EXEC_ASYNCRESULT, cmd_line, 0, &res, cmd_exe); temp = std; /* restore stdin or stdout */ DosDupHandle(old1, &temp); DosClose(old1); if ( std == 1 ) { temp = 2; /* restore stderr */ DosDupHandle(old2, &temp); DosClose(old2); } if (rc) { DosClose(end1); return NULL; } file = fdopen(end1, mode); pids[end1] = res.codeTerminate; return file; } int pclose(FILE *pipe) { RESULTCODES rc; PID pid; int handle = fileno(pipe); fclose(pipe); if (pids[handle]) DosWaitChild(DCWA_PROCESSTREE, DCWW_WAIT, &rc, &pid, pids[handle]); pids[handle] = 0; return rc.codeTerminate == 0 ? rc.codeResult : -1; } #endif #ifdef CK_REDIR int ttruncmd(cmd) char *cmd; { /* Return: 0 = failure, 1 = success */ HFILE old[3], temp; char fail[256], cmd_line[256], *cmd_exe, *args; RESULTCODES res; PID pid; int cnt, rc; if (ttyfd == -1) { printf("?Sorry, device is not open\n"); return 0; } for (cnt = 0; cnt <= 2; cnt++) /* save stdin, stdout, stderr */ { old[cnt] = -1; /* save old std* */ DosDupHandle(cnt, &old[cnt]); DosSetFHState(old[cnt], OPEN_FLAGS_NOINHERIT); temp = cnt; /* redirect to line */ DosDupHandle(ttyfd, &temp); } if ( (cmd_exe = getenv("COMSPEC")) == NULL ) cmd_exe = "cmd.exe"; strcpy(cmd_line, cmd_exe); args = cmd_line + strlen(cmd_line) + 1; /* skip zero */ strcpy(args, "/c "); strcat(args, cmd); args[strlen(args) + 1] = '\0'; /* two zeroes */ rc = DosExecPgm(fail, sizeof(fail), EXEC_ASYNCRESULT, cmd_line, 0, &res, cmd_exe); pid = res.codeTerminate; for (cnt = 0; cnt <= 2; cnt++) /* restore stdin, stdout, stderr */ { temp = cnt; /* restore std* */ DosDupHandle(old[cnt], &temp); DosClose(old[cnt]); } if (rc) return 0; rc = DosWaitChild(DCWA_PROCESSTREE, DCWW_WAIT, &res, &pid, pid); if (rc) { printf("?Command did not terminate: %d\r\n", rc); DosKillProcess(DKP_PROCESSTREE, pid); return 0; } if (res.codeTerminate != 0) { printf("?Command terminated abnormally: %d\r\n", res.codeTerminate); return 0; } if (res.codeResult != 0) { printf("?Command exit status: %d\r\n", res.codeResult); return 0; } return 1; } #endif /* CK_REDIR */ void ChangeNameForFAT(char *name) { char *src, *dst, *next, *ptr, *dot, *start; static char invalid[] = ":;,=+\"[]<>| \t"; if ( isalpha(name[0]) && (name[1] == ':') ) start = name + 2; else start = name; src = dst = start; if ( (*src == '/') || (*src == '\\') ) src++, dst++; while ( *src ) { for ( next = src; *next && (*next != '/') && (*next != '\\'); next++ ); for ( ptr = src, dot = NULL; ptr < next; ptr++ ) if ( *ptr == '.' ) { dot = ptr; /* remember last dot */ *ptr = '_'; } if ( dot == NULL ) for ( ptr = src; ptr < next; ptr++ ) if ( *ptr == '_' ) dot = ptr; /* remember last _ as if it were a dot */ if ( dot && (dot > src) && ((next - dot <= 4) || ((next - src > 8) && (dot - src > 3))) ) { if ( dot ) *dot = '.'; for ( ptr = src; (ptr < dot) && ((ptr - src) < 8); ptr++ ) *dst++ = *ptr; for ( ptr = dot; (ptr < next) && ((ptr - dot) < 4); ptr++ ) *dst++ = *ptr; } else { if ( dot && (next - src == 1) ) *dot = '.'; /* special case: "." as a path component */ for ( ptr = src; (ptr < next) && ((ptr - src) < 8); ptr++ ) *dst++ = *ptr; } *dst++ = *next; /* either '/' or 0 */ if ( *next ) { src = next + 1; if ( *src == 0 ) /* handle trailing '/' on dirs ! */ *dst = 0; } else break; } for ( src = start; *src != 0; ++src ) if ( strchr(invalid, *src) != NULL ) *src = '_'; } int IsFileNameValid(char *name) { HFILE hf; U_INT uAction; int rc; switch( DosOpen(name, &hf, &uAction, 0, 0, FILE_OPEN, OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, 0) ) { case ERROR_INVALID_NAME: case ERROR_FILENAME_EXCED_RANGE: case ERROR_INVALID_PARAMETER: return FALSE; case NO_ERROR: DosClose(hf); default: return TRUE; } } long zdskspace(int drive) { FSALLOCATE fsa; if ( DosQueryFSInfo(drive, 1, (PBYTE) &fsa, sizeof(fsa)) ) return 0; return fsa.cUnitAvail * fsa.cSectorUnit * fsa.cbSector; } char * GetLoadPath(void) { #ifdef __32BIT__ PTIB pptib; PPIB pppib; char *szPath; DosGetInfoBlocks(&pptib, &pppib); szPath = pppib -> pib_pchenv; while (*szPath) szPath = strchr(szPath, 0) + 1; return szPath + 1; #else extern char *_pgmptr; return _pgmptr; #endif } /* Keyboard Hardware ID PC AT* Standard Keyboard 0001H 101 Key Enhanced Keyboard and AB41H 102 Key Enhanced Keyboard 88 Key Enhanced Keyboard and AB54H 89 Key Enhanced Keyboard 122 Key Mainframe Interactive AB86H (MFI) Keyboard */ static char os2kbt[20]; char * conkbg(void) { HKBD hKbd; KBDHWID kbID; int rc; int x; char * p; p = os2kbt; *p = '\0'; if ( KbdOpen(&hKbd) == 0) { KbdGetFocus(IO_WAIT, hKbd); kbID.cb = sizeof(kbID); KbdGetHWID(&kbID, hKbd); KbdClose(hKbd); debug(F101,"conkbg","",kbID.idKbd); switch (kbID.idKbd) { case 0x0001: /* PC/AT keyboard */ case 0xab54: /* PC or PC/XT 88 or 89 key */ x = 88; break; case 0xab41: /* 101 or 102 enhanced keyboard */ case 0xab83: x = 101; break; case 0xab86: /* 122-key "mainframe interactive" */ x = 122; break; default: x = 0; break; /* Something else... */ } if (x) /* If it's known model */ sprintf(p,"%d",x); /* use its "name" */ else /* otherwise */ sprintf(p,"%04X",(int) kbID.idKbd); /* use the hex code */ } return(p); /* Return string pointer */ }; #ifdef CK_LABELED static CHAR os2version[50] ; char * get_os2_vers() { ULONG StartIndex = 11 ; /* Major Version Number */ ULONG EndIndex = 13 ; /* Revision Letter */ ULONG DataBuf[3] ; ULONG DataBufLen = 3 * sizeof(ULONG) ; APIRET rc ; rc = DosQuerySysInfo( StartIndex, EndIndex, DataBuf, DataBufLen ); if (rc) os2version[0] = '\0' ; else sprintf(os2version,"%02d.%02d%c",DataBuf[0],DataBuf[1],DataBuf[2]) ; return os2version ; } #endif /* CK_LABELED */ #ifdef CK_REXX RexxFunctionHandler os2rexxckcmd ; RexxSubcomHandler os2rexxsubcom ; extern char * mrval[] ; extern int maclvl ; /* This is the CkCommand/CKermit function handler. It is an undocumented */ /* C-Kermit feature. Do not remove this code. */ ULONG os2rexxckcmd( PUCHAR Name, ULONG Argc, PRXSTRING Argv, PSZ Queuename, PRXSTRING Retstr) { APIRET rc = 0 ; int i ; for ( i = 0 ; i < Argc ; i++ ) { rc = domac("_rexx_commands",RXSTRPTR(Argv[i])); debug(F111,"os2rexxckcmd",RXSTRPTR(Argv[i]),rc); delmac("_rexx_commands"); if (rc < 0) break ; } if ( mrval[maclvl+1] ) { MAKERXSTRING(*Retstr, strdup(mrval[maclvl+1]), strlen(mrval[maclvl+1]) ) ; } else MAKERXSTRING( *Retstr, strdup(""), 0 ) ; return (rc < 0 ? rc : 0 ) ; } ULONG os2rexxsubcom( PRXSTRING Command, PUSHORT pFlags, PRXSTRING Retstr) { APIRET rc = 0 ; rc = domac("_rexx_commands",RXSTRPTR(Command[0])); debug(F111,"os2rexxsubcom",RXSTRPTR(Command[0]),rc); delmac("_rexx_commands"); *pFlags = rc < 0 ? RXSUBCOM_ERROR : RXSUBCOM_OK; if ( mrval[maclvl+1] ) { MAKERXSTRING(*Retstr, strdup(mrval[maclvl+1]), strlen(mrval[maclvl+1])) ; } else MAKERXSTRING( *Retstr, strdup(""), 0 ) ; return 0; } int os2rexx( char * rexxcmd, char * rexxbuf, int rexxbuflen ) { long return_code ; /* rexx interpreter return code */ short rc ; /* converted return code */ char return_buffer[256] ; /*returned buffer*/ RXSTRING Instore[2] ; /* Instorage rexx procedure */ RXSTRING retstr ; /* program return value */ int retval ; /* os2rexx return value */ MAKERXSTRING( Instore[0], rexxcmd, strlen(rexxcmd) ) ; MAKERXSTRING( Instore[1], 0, 0 ) ; MAKERXSTRING( retstr, return_buffer, sizeof(return_buffer) ) ; debug(F110,"os2rexx: procedure",rexxcmd,0); return_code = RexxStart( 0, /* no program arguments */ 0, /* null argument list */ "C-Kermit for OS/2 REXX Command", /* default program name */ Instore, /* rexx procedure to interpret */ "CKermit", /* default address name */ RXFUNCTION, /* calling as a function */ 0, /* no exits used */ &rc, /* converted return code */ &retstr); /* returned result */ debug(F111,"os2rexx: returns",RXSTRPTR(retstr),return_code); if ( !return_code && RXSTRLEN( retstr ) < rexxbuflen ) { strncpy( rexxbuf, RXSTRPTR(retstr), RXSTRLEN( retstr ) ); rexxbuf[ RXSTRLEN( retstr ) ] = '\0' ; retval = 0 ; /* Success */ } else { rexxbuf[0] = '\0' ; retval = 1 ; /* Failure */ } if (RXSTRPTR(retstr) != return_buffer) DosFreeMem(RXSTRPTR(retstr)); return retval ; } int os2rexxinit() { /* this next line installs the CkCommand statement into the Rexx */ /* interpretter environment. We have replaced it with a subcommand */ /* handler instead. Both mechanisms can co-exist, so we leave in */ /* the CkCommand/CKermit as an undocumented function. */ RexxRegisterFunctionExe("CKermit",os2rexxckcmd) ; RexxRegisterFunctionExe("CKCommand",os2rexxckcmd) ; RexxRegisterSubcomExe("CKermit", (PFN)os2rexxsubcom, NULL); } #endif /* CK_REXX */ int os2settitle(char *title) { HSWITCH hSwitch; SWCNTRL swctl; /* This changes the text in the task list. */ /* That the window handle (first parameter) in the WinQuerySwitchHandle */ /* call can be NULL is fully documented in the API description. */ hSwitch = WinQuerySwitchHandle((HWND) NULL, pid); WinQuerySwitchEntry(hSwitch, &swctl); strcpy(swctl.szSwtitle, title); WinChangeSwitchEntry(hSwitch, &swctl); zsyscmd( "" ) ; #ifdef CK_SETTITLE { /* and this undocumented call changes the session title */ #ifdef __32BIT__ extern _Far16 _Pascal DosSmSetTitle(char * _Seg16 szTitle); #else extern _far _pascal DosSmSetTitle(char _far *szTitle); #endif /* __32BIT__ */ DosSmSetTitle(title); } #endif /* CK_SETTITLE */ return 0; } int os2gettitle(char *buffer, int size) { HSWITCH hSwitch; SWCNTRL swctl; /* Query the text in the task list */ hSwitch = WinQuerySwitchHandle( (HWND) NULL, pid); WinQuerySwitchEntry(hSwitch, &swctl); strncpy(buffer, swctl.szSwtitle, size); buffer[size - 1] = NUL; /* In case we truncate the title */ #ifdef COMMENT /* Only documented for PM applications */ WinQuerySessionTitle(NULL, 0, buffer, size); #endif /* COMMENT */ return 0; } #ifdef __32BIT__ /* Begin Keyboard Buffer Code This is a simple implementation of a circular queue with access protected by a Mutual Exclusion Semaphore */ #define KEY_BUF_SIZE 16384 int Keystroke[KEY_BUF_SIZE] ; int start=0, end=0 ; HMUX hmuxKeyStroke = (HMUX) 0 ; HMUX hmuxKeyboard = (HMUX) 0 ; void keybufinit( void ) { int i ; DosCreateEventSem( NULL, &hevKeyAvail, 0, 0 ) ; DosCreateMutexSem( NULL, &hmuxKeyStroke, 0, 1 ) ; DosCreateMutexSem( NULL, &hmuxKeyboard, 0, 0 ) ; for ( i = 0 ; i < KEY_BUF_SIZE ; i++ ) Keystroke[i] = 0 ; start = 0 ; end = 0 ; DosReleaseMutexSem( hmuxKeyStroke ) ; } void keybufcleanup( void ) { DosCloseMutexSem( hmuxKeyStroke ) ; DosCloseMutexSem( hmuxKeyboard ) ; DosCloseEventSem( hevKeyAvail ) ; } int keyinbuf( void ) { int rc = 0 ; DosRequestMutexSem( hmuxKeyStroke, SEM_INDEFINITE_WAIT ) ; rc = start != end ; DosReleaseMutexSem( hmuxKeyStroke ) ; return rc ; } int putkey( int k ) { int rc = 0 ; DosRequestMutexSem( hmuxKeyStroke, SEM_INDEFINITE_WAIT ) ; if ( (start - end == 1) || ( start == 0 && end == KEY_BUF_SIZE - 1 ) ) rc = -1 ; /* Buffer is full */ else { Keystroke[end++] = k ; if ( end == KEY_BUF_SIZE ) end = 0 ; DosPostEventSem( hevKeyAvail ) ; } DosReleaseMutexSem( hmuxKeyStroke ) ; return rc ; } int getkey( int * k ) { int rc = 0 ; ULONG PostCount ; DosRequestMutexSem( hmuxKeyStroke, SEM_INDEFINITE_WAIT ) ; if ( start != end ) { *k = Keystroke[start] ; Keystroke[start] = 0 ; start++ ; if ( start == KEY_BUF_SIZE ) start = 0 ; if ( start == end ) DosResetEventSem( hevKeyAvail, &PostCount ) ; rc++ ; } DosReleaseMutexSem( hmuxKeyStroke ) ; return rc ; } /* Begin Keyboard Handler Thread Code */ int KbdHandlerInit( void ) { KbdHandlerThreadID = _beginthread( &KbdHandlerThread, 0, THRDSTKSIZ, 0 ) ; if ( KbdHandlerThreadID == -1 ) { printf( "Sorry, can't create KbdHandlerThread\n" ) ; return -1 ; } return 0 ; } int KbdHandlerCleanup( void ) { return 0 ; } void KbdHandlerThread( void * ArgList ) { KBDKEYINFO k ; int rc, c ; for (;;) { rc = -1 ; while (1){ memset( &k, 0, sizeof(k) ) ; DosRequestMutexSem( hmuxKeyboard, SEM_INDEFINITE_WAIT ) ; KbdCharIn(&k, IO_NOWAIT, 0 ) ; DosReleaseMutexSem( hmuxKeyboard ) ; if (k.fbStatus & (3 << 6)) /* && !(k.fbStatus & 1) --- blocks ScrollLock */ break ; DosSleep( 80 ) ; /* a human can't type faster than this */ } if ( k.chChar || k.chScan ) { c = k.chChar; if (c == 0x00) c = 0x100 | k.chScan; if (c == 0xE0) c = 0x200 | k.chScan; switch (c) { /* Handle ambiguous keypad and space keys */ case '\t': rc = k.chScan == 0x0F ? 0x100 | c : c; break; case '\b': rc = k.chScan == 0x0E ? DEL : c; break; case ESC: rc = ((k.fsState & LEFTSHIFT) || (k.fsState & RIGHTSHIFT) ? 0x100 | c : c); break; case DEL: rc = 0x200 | c; break; case ' ': rc = (k.fsState & CONTROL) ? 0x200 | c : c; break; case '+': rc = k.chScan == 0x4E ? 0x200 | c : c; break; case '-': rc = k.chScan == 0x4A ? 0x200 | c : c; break; case '*': rc = k.chScan == 0x37 ? 0x200 | c : c; break; case '/': rc = k.chScan == 0xE0 ? 0x200 | c : c; break; case '\r': case '\n': rc = k.chScan == 0xE0 ? 0x200 | c : c; break; case '.': case ',': rc = k.chScan == 0x53 ? 0x200 | c : c; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': rc = k.chScan >= 0x47 ? 0x200 | c : c; break; default: rc = c; } } else if ( (k.fbStatus & SHIFT_KEY_IN) && (k.fsState & NUMLOCK) ) rc = (k.fsState & NUMLOCK_ON) ? 0x2FE : 0x1FE; else if ( (k.fbStatus & SHIFT_KEY_IN) && (k.fsState & SCROLLLOCK) ) rc = (k.fsState & SCROLLLOCK_ON) ? 0x2FF : 0x1FF; if ( rc >= 0 ) putkey( rc ) ; } _endthread(); /* we never get here */ } #endif /* __32BIT__ */ #ifdef OS2PM #define CKPM_PIPE_NAME "\\PIPE\\CKPM" #define MAX_PIPE_NAME_LEN 80 #define DEFAULT_MAKE_MODE NP_ACCESS_DUPLEX #define DEFAULT_PIPE_MODE NP_WMESG | NP_RMESG | 0x01 #define DEFAULT_OPEN_FLAG OPEN_ACTION_OPEN_IF_EXISTS #define DEFAULT_OPEN_MODE OPEN_FLAGS_WRITE_THROUGH | \ OPEN_FLAGS_FAIL_ON_ERROR | \ OPEN_FLAGS_RANDOM | \ OPEN_SHARE_DENYNONE | \ OPEN_ACCESS_READWRITE #define DEFAULT_OUTB_SIZE 0x1000 #define DEFAULT_INPB_SIZE 0x1000 #define DEFAULT_TIME_OUTV 20000L #define TOKEN_F2_SWITCH 0x0000003CL #define TOKEN_F3_DISCON 0x0000003DL #define RETURN_CHAR 0x0D #define LINE_FEED_CHAR 0x0A #define FUNC_KEYS_CHAR 0x00 #define EXTD_KEYS_CHAR 0xE0 #define HAND_SHAKE_LEN 0x08 #define HAND_SHAKE_INP "CKermit VIO" #define HAND_SHAKE_OUT "CKermit PM" #define HAND_SHAKE_ERROR -1 #define PROGRAM_ERROR 999 CHAR achPipeName [MAX_PIPE_NAME_LEN] ; HPIPE hpRdPipe ; CHAR chToken ; APIRET ConnectToPM( void ) { CHAR achInitBuf [HAND_SHAKE_LEN + 1] ; ULONG ulOpenFlag ; ULONG ulOpenMode ; ULONG ulActionTaken ; APIRET arReturn ; ULONG ulBytesDone ; memset ( achInitBuf, 0, sizeof ( achInitBuf )) ; ulOpenFlag = DEFAULT_OPEN_FLAG ; ulOpenMode = DEFAULT_OPEN_MODE ; arReturn = DosOpen ( CKPM_PIPE_NAME, &hpRdPipe, &ulActionTaken, 0, 0, ulOpenFlag, ulOpenMode, 0 ) ; if ( arReturn ) { printf ( "\n The Pipe Open / Connection API " "returned rc = %02x\n", arReturn ) ; printf ( "\n Make sure CKermit PM is running.\n\n" ) ; } /* endif */ return arReturn ; } APIRET ReadFromPM( void ) { APIRET arReturn ; CHAR chr ; ULONG ulBytesDone ; int i ; arReturn = DosRead ( hpRdPipe, &chr, 1L, &ulBytesDone ) ; if ( !arReturn ) { return chr ; } return -1 ; } #endif /* OS2PM */