Path: utzoo!utgpu!watserv1!maytag!xenitec!zswamp!root From: root@zswamp.fidonet.org (Geoffrey Welsh) Newsgroups: comp.sys.cbm Subject: 6510 assembly punter source anyone? Message-ID: <4529.274478D3@zswamp.fidonet.org> Date: Fri, 16 Nov 90 14:49:40 PDT Organization: Izot's Swamp BBS - Kitchener, Ontario Matthew E Cross (profesor@wpi.WPI.EDU ) wrote: >Now that I know a decent amount of C/Unix programming, I'm >trying to implement the protocol on UNIX. Here is the 'C' source, written for Steve Punter's MS-DOS BBS software by Ben Pedersen: Docs for the 'C' source code the the C1 protocol By Steve Punter The following source code for my "C1" protocol was written by BEN PEDERSEN, and donated to the public domain. Specifically, it is written to compile under MicroSoft's "Quick-C", and be called from a higher level language ("Quick- BASIC"). However, it should compile with most PC compilers, and you don't HAVE to call it from a higher language. The two important routines are "C1Rec" and "C1Send". Both these routines are passed THREE parameters: File Name POINTER File Type Flag Base Location of Screen The file name pointer is merely a pointer to a NULL TERMINATED string which contains the file name to be written to, or read from, the disk. The File Type Flag is an INTEGER value of 0 or 1, which determines whether the routines go through the initial transfer of a file type byte. This is NECESSARY when uploading or downloading from a Punter type BBS, but is not required by the protocol per se. The Base Location of Screen is a LONG value telling the protocol at what SEGMENT the screen is located (usually $B000 for monochrome, or $B800 for CGA). As the transfer proceeds, the number of successful bytes, and number of bad blocks, are put on the top line of your screen. This is to accommodate the STATUS LINE of the BBS, but will most likely not suit your applications. It should be changed appropriately. RS-232 is handled via three routines: GETSER(), PUTSER(), and CHECK(). All of the above are EXTERNAL routines which sould be supplied at compile time. GETSER() should return an INT value of the byte received from the RS-232 input port, or input buffer. PUTSER() should accept an INT value to put out on the RS-232 port. CHECK() should return an INT value of how many characters are waiting in the RS-232 input buffer. extern void setser(unsigned,unsigned,unsigned); extern int getser(); extern int check(); #include #include #include #include #include #include #include static unsigned buffer; static unsigned ds; static unsigned tab2; static int tfh; static int badblocks; static long xfertotal; static int nocount; static long scnloc; unsigned _dos_findfirst(char *,unsigned,struct find_t *); unsigned _dos_findnext(struct find_t *); void dosc(int *,int *); typedef struct C1STUFF { int fp; /* pointer to open file for send & receive */ char *BuffPtr; /* pointer to data buffer */ char BuffOne[256]; /* data buffer no. one */ char BuffTwo[256]; /* data buffer no. two */ char TempBuff[500]; /* general purpose buffer */ char *ReplyStr[5]; /* pointers to reply code strings */ char *CharPtr; /* general purpose char pointer */ int BlkSize; /* size of block being sent or received */ int NextBsize; /* size of next block to be sent or received */ int FullBsize; /* selected size, 40-255 bytes, of a full block */ int BlkNum; /* block number count */ int FileFlag; /* file type being sent or received */ int ReplyOut; /* array index flags currently-transmitted reply code */ int ReplyWant; /* array index flags currently-wanted reply code */ int ErrCodes; /* count of erroneous reply codes received */ int ErrBlocks; /* count of erroneous blocks received */ int Chksum; /* additive checksum for current block */ int CLC; /* cyclic checksum for current block */ int EndFlag; /* local last block flag */ int EndOff; /* signal end of transfer */ int EndXfer; /* signal to terminate transfer */ int TransFlag; /* flag text file for ASCII-PETSCII-ASCII translate */ int Wait; /* index to Wait Period array for reply codes */ long Period[3]; /* array of reply code Wait Period values */ }; struct C1STUFF C1Stuff, *StuffPtr; /* C1 variables structure & pointer */ void prtstat (gd,bb) long gd; int bb; { char far *screen; char buf[20]; int i; int z; FP_SEG(screen)=scnloc; FP_OFF(screen)=160; sprintf(buf,"%lu",gd); for (i=0,z=94;*(buf+i)!=0;i++,z=z+2) *(screen+z)=*(buf+i); sprintf(buf,"%u",bb); for (i=0,z=120;*(buf+i)!=0;i++,z=z+2) *(screen+z)=*(buf+i); } /*********************************** * c1.c * * * * C language implementation * * of Steve Punter's * * C1 file transfer protocol * * written for MS-DOS 2.xx * * * * Ben Pedersen Jun 88 * ************************************ /* constants for external assembler functions */ #define END 0x4f /* exit program */ #define PGUP 0x49 /* upload a file */ #define PGDN 0x51 /* download a file */ #define F1 0x3b /* DOS shell */ #define BELL 0x07 /* tweak speaker */ /* response code string array index */ #define CODE_ACK 0x00 #define CODE_GOO 0x01 #define CODE_BAD 0x02 #define CODE_SYN 0x03 #define CODE_SBK 0x04 /* used to clear a reply code flag */ #define NONE 0x05 /* short and long periods to wait for a response */ #define SHORT 0x400L #define LONG 0x460L #define ERROR 0xffff /* flag error condition on function return */ #define NOERR 0x00 /* flag no error on function return */ #define MAXCODERR 0x18 /* maximum number of reply code errors */ #define MAXBLKERR 0x05 /* maximum number of data block errors */ #define EOT_FLAG 0xff /* end of transfer flag in BLKNUM_H */ #define HEADER 0x07 /* no. of bytes in block header */ #define CHKSUM_L 0x00 /* byte no. of additive checksum low byte */ #define CHKSUM_H 0x01 /* byte no. of additive checksum high byte */ #define CLC_L 0x02 /* byte no. of cyclic checksum low byte */ #define CLC_H 0x03 /* byte no. of cyclic checksum high byte */ #define NEXT_BSIZE 0x04 /* byte no. of next blocksize byte */ #define BLKNUM_L 0x05 /* byte no. of block number low byte */ #define BLKNUM_H 0x06 /* byte no. of block number high byte */ #define FILE_TYPE 0x07 /* byte no. of file type byte */ #define FALSE 0 /* false response */ #define TRUE 1 /* true response */ /***************************************************************************/ /* C1 protocol functions for receiving data */ int HandleRec(); /* handle reply codes for receiving data blocks */ int BlockRec(); /* get a block of data from serial buffer */ int ChksmRec(); /* performs checksum tests on received block */ int EndReceive(); /* handle reply codes for ending data receive */ /* C1 protocol functions for sending data */ int FtypeSend(int); /* handle sending file type block */ int DataSend(); /* controls block sending sequence */ int DataBuild(); /* builds both the next and the current block */ void ChksmSend(); /* generates checksums for current block */ int EndSend(); /* handle reply codes for data send */ int SLBlocks(); /* statement & listen loop for block send */ /* C1 protocol functions common to sending and receiving data */ int SLCodes(); /* statement & listen loop for reply codes */ int GetBytes(); /* loop for getting reply chars */ int CodeOut(); /* send out a reply code */ /************************************************************************** * * functions to receive blocks * **************************************************************************/ int fortran C1Rec(pathname,fflg,loc) char *pathname; int fflg; long loc; { int i; int filetype; scnloc=loc; C1Stuff.ReplyStr[0] = "ACK"; /* signal a good or bad block */ C1Stuff.ReplyStr[1] = "GOO"; /* signal a good block */ C1Stuff.ReplyStr[2] = "BAD"; /* signal a bad block */ C1Stuff.ReplyStr[3] = "SYN"; /* signal end of transfer sequence */ C1Stuff.ReplyStr[4] = "S/B"; /* request block or signal transfer done */ /* sequence of reply code wait periods */ C1Stuff.Period[0] = SHORT; C1Stuff.Period[1] = SHORT; C1Stuff.Period[2] = LONG; StuffPtr = &C1Stuff; /* set pointer to struct of C1 variables */ C1Stuff.BuffPtr = C1Stuff.BuffOne; /* set pointer to a data buffer */ C1Stuff.ErrCodes = 0; /* count of reply code errors */ C1Stuff.ErrBlocks = 0; /* count of data block errors */ C1Stuff.Wait = 0; /* index variable of reply code wait periods */ C1Stuff.TransFlag = FALSE; /* PETSCII-ASCII translation flag */ xfertotal = 0; badblocks = 0; _dos_creat(pathname,_A_NORMAL,&tfh); C1Stuff.FileFlag=1; if(fflg != 0) { nocount = 1; C1Stuff.BlkSize = HEADER+1; /* size of file type block */ if(HandleRec() == ERROR) /* receive file type block */ { _dos_close(tfh); return(1); } StuffPtr->CharPtr = StuffPtr->BuffPtr+7; filetype = *StuffPtr->CharPtr & 255; if(EndReceive() == ERROR) /* end off file type receive */ { _dos_close(tfh); return(2); } } nocount = 0; C1Stuff.BlkSize = HEADER; /* size of dummy data block */ if(HandleRec() == ERROR) /* receive data blocks */ { _dos_close(tfh); return(1); } if(EndReceive() == ERROR) /* end off data receive */ { _dos_close(tfh); return(3); } _dos_close(tfh); if (fflg==0) return(0); else return (-filetype); } int HandleRec() /* handle reply codes for receiving data blocks */ { int flag; int bw; StuffPtr->BlkNum = 0; /* local block number count */ StuffPtr->ReplyOut = CODE_GOO; /* reply code to send to sender */ StuffPtr->ReplyWant = CODE_ACK; /* reply code wanted from sender */ StuffPtr->EndOff = 0; StuffPtr->EndFlag = 0; StuffPtr->EndXfer = 0; if(SLCodes() == ERROR) return(ERROR); /* send & get reply */ do { do { StuffPtr->ReplyOut = CODE_SBK; /* code to request a block */ CodeOut(); /* request a block */ } while ((flag = BlockRec()) == -2); if(flag == NOERR) /* receive a block */ { if (StuffPtr->BlkNum > 0) { if (nocount==0) xfertotal += ((StuffPtr->BlkSize & 0xff) - HEADER); prtstat(xfertotal,badblocks); } ++StuffPtr->BlkNum; /* increment local block count */ StuffPtr->ErrBlocks = NOERR; /* zero block error count */ StuffPtr->ReplyOut = CODE_GOO; /* reply code signals good block */ if(StuffPtr->BlkNum > 1) /* block number > 1 written to disk */ { _dos_write(tfh,StuffPtr->BuffPtr+HEADER, (StuffPtr->BlkSize & 0xff)-HEADER,&bw); } /* last block received? - goto end off */ if((*(StuffPtr->BuffPtr + BLKNUM_H) & 0xff) == EOT_FLAG) return(NOERR); /* get size of the next block from fifth byte of received block */ StuffPtr->BlkSize = (unsigned)*(StuffPtr->BuffPtr+NEXT_BSIZE); } if(flag == ERROR) { /* transmitter still sending ACK? */ if(GetBytes() != ERROR && strncmp(StuffPtr->CharPtr-3, StuffPtr->ReplyStr[CODE_ACK], 3) == NULL) continue; else /* otherwise reply BAD */ { badblocks++; prtstat(xfertotal,badblocks); StuffPtr->ReplyOut = CODE_BAD; /* signal a bad block received */ ++StuffPtr->ErrBlocks; /* increment local block error count */ } } if(SLCodes() == ERROR) return(ERROR); /* send & get reply */ } while(StuffPtr->ErrBlocks < MAXBLKERR); return(ERROR); } int BlockRec() /* get a block of data from serial buffer */ { long t1, t2; StuffPtr->CharPtr = StuffPtr->BuffPtr; /* cycle through wait periods */ if(++StuffPtr->Wait > 2) StuffPtr->Wait = 0; t2 = 0L; /* set to current time plus the wait period */ t1 = clock() + StuffPtr->Period[StuffPtr->Wait]; while(check() == NULL) { if(t2 > t1) return(ERROR); t2 = clock(); } do { t2 = 0L; t1 = clock() + 150L; /* max of .15 sec without receiving a byte */ while(check() == NULL) { if(t2 > t1) return(-2); t2 = clock(); } *StuffPtr->CharPtr = getser(); ++StuffPtr->CharPtr; } while(StuffPtr->CharPtr < StuffPtr->BuffPtr+(StuffPtr->BlkSize & 0xff)); return(ChksmRec()); /* return result of checksum verification */ } int ChksmRec() /* performs checksum tests on received block */ { /* do both additive and cyclical checksum calculation on block */ for(StuffPtr->Chksum = StuffPtr->CLC = 0,StuffPtr->CharPtr = StuffPtr->BuffPtr+4; StuffPtr->CharPtr < StuffPtr->BuffPtr + (StuffPtr->BlkSize & 0xff); StuffPtr->CharPtr++) { StuffPtr->Chksum += (*StuffPtr->CharPtr & 0xff); StuffPtr->CLC ^= (*StuffPtr->CharPtr & 0xff); if(StuffPtr->CLC & 0x8000) StuffPtr->CLC = (StuffPtr->CLC << 1) + 1; else StuffPtr->CLC <<= 1; } /* test against checksums received */ if(*(StuffPtr->BuffPtr+CHKSUM_L) == (char)StuffPtr->Chksum & 0xff && *(StuffPtr->BuffPtr+CHKSUM_H) == (char)(StuffPtr->Chksum >> 8 & 0xff) && *(StuffPtr->BuffPtr+CLC_L) == (char)StuffPtr->CLC & 0xff && *(StuffPtr->BuffPtr+CLC_H) == (char)(StuffPtr->CLC >> 8 & 0xff)) return(NOERR); /* signal good block */ else return(ERROR); /* signal bad block */ } int EndReceive() /* handle reply codes for ending data receive */ { if(SLCodes() == ERROR) return(ERROR); /* send & get reply */ StuffPtr->ReplyOut = CODE_SBK; /* send out 'S/B' */ StuffPtr->ReplyWant = CODE_SYN; /* want 'SYN' */ if(SLCodes() == ERROR) return(ERROR); /* send & get reply */ StuffPtr->ReplyOut = CODE_SYN; /* send 'SYN' */ StuffPtr->ReplyWant = CODE_SBK; /* want 'S/B' */ if(SLCodes() == ERROR) return(ERROR); /* send & get reply */ StuffPtr->ReplyOut = CODE_SBK; /* receiver terminates */ CodeOut(); return(NOERR); } /************************************************************************** * * functions to send blocks * **************************************************************************/ int fortran C1Send(pathname,bsize,fflg,loc) char *pathname; int bsize; int fflg; long loc; { struct find_t find, *f_ptr; int i; int x; scnloc=loc; C1Stuff.ReplyStr[0] = "ACK"; /* signal a good or bad block */ C1Stuff.ReplyStr[1] = "GOO"; /* signal a good block */ C1Stuff.ReplyStr[2] = "BAD"; /* signal a bad block */ C1Stuff.ReplyStr[3] = "SYN"; /* signal end of transfer sequence */ C1Stuff.ReplyStr[4] = "S/B"; /* request block or signal transfer done */ /* reply code Wait Period sequence */ C1Stuff.Period[0] = LONG; C1Stuff.Period[1] = LONG; C1Stuff.Period[2] = SHORT; StuffPtr = &C1Stuff; /* set pointer to C1 variables struct */ f_ptr = &find; C1Stuff.BuffPtr = C1Stuff.BuffOne; /* set pointer to a data buffer */ C1Stuff.FullBsize = 0; /* zero size of a full block */ C1Stuff.Wait = 0; /* zero reply code Wait Period index */ C1Stuff.TransFlag = FALSE; /* set ASCII-PETSCII TransFlag flag */ xfertotal = 0; badblocks = 0; _dos_open(pathname,O_RDONLY,&tfh); C1Stuff.FileFlag=fflg; C1Stuff.FullBsize=bsize; x=0; do { GetBytes(); if (x++>12 || c1cancel()==ERROR) return; } while (strncmp(StuffPtr->CharPtr-3,StuffPtr->ReplyStr[CODE_GOO],3) != NULL && x++<80); if(fflg != 0) { nocount = 1; if(FtypeSend(fflg) == ERROR) /* send the file type block */ { _dos_close(tfh); return(4); } } nocount = 0; if(DataSend() == ERROR) /* send data blocks */ { _dos_close(tfh); return(1); } _dos_close(tfh); return(0); } int FtypeSend(ftype) /* handle sending file type block */ int ftype; { StuffPtr->ErrCodes = NOERR; /* zero reply code error count */ StuffPtr->ErrBlocks = NOERR; /* zero data block error count */ StuffPtr->EndOff = FALSE; /* end off sequence flag */ StuffPtr->BlkSize = HEADER+1; /* set size of this block */ StuffPtr->BlkNum = 0; /* set number of this block */ /* build the file type block */ *(StuffPtr->BuffPtr+BLKNUM_L) = EOT_FLAG; /* sixth byte = 255 */ *(StuffPtr->BuffPtr+BLKNUM_H) = EOT_FLAG; /* seventh byte = 255 */ /* eighth byte contains file type: 1=SEQ(text),2=PROG(binary),3=WORDPRO */ *(StuffPtr->BuffPtr+FILE_TYPE) = ftype; ChksmSend(); /* get checksum into first four bytes */ /* start of a file type transfer */ if(SLBlocks() == ERROR) return(ERROR); /* send file type block */ return(EndSend()); /* return result of file type xfer end off */ } int DataSend() /* controls block sending sequence */ { StuffPtr->EndFlag = FALSE; /* local last block flag */ StuffPtr->EndOff = FALSE; /* end off sequence flag */ StuffPtr->ErrCodes = NOERR; /* zero reply code error count */ StuffPtr->ErrBlocks = NOERR; /* zero data block error count */ StuffPtr->BlkSize = HEADER; /* set up block zero */ *(StuffPtr->BuffPtr+NEXT_BSIZE) = HEADER; /* size of block zero */ /* build block zero */ *(StuffPtr->BuffPtr+BLKNUM_L) = 0x00; *(StuffPtr->BuffPtr+BLKNUM_H) = 0x00; StuffPtr->BlkNum = -1; ChksmSend(); /* get checksums into first four bytes */ if(SLBlocks() == ERROR) return(ERROR); /* send block zero */ ++StuffPtr->BlkNum; /* increment local block number */ /* set up block two so its size can be sent in block one */ if(DataBuild() == ERROR) return(ERROR); StuffPtr->BlkSize = HEADER; /* size of block one */ /* build block number one */ *(StuffPtr->BuffPtr+BLKNUM_L) = 0x01; *(StuffPtr->BuffPtr+BLKNUM_H) = 0x00; ChksmSend(); /* get checksums into first four bytes */ if(SLBlocks() == ERROR) return(ERROR); /* send block one */ do { ++StuffPtr->BlkNum; /* increment local block number */ /* current block obtained previously so its size is already known */ StuffPtr->BlkSize = StuffPtr->NextBsize; /* build next block and do checksums for current block */ if(DataBuild() == ERROR) return(ERROR); if(SLBlocks() == ERROR) return(ERROR); /* send current block */ /* if final block was sent do end off and return result */ if(StuffPtr->EndOff == TRUE) return(EndSend()); } while(TRUE); } int DataBuild() /* builds both the next and the current block */ { int BlkSize; /* holds actual no. of bytes read from disk */ /* read a block from disk if last block not yet obtained */ /* NOTE: block read now will be the following one sent, not current one */ if(StuffPtr->EndFlag == FALSE) { _dos_read(tfh,StuffPtr->BuffPtr+HEADER,StuffPtr->FullBsize-HEADER,&BlkSize); if(eof(tfh) != NULL) /* check for end-of-file */ { /* signal last block to receiver */ *(StuffPtr->BuffPtr+BLKNUM_L) = EOT_FLAG; *(StuffPtr->BuffPtr+BLKNUM_H) = EOT_FLAG; StuffPtr->EndFlag = TRUE; /* set local last block flag */ } else /* put block number in sixth & seventh bytes */ { *(StuffPtr->BuffPtr+BLKNUM_L) = (StuffPtr->BlkNum+1) & 0xff; *(StuffPtr->BuffPtr+BLKNUM_H) = (StuffPtr->BlkNum+1) >> 8 & 0xff; } /* store size of this block for when it is sent after current one */ StuffPtr->NextBsize = BlkSize+HEADER; } /* swap buffer pointer to other buffer which contains current block */ StuffPtr->BuffPtr = (StuffPtr->BuffPtr == StuffPtr->BuffOne) ? StuffPtr->BuffTwo : StuffPtr->BuffOne; /* set fifth byte of current block to size of next block */ *(StuffPtr->BuffPtr+NEXT_BSIZE) = StuffPtr->NextBsize & 0xff; /* put additive & cyclical checksums into first four bytes */ ChksmSend(); return(NOERR); } int SLBlocks() /* statement & listen loop for block send */ { int resend; char *charptr; do { resend = FALSE; /* set resend flag */ StuffPtr->ReplyOut = CODE_ACK; /* send 'ACK' to receiver */ StuffPtr->ReplyWant = CODE_SBK; /* want 'S/B' from receiver */ if(SLCodes() == ERROR) /* send & get reply */ { return(ERROR); } for(charptr = StuffPtr->BuffPtr; /* send out block */ charptr < StuffPtr->BuffPtr + (unsigned)StuffPtr->BlkSize; charptr++) putser(*charptr); do { GetBytes(); /* search for string match for 'GOO' or 'BAD' */ if(strncmp(StuffPtr->CharPtr-3,StuffPtr->ReplyStr[CODE_GOO],3) == NULL) { if (*(StuffPtr->BuffPtr + BLKNUM_H) !=0 || *(StuffPtr->BuffPtr + BLKNUM_L) !=0) { if (nocount==0) xfertotal += ((StuffPtr->BlkSize & 0xff) - HEADER); prtstat(xfertotal,badblocks); } StuffPtr->ErrBlocks = NOERR; /* clear block error count */ StuffPtr->ErrCodes = NOERR; /* clear reply error count */ if((*(StuffPtr->BuffPtr + BLKNUM_H) & 0xff) == EOT_FLAG) StuffPtr->EndOff = TRUE; /* final block sent ok */ return(NOERR); } else if(strncmp(StuffPtr->CharPtr-3,StuffPtr->ReplyStr[CODE_BAD],3) == NULL) { badblocks++; prtstat(xfertotal,badblocks); ++StuffPtr->ErrBlocks; /* increment block error count */ StuffPtr->ErrCodes = NOERR; /* clear reply error count */ resend = TRUE; /* flag no end off */ } else ++StuffPtr->ErrCodes; if(StuffPtr->ErrCodes > MAXCODERR) return(ERROR); } while(resend == FALSE); } while(StuffPtr->ErrBlocks < MAXBLKERR); return(ERROR); } void ChksmSend() /* generates checksums for current block */ { int x; /* calculate additive and cyclical checksums */ for(StuffPtr->Chksum=StuffPtr->CLC=0,StuffPtr->CharPtr=StuffPtr->BuffPtr+4; StuffPtr->CharPtr < StuffPtr->BuffPtr + (StuffPtr->BlkSize & 0xff); StuffPtr->CharPtr++) { StuffPtr->Chksum += (*StuffPtr->CharPtr & 0xff); StuffPtr->CLC ^= (*StuffPtr->CharPtr & 0xff); if(StuffPtr->CLC & 0x8000) StuffPtr->CLC = (StuffPtr->CLC << 1) + 1; else StuffPtr->CLC <<= 1; } /* put checksums into first four bytes */ *(StuffPtr->BuffPtr+CHKSUM_L) = StuffPtr->Chksum & 0xff; *(StuffPtr->BuffPtr+CHKSUM_H) = StuffPtr->Chksum >> 8 & 0xff; *(StuffPtr->BuffPtr+CLC_L) = StuffPtr->CLC & 0xff; *(StuffPtr->BuffPtr+CLC_H) = StuffPtr->CLC >> 8 & 0xff; } int EndSend() /* handle reply codes for data send */ { StuffPtr->EndXfer = FALSE; StuffPtr->ReplyOut = CODE_ACK; /* send 'ACK' */ StuffPtr->ReplyWant = CODE_SBK; /* want 'S/B' */ if(SLCodes() == ERROR) return(ERROR); /* send & get reply */ StuffPtr->ReplyOut = CODE_SYN; /* send 'SYN' */ StuffPtr->ReplyWant = CODE_SYN; /* want 'SYN' */ if(SLCodes() == ERROR) return(ERROR); /* send & get reply */ StuffPtr->EndXfer = TRUE; StuffPtr->ReplyOut = CODE_SBK; /* send 'S/B' */ StuffPtr->ReplyWant = CODE_SBK; /* want 'S/B' */ if(SLCodes() == ERROR) return(ERROR); /* send & get reply */ return(NOERR); } /************************************************************************** * * functions common to both receiving and sending * **************************************************************************/ int SLCodes() /* statement & listen loop for reply codes */ { do { if (c1cancel()==ERROR) return (ERROR); CodeOut(); /* send reply code to receiver */ /* on final end off only send 'S/B' three times */ if(StuffPtr->EndXfer == TRUE && StuffPtr->ErrCodes > 1) return(NOERR); if(GetBytes() == ERROR) continue; /* search for string match */ if(strncmp(StuffPtr->CharPtr-3, StuffPtr->ReplyStr[StuffPtr->ReplyWant],3) == NULL) { StuffPtr->ErrCodes = NOERR; /* clear reply code error count */ return(NOERR); } else ++StuffPtr->ErrCodes; } while(StuffPtr->ErrCodes < MAXCODERR); return(ERROR); } int GetBytes() { long t1, t2; StuffPtr->CharPtr = StuffPtr->TempBuff; *(StuffPtr->CharPtr+0)=0; *(StuffPtr->CharPtr+1)=0; *(StuffPtr->CharPtr+2)=0; /* cycle through wait periods */ if(++StuffPtr->Wait > 2) StuffPtr->Wait = 0; t2 = 0L; /* set to current time plus the wait period */ t1 = clock() + StuffPtr->Period[StuffPtr->Wait]; while(check() == NULL) { if(t2 > t1) { ++StuffPtr->ErrCodes; return(ERROR); } t2 = clock(); } do { t2 = 0L; t1 = clock() + 50L; /* max of .05 sec without receiving a byte */ while(check() == NULL) { if(t2 > t1) { StuffPtr->CharPtr += 3; return(NOERR); } t2 = clock(); } *(StuffPtr->CharPtr+0)=*(StuffPtr->CharPtr+1); *(StuffPtr->CharPtr+1)=*(StuffPtr->CharPtr+2); *(StuffPtr->CharPtr+2)=getser(); } while(1); } int CodeOut() /* send out a reply code */ { if (StuffPtr->ReplyOut < 5) { StuffPtr->CharPtr = StuffPtr->ReplyStr[StuffPtr->ReplyOut]; while(*StuffPtr->CharPtr != NULL) putser(*StuffPtr->CharPtr++); } } int c1cancel () { int x; if ((inp(1022) & 128)==0) return (ERROR); x=_bios_keybrd(_KEYBRD_SHIFTSTATUS) & 15; if (x==14 || x==13) return (ERROR); return (NOERR); } -- UUCP: watmath!xenitec!zswamp!root | 602-66 Mooregate Crescent Internet: root@zswamp.fidonet.org | Kitchener, Ontario FidoNet: SYSOP, 1:221/171 | N2M 5E6 CANADA Data: (519) 742-8939 | (519) 741-9553 MC Hammer, n. Device used to ensure firm seating of MicroChannel boards Try our new Bud 'C' compiler... it specializes in 'case' statements!