################################################################## ## ## In this file is the source code for the WKERMIT, the "Windows" ## version of Kermit for the IBM PC family. ## ## To use, separate this file into separate files at the lines ## of "#" characters. The name of the file is given on the line ## immediately after the line of "#" characters. ## ################################################################## ## ## Start of PCKERMIT code ## ################################################################## ## ASIC.H /* include for things that use asi buffer structure */ #define N_ASPORTS 2 /* actual number of ports */ #define MAX_ASPORTS 8 #define max_asbuf_len 32000 /* max buffer size - user selectable */ struct AS_FLAGS { unsigned alert : 1; /* alert when 1 */ unsigned rxempty: 1; /* Rx Buffer Empty */ unsigned rxfull: 1; /* Rx Buffer Full */ unsigned txempty: 1; /* Tx Buffer Empty */ unsigned txfull: 1; /* Tx Buffer Full */ unsigned linerr: 1; /* line error */ unsigned modchg: 1; /* modem status change */ unsigned chkerr: 1; /* checksum error */ unsigned xchrun: 1; /* transmit interrupts are running */ unsigned rchrun: 1; /* receive interrupts are running */ unsigned igalert: 1; /* ignore alert */ unsigned igcts: 1; /* ignore CTS */ unsigned igdsr: 1; /* ignore DTR */ unsigned igcd: 1; /* ignore carrier detect CD */ unsigned igmstat: 1; /* ignore modem status changes */ unsigned igrcver: 1; /* ignore receive errors */ }; /* L I N E S T A T U S B I T S * * These are set by the interrupts and status functions. asilrst() * resets the static portion. * * Use the macros (below) to test individual bits. */ struct AS_LSTAT { /* First 8 are dynamic */ unsigned dready: 1; /* Rx data ready */ unsigned overrun: 1; /* Overrun Error */ unsigned parerr: 1; /* Parity Error */ unsigned framerr: 1; /* Framing Error */ unsigned breakdet:1; /* Break Signal Detect */ unsigned txhempty:1; /* Tx Holding Reg Empty */ unsigned txsempty:1; /* Tx Shift Reg Empty */ unsigned timeout: 1; /* Timeout (not used) */ unsigned sdready: 1; /* the next 8 are STATIC repeat */ unsigned soverrun:1; /* of the last 8 bits */ unsigned sparerr: 1; unsigned sframerr: 1; unsigned sbreakdet:1; unsigned stxhempty:1; unsigned stxsempty:1; unsigned stimeout: 1; }; /* M O D E M S T A T U S B I T S * * These are set by the interrupts and status functions. asimrst() resets * the static portion. * * Use macros (below) to read individual bits. */ struct AS_MSTAT { /* first 8 are dynamic */ unsigned dcts: 1; /* delta CTS */ unsigned ddsr: 1; /* delta DSR */ unsigned teri: 1; /* trailing edge of RI */ unsigned drlsd: 1; /* delta CD */ unsigned cts: 1; /* CTS */ unsigned dsr: 1; /* DSR */ unsigned ri: 1; /* RI */ unsigned rlsd: 1; /* CD */ unsigned sdcts: 1; /* the next 8 are static */ unsigned sddsr: 1; /* repeats of last 8 */ unsigned steri: 1; unsigned sdrlsd: 1; unsigned scts: 1; unsigned sdsr: 1; unsigned sri: 1; unsigned srlsd: 1; }; struct CHK_FLAGS { unsigned no_usef: 7; unsigned chk2flg: 1; /* Check character 2 has been detected */ unsigned chk1flg: 1; /* Check character 1 has been detected */ unsigned chk0flg: 1; /* Check character 0 has been detected */ unsigned reserve: 6; /* Hands off these */ }; struct ASITABLE { int port; /* port number 0... */ int intnum; /* interrupt no. 0C... */ unsigned ioaddr; /* base address of 8250 */ unsigned flags; /* major status flags */ unsigned lstat; /* line status */ unsigned mstat; /* modem status */ int mode; unsigned rseg; /* Rx Buffer segment */ unsigned rbob; /* Beginning of Buf (Rx)*/ unsigned rpi; /* Pointer In (Rx)*/ unsigned rpo; /* Pointer Out (Rx)*/ int rsize; /* size of receive queue */ int rfree; /* free space in receive queue */ unsigned tseg; /* Tx Buffer segment */ unsigned tbob; /* Beginning of Buf (Tx)*/ unsigned tpi; /* Pointer In (Tx)*/ unsigned tpo; /* Pointer Out (Tx)*/ int tsize; /* size of transmit queue */ int tcnt; /* number of bytes in transmit queue */ int xmcount; /* count/is rx active */ unsigned chkflag; /* flags for check characters */ char chkchr0; /* Check character 0 */ char chkchr1; /* Check character 1 */ char chkchr2; /* Check character 2 */ unsigned irq8259; /* Interrupt # in 8259 (com0 = 4) */ unsigned port8259; /* I/O Address of 8259 */ char not_used[15]; /* Pad to 64 bytes */ }; /* * Structure for Local Parameters for XMODEM functions. */ struct XMBUF { int xblocknum; char first; int xstatus; }; /* * The next declarations must be exactly as stated. * */ extern int n_asi_ports; extern struct ASITABLE asi_parms[ N_ASPORTS ]; extern int as_intnums[]; extern int as_port[]; extern int _as_wcts; extern int as_wtime[]; extern int as_rtime[]; extern int as_8259ports[]; extern int as_8259irq[]; /* * End of mandatory declarations. */ /* * Macros to define status and flag bits. */ /* T E S T IF RECEIVER DETECTED A PARTICULAR CHECK CHARACTER * * Use these in conjunction with asirchk(). */ #define ischk2(x) (asi_parms[x].chkflag&256)?1:0 #define ischk1(x) (asi_parms[x].chkflag&128)?1:0 #define ischk0(x) (asi_parms[x].chkflag&64)?1:0 /* F L A G B I T T E S T S * * These just test flag bits. The first 8 are for general applications, * the next 8 are provided for completeness and to test when the system * has been told to ignore certain conditions. Never write into these. */ #define isalert(x) (asi_parms[x].flags&1)?1:0 #define isrxempty(x) (asi_parms[x].flags&2)?1:0 #define isrxfull(x) (asi_parms[x].flags&4)?1:0 #define istxempty(x) (asi_parms[x].flags&8)?1:0 #define istxfull(x) (asi_parms[x].flags&16)?1:0 #define islnerr(x) (asi_parms[x].flags&32)?1:0 #define ismderr(x) (asi_parms[x].flags&64)?1:0 #define isckerr(x) (asi_parms[x].flags&128)?1:0 #define isxchrun(x) (asi_parms[x].flags&256)?1:0 #define isrchrun(x) (asi_parms[x].flags&512)?1:0 #define isigalert(x) (asi_parms[x].flags&1024)?1:0 #define isigcts(x) (asi_parms[x].flags&2048)?1:0 #define isigdtr(x) (asi_parms[x].flags&4096)?1:0 #define isigcd(x) (asi_parms[x].flags&8192)?1:0 #define isigmstat(x) (asi_parms[x].flags&16384)?1:0 #define isigrcver(x) (asi_parms[x].flags&32768)?1:0 /* Return DYNAMIC Line Status */ #define isdatardy(x) (asi_parms[x].lstat&1)?1:0 /* DATA READY */ #define isoverrun(x) (asi_parms[x].lstat&2)?1:0 /* OVERRUN ERROR */ #define isparityerr(x) (asi_parms[x].lstat&4)?1:0 /* PARITY ERROR */ #define isframerr(x) (asi_parms[x].lstat&8)?1:0 /* FRAMING ERROR */ #define isbreak(x) (asi_parms[x].lstat&16)?1:0 /* BREAK DETECT */ #define ishrempty(x) (asi_parms[x].lstat&32)?1:0 /* TX HOLDING REG */ #define issrempty(x) (asi_parms[x].lstat&64)?1:0 /* TX SHIFT REG */ #define istimeout(x) (asi_parms[x].lstat&128)?1:0 /* NOT USED */ /* Return STATIC Line Status */ #define issdatardy(x) (asi_parms[x].lstat&256)?1:0 #define issoverrun(x) (asi_parms[x].lstat&512)?1:0 #define issparityerr(x) (asi_parms[x].lstat&1024)?1:0 #define issframerr(x) (asi_parms[x].lstat&2048)?1:0 #define issbreak(x) (asi_parms[x].lstat&4096)?1:0 #define isshrempty(x) (asi_parms[x].lstat&8192)?1:0 #define isssrempty(x) (asi_parms[x].lstat&0x4000)?1:0 #define isstimeout(x) (asi_parms[x].lstat&0x8000)?1:0 /* Return DYNAMIC Modem Status */ #define ischgcts(x) (asi_parms[x].mstat&1)?1:0 #define ischgdsr(x) (asi_parms[x].mstat&2)?1:0 #define ischgri(x) (asi_parms[x].mstat&4)?1:0 #define ischgcd(x) (asi_parms[x].mstat&8)?1:0 #define iscts(x) (asi_parms[x].mstat&16)?1:0 #define isdsr(x) (asi_parms[x].mstat&32)?1:0 #define isri(x) (asi_parms[x].mstat&64)?1:0 #define iscd(x) (asi_parms[x].mstat&128)?1:0 /* Return STATIC Modem Status */ #define isschgcts(x) (asi_parms[x].mstat&256)?1:0 #define isschgdsr(x) (asi_parms[x].mstat&512)?1:0 #define isschgri(x) (asi_parms[x].mstat&1024)?1:0 #define isschgcd(x) (asi_parms[x].mstat&2048)?1:0 #define isscts(x) (asi_parms[x].mstat&4096)?1:0 #define issdsr(x) (asi_parms[x].mstat&8192)?1:0 #define issri(x) (asi_parms[x].mstat&0x4000)?1:0 #define isscd(x) (asi_parms[x].mstat&0x8000)?1:0 /* Boolean: Has receiver gotten one or more characters ? */ #define isxmrxing(x) (asi_parms[x].xmcount>0)?1:0 /* Boolean: Has receiver gotten a specified number of characters ? */ #define isxmrxcnt(x,y) (asi_parms[x].xmcount>=y)?1:0 /* Misc. definitions */ #define ASIN 1 /* mode = input */ #define ASOUT 2 /* mode = out */ #define ASINOUT 3 /* mode = in,out*/ #define ASCIINONE 1 /* protocol = ASCII, no protocol */ #define ASCIIXM 5 /* protocol = ASCII, XMODEM */ #define BINARYNONE 2 /* protocol = Binary, no protocol */ #define BINARYXM 6 /* protocol = Binary XMODEM */ /* ASCII Protocol Characters */ #define NUL 0 #define SOH 1 #define STX 2 #define ETX 3 #define EOT 4 #define ACK 6 #define DLE 0x10 #define DC1 0x11 #define DC2 0x12 #define DC3 0x13 #define DC4 0x14 #define NAK 0x15 #define ETB 0x17 #define XON 0x11 #define XOFF 0x13 ################################################################## ## ASIPORTS.H /* asiports.h * * Defines and parameter structures for Async I/O Ports. * * The Greenleaf Comm Library - Copyright (C) 1984 Greenleaf Software Inc. * * USAGE - INCLUDE IN MAIN PROGRAM ONLY WHEN USING ASYNC FUNCTIONS */ #define MAX_ASPORTS 8 /* maximum number of ports - may be changed */ #define N_ASPORTS 2 /* actual number of ports in the system */ #define max_asbuf_len 32000 /* max buffer size - user selectable */ /* F L A G S * * These should be considered read-only by all applications. Use macros * provided below to read individual bits. Use asierst() to reset alert, * linerr, modchg, and chkerr bits. Applications should NOT write to other * bits as the interrupts and other functions depend on these. */ struct AS_FLAGS { unsigned alert : 1; /* alert when 1 */ unsigned rxempty: 1; /* Rx Buffer Empty */ unsigned rxfull: 1; /* Rx Buffer Full */ unsigned txempty: 1; /* Tx Buffer Empty */ unsigned txfull: 1; /* Tx Buffer Full */ unsigned linerr: 1; /* line error */ unsigned modchg: 1; /* modem status change */ unsigned chkerr: 1; /* checksum error */ unsigned xchrun: 1; /* transmit interrupts are running */ unsigned rchrun: 1; /* receive interrupts are running */ unsigned igalert: 1; /* ignore alert */ unsigned igcts: 1; /* ignore CTS */ unsigned igdsr: 1; /* ignore DTR */ unsigned igcd: 1; /* ignore carrier detect CD */ unsigned igmstat: 1; /* ignore modem status changes */ unsigned igrcver: 1; /* ignore receive errors */ }; /* L I N E S T A T U S B I T S * * These are set by the interrupts and status functions. asilrst() * resets the static portion. * * Use the macros (below) to test individual bits. */ struct AS_LSTAT { /* First 8 are dynamic */ unsigned dready: 1; /* Rx data ready */ unsigned overrun: 1; /* Overrun Error */ unsigned parerr: 1; /* Parity Error */ unsigned framerr: 1; /* Framing Error */ unsigned breakdet:1; /* Break Signal Detect */ unsigned txhempty:1; /* Tx Holding Reg Empty */ unsigned txsempty:1; /* Tx Shift Reg Empty */ unsigned timeout: 1; /* Timeout (not used) */ unsigned sdready: 1; /* the next 8 are STATIC repeat */ unsigned soverrun:1; /* of the last 8 bits */ unsigned sparerr: 1; unsigned sframerr: 1; unsigned sbreakdet:1; unsigned stxhempty:1; unsigned stxsempty:1; unsigned stimeout: 1; }; /* M O D E M S T A T U S B I T S * * These are set by the interrupts and status functions. asimrst() resets * the static portion. * * Use macros (below) to read individual bits. */ struct AS_MSTAT { /* first 8 are dynamic */ unsigned dcts: 1; /* delta CTS */ unsigned ddsr: 1; /* delta DSR */ unsigned teri: 1; /* trailing edge of RI */ unsigned drlsd: 1; /* delta CD */ unsigned cts: 1; /* CTS */ unsigned dsr: 1; /* DSR */ unsigned ri: 1; /* RI */ unsigned rlsd: 1; /* CD */ unsigned sdcts: 1; /* the next 8 are static */ unsigned sddsr: 1; /* repeats of last 8 */ unsigned steri: 1; unsigned sdrlsd: 1; unsigned scts: 1; unsigned sdsr: 1; unsigned sri: 1; unsigned srlsd: 1; }; /* P A R A M E T E R S T R U C T U R E * * This holds parameters used by all functions and interrupt routines. * asisetup() establishes the values for these; applications should NOT * write to this structure at any time. Use asixrst() to reset the receiver * counter (.xmcount). */ struct ASITABLE { int port; /* port number 0... */ int intnum; /* interrupt no. ... */ unsigned ioaddr; /* base address of 8250 */ unsigned flags; /* major status flags */ unsigned lstat; /* line status */ unsigned mstat; /* modem status */ int mode; unsigned rseg; /* Rx Buffer segment */ unsigned rbob; /* Beginning of Buf (Rx)*/ unsigned rpi; /* Pointer In (Rx)*/ unsigned rpo; /* Pointer Out (Rx)*/ int rsize; /* size of Rx queue */ int rfree; /* free space in Rx queue */ unsigned tseg; /* Tx Buffer segment */ unsigned tbob; /* Beginning of Buf (Tx)*/ unsigned tpi; /* Pointer In (Tx)*/ unsigned tpo; /* Pointer Out (Tx)*/ int tsize; /* size of Tx queue */ int tcnt; /* number of bytes in Tx queue */ int xmcount; /* count/is rx active */ unsigned chkflag; /* flags for check characters */ char chkchr0; /* Check character 0 */ char chkchr1; /* Check character 1 */ char chkchr2; /* Check character 2 */ unsigned irq8259; /* Interrupt # in 8259 (com0 = 4) */ unsigned port8259; /* I/O Address of 8259 */ char not_used[15]; /* Pad to 64 bytes */ }; /* * Structure for Local Parameters for XMODEM functions. */ struct XMBUF { int xblocknum; char first; int xstatus; }; /* * The next two declarations must be exactly as stated. * */ int n_asi_ports = N_ASPORTS; struct ASITABLE asi_parms[ N_ASPORTS ]; char *loc_asi_parms; /* * Define I/O Addresses for Intel 8250 UART devices. These are addresses of * the base of a register array. The first two are declared as COM1 and COM2. * * These values will be transferred into the structures by "asisetup". */ unsigned as_port[MAX_ASPORTS] = { 0x3f8,0x2f8,0,0,0,0,0,0 }; /* * Define Interrupt Numbers. For COM1 and COM2 the conventional ones * are used. The rest are just unassigned numbers. */ int as_intnums[MAX_ASPORTS] = { 12,11,0,0,0,0,0,0 }; /* * Define Port Numbers for the 8259, COM1 and COM2 are 33, add * addresses here for additional 8259's */ int as_8259ports[MAX_ASPORTS] = { 33,33,0,0,0,0,0,0}; /* * Define IRQ number for 8259 COM1 = 4, COM2 = 3, add additional * ones as necessary. */ int as_8259irq[MAX_ASPORTS] = {4,3,0,0,0,0,0,0}; /* * The next variable, when set to 1 in an assignment statement, will * make the time constants below valid. When set to 0, however, NO * DELAY is taken except for character ready or Tx Buffer Empty. * In this mode ( _as_wcts = 0 ), communication with certain modems * such as the Hayes series can be managed when CTS is not high - e.g. * before a call is established, or when DSR is not high. */ int _as_wcts; /* * Time Constants for timeout on polled write (asputc). A call to asputc * will first read the status - if the Tx Buffer is empty the character * will be written and the function will exit. If it is not empty, the * function will enter a loop in which status is repeatedly read and * checked for Tx Buffer Empty so that when it goes empty, the character * will be written. This delay, then, must assure that a full character * may be transmitted at the worst-case baud rate. * * Time Constant: Each loop is approx. 1 millisec. in the IBM PC and XT. * * At 300 baud and 8 data bits, 1 stop bit, odd or even parity, * one character requires about 33 millisec. to transmit. Therefore * TC must be at least 35. * * Baud Rate Minimum Time Constant Recommended * 110 95 * 150 70 * 300 35 * 600 17 * 1200 9 * 2400 5 * 4800 2 * 9600 1 * * NOTE: The maximum value is 255; only 8 bits are significant. * * These timeouts do NOT apply to interrupt mode, e.g. asiputc. */ int as_wtime[MAX_ASPORTS] = { 95,95,95,95,95,95,95,95 }; /* Time Constants for READ (polled mode only) * * These operate to allow the asgetc function to dally before returning, * hence waiting until the Receiver Data Buffer has been filled with a * character. For applications which do NOT want to wait, this time * constant may be 0 in which case the function asgetc will return -1 * if no character is available. Alternatively, the time constants may * be set to similar values as above for WRITE operations. */ int as_rtime[MAX_ASPORTS] = { 0,0,0,0,0,0,0,0 }; /* * Macros to define status and flag bits. */ /* T E S T IF RECEIVER DETECTED A PARTICULAR CHECK CHARACTER * * Use these in conjunction with asirchk(). */ #define ischk2(x) (asi_parms[x].chkflag&256)?1:0 #define ischk1(x) (asi_parms[x].chkflag&128)?1:0 #define ischk0(x) (asi_parms[x].chkflag&64)?1:0 /* F L A G B I T T E S T S * * These just test flag bits. The first 8 are for general applications, * the next 8 are provided for completeness and to test when the system * has been told to ignore certain conditions. Never write into these. */ #define isalert(x) (asi_parms[x].flags&1)?1:0 #define isrxempty(x) (asi_parms[x].flags&2)?1:0 #define isrxfull(x) (asi_parms[x].flags&4)?1:0 #define istxempty(x) (asi_parms[x].flags&8)?1:0 #define istxfull(x) (asi_parms[x].flags&16)?1:0 #define islnerr(x) (asi_parms[x].flags&32)?1:0 #define ismderr(x) (asi_parms[x].flags&64)?1:0 #define isckerr(x) (asi_parms[x].flags&128)?1:0 #define isxchrun(x) (asi_parms[x].flags&256)?1:0 #define isrchrun(x) (asi_parms[x].flags&512)?1:0 #define isigalert(x) (asi_parms[x].flags&1024)?1:0 #define isigcts(x) (asi_parms[x].flags&2048)?1:0 #define isigdtr(x) (asi_parms[x].flags&4096)?1:0 #define isigcd(x) (asi_parms[x].flags&8192)?1:0 #define isigmstat(x) (asi_parms[x].flags&16384)?1:0 #define isigrcver(x) (asi_parms[x].flags&32768)?1:0 /* Return DYNAMIC Line Status */ #define isdatardy(x) (asi_parms[x].lstat&1)?1:0 /* DATA READY */ #define isoverrun(x) (asi_parms[x].lstat&2)?1:0 /* OVERRUN ERROR */ #define isparityerr(x) (asi_parms[x].lstat&4)?1:0 /* PARITY ERROR */ #define isframerr(x) (asi_parms[x].lstat&8)?1:0 /* FRAMING ERROR */ #define isbreak(x) (asi_parms[x].lstat&16)?1:0 /* BREAK DETECT */ #define ishrempty(x) (asi_parms[x].lstat&32)?1:0 /* TX HOLDING REG */ #define issrempty(x) (asi_parms[x].lstat&64)?1:0 /* TX SHIFT REG */ #define istimeout(x) (asi_parms[x].lstat&128)?1:0 /* NOT USED */ /* Return STATIC Line Status */ #define issdatardy(x) (asi_parms[x].lstat&256)?1:0 #define issoverrun(x) (asi_parms[x].lstat&512)?1:0 #define issparityerr(x) (asi_parms[x].lstat&1024)?1:0 #define issframerr(x) (asi_parms[x].lstat&2048)?1:0 #define issbreak(x) (asi_parms[x].lstat&4096)?1:0 #define isshrempty(x) (asi_parms[x].lstat&8192)?1:0 #define isssrempty(x) (asi_parms[x].lstat&0x4000)?1:0 #define isstimeout(x) (asi_parms[x].lstat&0x8000)?1:0 /* Return DYNAMIC Modem Status */ #define ischgcts(x) (asi_parms[x].mstat&1)?1:0 #define ischgdsr(x) (asi_parms[x].mstat&2)?1:0 #define ischgri(x) (asi_parms[x].mstat&4)?1:0 #define ischgcd(x) (asi_parms[x].mstat&8)?1:0 #define iscts(x) (asi_parms[x].mstat&16)?1:0 #define isdsr(x) (asi_parms[x].mstat&32)?1:0 #define isri(x) (asi_parms[x].mstat&64)?1:0 #define iscd(x) (asi_parms[x].mstat&128)?1:0 /* Return STATIC Modem Status */ #define isschgcts(x) (asi_parms[x].mstat&256)?1:0 #define isschgdsr(x) (asi_parms[x].mstat&512)?1:0 #define isschgri(x) (asi_parms[x].mstat&1024)?1:0 #define isschgcd(x) (asi_parms[x].mstat&2048)?1:0 #define isscts(x) (asi_parms[x].mstat&4096)?1:0 #define issdsr(x) (asi_parms[x].mstat&8192)?1:0 #define issri(x) (asi_parms[x].mstat&0x4000)?1:0 #define isscd(x) (asi_parms[x].mstat&0x8000)?1:0 /* Boolean: Has receiver gotten one or more characters ? */ #define isxmrxing(x) (asi_parms[x].xmcount>0)?1:0 /* Boolean: Has receiver gotten a specified number of characters ? */ #define isxmrxcnt(x,y) (asi_parms[x].xmcount>=y)?1:0 /* Misc. definitions */ #define ASIN 1 #define ASOUT 2 #define ASINOUT 3 #define ASCIINONE 1 #define ASCIIXM 5 #define BINARYNONE 2 #define BINARYXM 6 /* ASCII Protocol Characters */ #define NUL 0 #define SOH 1 #define STX 2 #define ETX 3 #define EOT 4 #define ACK 6 #define DLE 0x10 #define DC1 0x11 #define DC2 0x12 #define DC3 0x13 #define DC4 0x14 #define NAK 0x15 #define ETB 0x17 #define XON 0x11 #define XOFF 0x13 ################################################################## ## CDISK.H /* disk.h * * Disk System and Diskette Primitive Access Header * * The Greenleaf Functions - Copyright (C) 1983 Greenleaf Software */ typedef long dword; #define dosint 0x21 /* DOS function interrupt */ /* Disk File Attribute bits are in the following structure */ struct DISKATTR { word rdo : 1; /* bit 0 - Read Only attribute */ word hid : 1; /* bit 1 - Hidden attribute */ word sys : 1; /* bit 2 - System attribute */ word vll : 1; /* bit 3 - Volume Label in 1st 11 bytes */ word sbd : 1; /* bit 4 - Sub Directory bit */ word arc : 1; /* bit 5 is archive bit */ word _spares :10; /* bits 6,7, and first byte . unused */ }; /* this union allows ease of access to the attribute as a word */ union FILEATTR { word fattr; struct DISKATTR dattr; }; struct EXTFCB { byte extflag; /* extension flag: 0FF=extd fcb */ byte sysreserve[4]; /* reserved DOS 2.0 - don't use */ union FILEATTR dskattr; /* Attribute in second byte, 1st unused */ byte fdrive; /* drive code: 0=default 1=A 2=B.. */ byte fname[8]; /* filename UC left justify blank fill */ byte fext[3]; /* filename extension */ word blocknum; /* current block number, first = 0 */ word lrs; /* logical record size (bytes): 80h opn */ dword lfs; /* logical file size bytes: wd 1 = lo */ /* Create or Last Update Date */ word fcbyear : 7; /* year 0..119 (1980..2099) */ word fcbmonth: 4; /* month 1..12 */ word fcbday : 5; /* day 1..31 */ byte fcbsys[10]; /* reserved for DOS use */ byte fcbcr; /* current record number (seq i/o) */ dword fcbrec; /* random record number (rand i/o) */ }; /* Structure for FATINFO part of DISKTABLE */ struct FATINFO { word fatid; /* see function 1B */ word allocunits; /* allocation units */ word sectsalloc; /* sectors per allocation unit */ word sectsize; /* sector size */ }; /* Structure for LOLEV part of DISKTABLE */ struct LOLEV { int head; /* head 0..1 (0..7 for hard disk) */ int cylinder; /* 0..39 (0..1023 hard disk) */ int track; /* 0..39 ..synonym for cylinder */ int fsector; /* first sector - 1..9 (1..17 hard dsk) */ int nsectors; /* no. sectors - 1..8 (1..128 harddsk) */ int sectsdone; /* sectors actually done (return value) */ }; /* structure for lots of DOS disk access functions including members * to handle DOS 2.0 and 1.x functions. Note that an Extended FCB is * an integral part of this structure. * * The "lolev" structure part of this is used only for DOS interrupts * 24h and 25h and for ALL "BIOS" or "LOLEV" disk functions "diskxxxx". * * The "fatinfo" structure part is used only for "dosfatinfo". */ struct DISKTABLE { char *string; /* drive:path\filename.ext */ word handle; /* File Handle */ int drive; /* drive code: 0=A, etc. */ byte *bufoffset; /* pointer to disk buffer (offset) */ word bufseg; /* segment address of disk buffer */ /* code as 0 to use current DS */ word access; /* file access method 1..6 */ word mode; /* mode ASCII or BINARY */ struct EXTFCB dskfcb; /* FCB is used for some functions */ int rbytes; /* number of bytes to be read/written */ int abytes; /* ..bytes actually read/written */ struct LOLEV lolev; /* use for all "diskxxxx" functions only*/ word status; /* status return from all functions */ char *save; /* output string, as in fn 47h */ word dosver; /* DOS version as read by functions */ }; /* structure to use when renaming a file */ struct RENFILE { byte drvcode; /* drive */ byte oldname[8]; /* DS:DX + 1..8 old filename */ byte oldext[3]; /* + 9..B old extension */ byte dontuse[5]; /* + C..10 .. do not use */ byte newname[8]; /* +11..18 .. new filename */ byte newext[3]; /* +19..1B .. new extension */ byte padddd[8]; /* pad out to regular FCB size */ }; struct FHANDLE { unsigned xfhandle; char xfname[13]; /* filename, ext */ }; ################################################################## ## COMPILE.BAT lc1 >%1.err %1 -mS -b type %1.err lc2 %1 ################################################################## ## CSTDIO.H /* stdio.h - standard i/o header add-on * * ..for Lattice and Microsoft C and The Greenleaf Functions * Copyright (C) 1983,1984 Greenleaf Software */ /* Note: add defines for _LDATA and/or _LCODE here to determine * memory model. S - None. P - _LCODE. D - _LDATA. L - Both. */ #define EOS '\0' /* standard end of string */ /* Additional Data and Function Types */ typedef unsigned int word; typedef char byte; typedef int void; /* no-return functions */ typedef int bool; /* boolean */ /* Video and other system interrupts */ #define VIDEO 0x10 /* BIOS video interrupt */ #define DOSINT 0x21 /* DOS Function Call interrupt */ /* Structure used to pass registers to system interrupts (sysint) */ struct REGS { int ax,bx,cx,dx,si,di,ds,es; }; /* Some useful words to use... */ #define YES 1 #define NO 0 #define TRUE 1 #define FALSE 0 #define OK 1 #define NOTOK 0 #define SUCCESS 1 #define FAILURE 0 #define ON 1 #define OFF 0 #define SET 1 #define CLEAR 0 #define FOREVER 1 #define NEVER 0 #define ERR (-1) #define ERROR (-1) /* defines supporting IBM graphics printer functions and cursor */ #define NORM 1 /* normal graphics printer or plain-vanilla cursor */ #define FAST 2 /* fast (ESC Y) graphics print or fast blink cursr */ #define SLOW 3 /* slow blink cursor */ #define NOBLINK 4 /* non-blinking cursor */ #define INCHES 10 /* as in inches per page for form length */ #define LINES 11 /* ..lines per page.. */ /* general ASCII and related defines */ #define BLANK 0x20 #define CR 13 #define LF 10 #define FF 12 #define BKSP 8 /* BackSpace */ #define TAB 9 #define ESC 27 /* ESCape */ #define DEL 0x7F /* Delete */ /* video attributes (black/white) */ #define NORMAL 7 #define VNORMAL 7 #define REVERSE 0x70 #define NONDISP 0 #define BLINK 32 /* for video attributes or normal blink cursor */ /* used in some DOS functions to detect carry flag on return from SYSINT */ #define iscarry(x) ((x&0x0001)?TRUE:FALSE) /* end of standard header file add-on section. */ ################################################################## ## CTYPE.H /** * * This header file defines various ASCII character manipulation macros, * as follows: * * isalpha(c) non-zero if c is alpha * isupper(c) non-zero if c is upper case * islower(c) non-zero if c is lower case * isdigit(c) non-zero if c is a digit (0 to 9) * isxdigit(c) non-zero if c is a hexadecimal digit (0 to 9, A to F, * a to f) * isspace(c) non-zero if c is white space * ispunct(c) non-zero if c is punctuation * isalnum(c) non-zero if c is alpha or digit * isprint(c) non-zero if c is printable (including blank) * isgraph(c) non-zero if c is graphic (excluding blank) * iscntrl(c) non-zero if c is control character * isascii(c) non-zero if c is ASCII * iscsym(c) non-zero if valid character for C symbols * iscsymf(c) non-zero if valid first character for C symbols * **/ #define _U 1 /* upper case flag */ #define _L 2 /* lower case flag */ #define _N 4 /* number flag */ #define _S 8 /* space flag */ #define _P 16 /* punctuation flag */ #define _C 32 /* control character flag */ #define _B 64 /* blank flag */ #define _X 128 /* hexadecimal flag */ extern char _ctype[]; /* character type table */ #define isalpha(c) (_ctype[(c)+1]&(_U|_L)) #define isupper(c) (_ctype[(c)+1]&_U) #define islower(c) (_ctype[(c)+1]&_L) #define isdigit(c) (_ctype[(c)+1]&_N) #define isxdigit(c) (_ctype[(c)+1]&_X) #define isspace(c) (_ctype[(c)+1]&_S) #define ispunct(c) (_ctype[(c)+1]&_P) #define isalnum(c) (_ctype[(c)+1]&(_U|_L|_N)) #define isprint(c) (_ctype[(c)+1]&(_P|_U|_L|_N|_B)) #define isgraph(c) (_ctype[(c)+1]&(_P|_U|_L|_N)) #define iscntrl(c) (_ctype[(c)+1]&_C) #define isascii(c) ((unsigned)(c)<=127) #define iscsym(c) (isalnum(c)||(((c)&127)==0x5f)) #define iscsymf(c) (isalpha(c)||(((c)&127)==0x5f)) #define toupper(c) (islower(c)?((c)-('a'-'A')):(c)) #define tolower(c) (isupper(c)?((c)+('a'-'A')):(c)) #define toascii(c) ((c)&127) ################################################################## ## FCNTL.H /** * * The following symbols are used for the "open" and "creat" functions. * **/ #define O_RDONLY 0 /* Read-only value (right byte of mode word) */ #define O_WRONLY 1 /* Write-only value */ #define O_RDWR 2 /* Read-write value */ #define O_NDELAY 4 /* Non-blocking I/O flag */ #define O_APPEND 8 /* Append mode flag */ #define O_CREAT 0x0100 /* File creation flag */ #define O_TRUNC 0x200 /* File truncation flag */ #define O_EXCL 0x400 /* Exclusive access flag */ #define O_RAW 0x8000 /* Raw I/O flag (Lattice feature) */ /** * * The following symbols are used for the "fcntl" function. * */ #define F_DUPFD 0 /* Duplicate file descriptor */ #define F_GETFD 1 /* Get file descriptor flags */ #define F_SETFD 2 /* Set file descriptor flags */ #define F_GETFL 3 /* Get file flags */ #define F_SETFL 4 /* Set file flags */ ################################################################## ## KWCHANGE.DOC December 6, 1985 CHANGES TO THE KERMIT WINDOWING DEFINITION DECEMBER 6, 1985 DRAFT ["KWINDOW5.TXT] ---------------------- There is one change in the draft KERMIT WINDOWING PROTOCOL definition between the draft dated November 11, 1985 and the draft dated December 6, 1985. An additional heuristic is added to section 4.4 "Error Handling on Both Sides". Here is the additional text: *** TIMEOUT AVOIDANCE HEURISTIC Section added through An additional heuristic will prevent most timeouts due to lost stars ACKs or NAKs. The sender re-sends the earliest packet (the packet below blocking the window) if the following conditions are true: 1. The Sender's window is blocked. 2. The Retry Count for the earliest packet is zero. 3. An ACK (or optionally also NAK) for any later packet has been received. This heuristic takes advantage of the fact that ACKs and NAKs should normally be received in order. Receipt of a later ACK implies that the earliest ACK was lost. Therefore, we can anticipate that a timeout is likely to occur and avoid it by resending (once) the packet blocking the window. The packet is only sent once (i.e. if the retry count is zero) to avoid *** complicating error recovery. NOVEMBER 11, 1985 DRAFT ["KWINDOW4.TXT"] ----------------------- There are two changes in the draft KERMIT WINDOWING PROTOCOL definition between the draft dated July 19, 1985 and the draft dated November 11, 1985. (** in the left margin indicates text changed from July 19 version.) They are: A) In section "4.3 The Sender's Handling of Confirmations", "...When the sender receives a NAK, the table boundaries are checked. A NAK inside the table boundary indicates that the sender must re-send the packet. The sender first tests the packet's retry counter against the retry threshold. If the threshold has been reached, then the transfer is stopped (by going to the Abort state). Otherwise, the retry counter is incremented and the packet re-sent. ** A NAK outside of the table boundary causes the sender to send ** the earliest unACKed packet, or if all have been ACKed, the ** next packet. The retry counter is tested and incremented as ** above." COMMENT: This section previously said that a NAK outside the table boundaries would be ignored. This change was made to accomodate the timeout condition where the receiver is sending a NAK for WINDOW_HIGH +1 (the next packet) which can happen if an ACK is lost. This change handles the scenario where: 1) An ACK is lost 2) Sender's window is blocked 3) The Receiver times out and sends NAK for next packet 4) Sender gets NAK for packet not yet sent B) In section "5.3 Receiver User Interrupt", "... Whenever the receiver checks for input from the data communications line, it also should check for user input. If that indicates that the file transfer should be stopped, the receiver sets an "interrupt indication" of X (for "stop this file transfer") or of Z (for "stop the batch of file transfers"). When the receiver later sends an ACK, it places an X or Z in the data field. When the sender gets this ACK, it goes to the Send_Eof state and sends the End_of_File packet with the Discard indication, as above. ** The sequence number of the End_of_File packet is the (sequence ** number of the ACK with Discard) + 1. ..." COMMENT: The July 19 draft made no mention of what the sequence number of the EOF packet should be under this condition. This addition defines the EOF packet sequence number. ################################################################## ## KWINDOW5.DOC ***Change from November 11, 1985 draft definition. Change is to section 4.4 ** Changes from July 19 draft definition indicated by ** at left margin. Changes are to section 4.3 and section 5.3 KERMIT WINDOWING PROTOCOL December 6, 1985 DRAFT VERSION 1.3 1 INTRODUCTION The windowing protocol as defined for the Kermit file transfer protocol is based on the main premise of continuously sending data packets up to the number defined by a set window size. These data packets are continuously acknowledged by the receive side and the ideal transfer occurs as long as they are transmitted with good checksums, they are transmitted in sequential order and there are no lost data packets or acknowledgements. The various error conditions define the details of the windowing protocol and are best examined on a case basis. There are five stages that describe the overall sequence of events in the Kermit protocol. Three of these stages deviate from the original protocol in order to add the windowing feature. Stages 1 through 5 are briefly described on the following page. The three stages (1, 3 and 4) which deviate from the original protocol are then described in greater detail in the pages that follow. DRAFT PROPOSED DEFINITION Page 1 KERMIT WINDOWING PROTOCOL December 6, 198 2 OVERALL SEQUENCE OF EVENTS STAGE 1 - Propose and Accept Windowing The send side requests windowing in the transmission of the Send-Initiate (S) packet. The receive side accepts windowing by sending an acknowledgement (ACK packet) for the Send-Initiate packet. STAGE 2 - Send and Accept File-Header Packet The send side transmits the File-Header (F) packet and waits for the receive side to acknowledge it prior to transmitting any data. STAGE 3 - Transfer Data The sending routine transmits Data (D) packets one after the other until the protocol window is closed. The receiving side ACKs good data, stores data to disk as necessary and NAKs bad data. When the sender receives an ACK, the window may be rotated and the next packet sent. If the sender receives a NAK, the data packet concerned is retransmitted. STAGE 4 - Send and Accept End_of_File Packet As the sender is reading the file for data to send, it will eventually reach the end of the file. It then waits until all outstanding data packets have been acknowledged, and then sends an End-of_File (Z) packet. When the receive side gets the End-of-File packet it stores the rest of the data to disk, closes the file, and ACKs the End-of_File packet. The protocol then returns to Stage 2, sending and acknowledging any further File-Header (F) packets. STAGE 5 - End of Transmission Once the End-of-File packet has been sent and acknowledged and there are no more files to send, the sender transmits the End-of-Transmission (B) packet in order to end the ongoing transaction. Once the receiver ACKs this packet, the transaction is ended and the logical connection closed. DRAFT PROPOSED DEFINITION Page 2 KERMIT WINDOWING PROTOCOL December 6, 198 3 PROPOSE AND ACCEPT WINDOWING (STAGE 1) The initial connection as currently defined for the Kermit protocol will need to change only in terms of the contents of the Send-Initiate packet. The receiving Kermit waits for the sending Kermit to transmit the Send-Initiate (S) packet and the sending packet does not proceed with any additional transmission until the ACK has been returned by the receiver. The contents of the Send-Init packet, however, will be slightly revised. The data field of the Send-Init packet currently contains all of the configuration parameters. The first six fields of the Send-Init packet are fixed as follows: 1 2 3 4 5 6 +--------+--------+--------+--------+--------+--------+ | MAXL | TIME | NPAD | PADC | EOL | QCTL | +--------+--------+--------+--------+--------+--------+ Fields 7 through 10 are optional features of Kermit and fields 7 through 9 will also remain unchanged as defined for the existing protocol: 7 8 9 10 +--------+--------+--------+--------+ | QBIN | CHKT | REPT | CAPAS | +--------+--------+--------+--------+ Field 10 is the capability field and requires N number of bytes depending on the number of capabilities defined for kermit. Each bit position of these 6-bit fields corresponds to a capability with the low order bit used to indicate whether or not another capability byte follows. If the low order bit is "1" then another capability byte follows. If the low order bit is "0" then the current byte is the last capability byte. The second through sixth bit positions represent capabilities in the same way. If a bit position is set to 1 then the capability it represents is present. If the bit position is set to 0 then the capability it represents does not exist. Currently, there are only 3 capabilities defined for Kermit as follows: #1 Reserved #2 Reserved #3 Ability to accept "A" packets (file attributes) The windowing capability will constitute a fourth capability and the fourth bit of the capability field will be set to 1 if the kermit implementation can handle windowing. #4 Ability to handle windowing. DRAFT PROPOSED DEFINITION Page 3 KERMIT WINDOWING PROTOCOL December 6, 198 The remaining fields of the Send-Init packet are either reserved for future use by the standard Kermit protocol or reserved for local site implementations. The four fields following the capability field are reserved for the standard Kermit protocol. We propose the use of field 11 to be used to specify the "Window Size" for all kermits 11 12 13 14 15 16 - N +--------+--------+--------+--------+--------+------------------+ | WINDW | RESV1 | RESV2 | RESV3 | RESV4 | LOCAL Reserved | +--------+--------+--------+--------+--------+------------------+ 11. WINDW The window size to be used encoded printably using the char() function. The window size may range from 1 to 31 inclusive. The sender will specify the window size it wishes to use and the receiver will reply (in the ACK packet) with the window size it wishes to use. The window size actually used will be the minimum of the two. If the receiver replies with a window size of 0 then no windowing will be done. DRAFT PROPOSED DEFINITION Page 4 KERMIT WINDOWING PROTOCOL December 6, 198 4 TRANSFER DATA (STAGE 3) The sequence of events required for the transmission of data packets and confirmation of receipts constitute the main functions of the windowing protocol. There are four main functions which can be identified within this stage. These are: - the sender's processing of the data packets, - the receiver's handling of incoming packets, - the sender's handling of the confirmations, - the error handling on both sides. The following discussion details the specific actions required for each of these functions. Refer to the state table at the end of this document for the specific action taken on a "received message" basis for the full protocol. 4.1 The Sender's Processing of Data Packets The sender instigates the transmission by sending the first data packet and then operating in a cyclical mode of sending data until the defined window is closed. Data to be sent must be read from the file, encoded into the Kermit Data packet, and saved in a Send-Table. A Send-Table entry consists of the data packet itself (which makes convenient the re-send of a NAKed packet), a bit which keeps track of whether the packet has been ACKed (the ACKed bit), and a retry counter. The table is large enough to hold all the packets for the protocol window. Before each transmission, the input buffer is checked and input is processed, as described below. Transmission is stopped if the protocol window "closes", that is, if the Send-Table is full. DRAFT PROPOSED DEFINITION Page 5 KERMIT WINDOWING PROTOCOL December 6, 198 4.2 The Receiver's Handling of Incoming Packets The receiver keeps its own table as it receives incoming data packets. This allows the receiver to receive subsequent packets while it is waiting for a re-send of an erroneous or lost packet. In other words, the incoming packets do not have to be received in sequential order and can still be written to disk in order. A Receive-Table entry consists of the data packet, a bit which keeps track of whether a good version of the packet has been received (the ACKed bit), and a retry counter for the NAKs we send to request retransmissions of the packet. The table is large enough to hold all the packets for the protocol window. The different possibilities for a received packet are: 1. A new packet, the next sequential one (the usual case) 2. A new packet, not the next sequential one (some were lost) 3. An old packet, retransmitted 4. An unexpected data packet 5. Any packet with a bad checksum These are discussed separately below. 1. The next new packet has sequence number one past the . The packet is ACKed, and the Receive-Table is checked for space. If it is full (already contains window_size entries) then the oldest entry is written to disk. (This entry should have the ACKed bit set. If not, the receiver aborts the file transfer.) The received packet is then stored in the Receive-Table, with the ACKed bit set. 2. If the packet received has sequence number in the range to then it is a new packet, but some have been lost. (The upper limit here represents the highest packet the sender could send within its protocol window. Note that the requirement to test for this case is what limits the maximum window_size to half of the range of possible sequence numbers) We ACK the packet, and NAK all packets that were skipped. (The skipped packets are those from to ) The Receive-Table is then checked. The table may have to be rotated to accomodate the packet, as with case 1. (This time, several table entries may have to be written to disk. As before, if any do not have the ACKed bit set, they will trigger an abort.) The packet is then stored in the table, and the ACKed bit set. 3. A retransmitted packet will have sequence number in the range to . The packet is ACKed, then placed in the table, setting the ACKed bit. DRAFT PROPOSED DEFINITION Page 6 KERMIT WINDOWING PROTOCOL December 6, 198 4. A packet with sequence number outside of the range from to is ignored. 5. If the packet received has a bad checksum, we must decide whether to generate a NAK, and if so, with what sequence number. The best action may depend on the configuration and channel error rate. For now, we adopt the following heuristic: If there are unACKed entries in our Receive-Table, we send a NAK for the oldest one. Otherwise we ignore the packet. (Notice that this will occur in a common case: when things have been going smoothly and one packet gets garbled. In this case, when we later receive the next packet we will NAK for this one as described under Case 2 above.) DRAFT PROPOSED DEFINITION Page 7 KERMIT WINDOWING PROTOCOL December 6, 198 4.3 The Sender's Handling of Confirmations The sender's receipt of confirmations controls the rotation of the Send-Table and normally returns the sender to a sending state. The sender's action depends on the packet checksum, the type of confirmation (ACK or NAK), and whether the confirmation is within the high and low boundaries of the Send-Table. If the checksum is bad the packet is ignored. When the sender receives an ACK, the sequence number is examined. If the sequence number is outside of the current table boundaries, then the ACK is also ignored. If the sequence number is inside of the current table boundaries then the ACKed bit for that packet is marked. If the entry is at the low boundary, this enables a "rotation" of the table. The low boundary is changed to the next sequential entry for which the ACKed bit is not set. This frees space in the table to allow further transmissions. When the sender receives a NAK, the table boundaries are checked. A NAK inside the table boundary indicates that the sender must re-send the packet. The sender first tests the packet's retry counter against the retry threshold. If the threshold has been reached, then the transfer is stopped (by going to the Abort state). Otherwise, the retry counter is incremented and the packet re-sent. ** A NAK outside of the table boundary causes the sender to send ** the earliest unACKed packet, or if all have been ACKed, the ** next packet. The retry counter is tested and incremented as above. DRAFT PROPOSED DEFINITION Page 8 KERMIT WINDOWING PROTOCOL December 6, 198 4.4 Error Handling for Both Sides Three situations are discussed here: Sender timeout, Receiver timeout, and invalid packets. If certain packets are lost, each side may "hang", waiting for the other. To get things moving when this happens each may have a "timeout limit", the longest they will wait for something from the other side. If the sender's timeout condition is triggered, then it will send the oldest unACKed packet. This will be the first one in the Send-Table. If the receiver's timeout condition is triggered, then it will send a NAK for the "most desired packet". This is defined as either the oldest unACKed packet, or if none are unACKed, then the next packet to be received (sequence number ). The packet retry count is not incremented by this NAK; instead we depend on the timeout retry count, discussed next. For either the sender or receiver, the timeout retry count is incremented each time a timeout occurs. If the timeout retry limit is exceeded then the side aborts the file transfer. Each side resets the retry count to zero whenever they receive a packet. In addition, as with the existing Kermit, any invalid packet types received by either side will cause an Error packet and stop the file transfer. *** TIMEOUT AVOIDANCE HEURISTIC Section added through An additional heuristic will prevent most timeouts due to lost stars ACKs or NAKs. The sender re-sends the earliest packet (the packet below blocking the window) if the following conditions are true: 1. The Sender's window is blocked. 2. The Retry Count for the earliest packet is zero. 3. An ACK (or optionally also NAK) for any later packet has been received. This heuristic takes advantage of the fact that ACKs and NAKs should normally be received in order. Receipt of a later ACK implies that the earliest ACK was lost. Therefore, we can anticipate that a timeout is likely to occur and avoid it by resending (once) the packet blocking the window. The packet is only sent once (i.e. if the retry count is zero) to avoid *** complicating error recovery. DRAFT PROPOSED DEFINITION Page 9 KERMIT WINDOWING PROTOCOL December 6, 198 5 SEND AND ACCEPT END_OF_FILE PACKET (STAGE 4) There are several ways to end the file transfer. The first is the normal way, when the sender encounters an end-of-file condition when reading the file to get a packet for transmission. The second is because of a sender side user interrupt. The third is because of a receiver side user interrupt. Both of these cause the received file to be discarded. In addition either side may stop the transfer with an Error packet if an unrecoverable error is encountered. 5.1 Normal End of File Handling When the sender reaches the end of file, it must wait until all data packets have been acknowledged before sending the End-of-File (Z) packet. To do this it must be able to check the end-of-file status when it processes ACKs. If the ACK causes the Send-Table to be emptied and the end-of-file has been reached, then a transition is made to the Send_Eof state which sends the End_of_File packet. When the receiver gets the End_of_File packet, it writes the contents of the Receive-Table to the file (suitably decoded) and closes the file. (If any entries do not have the ACKed bit set, or if errors occur in writing the file, the receiver aborts the file transfer.) If the operation is successful, the receiver sends an ACK. It then sets its sequence number to the End_of_File packet sequence number and goes to Rcv_File state. 5.2 Sender User Interrupt Whenever the sender checks for input from the data communications line, it should also check for user input. If that indicates that the file transfer should be stopped, the sender goes directly to the Send_Eof state and sends an End_of_File packet with the Discard indication. It will not have to wait for outstanding packets to be ACKed. When the receiver gets the End_of_File packet with the Discard indication it discards the file, sets its sequence number to the End_of_File packet sequence number, and goes to RcvFile state. DRAFT PROPOSED DEFINITION Page 10 KERMIT WINDOWING PROTOCOL December 6, 198 5.3 Receiver User Interrupt Whenever the receiver checks for input from the data communications line, it also should check for user input. If that indicates that the file transfer should be stopped, the receiver sets an "interrupt indication" of X (for "stop this file transfer") or of Z (for "stop the batch of file transfers"). When the receiver later sends an ACK, it places an X or Z in the data field. When the sender gets this ACK, it goes to the Send_Eof state and sends the End_of_File packet with the Discard indication, as above. ** The sequence number of the End_of_File packet is the (sequence ** number of the ACK with Discard) + 1. When the receiver gets the End_of_File packet with the Discard indication, it discards the file, sets its sequence number to the End_of_File packet sequence number, and goes to RcvFile state. DRAFT PROPOSED DEFINITION Page 11 KERMIT WINDOWING PROTOCOL December 6, 198 5.4 LOW LEVEL PROTOCOL REQUIREMENTS The Kermit windowing protocol, as defined in this document, makes certain assumptions about the underlying transmission and reception mechanism. First, it must provide a full-duplex channel so that messages may be sent and received simultaneously. Second, it will prove advantageous to be able to buffer several received messages at the low level before processing them at the Kermit level. This is for two reasons. The first is that the Kermit windowing level of the protocol may take a while to process one input, and meanwhile several others may arrive. The second reason is to support XON/XOFF flow control. If Kermit receives an XOFF from the data communications line, it must wait for an XON before sending its packet. While it is waiting, the low level receive must be able to accept input. Otherwise a deadlock situation could arise with each side flow controlled, waiting for the other. DRAFT PROPOSED DEFINITION Page 12 KERMIT WINDOWING PROTOCOL December 6, 198 5.5 KERMIT WINDOWING PROTOCOL STATE TABLE The following defines the inputs expected, the actions performed, and the succeeding states for proposed new Send_Data_Windowing and Rcv_Data_Windowing states. If both sides agree on windowing in the Send Init exchange, then instead of entering the old Send_Data or Rcv_Data states from Send_File or Rcv_File, we enter the new Send_Data_Windowing or Rcv_Data_Windowing. SEND_DATA_WINDOWING Rec'd Msg Action Next State --------- ------ ---------- No input/Window closed (1) Wait for input SDW No input/Window open (2) Read file, encode packet, SDW Place in table, mark unACKed, Send packet ACK/ X or Z (3) set interrupt indicator (X/Z) Send_Eof ACK/outside table -ignore- SDW ACK/inside table (4) mark pkt ACKed, SDW or Send_Eof if low rotate table, if file eof & table empty then goto Send_Eof NAK/outside table -ignore- SDW NAK/inside table (5) test retry limit, SDW re-send DATA packet Bad checksum -ignore- SDW Timeout (6) re-send oldest unACKed pkt SDW User interrupt (7) set interrupt indicator (X/Z) Send_Eof Other (8) send Error Abort DRAFT PROPOSED DEFINITION Page 13 KERMIT WINDOWING PROTOCOL December 6, 198 RCV_DATA_WINDOWING Rec'd Msg Action Next State --------- ------ ---------- DATA/new (1) send ACK RDW if table full: file & rotate store new pkt in table DATA/old (2) send ACK, store in table RDW DATA/unexpected -ignore- RDW Z/discard (3) discard file Rcv_File Z/ (4) write table to file & close Rcv_File if OK send ACK, else Error or Abort Bad checksum (5) send NAK for oldest unACKed RDW Timeout (6) send NAK for most desired pkt RDW User Interrupt (7) Set interrupt indicator X or Z RDW Other (8) send Error pkt Abort DRAFT PROPOSED DEFINITION Page 14 ################################################################## ## LCKCMD.H /* C K U C M D . H -- Header file for Unix cmd package */ /* Author: Frank da Cruz (SY.FDC@CU20B), Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* Sizes of things */ #define HLPLW 78 /* Width of ?-help line */ #define HLPCW 19 /* Width of ?-help column */ #define CMDBL 200 /* Command buffer length */ #define HLPBL 100 /* Help string buffer length */ #define ATMBL 100 /* Command atom buffer length*/ /* Special characters */ #ifndef NUL #define NUL '\0' /* Null */ #endif #define HT '\t' /* Horizontal Tab */ #define NL '\n' /* Newline */ #ifndef CR #define CR '\r' #endif #define RDIS 0022 /* Redisplay (^R) */ #define LDEL 0025 /* Delete line (^U) */ #define WDEL 0027 /* Delete word (^W) */ #define RUB 0177 /* Rubout */ #ifndef BEL #define BEL 0007 /* Bell */ #endif #ifndef BS #define BS 0010 /* Backspace */ #endif #ifndef SP #define SP 0040 /* Space */ #endif /* Keyword table flags */ #define CM_INV 1 /* Invisible keyword */ /* Keyword Table Template */ struct keytab { /* Keyword table */ char *kwd; /* Pointer to keyword string */ int val; /* Associated value */ int flgs; /* Flags (as defined above) */ }; ################################################################## ## LCKDEB.H /* C K C D E B . H */ /* This file is included by all C-Kermit modules, including the modules that aren't specific to Kermit (like the command parser and the ck?tio and ck?fio modules. It specifies format codes for debug(), tlog(), and similar functions, and includes any necessary typedefs to be used by all C-Kermit modules, and also includes some feature selection compile-time switches. */ /* Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* DEBUG and TLOG should be defined in the Makefile if you want debugging and transaction logs. Don't define them if you want to save the space and overhead. */ #ifndef DEBUG #define debug(a,b,c,d) {} #endif #ifndef TLOG #define tlog(a,b,c,d) {} #endif /* Formats for debug(), tlog(), etc */ #define F000 0 #define F001 1 #define F010 2 #define F011 3 #define F100 4 #define F101 5 #define F110 6 #define F111 7 /* Compiler dependencies */ #ifdef PROVX1 typedef char CHAR; typedef long LONG; typedef int void; #else #ifdef V7 typedef char CHAR; typedef long LONG; #else typedef char CHAR; typedef long LONG; #endif #endif #ifdef TOWER1 typedef int void; #endif /* Line delimiter for text files */ /* If the system uses a single character for text file line delimitation, define NLCHAR to the value of that character. For text files, that character will be converted to CRLF upon output, and CRLF will be converted to that character on input. */ #ifdef MAC /* Macintosh */ #define NLCHAR 015 #else /* All Unix-like systems */ #define NLCHAR 012 #endif /* At this point, if there's a system that uses ordinary CRLF line delimitation AND the C compiler actually returns both the CR and the LF when doing input from a file, then #undef NLCHAR. */ /* The device name of a job's controlling terminal */ /* Special for VMS, same for all Unixes (?), not used by Macintosh */ #ifdef vax11c #define CTTNAM "TT:" #else #define CTTNAM "/dev/tty" #endif /* Some special includes for VAX/VMS */ #ifdef vax11c #include ssdef #include stsdef #endif /* Program return codes for VMS, DECUS C, and Unix */ #ifdef vax11c #define GOOD_EXIT (SS$_NORMAL | STS$M_INHIB_MSG) #define BAD_EXIT SS$_ABORT #else #ifdef decus #define GOOD_EXIT IO_NORMAL #define BAD_EXIT IO_ERROR #else #define GOOD_EXIT 0 #define BAD_EXIT 1 #endif #endif ################################################################## ## LCKERM.H /* ckcker.h -- Symbol and macro definitions for C-Kermit */ /* Author: Frank da Cruz (SY.FDC@CU20B), Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* Mnemonics for ASCII characters */ #define NUL 000 /* ASCII Null */ #define SOH 001 /* ASCII Start of header */ #define BEL 007 /* ASCII Bell (Beep) */ #define BS 010 /* ASCII Backspace */ #define XON 021 /* ASCII XON */ #define SP 040 /* ASCII Space */ /* Kermit parameters and defaults */ #define MAXPACK 94 /* Maximum packet size */ #define RBUFL 200 /* Receive buffer length */ #define CTLQ '#' /* Control char prefix I will use */ #define MYEBQ '&' /* 8th-Bit prefix char I will use */ #define MYRPTQ '~' /* Repeat count prefix I will use */ #define MAXTRY 10 /* Times to retry a packet */ #define MYPADN 0 /* How many padding chars I need */ #define MYPADC '\0' /* Which padding character I need */ #define MYCAPA 12 /* File attributes and windowing */ #define MYWND 31 /* Maximum window I can handle */ #define DMYTIM 7 /* Default timeout interval to use. */ #define URTIME 10 /* Timeout interval to be used on me. */ #define DEFTRN 0 /* Default line turnaround handshake */ #define DEFPAR 0 /* Default parity */ #define MYEOL CR /* End-Of-Line character I need on packets. */ #define DRPSIZ 90 /* Default incoming packet size. */ #define DSPSIZ 90 /* Default outbound packet size. */ #define DDELAY 5 /* Default delay. */ #define DSPEED 1200 /* Default line speed. */ /* Files */ #define ZCTERM 0 /* Console terminal */ #define ZSTDIO 1 /* Standard input/output */ #define ZIFILE 2 /* Current input file */ #define ZOFILE 3 /* Current output file */ #define ZDFILE 4 /* Current debugging log file */ #define ZTFILE 5 /* Current transaction log file */ #define ZPFILE 6 /* Current packet log file */ #define ZSFILE 7 /* Current session log file */ #define ZSYSFN 8 /* Input from a system function */ #define ZNFILS 9 /* How many defined file numbers */ /* Screen functions */ #define SCR_FN 1 /* filename */ #define SCR_AN 2 /* as-name */ #define SCR_FS 3 /* file-size */ #define SCR_XD 4 /* x-packet data */ #define SCR_ST 5 /* File status: */ #define ST_OK 0 /* Transferred OK */ #define ST_DISC 1 /* Discarded */ #define ST_INT 2 /* Interrupted */ #define ST_SKIP 3 /* Skipped */ #define ST_ERR 4 /* Fatal Error */ #define SCR_PN 6 /* packet number */ #define SCR_PT 7 /* packet type or pseudotype */ #define SCR_TC 8 /* transaction complete */ #define SCR_EM 9 /* error message */ #define SCR_WM 10 /* warning message */ #define SCR_TU 11 /* arbitrary undelimited text */ #define SCR_TN 12 /* arbitrary new text, delimited at beginning */ #define SCR_TZ 13 /* arbitrary text, delimited at end */ #define SCR_QE 14 /* quantity equals (e.g. "foo: 7") */ #define SCR_DT 15 /* print the date */ /* Macros */ #define tochar(ch) ((ch) + SP ) /* Number to character */ #define unchar(ch) ((ch) - SP ) /* Character to number */ #define ctl(ch) ((ch) ^ 64 ) /* Controllify/Uncontrollify */ #define unpar(ch) ((ch) & 127) /* Clear parity bit */ ################################################################## ## LCKFIO.C char *ckzv = "MS-DOS file support, 4LC (001) 01 Jul 85"; /* F. da Cruz, Columbia University Center for Computing Activities */ /* Modified for use with MS-DOS by: Jan A. van der Eijk, NUS Corp., July 1985 */ /* Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ char *ckzsys = "MS-DOS 3.1"; /* Functions (n is one of the predefined file numbers from ckcker.h): zopeni(n,name) -- Opens an existing file for input. zopeno(n,name) -- Opens a new file for output. zclose(n) -- Closes a file. zchin(n,&c) -- Gets the next character from an input file. zsout(n,s) -- Write a null-terminated string to output file, buffered. zsoutl(n,s) -- Like zsout, but appends a line terminator. zsoutx(n,s,x) -- Write x characters to output file, unbuffered. zchout(n,c) -- Add a character to an output file, unbuffered. zchki(name) -- Check if named file exists and is readable, return size. zchko(name) -- Check if named file can be created. znewn(name,s) -- Make a new unique file name based on the given name. zdelet(name) -- Delete the named file. zxpand(string) -- Expands the given wildcard string into a list of files. znext(string) -- Returns the next file from the list in "string". zrtol(n1,n2) -- Convert remote filename into local form. zltor(n1,n2) -- Convert local filename into remote form. */ /* Includes */ #include "stdios.h" /* stdio for small model */ #include #include "lckerm.h" /* Kermit definitions, ctype, stdio */ #include "lckdeb.h" #include "cdisk.h" /* Greenleaf header file */ #include "timedate.h" /* Greenleaf header file */ #define MAXWLD 500 /* Maximum wildcard filenames */ /* Declarations */ FILE *fp[ZNFILS] = { /* File pointers */ NULL, NULL, NULL, NULL, NULL, NULL, NULL }; static int fcount; /* Number of files in wild group */ char *strcpy(), *stpchr(); extern errno; /* System error code */ extern binary; /* Flag for RAW mode, use for Lattice when opening file, JAV * static char *mtchs[MAXWLD], /* Matches found for filename */ **mtchptr; /* Pointer to current match */ /* Z O P E N I -- Open an existing file for input. */ /* Return 1 if successful */ zopeni(n,name) int n; char *name; { debug(F111," zopeni",name,n); debug(F101," fp","",(int) fp[n]); if (chkfn(n) != 0) return(0); if (n == ZSTDIO) { /* Standard input? */ fp[ZIFILE] = stdin; return(1); } if ( n == ZIFILE && binary ) { fp[n] = fopen(name,"rb"); /* Lattice RAW mode */ } else { fp[n] = fopen(name,"r"); /* Real file. */ } debug(F111," zopeni", name, (int) fp[n]); if (fp[n] == NULL) { perror("zopeni"); printf("%s \n",name); } return((fp[n] != NULL) ? 1 : 0); } /* Z O P E N O -- Open a new file for output. */ /* Return 1 if successful */ zopeno(n,name) int n; char *name; { debug(F111," zopeno",name,n); if (chkfn(n) != 0) return(0); if ((n == ZCTERM) || (n == ZSTDIO)) { /* Terminal or standard output */ fp[ZOFILE] = stdout; debug(F101," fp[]=stdout", "", (int) fp[n]); return(1); } if ( n == ZOFILE && binary ) { fp[n] = fopen(name,"wb"); /* Lattice RAW mode */ } else { fp[n] = fopen(name,"w"); /* Real file. */ } if (fp[n] == NULL) perror("zopeno"); if (n == ZDFILE) setbuf(fp[n],NULL); /* Make debugging file unbuffered */ debug(F101, " fp[n]", "", (int) fp[n]); return((fp[n] != NULL) ? 1 : 0); } /* Z C L O S E -- Close the given file. */ /* Return 1 if successful */ zclose(n) int n; { if (chkfn(n) < 1) return(0); if ((fp[n] != stdout) && (fp[n] != stdin)) fclose(fp[n]); fp[n] = NULL; return(1); } /* Z C H I N -- Get a character from the input file. */ /* Returns -1 if EOF, 0 otherwise with character returned in argument */ zchin(n,c) int n; char *c; { int a; if (chkfn(n) < 1) return(-1); a = getc(fp[n]); if (a == EOF) return(-1); *c = a & 0377; return(0); } /* Z S O U T -- Write a string to the given file, buffered. */ /* Returns -1 if ERROR, 0 otherwise */ zsout(n,s) int n; char *s; { if (chkfn(n) < 1) return(-1); fprintf(fp[n],s); return(0); } /* Z S O U T L -- Write string to file, with line terminator, buffered */ /* Returns -1 if ERROR, 0 otherwise */ zsoutl(n,s) int n; char *s; { if (chkfn(n) < 1) return(-1); fprintf(fp[n],"%s\n",s); return(0); } /* Z S O U T X -- Write x characters to file, unbuffered. */ /* Returns -1 if ERROR, 0 otherwise */ zsoutx(n,s,x) int n, x; char *s; { if (chkfn(n) < 1) return(-1); return(write(fp[n]->_file,s,x)); } /* Z C H O U T -- Add a character to the given file. */ /* Returns -1 if ERROR, 0 otherwise */ zchout(n,c) int n; char c; { if (chkfn(n) < 1) return(-1); if (n == ZSFILE) return(write(fp[n]->_file,&c,1)); /* Use unbuffered for session log */ else { putc(c,fp[n]); /* Buffered for everything else */ return(0); } } /* C H K F N -- Internal function to verify file number is ok */ /* Returns: -1: File number n is out of range 0: n is in range, but file is not open 1: n in range and file is open */ chkfn(n) int n; { switch (n) { case ZCTERM: case ZSTDIO: case ZIFILE: case ZOFILE: case ZDFILE: case ZTFILE: case ZPFILE: case ZSFILE: break; default: debug(F101,"chkfn: file number out of range","",n); fprintf(stderr,"?File number out of range - %d\n",n); return(-1); } return( (fp[n] == NULL) ? 0 : 1 ); } /* Z C H K I -- Check if input file exists and is readable */ /* Returns: >= 0 if the file can be read (returns the size). -1 if file doesn't exist or can't be accessed, -2 if file exists but is not readable (e.g. a directory file). -3 if file exists but protected against read access. */ /* Directory files, special files, and symbolic links are not readable. */ long zchki(name) char *name; { long int flen; char fname[40]; long lseek(); int foo; stccpy(fname,name,39); if((foo=open(fname,O_RDONLY)) == -1 ) { return(0L); } flen = lseek(foo,0L,2); close(foo); return( (flen > -1L) ? flen : 0L ); } /* Z C H K O -- Check if output file can be created */ /* Returns -1 if write permission for the file would be denied, 0 otherwise. */ zchko(name) char *name; { int i, x; char s[50], *sp; sp = s; /* Make a copy, get length */ x = 0; while ((*sp++ = *name++) != '\0') x++; if (x == 0) return(-1); /* If no filename, fail. */ debug(F101," length","",x); for (i = x; i > 0; i--) /* Strip filename. */ if (s[i-1] == '/') break; debug(F101," i","",i); if (i == 0) /* If no path, use current directory */ strcpy(s,"./"); else /* Otherwise, use given one. */ s[i] = '\0'; /* x = access(s,W_OK); */ /* Check access of path. */ x = 0; /* assume it is ok to open file under DOS */ if (x < 0) { debug(F111,"zchko access failed:",s,errno); return(-1); } else { debug(F111,"zchko access ok:",s,x); return(0); } } /* Z D E L E T -- Delete the named file. */ zdelet(name) char *name; { unlink(name); } /* Z R T O L -- Convert remote filename into local form */ /* For DOS, this means changing lowercase letters to uppercase. */ zrtol(name,name2) char *name, *name2; { for ( ; *name != '\0'; name++) { *name2++ = islower(*name) ? toupper(*name) : *name; } *name2 = '\0'; } /* Z L T O R -- Convert filename from local format to common form. */ zltor(name,name2) char *name, *name2; { char work[100], *cp, *pp; int dc = 0; strcpy(work,name); for (cp = pp = work; *cp != '\0'; cp++) { /* strip path name */ if (*cp == '\\' || *cp == ':') { pp = cp; pp++; } else if (islower(*cp)) *cp = toupper(*cp); /* Uppercase letters */ else if (*cp == '~') *cp = 'X'; /* Change tilde to 'X' */ else if ((*cp == '.') && (++dc > 1)) *cp = 'X'; /* & extra dots */ } cp = name2; /* If nothing before dot, */ if (*pp == '.') *cp++ = 'X'; /* insert 'X' */ strcpy(cp,pp); } /* Z N E X T -- Get name of next file from list created by zxpand(). */ /* Returns >0 if there's another file, with its name copied into the arg string, or 0 if no more files in list. */ znext(fn) char *fn; { if (fcount-- > 0) strcpy(fn,*mtchptr++); else *fn = '\0'; debug(F111,"znext",fn,fcount+1); return(fcount+1); } /* Z N E W N -- Make a new name for the given file */ znewn(fn,s) char *fn, **s; { static char buf[100]; char *bp, *xp; int len = 0, n = 0, d = 0, t; bp = buf; while (*fn) { *bp++ = *fn; len++; if ( *fn++ == '.') break; /* Ignore anything after dot */ } *bp++ = '*'; /* Put a star on the end */ *bp-- = '\0'; n = zxpand(buf); /* Expand the resulting wild name */ while (n-- > 0) { /* Find any existing name~d files */ xp = *mtchptr++; xp += len; if (*xp == '~') { t = atoi(xp+1); if (t > d) d = t; /* Get maximum d */ } } if (len <= 8 && buf[len-1] != '.') sprintf(bp,".~%d ",d+1); /* JRM Add else sprintf(bp,"~%d ",d+1); /* Make and return name~(d+1) */ *s = buf; } /* Z X P A N D -- Expand a wildcard string into an array of strings */ /* Returns the number of files that match fn1, with data structures set up so that first file (if any) will be returned by the next znext() call. */ zxpand(fn) char *fn; { fcount = fgen(fn,mtchs,MAXWLD); /* Look up the file. */ if (fcount > 0) { mtchptr = mtchs; /* Save pointer for next. */ } debug(F111,"zxpand",mtchs[0],fcount); return(fcount); } /* ===================================================================== The following functions use the Greenleaf libaries. ======================================================================== */ #define SSPACE 2000 /* size of string-generating buffer */ static char sspace[SSPACE]; /* buffer to generate names in */ static char *freeptr,**resptr; /* copies of caller's arguments */ static int remlen; /* remaining length in caller's array*/ static int numfnd; /* number of matches found */ /* * fgen: * This is the actual name generator. It is passed a string, * possibly containing wildcards, and an array of character pointers. * It finds all the matching filenames and stores them into the array. * The returned strings are allocated from a static buffer local to * this module (so the caller doesn't have to worry about deallocating * them); this means that successive calls to fgen will wipe out * the results of previous calls. This isn't a problem here * because we process one wildcard string at a time. * * Input: a wildcard string, an array to write names to, the * length of the array. * Returns: the number of matches. The array is filled with filenames * that matched the pattern. If there wasn't enough room in the * array, -1 is returned. * By: Jeff Damens, CUCCA, 1984. */ fgen(fname,resarry,len) char *fname,*resarry[]; int len; { char *ptr; unsigned attr = 0; int stat,len1,len2; char dest[15],path[100],result[120]; numfnd = 0; /* none found yet */ freeptr = sspace; /* this is where matches are copied */ resptr = resarry; /* static copies of these so*/ remlen = len; /* recursive calls can alter them */ if ( (ptr=stpchr(fname,'*')) == NULL ) { if (( ptr = stpchr(fname,'?')) == NULL) { addresult(fname); /* No wild card */ return(numfnd); } } zltor(fname,dest); len1 = strlen(fname); /* get length of whole file */ len2 = strlen(dest); /* length of file */ strcpy(path,fname); /* get the pathname part */ path[len1-len2] = '\0'; stat = dosfirst(fname,attr,dest); /* Greenleaf Function */ if ( stat) return(0); strcpy(result,path); strcat(result,dest); addresult(result); while (TRUE) { stat = dosnext(fname,attr,dest); /* Greenleaf function */ if ( stat) return(numfnd); strcpy(result,path); /* make a complete file name */ strcat(result,dest); addresult(result); } } /* * addresult: * Adds a result string to the result array. Increments the number * of matches found, copies the found string into our string * buffer, and puts a pointer to the buffer into the caller's result * array. Our free buffer pointer is updated. If there is no * more room in the caller's array, the number of matches is set to -1. * Input: a result string. * Returns: nothing. */ addresult(str) char *str; { int l; if (--remlen < 0) { numfnd = -1; return; } l = strlen(str) + 1; /* size this will take up */ if ((freeptr + l) > &sspace[SSPACE-1]) { numfnd = -1; /* do not record if not enough space */ return; } strcpy(freeptr,str); *resptr++ = freeptr; freeptr += l; numfnd++; } /* Z F C D A T -- Return file creation date/time */ zfcdat(fname,str) char *fname,*str; { struct TIMEDATE td; /* Greenleaf function */ if (( getfstamp( &td,fname)) != 0) return(0); /* return false if not */ /* able to get file date */ sprintf(str,"%-4.4d%02.2d%02.2d %002.2d:%002.2d:%002.2d", td.year,td.month,td.day,td.hours,td.minutes,td.seconds); return(1); } /* Z F R E E -- Return total number of free bytes on drive specified */ long zfree(drive) char *drive; { long diskfree(); int driveno; long stat; if (drive[0] != '\0' && drive[1]== ':' ) { driveno = islower(*drive) ? toupper(*drive) : *drive; driveno = driveno - 'A' + 1; } else { driveno = 0; /* Default drive */ } stat = diskfree(driveno,0); /* Greenleaf function */ return(stat); } /* Z F P D A T -- Stamp a given file name with the given date */ zfpdat(fname,dattim) char *fname, *dattim;{ struct TIMEDATE td; /* Greenleaf function */ int i; char date[20],time[20], *dp; i = 0; for ( dp=dattim; *dp != '\0' && *dp != ' '; dp++) { date[i++] = *dp; } date[i] = '\0'; /* delimted date string */ if ( i <= 5 ) return; /* not ISO standard */ td.day = atoi(&date[i-2]); /* convert the day to int */ date[i-2] = '\0'; td.month = atoi(&date[i-4]); /* convert the month to int */ date[i-4] = '\0'; td.year = atoi(date); /* convert the year to int */ if ( td.day <= 0 || td.month <=0 || td.year < 0 ) return; if ( td.year < 1900 ) td.year += 1900; /* check date range */ i= 0; if ( *dp++ == ' ') { /* get the time if given */ for ( i=0; *dp != '\0';dp++){ time[i++] = *dp; } time[i] = '\0'; } td.seconds = 0; td.minutes = 0; td.hours = 0; switch (i){ case 8: td.seconds = atoi(&time[6]); time[5] ='\0'; /* fall through */ case 5: td.minutes = atoi(&time[3]); time[2] = '\0'; /* fall through */ case 2: td.hours = atoi(time); default: break; } /* Greenleaf function */ putfstamp(&td,fname); /* change the creation date */ } ################################################################## ## LCKFIO.DOC L C K F I O -- File I/O module Z O P E N I -- Open an existing file for input. Return 1 if successful zopeni(n,name) int n = file number to use char *name = name of file to open Z O P E N O -- Open a new file for output. Return 1 if successful zopeno(n,name) int n = file number to use char *name = name of file to open Z C L O S E -- Close the given file. Return 1 if successful zclose(n) int n = number of file to close Z C H I N -- Get a character from the input file. Returns -1 if EOF, 0 otherwise. zchin(n,c) int n = number of file to read char *c = character read Z S O U T -- Write a string to the given file, buffered. Returns -1 if ERROR, 0 otherwise zsout(n,s) int n = number of file to write to char *s = character string to write Z S O U T L -- Write string to file, with line terminator, buffered Returns -1 if ERROR, 0 otherwise zsoutl(n,s) int n = number of file to write to char *s = character string to write Z S O U T X -- Write x characters to file, unbuffered. Returns -1 if ERROR, 0 otherwise zsoutx(n,s,x) int n = number of file to write to int x = number of character to write char *s = character string to write Z C H O U T -- Add a character to the given file. Returns -1 if ERROR, 0 otherwise zchout(n,c) int n = number of file to write to char c = character to write C H K F N -- Internal function to verify file number is ok Returns: -1 = File number n is out of range 0 = n is in range, but file is not open 1 = n in range and file is open chkfn(n) int n = file number to check Z C H K I -- Check if input file exists and is readable Returns: >= 0 if the file can be read (returns the size). -1 if file doesn't exist or can't be accessed, -2 if file exists but is not readable . -3 if file exists but protected against read. long zchki(name) char *name = name of file to check Z C H K O -- Check if output file can be created . Returns -1 if write permission for the file would be denied, 0 otherwise. zchko(name) char *name = name of file to check Z D E L E T -- Delete the named file. zdelet(name) char *name = name of file to delete Z R T O L -- Convert remote filename into local form For DOS, this means changing lowercase letters to uppercase. zrtol(name,name2) char *name = file name to be converted char *name2 = converted file name Z L T O R -- Convert filename from local format to common form. Strip pathnames, directory names and uppercase. zltor(name,name2) char *name = file name to be converted char *name2 = converted file name Z N E X T -- Get name of next file from list created by zxpand(). Returns >0 if there's another file or 0 if no more files. znext(fn) char *fn = filename Z N E W N -- Make a new name for the given file znewn(fn,s) char *fn = filename to be converted char **s = pointer to converted file name Z X P A N D -- Expand a wildcard string into an array of strings Returns the number of files that match fn1, with data structures set up so that first file (if any) will be returned by the next znext() call. zxpand(fn) char *fn = filename to be expanded Z N E X T -- Get name of next file from list created by zxpand(). Returns >0 if there's another file or 0 if no more files. znext(fn) char *fn = filename Z F C D A T -- Return file creation date/time zfcdat(fname,str) char *fname = filename char *str = string with date and time Z F R E E -- Return total number of free bytes on drive specified long zfree(drive) char *drive = drive name to check Z F P D A T -- Stamp a given file name with the given date zfpdat(fname,dattim) char *fname = name of file to stamp cahr *dattim = date and time to stamp ################################################################## ## LCKFIO.ERR Lattice C Compiler (Phase 1) V2.15 Copyright (C) 1982 Lattice, Inc. ################################################################## ## LCKFNS1.C char *fnsv = "C-Kermit functions, 4LC(001) 21 Jun 85"; /* C K C F N S -- System-independent Kermit protocol support functions. */ /* ...Part 1 (others moved to ckcfn2 to make this module small enough) */ /* Author: Frank da Cruz (SY.FDC@CU20B), Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* System-dependent primitives defined in: lcktio.c -- terminal i/o lckfio.c -- file i/o, directory structure */ #include "stdios.h" /* Standard header for LC and Greenleaf */ #include "lckerm.h" /* Symbol definitions for Kermit */ #include "lckdeb.h" /* Debug formats, typedefs, etc. */ #ifndef NULL #define NULL 0 #endif /* Externals from lckmain.c */ extern int spsiz, rpsiz, timint, rtimo, npad, chklen, ebq, ebqflg, rpt, rptq, rptflg, capas; extern int filatr, nxtcas, capflg, wndsiz, wndmax, sldwnd, window; extern int pktnum, prvpkt, sndtyp, bctr, bctu, size, osize, maxsize, spktl, nfils, warn, timef; extern int parity, speed, turn, turnch, delay, displa, pktlog, tralog, seslog, xflg, mypadn; extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize; extern int deblog, hcflg, binary, fncnv, local, server, cxseen, czseen; extern char padch, mypadc, seol, eol, ctlq, myctlq, sstate; extern char filnam[], sndpkt[], recpkt[], data[], srvcmd[], *srvptr, stchr, mystch; extern char fildat[]; extern char *cmarg, *cmarg2, **cmlist; long zchki(), zfree(); char *strcpy(); /* Variables local to this module */ static char *memptr; /* Pointer for memory strings */ static char cmdstr[100]; /* Unix system command string */ static int sndsrc; /* Flag for where to send from: */ /* -1: name in cmdata */ /* 0: stdin */ /* >0: list in cmlist */ static int memstr, /* Flag for input from memory string */ t, /* Current character */ next; /* Next character */ /* E N C S T R -- Encode a string from memory. */ /* Call this instead of getpkt() if source is a string, rather than a file. */ encstr(s) char* s; { int m; char *p; m = memstr; p = memptr; /* Save these. */ memptr = s; /* Point to the string. */ memstr = 1; /* Flag memory string as source. */ next = -1; /* Initialize character lookahead. */ getpkt(spsiz); /* Fill a packet from the string. */ memstr = m; /* Restore memory string flag */ memptr = p; /* and pointer */ next = -1; /* Put this back as we found it. */ } /* E N C O D E - Kermit packet encoding procedure */ encode(a) int a; { /* The current character */ int a7; /* Low order 7 bits of character */ int b8; /* 8th bit of character */ if (rptflg) { /* Repeat processing? */ if (a == next) { /* Got a run... */ if (++rpt < 94) /* Below max, just count */ return; else if (rpt == 94) { /* Reached max, must dump */ data[size++] = rptq; data[size++] = tochar(rpt); rpt = 0; } } else if (rpt == 1) { /* Run broken, only 2? */ rpt = 0; /* Yes, reset repeat flag & count. */ encode(a); /* Do the character twice. */ if (size <= maxsize) osize = size; rpt = 0; encode(a); return; } else if (rpt > 1) { /* More than two */ data[size++] = rptq; /* Insert the repeat prefix */ data[size++] = tochar(++rpt); /* and count. */ rpt = 0; /* Reset repeat counter. */ } } a7 = a & 0177; /* Isolate ASCII part */ b8 = a & 0200; /* and 8th (parity) bit. */ if (ebqflg && b8) { /* Do 8th bit prefix if necessary. */ data[size++] = ebq; a = a7; } if ((a7 < SP) || (a7==DEL)) { /* Do control prefix if necessary */ data[size++] = myctlq; a = ctl(a); } if (a7 == myctlq) /* Prefix the control prefix */ data[size++] = myctlq; if ((rptflg) && (a7 == rptq)) /* If it's the repeat prefix, */ data[size++] = myctlq; /* quote it if doing repeat counts. */ if ((ebqflg) && (a7 == ebq)) /* Prefix the 8th bit prefix */ data[size++] = myctlq; /* if doing 8th-bit prefixes */ data[size++] = a; /* Finally, insert the character */ data[size] = '\0'; /* itself, and mark the end. */ } /* D E C O D E -- Kermit packet decoding procedure */ /* Call with string to be decoded and an output function. */ /* Returns 0 on success, -1 on failure (e.g. disk full). */ decode(buf,fn) char *buf; int (*fn)(); { unsigned int a, a7, b8; /* Low order 7 bits, and the 8th bit */ rpt = 0; /* Initialize repeat count. */ while ((a = *buf++) != '\0') { if (rptflg) { /* Repeat processing? */ if (a == rptq) { /* Yes, got a repeat prefix? */ rpt = unchar(*buf++); /* Yes, get the repeat count, */ a = *buf++; /* and get the prefixed character. */ } } b8 = 0; /* Check high order "8th" bit */ if (ebqflg) { /* 8th-bit prefixing? */ if (a == ebq) { /* Yes, got an 8th-bit prefix? */ b8 = 0200; /* Yes, remember this, */ a = *buf++; /* and get the prefixed character. */ } } if (a == ctlq) { /* If control prefix, */ a = *buf++; /* get its operand. */ a7 = a & 0177; /* Only look at low 7 bits. */ if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') /* Uncontrollify */ a = ctl(a); /* if in control range. */ } a |= b8; /* OR in the 8th bit */ if (rpt == 0) rpt = 1; /* If no repeats, then one */ #ifdef NLCHAR if (!binary) { /* If in text mode, */ if (a == CR) continue; /* discard carriage returns, */ if (a == LF) a = NLCHAR; /* convert LF to system's newline. */ } #endif for (; rpt > 0; rpt--) { /* Output the char RPT times */ ffc++, tfc++; /* Count the character */ if ((*fn)(a) < 0) return(-1); /* Send it to the output function. */ } } return(0); } /* Output functions passed to 'decode': */ putsrv(c) char c; { /* Put character in server command buffer */ *srvptr++ = c; *srvptr = '\0'; /* Make sure buffer is null-terminated */ return(0); } putfil(c) char c; { /* Output char to file. */ if (zchout(ZOFILE,c) < 0) { czseen = 1; /* If write error... */ debug(F101,"putfil zchout write error, setting czseen","",1); return(-1); } return(0); } /* G E T P K T -- Fill a packet data field */ /* Gets characters from the current source -- file or memory string. Encodes the data into the packet, filling the packet optimally. Uses global variables: t -- current character. next -- next character. data -- the packet data buffer. size -- number of characters in the data buffer. Returns the size as value of the function, and also sets global size, and fills (and null-terminates) the global data array. Before calling getpkt the first time for a given source (file or string), set the variable 'next' to -1. */ getpkt(maxsize) int maxsize; { /* Fill one packet buffer */ int i; /* Loop index. */ static char leftover[6] = { '\0', '\0', '\0', '\0', '\0', '\0' }; debug(F101,"getpkt, entering with next","",next); debug(F101," t","",t); if (next < 0) { /* If first time through, */ t = getchxx(); /* get first character of file, */ *leftover = '\0'; /* discard any interrupted leftovers. */ } /* Do any leftovers */ for (size = 0; (data[size] = leftover[size]) != '\0'; size++) ; *leftover = '\0'; /* Now fill up the rest of the packet. */ rpt = 0; /* Clear out any old repeat count. */ while(t >= 0) { /* Until EOF... */ next = getchxx(); /* Get next character for lookahead. */ osize = size; /* Remember current position. */ encode(t); /* Encode the current character. */ t = next; /* Next is now current. */ next = 0; /* No more next. */ if (size == maxsize) { /* If the packet is exactly full, */ debug(F101,"getpkt exact fit","",size); return(size); /* and return. */ } if (size > maxsize) { /* If too big, save some for next. */ for (i = 0; (leftover[i] = data[osize+i]) != '\0'; i++) ; debug(F111,"getpkt leftover",leftover,size); debug(F101," osize","",osize); size = osize; /* Return truncated packet. */ data[size] = '\0'; return(size); } } debug(F101,"getpkt eof/eot","",size); return(size); /* Return any partial final buffer. */ } /* G E T C H X X -- Get the next character from file (or pipe). */ /* renamed by Jan A. van der Eijk, because getch() is a standard C function */ /* On systems like Unix, the Macintosh, etc, that use a single character (NLCHAR, defined in ckcdeb.h) to separate lines in text files, and when in text/ascii mode (binary == 0), this function maps the newline character to CRLF. If NLCHAR is not defined, then this mapping is not done, even in text mode. */ getchxx() { /* Get next character */ int x; CHAR a; /* The character to return. */ static int b = 0; /* A character to remember. */ if (b > 0) { /* Do we have a LF saved? */ b = 0; /* Yes, return that. */ return(LF); } if (memstr) /* Try to get the next character */ x = ((a = *memptr++) == '\0'); /* from the appropriate source, */ else /* memory or the current file. */ x = (zchin(ZIFILE,&a) == -1); if (x) return(-1); /* No more, return -1 for EOF. */ else { /* Otherwise, read the next char. */ ffc++, tfc++; /* Count it. */ #ifdef NLCHAR if (!binary && (a == NLCHAR)) { /* If nl and we must do nl-CRLF */ b = 1; /* mapping, remember a linefeed, */ return(CR); /* and return a carriage return. */ } else return(a); /* General case, return the char. */ #else return(a); #endif } } /* C A N N E D -- Check if current file transfer cancelled */ canned(buf) char *buf; { if (*buf == 'X') cxseen = 1; if (*buf == 'Z') czseen = 1; debug(F101,"canned: cxseen","",cxseen); debug(F101," czseen","",czseen); return((czseen || cxseen) ? 1 : 0); } /* T I N I T -- Initialize a transaction */ tinit() { memstr = 0; /* Reset memory-string flag */ memptr = NULL; /* and pointer */ bctu = 1; /* Reset block check type to 1 */ filcnt = 0; /* Reset file counter */ tfc = tlci = tlco = 0; /* Reset character counters */ prvpkt = -1; /* Reset packet number */ pktnum = 0; cxseen = czseen = 0; /* Reset interrupt flags */ *filnam = '\0'; /* Clear file name */ } /* R I N I T -- Respond to S packet */ rinit(d) char *d; { char *tp; ztime(&tp); tlog(F110,"Transaction begins",tp,0l); /* Make transaction log entry */ tfc = tlci = tlco = 0; spar(d); rpar(d); ack1(d); } /* S I N I T -- Make sure file exists, then send Send-Init packet */ sinit() { int x; char *tp; sndsrc = nfils; /* Where to look for files to send */ ztime(&tp); tlog(F110,"Transaction begins",tp,0l); /* Make transaction log entry */ debug(F101,"sinit: sndsrc","",sndsrc); if (sndsrc < 0) { /* Must expand from 'send' command */ nfils = zxpand(cmarg); /* Look up literal name. */ if (nfils < 0) { screen(SCR_EM,0,0l,"Too many files"); return(0); } else if (nfils == 0) { /* If none found, */ char xname[100]; /* convert the name. */ zrtol(cmarg,xname); nfils = zxpand(xname); /* Look it up again. */ } if (nfils < 1) { /* If no match, report error. */ screen(SCR_EM,0,0l,"File not found"); return(0); } x = gnfile(); /* Position to first file. */ if (x < 1) { screen(SCR_EM,0,0l,"No readable file to send"); return(0); } } else if (sndsrc > 0) { /* Command line arglist -- */ x = gnfile(); /* Get the first file from it. */ if (x < 1) return(0); /* (if any) */ } else if (sndsrc == 0) { /* memory always exist... */ if ((cmarg2 != NULL) && (*cmarg2)) { strcpy(filnam,cmarg2); /* If F packet, filnam is used */ cmarg2 = ""; /* if provided, */ } else /* otherwise */ return(0); /* just use this. */ tlog(F110,"Sending from",cmdstr,0l); } debug(F101,"sinit: nfils","",nfils); debug(F110," filnam",filnam,0); debug(F110," cmdstr",cmdstr,0); ttflui(); /* Flush input buffer. */ x = rpar(data); /* Send a Send-Init packet. */ if (!local) sleep(delay); spack('S',pktnum,x,data); return(1); } /* R C V F I L -- Receive a file */ rcvfil() { int x; ffc = flci = flco = 0; /* Init per-file counters */ srvptr = srvcmd; /* Decode file name from packet. */ decode(data,putsrv); if (*srvcmd == '\0') *srvcmd = 'x'; /* Watch out for null F packet. */ screen(SCR_FN,0,0l,srvcmd); /* Put it on screen */ tlog(F110,"Receiving",srvcmd,0l); /* Transaction log entry */ if (cmarg2 != NULL && *cmarg2 != '\0') { /* Check for alternate name */ strcpy(srvcmd,cmarg2); /* Got one, use it. */ *cmarg2 = '\0'; } else if ( fncnv) { /* Do not allow pathnames being send */ char xname[100]; /* convert the name. */ zltor(srvcmd,xname); strcpy(srvcmd,xname); } x = openo(srvcmd,filnam); /* Try to open it */ if (x) { tlog(F110," as",filnam,0l); screen(SCR_AN,0,0l,filnam); intmsg(++filcnt); } else { tlog(F110,"Failure to open",filnam,0l); screen(SCR_EM,0,0l,"Can't open file"); } return(x); /* Pass on return code from openo */ } /* R E O F -- Receive End Of File */ reof() { if (cxseen == 0) cxseen = (*data == 'D'); clsof(); if (cxseen || czseen) { tlog(F100," *** Discarding","",0l); } else { tlog(F100," end of file","",0l); tlog(F101," file characters ","",ffc); tlog(F101," communication line in ","",flci); tlog(F101," communication line out ","",flco); } } /* R E O T -- Receive End Of Transaction */ reot() { char *tp; cxseen = czseen = 0; ztime(&tp); tlog(F110,"End of transaction",tp,0l); if (filcnt > 1) { tlog(F101," files","",filcnt); tlog(F101," total file characters ","",tfc); tlog(F101," communication line in ","",tlci); tlog(F101," communication line out ","",tlco); } } /* S F I L E -- Send File header packet for global "filnam" */ sfile() { char pktnam[100]; /* Local copy of name */ if (*cmarg2 != '\0') { /* If we have a send-as name, */ strcpy(pktnam,cmarg2); /* copy it literally, */ cmarg2 = ""; /* and blank it out for next time. */ } else { /* Otherwise use actual file name: */ if (fncnv) { /* If converting names, */ zltor(filnam,pktnam); /* convert it to common form, */ } else { /* otherwise, */ strcpy(pktnam,filnam); /* copy it literally. */ } } debug(F110,"sfile",filnam,0); debug(F110," pktnam",pktnam,0); if (openi(filnam) == 0) /* Try to open the file */ return(0); flci = flco = ffc = 0; /* OK, Init counters, etc. */ encstr(pktnam); /* Encode the name. */ nxtpkt(&pktnum); /* Increment the packet number */ ttflui(); /* Clear pending input */ spack('F',pktnum,size,data); /* Send the F packet */ if (displa) { screen(SCR_FN,'F',(long)pktnum,filnam); /* Update screen */ screen(SCR_AN,0,0l,pktnam); screen(SCR_FS,0,(long)fsize,""); intmsg(++filcnt); /* Count file, give interrupt msg */ } tlog(F110,"Sending",filnam,0l); /* Transaction log entry */ tlog(F110," as",pktnam,0l); next = -1; /* Init file character lookahead. */ return(1); } /* S D A T A -- Send a data packet */ sdata() { int len; if (cxseen || czseen) return(0); /* If interrupted, done. */ if ((len = getpkt(spsiz-chklen-3)) == 0) return(0); /* If no data, done. */ nxtpkt(&pktnum); /* Increment the packet number */ spack('D',pktnum,len,data); /* Send the packet */ return(1); } /* S E O F -- Send an End-Of-File packet */ seof() { nxtpkt(&pktnum); /* Increment the packet number */ if (czseen || cxseen) { spack('Z',pktnum,1,"D"); tlog(F100," *** interrupted, sending discard request","",0l); } else { spack('Z',pktnum,0,""); tlog(F100," end of file","",0l); tlog(F101," file characters ","",ffc); tlog(F101," communication line in ","",flci); tlog(F101," communication line out ","",flco); } } /* S E O T -- Send an End-Of-Transaction packet */ seot() { char *tp; nxtpkt(&pktnum); /* Increment the packet number */ spack('B',pktnum,0,""); cxseen = czseen = 0; ztime(&tp); tlog(F110,"End of transaction",tp,0l); if (filcnt > 1) { tlog(F101," files","",filcnt); tlog(F101," total file characters ","",tfc); tlog(F101," communication line in ","",tlci); tlog(F101," communication line out ","",tlco); } } /* R P A R -- Fill the data array with my send-init parameters */ rpar(data) char data[]; { data[0] = tochar(rpsiz); /* Biggest packet I can receive */ data[1] = tochar(rtimo); /* When I want to be timed out */ data[2] = tochar(mypadn); /* How much padding I need (none) */ data[3] = ctl(mypadc); /* Padding character I want */ data[4] = tochar(eol); /* End-Of-Line character I want */ data[5] = CTLQ; /* Control-Quote character I send */ if (parity || ebqflg && (ebq != 'N')) { /* 8-bit quoting */ data[6] = '&'; ebqflg = 1; } else { data[6] = 'Y'; } data[7] = bctr + '0'; /* Block check type */ data[8] = MYRPTQ; /* Do repeat counts */ data[9] = tochar(capas); /* Capabilities */ data[10] = tochar(wndmax); /* Maximum window size I want */ data[11] = '\0'; return(11); /* Return the length. */ } /* S P A R -- Get the other system's Send-Init parameters. */ spar(data) char data[]; { int len, x; len = strlen(data); /* Number of fields */ spsiz = (len-- > 0) ? unchar(data[0]) : DSPSIZ; /* Packet size */ if (spsiz < 10 || spsiz > DSPSIZ) spsiz = DSPSIZ; x = (len-- > 0) ? unchar(data[1]) : DMYTIM; /* Timeout */ if (!timef) { /* Only use if not overridden */ timint = x; if (timint < 0) timint = DMYTIM; } npad = 0; padch = '\0'; /* Padding */ if (len-- > 0) { npad = unchar(data[2]); if (len-- > 0) padch = ctl(data[3]); else padch = 0; } seol = (len-- > 0) ? unchar(data[4]) : '\r'; /* Terminator he wants */ if ((seol < 2) || (seol > 037)) seol = '\r'; ctlq = (len-- > 0) ? data[5] : CTLQ; /* Control prefix */ if (len-- > 0) { ebq = data[6]; if ((ebq > 040 && ebq < 0100) || (ebq > 0140 && ebq < 0177)) { ebqflg = 1; } else if ((parity || ebqflg) && (ebq == 'Y')) { ebqflg = 1; ebq = '&'; } else if (ebq == 'N') { ebqflg = 0; } else ebqflg = 0; } else ebqflg = 0; chklen = 1; /* Block check */ if (len-- > 0) { chklen = data[7] - '0'; if ((chklen < 1) || (chklen > 3)) chklen = 1; } bctr = chklen; if (len-- > 0) { /* Repeat prefix */ rptq = data[8]; rptflg = ((rptq > 040 && rptq < 0100) || (rptq > 0140 && rptq < 0177)); } else rptflg = 0; filatr = 0; sldwnd = 0; if (len-- > 0) { /* Capabilities */ capflg = unchar(data[9]) & capas; /* Supported by both */ if ( (capflg & 0x0008) == 0x0008) filatr = 1; /* File attributes ? */ if ( (capflg & 0x0004) == 0x0004) sldwnd = 1; /* Sliding windows ? */ } wndsiz = (len-- > 0) ? unchar(data[10]) : 0; /* Window size he wants */ if ( wndsiz > wndmax ) wndsiz = wndmax; else if ( wndsiz <= 0 ) { sldwnd = 0; wndsiz = 0; } if (deblog) sdebu(len); } /* S D E B U -- Record spar results in debugging log */ sdebu(len) int len; { debug(F111,"spar: data",data,len); debug(F101," spsiz ","",spsiz); debug(F101," timint","",timint); debug(F101," npad ","",npad); debug(F101," padch ","",padch); debug(F101," eol ","",eol); debug(F101," ctlq ","",ctlq); debug(F101," ebq ","",ebq); debug(F101," ebqflg","",ebqflg); debug(F101," chklen","",chklen); debug(F101," rptq ","",rptq); debug(F101," rptflg","",rptflg); debug(F101," capflg","",capflg); } /* G N F I L E -- Get the next file name from a file group. */ /* Returns 1 if there's a next file, 0 otherwise */ gnfile() { int x; long y; /* If file group interruption (C-Z) occured, fail. */ debug(F101,"gnfile: czseen","",czseen); if (czseen) { tlog(F100,"Transaction cancelled","",0l); return(0); } /* If input was memory string, there is no next file. */ if (sndsrc == 0) return(0); /* If file list comes from command line args, get the next list element. */ y = -1; while (y < 0) { /* Keep trying till we get one... */ if (sndsrc > 0) { if (nfils-- > 0) { strcpy(filnam,*cmlist++); debug(F111,"gnfile: cmlist filnam",filnam,nfils); } else { *filnam = '\0'; debug(F101,"gnfile cmlist: nfils","",nfils); return(0); } } /* Otherwise, step to next element of internal wildcard expansion list. */ if (sndsrc < 0) { x = znext(filnam); debug(F111,"gnfile znext: filnam",filnam,x); if (x == 0) return(0); } /* Get here with a filename. */ y = zchki(filnam); /* Check if file readable */ if (y < 0) { debug(F110,"gnfile skipping:",filnam,0); tlog(F111,filnam,"not sent, reason",(long)y); screen(SCR_ST,ST_SKIP,0l,filnam); } else fsize = y; } return(1); } /* O P E N I -- Open an existing file for input */ openi(name) char *name; { int x, filno; if (memstr) return(1); /* Just return if file is memory. */ debug(F110,"openi",name,0); debug(F101," sndsrc","",sndsrc); filno = ZIFILE; /* ... */ debug(F101," file number","",filno); if (zopeni(filno,name)) { /* Otherwise, try to open it. */ debug(F110," ok",name,0); return(1); } else { /* If not found, */ char xname[100]; /* convert the name */ zrtol(name,xname); /* to local form and then */ debug(F110," zrtol:",xname,0); x = zopeni(filno,xname); /* try opening it again. */ debug(F101," zopeni","",x); if (x) { debug(F110," ok",xname,0); return(1); /* It worked. */ } else { screen(SCR_EM,0,0l,"Can't open file"); /* It didn't work. */ tlog(F110,xname,"could not be opened",0l); debug(F110," openi failed",xname,0); return(0); } } } /* O P E N O -- Open a new file for output. */ /* Returns actual name under which the file was opened in string 'name2'. */ openo(name,name2) char *name, *name2; { char xname[100], *xp; debug(F110,"openo: name",name,0); if (cxseen || czseen) { /* If interrupted, get out before */ debug(F100," open cancelled","",0); /* destroying existing file. */ return(1); /* Pretend to succeed. */ } xp = xname; /* OK to proceed. */ if (fncnv) /* If desired, */ zrtol(name,xp); /* convert name to local form */ else /* otherwise, */ strcpy(xname,name); /* use it literally */ debug(F110,"openo: xname",xname,0); if (warn) { /* File collision avoidance? */ if (zchki(xname) > 0) { /* Yes, file exists? */ znewn(xname,&xp); /* Yes, make new name. */ strcpy(xname,xp); debug(F110," exists, new name ",xname,0); } } if (zopeno(ZOFILE,xname) == 0) { /* Try to open the file */ debug(F110,"openo failed",xname,0); tlog(F110,"Failure to open",xname,0l); return(0); } else { strcpy(name2,xname); debug(F110,"openo ok, name2",name2,0); return(1); } } /* C L S I F -- Close the current input file. */ clsif() { if (memstr) { /* If input was memory string, */ memstr = 0; /* indicate no more. */ } else zclose(ZIFILE); /* else close input file. */ if (czseen || cxseen) screen(SCR_ST,ST_DISC,0l,""); else screen(SCR_ST,ST_OK,0l,""); cxseen = hcflg = 0; /* Reset flags, */ *filnam = '\0'; /* and current file name */ window = 0; /* Reset window flag */ } /* C L S O F -- Close an output file. */ clsof() { zclose(ZOFILE); /* Close it. */ if (czseen || cxseen) { if (*filnam) zdelet(filnam); /* Delete it if interrupted. */ debug(F100,"Discarded","",0); tlog(F100,"Discarded","",0l); screen(SCR_ST,ST_DISC,0l,""); } else { if ( filatr) zfpdat(filnam,fildat); /* Stamp the file with orginal date */ debug(F100,"Closed","",0); screen(SCR_ST,ST_OK,0l,""); } cxseen = 0; /* Reset file interruption flag */ *filnam = '\0'; /* and current file name. */ window = 0; /* Reset window flag */ } /* S A T T R -- Send the attribute packet. */ /* send multiple attribute packets, in case the attribute won't fit in current packet, set nxtcase to the case we did break out of */ sattr() { int index,len; index = 2; /* start of data field */ switch(nxtcas){ case 1: sprintf(&data[index],"%ld",fsize); /* Convert to character string */ len = strlen(&data[index]); /* Get the length of data field */ data[index - 2] = '1'; /* set attribute type,file size */ data[ index - 1 ] = tochar(len); /* Put it in the packet */ index += (len + 2); /* start of next data field */ case 2: if (zfcdat(filnam,&data[index])) { /* Get the time and date stamp */ len = strlen(&data[index]); /* Get the length of data field */ if ( (index + len) > (spsiz - chklen - 3)) { nxtcas = 2; /* does not fit in packet */ break ; /* start here next packet */ } screen(SCR_DT,0,0L,&data[index]); data[index - 2] = '#'; /* set attribute type */ data[index -1] = tochar(len); /* Put it in the packect */ index += (len + 2); /* start of next data field */ } default: nxtcas = 1; /* we are done for this file */ break; } data[index - 2] = '\0'; /* delimit the string */ len = strlen(data); nxtpkt(&pktnum); /* Increment the packet number */ spack('A',pktnum,len,data); /* Send the packet */ next = -1; if (nxtcas > 1 ) return(1); else return(0); /* Last time called, return 0 */ } /* R D A T T R -- Read the attribute packet. */ rdattr(data) char data[]; { int len, index,i; char string[100]; /* Local scratch variable */ long int atol(); len = strlen(data); /* Number of fields */ index = 0; while (1) { switch(data[index++]){ case '!': /* File length in Kbytes */ len = unchar(data[index++]); for (i=0; i < len; i++ ) string[i] = data[index++]; string[i] = '\0'; fsize = (long) (atoi(string) + 1) ; screen(SCR_QE,0,fsize,"Approximate file size (Kbytes)"); fsize = fsize * 1024L; /* Change size to bytes */ if ( fsize > zfree(filnam)){ cxseen = 1 ; /* Set to true so file will be deleted */ return(0); } break; case '#': /* ISO Julian file creation date */ len = unchar(data[index++]); for (i=0; i < len; i++ ) fildat[i] = data[index++]; fildat[i] = '\0'; screen(SCR_DT,0,0L,fildat); break; case '1': /* file size in bytes */ len = unchar(data[index++]); for (i=0; i < len; i++ ) string[i] = data[index++]; string[i] = '\0'; fsize = atol(string) ; screen(SCR_QE,0,fsize,"File size (bytes)"); if ( fsize > zfree(filnam)) { cxseen = 1 ; /* Set to true so file will be deleted */ return(0); } break; default: /* Non supported attributes */ len = unchar(data[index++]); for (i=0; i < len; i++ ) string[i] = data[index++]; string[i] = '\0'; break; } if ( data[index] == '\0') break; /* End of data packet */ } return(1); } ################################################################## ## LCKFNS1.ERR Lattice C Compiler (Phase 1) V2.15 Copyright (C) 1982 Lattice, Inc. lckfns1.c 291 Warning 85: function return value mismatch ################################################################## ## LCKFNS2.C /* C K C F N 2 -- System-independent Kermit protocol support functions... */ /* ...Part 2 (continued from ckcfns.c) */ /* Author: Frank da Cruz (SY.FDC@CU20B), Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* Note -- if you change this file, please amend the version number and date at the top of ckcfns.c accordingly. */ #include "lckerm.h" #include "lckdeb.h" extern int spsiz, rpsiz, timint, npad, chklen, ebq, ebqflg, rpt, rptq, rptflg, capas, window; extern int pktnum, prvpkt, sndtyp, bctr, bctu, size, osize, maxsize, spktl, nfils, stdouf, warn, timef; extern int parity, speed, turn, turnch, delay, displa, pktlog, tralog, seslog, xflg, mypadn; extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize; extern int deblog, hcflg, binary, fncnv, local, server, cxseen, czseen; extern char padch, mypadc, eol, seol, ctlq, myctlq, sstate; extern char filnam[], sndpkt[], recpkt[], data[], srvcmd[], *srvptr, stchr, mystch; extern char *cmarg, *cmarg2, **cmlist; char *strcpy(); CHAR dopar(); /* S P A C K -- Construct and send a packet */ spack(type,num,len,dat) char type, *dat; int num, len; { int i,j; j = dopar(padch); for (i = 0; i < npad; sndpkt[i++] = j) /* Do any requested padding */ ; sndpkt[i++] = dopar(mystch); /* Start packet with the start char */ sndpkt[i++] = dopar(tochar(len+bctu+2)); /* Put in the length */ sndpkt[i++] = dopar(tochar(num)); /* The packet number */ sndpkt[i++] = sndtyp = dopar(type); /* Packet type */ for (j = len; j > 0; j-- ) sndpkt[i++] = dopar(*dat++); /* Data */ sndpkt[i] = '\0'; /* Mark end for block check */ switch(bctu) { case 1: /* Type 1 - 6 bit checksum */ sndpkt[i++] = dopar(tochar(chk1(sndpkt+1))); break; case 2: /* Type 2 - 12 bit checksum*/ j = chk2(sndpkt+1); sndpkt[i++] = dopar(tochar((j & 07700) >> 6)); sndpkt[i++] = dopar(tochar(j & 077)); break; case 3: /* Type 3 - 16 bit CRC-CCITT */ j = chk3(sndpkt+1); sndpkt[i++] = dopar(tochar(( (unsigned)(j & 0170000)) >> 12)); sndpkt[i++] = dopar(tochar((j & 07700) >> 6)); sndpkt[i++] = dopar(tochar(j & 077)); break; } for (j = npad; j > 0; j-- ) sndpkt[i++] = dopar(padch); /* Padding */ sndpkt[i++] = dopar(seol); /* EOL character */ sndpkt[i] = '\0'; /* End of the packet */ ttol(sndpkt,spktl=i); /* Send the packet just built */ flco += spktl; /* Count the characters */ tlco += spktl; if (pktlog) zsoutl(ZPFILE,sndpkt); /* If logging packets, log it */ screen(SCR_PT,type,(long)num,sndpkt); /* Update screen */ } /* D O P A R -- Add an appropriate parity bit to a character */ CHAR dopar(ch) char ch; { int a, b; if (!parity) return(ch); else ch &= 0177; switch (parity) { case 'm': ch = (ch | 128); return(ch); /* Mark */ case 's': ch = (ch & 127); return(ch); /* Space */ case 'o': /* Odd (fall thru) */ case 'e': /* Even */ a = (ch & 15) ^ ((ch >> 4) & 15); a = (a & 3) ^ ((a >> 2) & 3); a = (a & 1) ^ ((a >> 1) & 1); if (parity == 'o') a = 1 - a; /* Switch sense for odd */ ch = ch | ( a << 7); return(ch); default: return(ch); } } /* C H K 1 -- Compute a type-1 Kermit 6-bit checksum. */ chk1(pkt) char *pkt; { int chk; chk = chk2(pkt); return((((chk & 0300) >> 6) + chk) & 077); } /* C H K 2 -- Compute the numeric sum of all the bytes in the packet. */ chk2(pkt) char *pkt; { unsigned int chk; int p; for (chk = 0; *pkt != '\0'; *pkt++) { p = (parity) ? *pkt & 0177 : *pkt; chk += p; } p = chk; /* return an int because function is int */ return(p); } /* C H K 3 -- Compute a type-3 Kermit block check. */ /* Calculate the 16-bit CRC of a null-terminated string using a byte-oriented tableless algorithm invented by Andy Lowry (Columbia University). The magic number 010201 is derived from the CRC-CCITT polynomial x^16+x^12+x^5+1. Note - this function could be adapted for strings containing imbedded 0's by including a length argument. */ chk3(s) char *s; { unsigned int c, q; LONG crc = 0; while ((c = *s++) != '\0') { if (parity) c &= 0177; q = (crc ^ c) & 017; /* Low-order nibble */ crc = (crc >> 4) ^ (q * 010201); q = (crc ^ (c >> 4)) & 017; /* High order nibble */ crc = (crc >> 4) ^ (q * 010201); } return(crc); } /* Functions for sending various kinds of packets */ ack() { /* Send an ordinary acknowledgment. */ spack('Y',pktnum,0,""); /* No data. */ nxtpkt(&pktnum); /* Increment the packet number. */ } /* Note, only call this once! */ ack1(s) char *s; { /* Send an ACK with data. */ spack('Y',pktnum,strlen(s),s); /* Send the packet. */ nxtpkt(&pktnum); /* Increment the packet number. */ } /* Only call this once! */ nack() { /* Negative acknowledgment. */ spack('N',pktnum,0,""); /* NAK's never have data. */ } resend() { /* Send the old packet again. */ int w; for (w = 0; w < timint - 2; w++) { /* Be extra sure no stuff is */ ttflui(); /* still coming in. */ sleep(1); if (!ttchk() ) ttinc(1); /* be extra sure no stuff in SIII/V */ if (!ttchk() ) break; } if (*sndpkt) ttol(sndpkt,spktl); /* Resend if buffer not empty */ screen(SCR_PT,'%',(long)pktnum,sndpkt); /* Display that resend occurred */ if (pktlog && *sndpkt) zsoutl(ZPFILE,sndpkt); /* Log packet if desired */ } errpkt(reason) char *reason; { /* Send an error packet. */ encstr(reason); spack('E',pktnum,size,data); screen(SCR_TC,0,0l,""); } scmd(t,dat) char t, *dat; { /* Send a packet of the given type */ encstr(dat); /* Encode the command string */ spack(t,pktnum,size,data); } srinit() { /* Send R (GET) packet */ encstr(cmarg); /* Encode the filename. */ spack('R',pktnum,size,data); /* Send the packet. */ } nxtpkt(num) int *num; { prvpkt = *num; /* Save previous */ *num = (*num + 1) % 64; /* Increment packet number mod 64 */ } sigint() { /* Terminal interrupt handler */ errpkt("User typed ^C"); doexit(GOOD_EXIT); /* Exit program */ } /* R P A C K -- Read a Packet */ rpack(l,n,dat) int *l, *n; char *dat; { int i, j, x, done, pstart, pbl; char chk[4], xchk[4], t, type; chk[3] = xchk[3] = 0; i = inlin(); /* Read a line */ if (i != 0) { debug(F101,"rpack: inlin","",i); screen(SCR_PT,'T',(long)pktnum,""); return('T'); } debug(F110,"rpack: inlin ok, recpkt",recpkt,0); /* Look for start of packet */ for (i = 0; ((t = recpkt[i]) != stchr) && (i < RBUFL) ; i++) ; if (++i >= RBUFL) return('Q'); /* Skip rest if not found */ /* now "parse" the packet */ debug(F101,"entering rpack with i","",i); done = 0; while (!done) { debug(F101,"rpack starting at i","",i); pstart = i; /* remember where packet started */ /* length */ if ((t = recpkt[i++]) == stchr) continue; /* Resynch if SOH */ /*** this allows ^A^B to cause exit, comment it out when not debugging ***/ /*** if (t == 2) doexit(0); ***/ if (t == eol) return('Q'); *l = unchar(t); /* Packet length */ debug(F101," pkt len","",*l); /* sequence number */ if ((t = recpkt[i++]) == stchr) continue; if (t == eol) return('Q'); *n = unchar(t); debug(F101,"rpack: n","",*n); /* cont'd... */ /* ...rpack(), cont'd */ /* type */ if ((type = recpkt[i++]) == stchr) continue; if (type == eol) return('Q'); debug(F101,"rpack: type","",type); if ((type == 'S') || (type == 'I')) pbl = 1; /* Heuristics for */ else if (type == 'N') pbl = *l - 2; /* syncing block check type */ else pbl = bctu; *l -= (pbl + 2); /* Now compute data length */ debug(F101,"rpack: bctu","",bctu); debug(F101," pbl","",pbl); debug(F101," data length","",*l); /* data */ dat[0] = '\0'; /* Return null string if no data */ for (j=0; j<*l; i++,j++) if ((dat[j] = recpkt[i]) == stchr) continue; else if (dat[j] == eol) return('Q'); dat[j] = '\0'; /* get the block check */ debug(F110," packet chk",recpkt+i,0); for (j = 0; j < pbl; j++) { chk[j] = recpkt[i]; debug(F101," chk[j]","",chk[j]); if (chk[j] == stchr) break; if (chk[j] == eol) return('Q'); recpkt[i++] = '\0'; } chk[j] = 0; debug(F111," chk array, j",chk,j); if (j != pbl) continue; /* Block check right length? */ done = 1; /* Yes, done. */ } /* cont'd... */ /* ...rpack(), cont'd */ /* Got packet, now check the block check */ switch (pbl) { case 1: xchk[0] = tochar(chk1(&recpkt[pstart])); if (chk[0] != xchk[0]) { if (deblog) { debug(F000,"rpack: chk","",chk[0]); debug(F000," should be ","",xchk[0]); } screen(SCR_PT,'Q',(long)n,recpkt); return('Q'); } break; case 2: x = chk2(&recpkt[pstart]); xchk[0] = tochar((x & 07700) >> 6); xchk[1] = tochar(x & 077); if (deblog) { debug(F000," xchk[0]","=",xchk[0]); debug(F000," xchk[1]","=",xchk[1]); } if ((xchk[0] != chk[0]) || (xchk[1] != chk[1])) { debug(F100," bct2's don't compare","",0); screen(SCR_PT,'Q',(long)n,recpkt); return('Q'); } break; case 3: x = chk3(&recpkt[pstart]); xchk[0] = tochar(( (unsigned)(x & 0170000)) >> 12); xchk[1] = tochar((x & 07700) >> 6); xchk[2] = tochar(x & 077); if (deblog) { debug(F000," xchk[0]","=",xchk[0]); debug(F000," xchk[1]","=",xchk[1]); debug(F000," xchk[2]","=",xchk[2]); } if ((xchk[0] != chk[0]) || (xchk[1] != chk[1]) || (xchk[2] != chk[2])) { debug(F100," bct3's don't compare","",0); screen(SCR_PT,'Q',(long)n,recpkt); return('Q'); } break; } /* Good packet, return its type */ if ( !window) ttflui(); /* Done, flush any remaining. */ screen(SCR_PT,type,(long)(*n),recpkt); /* Update screen */ return((int)type); } /* I N C H R -- Input character from communication line, with timeout */ inchr(timo) int timo; { int c; c = ttinc(timo); debug(F101,"inchr ttinc","",c); if (c < 0) return(c); /* Get a character */ if (parity) c = c & 0177; /* If parity on, discard parity bit. */ debug(F101," after parity","",c); return(c); } /* I N L I N -- Input a line (up to break char) from communication line */ /* Returns 0 on success, nonzero on failure */ inlin() { int i, j, k, maxt; CHAR e; maxt = (speed >= 110) ? (MAXTRY * 9600 / speed) : MAXTRY; debug(F101,"inlin: speed","",speed); debug(F101," maxt","",maxt); e = (turn) ? turnch : eol; i = j = k = 0; if (parity) { while ((j != e) && (i < RBUFL) && (k < maxt)) { j = inchr(1); /* Get char, 1 second timeout */ debug(F101,"inlin inchr","",j); if (j < 0) k++; /* Timed out. */ else { if (j) recpkt[i++] = j; /* Save it */ k = 0; /* Reset timeout counter. */ } } } else { i = ttinl(recpkt,(RBUFL-1),timint,e); /* Get them all at once */ if (i < 1 ) k = 1; } recpkt[i+1] = '\0'; /* Terminate near end of packet */ debug(F111,"inlin",recpkt,i); /* Debug report... */ debug(F101," timeouts","",k); if (i < 1) return(1); /* No characters, return. */ if (pktlog) zsoutl(ZPFILE,recpkt); /* Log any we got, if logging. */ if (k > maxt) return(1); /* If too many tries, give up. */ /* conoll(recpkt); printf(" \n %d %d ",e,eol); */ tlci += i; /* All OK, Count the characters. */ flci += i; return(0); } ################################################################## ## LCKFNS2.ERR Lattice C Compiler (Phase 1) V2.15 Copyright (C) 1982 Lattice, Inc. lckfns2.c 143 Warning 85: function return value mismatch ################################################################## ## LCKFNS3.C /* C K C F N 3 -- System-independent Kermit protocol support functions... */ /* ...Part 3 (continued from lckfns2.c) */ /* Protocol functions for sliding window implementation. */ /* Author: Jan A. van der Eyk, NUS Corp., July 1985. Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* Note -- if you change this file, please amend the version number and date at the top of lckfns.c accordingly. */ /* IMPORTANT: When a window is being closed, i.e, after received an end of file, pktnum should be reset to the received packet number. */ #include "lckerm.h" #include "lckdeb.h" int wndack[64], wndtry[64], wndlow, wndhgh, rpktno; char wndata[64][94]; extern int cxseen, czseen, sndtyp, prvpkt, pktnum, wndsiz, window; extern int pktlog, sldwnd, quiet; extern int putfil(); extern char data[],sndpkt[], sstate; char *strcpy(); /* I N P U T -- Attempt to read packet number 'pktnum'. */ /* This is the function that feeds input to Kermit's finite state machine. If a special start state is in effect, that state is returned as if it were the type of an incoming packet. Otherwise: . If the desired packet arrives within MAXTRY tries, return its type, with its data stored in the global 'data' array. . If the previous packet arrives again, resend the last packet and wait for another to come in. . If the desired packet does not arrive within MAXTRY tries, return indicating that an error packet should be sent. */ input() { int len, num, type; static int numtry; if (!window) numtry = 0; while ( numtry <= MAXTRY ) { if (sstate != 0) { /* If an interrupt routine has set */ type = sstate; /* sstate behind our back, or */ sstate = 0; /* if a start state is in effect, */ *data = '\0'; /* nulify start state and return it */ numtry = 0; /* like a packet type */ return(type); } num = -1; type = rpack(&len,&num,data); /* Try to read a packet. */ chkint(); /* Look for interruptions. */ if ( window ) { rpktno = num; /* Set the packet num just received */ if ( type == 'T') { /* Timeout for window, set number */ type = 'N'; /* to most desirable and set type=N */ rpktno = wndesr(); } if ( type == 'Q' || type == 'N') { /* Bad checksum or NACK */ if ( type == 'N' ) numtry++; /* NACK increment retry */ type = 'N'; /* We either want to send a NACK or */ } /* treat it like we received a NACK */ else numtry = 0; return(type); } else { /* Not in window state */ /* If it's the same packet we just sent, it's an echo. Read another. */ if (type == sndtyp) type = rpack(&len,&num,data); /* If previous packet again, a timeout pseudopacket, or a bad packet, try again. */ if ( type == 'E') return(type); if (num != pktnum || type == 'T' || type == 'Q' || type == 'N') { numtry++; resend(); /* send last packet again, */ } else { numtry = 0; rpktno = num; return(type); } /* Success, return packet type. */ } } /* Too many tries, give up, and send a timeout error packet */ errpkt("Other side timed out."); strcpy(data,"Timed out."); return('E'); } /* G W D A T A -- Receive data in a sliding window */ gwdata() { int wndtop; wndtop = (wndlow + 2 * (wndsiz) -1 ) % 64; /* Maximum receive window */ if (wndtop == wndlow ) wndtop = ( wndtop + 1) % 64; if ( ckintv(&rpktno,&wndlow,&wndhgh) ) { pktnum = rpktno; /* Packet inside send */ wndack[rpktno] = 1; /* window, ACK it and mark */ wndtry[rpktno] = 0; /* as such */ ack(); strcpy(wndata[rpktno],data); /* Store the packet */ /* ============================================================================ /* Check to see if we are filling window, if so test for skipped packages */ if ( ckintv(&pktexp,&wndlow,&wndhgh)) { for (i = pktexp; i != rpktno; i = ( i + 1) % 64 ) { if ( wndack[i] || wndtry[i] ) break; pktnum = i; /* See if we lost some */ nack(); /* if so, NACK it */ } pktexp = (pktexp + 1) % 64; } =========================================================================== */ } else if ( ckintv(&rpktno,&wndhgh,&wndtop) ) { pktnum = rpktno; /* Received is greater then */ ack(); /* send window. */ strcpy(wndata[rpktno],data); /* Store the packet */ wndack[rpktno] = 1; /* mark as ACK and */ while ( 1 ) { /* Slide the window */ if ( wndack[wndlow] != 1 ) return(0); /* Protocol error */ decode(wndata[wndlow],putfil); /* Decode and store low */ wndack[wndlow] = 0; /* packet & clear ackflg */ wndlow = (wndlow + 1) % 64; /* Up lower bound */ wndhgh = (wndhgh + 1) % 64; /* Up higher bound */ if ( wndhgh == rpktno ) break; /* End of sliding */ pktnum = wndhgh; /* Nack any packets that */ nack(); /* have been lost */ wndack[pktnum] = 0; wndtry[pktnum] = 1; } } /* Anything else ignore */ return(1); } /* R W E O F -- Received EOF in sliding window, write the window to disk */ rweof() { /* Received EOF */ /* Write ACKed packages */ while ( wndack[wndlow] ) { decode(wndata[wndlow],putfil); /* Decode and store low packet*/ wndack[wndlow] = 0; /* clear ackflg */ wndlow = (wndlow + 1) % 64; /* Up lower bound */ } } /* N A C K D P -- Bad data packet in window, try to NACK it. */ /* Returns 0, if timeout */ nackdp() { int wndtop; /* Packets with BAD checksum or timeout, NACK the appropiate one */ wndtop = ( wndhgh + 1 ) % 64; /* Highest we are allowed to Nack */ if ( ckintv(&rpktno,&wndlow,&wndtop) ) { /* Packet inside window, */ if ( wndack[rpktno] ) { /* already ACKed */ pktnum = wndesr(); /* NACK, desirable one */ } else { /* else, NACK received packet */ pktnum = rpktno; /* Up retry limit & test */ if ( wndtry[rpktno]++ > MAXTRY ) return(0); } } else { pktnum = wndesr(); /* Get most desirable packet */ } nack(); /* NACK pktnum */ return(1); /* Succesfully NACKed */ } /* S D A T A W -- Send the next data packet in sliding window */ /* Return 0 if EOF */ sdataw() { /* received an ACK to a data package */ /* ACK inside window, mark it as ACKed */ if ( ckintv(&rpktno,&wndlow,&pktnum) ) wndack[rpktno] = 1; while ( wndack[wndlow] ) { /* Slide window in send table */ wndtry[wndlow] = 0; wndack[wndlow] = 0; wndlow = (wndlow + 1) % 64; wndhgh = (wndhgh + 1) % 64; } while (1) { if ( cxseen || czseen ) return(0); /* Aborted */ else if ( pktnum == wndhgh ) return(1); /* Window is full */ else if ( !sdata()) { /* End of file */ if ( wndtry[wndlow] == 0 ) window = 0; /* Window is empty */ return(0); } strcpy(wndata[pktnum],sndpkt); /* Store data in */ wndack[pktnum] = 0; /* window */ wndtry[pktnum] = 1; if ( ttsome() ) return(1); /* Some waiting */ } } /* W R E S N D -- Resend the requested data packet from the window */ /* Returns 0 if timeout */ wresnd() { /* resend data packet rpktno */ /* NACK inside window */ if ( ckintv(&rpktno,&wndlow,&pktnum) ) { if ( wndtry[rpktno] != 0 ) { /* Did we ever send it */ if ( wndtry[rpktno]++ > MAXTRY ) return(0); /* Up & test retry */ ttol(wndata[rpktno],strlen(wndata[rpktno])); /* Resend it */ /* Display that resend occurred */ screen(SCR_PT,'%',(long)rpktno,wndata[rpktno]); /* Log packet if desired */ if (pktlog && *sndpkt) zsoutl(ZPFILE,wndata[rpktno]); } } /* Keep on sending data packets if we didn't receive something and the window is not filled */ while (1) { if ( ttsome() || pktnum == wndhgh ) return(1); if ( !sdata()) return(1); /* End of file */ strcpy(wndata[pktnum],sndpkt); /* Store data in */ wndack[pktnum] = 0; /* window */ wndtry[pktnum] = 1; } } /* W E O F -- Receive ACK to data package, while there is no more data */ /* to send, return 1 if all packets have been ACKed */ weof() { /* received an ACK to a data package */ /* ACK inside window */ if ( ckintv(&rpktno,&wndlow,&wndhgh) ) wndack[rpktno] = 1; while ( wndack[wndlow] ) { if ( wndlow == pktnum ) return(1); /* All packets ACKed ? */ wndack[wndlow] = 0; /* No, slide low end of */ wndlow = (wndlow + 1) % 64; /* window */ } return(0); } /* W D I N I T initialize windowing variables */ /* returns 1 if windows are requested */ wdinit() { int i; if ( !sldwnd || wndsiz == 0) return(0); window = 1; for (i = 0; i < 64; i++ ) { wndack[i] = 0; wndtry[i] = 0; wndata[i][0] = '\0'; } wndlow = pktnum; wndhgh = (pktnum + wndsiz - 1 ) % 64; return(1); } /* W N D E S R returns most desirable packet */ int wndesr() { int i; i = wndlow; while (1) { if ( !wndack[i] ) return(i); if ( i == wndhgh) break; i = ( i + 1 ) % 64; } i = ( i + 1 ) % 64; return ( i ); } /* C K I N T V -- check to see if a value is within an interval */ /* Return 1 if within interval */ /* a is reference value */ /* b = lower bound of interval ( b >= 0 ) */ /* c = higher bound of interval ( c >= 0 ) */ int ckintv(a,b,c) int *a, *b, *c; { if ( *a < 0 || *a > 63 ) return(0); else if ( *b > *c ) { /* Split interval */ if ( *a > *c && *a < *b ) return(0); /*|=======c-------b=======| */ else return(1); /*<-- a --> <-- a --> */ } else { /* Continuous interval */ if ( *a < *b || *a > *c ) return(0); /*|-------b=======c-------| */ else return(1); /* <-- a --> */ } } /* W N D E R R -- Abort while in windowing state */ /* Print error messages d */ wnderr(d) char *d; { int x; ermsg(d); /* Issue message */ errpkt(d); /* Send the other side the message */ x = quiet; quiet = 1; cxseen = 1; /* We aborted */ clsif(); clsof(); /* Close files and window */ quiet = x; } ################################################################## ## LCKFNS3.ERR Lattice C Compiler (Phase 1) V2.15 Copyright (C) 1982 Lattice, Inc. ################################################################## ## LCKLINK.C char *versio = "PC-DOS C-Kermit, file transfer module, 4LC(001) 27 July 85.\n\ Jan A. van der Eijk, NUS Corporation, 26 June 85."; /* C K C L I N K -- Main driver program for linking to user program */ /* Authors: Frank da Cruz, Bill Catchings, Jeff Damens; Columbia University Center for Computing Activities, 1984-85. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* The Kermit file transfer protocol was developed at Columbia University. It is named after Kermit the Frog, star of the television series THE MUPPET SHOW; the name is used by permission of Henson Associates, Inc. "Kermit" is also Celtic for "free". */ /* Thanks to Herm Fischer of Encino, CA, for extensive contributions to version 4, and to the following people for their contributions over the years: Larry Afrin, Clemson U Charles Brooks, EDN Bob Cattani & Chris Maio, Columbia CS Dept Alan Crosswell, CUCCA Carl Fongheiser, CWRU Yekta Gursel, MIT Jim Guyton, Rand Corp Stan Hanks, Rice U. Ken Harrenstein, SRI Steve Hemminger, Tektronix Randy Huntziger, NLM Martin Minow, DEC Tony Movshon, NYU Ken Poulton, HP Labs Frank Prindle, NADC Stew Rubenstein, Harvard Dan Schullman, DEC Bradley Smith, UCLA Dave Tweten, AMES-NAS Walter Underwood, Ford Aerospace Pieter Van Der Linden, Centre Mondial (Paris) Mark Vasoll & Gregg Wonderly, Oklahoma State University Lauren Weinstein, Vortex and many others. */ #include "lckerm.h" #include "lckdeb.h" #include "asiports.h" /* JAV, NUS use for Greenleaf COM libs */ #include "stdios.h" /* JAV, NUS special Greenleaf and Lattice header * /* Declarations for Send-Init Parameters */ int spsiz = DSPSIZ, /* Biggest packet size we can send */ rpsiz = DRPSIZ, /* Biggest we want to receive */ timint = DMYTIM, /* Timeout interval I use */ rtimo = URTIME, /* Timeout I want you to use */ timef = 0, /* Flag to override what you ask */ npad = MYPADN, /* How much padding to send */ mypadn = MYPADN, /* How much padding to ask for */ chklen = 1, /* Length of block check */ bctr = 3, /* Block check type requested */ bctu = 1, /* Block check type used */ ebq = MYEBQ, /* 8th bit prefix */ ebqflg = 0, /* 8th-bit quoting flag */ rpt = 0, /* Repeat count */ rptq = MYRPTQ, /* Repeat prefix */ rptflg = 0, /* Repeat processing flag */ capas = MYCAPA; /* Capabilities */ char padch = MYPADC, /* Padding character to send */ mypadc = MYPADC, /* Padding character to ask for */ seol = MYEOL, /* End-Of-Line character to send */ eol = MYEOL, /* End-Of-Line character to look for */ ctlq = CTLQ, /* Control prefix in incoming data */ myctlq = CTLQ; /* Outbound control character prefix */ wndmax = 31; /* Maximum window size for table */ wndsiz = 31; /* Window size I want */ /* Packet-related variables */ int pktnum = 0, /* Current packet number */ prvpkt = -1, /* Previous packet number */ sndtyp, /* Type of packet just sent */ size, /* Current size of output pkt data */ osize, /* Previous output packet data size */ maxsize, /* Max size for building data field */ spktl; /* Length packet being sent */ char sndpkt[MAXPACK*2], /* Entire packet being sent */ recpkt[RBUFL+2], /* Packet most recently received */ data[MAXPACK+4], /* Packet data buffer */ srvcmd[MAXPACK*2], /* Where to decode server command */ *srvptr, /* Pointer to above */ mystch = SOH, /* Outbound packet-start character */ stchr = SOH; /* Incoming packet-start character */ /* File-related variables */ char filnam[50]; /* Name of current file. */ char fildat[20]; /* File creation date */ int nfils; /* Number of files in file group */ long fsize; /* Size of current file */ /* Communication line variables */ char ttname[50]; /* Name of communication line. */ int parity, /* Parity specified, 0,'e','o',etc */ flow, /* Flow control, 1 = xon/xoff */ speed = 1200, /* Line speed */ turn = 0, /* Line turnaround handshake flag */ turnch = XON, /* Line turnaround character */ duplex = 0, /* Duplex, full by default */ escape = 034, /* Escape character for connect */ delay = DDELAY, /* Initial delay before sending */ cdetect = FALSE, /* Carrier detect not required */ mdmtyp = 0; /* Modem type (initially none) */ /* Statistics variables */ long filcnt, /* Number of files in transaction */ flci, /* Characters from line, current file */ flco, /* Chars to line, current file */ tlci, /* Chars from line in transaction */ tlco, /* Chars to line in transaction */ ffc, /* Chars to/from current file */ tfc; /* Chars to/from files in transaction */ /* Flags */ int deblog = 0, /* Flag for debug logging */ pktlog = 0, /* Flag for packet logging */ seslog = 0, /* Session logging */ tralog = 0, /* Transaction logging */ displa = 0, /* File transfer display on/off */ stdouf = 0, /* Flag for output to stdout */ xflg = 0, /* Flag for X instead of F packet */ hcflg = 0, /* Doing Host command */ fncnv = 1, /* Flag for file name conversion */ binary = 1, /* Flag for binary file */ warn = 1, /* Flag for file warning */ quiet = 0, /* Be quiet during file transfer */ local = 0, /* Flag for external tty vs stdout */ server = 0, /* Flag for being a server */ cnflg = 0, /* Connect after transaction */ cxseen = 0, /* Flag for cancelling a file */ czseen = 0; /* Flag for cancelling file group */ filatr = 0; /* Flag for sending file attributes */ nxtcas = 1; /* Flag for sending next attribute */ capflg = 0; /* Which capas are supported */ sldwnd = 0; /* Flag for sliding window support */ window = 0; /* Flag for windowing state */ /* Variables passed from command parser to protocol module */ char parser(); /* The parser itself */ char sstate = 0; /* Starting state for automaton */ char *cmarg = ""; /* Pointer to command data */ char *cmarg2 = ""; /* Pointer to 2nd command data */ char **cmlist; /* Pointer to file list in argv */ /* Miscellaneous */ char **xargv; /* Global copies of argv */ int xargc; /* and argc */ extern char *dftty; /* Default tty name from ckx???.c */ extern int dfloc; /* Default location: remote/local */ extern int dfprty; /* Default parity */ extern int dfflow; /* Default flow control */ /* K L I N K -- C-Kermit main program */ klink() { char *strcpy(); /* Do some initialization */ sstate = 0; /* No default start state. */ strcpy(ttname,dftty); /* Set up default tty name. */ local = dfloc; /* And whether it's local or remote. */ parity = dfprty; /* Set initial parity, */ flow = dfflow; /* and flow control. */ sstate = kinit(); /* Setup and intialize */ if (sstate) { proto(); /* Take any requested action */ doexit(GOOD_EXIT); /* and then exit with status 0. */ } } /* K I N I T -- routine to initialize variable if kermit is linked to other programs, returns action to take */ char kinit() { cmarg = ""; /* Initialize. */ cmarg2 = ""; action = cflg = 0; strcpy(ttname,???????) /* com port name COM1 or COM2 */ z = ??????? /* set baud rate */ if (chkspd(z) > -1) speed = z; /* Check it */ else fatal("unsupported baud rate"); cdetect = ???? /* CD required 0 or 1 */ binary = ???? /* set filetype 0 or 1 */ warn = ????? /* file overwrite 0 or 1 */ quiet = ????? /* be quit 0 or 1 */ parity = ?????? /* set parity e, m, n, s, or o */ debopn("debug.log"); /* To open debug log */ /* Only valid if compiled with */ /* DEBUG 1 */ z = ???????? /* set window size */ if ( z > MYWND || z < 0 ) /* Check it */ fatal("invalid window size"); else wndmax = z; duplex = ???????? /* Set duplex 0 or 1 */ if ( duplex ) turn = 1; /* Line turnaround handshake */ turnch = XON; /* XON is turnaround character */ duplex = 1; /* Half duplex */ flow = 0; /* No flow control */ wndmax = 0; /* No windowing for half duplex */ } /* If receiving a file */ action = 'v'; cmarg2 = ?????????; /* Optional filename */ /* Else if sending a file */ action = 's'; /* if sending multiple files */ nfils = ?? /* Initialize file counter,to */ /* number of file in list */ cmlist = ???????? /* point cmlist to list of files */ /* else if sending wild card name */ nfils = -1; /* Incase protocol has to expand */ cmarg = ?????; /* wildcards, point cmarg */ /* to variable containing wildcard */ /* else if sending one file as another file */ nfils = 1; cmlist = ??????; /* pointer to filename to send */ cmarg2 = ??????; /* pointer to filename to send as */ return(action); ################################################################## ## LCKMAIN.C char *versio = "PC-DOS C-Kermit, file transfer module, 4LC(001) 27 July 85.\n\ Jan A. van der Eijk, NUS Corporation, 26 June 85."; /* C K C M A I -- C-Kermit Main program */ /* Authors: Frank da Cruz, Bill Catchings, Jeff Damens; Columbia University Center for Computing Activities, 1984-85. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* The Kermit file transfer protocol was developed at Columbia University. It is named after Kermit the Frog, star of the television series THE MUPPET SHOW; the name is used by permission of Henson Associates, Inc. "Kermit" is also Celtic for "free". */ /* Thanks to Herm Fischer of Encino, CA, for extensive contributions to version 4, and to the following people for their contributions over the years: Larry Afrin, Clemson U Charles Brooks, EDN Bob Cattani & Chris Maio, Columbia CS Dept Alan Crosswell, CUCCA Carl Fongheiser, CWRU Yekta Gursel, MIT Jim Guyton, Rand Corp Stan Hanks, Rice U. Ken Harrenstein, SRI Steve Hemminger, Tektronix Randy Huntziger, NLM Martin Minow, DEC Tony Movshon, NYU Ken Poulton, HP Labs Frank Prindle, NADC Stew Rubenstein, Harvard Dan Schullman, DEC Bradley Smith, UCLA Dave Tweten, AMES-NAS Walter Underwood, Ford Aerospace Pieter Van Der Linden, Centre Mondial (Paris) Mark Vasoll & Gregg Wonderly, Oklahoma State University Lauren Weinstein, Vortex and many others. */ #include "lckerm.h" #include "lckdeb.h" #include "asiports.h" /* JAV, NUS use for Greenleaf COM libs */ #include "stdios.h" /* JAV, NUS special Greenleaf and Lattice header * /* Declarations for Send-Init Parameters */ int spsiz = DSPSIZ, /* Biggest packet size we can send */ rpsiz = DRPSIZ, /* Biggest we want to receive */ timint = DMYTIM, /* Timeout interval I use */ rtimo = URTIME, /* Timeout I want you to use */ timef = 0, /* Flag to override what you ask */ npad = MYPADN, /* How much padding to send */ mypadn = MYPADN, /* How much padding to ask for */ chklen = 1, /* Length of block check */ bctr = 3, /* Block check type requested */ bctu = 1, /* Block check type used */ ebq = MYEBQ, /* 8th bit prefix */ ebqflg = 0, /* 8th-bit quoting flag */ rpt = 0, /* Repeat count */ rptq = MYRPTQ, /* Repeat prefix */ rptflg = 0, /* Repeat processing flag */ capas = MYCAPA; /* Capabilities */ char padch = MYPADC, /* Padding character to send */ mypadc = MYPADC, /* Padding character to ask for */ seol = MYEOL, /* End-Of-Line character to send */ eol = MYEOL, /* End-Of-Line character to look for */ ctlq = CTLQ, /* Control prefix in incoming data */ myctlq = CTLQ; /* Outbound control character prefix */ wndmax = 31; /* Maximum window size for table */ wndsiz = 31; /* Window size I want */ /* Packet-related variables */ int pktnum = 0, /* Current packet number */ prvpkt = -1, /* Previous packet number */ sndtyp, /* Type of packet just sent */ size, /* Current size of output pkt data */ osize, /* Previous output packet data size */ maxsize, /* Max size for building data field */ spktl; /* Length packet being sent */ char sndpkt[MAXPACK*2], /* Entire packet being sent */ recpkt[RBUFL+2], /* Packet most recently received */ data[MAXPACK+4], /* Packet data buffer */ srvcmd[MAXPACK*2], /* Where to decode server command */ *srvptr, /* Pointer to above */ mystch = SOH, /* Outbound packet-start character */ stchr = SOH; /* Incoming packet-start character */ /* File-related variables */ char filnam[50]; /* Name of current file. */ char fildat[20]; /* File creation date */ int nfils; /* Number of files in file group */ long fsize; /* Size of current file */ /* Communication line variables */ char ttname[50]; /* Name of communication line. */ int parity, /* Parity specified, 0,'e','o',etc */ flow, /* Flow control, 1 = xon/xoff */ speed = 1200, /* Line speed */ turn = 0, /* Line turnaround handshake flag */ turnch = XON, /* Line turnaround character */ duplex = 0, /* Duplex, full by default */ escape = 034, /* Escape character for connect */ delay = DDELAY, /* Initial delay before sending */ cdetect = FALSE, /* Carrier detect not required */ mdmtyp = 0; /* Modem type (initially none) */ /* Statistics variables */ long filcnt, /* Number of files in transaction */ flci, /* Characters from line, current file */ flco, /* Chars to line, current file */ tlci, /* Chars from line in transaction */ tlco, /* Chars to line in transaction */ ffc, /* Chars to/from current file */ tfc; /* Chars to/from files in transaction */ /* Flags */ int deblog = 0, /* Flag for debug logging */ pktlog = 0, /* Flag for packet logging */ seslog = 0, /* Session logging */ tralog = 0, /* Transaction logging */ displa = 0, /* File transfer display on/off */ stdouf = 0, /* Flag for output to stdout */ xflg = 0, /* Flag for X instead of F packet */ hcflg = 0, /* Doing Host command */ fncnv = 1, /* Flag for file name conversion */ binary = 1, /* Flag for binary file */ warn = 1, /* Flag for file warning */ quiet = 0, /* Be quiet during file transfer */ local = 0, /* Flag for external tty vs stdout */ server = 0, /* Flag for being a server */ cnflg = 0, /* Connect after transaction */ cxseen = 0, /* Flag for cancelling a file */ czseen = 0; /* Flag for cancelling file group */ filatr = 0; /* Flag for sending file attributes */ nxtcas = 1; /* Flag for sending next attribute */ capflg = 0; /* Which capas are supported */ sldwnd = 0; /* Flag for sliding window support */ window = 0; /* Flag for windowing state */ /* Variables passed from command parser to protocol module */ char parser(); /* The parser itself */ char sstate = 0; /* Starting state for automaton */ char *cmarg = ""; /* Pointer to command data */ char *cmarg2 = ""; /* Pointer to 2nd command data */ char **cmlist; /* Pointer to file list in argv */ /* Miscellaneous */ char **xargv; /* Global copies of argv */ int xargc; /* and argc */ extern char *dftty; /* Default tty name from ckx???.c */ extern int dfloc; /* Default location: remote/local */ extern int dfprty; /* Default parity */ extern int dfflow; /* Default flow control */ /* M A I N -- C-Kermit main program */ main(argc,argv) int argc; char **argv; { char *strcpy(); char *ptr; /* Do some initialization */ xargc = argc; /* Make global copies of argc */ xargv = argv; /* ...and argv. */ while (--xargc > 0) { /* Go through command line words */ xargv++; /* and low case it all */ ptr = *xargv; for ( ; *ptr != '\0';*ptr++) { *ptr = tolower(*ptr); } } xargc = argc; xargv = argv; sstate = 0; /* No default start state. */ strcpy(ttname,dftty); /* Set up default tty name. */ local = dfloc; /* And whether it's local or remote. */ flow = dfflow; /* and flow control. */ /* Look for a UNIX-style command line... */ if (argc > 1) { /* Command line arguments? */ sstate = cmdlin(); /* Yes, parse. */ if (sstate) { proto(); /* Take any requested action */ doexit(GOOD_EXIT); /* and then exit with status 0. */ } } else { usage(); } } ################################################################## ## LCKMAIN.DOC Bill and Lloyd- Here are documenation files recieved from Jan about PCKERMIT. This is therefore a long letter. You don't want to read it, just save it to disk. I wrote Bill a separate letter explaining these files a little more. This is about 10 pages material. LCKTIO.DOC: /* L C K T I O module */ C O N O C -- Output a character to the console terminal conoc(c) char c = character to print C O N X O -- Write x characters to the console terminal conxo(x,s) char *s = string to print int x = number of characters to print C O N O L -- Write a line to the console terminal conol(s) char *s line to print C O N O L A -- Write an array of lines to the console terminal conola(s) char *s[] = array to print C O N O L L -- Output a string followed by CRLF conoll(s) char *s = string to print C O N C H K -- Check to see if user did hit keyboard Return 1 if keyboard has been hit conchk() C O N I N C -- Get a character from the console, wait for timo seconds returns -1 if no keyboard input coninc(timo) int timo = timeout in seconds T T O P E N -- Open a Comport, returns 0 on success, -1 on failure. sets ttyfd to 0 if COM1 or to 1 if COM2 ttopen(ttname,lcl,modem) char *ttname = name of comport ("COM1" or "COM2") int lcl ( not used , set to zero ) int modem ( not used , dummy argument) T T C L O S -- Close the TTY , set ttyfd to 0 ttclos() T T O L -- Similar to "ttinl", but for writing. returns number of characters writen to Com port ttol(s,n) int n = number of characters to send char *s = string to send T T O C -- Output a character to the communication line Returns -1 if an error occured ttoc(c) char c = character to write T T I N C -- Read a character from the communication line return the character if possible otherwise -1 timout in timo seconds ttinc(timo) int timo = timout period T T I N L -- Read a record (up to break character) from comm line. If no break character encountered within "max", return "max" characters, with disposition of any remaining characters undefined. Otherwise, return the characters that were read, including the break character, in "dest" and the number of characters read as the value of function, or 0 upon end of file, or -1 if an error occurred. Times out & returns error if not completed within "timo" sconds. ttinl(dest,maxnum,timo,eol) int maxnum = maximum number of char to read int timo = timout period int eol = break character char *dest = destination string TTPKT -- Condition communication line for packect mode ttpkt (speed,flow) int speed = baud rate int flow = flow control used 0 = None, 1 = XON/XOFF TTVT -- Condition communication line for use as virtual terminal Returns -1 if Error */ ttvt (speed,flow) int speed = baud rate int flow = flow control used extern int parity = parity to be used (e, o, m, s, n) T T S S P D -- check for valid baud rates return the baud rate if valid otherwise -1 ttsspd(speed) int speed = baud rate TTFLUI -- Flush tty input buffer ttflui() TTFLUO -- Flush tty ouput buffer ttfluo() T T I N -- read one character for tty input buffer return the character if available otherwise -1 ttin() T T C H K -- check if character available in receive buffer */ ttchk() { T T S O M E -- Return TRUE if receive buffer has character in it. int ttsome() T T F L O W -- Checks for XOFF,if so waits for XON, timeout after 5 sec. ttflow() C A R R I E R -- Check for existance of modem carrier signal Returns: 1 if carrier present; else returns 0 int carrier() extern int cdetect = if set will return 1 S L E E P -- Wait for m seconds sleep(m) int m = number of seconds to sleep T I C K S -- Returns total number of clock ticks since midnight */ long int ticks() T O T S E C -- Returns time since midnight in seconds long int totsec() T O O L O N G -- Timeout for user input with tout in seconds */ toolong(tout) int tout = time out period extern long int strtim = starting time tor tout Z T I M E -- Return date/time string ztime(s) char **s = pointer to string containing date and time LCKFIO.DOC: L C K F I O -- File I/O module Z O P E N I -- Open an existing file for input. Return 1 if successful zopeni(n,name) int n = file number to use char *name = name of file to open Z O P E N O -- Open a new file for output. Return 1 if successful zopeno(n,name) int n = file number to use char *name = name of file to open Z C L O S E -- Close the given file. Return 1 if successful zclose(n) int n = number of file to close Z C H I N -- Get a character from the input file. Returns -1 if EOF, 0 otherwise. zchin(n,c) int n = number of file to read char *c = character read Z S O U T -- Write a string to the given file, buffered. Returns -1 if ERROR, 0 otherwise zsout(n,s) int n = number of file to write to char *s = character string to write Z S O U T L -- Write string to file, with line terminator, buffered Returns -1 if ERROR, 0 otherwise zsoutl(n,s) int n = number of file to write to char *s = character string to write Z S O U T X -- Write x characters to file, unbuffered. Returns -1 if ERROR, 0 otherwise zsoutx(n,s,x) int n = number of file to write to int x = number of character to write char *s = character string to write Z C H O U T -- Add a character to the given file. Returns -1 if ERROR, 0 otherwise zchout(n,c) int n = number of file to write to char c = character to write C H K F N -- Internal function to verify file number is ok Returns: -1 = File number n is out of range 0 = n is in range, but file is not open 1 = n in range and file is open chkfn(n) int n = file number to check Z C H K I -- Check if input file exists and is readable Returns: >= 0 if the file can be read (returns the size). -1 if file doesn't exist or can't be accessed, -2 if file exists but is not readable . -3 if file exists but protected against read. long zchki(name) char *name = name of file to check Z C H K O -- Check if output file can be created . Returns -1 if write permission for the file would be denied, 0 otherwise. zchko(name) char *name = name of file to check Z D E L E T -- Delete the named file. zdelet(name) char *name = name of file to delete Z R T O L -- Convert remote filename into local form For DOS, this means changing lowercase letters to uppercase. zrtol(name,name2) char *name = file name to be converted char *name2 = converted file name Z L T O R -- Convert filename from local format to common form. Strip pathnames, directory names and uppercase. zltor(name,name2) char *name = file name to be converted char *name2 = converted file name Z N E X T -- Get name of next file from list created by zxpand(). Returns >0 if there's another file or 0 if no more files. znext(fn) char *fn = filename Z N E W N -- Make a new name for the given file znewn(fn,s) char *fn = filename to be converted char **s = pointer to converted file name Z X P A N D -- Expand a wildcard string into an array of strings Returns the number of files that match fn1, with data structures set up so that first file (if any) will be returned by the next znext() call. zxpand(fn) char *fn = filename to be expanded Z N E X T -- Get name of next file from list created by zxpand(). Returns >0 if there's another file or 0 if no more files. znext(fn) char *fn = filename Z F C D A T -- Return file creation date/time zfcdat(fname,str) char *fname = filename char *str = string with date and time Z F R E E -- Return total number of free bytes on drive specified long zfree(drive) char *drive = drive name to check Z F P D A T -- Stamp a given file name with the given date zfpdat(fname,dattim) char *fname = name of file to stamp cahr *dattim = date and time to stamp LCKUSR.DOC: C K U U S R -- "User Interface" for PC-DOS Kermit C M D L I N -- Get arguments from command line cmdlin() { D O A R G -- Do a command-line argument. */ doarg(x) char x = character on command line to be evaluated U S A G E -- Print help message , how to use usage() F A T A L -- Print error message and exit to dos through doexit() fatal(msg) char *msg = message to print D O E X I T -- Close files, turn of interrupt and exit from the program doexit(exitstat) int exitstat = type of exit to pass to exit(). B L D L E N -- Make length-encoded copy of string */ char *bldlen(str,dest) char *str = string to copy char *dest = destination string D E B O P N -- Open a debugging file */ debopn(s) char *s = name of debug file C H K S P D -- Check if argument is a valid baud rate */ chkspd(x) int x = baud rate to check I N T M S G -- Issue message about terminal interrupts during file transfer if not quiet intmsg(n) long n = if 1 print message else print ignored C H K I N T -- Check for console interrupts during file transfer and execute them if any. Ignored if quiet = TRUE chkint() D E B U G -- Enter a record in the debugging log debug(f,s1,s2,n) Call with a format, two strings, and a number: int f - Format, a bit string in range 0-7. If bit x is on, then argument number x is printed. char *s1 - String, argument number 1. Printed as is. char *s2 - String, argument number 2. Printed in brackets. int n - Int, argument 3. Printed preceded by equals sign. f=0 is special: print s1,s2, and interpret n as a char. T L O G -- Log a record in the transaction file tlog(f,s1,s2,n) Call with a format and 3 arguments: two strings and a number: int f - Format, a bit string in range 0-7, bit x is on, arg #x is printed. char *s1,s2 - String arguments 1 and 2. long n - Int, argument 3. E R M S G -- Print an error message on file stderr ermsg(msg) char *msg = message to print P E R R O R -- Print a error message and associated errno perror(s) char *s = message to print S C R E E N -- Screen display function screen(f,c,n,s) int f - argument descriptor (format to use) int c - a character or small integer long n - a long integer (used for packet number) char *s - a string to print. The possible values of f currently accepted are defined as SCR_??? in the lckerm.h header file LCKMAIN.DOC: L C K C M A I M -- C-Kermit Main program Declarations for Send-Init Parameters int spsiz = DSPSIZ ---- Biggest packet size we can send int rpsiz = DRPSIZ ---- Biggest we want to receive int timint = DMYTIM ---- Timeout interval I use int rtimo = URTIME ---- Timeout I want you to use int timef = 0 ---- Flag to override what you ask int npad = MYPADN ---- How much padding to send int mypadn = MYPADN ---- How much padding to ask for int chklen = 1 ---- Length of block check int bctr = 3 ---- Block check type requested int bctu = 1 ---- Block check type used int ebq = MYEBQ ---- 8th bit prefix int ebqflg = 0 ---- 8th-bit quoting flag int rpt = 0 ---- Repeat count int rptq = MYRPTQ ---- Repeat prefix int rptflg = 0 ---- Repeat processing flag int capas = MYCAPA --- Capabilities char padch = MYPADC ---- Padding character to send char mypadc = MYPADC ---- Padding character to ask for char seol = MYEOL ---- End-Of-Line character to send char eol = MYEOL ---- End-Of-Line character to look for char ctlq = CTLQ ---- Control prefix in incoming data char myctlq = CTLQ ---- Outbound control character prefix char wndmax = 31 ---- Maximum window size for table char wndsiz = 31 ----- Window size I want Packet-related variables int pktnum = 0 ---- Current packet number int prvpkt = -1 ---- Previous packet number int sndtyp ---- Type of packet just sent int size ---- Current size of output pkt data int osize ---- Previous output packet data size int maxsize ---- Max size for building data field int spktl; Length packet being sent char sndpkt[MAXPACK*2] ---- Entire packet being sent char recpkt[RBUFL+2] ---- Packet most recently received char data[MAXPACK+4] ---- Packet data buffer char srvcmd[MAXPACK*2] ---- Where to decode server command char *srvptr ---- Pointer to above char mystch = SOH ---- Outbound packet-start character char stchr = SOH ---- Incoming packet-start character Communication line variables char ttname[50] ----- Name of communication line. int parity ---- Parity specified, 0,'e','o',etc int flow ---- Flow control, 1 = xon/xoff int speed = 1200 ---- Line speed int turn = 0 ---- Line turnaround handshake flag int turnch = XON ---- Line turnaround character int duplex = 0 ---- Duplex, full by default int escape = 034 ---- Escape character for connect int delay = DDELAY ---- Initial delay before sending int cdetect = FALSE ---- Carrier detect not required int mdmtyp = 0 ----- Modem type (initially none) not used File-related variables char filnam[50] ----- Name of current file. char fildat[20] ----- File creation date int nfils ----- Number of files in file group long fsize ----- Size of current file Statistics variables long filcnt ---- Number of files in transaction long flci ---- Characters from line, current file long flco ---- Chars to line, current file long tlci ---- Chars from line in transaction long tlco ---- Chars to line in transaction long ffc ---- Chars to/from current file long tfc ----- Chars to/from files in transaction Flags int deblog = 0 ---- Flag for debug logging int pktlog = 0 ---- Flag for packet logging int seslog = 0 ---- Session logging int tralog = 0 ---- Transaction logging int displa = 0 ---- File transfer display on/off int stdouf = 0 ---- Flag for output to stdout int xflg = 0 ---- Flag for X instead of F packet int hcflg = 0 ---- Doing Host command int fncnv = 1 ---- Flag for file name conversion int binary = 1 ---- Flag for binary file int warn = 1 ---- Flag for file warning int quiet = 0 ---- Be quiet during file transfer int local = 0 ---- Flag for external tty vs stdout int server = 0 ---- Flag for being a server int cnflg = 0 ---- Connect after transaction int cxseen = 0 ---- Flag for cancelling a file int czseen = 0 ---- Flag for cancelling file group int filatr = 0 ---- Flag for sending file attributes int nxtcas = 1 ---- Flag for sending next attribute int capflg = 0 ---- Which capas are supported int sldwnd = 0 ---- Flag for sliding window support int window = 0 ---- Flag for windowing state Variables passed from command parser to protocol module char parser() ----- The parser itself char sstate = 0 ------ Starting state for automaton char *cmarg = "" ----- Pointer to command data char *cmarg2 = "" ------ Pointer to 2nd command data char **cmlist -------- Pointer to file list in argv char **xargv ------ Global copies of argv int xargc ------ and argc char *dftty ------- Default tty name from ckx???.c int dfloc ------ Default location: remote/local int dfprty ----- Default parity int dfflow ------ Default flow control M A I N -- C-Kermit main program main(argc,argv) int argc = number of arguments on command line char **argv = arguments on command line P.S. These files will also be put into the sub-ufd SFILES>STC356>PCKERMIT -John ################################################################## ## LCKMAIN.ERR Lattice C Compiler (Phase 1) V2.15 Copyright (C) 1982 Lattice, Inc. asiports.h 317 Warning 84: redefinition of pre-processor symbol "NUL" asiports.h 318 Warning 84: redefinition of pre-processor symbol "SOH" asiports.h 330 Warning 84: redefinition of pre-processor symbol "XON" ################################################################## ## LCKPROT.C /* WARNING -- This C source program generated by Wart preprocessor. */ /* Do not edit this file; edit the Wart-format source file instead, */ /* and then run it through Wart to produce a new C source file. */ /* Wart Version Info: */ char *wartv = "Wart Version 1A(003) 27 May 85"; char *protv = "C-Kermit Protocol Module 4C(026), 12 Jun 85"; /* -*-C-*- */ /* C K C P R O -- C-Kermit Protocol Module, in Wart preprocessor notation. */ /* Author: Frank da Cruz (SY.FDC@CU20B), Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* Modified for sliding windows impl. by: Jan A. van der Eijk */ #include "lckdeb.h" #include "lckerm.h" /* Note -- This file may also be preprocessed by the Unix Lex program, but you must indent the above #include statement before using Lex, and then restore it to the left margin in the resulting C program before compilation. Also, the invocation of the "wart()" function below must be replaced by an invocation of the "yylex()" function. It might also be necessary to remove comments in the %%...%% section. */ /* State definitions for Wart (or Lex) */ #define rfile 1 #define rdata 2 #define ssinit 3 #define ssdata 4 #define sseof 5 #define sseot 6 #define get 7 #define rattr 8 #define ssattr 9 #define swdata 10 #define rwdata 11 #define sweof 12 /* External C-Kermit variable declarations */ extern char sstate, *versio, *cmarg, *cmarg2; extern char data[], filnam[], ttname[]; extern int pktnum, timint, nfils, image, hcflg, xflg, speed, flow, mdmtyp; extern int prvpkt, cxseen, czseen, local, displa, bctu, bctr, quiet; extern int putfil(), errpkt(); extern int filatr,nxtcas, rpktno, window; /* Local variables */ static char vstate = 0; /* Saved State */ static char vcmd = 0; /* Saved Command */ static int x; /* General-purpose integer */ /* Macros - Note, BEGIN is predefined by Wart (and Lex) */ #define RESUME return #define BEGIN state = int state = 0; wart() { int c,actno; extern int tbl[]; while (1) { c = input(); if ((actno = tbl[c + state*128]) != -1) switch(actno) { case 1: { tinit(); /* Do Send command */ if (sinit()) BEGIN ssinit; else RESUME; } break; case 2: { tinit(); sleep(1); nack(); BEGIN get; } break; case 3: { errpkt("User cancelled transaction"); /* Tell other side what's going on */ clsif(); clsof(); return(0); } break; case 4: { rinit(data); bctu = bctr; BEGIN rfile; } break; case 5: { if (rcvfil()) { /* A file is coming */ ack(); if (filatr) BEGIN rattr; /* Both want attributes */ else if ( wdinit() ) BEGIN rwdata; /* Both want windows */ else BEGIN rdata; } else { errpkt("Can't open file"); RESUME; } } break; case 6: { ack(); reot(); sleep(2); RESUME; } break; case 7: { if ( rdattr(data)) ack(); /* Got file Attributes */ else { errpkt("Not enough disk space"); clsof(); RESUME; } } break; case 8: { ack(); decode(data,putfil); /* First data packet */ if ( wdinit() ) BEGIN rwdata; else BEGIN rdata; } break; case 9: { ack(); reof(); BEGIN rfile; } break; case 10: { if ( !(cxseen || czseen) ) { /* Not aborted by me */ rweof(); } /* write data to disk */ pktnum = rpktno; /* make sure we have the right packet number */ ack(); reof(); BEGIN rfile; } break; case 11: { if (cxseen) ack1("X"); /* Got data. */ else if (czseen) ack1("Z"); else ack(); decode(data,putfil); } break; case 12: { if (cxseen || czseen) { /* Got data, in window */ pktnum = rpktno; /* Resynch. packet numbers */ if (czseen) ack1("Z"); else ack1("X"); ttflui(); sleep(3); ttflui(); } /* Flush input buffer */ else if ( !gwdata()) { wnderr("Protocol Error"); RESUME; } } break; case 13: { if ( ! nackdp() ) { /* Got bad data, NACK it */ wnderr("Timed out."); /* Timed out, issue message and */ RESUME; } } break; case 14: { resend(); } break; case 15: { spar(data); /* Got ACK to Send-Init */ bctu = bctr; if (sfile()) { if (filatr) { BEGIN ssattr; nxtcas = 1;} else BEGIN ssdata; } else { errpkt("Can't open file"); RESUME; } } break; case 16: { if (canned(data)) { seof(); clsif(); BEGIN sseof; } else if (!sattr()) { /* Send Attr packet(s) */ BEGIN ssdata; } } break; case 17: { if (canned(data) || !sdata()) { /* Got ACK to data */ seof(); clsif(); BEGIN sseof; } else if (wdinit()) BEGIN swdata; } break; case 18: { if (canned(data) || !sdataw() ) { /* Got ACK, with Abort data */ if (!cxseen && !czseen && window ) { /* or abort by me or EOF */ BEGIN sweof; /* EOF but window not empty */ } else { pktnum = rpktno; /* Get the right number */ ttfluo(); sleep(2); ttflui(); /* Wait and flush buffer */ seof();clsif(); /* Send the Z packet */ BEGIN sseof; } } } break; case 19: { if ( !wresnd() ) { /* Not an ACK, try resend */ wnderr("Timed out."); /* Timed out, issue message */ RESUME; } } break; case 20: { if ( weof() ) { /* If all the packets are ACKEd */ seof(); clsif(); /* End Of File state */ BEGIN sseof; } } break; case 21: { if (gnfile() > 0) { /* Got ACK to EOF, get next file */ if (sfile()) { if (filatr) { BEGIN ssattr; nxtcas = 1;} else BEGIN ssdata; } else { errpkt("Can't open file") ; RESUME; } } else { /* If no next file, EOT */ seot(); BEGIN sseot; } } break; case 22: { RESUME; } break; case 23: { ermsg(data); /* Error packet, issue message */ x = quiet, quiet = 1; /* close files silently */ clsif(); clsof(); quiet = x; RESUME; } break; case 24: { nack(); } break; } } } int tbl[] = { -1, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 3, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 1, 24, 24, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, -1, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 6, 24, 24, 23, 5, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 3, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 1, 24, 24, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, -1, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 11, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 9, 24, 24, 24, 24, 24, 24, 3, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 1, 24, 24, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, -1, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 24, 24, 24, 24, 24, 24, 24, 24, 14, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 15, 24, 24, 24, 24, 24, 24, 24, 3, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 1, 24, 24, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, -1, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 24, 24, 24, 24, 24, 24, 24, 24, 14, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 17, 24, 24, 24, 24, 24, 24, 24, 3, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 1, 24, 24, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, -1, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 24, 24, 24, 24, 24, 24, 24, 24, 14, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 21, 24, 24, 24, 24, 24, 24, 24, 3, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 1, 24, 24, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, -1, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 24, 24, 24, 24, 24, 24, 24, 24, 14, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 22, 24, 24, 24, 24, 24, 24, 24, 3, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 1, 24, 24, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, -1, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 4, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 3, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 1, 24, 24, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, -1, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 7, 24, 24, 8, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 9, 24, 24, 24, 24, 24, 24, 3, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 1, 24, 24, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, -1, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 16, 24, 24, 24, 24, 24, 24, 24, 3, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 1, 24, 24, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, -1, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 24, 24, 24, 24, 24, 24, 24, 24, 19, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 18, 24, 24, 24, 24, 24, 24, 24, 3, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 1, 24, 24, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, -1, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 12, 23, 24, 24, 24, 24, 24, 24, 24, 24, 13, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 10, 24, 24, 24, 24, 24, 24, 3, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 1, 24, 24, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 24, 24, 24, 24, 24, 24, 24, 24, 19, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 20, 24, 24, 24, 24, 24, 24, 24, 3, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 1, 24, 24, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, }; /* P R O T O -- Protocol entry function */ proto() { int x; /* Set up the communication line for file transfer. */ if (local && (speed < 0)) { screen(SCR_EM,0,0l,"Sorry, you must 'set speed' first"); return; } x = -1; if (ttopen(ttname,&x,mdmtyp) < 0) { debug(F111,"proto ttopen local",ttname,local); screen(SCR_EM,0,0l,"Can't open line"); return; } if (x > -1) local = x; debug(F111,"proto ttopen local",ttname,local); x = (local) ? speed : -1; if (ttpkt(x,flow) < 0) { /* Put line in packet mode, */ screen(SCR_EM,0,0l,"Can't condition line"); return; } sleep(1); /* The 'wart()' function is generated by the wart program. It gets a character from the input() routine and then based on that character and the current state, selects the appropriate action, according to the state table above, which is transformed by the wart program into a big case statement. The function is active for one transaction. */ wart(); /* Enter the state table switcher. */ screen(SCR_TC,0,0l,""); /* Transaction complete */ } ################################################################## ## LCKPROT.ERR Lattice C Compiler (Phase 1) V2.15 Copyright (C) 1982 Lattice, Inc. ################################################################## ## LCKPROT.W char *protv = "C-Kermit Protocol Module 4C(026), 12 Jun 85"; /* -*-C-*- */ /* C K C P R O -- C-Kermit Protocol Module, in Wart preprocessor notation. */ /* Author: Frank da Cruz (SY.FDC@CU20B), Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* Modified for sliding windows impl. by: Jan A. van der Eijk */ #include "lckdeb.h" #include "lckerm.h" /* Note -- This file may also be preprocessed by the Unix Lex program, but you must indent the above #include statement before using Lex, and then restore it to the left margin in the resulting C program before compilation. Also, the invocation of the "wart()" function below must be replaced by an invocation of the "yylex()" function. It might also be necessary to remove comments in the %%...%% section. */ /* State definitions for Wart (or Lex) */ %states rfile rdata ssinit ssdata sseof sseot get rattr ssattr swdata rwdata swe /* External C-Kermit variable declarations */ extern char sstate, *versio, *cmarg, *cmarg2; extern char data[], filnam[], ttname[]; extern int pktnum, timint, nfils, image, hcflg, xflg, speed, flow, mdmtyp; extern int prvpkt, cxseen, czseen, local, displa, bctu, bctr, quiet; extern int putfil(), errpkt(); extern int filatr,nxtcas, rpktno, window; /* Local variables */ static char vstate = 0; /* Saved State */ static char vcmd = 0; /* Saved Command */ static int x; /* General-purpose integer */ /* Macros - Note, BEGIN is predefined by Wart (and Lex) */ #define RESUME return %% /* Protocol entry points, one for each start state (sstate) */ s { tinit(); /* Do Send command */ if (sinit()) BEGIN ssinit; else RESUME; } v { tinit(); sleep(1); nack(); BEGIN get; } /* Receive */ a { errpkt("User cancelled transaction"); /* Tell other side what's going on */ clsif(); clsof(); return(0); } /* Return from protocol. */ /* Dynamic states: input-character { action } */ S { rinit(data); bctu = bctr; BEGIN rfile; } /* Send-Init */ F { if (rcvfil()) { /* A file is coming */ ack(); if (filatr) BEGIN rattr; /* Both want attributes */ else if ( wdinit() ) BEGIN rwdata; /* Both want windows */ else BEGIN rdata; } else { errpkt("Can't open file"); RESUME; } } B { ack(); reot(); sleep(2); RESUME; } /* Got End Of Trans. */ A { if ( rdattr(data)) ack(); /* Got file Attributes */ else { errpkt("Not enough disk space"); clsof(); RESUME; } } D { ack(); decode(data,putfil); /* First data packet */ if ( wdinit() ) BEGIN rwdata; else BEGIN rdata; } Z { ack(); reof(); BEGIN rfile; } /* Got End Of File */ Z { if ( !(cxseen || czseen) ) { /* Not aborted by me */ rweof(); } /* write data to disk */ pktnum = rpktno; /* make sure we have the right packet number */ ack(); reof(); BEGIN rfile; } D { if (cxseen) ack1("X"); /* Got data. */ else if (czseen) ack1("Z"); else ack(); decode(data,putfil); } D { if (cxseen || czseen) { /* Got data, in window */ pktnum = rpktno; /* Resynch. packet numbers */ if (czseen) ack1("Z"); else ack1("X"); ttflui(); sleep(3); ttflui(); } /* Flush input buffer */ else if ( !gwdata()) { wnderr("Protocol Error"); RESUME; } } N { if ( ! nackdp() ) { /* Got bad data, NACK it */ wnderr("Timed out."); /* Timed out, issue message and */ RESUME; } } /* clean up */ N { resend(); } /* Got a NAK, resend. */ Y { spar(data); /* Got ACK to Send-Init */ bctu = bctr; if (sfile()) { if (filatr) { BEGIN ssattr; nxtcas = 1;} else BEGIN ssdata; } else { errpkt("Can't open file"); RESUME; } } Y { if (canned(data)) { seof(); clsif(); BEGIN sseof; } else if (!sattr()) { /* Send Attr packet(s) */ BEGIN ssdata; } } Y { if (canned(data) || !sdata()) { /* Got ACK to data */ seof(); clsif(); BEGIN sseof; } else if (wdinit()) BEGIN swdata; } Y { if (canned(data) || !sdataw() ) { /* Got ACK, with Abort data */ if (!cxseen && !czseen && window ) { /* or abort by me or EOF */ BEGIN sweof; /* EOF but window not empty */ } else { pktnum = rpktno; /* Get the right number */ ttfluo(); sleep(2); ttflui(); /* Wait and flush buffer */ seof();clsif(); /* Send the Z packet */ BEGIN sseof; } } } N { if ( !wresnd() ) { /* Not an ACK, try resend */ wnderr("Timed out."); /* Timed out, issue message */ RESUME; } } /* and clean up */ Y { if ( weof() ) { /* If all the packets are ACKEd */ seof(); clsif(); /* End Of File state */ BEGIN sseof; } } Y { if (gnfile() > 0) { /* Got ACK to EOF, get next file */ if (sfile()) { if (filatr) { BEGIN ssattr; nxtcas = 1;} else BEGIN ssdata; } else { errpkt("Can't open file") ; RESUME; } } else { /* If no next file, EOT */ seot(); BEGIN sseot; } } Y { RESUME; } /* Got ACK to EOT */ E { ermsg(data); /* Error packet, issue message */ x = quiet, quiet = 1; /* close files silently */ clsif(); clsof(); quiet = x; RESUME; } . { nack(); } /* Anything else, send NAK */ %% /* P R O T O -- Protocol entry function */ proto() { int x; /* Set up the communication line for file transfer. */ if (local && (speed < 0)) { screen(SCR_EM,0,0l,"Sorry, you must 'set speed' first"); return; } x = -1; if (ttopen(ttname,&x,mdmtyp) < 0) { debug(F111,"proto ttopen local",ttname,local); screen(SCR_EM,0,0l,"Can't open line"); return; } if (x > -1) local = x; debug(F111,"proto ttopen local",ttname,local); x = (local) ? speed : -1; if (ttpkt(x,flow) < 0) { /* Put line in packet mode, */ screen(SCR_EM,0,0l,"Can't condition line"); return; } sleep(1); /* The 'wart()' function is generated by the wart program. It gets a character from the input() routine and then based on that character and the current state, selects the appropriate action, according to the state table above, which is transformed by the wart program into a big case statement. The function is active for one transaction. */ wart(); /* Enter the state table switcher. */ screen(SCR_TC,0,0l,""); /* Transaction complete */ } ################################################################## ## LCKTIO.C /* L C K T I O module */ char *ckxv = "tty I/O, 4LC (001), 01 Jul 85"; /* C-Kermit interrupt, terminal control & i/o functions for PC-DOS systems */ /* F. da Cruz, Columbia University Center for Computing Activities */ /* Modified for use with PC-DOS by: Jan A. van der Eijk, NUS Corp., July 1985 */ /* Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ char *ckxsys = " PC-DOS > 2.0"; /* 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): ttopen(ttname,local,mdmtyp) -- Open the named tty for exclusive access. ttclos() -- Close & reset the tty, releasing any access lock. ttpkt(speed,flow) -- Put the tty in packet mode and set the speed. ttvt(speed,flow) -- Put the tty in virtual terminal mode. or in DIALING or CONNECTED modem control state. ttinl(dest,max,timo,eol)-- Timed read line from the tty. ttinc(timo) -- Timed read character from tty. ttchk() -- See how many characters in tty input buffer. ttol(string,length) -- Write a string to the tty. ttoc(c) -- Write a character to the tty. ttflui() -- Flush tty input buffer. */ /* Functions for console terminal: 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. Time functions msleep(m) -- Millisecond sleep ztime(&s) -- Return pointer to date/time string */ /* Includes */ #include "stdios.h" /* Unix Standard i/o */ #include #include "lckdeb.h" /* Formats for debug() */ #include "asic.h" /* Greenleaf header */ #include "timedate.h" /* Greenleaf header */ #define XONCODE 0 #define XOFFCODE 1 #define NULCODE 2 struct TIMEDATE *sgettime(); long int strtim; /* 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 */ char *dftty = "COM1"; int dfloc = 1; int dfprty = 0; /* Parity (0 = none) */ int dfflow = 1; /* Xon/Xoff flow control */ int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */ /* Declarations of variables global within this module */ static int xlocal = 0, /* Flag for tty local or remote */ ttyfd = -1; /* TTY file descriptor */ static char escchr; /* Escape or attn character */ static int conesc = 0; /* set to 1 if esc char (^\) typed */ char rbuf[4000],tbuf[4000]; /* receive and transmit buffer pointer */ int tlen,rlen; /* length of Xmit & Recv buffers */ /* C O N O C -- Output a character to the console terminal */ conoc(c) char c; { write(1,&c,1); } /* C O N X O -- Write x characters to the console terminal */ conxo(x,s) char *s; int x; { write(1,s,x); } /* C O N O L -- Write a line to the console terminal */ conol(s) 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 -- Check to see if user did hit keyboard */ /* Return 1 if keyboard has been hit */ conchk() { if (asikbhit()) return(1); /* Greenleaf function to test keyboard hit */ return(0); } /* C O N I N C -- Get a character from the console */ /* argument; timo = number of seconds to wait for keyboard input */ /* return -1 if no keyboard input */ coninc(timo) int timo; { int n, time; time = 0; while ( !conchk() ) { if ( time++ > (timo*18 )) return(-1); timer(1); /* wait for 1 clock tick */ } /* Greenleaf function timer() */ n = getch(); /* Read a character. */ if (n > 0 ) return(n); /* Return the char if read */ } /* T T O P E N -- Open a tty for exclusive access. */ /* Returns 0 on success, -1 on failure. */ ttopen(ttname,lcl,modem) char *ttname; int lcl, modem; { int status; if (ttyfd > -1) return(0); /* If already open, ignore this call */ xlocal = lcl; /* Make available to other functions */ ttyfd = -1; if (strcmp(ttname,"COM1") == 0) ttyfd = 0; /* Check for valid name */ else if (strcmp(ttname,"COM2") == 0) ttyfd = 1; else return(-1); rlen = 4000; /* Allocate space for interrupt driven */ tlen = 4000; /* RS 232 I/O */ status=asisetup(ttyfd,ASINOUT,BINARYNONE,rbuf,(rlen-2),tbuf,(tlen-2)); if (status < 0) { ttyfd = -1; return(-1); /* Setup buffers, return -1 if error */ } asdtr(ttyfd,1); asrts(ttyfd,1); /* Greenleaf specific function to */ status=asistart(ttyfd,ASINOUT); /* Setup interrupt handlers */ if (status < 0) { ttyfd = -1; return(-1); /* return -1 if any error */ } status= asixrst(ttyfd); if (status < 0) return(-1); status=asiclear(ttyfd,ASIN); if (status < 0) return(-1); return(0); } /* T T C L O S -- Close the TTY */ ttclos() { if (ttyfd < 0) return; /* Wasn't open. */ asiquit(ttyfd); /* Reset modes, turn off interrupts. */ /* Using Greenleaf function */ ttyfd = -1; /* Mark it as closed. */ } /* T T O L -- Similar to "ttinl", but for writing. */ /* returns number of characters writen to Com port */ ttol(s,n) int n; char *s; { int x; if (ttyfd < 0) return(-1); /* Not open, return -1. */ ttflow(); /* check for XON */ if ((x = asiputb(ttyfd,s,n)) >= 0 ) x = n; /* All characters writen ?? */ debug(F111,"ttol",s,n); if (x < 0) debug(F101,"ttol failed","",x); return(x); } /* T T O C -- Output a character to the communication line */ /* Returns -1 if an error occured */ ttoc(c) char c; { if (ttyfd < 0) return(-1); /* Not open. */ ttflow(); return(asiputc(ttyfd,c)); } /* T T I N C -- Read a character from the communication line */ /* return the character if possible otherwise -1 */ /* Argument timo, timout in seconds */ ttinc(timo) int timo; { extern long int strtim; long int totsec(); int n,time; n = -1; time = 0; if (ttyfd < 0) return(-1); /* Not open. */ if (timo <= 0) { /* Untimed. */ while (carrier()) { if( (n = ttin())>= 0) break ; /* Wait for a character. */ } } else { if ((n = ttin()) < 0) { strtim = totsec(); while(carrier()) { if( (n = ttin()) >= 0) break ; /* Wait for a character. */ else if (toolong(timo)) return(-1); /* Timeout return -1 */ } } } return(n); } /* T T I N L -- Read a record (up to break character) from comm line. */ /* If no break character encountered within "max", return "max" characters, with disposition of any remaining characters undefined. Otherwise, return the characters that were read, including the break character, in "dest" and the number of characters read as the value of function, or 0 upon end of file, or -1 if an error occurred. Times out & returns error if not completed within "timo" sconds. */ ttinl(dest,maxnum,timo,eol) int maxnum,timo,eol; char *dest; { extern long int strtim; long int totsec(); int i, y, c; int time; time = 0; if (ttyfd < 0) return(-1); /* Not open. */ if (timo <= 0) { /* Untimed. */ for ( i = c = 0; (i < maxnum) && (c != eol) ; i++) { c = ttin(); if ( c > -1 ) dest[i] = c; /* Try to read. */ else dest[i] = 0; } return(i); } else { strtim = totsec(); /* Intialize timer */ for ( i = c = 0; (i < maxnum) && (c !=eol) ; i++) { while ( (c = ttin()) < 0 ) { /* Try to read */ /* Timed out yet */ if(toolong(timo) || !carrier()) return(i); } dest[i] = c; /* Store the character */ } } return(i); /* Return the count. */ } /* TTPKT -- Condition communication line for packect mode */ /* arguments - speed, communications baud rate flow, flow control used */ ttpkt (speed,flow) int speed, flow; { int ispeed,iflow; ispeed =speed; iflow = flow; return(ttvt(ispeed,iflow)); } /* TTVT -- Condition communication line for use as virtual terminal */ /* Returns -1 if Error */ /* Arguments : speed -- requested communication baud rate flow -- requested flow control */ ttvt (speed,flow) int speed, flow; { extern int parity; int s, status,ipar,dbits; s = ttsspd(speed); /* Check the requested speed */ if (s < 0 ) return(-1); ipar=0; dbits = 8; if (parity ) dbits = 7; /* Set up required parity */ if (parity =='o') ipar =1; else if (parity =='e') ipar =2; else if (parity =='m') ipar =3; else if (parity =='s') ipar =4; status = asiinit(ttyfd,s,ipar,1,dbits); /* Condition comm port using */ /* Greenleaf functions */ if ( status < 0 ) return(-1); if ( flow) { asirchk(ttyfd,XOFFCODE,XOFF,2); asirchk(ttyfd,XONCODE,XON,2); } else { asirchk(ttyfd,XOFFCODE,XOFF,0); asirchk(ttyfd,XONCODE,XON,0); } asirchk(ttyfd,NULCODE,0x00,2); asiignore(ttyfd,1,ON); asiignore(ttyfd,2,ON); return(0); } /* T T S S P D -- check for valid baud rates */ /* return the baud rate if valid otherwise -1 */ ttsspd(speed) { int s; if (speed <0) return(-1); switch (speed) { case 0: s = 0 ; break; case 300: s = 300 ; break; case 1200: s = 1200 ; break; case 2400: s = 2400 ; break; case 4800: s = 4800 ; break; case 9600: s = 9600 ; break; default: fprintf(stderr,"Unsupported line speed - %d\n",speed); fprintf(stderr,"Current speed not changed\n"); s = - 1; break; } return(s); } /* TTFLUI --- Flush tty input buffer */ ttflui() { if ( ttyfd < 0) return(-1); if ( !ttsome()) return(0); while (1) { while(ttsome()) asigetc(ttyfd); /* Greenleaf function */ if (ttinc(1) < 0) break; /* Wait one sec */ } return(0); } /* TTFLUO ---- Flush tty ouput buffer */ ttfluo() { if ( ttyfd > -1 ) asiclear(ttyfd,ASOUT); /* Greenleaf function */ } /* T T I N -- read one character for tty input buffer */ /* return the character if available otherwise -1 */ ttin() { char ch; int n; if ( ttyfd <0 ) return(-1); if (!ttsome()) return(-1); /* Anything there */ n = asigetc(ttyfd); /* Greenleaf function */ if ( n > 0 ) n &= 0377; return(n); } /* T T C H K check if character available in receive buffer */ ttchk() { int n; if ( ttyfd < 0 ) return(0); if ( !ttsome() ) return(0); return (TRUE); } /* T T S O M E * * Routine to return TRUE if receive buffer has character in it * * Returns: Serial port receive character register status */ int ttsome() { int status; ttflow(); /* Check for XOFF if enabled */ /* if receiver is not empty */ if ((asi_parms[ttyfd].flags&2)==0) return(TRUE); /* Greenleaf */ return(FALSE); } int ttflow() { if ( isrchk(ttyfd,XOFFCODE)) { /* check for XOFF */ asihold(ttyfd); /* Hold interrupts */ asiresume(ttyfd,ASIN); /* Resume receiving */ if ( !isrchk(ttyfd,XONCODE)) { strtim = totsec(); /* Intialize timer */ while ( TRUE) { if ( isrchk(ttyfd,XONCODE)) { /* wait for XON */ break; /* go for it again */ } if ( !carrier() || toolong(5)) break; /* don't wait toolong */ } } asihold(ttyfd); /* stop interrupts */ asiresume(ttyfd,ASINOUT); /* resume them */ if ( isrchk(ttyfd,XOFFCODE)) { asirchk(ttyfd,XOFFCODE,XOFF,4); /* Clear XOFF flag */ } if ( isrchk(ttyfd,XONCODE)) { asirchk(ttyfd,XONCODE,XON,4); /* Clear XON flag */ } /* printf("xon/xoff detected \n"); */ } } /* C A R R I E R * * check for existance of modem carrier signal * * carrier() * * Returns: 1 if carrier present; else returns 0 */ int carrier() { extern int cdetect; int status; if ( !cdetect) return(TRUE); /* Carrier not required */ status = asistat(ttyfd); /* Greenleaf function */ if (status & 0x0080) return(TRUE); /* check rec line sig detect */ return(FALSE); /* return FALSE if no carrier */ } /* S L E E P wait for m seconds */ sleep(m) int m; { extern long int strtim, totsec(); strtim = totsec(); while (1) { if ( toolong(m) ) break; } } /* T I C K S -- Returns total number of clock ticks since midnight */ long int ticks() { struct REGS regs; union { int s[2]; long ll;} secs ; regs.ax = 0; secs.ll = 0L; int86(0x1A,®s,®s); secs.s[0] = regs.dx; /* High count */ secs.s[1] = regs.cx; /* Low count */ return(secs.ll); } /* T O T S E C -- Time since midnight in seconds */ long int totsec() { long int ticks(), secnds; secnds = (10l * ticks() ) / 182; return(secnds); } /* T O O L O N G -- Timeout for user input with tout in seconds */ toolong(tout) int tout; { extern long int strtim, totsec(); long int nowtim; nowtim = totsec(); if (nowtim < strtim) nowtim += 86400L; if ( (nowtim - strtim) < tout) return(0); else return(1); } /* Z T I M E -- Return date/time string */ ztime(s) char **s; { struct TIMEDATE *ptd; ptd = sgettime(6); /* get the time from system */ *s= ptd->dateline; /* Using Greenleaf function */ } ################################################################## ## LCKTIO.DOC /* L C K T I O module */ C O N O C -- Output a character to the console terminal conoc(c) char c = character to print C O N X O -- Write x characters to the console terminal conxo(x,s) char *s = string to print int x = number of characters to print C O N O L -- Write a line to the console terminal conol(s) char *s line to print C O N O L A -- Write an array of lines to the console terminal conola(s) char *s[] = array to print C O N O L L -- Output a string followed by CRLF conoll(s) char *s = string to print C O N C H K -- Check to see if user did hit keyboard Return 1 if keyboard has been hit conchk() C O N I N C -- Get a character from the console, wait for timo seconds returns -1 if no keyboard input coninc(timo) int timo = timeout in seconds T T O P E N -- Open a Comport, returns 0 on success, -1 on failure. sets ttyfd to 0 if COM1 or to 1 if COM2 ttopen(ttname,lcl,modem) char *ttname = name of comport ("COM1" or "COM2") int lcl ( not used , set to zero ) int modem ( not used , dummy argument) T T C L O S -- Close the TTY , set ttyfd to 0 ttclos() T T O L -- Similar to "ttinl", but for writing. returns number of characters writen to Com port ttol(s,n) int n = number of characters to send char *s = string to send T T O C -- Output a character to the communication line Returns -1 if an error occured ttoc(c) char c = character to write T T I N C -- Read a character from the communication line return the character if possible otherwise -1 timout in timo seconds ttinc(timo) int timo = timout period T T I N L -- Read a record (up to break character) from comm line. If no break character encountered within "max", return "max" characters, with disposition of any remaining characters undefined. Otherwise, return the characters that were read, including the break character, in "dest" and the number of characters read as the value of function, or 0 upon end of file, or -1 if an error occurred. Times out & returns error if not completed within "timo" sconds. ttinl(dest,maxnum,timo,eol) int maxnum = maximum number of char to read int timo = timout period int eol = break character char *dest = destination string TTPKT -- Condition communication line for packect mode ttpkt (speed,flow) int speed = baud rate int flow = flow control used 0 = None, 1 = XON/XOFF TTVT -- Condition communication line for use as virtual terminal Returns -1 if Error */ ttvt (speed,flow) int speed = baud rate int flow = flow control used extern int parity = parity to be used (e, o, m, s, n) T T S S P D -- check for valid baud rates return the baud rate if valid otherwise -1 ttsspd(speed) int speed = baud rate TTFLUI -- Flush tty input buffer ttflui() TTFLUO -- Flush tty ouput buffer ttfluo() T T I N -- read one character for tty input buffer return the character if available otherwise -1 ttin() T T C H K -- check if character available in receive buffer */ ttchk() { T T S O M E -- Return TRUE if receive buffer has character in it. int ttsome() T T F L O W -- Checks for XOFF,if so waits for XON, timeout after 5 sec. ttflow() C A R R I E R -- Check for existance of modem carrier signal Returns: 1 if carrier present; else returns 0 int carrier() extern int cdetect = if set will return 1 S L E E P -- Wait for m seconds sleep(m) int m = number of seconds to sleep T I C K S -- Returns total number of clock ticks since midnight */ long int ticks() T O T S E C -- Returns time since midnight in seconds long int totsec() T O O L O N G -- Timeout for user input with tout in seconds */ toolong(tout) int tout = time out period extern long int strtim = starting time tor tout Z T I M E -- Return date/time string ztime(s) char **s = pointer to string containing date and time ################################################################## ## LCKTIO.ERR Lattice C Compiler (Phase 1) V2.15 Copyright (C) 1982 Lattice, Inc. ################################################################## ## LCKUSER.C char *userv = "User Interface 4LC(001), 01 Jul 85"; /* C K U U S R -- "User Interface" for PC-DOS Kermit */ /* F. da Cruz, Columbia University Center for Computing Activities */ /* Modified for use with PC-DOS by: Jan A. van der Eijk, NUS Corp., July 1985 */ /* Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* The ckuser module contains the terminal input and output functions for MS-DOS Kermit. It includes a simple Unix-style command line parser as well as an interactive prompting keyword command parser. It depends on the existence of 'C' facilities like fopen, fgets, feof, (f)printf, argv/argc, etc. Other functions that are likely to vary among 'C' implementations -- like setting terminal modes or interrupts -- are invoked via calls to functions that are defined in the system-dependent modules, ck?[ft]io.c. The command line parser processes any arguments found on the command line, as passed to main() via argv/argc. The interactive parser uses the facilities of the cmd package (developed for this program, but usable by any program). Any command parser may be substituted for this one. The only requirements for the Kermit command parser are these: 1. Set parameters via global variables like duplex, speed, ttname, etc. See ckmain.c for the declarations and descriptions of these variables. 2. If a command can be executed without the use of Kermit protocol, then execute the command directly and set the variable sstate to 0. Examples include 'set' commands, local directory listings, the 'connect' command. 3. If a command requires the Kermit protocol, set the following variables: sstate string data 'v' (enter receive mode) cmarg2 's' (send files) nfils, cmarg & cmarg2 OR cmlist cmlist is an array of pointers to strings. cmarg, cmarg2 are pointers to strings. nfils is an integer. cmarg can be a filename string (possibly wild), or a pointer to a prefabricated generic command string, or a pointer to a host command string. cmarg2 is the name to send a single file under, or the name under which to store an incoming file; must not be wild. cmlist is a list of nonwild filenames, such as passed via argv. nfils is an integer, interpreted as follows: -1: argument string is in cmarg, and should be expanded internally. >0: number of files to send, from cmlist. The screen() function is used to update the screen during file transfer. The tlog() function maintains a transaction log. The debug() function maintains a debugging log. The intmsg() and chkint() functions provide the user i/o for interrupting file transfers. */ /* Includes */ #include "stdios.h" #include #include "lckdeb.h" #include "lckerm.h" #include "lckcmd.h" #include "lckusr.h" #define KERMRC "kermit.ini" /* External Kermit Variables, see ckmain.c for description. */ extern int size, spsiz, rpsiz, npad, timint, rtimo, speed, local, server, displa, binary, fncnv, delay, parity, deblog, escape, xargc, flow, turn, duplex, cxseen, czseen, nfils, ckxech, pktlog, seslog, tralog, turnch, chklen, bctr, bctu, dfloc, mdmtyp, cdetect, rptflg, ebqflg, warn, quiet, cnflg, timef, mypadn, sldwnd, wndsiz, wndmax; extern long filcnt, tlci, tlco, ffc, tfc, fsize; extern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv; extern char *ckxsys, *ckzsys, *cmarg, *cmarg2, **xargv, **cmlist; extern char mystch, stchr, sstate, mypadc, padch, eol, seol, ctlq, filnam[], ttname[]; extern char *DIRCMD, *PWDCMD; char *strcpy(), *getenv(); /* Declarations from cmd package */ extern char cmdbuf[]; /* Command buffer */ /* Declarations from ck?fio.c module */ extern char *SPACMD, *zhome(); /* Space command, home directory. */ extern int backgrd; /* Kermit executing in background */ /* The background flag is set by ckutio.c (via conint() ) to note whether */ /* this kermit is executing in background ('&' on shell command line). */ /* Variables and symbols local to this module */ char line[CMDBL+10], *lp; /* Character buffer for anything */ char debfil[50]; /* Debugging log file name */ char pktfil[50]; /* Packet log file name */ char sesfil[50]; /* Session log file name */ char trafil[50]; /* Transaction log file name */ int n, /* General purpose int */ cflg, /* Command-line connect cmd given */ action, /* Action selected on command line*/ repars, /* Reparse needed */ tlevel, debugp = 0, /* Debug print */ /* Take command level */ cwdf = 0; /* CWD has been done */ char *homdir; /* Pointer to home directory string */ char cmdstr[100]; /* C M D L I N -- Get arguments from command line */ /* Simple Unix-style command line parser, conforming with 'A Proposed Command Syntax Standard for Unix Systems', Hemenway & Armitage, Unix/World, Vol.1, No.3, 1984. */ cmdlin() { char x; cmarg = ""; /* Initialize. */ cmarg2 = ""; action = cflg = 0; while (--xargc > 0) { /* Go through command line words */ xargv++; debug(F111,"xargv",*xargv,xargc); if (**xargv == '-') { /* Got an option (begins with dash) */ x = *(*xargv+1); /* Get the option letter */ x = doarg(x); /* Go handle the option */ if (x < 0) exit(GOOD_EXIT); } else { /* No dash where expected */ usage(); exit(BAD_EXIT); } } debug(F101,"action","",action); if (!local) { if ((action == 'g') || (action == 'r') ) fatal("-l and -b required"); } if (*cmarg2 != 0) { if ((action != 's') && (action != 'r') && (action != 'v')) fatal("-a without -s, -r, or -g"); } if ((action == 's') || (action == 'v') || (action == 'r') || (action == 'x')) { if (local) displa = 1; } if (quiet) displa = 0; /* No display if quiet requested */ return(action); /* Then do any requested protocol */ } /* D O A R G -- Do a command-line argument. */ doarg(x) char x; { int z; char *xp; xp = *xargv+1; /* Pointer for bundled args */ while (x) { switch (x) { case 'f': if (action) fatal("conflicting actions"); action = setgen('F',"","",""); break; case 'r': /* receive */ if (action) fatal("conflicting actions"); action = 'v'; break; case 's': /* send */ if (action) fatal("conflicting actions"); if (*(xp+1)) fatal("invalid argument bundling after -s"); nfils = 0; /* Initialize file counter, flag */ cmlist = xargv+1; /* Remember this pointer */ while (--xargc > 0) { /* Traverse the list */ *xargv++; if (**xargv == '-') break; /* Check for '-' */ nfils++; /* Bump file counter */ } xargc++, *xargv--; /* Adjust argv/argc */ if (nfils < 1) fatal("missing filename for -s"); if ( nfils == 1) { /* Incase wild cards were specified */ cmarg = *cmlist; nfils = -1; } debug(F101,*xargv,"",nfils); action = 's'; break; /* cont'd... */ /* ...doarg(), cont'd */ case 'h': /* help */ usage(); return(-1); case 'c': cdetect = TRUE; break; case 'a': /* "as" */ if (*(xp+1)) fatal("invalid argument bundling after -a"); *xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) fatal("missing name in -a"); cmarg2 = *xargv; break; case 'l': /* set line */ if (*(xp+1)) fatal("invalid argument bundling after -l"); *xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) fatal("communication line device name missing"); /* strcpy(ttname,*xargv); */ zrtol(*xargv,ttname); /* if (strcmp(ttname,dftty) == 0) local = dfloc; else local = 1; */ local = (strcmp(ttname,CTTNAM) != 0); /* (better than old way) */ debug(F101,"local","",local); ttopen(ttname,&local,0); break; case 'b': /* set baud */ if (*(xp+1)) fatal("invalid argument bundling"); *xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) fatal("missing baud"); z = atoi(*xargv); /* Convert to number */ if (chkspd(z) > -1) speed = z; /* Check it */ else fatal("unsupported baud rate"); break; case 'n': /* Treat files as non-binary */ binary = 0; break; /* cont'd... */ /* ...doarg(), cont'd */ case 'w': /* File warning */ warn = 0; break; case 'q': /* Quiet */ quiet = 1; break; case 'd': /* debug */ debugp = 1; #ifdef DEBUG debugp = 0; #endif debopn("debug.log"); break; case 'p': /* set parity */ if (*(xp+1)) fatal("invalid argument bundling"); *xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) fatal("missing parity"); switch(x = **xargv) { case 'e': case 'o': case 'm': case 's': parity = x; break; case 'n': parity = 0; break; default: fatal("invalid parity"); } break; case 'm': /* set window size */ if (*(xp+1) || duplex ) fatal("invalid argument bundling"); *xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) fatal("missing window size"); z = atoi(*xargv); /* Convert to number */ if ( z > MYWND || z < 0 ) /* Check it */ fatal("invalid window size"); else wndmax = z; break; case 't': turn = 1; /* Line turnaround handshake */ turnch = XON; /* XON is turnaround character */ duplex = 1; /* Half duplex */ flow = 0; /* No flow control */ wndsiz = 0; /* No windowing */ sldwnd = 0; break; default: fatal("invalid argument, type 'kermit -h' for help"); } x = *++xp; /* See if options are bundled */ } return(0); } static char *hlp1[] = { "\n", " Kermit Receive and Send protocol module for MS-DOS operating system.\n", " Jan A. van der Eijk, NUS Corp. July 1985. \n", " PCKERMIT version 1.18, December 10, 1985 \n", " Usage: PCKERMIT [-x arg [-x arg]...[-yyy]..]]\n", " x is an option that requires an argument, y an option with no argument:\n", " -s file(s) send \n", " -r receive\n", " -a name alternate name, used with -s, -r\n", " -h help - print this message\n", " settings -- default\n" " -l line communication line device ( COM1, COM2 ) [COM1]\n" " -b baud line speed, e.g. 1200 [1200]\n" " -p x parity, x is one of e,o,m,s,n [N] \n" " -m size maximum window size to use ( <= 31 ) [31] \n" " -n non binary file transfer, affect CR/LF \n", " -t line turnaround handshake = xon, half duplex\n", " -w write over preexisting files\n", " -q be quiet during file transfer\n", " -c carrier detect signal required to be present\n", "" }; /* U S A G E */ usage() { conola(hlp1); } /* Misc */ fatal(msg) char *msg; { /* Fatal error message */ fprintf(stderr,"\r\nFatal: %s\n",msg); tlog(F110,"Fatal:",msg,0l); doexit(BAD_EXIT); /* Exit indicating failure */ } /* D O E X I T -- Exit from the program. */ doexit(exitstat) int exitstat; { sleep(2); ttclos(); /* Close external line, if any */ if (local) { strcpy(ttname,dftty); /* Restore default tty */ local = dfloc; /* And default remote/local status */ } if (deblog) { /* Close any open logs. */ debug(F100,"Debug Log Closed","",0); *debfil = '\0'; deblog = 0; zclose(ZDFILE); } if (tralog) { tlog(F100,"Transaction Log Closed","",0l); *trafil = '\0'; tralog = 0; zclose(ZTFILE); } exit(exitstat); /* Exit from the program. */ } /* B L D L E N -- Make length-encoded copy of string */ char * bldlen(str,dest) char *str, *dest; { int len; len = strlen(str); *dest = tochar(len); strcpy(dest+1,str); return(dest+len+1); } /* S E T G E N -- Construct a generic command */ setgen(type,arg1,arg2,arg3) char type, *arg1, *arg2, *arg3; { char *upstr, *cp; cp = cmdstr; *cp++ = type; *cp = NUL; if (*arg1 != NUL) { upstr = bldlen(arg1,cp); if (*arg2 != NUL) { upstr = bldlen(arg2,upstr); if (*arg3 != NUL) bldlen(arg3,upstr); } } cmarg = cmdstr; debug(F110,"setgen",cmarg,0); return('g'); } /* D E B O P N -- Open a debugging file */ debopn(s) char *s; { #ifdef DEBUG char *tp; zclose(ZDFILE); deblog = zopeno(ZDFILE,s); if (deblog > 0) { strcpy(debfil,s); debug(F110,"Debug Log ",versio,0); debug(F100,ckxsys,"",0); ztime(&tp); debug(F100,tp,"",0); } else *debfil = '\0'; return(deblog); #else return(0); #endif } /* C H K S P D -- Check if argument is a valid baud rate */ chkspd(x) int x; { switch (x) { case 0: case 110: case 150: case 300: case 600: case 1200: case 1800: case 2400: case 4800: case 9600: return(x); default: return(-1); } } /* I N T M S G -- Issue message about terminal interrupts */ intmsg(n) long n; { extern char *chstr(); char buf[80]; if ((!displa) || (quiet)) return; if (n == 1) { screen(SCR_TN,0,0l,"CTRL-F to cancel File, CTRL-R to Resend current packet"); screen(SCR_TN,0,0l,"CTRL-B to cancel Batch, CTRL-K to abort Kermit and exit"); screen(SCR_TN,0,0l,"CTRL-A for status report: "); } else screen(SCR_TU,0,0l," "); } /* C H K I N T -- Check for console interrupts */ /*** should rework not to destroy typeahead ***/ chkint() { int ch, cn; if ((!local) || (quiet)) return(0); /* Only do this if local & not quiet */ cn = conchk(); /* Any input waiting? */ debug(F101,"conchk","",cn); while (cn > 0) { /* Yes, read it. */ cn--; /* give read 5 seconds for interrupt character */ if ((ch = coninc(5)) < 0) return(0); switch (ch & 0177) { case 0001: /* CTRL-A */ screen(SCR_TN,0,0l,"^A Status report:"); screen(SCR_TN,0,0l," file type: "); if (binary) screen(SCR_TZ,0,0l,"binary"); else screen(SCR_TZ,0,0l,"text"); screen(SCR_QE,0,(long)filcnt," file number"); screen(SCR_QE,0,(long)ffc, " characters "); if (sldwnd) screen(SCR_QE,0,(long)wndsiz," window size"); screen(SCR_QE,0,(long)bctu, " block check"); screen(SCR_QE,0,(long)rptflg," compression"); screen(SCR_QE,0,(long)ebqflg," 8th-bit prefixing"); continue; case 0002: /* CTRL-B */ screen(SCR_TN,0,0l,"^B - Cancelling Batch "); czseen = 1; continue; case 0013: /* CTRL-K */ screen(SCR_TN,0,0l,"^K - Aborting Kermit "); errpkt("Tranfer aborted by otherside."); czseen = 1; cxseen = 1; clsif();clsof(); doexit(BAD_EXIT); continue; case 0006: /* CTRL-F */ screen(SCR_TN,0,0l,"^F - Cancelling File "); cxseen = 1; continue; case 0022: /* CTRL-R */ screen(SCR_TN,0,0l,"^R - Resending "); resend(); return(1); default: /* Anything else, just ignore */ screen(SCR_TU,0,0l," [Ignored] "); continue; } } return(0); } /* D E B U G -- Enter a record in the debugging log */ /* Call with a format, two strings, and a number: f - Format, a bit string in range 0-7. If bit x is on, then argument number x is printed. s1 - String, argument number 1. If selected, printed as is. s2 - String, argument number 2. If selected, printed in brackets. n - Int, argument 3. If selected, printed preceded by equals sign. f=0 is special: print s1,s2, and interpret n as a char. */ #ifdef DEBUG debug(f,s1,s2,n) int f, n; char *s1, *s2; { static char s[200]; char *sp = s; if (!deblog) return; /* If no debug log, don't */ switch (f) { case F000: /* 0, print both strings, */ sprintf(sp,"%s%s%c\n",s1,s2,n); /* and interpret n as a char */ zsout(ZDFILE,s); break; case F001: /* 1, "=n" */ sprintf(sp,"=%d\n",n); zsout(ZDFILE,s); break; case F010: /* 2, "[s2]" */ sprintf(sp,"[%s]\n",s2); zsout(ZDFILE,""); break; case F011: /* 3, "[s2]=n" */ sprintf(sp,"[%s]=%d\n",s2,n); zsout(ZDFILE,s); break; case F100: /* 4, "s1" */ zsoutl(ZDFILE,s1); break; case F101: /* 5, "s1=n" */ sprintf(sp,"%s=%d\n",s1,n); zsout(ZDFILE,s); break; case F110: /* 6, "s1[s2]" */ sprintf(sp,"%s[%s]\n",s1,s2); zsout(ZDFILE,s); break; case F111: /* 7, "s1[s2]=n" */ sprintf(sp,"%s[%s]=%d\n",s1,s2,n); zsout(ZDFILE,s); break; default: sprintf(sp,"\n?Invalid format for debug() - %d\n",n); zsout(ZDFILE,s); } } #endif #ifdef TLOG /* T L O G -- Log a record in the transaction file */ /* Call with a format and 3 arguments: two strings and a number: f - Format, a bit string in range 0-7, bit x is on, arg #x is printed. s1,s2 - String arguments 1 and 2. n - Int, argument 3. */ tlog(f,s1,s2,n) int f; long n; char *s1, *s2; { static char s[200]; char *sp = s; int x; if (!tralog) return; /* If no transaction log, don't */ switch (f) { case F000: /* 0 (special) "s1 n s2" */ sprintf(sp,"%s %ld %s\n",s1,n,s2); zsout(ZTFILE,s); break; case F001: /* 1, " n" */ sprintf(sp," %ld\n",n); zsout(ZTFILE,s); break; case F010: /* 2, "[s2]" */ x = strlen(s2); if (s2[x] == '\n') s2[x] = '\0'; sprintf(sp,"[%s]\n",s2); zsout(ZTFILE,""); break; case F011: /* 3, "[s2] n" */ x = strlen(s2); if (s2[x] == '\n') s2[x] = '\0'; sprintf(sp,"[%s] %ld\n",s2,n); zsout(ZTFILE,s); break; case F100: /* 4, "s1" */ zsoutl(ZTFILE,s1); break; case F101: /* 5, "s1: n" */ sprintf(sp,"%s: %ld\n",s1,n); zsout(ZTFILE,s); break; case F110: /* 6, "s1 s2" */ x = strlen(s2); if (s2[x] == '\n') s2[x] = '\0'; sprintf(sp,"%s %s\n",s1,s2); zsout(ZTFILE,s); break; case F111: /* 7, "s1 s2: n" */ x = strlen(s2); if (s2[x] == '\n') s2[x] = '\0'; sprintf(sp,"%s %s: %ld\n",s1,s2,n); zsout(ZTFILE,s); break; default: sprintf(sp,"\n?Invalid format for tlog() - %ld\n",n); zsout(ZTFILE,s); } } #endif ermsg(msg) char *msg; { /* Print error message */ if (!quiet) fprintf(stderr,"\r\n%s - %s\n","PC-KERMIT>",msg); tlog(F110,"Error -",msg,0l); } perror(s) char *s; { extern int errno; fprintf(stderr," Error %d, %s \n ",errno,s); } /* S C R E E N -- Screen display function */ /* screen(f,c,n,s) f - argument descriptor c - a character or small integer n - a long integer s - a string. Fill in this routine with the appropriate display update for the system. This version is for a dumb tty. */ screen(f,c,n,s) int f; long n; char c; char *s; { static int p = 0; /* Screen position */ int len; /* Length of string */ char buf[120]; /* Output buffer */ len = strlen(s); /* Length of string */ if (!displa || quiet) return; /* No update if display flag off */ switch (f) { case SCR_FN: /* filename */ conoll(""); conol(s); conoc(SP); p = len + 1; return; case SCR_AN: /* as-name */ if (p + len > 75) { conoll(""); p = 0; } conol("=> "); conol(s); if ((p += (len + 3)) > 78) { conoll(""); p = 0; } return; case SCR_FS: /* file-size */ sprintf(buf,", Size: %ld",n); conoll(buf); p = 0; return; case SCR_DT: if ( p != 0) conoll(""); sprintf(buf,"File creation date: %2.2s/%2.2s/%2.2s -%s ",&s[4],&s[6],&s[2],& conoll(buf); p =0; return; case SCR_XD: /* x-packet data */ conoll(""); conoll(s); p = 0; return; case SCR_ST: /* File status */ switch (c) { case ST_OK: /* Transferred OK */ if ((p += 5) > 78) { conoll(""); p = 0; } conol(" [OK]"); p += 5; return; case ST_DISC: /* Discarded */ if ((p += 12) > 78) { conoll(""); p = 0; } conol(" [discarded]"); p += 12; return; case ST_INT: /* Interrupted */ if ((p += 14) > 78) { conoll(""); p = 0; } conol(" [interrupted]"); p += 14; return; case ST_SKIP: /* Skipped */ conoll(""); conol("Skipping "); conoll(s); p = 0; return; default: conoll("*** screen() called with bad status ***"); p = 0; return; } case SCR_PN: /* Packet number */ sprintf(buf,"\n%s: %ld",s,n); conol(buf); p += strlen(buf); return; case SCR_PT: /* Packet type or pseudotype */ if (c == 'Y') return; /* Don't bother with ACKs */ if (c == 'D') { /* Only show every 4th data packet */ if (n % 4) return; c = '.'; } else if (debugp) { sprintf(buf,"\n%s: %ld",s,n); conoll(buf); p = 0; return; } if (p++ > 78) { /* If near right margin, */ conoll(""); /* Start new line */ p = 1; /* and reset counter. */ } conoc(c); /* Display the character. */ return; case SCR_TC: /* transaction complete */ conoc(BEL); return; case SCR_EM: /* Error message */ conoll(""); conoc('?'); conoll(s); p = 0; return; /* +1 */ case SCR_WM: /* Warning message */ conoll(""); conoll(s); p = 0; return; case SCR_TU: /* Undelimited text */ if ((p += len) > 78) { conoll(""); p = len; } conol(s); return; case SCR_TN: /* Text delimited at beginning */ conoll(""); conol(s); p = len; return; case SCR_TZ: /* Text delimited at end */ if ((p += len) > 78) { conoll(""); } conoll(s); p = 0; return; case SCR_QE: /* Quantity equals */ conoll(""); sprintf(buf,"%s: %ld",s,n); conoll(buf); p = 0; return; default: conoll("*** screen() called with bad object ***"); p = 0; return; } } ################################################################## ## LCKUSER.DOC C K U U S R -- "User Interface" for PC-DOS Kermit C M D L I N -- Get arguments from command line cmdlin() { D O A R G -- Do a command-line argument. */ doarg(x) char x = character on command line to be evaluated U S A G E -- Print help message , how to use usage() F A T A L -- Print error message and exit to dos through doexit() fatal(msg) char *msg = message to print D O E X I T -- Close files, turn of interrupt and exit from the program doexit(exitstat) int exitstat = type of exit to pass to exit(). B L D L E N -- Make length-encoded copy of string */ char *bldlen(str,dest) char *str = string to copy char *dest = destination string D E B O P N -- Open a debugging file */ debopn(s) char *s = name of debug file C H K S P D -- Check if argument is a valid baud rate */ chkspd(x) int x = baud rate to check I N T M S G -- Issue message about terminal interrupts during file transfer if not quiet intmsg(n) long n = if 1 print message else print ignored C H K I N T -- Check for console interrupts during file transfer and execute them if any. Ignored if quiet = TRUE chkint() D E B U G -- Enter a record in the debugging log debug(f,s1,s2,n) Call with a format, two strings, and a number: int f - Format, a bit string in range 0-7. If bit x is on, then argument number x is printed. char *s1 - String, argument number 1. Printed as is. char *s2 - String, argument number 2. Printed in brackets. int n - Int, argument 3. Printed preceded by equals sign. f=0 is special: print s1,s2, and interpret n as a char. T L O G -- Log a record in the transaction file tlog(f,s1,s2,n) Call with a format and 3 arguments: two strings and a number: int f - Format, a bit string in range 0-7, bit x is on, arg #x is printed. char *s1,s2 - String arguments 1 and 2. long n - Int, argument 3. E R M S G -- Print an error message on file stderr ermsg(msg) char *msg = message to print P E R R O R -- Print a error message and associated errno perror(s) char *s = message to print S C R E E N -- Screen display function screen(f,c,n,s) int f - argument descriptor (format to use) int c - a character or small integer long n - a long integer (used for packet number) char *s - a string to print. The possible values of f currently accepted are defined as SCR_??? in the lckerm.h header file ################################################################## ## LCKUSER.ERR Lattice C Compiler (Phase 1) V2.15 Copyright (C) 1982 Lattice, Inc. ################################################################## ## LCKUSR.H /* C K U U S R . H -- Symbol definitions for C-Kermit ckuus*.c modules */ /* Author: Frank da Cruz (SY.FDC@CU20B), Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* --------- Not for PC-DOS version #ifndef vax11c #include #endif ---------------------- */ /* Values associated with top-level commands, must be 0 or greater. */ #define XXBYE 0 /* BYE */ #define XXCLE 1 /* CLEAR */ #define XXCLO 2 /* CLOSE */ #define XXCON 3 /* CONNECT */ #define XXCPY 4 /* COPY */ #define XXCWD 5 /* CWD (Change Working Directory) */ #define XXDEF 6 /* DEFINE (a command macro) */ #define XXDEL 7 /* (Local) DELETE */ #define XXDIR 8 /* (Local) DIRECTORY */ #define XXDIS 9 /* DISCONNECT */ #define XXECH 10 /* ECHO */ #define XXEXI 11 /* EXIT */ #define XXFIN 12 /* FINISH */ #define XXGET 13 /* GET */ #define XXHLP 14 /* HELP */ #define XXINP 15 /* INPUT */ #define XXLOC 16 /* LOCAL */ #define XXLOG 17 /* LOG */ #define XXMAI 18 /* MAIL */ #define XXMOU 19 /* (Local) MOUNT */ #define XXMSG 20 /* (Local) MESSAGE */ #define XXOUT 21 /* OUTPUT */ #define XXPAU 22 /* PAUSE */ #define XXPRI 23 /* (Local) PRINT */ #define XXQUI 24 /* QUIT */ #define XXREC 25 /* RECEIVE */ #define XXREM 26 /* REMOTE */ #define XXREN 27 /* (Local) RENAME */ #define XXSEN 28 /* SEND */ #define XXSER 29 /* SERVER */ #define XXSET 30 /* SET */ #define XXSHE 31 /* Command for SHELL */ #define XXSHO 32 /* SHOW */ #define XXSPA 33 /* (Local) SPACE */ #define XXSTA 34 /* STATISTICS */ #define XXSUB 35 /* (Local) SUBMIT */ #define XXTAK 36 /* TAKE */ #define XXTRA 37 /* TRANSMIT */ #define XXTYP 38 /* (Local) TYPE */ #define XXWHO 39 /* (Local) WHO */ #define XXDIAL 40 /* (Local) dial */ #define XXLOGI 41 /* (Local) logon */ /* SET parameters */ #define XYBREA 0 /* BREAK simulation */ #define XYCHKT 1 /* Block check type */ #define XYDEBU 2 /* Debugging */ #define XYDELA 3 /* Delay */ #define XYDUPL 4 /* Duplex */ #define XYEOL 5 /* End-Of-Line (packet terminator) */ #define XYESC 6 /* Escape character */ #define XYFILE 7 /* File Parameters */ #define XYFILN 0 /* Naming */ #define XYFILT 1 /* Type */ #define XYFILW 2 /* Warning */ #define XYFILD 3 /* ... */ /* empty space to add something */ #define XYFLOW 9 /* Flow Control */ #define XYHAND 10 /* Handshake */ #define XYIFD 11 /* Incomplete File Disposition */ #define XYIMAG 12 /* "Image Mode" */ #define XYINPU 13 /* INPUT command parameters */ #define XYLEN 14 /* Maximum packet length to send */ #define XYLINE 15 /* Communication line to use */ #define XYLOG 16 /* Log file */ #define XYMARK 17 /* Start of Packet mark */ #define XYNPAD 18 /* Amount of padding */ #define XYPADC 19 /* Pad character */ #define XYPARI 20 /* Parity */ #define XYPAUS 21 /* Interpacket pause */ #define XYPROM 22 /* Program prompt string */ #define XYQBIN 23 /* 8th-bit prefix */ #define XYQCTL 24 /* Control character prefix */ #define XYREPT 25 /* Repeat count prefix */ #define XYRETR 26 /* Retry limit */ #define XYSPEE 27 /* Line speed (baud rate) */ #define XYTACH 28 /* Character to be doubled */ #define XYTIMO 29 /* Timeout interval */ #define XYMODM 30 /* Modem type */ #define XYSEND 31 /* SEND parameters, used with some of the above */ #define XYRECV 32 /* RECEIVE parameters, ditto */ /* REMOTE command symbols */ #define XZCPY 0 /* Copy */ #define XZCWD 1 /* Change Working Directory */ #define XZDEL 2 /* Delete */ #define XZDIR 3 /* Directory */ #define XZHLP 4 /* Help */ #define XZHOS 5 /* Host */ #define XZKER 6 /* Kermit */ #define XZLGI 7 /* Login */ #define XZLGO 8 /* Logout */ #define XZMAI 9 /* Mail */ #define XZMOU 10 /* Mount */ #define XZMSG 11 /* Message */ #define XZPRI 12 /* Print */ #define XZREN 13 /* Rename */ #define XZSET 14 /* Set */ #define XZSPA 15 /* Space */ #define XZSUB 16 /* Submit */ #define XZTYP 17 /* Type */ #define XZWHO 18 /* Who */ /* Symbols for logs */ #define LOGD 0 /* Debugging */ #define LOGP 1 /* Packets */ #define LOGS 2 /* Session */ #define LOGT 3 /* Transaction */ ################################################################## ## LCKWART.ARF cs+ lckwart lckwart lckwart lcms+lcs ################################################################## ## LCKWART.C char *wartv = "Wart Version 1A(003) 27 May 85"; /* W A R T */ /* pre-process a lex-like file into a C program. Author:Jeff Damens, Columbia University Center for Computing Activites, 11/84. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. * input format is: * lines to be copied | %state * %% * | CHAR { actions } * ... * %% */ #include "lckdeb.h" /* Includes */ #include #include #define C_L 014 /* Formfeed */ #define SEP 1 /* Token types */ #define LBRACK 2 #define RBRACK 3 #define WORD 4 #define COMMA 5 /* Storage sizes */ #define MAXSTATES 50 /* max number of states */ #define MAXWORD 50 /* max # of chars/word */ #define SBYTES ((MAXSTATES+7)/8) /* # of bytes for state bitmask */ /* Name of wart function in generated program */ #ifndef FNAME #define FNAME "wart" #endif /* Structure for state information */ struct trans { CHAR states[SBYTES]; /* included states */ int anyst; /* true if this good from any state */ CHAR inchr; /* input character */ int actno; /* associated action */ struct trans *nxt; }; /* next transition */ typedef struct trans *Trans; char *malloc(); /* Returns pointer (not int) */ /* Variables and tables */ int lines,nstates,nacts; char tokval[MAXWORD]; int tbl[MAXSTATES*128]; char *txt1 = "\n#define BEGIN state =\n\nint state = 0;\n\n"; char *fname = FNAME; /* function name goes here */ /* rest of program... */ char *txt2 = "()\n\ {\n\ int c,actno;\n\ extern int tbl[];\n\ while (1) {\n\ c = input();\n\ if ((actno = tbl[c + state*128]) != -1)\n\ switch(actno) {\n"; /* this program's output goes here, followed by final text... */ char *txt3 = "\n }\n }\n\}\n\n"; /* * turn on the bit associated with the given state * */ setstate(state,t) int state; Trans t; { int idx,msk; idx = state/8; /* byte associated with state */ msk = 0x80 >> (state % 8); /* bit mask for state */ t->states[idx] |= msk; } /* * see if the state is involved in the transition * */ teststate(state,t) int state; Trans t; { int idx,msk; idx = state/8; msk = 0x80 >> (state % 8); return(t->states[idx] & msk); } /* * read input from here... * */ Trans rdinput(infp,outfp) FILE *infp,*outfp; { Trans x,rdrules(); lines = 1; /* line counter */ nstates = 0; /* no states */ nacts = 0; /* no actions yet */ fprintf(outfp,"\n%c* WARNING -- This C source program generated by ",'/'); fprintf(outfp,"Wart preprocessor. */\n"); fprintf(outfp,"%c* Do not edit this file; edit the Wart-format ",'/'); fprintf(outfp,"source file instead, */\n"); fprintf(outfp,"%c* and then run it through Wart to produce a new ",'/'); fprintf(outfp,"C source file. */\n\n"); fprintf(outfp,"%c* Wart Version Info: */\n",'/'); fprintf(outfp,"char *wartv = \"%s\";\n\n",wartv); initial(infp,outfp); /* read state names, initial defs */ prolog(outfp); /* write out our initial code */ x = rdrules(infp,outfp); /* read rules */ epilogue(outfp); /* write out epilogue code */ return(x); } /* * initial - read initial definitions and state names. Returns * on EOF or %%. * */ initial(infp,outfp) FILE *infp,*outfp; { int c; char wordbuf[MAXWORD]; while ((c = getc(infp)) != EOF) { if (c == '%') { rdword(infp,wordbuf); if (strcmp(wordbuf,"states") == 0) rdstates(infp,outfp); else if (strcmp(wordbuf,"%") == 0) return; else fprintf(outfp,"%%%s",wordbuf); } else putc(c,outfp); if (c == '\n') lines++; } } /* * boolean function to tell if the given character can be part of * a word. * */ isin(s,c) char *s; int c; { for (; *s != '\0'; s++) if (*s == c) return(1); return(0); } isword(c) int c; { static char special[] = ".%_-$@"; /* these are allowable */ return(isalnum(c) || isin(special,c)); } /* * read the next word into the given buffer. * */ rdword(fp,buf) FILE *fp; char *buf; { int len = 0,c; while (isword(c = getc(fp)) && ++len < MAXWORD) *buf++ = c; *buf++ = '\0'; /* tie off word */ ungetc(c,fp); /* put break char back */ } /* * read state names, up to a newline. * */ rdstates(fp,ofp) FILE *fp,*ofp; { int c; char wordbuf[MAXWORD]; while ((c = getc(fp)) != EOF && c != '\n') { if (isspace(c) || c == C_L) continue; /* skip whitespace */ ungetc(c,fp); /* put char back */ rdword(fp,wordbuf); /* read the whole word */ enter(wordbuf,++nstates); /* put into symbol tbl */ fprintf(ofp,"#define %s %d\n",wordbuf,nstates); } lines++; } /* * allocate a new, empty transition node * */ Trans newtrans() { Trans new; int i; new = (Trans) malloc(sizeof (struct trans)); for (i=0; istates[i] = 0; new->anyst = 0; new->nxt = NULL; return(new); } /* * read all the rules. * */ Trans rdrules(fp,out) FILE *fp,*out; { Trans head,cur,prev; int curtok,i; head = cur = NULL; while ((curtok = gettoken(fp)) != SEP) switch(curtok) { case LBRACK: if (cur == NULL) cur = newtrans(); else fatal("duplicate state list"); statelist(fp,cur);/* set states */ continue; /* prepare to read char */ case WORD: if (strlen(tokval) != 1) fatal("multiple chars in state"); if (cur == NULL) { cur = newtrans(); cur->anyst = 1; } cur->actno = ++nacts; cur->inchr = tokval[0]; if (head == NULL) head = cur; else prev->nxt = cur; prev = cur; cur = NULL; copyact(fp,out,nacts); break; default: fatal("bad input format"); } return(head); } /* * read a list of (comma-separated) states, set them in the * given transition. * */ statelist(fp,t) FILE *fp; Trans t; { int curtok,sval; curtok = COMMA; while (curtok != RBRACK) { if (curtok != COMMA) fatal("missing comma"); if ((curtok = gettoken(fp)) != WORD) fatal("missing state name"); if ((sval = lkup(tokval)) == -1) { fprintf(stderr,"state %s undefined\n",tokval); fatal("undefined state"); } setstate(sval,t); curtok = gettoken(fp); } } /* * copy an action from the input to the output file * */ copyact(inp,outp,actno) FILE *inp,*outp; int actno; { int c,bcnt; fprintf(outp,"case %d:\n",actno); while (((c = getc(inp)) != '\n') && (isspace(c) || c == C_L)); if (c == '{') { bcnt = 1; putc(c,outp); while (bcnt > 0 && (c = getc(inp)) != EOF) { if (c == '{') bcnt++; else if (c == '}') bcnt--; else if (c == '\n') lines++; putc(c,outp); } if (bcnt > 0) fatal("action doesn't end"); } else { while (c != '\n' && c != EOF) { putc(c,outp); c = getc(inp); } lines++; } fprintf(outp,"\nbreak;\n"); } /* * find the action associated with a given character and state. * returns -1 if one can't be found. * */ faction(hd,state,chr) Trans hd; int state,chr; { while (hd != NULL) { if (hd->anyst || teststate(state,hd)) if (hd->inchr == '.' || hd->inchr == chr) return(hd->actno); hd = hd->nxt; } return(-1); } /* * empty the table... * */ emptytbl() { int i; for (i=0; i 1) { if ((infile = fopen(argv[1],"r")) == NULL) { fprintf(stderr,"Can't open %s\n",argv[1]); fatal("unreadable input file"); } } else infile = stdin; if (argc > 2) { if ((outfile = fopen(argv[2],"w")) == NULL) { fprintf(stderr,"Can't write to %s\n",argv[2]); fatal("bad output file"); } } else outfile = stdout; clrhash(); /* empty hash table */ head = rdinput(infile,outfile); /* read input file */ emptytbl(); /* empty our tables */ for (state = 0; state <= nstates; state++) for (c = 1; c < 128; c++) addaction(faction(head,state,c),state,c); /* find actions, add to tbl */ writetbl(outfile); copyrest(infile,outfile); printf("%d states, %d actions\n",nstates,nacts); #ifdef undef for (state = 1; state <= nstates; state ++) for (c = 1; c < 128; c++) if (tbl[state*128 + c] != -1) printf("state %d, chr %d, act %d\n", state,c,tbl[state*128 + c]); #endif exit(GOOD_EXIT); } /* * fatal error handler * */ fatal(msg) char *msg; { fprintf(stderr,"error in line %d: %s\n",lines,msg); exit(BAD_EXIT); } prolog(outfp) FILE *outfp; { int c; while ((c = *txt1++) != '\0') putc(c,outfp); while ((c = *fname++) != '\0') putc(c,outfp); while ((c = *txt2++) != '\0') putc(c,outfp); } epilogue(outfp) FILE *outfp; { int c; while ((c = *txt3++) != '\0') putc(c,outfp); } copyrest(in,out) FILE *in,*out; { int c; while ((c = getc(in)) != EOF) putc(c,out); } /* * gettoken - returns token type of next token, sets tokval * to the string value of the token if appropriate. * */ gettoken(fp) FILE *fp; { int c; while (1) { /* loop if reading comments... */ do { c = getc(fp); if (c == '\n') lines++; } while ((isspace(c) || c == C_L)); /* skip whitespace */ switch(c) { case EOF: return(SEP); case '%': if ((c = getc(fp)) == '%') return(SEP); tokval[0] = '%'; tokval[1] = c; rdword(fp,tokval+2); return(WORD); case '<': return(LBRACK); case '>': return(RBRACK); case ',': return(COMMA); case '/': if ((c = getc(fp)) == '*') { rdcmnt(fp); /* skip over the comment */ continue; } /* and keep looping */ else { ungetc(c); /* put this back into input */ c = '/'; } /* put character back, fall thru */ default: if (isword(c)) { ungetc(c,fp); rdword(fp,tokval); return(WORD); } else fatal("Invalid character in input"); } } } /* * skip over a comment * */ rdcmnt(fp) FILE *fp; { int c,star,prcnt; prcnt = star = 0; /* no star seen yet */ while (!((c = getc(fp)) == '/' && star)) { if (c == EOF || (prcnt && c == '%')) fatal("Unterminated comment"); prcnt = (c == '%'); star = (c == '*'); if (c == '\n') lines++; } } /* * symbol table management for wart * * entry points: * clrhash - empty hash table. * enter - enter a name into the symbol table * lkup - find a name's value in the symbol table. * */ #define HASHSIZE 101 /* # of entries in hash table */ struct sym { char *name; /* symbol name */ int val; /* value */ struct sym *hnxt; } /* next on collision chain */ *htab[HASHSIZE]; /* the hash table */ /* * empty the hash table before using it... * */ clrhash() { int i; for (i=0; iname = copy(name); cur->val = svalue; cur->hnxt = htab[h]; htab[h] = cur; } /* * find name in the symbol table, return its value. Returns -1 * if not found. * */ lkup(name) char *name; { struct sym *cur; for (cur = htab[hash(name)]; cur != NULL; cur = cur->hnxt) if (strcmp(cur->name,name) == 0) return(cur->val); return(-1); } ################################################################## ## LCKWART.DOC WART Wart is a program that implements a small subset of the Unix 'lex' lexical analyzer generator. Unlike lex, wart may be distributed without requirement for a Unix license. Wart was written by Jeff Damens at the Columbia University Center of Computing Activities to facilitate development of Unix Kermit. Wart is intended for production of state table switchers. It allows a set of states to be defined, along with a function for getting input, and a table of state transitions. A C program is generated which performs actions and switches states based on the current state and the input. The following short program demonstrates some of the capabilities and limitations of Wart. The program accepts from the command line a binary number, preceded by an optional minus sign, and optionally containing a fractional part. It prints the decimal equivalent. #include int state, s = 1, m = 0, d; float f; char *b; %states sign mantissa fraction /* Declare wart states */ %% /* Begin state table */ - { s = -1; BEGIN mantissa; } /* Look for sign */ 0 { m = 0; BEGIN mantissa; } /* Got digit, start mantissa */ 1 { m = 1; BEGIN mantissa; } . { fatal("bad input"); } /* Detect bad format */ 0 { m *= 2; } /* Accumulate mantissa */ 1 { m = 2 * m + 1; } $ { printf("%d\n", s * m); return; } . { f = 0.0; d = 1; BEGIN fraction; } /* Start fraction */ 0 { d *= 2; } /* Accumulate fraction */ 1 { d *= 2; f += 1.0 / d; } $ { printf("%f\n", s * (m + f) ); return; } . { fatal("bad input"); } %% input() { /* Define input() function */ int x; return(((x = *b++) == '\0') ? '$' : x ); } fatal(s) char *s; { /* Error exit */ fprintf(stderr,"fatal - %s\n",s); exit(1); } main(argc,argv) int argc; char **argv; { /* Main program */ if (argc < 1) exit(1); b = *++argv; state = sign; /* Initialize state */ wart(); /* Invoke state switcher */ exit(0); /* Done */ } The wart program accepts as input a C program containing lines that start with "%" or sections delimited by "%%". The directive "%states" declares the program's states. The section enclosed by "%%" markers is the state table, with entries of the form X { action } which is read as "if in state with input X perform { action }" The optional field tells the current state or states the program must be in to perform the indicated action. If no state is specified, then it means the action will be performed regardless of the current state. If more than one state is specifed, then the action will be performed in any of the listed states. Multiple states are separated by commas. The required input field consists of a single literal character. When in the indicated state, if the input is the specified character, then the associated action will be performed. The character '.' matches any input character. No pattern matching or range notation is provided. The input character is obtained from the input() function, which you must define. It should be alphanumeric, or else one of the characters ".% -$@" (quotes not included). Note that the program above recognize the binary point '.' through a ruse. The action is a series of zero or more C language statements, enclosed in curly braces. The BEGIN macro is defined simply to be "state = ", as in lex. The wart() function is generated by the wart program based on the state declarations and the state transition table. It loops through calls to input(), using the result to index into a big case statement it has created from the state table. Wart is invoked as follows: wart (Input from stdin, output to stdout) wart fn1 (Input from fn1, output to stdout) wart fn1 fn2 (Input from fn1, output to fn2. Example: wart a.w a.c) Wart programs have the conventional filetype '.w'. ################################################################## ## PCKCOMP.BAT lc1 >lckmain.err lckmain -mS -b type lckmain.err lc2 lckmain lc1 >lckprot.err lckprot -mS -b type lckprot.err lc2 lckprot lc1 >lckfns1.err lckfns1 -mS -b type lckfns1.err lc2 lckfns1 lc1 >lckfns2.err lckfns2 -mS -b type lckfns2.err lc2 lckfns2 lc1 >lckfns3.err lckfns3 -mS -b type lckfns3.err lc2 lckfns3 lc1 >lckuser.err lckuser -mS -b type lckuser.err lc2 lckuser lc1 >lckfio.err lckfio -mS -b type lckfio.err lc2 lckfio lc1 >lcktio.err lcktio -mS -b type lcktio.err lc2 lcktio ################################################################## ## PCKERMIT.ARF cs+ lckmain+ lckprot+ lckfns1+ lckfns2+ lckfns3+ lckuser+ lckfio+ lcktio pckermit pckermit/map gfts+gfs+ gfcs+lcms+lcs ################################################################## ## PCKERMIT.DOC PCKERMIT.DOC 12/10/85 PC-DOS Kermit with Sliding Windows Rev 1.18 ---------------------------------- 12/10/85 1. Source Code Implementation Documentation =========================================== By Larry Jordan and Jan van der Eijk Revised by John Mulligan The Kermit software modules contained in this package are modified versions of the C-KERMIT 4C modules distributed by Columbia University in June, 1985. The modules were modified to work with the Lattice C compiler and The Greenleaf Functions to produce Kermit software compatible with PC-DOS and MS-DOS. They were also modified to add two new features to the software--file attributes and sliding windows. File attributes have been in the official Kermit Protocol specification for some time, but the sliding windows concept has just been approved. The 4C version of Kermit was chosen because it was written for maximum portability to different operating systems, and it was the most robust version available. The 4C version was written for Unix and Xenix operating systems, but the similarities with PC-DOS made it relatively easy to port to that system. The 4C version contained all defined Kermit capabilities except file attributes. None of these capabilities were removed during our port of 4C to PC-DOS. Some functions had to be rewritten for PC-DOS compatibility such as filename conventions and wildcard filename expansion. Server support and non-protocol related code, such as terminal emulation, was removed from 4C during the port to reduce the size and complexity of the PC-DOS Kermit module. The Lattice C compiler was chosen because of its compatibility with Unix C and because of the quality of code it produces. The Microsoft C Version 3.0 would be a better choice now because of its superior error-checking and Unix compatibility; it was not available when we started the 4C port. The function calls are compatible with Lattice C Version 2.15. The modules could be compiled under Microsoft C 3.0 with few changes. Microsoft provides the Lattice-to-Microsoft transition header files. [NOTE: Their is a reported bug in the Microsoft C Compiler which causes an error in the Kermit Type 3 (CRC-16) Checksum algorithm. Beware!] [NOTE: Lattice C allows nested comments, which are not allowed by Microsoft C compiler. Their may be some instances of nested comments. LCKFNS3 has at least one area that was commented out that results in a nested comment.] The Greenleaf Functions General and COMM Libraries were chosen for file and communications I/O because the functions provide all the necessary capabilities. The functions are modestly priced and include source code. All uses of these functions are noted in comments in the source code. A software vendor can substitute another vendor's functions in place of The Greenleaf Functions or use functions generated inhouse. Unlike most communications software software and protocols, Kermit does check parity if parity is enabled, and the protocol will not function properly unless the selected parity matches on both ends of the communications link. Implementation of PCKermit --------------------------- The PC-DOS Kermit provided in this package can be implemented in one of two ways. A stand-alone version of the software can be executed from the DOS command line or through a software SYSTEM, FORK or SHELL call. A linkable version of the software can be linked to smart terminal object modules and the protocol executed from within the smart terminal program. The linkable version can also be added to host or bulletin board software. The software for both options is provided in the package. Stand-Alone Kermit ------------------ A stand-alone version of the PC-DOS Kermit is included in this package. The file is called PCKERMIT.EXE. This file was created by linking the LCKMAIN.OBJ module to the other Kermit modules. Execution of the stand-alone Kermit program requires the same command parameters and carrier conditions regardless of the execution method. The module runs as a "one-shot" execution then returns to the caller. A single file or multiple files (wildcard filename) are transferred until execution is completed or the transfer is abnormally aborted. If execution is performed by the user from the DOS command line, termination of PCKERMIT returns control to PC-DOS. If execution is performed from within a software package using a SYSTEM, FORK or SHELL call, termination of PCKERMIT returns control to the next executable statement after the calling statement. The command syntax of the stand-alone Kermit program is shown in Figure 1. An example of execution from the DOS command line is as follows: PCKERMIT -l COM1 -b 1200 -p n -m 8 -w -r This same Kermit execution can be started from within a Lattice C program with the following function call: system(" PCKERMIT -l COM1 -b 1200 -p n -m 8 -w -r"); Both methods allow you to receive a file through serial port COM1 at 1200 bps using no parity. They also request an 8 packet sliding window from the sender and allow overwriting of existing files. CRC-16 error-checking is automatically requested. If sliding windows are not supported by the sending computer, PCKERMIT reverts to "classic" half-duplex Kermit operation. If the sender cannot support CRC-16 the next best common error-check technique is negotiated. ---------------------------------------------------------------- Options: PCKERMIT version 1.17, December 6, 1985 Usage: PCKERMIT [-x arg [-x arg]...[-yyy]..]] x is an option that requires an argument, y an option with no argument: -s file(s) send -r receive -a name alternate name, used with -s, -r -h help - print this message settings -- default -l line communication line device ( COM1, COM2 ) [COM1] -b baud line speed, e.g. 1200 [1200] -p x parity, x is one of e,o,m,s,n [N] -m size maximum window size to use ( <= 31 ) [31] -n non binary file transfer, affect CR/LF -t line turnaround handshake = xon, half duplex -w write over preexisting files -q be quiet during file transfer -c carrier detect signal required to be present Fi Note 1: Use -d (debug) only if compiled with debug statements left in place. (hidden option) Note 2: If -t is used, -m should not be used. Note 3: The usage of -w is reversed from standard Columbia CKERMIT. Figure 1. PCKERMIT command syntax. ---------------------------------------------------------------- Regardless of the technique used to initiate operation of the stand-alone Kermit program, the software requires the same serial port and modem conditions. The Kermit module sets up its own send and receive interupt buffers, but it does not establish a carrier with a remote system. The user must initialize a selected serial port with bit rate, parity, and stop bits then establish a carrier with a remote host based on these parameters. After the carrier is established and the remote Kermit is started, the user can start the local stand-alone Kermit. Linkable PC-DOS Kermit ---------------------- The PC-DOS Kermit modules can be easily linked to existing smart terminal or host software written in the C language. Linking the modules to Pascal, compiled BASIC or assembly language requires a thorough knowledge of both C and the terminal or host program language. Before the linking is performed some software changes have to be made. The special link module is the LCKLINK.C file. This module contains several local and global variables that must be initialized. The variables can be initialized by reference to parameters selected or established in the smart terminal program or they can be hard coded for specific applications. All variables that must be initialized are shown equal to question marks. For example, the parity variable is shown as parity=????. It should be noted that the LCKCLINK.C module replaces the LCKMAIN.C module used to create the stand-alone PCKERMIT. Another required change to facilitate direct link of Kermit to other software is in the module LCKUSER.C. The function "doexit()" must be modified to return to the smart terminal program rather than exit to DOS. Specifically, the "exit();" statement must be changed to a "return;" statement. An existing smart terminal program should already contain functions or procedures to set up communication buffers and to initialize communication ports. A new software product may not have these functions established. In any event, the LCKTIO.C module must be modified to match the existing smart terminal communication functions. The "ttopen()", "ttclose()" and "ttvt()" functions should be studied, and the noted Greenleaf communication functions modified as necessary. Existing functions may be used to replace these functions. Code comments and Greenleaf documentation should be studied before these routines are modified--the sequence of the function calls in these functions are sometimes critical to interupt buffer setup and operation. A change in the sequence can either cause buffer setup problems or cause the interupt sending or receiving of characters to malfunction. Finally, screen I/O performed by PC-DOS Kermit is done in the LCKUSER.C module. A smart terminal vendor will probably want to change the TTY style output to a special file transfer screen format. All screen I/O are contained in the screen function. The vendor can use display functions from a third party (i.e., Greenleaf or Blaise) or use functions written by the vendor to perform fast, full screen color output. DOS or BIOS calls can be used without slowing down the protocol as long as the calls do not have to scroll the screen or produce elaborate I/O. All PCKERMIT object files contained in this package were compiled using the Lattice C small model. This model uses NEAR calls in its code segment. If the PCKERMIT files are to be linked to software compiled under other Lattice models, the C source code must be recompiled using the selected model. Files for PCKERMIT ------------------ [The LCK*.C naming convention stands for "Lattice C Kermit" files] Filename | Description ------------------------------------------------------------------------------ LCKFIO C /* File I/O module */ LCKFNS1 C /* Protocol specific module 1 */ LCKFNS2 C /* Protocol specific module 2 */ LCKFNS3 C /* Windowing specific module */ LCKLINK C /* Module for linkable Kermit */ LCKMAIN C /* Main program for PCKERMIT */ LCKPROT W /* Protocol state table in Wart */ LCKPROT C /* Protocol state table in C */ LCKTIO C /* RS232 I/O and time module */ LCKUSER C /* User interface module */ LCKCMD H /* Command interface header */ LCKDEB H /* Debug header file */ LCKERM H /* PCKERMIT main header file */ LCKUSR H /* User interface header file */ STDIOS H /* Lattice and Greenleaf stdio.h */ PCKERMIT ARF /* PCKERMIT link file */ PCKERMIT EXE /* EXE file */ PCKERMIT MAP /* Map file */ LCKWART C /* Wart source code */ LCKWART EXE /* Wart EXE file */ LCKWART DOC /* Wart documentation */ Referenced Products ------------------- The Greenleaf Functions Greenleaf Software Inc. 2101 Hickory Drive Carrollton, TX 75006 (214) 446-8641 Lattice C. Compiler Lattice P.O. Box 3148 Glen Ellyn, IL 60138 (312) 858-7950 Microsoft C. Compiler Microsoft 10700 Northup Way Bellevue, WA 98004 Asynch Manager Blaise Computing Inc. 2034 Blake Street Berkley, CA 94704 (415) 540-5441 2. PCKERMIT.EXE USER GUIDE ========================== The following material supplements the section "Stand-Alone Kermit" (above): CHARACTERS DISPLAYED DURING TRANSFER ------------------------------------ During operation of the standalone PCKERMIT it may display the following: % Resend of last packet . Is printed every FOURTH data packet A Attributes packet (file length and creation date) B End of transmission packet F File Header N NAK packet Q Bad checksum or other packet error S Send-Init packet T Timeout Z End of file packet KEYBOARD INTERRUPTS ------------------- During a file transfer PCKERMIT responds (sometimes slowly) to the following keystrokes: CTRL-F to cancel File, CTRL-R to Resend current packet . CTRL-B to cancel Batch, CTRL-K to abort Kermit and exit CTRL-A for status report: These functions are available even at the start of PCKERMIT before it tells you they are available. In particular, Control-K can be used if the "Send-Init" exchange does not seem to be working. Please note that PCKERMIT checks the keyboard infrequently under some conditions. WAIT at least 20 - 30 seconds before repeating a keystroke in order to avoid stacking up repeated commands. This is particularly true of CTRL-F (cancel file) where you might cancel more than one file. Also, the Control-F and Control-B (cancel file and cancel batch) functions sometimes require a NAK and a resend or a timeout before they actually work. This is not a protocol problem, but is due to the way PCKERMIT flushes it buffer before sending the abort packet. In some cases, the flushing of the buffer truncates a packet and the following abort packet is not seen as a separate packet. Here is a more detailed explanation of the functions: CTRL-F will cancel an individual file in a wildcard transaction, but then continue with the next file in the batch. CTRL-B will cancel the entire batch of files, according to protocol, and then return you to the DOS prompt. CTRL-K will abort the file transfer and return you to the DOS prompt. PCKERMIT sends an Error packet indicating it is aborting, but otherwise does not worry about protocol. CTRL-R will resend the current packet; this can be used as a manual timeout. With windowing is in effect, this feature should be tried only as a last resort as it has not been fully tested. CTRL-A will give you a status report on the screen. The items covere are: CONTROL-A STATUS REPORT ----------------------- COMMENTS ^A Status report: file type: binary ;Details unknown file number: 1 ;Indicates which file of a multiple file wildcard batch transfer characters : 1291 ;On SEND: indicates number of characters output to the buffer, but not necessarily yet sent out the modem. On RECEIVE: indicates characters actually written to disk so far; others may already have been received to memory. window size: 31 ;The window size agreed upon after negotiation with the other Kermit. By definition, 0 means Classic (non-windowing) Kermit. Otherwise, the size may vary from 1 to 31. block check: 1 ;The block check type agreed upon after negotiation with the other Kermit. Type 1 = 1 byte checksum Type 2 = 2 byte checksum Type 3 = 3 byte CRC-16 checksum compression: 0 ;Is data compression (repeat count prefixing) in effect? 0 = No compression 1 = Compression 8th-bit prefixing: 1 ;Is 8th bit prefixing being used? 0 = No 1 = Yes FUNCTIONS SUPPORTED BY PCKERMIT (Subject to agreement by the other Kermit) ------------------------------- Windowing (full-duplex chanell required) Data Compression 8-bit quoting (whenever parity is not "none") File Attributes: File Length On Receive: accepts either the attribute ! (Ascii 33) - Approximate File Length in K bytes the attribute 1 (Ascii 49) - Exact file length On Send: sends the attribute 1 (Ascii 49) - Exact File Length Time and Date: Both Receive and Send the attribute # (Ascii 35) - Creation date NOTE: when PCKERMIT receives the creation date file attribute, it automatically writes the received file with that date, rather than the current date. PCKERMIT AT A GLANCE -------------------- Local operation: Yes Remote operation: ??? Transfers text files: Yes Transfers binary files: Yes Wildcard send: Yes ^X/^Y interruption: Yes (Different keystrokes, though) Filename collision avoidance: Yes Can time out: Yes 8th-bit prefixing: Yes Repeat count prefixing: Yes Alternate block checks: Yes Terminal emulation: No Communication settings: Yes Transmit BREAK: No IBM mainframe communication: ??? Transaction logging: No Session logging: No Raw transmit: No Act as server: No Talk to server: No Advanced server functions: No Advanced commands for servers: NO Local file management: ??? Handle file attributes: Yes Command/init files: No Command macros: No 3. ADDENDUM TO KERMIT PROTOCOL MANUAL, FIFTH EDITION ==================================================== The exact file size attribute is not covered in the Fifth Edition of the KERMIT PROTOCOL MANUAL. This is an addendum to that manual from Frank da Cruz, who maintains the Kermit protocol: "Date: Fri 2 Aug 85 From: Frank da Cruz Subject: attribute packets I was just looking at the protocol manual and realized that the current edition does not contain something which might be useful to you, namely two new attribute fields: "1" specifies the exact byte count of the file, and "2" specifies the byte size (e.g. "7" or "8"). This will be in the next edition. Many people have asked for a somewhat finer-grained way to report the file size than the number of K (e.g. some systems need to preallocate space, but in some unit other than K). - Frank" 4. ADDITIONAL PCKERMIT DEVELOPMENT NOTES ======================================== The following information supplements the "1. Source Code Implmentation Documentation" section above: NOTES ON THE WART PROGRAM ------------------------- The module LCKPROT.C is produced by putting LCKPROT.W through the LCKWART.EXE pre-preprocessor. The utility LCKWART.EXE was produced by compiling LCKWART.C, using the for Lattice C) Link automatic response file LCKWART.ARF. The documentatiion for WART is LCKWART.DOC. To summarize: LCKPROT.W Input file to LCKWART.EXE LCKPROT.C What we needed; WART was required only to produce this file. COMPILE.BAT FOR LATTICE C ------------------------- This is a small batch file that will compile a .C module into a .OBJ module. Messages/Errors are sent to a .ERR file. The LC1 and LC2 are the compiler modules supplied by LATTICE C. Here is the batch file, with comments to the right: lc1 >%1.err %1 -mS -b ;LC1 is the first phase of the Lattice C Compiler ;>%1 Messages/Errors are logged to filename.ERR ;%1 is the file being compiled ;-mS indicates the Small memory model ;-b indicates "force byte alignment" type %1.err ;type out the .ERR file lc2 %1 ;LC2 is the second phase of the Lattice C Compiler ;It's input is the .Q file produced by LC1 ;It's output is a .OBJ file to later be linked. Note that the small memory model (-mS) is being used; therfore, when linking later on use the CS.OBJ module and the LCMS.LIB and LCS.LIB library modules, which are the corresponding Small modules. PCKERMIT.ARF ------------ The following is the contents of the PCKERMIT.ARF file, which is an automatic response file for the LINK procedure. (This is for the LINKer supplied with MS-DOS 3.0) I have annotated on the right what each line/module does: cs+ -LATTICE C OBJECT MODULE (Supplied by Lattice) lckmain+ -MAIN PROGRAM lckprot+ -PROTOCOL STATE TABLE lckfns1+ -PROTOCOL FUNCTIONS 1 lckfns2+ -PROTOCOL FUNCTIONS 2 lckfns3+ -PROTOCOL FUNCTIONS 3 (Windowing specific) lckuser+ -USER MODULE; CONTAINS SCREEN I/O lckfio+ -FILE I/O lcktio -TERMINAL I/O pckermit -.EXE file pckermit -.MAP file gfts+gfs+gfcs+ -GREENLEAF LIBRARIES (Supplied by Greenleaf) lcms+lcs -LATTICE C LIBRARIES (Supplied by Lattice) NOTE: The Greenleaf functions are available from: Greenleaf Software Inc. 2101 Hickory Drive Carrollton, TX 75006 (214) 446-8641 NOTE: Lattice C is available from: Lattice, Inc. OR from Lifeboat Assoc. P.O. Box 3148 1651 Third Avenue Glen Ellyn, IL 60138 New York, N.Y. 10028 (312) 858-7950 (212) 860-0300 THE DEVELOPMENT ENVIRONMENT --------------------------- The development of this software was done using the following: Lattice C (ver. 2.15) Greenleaf Functions General Library Rev. L2-2.10 Greenleaf Functions Communications Library Rev. L3-1.2 MS-DOS 3.0 on an IBM/PC AT The Microsoft Linker supplied with MS-DOS 3.0 DIRECTORY OF FILES USED ----------------------- Here is a sample directory of files for version 1.17 of PCKERMIT.EXE: LCKWART ARF 43 8-14-85 3:11p PCKERMIT ARF 133 11-26-85 3:24p COMPILE BAT 46 7-27-85 3:41p PCKCOMP BAT 513 8-26-85 4:32p PCKLINK BAT 21 11-26-85 3:30p LCKFIO C 16159 12-06-85 12:01p LCKFNS1 C 28939 12-03-85 6:37p LCKFNS2 C 12347 8-06-85 10:04p LCKFNS3 C 11025 11-13-85 6:07p LCKLINK C 9806 11-16-85 12:21p LCKMAIN C 8064 10-31-85 4:35p LCKPROT C 14153 11-09-85 7:50p LCKTIO C 15302 11-06-85 9:45p LCKUSER C 22935 12-06-85 12:05p LCKWART C 13151 7-30-85 11:11a KWCHANGE DOC 4190 12-05-85 1:43p KWINDOW5 DOC 28020 12-05-85 1:20p LCKWART DOC 4119 6-05-85 5:06p PCKERMIT DOC 37691 12-06-85 2:30p LCKFIO ERR 70 12-06-85 3:17p LCKFNS1 ERR 128 12-06-85 3:14p LCKFNS2 ERR 128 12-06-85 3:15p LCKFNS3 ERR 70 12-06-85 3:15p LCKMAIN ERR 283 12-06-85 3:13p LCKPROT ERR 70 12-06-85 3:13p LCKTIO ERR 70 12-06-85 3:18p LCKUSER ERR 70 12-06-85 3:16p LC1 EXE 68736 5-02-85 4:49p LC2 EXE 70592 5-02-85 4:49p LCKWART EXE 31996 8-14-85 3:11p PCKERMIT EXE 70236 12-06-85 3:19p ASIC H 9012 10-16-85 9:59p ASIPORTS H 12017 10-16-85 9:03p CDISK H 4112 11-10-84 12:00p CSTDIO H 2139 7-27-85 3:44p CTYPE H 2198 5-02-85 4:49p FCNTL H 896 5-02-85 4:49p LCKCMD H 1625 7-29-85 4:17p LCKDEB H 2643 7-30-85 11:00a LCKERM H 3610 10-26-85 3:39p LCKUSR H 4460 7-30-85 11:00a STDIOS H 2031 7-27-85 3:38p TIMEDATE H 553 8-17-84 12:00a GFCS LIB 21504 4-26-85 4:54p GFS LIB 60416 11-10-84 12:00p GFTS LIB 9216 11-10-84 12:00p LCMS LIB 68096 5-02-85 4:50p LCS LIB 78848 5-02-85 4:50p PCKERMIT MAP 25696 12-06-85 3:19p CS OBJ 1675 5-02-85 4:50p LCKFIO OBJ 6605 12-06-85 3:17p LCKFNS1 OBJ 12381 12-06-85 3:15p LCKFNS2 OBJ 5598 12-06-85 3:15p LCKFNS3 OBJ 5046 12-06-85 3:16p LCKMAIN OBJ 3035 12-06-85 3:13p LCKPROT OBJ 7611 12-06-85 3:13p LCKTIO OBJ 6472 12-06-85 3:18p LCKUSER OBJ 11453 12-06-85 3:16p PCKERMIT UPD 584 12-06-85 12:14p LCKPROT W 6962 11-06-85 8:24p DESCRIPTION OF FILES USED ------------------------- LCKWART ARF LINK Automatic Response File to create LCKWART pre-processor PCKERMIT ARF LINK Automatic Response File to create PCKERMIT.EXE COMPILE BAT COMPILE batch file for Lattice C and LCK?????.C modules PCKCOMP BAT PCKermit COMPile all modules batch file PCKLINK BAT PCKermit LINK batch file used with PCKERMIT.ARF LCKFIO C File I/O module LCKFNS1 C Kermit Protocol Specific Module #1 LCKFNS2 C Kermit Protocol Specific Module #2 LCKFNS3 C Kermit Windowing Specific Module LCKLINK C Module for linkable Kermit used in place of LCKMAIN.C LCKMAIN C Main program for PCKERMIT LCKPROT C Protocol State table in C (derived from LCKPROT.W) LCKTIO C RS232 I/O and time module LCKUSER C User interface module LCKWART C Source code for LCKWART.EXE preprocessor used on *.W files KWCHANGE DOC Kermit Windowing - Changes to definition draft to draft KWINDOW5 DOC Kermit WINDOWing Definition - Add to Protocol Manual LCKWART DOC LCKWART (WART preproccesor for *.W files) documenation PCKERMIT DOC PCKERMIT Sliding Window Kermit Documentation LC1 EXE Lattice C 1st phase LC2 EXE Lattice C 2nd phase LCKWART EXE WART pre-processor: *.W files input *.C files output PCKERMIT EXE PCKERMIT Sliding Window Executable code ASIC H "include for things that use asi buffer structure" ASIPORTS H Greenleaf Comm Library Header for Asynch I/O ports CDISK H Greenleaf Header CSTDIO H "I/O for Lattice and Microsoft C and The Greenleaf Functions" CTYPE H "defines various ASCII character manipulation macros" FCNTL H "symbols used for "open, "creat", and "fcntl" functions" LCKCMD H Command interface header LCKDEB H Debug header file LCKERM H PCKERMIT main header file LCKUSR H User interface header file STDIOS H Combination of Lattice C and Greenleaf Headers TIMEDATE H Greenleaf Header GFCS LIB Greenleaf Library GFS LIB Greenleaf Library GFTS LIB Greenleaf Library LCMS LIB Lattice C v. 2.15 Library LCS LIB Lattice C Library PCKERMIT MAP CS OBJ CS.OBJ file supplied with Lattice C - Small model LCKFIO OBJ LCKFNS1 OBJ LCKFNS2 OBJ LCKFNS3 OBJ LCKMAIN OBJ LCKPROT OBJ LCKTIO OBJ LCKUSER OBJ PCKERMIT UPD PCKERMIT UPDate list of changes version to version LCKPROT W PROTOCOL State Table in WART pre-proccesor form. COLUMBIA UNIVERSITY ------------------- Columbia University maintains the Kermit protocol. The following is taken from their file COMMER.DOC, which describes Columbia University's policy regarding commerical use of Kermit: " POLICY ON COMMERCIAL USE AND DISTRIBUTION OF KERMIT Frank da Cruz Columbia University Center for Computing Activities June 1984 The KERMIT file transfer protocol has always been open, available, and free to all. The protocol was developed at the Columbia University Center for Computing Activities, as were the first several KERMIT programs. Columbia has shared these programs freely with the worldwide computing community since 1981, and as a result many individuals and institutions have contributed their own improvements or new implementations in the same spirit. In this manner, the number of different systems supporting KERMIT implementations has grown from three to about sixty in less than three years. If Columbia had elected to keep the protocol secret, to restrict access to source code, or to license the software, the protocol would never have spread to cover so many systems, nor would the programs be in use at so many sites, nor would the quality of many of the implemementations be so high. Although KERMIT is free and available to anyone who requests it, it is not in the "public domain". The protocol, the manuals, the Columbia implementations, and many of the contributed implementations bear copyright notices dated 1981 or later, and include a legend like Permission is granted to any individual or institution to copy or use this document and the programs described in it, except for explicitly commercial purposes. This copyright notice is to protect KERMIT, Columbia University, and the various contributors from having their work usurped by others and sold as a product. In addition, the covering letter which we include with a KERMIT tape states that KERMIT can be passed along to others; "we ask only that profit not be your goal, credit be given where it is due, and that new material be sent back to us so that we can maintain a definitive and comprehensive set of KERMIT implementations". Within this framework, it is acceptable to charge a reproduction fee when supplying KERMIT to others. The reproduction fee may be designed to recover costs of media, packaging, printing, shipping, order processing, or any computer use required for reproduction. The fee should not reflect any program or documentation development effort, and it should be be independent of how many implementations of KERMIT appear on the medium or where they came from. It should not be viewed as a license fee. For instance, when Columbia ships a KERMIT tape, there is a $100.00 reproduction fee which includes a 2400' reel of magnetic tape, two printed manuals, various flyers, a box, and postage; there is an additional $100.00 order processing charge if an invoice must be sent. The tape includes all known versions of KERMIT, including sources and documentation. Commercial institutions may make unlimited internal use of KERMIT. However, a question raised with increasing frequency is whether a company may incorporate KERMIT into its products. A hardware vendor may wish to include KERMIT with its standard software. A software house may wish to incorporate KERMIT protocol into its communications package, or to distribute it along with some other product. A timesharing vendor or dialup database may wish to provide KERMIT for downloading. All these uses of KERMIT are permissible, with the following provisos: . A KERMIT program may not be sold as a product in and of itself. In addition to violating the prevailing spirit of sharing and cooperation, commercial sale of a product called "KERMIT" would violate the trade mark which is held on that name by Henson Associates, Inc., creators of The Muppet Show. . Existing KERMIT programs and documentation may be included with hardware or other software as part of a standard package, provided the price of the hardware or software product is not raised significantly beyond costs of reproduction of the KERMIT component. . KERMIT protocol may be included in a multi-protocol communication package as one of the communication options, or as a communication feature of some other kind of software package, in order to enhance the attractiveness of the package. KERMIT protocol file transfer and management should not be the primary purpose of the package. The price of the package should not be raised significantly because KERMIT was included, and the vendor's literature should make a statement to this effect. . Credit for development of the KERMIT protocol should be given to the Columbia University Center for Computing Activities, and customers should be advised that KERMIT is available for many systems for only a nominal fee from Columbia and from various user group organizations, such as DECUS and SHARE. Columbia University holds the copyright on the KERMIT protocol, and may grant permission to any person or institution to develop a KERMIT program for any particular system. A commercial institution that intends to distribute KERMIT under the conditions listed above should be aware that other implementations of KERMIT for the same system may appear in the standard KERMIT distribution at any time. Columbia University encourages all developers of KERMIT software and documentation to contribute their work back to Columbia for further distribution. Finally, Columbia University does not warrant in any way the KERMIT software nor the accuracy of any related documentation, and neither the authors of any KERMIT programs or documentation nor Columbia University acknowledge any liability resulting from program or documentation errors. These are general guidelines, not a legal document to be searched for loopholes. To date, KERMIT has been freely shared by all who have taken the time to do work on it, and no formal legalities have proven necessary. The guidelines are designed to allow commercial enterprises to participate in the promulgation of KERMIT without seriously violating the KERMIT user community's trust that KERMIT will continue to spread and improve at no significant cost to themeselves. The guidelines are subject to change at any time, should more formal detail prove necessary. Commercial organizations wishing to provide KERMIT to their customers should write a letter stating their plans and their agreement to comply with the guidelines listed above. The letter should be addressed to: KERMIT Distribution Columbia University Center for Computing Activities 612 West 115th Street New York, NY 10025" PCKERMIT KNOWN PROBLEMS (BEWARE FILE) ------------------------------------- 12/10/85 PCKERMIT V1.18: MAXIMUM PACKET SIZE LIMITED TO 90 The maximum packet send packet size is limited to 90. This was done as a work-around to an undetermined problem in the code from Columbia which caused errors on some packets when a maximum packet size of 94 was requested by the receiver. Even if the receiver allows a max packet size of 94 in the Send-Init exchange, PCKERMIT limits the actual size of packets it sends out to 90. I believe this is done in one of the .H header files. TIMEOUT AVOIDANCE HEURISTIC An additional heuristic is being added to the Kermit Sliding Window Definition to avoid unnecessary timeouts due to lost ACKs or NAKs. This additional heuristic has not been implemented in V1.16 of PCKERMIT.EXE. The substance of the additional heuristic will be: "An additional heuristic will prevent most timeouts due to lost ACKs or NAKs. The sender re-sends the earliest packet (the packet blocking the window) if the following conditions are true: 1. The Sender's window is blocked. 2. The Retry Count for the earliest packet is zero. 3. An ACK (or optionally also NAK) for any later packet has been received." This heuristic takes advantage of the fact that ACKs and NAKs should normally be received in order. Receipt of a later ACK implies that the earliest ACK was lost. Therefore, we can anticipate that a timeout is likely to occur and avoid it by resending (once) the packet blocking the window. The packet is only sent once (i.e. if the retry count is zero) to avoid complicating error recovery. SOURCE CODE COMPATIBILITY WITH OTHER COMPILERS 1. There is a reportedly a bug in the Microsoft C Compiler which causes an error in the Kermit Type 3 (CRC-16) Checksum algorithm. Beware! 2. Lattice C allows nested comments, which are not allowed by the Microsoft C compiler. Their may be some instances of nested comments. LCKFNS3 has at least one area that was commented out that results in a nested comment. FILE RENAMING WHEN DUPLICATE FILE NAME IS RECEIVED Long filenames can duplicate existing filenames because they are not evaluated by PCKERMIT. The long filename is sent to DOS, which truncates it to the first FILENAME.EXT characters. In general, renaming works for most standard MS-DOS files. However, there are some remaining bugs which reflect the UNIX origins of this code. Developers may wish to take a close look at this area. The addition of ~1, etc, after the filename is not ideal in the MS-DOS environment because the extension is completely lost. Often files are being received with same root but different extensions. If they are updates, it may take a while to sort things out. This logic is implemented in LCKFIO.C in the routine ZNEWN. SLIDING WINDOW DEFINITION ------------------------- The Kermit sliding window extension is defined in the file KWINDOW5.DOC. If the definition is unclear or ambiguous to you in any respect, please contact Columbia University or Source Telecomputing at the address below. SLIDING WINDOW KERMIT STANDARDIZATION ------------------------------------- The Kermit Sliding Window Definition is still labeled experimental by Columbia University in order to help iron out all problems before the final definition is published and to aid in coordinating efforts on sliding window Kermits. For the time being, we suggest developers can help the standardization process by testing their implementations with the following Kermits: PCKERMIT.EXE (Sliding window Kermit) The Source (Sliding window Kermit) MSKERMIT version 2.28 from Columbia University (Classic Kermit) TCOMM BBS --------- A bulletin board at 301-428-7931 (data only 300/1200/2400) is providing informal support for sliding window Kermit. This is a Maryland number. CORRECTIONS, QUESTIONS, COMMENTS -------------------------------- Please send all corrections, questions and comments to: John Mulligan Source Telecomputing Corporation 1616 Anderson Road McLean, VA 22102 703-734-7500 SourceMail: STC356 Columbia University System Mail: We are OC.SOURCE on system CU20B. ################################################################## ## PCKERMIT.MAP Start Stop Length Name Class 00000H 00001H 0002H BASE PROG 00002H 0A0FBH A0FAH PROG PROG 0A0FCH 0A0FDH 0002H TAIL PROG 0A100H 1106BH 6F6CH DATA DATA 11070H 110EFH 0080H STACK DATA Origin Group 0A10:0 DGROUP 0000:0 PGROUP Address Publics by Name 0000:215C ACK 0000:217E ACK1 0A10:2F99 ACTION 0000:46AC ADDRESUL 0000:9CB5 ALLMEM 0A10:6B96 ARGC 0A10:6B98 ARGV 0000:623E ASDTR 0000:624E ASIBREAK 0000:6E11 ASIBSTAT 0000:61AD ASICLEAR 0000:6306 ASIERST 0000:658E ASIGETC 0000:6493 ASIHOLD 0000:6347 ASIIGNOR 0000:6F43 ASIINIT 0000:6E94 ASIKBFETCH 0000:6EA3 ASIKBGET 0000:6E7A ASIKBHIT 0000:62C4 ASILRST 0000:6E55 ASILSTAT 0000:6D8F ASIMODI 0000:62E5 ASIMRST 0000:6E34 ASIMSTAT 0000:6EF5 ASIPUTB 0000:6563 ASIPUTC 0000:6EA9 ASIPUTS 0000:676C ASIQUIT 0000:638C ASIRCHK 0000:6278 ASIRESET 0000:64B4 ASIRESUM 0000:60C0 ASISETUP 0000:6163 ASISTART 0000:6DF3 ASISTAT 0000:6516 ASITIME 0000:6329 ASIXRST 0000:6C21 ASI_BREA 0000:6421 ASI_CLEA 0000:6B94 ASI_INIW 0000:6528 ASI_LOCF 0000:6B2E ASI_LSTA 0000:6B61 ASI_MSTA 0A10:0154 ASI_PARM 0000:6C68 ASI_RESE 0000:65CB ASI_SETU 0000:6693 ASI_STAR 0000:6AEA ASI_STAT 0000:622E ASRTS 0A10:0206 AS_8259I 0A10:01F6 AS_8259P 0000:6BF1 AS_DTR 0000:6A6C AS_GETC 0A10:01E6 AS_INTNU 0A10:01D6 AS_PORT 0000:6AAC AS_PUTC 0A10:0228 AS_RTIME 0000:6BC1 AS_RTS 0A10:0218 AS_WTIME 0000:709E ATOI 0000:70C1 ATOL 0A10:0248 BCTR 0A10:024A BCTU 0000:9C03 BDOS 0A10:05D8 BINARY 0000:3505 BLDLEN 0000:9CC8 BLDMEM 0000:0CED CANNED 0A10:0256 CAPAS 0A10:05EC CAPFLG 0000:519A CARRIER 0A10:05A6 CDETECT 0A10:2F97 CFLG 0000:202B CHK1 0000:2059 CHK2 0000:20A7 CHK3 0000:4161 CHKFN 0000:3698 CHKINT 0A10:0246 CHKLEN 0000:35B9 CHKSPD 0000:2EE6 CKINTV 0A10:45FF CKXECH 0A10:45EC CKXSYS 0A10:45DC CKXV 0A10:3908 CKZSYS 0A10:38FB CKZV 0000:8CE6 CLOSE 0000:1807 CLSIF 0000:1882 CLSOF 0A10:05F4 CMARG 0A10:05F6 CMARG2 0000:2F9D CMDLIN 0A10:2FA5 CMDSTR 0A10:05F8 CMLIST 0A10:05E2 CNFLG 0000:49E6 CONCHK 0000:4A0D CONINC 0000:492F CONOC 0000:4959 CONOL 0000:4987 CONOLA 0000:49C8 CONOLL 0000:4945 CONXO 0000:86A5 CREAT 0A10:025C CTLQ 0000:57C6 CURDSK 0A10:2FA1 CWDF 0000:99C5 CXC33 0000:93D3 CXD33 0000:81C7 CXM33 0A10:05E4 CXSEEN 0000:7CF3 CXVDF 0000:7B6A CXVFD 0A10:05E6 CZSEEN 0A10:03F6 DATA 0000:56FD DAYWEEK 0A10:2ECD DEBFIL 0A10:05C6 DEBLOG 0000:35B2 DEBOPN 0A10:2F9F DEBUGP 0000:09E3 DECODE 0A10:05A4 DELAY 0A10:45FD DFFLOW 0A10:45F9 DFLOC 0A10:45FB DFPRTY 0A10:45F7 DFTTY 0000:5B0E DISKFREE 0000:5800 DISKRESE 0A10:05CE DISPLA 0000:308C DOARG 0000:349C DOEXIT 0000:1F46 DOPAR 0000:5C3D DOS1APPE 0000:5C74 DOS1CLOS 0000:5C7F DOS1CREA 0000:5C8A DOS1DELE 0000:5C69 DOS1OPEN 0000:5C27 DOS1READ 0000:5C95 DOS1RENA 0000:5C32 DOS1WRIT 0000:5AD2 DOS2APPE 0000:5D82 DOS2CLOS 0000:5CDF DOS2CREA 0000:5D15 DOS2DELE 0000:5D4B DOS2OPEN 0000:5DA8 DOS2READ 0000:5DB9 DOS2WRIT 0000:5EDF DOSABSRE 0000:5EEF DOSABSWR 0000:5E78 DOSCHDIR 0000:5E32 DOSCHMOD 0000:58F4 DOSFIRST 0000:5896 DOSFSIZE 0000:5EC9 DOSGETDI 0000:5E2E DOSGETMO 0000:5E93 DOSMKDIR 0000:5905 DOSNEXT 0000:580A DOSPARSE 0000:5874 DOSRDRBL 0000:5852 DOSRDRRE 0000:5BFB DOSRENAM 0000:5EAE DOSRMDIR 0000:5FAB DOSSEEK 0000:5842 DOSVERSI 0000:5885 DOSWTRBL 0000:5863 DOSWTRRE 0A10:05A0 DUPLEX 0A10:024C EBQ 0A10:024E EBQFLG 0000:082F ENCODE 0000:07DD ENCSTR 0A10:025B EOL 0000:38DF ERMSG 0A10:691E ERRNO 0000:226A ERRPKT 0A10:05A2 ESCAPE 0000:8415 EXIT 0000:347E FATAL 0000:816D FCLOSE 0000:5A8C FETCHTIM 0A10:05BE FFC 0000:457A FGEN 0A10:05E8 FILATR 0A10:05AA FILCNT 0A10:054A FILDAT 0A10:0518 FILNAM 0A10:05AE FLCI 0A10:05B2 FLCO 0A10:0598 FLOW 0000:5348 FMTTIME 0A10:05D6 FNCNV 0A10:1421 FNSV 0000:7F72 FOPEN 0A10:390A FP 0000:72B9 FPRINTF 0000:A0B0 FPUTS 0000:7FB9 FREOPEN 0A10:0560 FSIZE 0000:9901 GETCH 0000:992B GETCHE 0000:0C3C GETCHXX 0000:57E9 GETDTA 0000:594D GETFSTAM 0000:9D5F GETMEM 0000:9D7C GETML 0000:0B6F GETPKT 0000:5B04 GETVERIF 0000:1606 GNFILE 0000:2998 GWDATA 0A10:05D4 HCFLG 0A10:2FA3 HOMDIR 0000:2717 INCHR 0000:2750 INLIN 0000:2865 INPUT 0000:81F4 INT86 0000:3609 INTMSG 0000:82FF ISALNUM 0000:8263 ISALPHA 0000:8377 ISCNTRL 0000:82DB ISDIGIT 0000:6031 ISLEAP 0000:6075 ISLETTER 0000:82B7 ISLOWER 0000:63FB ISRCHK 0000:832F ISSPACE 0000:8293 ISUPPER 0000:99A4 KBHIT 0A10:2DF9 LINE 0A10:05DE LOCAL 0A10:01D4 LOC_ASI_ 0A10:2ECB LP 0000:9142 LSBRK 0000:8BEE LSEEK 0000:0255 MAIN 0A10:026C MAXSIZE 0A10:05A8 MDMTYP 0000:56A9 MONTH_NA 0A10:025D MYCTLQ 0A10:0259 MYPADC 0A10:0244 MYPADN 0A10:0516 MYSTCH 0A10:2F95 N 0000:21B6 NACK 0000:2B2A NACKDP 0A10:055E NFILS 0A10:0242 NPAD 0A10:05EA NXTCAS 0000:22FA NXTPKT 0A10:0152 N_ASI_PO 0000:84A6 OPEN 0000:16DE OPENI 0000:175E OPENO 0A10:026A OSIZE 0A10:0258 PADCH 0A10:0596 PARITY 0000:5FFC PEEKB 0000:5FED PEEKW 0000:3910 PERROR 0A10:2EFF PKTFIL 0A10:05C8 PKTLOG 0A10:0262 PKTNUM 0000:601F POKEB 0000:600D POKEW 0000:70E7 PRINTF 0000:0701 PROTO 0A10:064B PROTV 0A10:0264 PRVPKT 0000:9955 PUTCH 0000:0B36 PUTFIL 0000:59EE PUTFSTAM 0000:A043 PUTS 0000:0B0A PUTSRV 0000:5AF6 PUTVERIF 0A10:05DC QUIET 0000:920D RBRK 0A10:4608 RBUF 0000:0F1E RCVFIL 0000:1A3F RDATTR 0000:86CA READ 0A10:032C RECPKT 0000:8D7F REMOVE 0000:8D92 RENAME 0000:102D REOF 0000:1070 REOT 0A10:2F9B REPARS 0000:21CF RESEND 0000:0D87 RINIT 0A10:654A RLEN 0000:9EA3 RLSMEM 0000:9EC3 RLSML 0000:2337 RPACK 0000:12E2 RPAR 0A10:162E RPKTNO 0A10:023A RPSIZ 0A10:0250 RPT 0A10:0254 RPTFLG 0A10:0252 RPTQ 0000:9C80 RSTMEM 0A10:023E RTIMO 0000:2AD4 RWEOF 0000:190F SATTR 0000:91E7 SBRK 0000:22A2 SCMD 0000:3929 SCREEN 0000:11CC SDATA 0000:2BA2 SDATAW 0000:1601 SDEBU 0000:57B7 SELDSK 0000:1235 SEOF 0A10:025A SEOL 0000:128D SEOT 0A10:05E0 SERVER 0A10:2F31 SESFIL 0A10:05CA SESLOG 0000:9311 SETBUF 0000:57D0 SETDTA 0000:3541 SETGEN 0000:9C15 SETNBF 0000:10A8 SFILE 0000:5317 SGETTIME 0000:2321 SIGINT 0000:0DD7 SINIT 0A10:0268 SIZE 0000:9D44 SIZMEM 0A10:05EE SLDWND 0000:51DA SLEEP 0A10:0270 SNDPKT 0A10:0266 SNDTYP 0000:1C92 SPACK 0000:1383 SPAR 0A10:059A SPEED 0A10:026E SPKTL 0000:71FA SPRINTF 0A10:0238 SPSIZ 0000:22D7 SRINIT 0A10:0458 SRVCMD 0A10:0514 SRVPTR 0A10:05F2 SSTATE 0A10:0651 STATE 0000:956A STCCPY 0000:94DE STCD_I 0000:9793 STCD_L 0A10:0517 STCHR 0A10:05D0 STDOUF 0000:83ED STPBLK 0000:9357 STPCHR 0000:988B STRCAT 0000:9389 STRCHR 0000:9845 STRCMP 0000:947B STRCPY 0000:92EB STRLEN 0000:98BD STRNCAT 0000:94A3 STRNCPY 0000:93A2 STRRCHR 0A10:45EE STRTIM 0A10:06B2 TBL 0A10:55A8 TBUF 0A10:05C2 TFC 0000:5208 TICKS 0A10:0240 TIMEF 0000:6DC5 TIMER 0A10:023C TIMINT 0000:0D3C TINIT 0A10:05B6 TLCI 0A10:05BA TLCO 0A10:6548 TLEN 0A10:2F9D TLEVEL 0000:83C4 TOLOWER 0000:527C TOOLONG 0000:524D TOTSEC 0000:839B TOUPPER 0A10:2F63 TRAFIL 0A10:05CC TRALOG 0000:5050 TTCHK 0000:4B7E TTCLOS 0000:50BA TTFLOW 0000:4F84 TTFLUI 0000:4FDA TTFLUO 0000:5004 TTIN 0000:4C34 TTINC 0000:4CB9 TTINL 0A10:0564 TTNAME 0000:4BFD TTOC 0000:4BAF TTOL 0000:4A69 TTOPEN 0000:4D87 TTPKT 0000:5085 TTSOME 0000:4EDB TTSSPD 0000:4DB0 TTVT 0A10:059C TURN 0A10:059E TURNCH 0000:9982 UNGETCH 0000:8D46 UNLINK 0000:3470 USAGE 0A10:2DF7 USERV 0A10:0150 VERSIO 0A10:05DA WARN 0000:02FD WART 0A10:061D WARTV 0000:2E15 WDINIT 0000:2D9F WEOF 0A10:05F0 WINDOW 0A10:152A WNDACK 0A10:1630 WNDATA 0000:2F5A WNDERR 0000:2E8D WNDESR 0A10:162C WNDHGH 0A10:162A WNDLOW 0A10:025E WNDMAX 0A10:0260 WNDSIZ 0A10:15AA WNDTRY 0000:2C8A WRESND 0000:89C5 WRITE 0A10:05FC XARGC 0A10:05FA XARGV 0000:0207 XCABT 0000:023C XCEXIT 0000:0220 XCOVF 0A10:05D2 XFLG 0000:3F7E ZCHIN 0000:41CB ZCHKI 0000:4241 ZCHKO 0000:40CA ZCHOUT 0000:3F17 ZCLOSE 0000:42D8 ZDELET 0000:4721 ZFCDAT 0000:47DF ZFPDAT 0000:476F ZFREE 0000:4343 ZLTOR 0000:4456 ZNEWN 0000:4416 ZNEXT 0000:3D8B ZOPENI 0000:3E49 ZOPENO 0000:42E5 ZRTOL 0000:3FFF ZSOUT 0000:403F ZSOUTL 0000:4083 ZSOUTX 0000:52ED ZTIME 0000:4544 ZXPAND 0000:9BC7 _AGET 0000:9BDB _APUT 0000:6CA3 _ASIMXI 0000:6CEF _ASIXMX 0A10:0216 _AS_WCTS 0A10:0017 _BASE 0A10:6C1E _BUFSIZ 0000:9B8B _CGET 0000:9B9F _CGETE 0000:9C74 _CGETS 0000:9BB3 _CPUT 0A10:6920 _CTYPE 0000:5761 _DAYR 0A10:6A22 _DNBS 0A10:000F _DOS 0000:5C3D _DOS1APP 0000:5C74 _DOS1CLO 0000:5C7F _DOS1CRE 0000:5C8A _DOS1DEL 0000:5C69 _DOS1OPE 0000:5C27 _DOS1REA 0000:5C95 _DOS1REN 0A10:006B _ENV 0A10:006F _ESIZE 0000:9B7B _EXIT 0000:9B2F _FCHGM 0000:9A9F _FCLOSE 0000:9A6B _FCREAT 0000:9B4E _FGDI 0000:8DCB _FILBF 0000:8ED7 _FLSBF 0A10:6C20 _FMODE 0000:9A85 _FOPEN 0A10:0071 _FPA 0A10:0079 _FPERR 0000:9AB6 _FREAD 0000:9B5D _FREN 0000:9B18 _FRMV 0000:9AF4 _FSEEK 0000:9AD5 _FWRITE 0A10:0019 _INAME 0A10:6806 _IOB 0A10:6C1C _IOMODE 0000:9BEF _LPUT 0000:95B8 _MAIN 0A10:005D _MBASE 0A10:6C14 _MELT 0A10:6C18 _MNEED 0A10:0061 _MNEXT 0A10:0065 _MSIZE 0A10:007B _NDP 0A10:007E _NDPCW 0A10:007C _NDPSW 0A10:6C22 _NUFBS 0A10:0039 _ONAME 0A10:0080 _OSERR 0000:73CC _PFMT 0A10:6C10 _POOL 0A10:0059 _PSP 0000:99E2 _RBRK 0000:9A27 _SBRK 0A10:0013 _SP 0A10:0011 _SS 0A10:6B94 _STACK 0000:5663 _STRNCPY 0A10:0015 _TOP 0A10:0069 _TSIZE 0A10:6C24 _UFBS 0A10:0002 _VER 0000:56DC _WKDAY Address Publics by Value 0000:0207 XCABT 0000:0220 XCOVF 0000:02FD WART 0000:0701 PROTO 0000:09E3 DECODE 0000:0B36 PUTFIL 0000:0B6F GETPKT 0000:10A8 SFILE 0000:12E2 RPAR 0000:1383 SPAR 0000:16DE OPENI 0000:175E OPENO 0000:1807 CLSIF 0000:1882 CLSOF 0000:1C92 SPACK 0000:217E ACK1 0000:21B6 NACK 0000:21CF RESEND 0000:22A2 SCMD 0000:22D7 SRINIT 0000:22FA NXTPKT 0000:2321 SIGINT 0000:2337 RPACK 0000:2750 INLIN 0000:2B2A NACKDP 0000:2E8D WNDESR 0000:2F5A WNDERR 0000:347E FATAL 0000:3609 INTMSG 0000:38DF ERMSG 0000:3E49 ZOPENO 0000:3F7E ZCHIN 0000:3FFF ZSOUT 0000:41CB ZCHKI 0000:4241 ZCHKO 0000:42D8 ZDELET 0000:4343 ZLTOR 0000:4544 ZXPAND 0000:46AC ADDRESUL 0000:492F CONOC 0000:4959 CONOL 0000:4987 CONOLA 0000:49C8 CONOLL 0000:4A69 TTOPEN 0000:4D87 TTPKT 0000:4DB0 TTVT 0000:4EDB TTSSPD 0000:4F84 TTFLUI 0000:5050 TTCHK 0000:5085 TTSOME 0000:519A CARRIER 0000:51DA SLEEP 0000:524D TOTSEC 0000:5348 FMTTIME 0000:56DC _WKDAY 0000:56FD DAYWEEK 0000:5761 _DAYR 0000:57B7 SELDSK 0000:57D0 SETDTA 0000:57E9 GETDTA 0000:5A8C FETCHTIM 0000:5AD2 DOS2APPE 0000:5B0E DISKFREE 0000:5C27 DOS1READ 0000:5C32 DOS1WRIT 0000:5C3D _DOS1APP 0000:5C3D DOS1APPE 0000:5C69 DOS1OPEN 0000:5C74 _DOS1CLO 0000:5C8A _DOS1DEL 0000:5D4B DOS2OPEN 0000:5DA8 DOS2READ 0000:5DB9 DOS2WRIT 0000:5FAB DOSSEEK 0000:5FED PEEKW 0000:5FFC PEEKB 0000:600D POKEW 0000:601F POKEB 0000:6031 ISLEAP 0000:6278 ASIRESET 0000:63FB ISRCHK 0000:6493 ASIHOLD 0000:64B4 ASIRESUM 0000:6528 ASI_LOCF 0000:6563 ASIPUTC 0000:658E ASIGETC 0000:676C ASIQUIT 0000:6AAC AS_PUTC 0000:6B2E ASI_LSTA 0000:6B61 ASI_MSTA 0000:6C21 ASI_BREA 0000:6E7A ASIKBHIT 0000:6EA3 ASIKBGET 0000:6EA9 ASIPUTS 0000:6EF5 ASIPUTB 0000:6F43 ASIINIT 0000:71FA SPRINTF 0000:72B9 FPRINTF 0000:7B6A CXVFD 0000:7CF3 CXVDF 0000:7FB9 FREOPEN 0000:82B7 ISLOWER 0000:82FF ISALNUM 0000:832F ISSPACE 0000:83C4 TOLOWER 0000:84A6 OPEN 0000:86CA READ 0000:93A2 STRRCHR 0000:956A STCCPY 0000:95B8 _MAIN 0000:9793 STCD_L 0000:9845 STRCMP 0000:988B STRCAT 0000:9901 GETCH 0000:992B GETCHE 0000:9955 PUTCH 0000:99A4 KBHIT 0000:99C5 CXC33 0000:9A9F _FCLOSE 0000:9AF4 _FSEEK 0000:9BC7 _AGET 0000:9BDB _APUT 0000:9CC8 BLDMEM 0000:9D7C GETML 0000:9EA3 RLSMEM 0000:9EC3 RLSML 0000:A043 PUTS 0000:A0B0 FPUTS 0A10:0002 _VER 0A10:000F _DOS 0A10:0011 _SS 0A10:0013 _SP 0A10:0015 _TOP 0A10:0017 _BASE 0A10:0019 _INAME 0A10:0059 _PSP 0A10:005D _MBASE 0A10:0061 _MNEXT 0A10:0065 _MSIZE 0A10:0069 _TSIZE 0A10:006B _ENV 0A10:006F _ESIZE 0A10:0071 _FPA 0A10:0079 _FPERR 0A10:007B _NDP 0A10:007C _NDPSW 0A10:007E _NDPCW 0A10:0080 _OSERR 0A10:0150 VERSIO 0A10:0152 N_ASI_PO 0A10:0154 ASI_PARM 0A10:01D4 LOC_ASI_ 0A10:01D6 AS_PORT 0A10:01E6 AS_INTNU 0A10:01F6 AS_8259P 0A10:0206 AS_8259I 0A10:0216 _AS_WCTS 0A10:0218 AS_WTIME 0A10:0228 AS_RTIME 0A10:0238 SPSIZ 0A10:023A RPSIZ 0A10:023C TIMINT 0A10:023E RTIMO 0A10:0240 TIMEF 0A10:0242 NPAD 0A10:0244 MYPADN 0A10:0246 CHKLEN 0A10:0248 BCTR 0A10:024A BCTU 0A10:024C EBQ 0A10:024E EBQFLG 0A10:0250 RPT 0A10:0252 RPTQ 0A10:0254 RPTFLG 0A10:0256 CAPAS 0A10:0258 PADCH 0A10:0259 MYPADC 0A10:025A SEOL 0A10:025B EOL 0A10:025C CTLQ 0A10:025D MYCTLQ 0A10:025E WNDMAX 0A10:0260 WNDSIZ 0A10:0262 PKTNUM 0A10:0264 PRVPKT 0A10:0266 SNDTYP 0A10:0268 SIZE 0A10:026A OSIZE 0A10:026C MAXSIZE 0A10:026E SPKTL 0A10:0270 SNDPKT 0A10:032C RECPKT 0A10:03F6 DATA 0A10:0458 SRVCMD 0A10:0514 SRVPTR 0A10:0516 MYSTCH 0A10:0517 STCHR 0A10:0518 FILNAM 0A10:054A FILDAT 0A10:055E NFILS 0A10:0560 FSIZE 0A10:0564 TTNAME 0A10:0596 PARITY 0A10:0598 FLOW 0A10:059A SPEED 0A10:059C TURN 0A10:059E TURNCH 0A10:05A0 DUPLEX 0A10:05A2 ESCAPE 0A10:05A4 DELAY 0A10:05A6 CDETECT 0A10:05A8 MDMTYP 0A10:05AA FILCNT 0A10:05AE FLCI 0A10:05B2 FLCO 0A10:05B6 TLCI 0A10:05BA TLCO 0A10:05BE FFC 0A10:05C2 TFC 0A10:05C6 DEBLOG 0A10:05C8 PKTLOG 0A10:05CA SESLOG 0A10:05CC TRALOG 0A10:05CE DISPLA 0A10:05D0 STDOUF 0A10:05D2 XFLG 0A10:05D4 HCFLG 0A10:05D6 FNCNV 0A10:05D8 BINARY 0A10:05DA WARN 0A10:05DC QUIET 0A10:05DE LOCAL 0A10:05E0 SERVER 0A10:05E2 CNFLG 0A10:05E4 CXSEEN 0A10:05E6 CZSEEN 0A10:05E8 FILATR 0A10:05EA NXTCAS 0A10:05EC CAPFLG 0A10:05EE SLDWND 0A10:05F0 WINDOW 0A10:05F2 SSTATE 0A10:05F4 CMARG 0A10:05F6 CMARG2 0A10:05F8 CMLIST 0A10:05FA XARGV 0A10:05FC XARGC 0A10:061D WARTV 0A10:064B PROTV 0A10:0651 STATE 0A10:06B2 TBL 0A10:1421 FNSV 0A10:152A WNDACK 0A10:15AA WNDTRY 0A10:162A WNDLOW 0A10:162C WNDHGH 0A10:162E RPKTNO 0A10:1630 WNDATA 0A10:2DF7 USERV 0A10:2DF9 LINE 0A10:2ECB LP 0A10:2ECD DEBFIL 0A10:2EFF PKTFIL 0A10:2F31 SESFIL 0A10:2F63 TRAFIL 0A10:2F95 N 0A10:2F97 CFLG 0A10:2F99 ACTION 0A10:2F9B REPARS 0A10:2F9D TLEVEL 0A10:2F9F DEBUGP 0A10:2FA1 CWDF 0A10:2FA3 HOMDIR 0A10:2FA5 CMDSTR 0A10:38FB CKZV 0A10:3908 CKZSYS 0A10:390A FP 0A10:45DC CKXV 0A10:45EC CKXSYS 0A10:45EE STRTIM 0A10:45F7 DFTTY 0A10:45F9 DFLOC 0A10:45FB DFPRTY 0A10:45FD DFFLOW 0A10:45FF CKXECH 0A10:4608 RBUF 0A10:55A8 TBUF 0A10:6548 TLEN 0A10:654A RLEN 0A10:6806 _IOB 0A10:691E ERRNO 0A10:6920 _CTYPE 0A10:6A22 _DNBS 0A10:6B94 _STACK 0A10:6B96 ARGC 0A10:6B98 ARGV 0A10:6C10 _POOL 0A10:6C14 _MELT 0A10:6C18 _MNEED 0A10:6C1C _IOMODE 0A10:6C1E _BUFSIZ 0A10:6C20 _FMODE 0A10:6C22 _NUFBS 0A10:0039 _ONAME 0000:3F17 ZCLOSE 0000:023C XCEXIT 0000:0255 MAIN 0000:07DD ENCSTR 0000:082F ENCODE 0000:0B0A PUTSRV 0000:0C3C GETCHXX 0000:0CED CANNED 0000:0D3C TINIT 0000:0D87 RINIT 0000:0DD7 SINIT 0000:0F1E RCVFIL 0000:102D REOF 0000:1070 REOT 0000:11CC SDATA 0000:1235 SEOF 0000:128D SEOT 0000:1601 SDEBU 0000:1606 GNFILE 0000:190F SATTR 0000:1A3F RDATTR 0000:1F46 DOPAR 0000:202B CHK1 0000:2059 CHK2 0000:20A7 CHK3 0000:215C ACK 0000:226A ERRPKT 0000:2717 INCHR 0000:2865 INPUT 0000:2998 GWDATA 0000:2AD4 RWEOF 0000:2BA2 SDATAW 0000:2C8A WRESND 0000:2D9F WEOF 0000:2E15 WDINIT 0000:2EE6 CKINTV 0000:2F9D CMDLIN 0000:308C DOARG 0000:3470 USAGE 0000:349C DOEXIT 0000:3505 BLDLEN 0000:3541 SETGEN 0000:35B2 DEBOPN 0000:35B9 CHKSPD 0000:3698 CHKINT 0000:3910 PERROR 0000:3929 SCREEN 0000:3D8B ZOPENI 0000:403F ZSOUTL 0000:4083 ZSOUTX 0000:40CA ZCHOUT 0000:4161 CHKFN 0000:42E5 ZRTOL 0000:4416 ZNEXT 0000:4456 ZNEWN 0000:457A FGEN 0000:4721 ZFCDAT 0000:476F ZFREE 0000:47DF ZFPDAT 0000:4945 CONXO 0000:49E6 CONCHK 0000:4A0D CONINC 0000:4B7E TTCLOS 0000:4BAF TTOL 0000:4BFD TTOC 0000:4C34 TTINC 0000:4CB9 TTINL 0000:4FDA TTFLUO 0000:5004 TTIN 0000:50BA TTFLOW 0000:5208 TICKS 0000:527C TOOLONG 0000:52ED ZTIME 0000:5317 SGETTIME 0000:5663 _STRNCPY 0000:56A9 MONTH_NA 0000:57C6 CURDSK 0000:5800 DISKRESE 0000:580A DOSPARSE 0000:5842 DOSVERSI 0000:5852 DOSRDRRE 0000:5863 DOSWTRRE 0000:5874 DOSRDRBL 0000:5885 DOSWTRBL 0000:5896 DOSFSIZE 0000:58F4 DOSFIRST 0000:5905 DOSNEXT 0000:594D GETFSTAM 0000:59EE PUTFSTAM 0000:5AF6 PUTVERIF 0000:5B04 GETVERIF 0000:5BFB DOSRENAM 0000:5C27 _DOS1REA 0000:5C69 _DOS1OPE 0000:5C74 DOS1CLOS 0000:5C7F DOS1CREA 0000:5C7F _DOS1CRE 0000:5C8A DOS1DELE 0000:5C95 DOS1RENA 0000:5C95 _DOS1REN 0000:5CDF DOS2CREA 0000:5D15 DOS2DELE 0000:5D82 DOS2CLOS 0000:5E2E DOSGETMO 0000:5E32 DOSCHMOD 0000:5E78 DOSCHDIR 0000:5E93 DOSMKDIR 0000:5EAE DOSRMDIR 0000:5EC9 DOSGETDI 0000:5EDF DOSABSRE 0000:5EEF DOSABSWR 0000:6075 ISLETTER 0000:60C0 ASISETUP 0000:6163 ASISTART 0000:61AD ASICLEAR 0000:622E ASRTS 0000:623E ASDTR 0000:624E ASIBREAK 0000:62C4 ASILRST 0000:62E5 ASIMRST 0000:6306 ASIERST 0000:6329 ASIXRST 0000:6347 ASIIGNOR 0000:638C ASIRCHK 0000:6421 ASI_CLEA 0000:6516 ASITIME 0000:65CB ASI_SETU 0000:6693 ASI_STAR 0000:6A6C AS_GETC 0000:6AEA ASI_STAT 0000:6B94 ASI_INIW 0000:6BC1 AS_RTS 0000:6BF1 AS_DTR 0000:6C68 ASI_RESE 0000:6CA3 _ASIMXI 0000:6CEF _ASIXMX 0000:6D8F ASIMODI 0000:6DC5 TIMER 0000:6DF3 ASISTAT 0000:6E11 ASIBSTAT 0000:6E34 ASIMSTAT 0000:6E55 ASILSTAT 0000:6E94 ASIKBFETCH 0000:709E ATOI 0000:70C1 ATOL 0000:70E7 PRINTF 0000:73CC _PFMT 0000:7F72 FOPEN 0000:816D FCLOSE 0000:81C7 CXM33 0000:81F4 INT86 0000:8263 ISALPHA 0000:8293 ISUPPER 0000:82DB ISDIGIT 0000:8377 ISCNTRL 0000:839B TOUPPER 0000:83ED STPBLK 0000:8415 EXIT 0000:86A5 CREAT 0000:89C5 WRITE 0000:8BEE LSEEK 0000:8CE6 CLOSE 0000:8D46 UNLINK 0000:8D7F REMOVE 0000:8D92 RENAME 0000:8DCB _FILBF 0000:8ED7 _FLSBF 0000:9142 LSBRK 0000:91E7 SBRK 0000:920D RBRK 0000:92EB STRLEN 0000:9311 SETBUF 0000:9357 STPCHR 0000:9389 STRCHR 0000:93D3 CXD33 0000:947B STRCPY 0000:94A3 STRNCPY 0000:94DE STCD_I 0000:98BD STRNCAT 0000:9982 UNGETCH 0000:99E2 _RBRK 0000:9A27 _SBRK 0000:9A6B _FCREAT 0000:9A85 _FOPEN 0000:9AB6 _FREAD 0000:9AD5 _FWRITE 0000:9B18 _FRMV 0000:9B2F _FCHGM 0000:9B4E _FGDI 0000:9B5D _FREN 0000:9B7B _EXIT 0000:9B8B _CGET 0000:9B9F _CGETE 0000:9BB3 _CPUT 0000:9BEF _LPUT 0000:9C03 BDOS 0000:9C15 SETNBF 0000:9C74 _CGETS 0000:9C80 RSTMEM 0000:9CB5 ALLMEM 0000:9D44 SIZMEM 0A10:6C24 _UFBS 0000:9D5F GETMEM Program entry point at 0000:0002 ################################################################## ## PCKERMIT.UPD PCKERMIT.UPD PCKERMIT.EXE UPDATE DOCUMENTATION December 10, 1985 Change from version 1.17 to 1.18 The fix in LCKFIO.C for renaming files was wrong. Version 1.17 would give an error if you were receiving a duplicate filename that had an extension but whose root filename was less than 8 characters (i.e. FILEN.EXT). OLD: Version 1.17 was: if (len <= 8) sprintf(bp,".~%d ",d+1); /* JRM Add period if needed */ else sprintf(bp,"~%d ",d+1); /* Make and return name~(d+1) */ *s = buf; NEW: Version 1.18 is: if (len <= 8 && buf[len-1] != '.') sprintf(bp,".~%d ",d+1); /* JRM Add else sprintf(bp,"~%d ",d+1); /* Make and return name~(d+1) */ *s = buf; -------------------------------------------------- December 6, 1985 VERSION 1.17 [!!! NOTE: THIS WAS WRONG. SEE VERSION 1.18 ABOVE !!!] Change from version 1.16 to 1.17: LCKUSER.C modified to correctly rename files of 8 characters or less with no extension in routine ZNEWN. Change: OLD: Version 1.16 was: sprintf(bp,"~%d ",d+1); /* Make and return name~(d+1) */ *s = buf; NEW: Vesion 1.17 is: if (len <= 8) sprintf(bp,".~%d ",d+1); /* JRM Add period if needed */ else sprintf(bp,"~%d ",d+1); /* Make and return name~(d+1) */ *s = buf; ################################################################## ## PCKLINK.BAT LINK @PCKERMIT.ARF ################################################################## ## REC.BAT PCKERMIT -P M -L COM1 -B 1200 -R ################################################################## ## SEND.BAT PCKERMIT -P M -L COM1 -B 1200 -S %1 ################################################################## ## STDIOS.H #include "cstdio.h" /* Greenleaf add on */ /** * * This header file defines the information used by the standard I/O * package. * **/ #define _BUFSIZ 512 /* standard buffer size */ #define BUFSIZ 512 /* standard buffer size */ #define _NFILE 20 /* maximum number of files */ struct _iobuf { char *_ptr; /* current buffer pointer */ int _rcnt; /* current byte count for reading */ int _wcnt; /* current byte count for writing */ char *_base; /* base address of I/O buffer */ char _flag; /* control flags */ char _file; /* file number */ int _size; /* size of buffer */ char _cbuff; /* single char buffer */ char _pad; /* (pad to even number of bytes) */ }; extern struct _iobuf _iob[_NFILE]; #define _IOREAD 1 /* read flag */ #define _IOWRT 2 /* write flag */ #define _IONBF 4 /* non-buffered flag */ #define _IOMYBUF 8 /* private buffer flag */ #define _IOEOF 16 /* end-of-file flag */ #define _IOERR 32 /* error flag */ #define _IOSTRG 64 #define _IORW 128 /* read-write (update) flag */ #if SPTR #define NULL 0 /* null pointer value */ #else #define NULL 0L #endif #define FILE struct _iobuf /* shorthand */ #define EOF (-1) /* end-of-file code */ #define stdin (&_iob[0]) /* standard input file pointer */ #define stdout (&_iob[1]) /* standard output file pointer */ #define stderr (&_iob[2]) /* standard error file pointer */ #define getc(p) (--(p)->_rcnt>=0? *(p)->_ptr++:_filbf(p)) #define getchar() getc(stdin) #define putc(c,p) (--(p)->_wcnt>=0? ((int)(*(p)->_ptr++=(c))):_flsbf((c),p)) #define putchar(c) putc(c,stdout) #define feof(p) (((p)->_flag&_IOEOF)!=0) #define ferror(p) (((p)->_flag&_IOERR)!=0) #define fileno(p) (p)->_file #define rewind(fp) fseek(fp,0L,0) #define fflush(fp) _flsbf(-1,fp) #define clearerr(fp) clrerr(fp) FILE *fopen(); FILE *freopen(); long ftell(); char *fgets(); #define abs(x) ((x)<0?-(x):(x)) #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<=(b)?(a):(b)) ################################################################## ## TIMEDATE.H /* timedate.h * * Header file for time and date functions * * The Greenleaf Functions - Copyright (C) 1983 Greenleaf Software * * Use: Include in programs utilizing gettime & getdate functions. */ struct TIMEDATE { int year; /* year 1980..2099 */ int month; /* month 1=Jan 2=Feb, etc. */ int day; /* day of month 0..31 */ int hours; /* hour 0..23 */ int minutes; /* minute 0..59 */ int seconds; /* second 0..59 */ int hsecs; /* 1/100ths of second 0..99 */ char dateline[47]; /* date & time together */ }; ##################################################################