wht@tridom.uucp (Warren Tucker) (10/11/89)
---- Cut Here and unpack ---- #!/bin/sh # this is part 30 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file z/zcommon.c continued # CurArch=30 if test ! -r s2_seq_.tmp then echo "Please unpack part 1 first!" exit 1; fi ( read Scheck if test "$Scheck" != $CurArch then echo "Please unpack part $Scheck next!" exit 1; else exit 0; fi ) < s2_seq_.tmp || exit 1 echo "x - Continuing file z/zcommon.c" sed 's/^X//' << 'SHAR_EOF' >> z/zcommon.c X\----> need M_XENIX or pyr defined X#endif X fprintf(stderr," using '%s'\r\n",home_dir); X } X else X strcpy(home_dir,cptr); /* home directory to string */ X X if( (strlen(home_dir) == 1) && (*home_dir == '/')) /* root is home */ X *home_dir = 0; /* use null for home dir of root */ X X} /* end of get_home_dir */ X X/* end of zcommon.c */ X/* vi: set tabstop=4 shiftwidth=4: */ SHAR_EOF echo "File z/zcommon.c is complete" chmod 0644 z/zcommon.c || echo "restore of z/zcommon.c fails" echo "x - extracting sea/Makefile (Text)" sed 's/^X//' << 'SHAR_EOF' > sea/Makefile && X# CHK=0x5649 X#+---------------------------------------------------------- X# Makefile for ecusea X#----------------------------------------------------------- X#+:EDITS:*/ X#:07-03-1989-22:58-wht------------- ecu 2.00 ---------------- X X XCFLAGS = -i -Ox -K -DLINT_ARGS XLFLAGS = -lx -lcurses -ltermcap X XSRC = \ X ecusea.c\ X scurses.c X XOBJ = \ X ecusea.o\ X scurses.o\ X ../ecudump.o X Xecusea: $(OBJ) Makefile X cc $(CFLAGS) $(LFLAGS) $(OBJ) -o ecusea X Xecusea.fls: $(SRC) X ls $(SRC) >ecusea.fls X Xlint: ecusea.fls X echo > lint_args.h X csh ../zgcc ecusea.fls lint_args.h $(CFLAGS) X fcrc -u Makefile *.c *.h X SHAR_EOF chmod 0644 sea/Makefile || echo "restore of sea/Makefile fails" echo "x - extracting sea/ecusea.c (Text)" sed 's/^X//' << 'SHAR_EOF' > sea/ecusea.c && X/* CHK=0x76B7 */ Xchar *revision = "1.0"; /* cannot be longer than 7 chars (blk0.sender) */ X/* #define TABLE_CRC16 */ X/*+------------------------------------------------------------------------- X ecusea.c - SEAlink - Sliding window file transfer protocol X X Defined functions: X crc_update(c,crc) X lgetc_timeout(tenths) X lgetc_timeout_SIGALRM() X main(argc,argv,envp) X receive_block(buf) X receive_file() X send_comm_block(blk,blknum) X send_file(name) X send_file_block(fp,blknum) X set_utime_1980(filename,secs_since_1980) X wait_for_rcvr_response() X xmit_ack(blknum) X xmit_cancel() X xmit_nak(blknum) X Xecu adaptation by W. Tucker Xmodelled after MSDOS sealink.c, which carried the following proviso: X X MS-DOS Version 1.20, created on 08/05/87 X at 17:51:40 (C) COPYRIGHT 1986,87 by X System Enhancement Associates; ALL RIGHTS X RESERVED By: Thom Henderson X X You are granted a license to use this X code in your programs, and to adapt it to X your particular situation and needs, X subject only to the following conditions: X 1) You must refer to it as the SEAlink X protocol, and you must give credit to X System Enhancement Associates. 2) If you X modify it in such a way that your version X cannot converse with the original code as X supplied by us, then you should refer to X it as "SEAlink derived", or as a X "variation of SEAlink", or words to that X effect. In short, we're not asking for X any money, but we'd like to get some X credit for our work. X X--------------------------------------------------------------------------*/ X/*+:EDITS:*/ X/*:07-03-1989-22:58-wht------------- ecu 2.00 ---------------- */ X/*:05-26-1989-20:25-wht-was clobberring CBAUD part of c_cflag */ X/*:05-26-1989-20:10-wht-add cancel_transaction */ X/*:05-24-1989-23:10-wht-add table lookup crc */ X/*:05-24-1989-19:06-wht-adoption of pd source with SERIOUS hardening */ X X#include <stdio.h> X#include <string.h> X#include <ctype.h> X#include <signal.h> X#include <setjmp.h> X#include <fcntl.h> X#include <termio.h> X#include <sys/ioctl.h> X#include <sys/types.h> X#include <sys/stat.h> X#include <time.h> X#include <sys/timeb.h> X#include <memory.h> X#if defined(M_I386) X#include <sys/select.h> X#endif X X#include "lint_args.h" X X/* Various system constants */ X#define WINDOW 6 /* maximum size of window */ X#define TIMEOUT 0x0FFF X#define OFFSET_1980 (time_t)315547200 /* time offset for 1970 <-> 1980 */ X X/* X * The section of code that is compiled when NAKEOT is defined is in the X * original MS-DOS version 1.16 routine. Its purpose is to send a NAK when X * an EOT is received during receive_file(), apparently to confirm that this is X * indeed the end of file. However, in certain (apparently non - standard) X * versions of the protocol, it is possible that the program will report an X * error when in fact there isn't one. Comment this out at your discretion. X */ X#define NAKEOT X X/* SEAlink block zero data structure */ Xtypedef struct blk0 X{ X long length; /* length */ X time_t secs_since_1980; /* creation/last mod in secs since 1/1/80 */ X char filename[17]; /* file name */ X char sender[15]; /* sending program */ X char send_no_acks; /* true if rcvr need not ack */ X char filler[87]; /* fill to 128 bytes */ X} BLK0; X X/* protocol characters */ X#define SOH 0x01 X#define EOT 0x04 X#define ACK 0x06 X#define NAK 0x15 X#define CAN 0x18 X X/* send_file state (sf_state) values */ X#define SFS_GND 0 /* Ground state, ACK or NAK expected */ X#define SFS_ACK 1 /* ACK received */ X#define SFS_NAK 2 /* NAK received */ X#define SFS_ACKW 3 /* ACK, block# received */ X#define SFS_NAKW 4 /* NAK, block# received */ X#define SFS_RGND 5 /* Returning to ground state */ Xint sf_state; X Xint allow_slide = 1; /* sliding windows allowed */ Xint crc_in_use; /* check type, 1 = CRC, 0 = checksum */ Xchar *dfile = "/tmp/ecuSEA.log"; Xint error_count; /* total number of errors */ Xint iofd = 0; /* file descriptor to use */ Xint no_ack_mode = 1; /* true of ACKs not required */ Xint rf_done = 0; /* receive file done */ Xint sf_ackw_count; /* count of sliding ACKs seen */ Xint sf_ackblk; /* number of last block ACKed */ Xint sf_blknum; /* number of next block to send */ Xint sf_lastnum; /* number of last block sent */ Xint sf_nakquan; /* number of sequential NAKs */ Xint sf_slide; /* true if sliding window */ X Xint sending_flag = -1; /* send == 1, receive == 0, bad usage == -1 */ Xint log_packets = 0; Xlong rx_char_count = 0; Xlong tx_char_count = 0; Xint Filcnt = 0; Xint npaths = 0; Xchar curr_dir[256]; Xchar s128[128]; X Xstruct termio tio; X Xjmp_buf lgetc_timeout_setjmp; X X/* CRC16 routine; finish CRC calculation for compare */ X X#ifdef TABLE_CRC16 X X/* crctab calculated by Mark G. Mendel,Network Systems Corporation */ Xunsigned short crctab[256] = X{ X 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, X 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, X 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, X 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, X 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, X 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, X 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, X 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, X 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, X 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, X 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, X 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, X 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, X 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, X 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, X 0xFF9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, X 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, X 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, X 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, X 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, X 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, X 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, X 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, X 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634, X 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, X 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3, X 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, X 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92, X 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9, X 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1, X 0xef1f,0xFF3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, X 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 X}; X X/*+------------------------------------------------------------------------- X updcrc macro derived from article Copyright (C) 1986 Stephen Satchell. X NOTE: First argument must be in range 0 to 255. X Second argument is referenced twice. X Programmers may incorporate any or all code into their programs, giving X proper credit within the source. Publication of the source routines is X permitted so long as proper credit is given to Stephen Satchell, X Satchell Evaluations and Chuck Forsberg, Omen Technology. X--------------------------------------------------------------------------*/ X#define crc_update(ch,crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ ch) X X#else /* calculated crc */ X X/*+------------------------------------------------------------------------- X crc_update(c,crc) X--------------------------------------------------------------------------*/ Xunsigned short Xcrc_update(c,crc) Xregister c; Xregister unsigned crc; X{ Xregister count; X X for(count = 8; --count >= 0;) X { X if(crc & 0x8000) X { X crc <<= 1; X crc += (((c <<= 1) & 0400) != 0); X crc ^= 0x1021; X } X else X { X crc <<= 1; X crc += (((c <<= 1) & 0400) != 0); X } X } X return(crc); X} /* end of crc_update */ X#endif /* crc calc selection */ X X/*+------------------------------------------------------------------------- X xmit_cancel() X--------------------------------------------------------------------------*/ Xvoid Xxmit_cancel() X{ Xchar *cancel_msg = "\030\030\030\030\030\030\030\030\b\b\b\b\b\b\b\b"; X X ioctl(iofd,TCFLSH,(char *)1); X write(iofd,cancel_msg,16); X tx_char_count += 16; X report_str("CANCELling transfer",1); X report_last_txhdr("CAN",0); X X} /* end of xmit_cancel */ X X/*+------------------------------------------------------------------------- X xmit_ack(blknum) X--------------------------------------------------------------------------*/ Xvoid Xxmit_ack(blknum) Xregister int blknum; /* block number */ X{ Xchar s16[16]; X X sprintf(s16,"ACK %3d",blknum); X report_last_txhdr(s16,0); X X s16[0] = ACK; X s16[1] = blknum; /* block number */ X s16[2] = blknum ^ 0xFF; /* block number check */ X write(iofd,s16,3); X tx_char_count += 3; X} /* end of xmit_ack */ X X/*+------------------------------------------------------------------------- X xmit_nak(blknum) X--------------------------------------------------------------------------*/ Xvoid Xxmit_nak(blknum) Xregister int blknum; /* block number */ X{ Xchar s16[16]; X X sprintf(s16,"NAK %d",blknum); X report_last_txhdr(s16,1); X X if(crc_in_use) X s16[0] = 'C'; X else X s16[0] = NAK; X X s16[1] = blknum; /* block number */ X s16[2] = blknum ^ 0xFF; /* block number check */ X write(iofd,s16,3); X tx_char_count += 3; X X} /* end of xmit_nak */ X X/*+------------------------------------------------------------------------- X lgetc_timeout_SIGALRM() - called when alarm is caught by lgetc_timeout X--------------------------------------------------------------------------*/ X#if defined(M_I286) Xvoid Xlgetc_timeout_SIGALRM() X{ X longjmp(lgetc_timeout_setjmp,TIMEOUT); X} /* end of lgetc_timeout_SIGALRM */ X#endif X X/*+------------------------------------------------------------------------- X lgetc_timeout(tenths) X X reads one character from line unless timeout in tenths passes X with no receipt. X--------------------------------------------------------------------------*/ Xunsigned int Xlgetc_timeout(tenths) Xint tenths; X{ X#if defined(M_I286) Xunsigned char rdchar; Xlong msec; Xint seconds; Xlong nap(long); X#else Xint fdmask; Xstruct timeval tval; Xunsigned char rdchar; X#endif X X if(!tenths) X { X if(!rdchk(iofd)) X return(TIMEOUT); X else X { X read(iofd,&rdchar,1); X rx_char_count++; X return((unsigned int)rdchar); X } X } X X#if defined(M_I286) X X/* there is a timeout ... if less than 2 secs, nap it out */ X if(tenths <= 20) X { X msec = (tenths < 6) ? 60L : (long)tenths * 10; X while(msec) X { X msec -= nap(20L); X if(rdchk(iofd)) X { X read(iofd,&rdchar,1); X rx_char_count++; X return((unsigned int)rdchar); X } X } X report_last_rxhdr("TIMEOUT",0); X return(TIMEOUT); X } X X/* timeout is > 2 seconds use sleep */ X X seconds = (tenths / 10) + 1; X X if(setjmp(lgetc_seconds_setjmp)) X { X report_last_rxhdr("TIMEOUT",0); X return(TIMEOUT); X } X X signal(SIGALRM,lgetc_timeout_SIGALRM); X alarm(seconds); X while(read(iofd,&rdchar,1) != 1) X ; X alarm(0); X signal(SIGALRM,SIG_DFL); X X#else X X if(tenths < 6) X tenths = 6; X tval.tv_sec = tenths / 10L; X tval.tv_usec = (tenths % 10L) * 100000L; X fdmask = 1 << iofd; X if(select(32,&fdmask,(int *)0,(int *)0,&tval) != 1) X { X report_last_rxhdr("TIMEOUT",0); X return(TIMEOUT); X } X if((!rdchk(iofd)) || (read(iofd,&rdchar,1) < 0)) X { X report_last_rxhdr("TIMEOUT",0); X return(TIMEOUT); X } X X#endif X X rx_char_count++; X return((unsigned int)rdchar); X X} /* end of lgetc_timeout */ X X/*+------------------------------------------------------------------------- X sf_state_text(state) X--------------------------------------------------------------------------*/ Xchar * Xsf_state_text(state) Xregister state; X{ Xchar unrecog[16]; X X switch(state) X { X case SFS_GND: return("GND"); X case SFS_ACK: return("ACK"); X case SFS_NAK: return("NAK"); X case SFS_ACKW: return("ACKW"); X case SFS_NAKW: return("NAKW"); X case SFS_RGND: return("RGND"); X default: X sprintf(unrecog,"SFS_%d",state); X return(unrecog); X } X X} /* end of sf_state_text */ X X/*+------------------------------------------------------------------------- X set_sf_state(place,new_state) X--------------------------------------------------------------------------*/ Xvoid Xset_sf_state(place,new_state) Xint place; Xint new_state; X{ X if(log_packets) X { X sprintf(s128,"state from %s to %s (%d)", X sf_state_text(sf_state),sf_state_text(new_state),place); X report_str(s128,0); X } X sf_state = new_state; X} /* end of set_sf_state */ X X/*+------------------------------------------------------------------------- X wait_for_rcvr_response() - check for ACK or NAK X sets 'sf_state' to SFS_... value depending on response from file rcvr X--------------------------------------------------------------------------*/ Xvoid Xwait_for_rcvr_response() X{ Xint c; /* one byte of data */ Xstatic int rawblk = 0; /* raw block number */ X X while((c = lgetc_timeout((sf_state == SFS_GND) ? 0 : 6)) != TIMEOUT) X { X if(c == CAN) X { /* CANcel received? */ X if((c = lgetc_timeout(20)) == CAN) X { X sf_nakquan = 11; X report_last_rxhdr("CAN",0); /* error counted at cancel time */ X } X break; X } X if(sf_state == SFS_ACKW || sf_state == SFS_NAKW) /* windowed */ X { X sf_slide = 0; /* assume this will fail */ X /* see if we believe the number */ X if(rawblk == (c ^ 0xFF)) X { X rawblk = sf_blknum - ((sf_blknum - rawblk)&0xFF); X if((rawblk >= 0) && (rawblk <= sf_blknum) && X (rawblk > (sf_blknum - 128))) X { /* we have sliding window! */ X if(sf_state == SFS_ACKW) X { X sf_ackblk = (sf_ackblk > rawblk) ? sf_ackblk : rawblk; X sf_slide = 1; X if(no_ack_mode && (++sf_ackw_count > 10)) X { X no_ack_mode = 0; X report_str("Overdrive disengaged",0); X } X } X else X { X sf_blknum = (rawblk < 0) ? 0 : rawblk; X sf_slide = (sf_nakquan < 4); X } X sprintf(s128,"%s %5d", X (sf_state == SFS_ACKW) ? "ACKW" : "NAKW",rawblk); X report_last_rxhdr(s128,(sf_state == SFS_NAKW)); X } X } X set_sf_state(1,SFS_RGND); /* return to ground state */ X } X X if(sf_state == SFS_ACK || sf_state == SFS_NAK) X { X rawblk = c; X if(sf_state == SFS_ACK) X set_sf_state(2,SFS_ACKW); X else X set_sf_state(3,SFS_NAKW); X } X X if(!sf_slide || sf_state == SFS_GND) X { X if(c == ACK) X { X if(!sf_slide) X { X sprintf(s128,"ACK %3d",sf_ackblk); X report_last_rxhdr(s128,0); X sf_ackblk++; X } X set_sf_state(4,SFS_ACK); X sf_nakquan = 0; X } X else if(c == 'C' || c == NAK) X { X /* if method not determined yet */ X if(crc_in_use > 1) /* then do what rcvr wants */ X { X crc_in_use = (c == 'C'); X report_protocol_crc_type(crc_in_use ? "/CRC16" : "/CHK"); X } X ioctl(iofd,TCFLSH,(char *)1); X if(!sf_slide) X { X sf_blknum = sf_ackblk + 1; X sprintf(s128,"NAK %3d",sf_blknum); X report_last_rxhdr(s128,1); X } X set_sf_state(5,SFS_NAK); X sf_nakquan++; X if(sf_lastnum) X error_count++; X } X } X X if(sf_state == SFS_RGND) X set_sf_state(6,SFS_GND); X } X} /* end of wait_for_rcvr_response */ X X/*+------------------------------------------------------------------------- X send_comm_block(blk,blknum) - format and transmit block X--------------------------------------------------------------------------*/ Xint Xsend_comm_block(blk,blknum) Xchar *blk; /* data to be shipped */ Xint blknum; /* number of block */ X{ Xregister unsigned short rUINT16 = 0; Xregister int itmp; Xunsigned char chksum; Xchar *cptr = blk; Xchar s3[3]; X X s3[0] = SOH; /* block header */ X s3[1] = blknum; /* block number */ X s3[2] = blknum ^ 0xFF; /* block number check value */ X X/* calculate the crc or checksum */ X itmp = 128; X if(crc_in_use) X { X while(itmp--) X { X rUINT16 = crc_update(*cptr,rUINT16); X cptr++; X } X rUINT16 = crc_update(0,rUINT16); X rUINT16 = crc_update(0,rUINT16); X } X else X { X while(itmp--) X rUINT16 += *cptr++; X } X X/* write the block */ X X{FILE *dfp= fopen("egad.log","a"); Xfprintf(dfp,"------ blknum %d ---------\n",blknum); Xhex_dump_fp(dfp,s3,3,"",1); Xhex_dump_fp(dfp,blk,128,"",1); Xfclose(dfp); X} X X write(iofd,s3,3); /* the header */ X write(iofd,blk,128); /* the block */ X if(crc_in_use) /* the crc or checksum */ X { X s3[0] = rUINT16 >> 8; X s3[1] = rUINT16 & 0xFF; X write(iofd,s3,2); X tx_char_count += 133; X } X else X { X chksum = rUINT16; X write(iofd,&chksum,1); X tx_char_count += 132; X } X X return(1); X} /* end of send_comm_block */ X X/*+------------------------------------------------------------------------- X send_file_block(fp,blknum) - read a block from file and send it X--------------------------------------------------------------------------*/ Xvoid Xsend_file_block(fp,blknum) XFILE *fp; Xint blknum; X{ Xlong fileaddr; Xchar buf[128]; X X fileaddr = (long)(blknum - 1) * 128L; X if(blknum != sf_lastnum + 1) X fseek(fp,fileaddr,0); /* move where to */ X sf_lastnum = blknum; X report_txpos(fileaddr); X X memset(buf,0x1A,sizeof(buf)); /* fill buffer with control Zs */ X fread(buf,1,sizeof(buf),fp); /* read in some data */ X send_comm_block(buf,blknum); /* pump it out to the receiver */ X} /* end of send_file_block */ X X/*+------------------------------------------------------------------------- X send_file(name) - transmit a file X--------------------------------------------------------------------------*/ Xint Xsend_file(name) Xchar *name; X{ Xregister int endblk; /* block number of EOT */ XFILE *fp; /* file to send */ Xstruct stat fst; XBLK0 blk0; Xchar *basename; /* base filename */ Xchar eot = EOT; X X Filcnt++; X if(name && *name) /* if sending a file */ X { X if((fp = fopen(name,"r")) == NULL) X { X sprintf(s128,"Cannot open %s",name); X report_str(s128,1); X return(0); X } X X memset((char *)&blk0,0,sizeof(blk0)); /* clear out data block */ X X stat(name,&fst); /* get file statistics */ X blk0.length = (long)fst.st_size; X X /* cnvt time from 1970 base to 1980 */ X if((blk0.secs_since_1980 = fst.st_mtime-OFFSET_1980) < 0L) X blk0.secs_since_1980 = 0; X X if((basename = strrchr(name,'/')) == NULL) /* find basename */ X strcpy(blk0.filename,name); X else X { X basename++; X strcpy(blk0.filename,basename); X } X X strcpy(blk0.sender,"ecusea "); X strcat(blk0.sender,revision); X blk0.send_no_acks = no_ack_mode; X X endblk = (int)((blk0.length + 127L) / 128L) + 1; X report_file_send_open(name,&fst); X } X else X { X endblk = 0; /* fake for no file */ X report_str("sending EOT indication",-1); X report_txpos(blk0.length); X } X X X sf_blknum = 1; /* set starting state */ X sf_ackblk = -1; X sf_state = SFS_GND; X sf_lastnum = 0; X sf_slide = 0; X sf_nakquan = 0; X error_count = 0; X sf_ackw_count = 0; X crc_in_use = 2; /* undetermined */ X X while(sf_ackblk < endblk) /* while not all there yet */ X { X if(sf_blknum <= sf_ackblk + ((sf_slide && allow_slide) ? WINDOW : 1)) X { X if(sf_blknum < endblk) X { X if(sf_blknum > 0) X { X sprintf(s128,"sending block %d",sf_blknum); X report_last_txhdr(s128,0); X send_file_block(fp,sf_blknum); X } X else X { X sprintf(s128,"sending filename",sf_blknum); X report_last_txhdr(s128,0); X send_comm_block((char *)&blk0,0); X report_txpos(0L); X } X if(no_ack_mode && sf_slide && allow_slide) X sf_ackblk = sf_blknum; X } X else if(sf_blknum == endblk) X { X report_last_txhdr("EOT",0); X write(iofd,&eot,1); X nap(500L); X tx_char_count++; X } X sf_blknum++; X } X X wait_for_rcvr_response(); X X if(sf_nakquan > 10) X goto CANCEL_TRANSFER; X } X X if(endblk) X fclose(fp); X return(1); /* exit with good status */ X XCANCEL_TRANSFER: X if(endblk) X fclose(fp); X xmit_cancel(); X return(0); /* exit with bad status */ X} /* end of send_file */ X X/*+------------------------------------------------------------------------- X set_utime_1980(filename,secs_since_1980) X--------------------------------------------------------------------------*/ Xvoid Xset_utime_1980(filename,secs_since_1980) Xchar *filename; /* file to set stamp on */ Xlong secs_since_1980; X{ Xtime_t times[2]; Xtime_t time(); X X times[0] = time((long *) 0); /* accessed */ X times[1] = secs_since_1980 + OFFSET_1980; /* modified (convert time) */ X utime(filename,times); X} /* end of set_utime_1980 */ X X/*+------------------------------------------------------------------------- X receive_block(buf) - get block from line Xreturn 0 if good chk/CRC, 1 if bad X--------------------------------------------------------------------------*/ Xint Xreceive_block(buf) Xchar *buf; /* data buffer */ X{ Xregister unsigned int rdchar; Xregister unsigned short rUINT16 = 0; /* calculated CRC or check value */ Xint itmp; Xint timeout = no_ack_mode ? 200 : 5; /* short block timeout */ Xunsigned short rcvd_crc; /* received CRC or check value */ X X itmp = 128; X while(itmp--) X { X if((rdchar = lgetc_timeout(timeout)) == TIMEOUT) X return(1); X if(crc_in_use) X rUINT16 = crc_update(rdchar,rUINT16); X else X rUINT16 += rdchar; X *buf++ = rdchar; X } X X if(crc_in_use) X { X rUINT16 = crc_update(0,rUINT16); X rUINT16 = crc_update(0,rUINT16); X rdchar = lgetc_timeout(timeout); X rcvd_crc = (rdchar << 8) | lgetc_timeout(timeout); X } X else X { X rUINT16 &= 0xFF; X rcvd_crc = lgetc_timeout(timeout) & 0xFF; X } X X if(rUINT16 != rcvd_crc) X { X sprintf(s128,"bad %s calc=%04x rcvd=%04x", X crc_in_use ? "CRC" : "checksum",rcvd_crc,rUINT16); X report_str(s128,-1); X } X return(rUINT16 != rcvd_crc); X} /* end of receive_block */ X X/*+------------------------------------------------------------------------- X receive_file() X--------------------------------------------------------------------------*/ Xchar * Xreceive_file() X{ Xint rdchar; /* received character */ Xint tries; /* retry counter */ Xint blknum; /* desired block number */ Xint inblk; /* this block number */ XFILE *fp; Xchar buf[128]; /* data buffer */ Xchar tmpname[100]; /* name of temporary file */ Xstatic char outname[100]; /* name of final file */ XBLK0 blk0; /* file header data storage */ Xint endblk; /* block number of EOT, if known */ Xlong left; /* bytes left to output */ Xint itmp; /* index */ Xint cnvrt; /* flag -- convert filename? */ Xchar *onp; /* use to convert filename to l / rdchar */ Xchar *basename; /* base filename */ Xlong ftell(); X X *outname = '\0'; /* get name from transmitter */ X cnvrt = 1; /* convert to local is necessary */ X sprintf(tmpname,"./SEA%05d.tmp",getpid()); /* use a unique temp filename */ X X if(!(fp = fopen(tmpname,"w"))) X { /* open temporary file */ X sprintf(s128,"Cannot create temp file %s\n",tmpname); X report_str(s128,0); X xmit_cancel(); X return(NULL); X } X X blknum = 0; X tries = -10; /* kludge for first time around */ X crc_in_use = 1; /* try for CRC error checking */ X error_count = 0; /* no errors yet */ X endblk = 0; /* we don't know the size yet */ X no_ack_mode = 0; /* we don't know about this yet */ X memset((char *)&blk0,0,sizeof(blk0)); /* or much of anything else */ X report_protocol_crc_type("/CRC16"); X XSEND_NAK: /* we got a bad block */ X if(blknum > 1) X error_count++; X if(++tries > 10) X goto CANCEL_TRANSFER; X if(tries == 0) /* if CRC isn't going */ X { X crc_in_use = 0; /* then give checksum a try */ X report_protocol_crc_type("/CHK"); X } X X xmit_nak(blknum); /* send the NAK */ X if(no_ack_mode && error_count > 20) X { /* if no_ack_mode mode isn't working */ X no_ack_mode = 0; /* then shut it off */ X report_str("Overdrive disengaged",0); X } X XRECEIVE_NEXT_BLOCK: /* start of "get a block" */ X report_rxpos(ftell(fp)); X while((rdchar = lgetc_timeout(30)) != TIMEOUT) X { X if(rdchar == CAN) X { X if((rdchar = lgetc_timeout(30)) == CAN) X { X xmit_cancel(); X return(NULL); X } X break; X } X if(rdchar == EOT) X { X if(!endblk || endblk == blknum) X goto RECEIVE_EOT_SEEN; X } X else if(rdchar == SOH) X { X if((inblk = lgetc_timeout(5)) == TIMEOUT) X goto SEND_NAK; X if(lgetc_timeout(5) == (inblk ^ 0xFF)) X { X sprintf(s128,"receiving %d",inblk); X report_last_rxhdr(s128,0); X goto GOT_START_OF_BLOCK; /* we found a start */ X } X } X } X goto SEND_NAK; X XGOT_START_OF_BLOCK: /* start of block detected */ X rdchar = blknum & 0xFF; X if(inblk == 0 && blknum <= 1) X { /* if this is the header */ X if(receive_block((char *)&blk0)) X goto SEND_NAK; /* bad header block */ X else X { X xmit_ack(inblk); /* ack the header */ X strcpy(outname,blk0.filename); X report_file_rcv_started(blk0.filename,blk0.length, X blk0.secs_since_1980 + OFFSET_1980); X if(left = blk0.length) /* length to transfer */ X endblk=(int)((left + 127L)/128L)+1; X if(no_ack_mode != blk0.send_no_acks) X { X sprintf(s128,"Overdrive %sengaged", X (blk0.send_no_acks) ? "" : "dis"); X report_str(s128,0); X } X no_ack_mode = blk0.send_no_acks; X blknum = 1; /* now we want first data block */ X goto RECEIVE_NEXT_BLOCK; X } X } X X if(inblk == rdchar) X { /* if this is the one we want */ X if(!receive_block(buf)) X { /* else if we get it okay */ X if(!no_ack_mode) /* if we're sending ACKs */ X xmit_ack(inblk); /* then ACK the data */ X for(itmp = 0; itmp < 128; itmp++) X { X if(endblk) X { /* limit file size if known */ X if(!left) X break; X left--; X } X if(fputc(buf[itmp],fp) == EOF) X { X report_str("FILE WRITE ERROR",0); X goto CANCEL_TRANSFER; X } X } X tries = 0; /* reset try count */ X blknum++; /* we want the next block */ X goto RECEIVE_NEXT_BLOCK; X } X goto SEND_NAK; /* ask for a resend */ X } X X if(inblk < rdchar || inblk > rdchar + 100) X { /* if resending what we have */ X receive_block(buf); /* ignore it */ X xmit_ack(inblk); /* but ack it */ X } X goto RECEIVE_NEXT_BLOCK; /* else if running ahead */ X XRECEIVE_EOT_SEEN: X#ifdef NAKEOT X xmit_nak(blknum); /* NAK the EOT, make sure */ X if(lgetc_timeout(20) != EOT) /* we're all done */ X goto SEND_NAK; X#endif /* NAKEOT */ X xmit_ack(blknum); /* ACK it and clean up */ X report_last_rxhdr("EOT",0); X if(blknum > 1) SHAR_EOF echo "End of part 30" echo "File sea/ecusea.c is continued in part 31" echo "31" > s2_seq_.tmp exit 0 -- ------------------------------------------------------------------- Warren Tucker, Tridom Corporation ...!gatech!emory!tridom!wht Ker-au'-lo-phon. An 8-foot partial flue-stop, having metal pipes surmounted by adjustable rings, and with a hole bored near the top of each pipe, producing a soft and "reedy" tone.