wht@n4hgf.uucp (Warren Tucker) (01/06/91)
Submitted-by: wht@n4hgf.uucp (Warren Tucker) Posting-number: Volume 16, Issue 47 Archive-name: ecu3/part23 ---- Cut Here and feed the following to sh ---- #!/bin/sh # This is part 23 of ecu3 if touch 2>&1 | fgrep 'amc' > /dev/null then TOUCH=touch else TOUCH=true fi # ============= sea/ecusea.c ============== if test ! -d 'sea'; then echo 'x - creating directory sea' mkdir 'sea' fi echo 'x - extracting sea/ecusea.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'sea/ecusea.c' && X Xchar *revision = "1.10"; /* cannot be longer than 7 chars (blk0.sender) */ X X/* #define TABLE_CRC16 */ X#ifdef M_XENIX X#define NO_SELECT X#endif X X/*+------------------------------------------------------------------------- X ecusea.c - SEAlink - Sliding window file transfer protocol X X Defined functions: X arg_token(parsestr,termchars) X cancel_transaction(sig) X crc_update(c,crc) X fname_split(cmd,arg,arg_max_quan,narg_rtn) X fname_too_long(fname) X fname_truncated() X getspeed(code) 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_sf_state(place,new_state) X set_utime_1980(filename,secs_since_1980) X sf_state_text(state) 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/*:08-14-1990-20:40-wht@n4hgf-ecu3.00-flush old edit history */ 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(NO_SELECT) 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 = 0; /* 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]; Xunsigned baud_rate; Xint exit_code; Xint sent_EOT = 0; X Xstruct termio tio; Xstruct termio tio0; 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 arg_token(parsestr,termchars) X XGet next token from string parsestr ((char *)0 on 2nd, 3rd, etc. Xcalls), where tokens are nonempty strings separated by runs of chars Xfrom termchars. Writes nulls into parsestr to end tokens. Xtermchars need not remain constant from call to call. X XTreats multiple occurrences of a termchar as one delimiter (does not Xallow null fields). X------------------------------------------------------------------------*/ X#if defined(M_UNIX) Xstatic char *arg_token_static = (char *)0; Xchar *arg_token(parsestr,termchars) Xchar *parsestr; Xchar *termchars; X{ Xregister int first = 1; Xregister char *termptr; Xregister char *parseptr; Xchar *token; X X if(parsestr == (char *)0 && arg_token_static == (char *)0) X return((char *)0); X X if(parsestr) X parseptr = parsestr; X else X parseptr = arg_token_static; X X while(*parseptr) X { X if(!strchr(termchars,*parseptr)) X break; X parseptr++; X } X X if(!*parseptr) X { X arg_token_static = (char *)0; X return((char *)0); X } X X token = parseptr; X if(*token == '\'') X { X token++; X parseptr++; X while(*parseptr) X { X if(*parseptr == '\'') X { X arg_token_static = parseptr + 1; X *parseptr = 0; X return(token); X } X parseptr++; X } X arg_token_static = (char *)0; X return(token); X } X while(*parseptr) X { X if(strchr(termchars,*parseptr)) X { X *parseptr = 0; X arg_token_static = parseptr + 1; X while(*arg_token_static) X { X if(!strchr(termchars,*arg_token_static)) X break; X arg_token_static++; X } X return(token); X } X parseptr++; X } X arg_token_static = (char *)0; X return(token); X} /* end of arg_token */ X#endif X X/*+------------------------------------------------------------------------- X fname_split(cmd,arg,arg_max_quan,&narg) X--------------------------------------------------------------------------*/ X#if defined(M_UNIX) Xvoid Xfname_split(cmd,arg,arg_max_quan,narg_rtn) Xchar *cmd; Xchar **arg; Xint arg_max_quan; Xint *narg_rtn; X{ Xregister itmp; Xregister narg; X X for(itmp = 0; itmp < arg_max_quan; itmp++) X arg[itmp] = (char *)0; X arg[0] = arg_token(cmd,"/"); X X for(narg = 1; narg < arg_max_quan; ++narg) X { X if((arg[narg] = arg_token((char *)0,"/")) == (char *)0) X break; X } X X *narg_rtn = narg; X X} /* end of fname_split */ X#endif X X#if defined(M_UNIX) X#define MAX_COMPONENT_LEN 14 X#define MAX_PATH_COMPONENTS 16 Xstatic char trunc_fname[257]; Xstatic char *trunc_components[MAX_PATH_COMPONENTS]; Xstatic int trunc_components_quan; Xstatic int trunc_absolute_path; X#endif X X/*+------------------------------------------------------------------------- X fname_too_long(fname) - check for any pathname component too long X--------------------------------------------------------------------------*/ X#if defined(M_UNIX) Xint Xfname_too_long(fname) Xregister char *fname; X{ Xregister int itmp; Xregister char **cpptr; X X if(trunc_absolute_path = (*fname == '/')) X fname++; X strncpy(trunc_fname,fname,sizeof(trunc_fname) - 1); X fname_split(trunc_fname,trunc_components, X MAX_PATH_COMPONENTS,&trunc_components_quan); X itmp = trunc_components_quan; X cpptr = trunc_components; X while(itmp--) X { X if(strlen(*cpptr) > MAX_COMPONENT_LEN) X return(1); X cpptr++; X } X return(0); X} /* end of fname_too_long */ X#endif X X/*+------------------------------------------------------------------------- X fname_truncated() - build truncated path last checked by fname_too_long X--------------------------------------------------------------------------*/ X#if defined(M_UNIX) Xchar * Xfname_truncated() X{ Xregister int icomp; Xchar new_fname[257]; Xregister char *cptr = new_fname; X X if(trunc_absolute_path) X { X *cptr = '/'; X *(cptr + 1) = 0; X } X else X *cptr = 0; X for(icomp = 0; icomp < trunc_components_quan; icomp++) X { X if(strlen(trunc_components[icomp]) > MAX_COMPONENT_LEN) X *(trunc_components[icomp] + MAX_COMPONENT_LEN) = 0; X strcat(cptr,trunc_components[icomp]); X if(icomp < trunc_components_quan - 1) X strcat(cptr,"/"); X } X strcpy(trunc_fname,cptr); X return(trunc_fname); X X} /* end of fname_truncated */ X#endif 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(NO_SELECT) 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(NO_SELECT) 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(NO_SELECT) 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_timeout_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 returns 1 if TIMEOUT at state other than ground, else 0 X--------------------------------------------------------------------------*/ Xint 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_ACKW) && rawblk); 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,(!!sf_blknum)); 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 return((sf_state != SFS_GND) && (c == TIMEOUT)); 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 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 exit_code = 253; 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 sent_EOT = 0; 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 sent_EOT = 1; X nap(500L); X tx_char_count++; X } X sf_blknum++; X } X X if(wait_for_rcvr_response() && sent_EOT) X { X report_str("Receiver did not ACK our EOT",-1); X break; X } X X if(sf_nakquan > 10) X goto CANCEL_TRANSFER; X } X X if(endblk) /* if sending file, not EOT */ X fclose(fp); X return(1); /* exit with good status */ X XCANCEL_TRANSFER: X if(endblk) /* if sending file, not EOT */ 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 { X error_count++; X report_str("bad block",1); X } 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 X#if defined(M_UNIX) X if(fname_too_long(blk0.filename)) X { X strcpy(s128,"truncated: "); X strncat(s128,blk0.filename,sizeof(s128) - 12); X report_str(s128,-1); X strcpy(outname,fname_truncated()); X } X else X#endif X strcpy(outname,blk0.filename); X report_file_rcv_started(outname,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) X { /* if we really got anything */ X fclose(fp); X unlink(outname); /* rename temp to proper name */ X for(onp = outname;cnvrt && *onp;onp++) X /* find out if there's lower- */ X if(islower(*onp)) /* case letters filename */ X cnvrt = 0; /* there are, don't convert */ X if(cnvrt) /* if there aren't, make all */ X for(onp = outname;*onp;onp++) /* into uppercase */ X *onp = tolower(*onp); X if(link(tmpname,outname) == 0) X unlink(tmpname); X if(blk0.secs_since_1980) /* set stamp, if known */ X set_utime_1980(outname,blk0.secs_since_1980); X return(outname); X } X else X { /* else no real file */ X fclose(fp); X unlink(tmpname); /* discard empty file */ X report_str("end of transfer",0); X rf_done = 1; X return(NULL); X } X XCANCEL_TRANSFER: X fclose(fp); X xmit_cancel(); X rf_done = 2; X return(NULL); X} /* end of receive_file */ X X/*+------------------------------------------------------------------------- X cancel_transaction(sig) X--------------------------------------------------------------------------*/ Xcancel_transaction(sig) Xint sig; X{ X xmit_cancel(); X sprintf(s128,"signal %d ... exiting",sig); X report_str(s128,1); X/* X report_rx_ind(0); X report_tx_ind(0); X*/ X report_uninit(); X if(sig == SIGQUIT) X abort(); X exit(128+sig); X} /* end of cancel_transaction */ X X/*+------------------------------------------------------------------------- X getspeed(code) X--------------------------------------------------------------------------*/ Xstruct B_to_baud { unsigned baud; int B_code; }; Xunsigned Xgetspeed(code) Xint code; X{ Xregister itmp; Xstatic struct B_to_baud speeds[] = X{ X 50, B50, 75, B75, 110, B110, 300, B300, 600, B600, 1200, B1200, X 2400, B2400, 4800, B4800, 9600, B9600, 19200, EXTA, 38400, EXTB, 0 X}; X X code &= CBAUD; X for(itmp = 0; speeds[itmp].baud; itmp++) X if(speeds[itmp].B_code == code) X return(speeds[itmp].baud); X return(38400); /* Assume fifo if ioctl failed */ X} /* end of getspeed */ X X/*+------------------------------------------------------------------------- X main(argc,argv,envp) X--------------------------------------------------------------------------*/ Xmain(argc,argv,envp) Xint argc; Xchar **argv; Xchar **envp; X{ Xint ipaths; Xint ok; X#define MAX_PATHS 512 Xchar *paths[MAX_PATHS]; Xchar **ppaths = paths; Xchar *cptr; Xchar **gargv = argv; Xint gargc = argc; X X exit_code = 254; X while(--argc) X { X cptr = *++argv; X if(*cptr == '-') X { X cptr++; X switch(*cptr++) X { X case ',': X log_packets = 1; X break; X case '/': X if(--argc < 1) X exit(255); X strcpy(curr_dir,*++argv); X break; X case '.': X if(--argc < 1) X exit(255); X iofd = atoi(*++argv); X break; X case 'r': X sending_flag = 0; X break; X case 's': X sending_flag = 1; X } X } X else if(argc > 0) X { X if(npaths < MAX_PATHS) X { X *ppaths++ = cptr; X npaths++; X } X else X { X printf("too many filenames to send\n"); X exit(255); X } X } X } X X if(sending_flag == -1) X { X printf("no -r or -s\n"); X exit(255); X } X X if((npaths < 1) && sending_flag) X exit(253); X X if(npaths && !sending_flag) X exit(255); X X if(log_packets) X { X char log_packets_name[64]; X FILE *ftmp; X int iargv; X sprintf(log_packets_name,"/tmp/sea%05d.plog",getpid()); X unlink(log_packets_name); X ftmp = fopen(log_packets_name,"w"); X fclose(ftmp); X log_packets = open(log_packets_name,O_WRONLY,0644); X if(log_packets < 0) X log_packets = 0; X else X { X write(log_packets,"exec: ",6); X for(iargv = 0; iargv < gargc; iargv++) X { X write(log_packets,gargv[iargv],strlen(gargv[iargv])); X write(log_packets," ",1); X } X write(log_packets,"\n",1); X } X } X X sprintf(s128,"ecusea %s",revision); X report_init(s128); X signal(SIGHUP,cancel_transaction); X signal(SIGQUIT,cancel_transaction); X signal(SIGINT,cancel_transaction); X signal(SIGTERM,cancel_transaction); X X ioctl(iofd,TCGETA,&tio0); X tio = tio0; X X tio.c_oflag = 0; X tio.c_cflag &= ~PARENB; X tio.c_cflag &= ~CSIZE; X tio.c_cflag |= CS8; X X baud_rate = getspeed(tio.c_cflag); X ioctl(iofd,TCSETA,&tio); X report_line(baud_rate,"RAW"); X X switch(sending_flag) X { X case 0: /* receive files */ X while(receive_file() != NULL) X nap(1000L); X ok = (rf_done == 1); X break; X X case 1: /* send files */ X ipaths = 0; X while(ipaths < npaths) X { X if(!(ok = send_file(paths[ipaths]))) X break; X nap(1000L); X ipaths++; X } X if(ok) /* no errors, send end marker */ X send_file(""); X report_str("end of transfer",0); X break; X } X X ioctl(iofd,TCSETA,&tio0); X report_line(baud_rate,"NORMAL"); X report_uninit(); X exit(ok ? 0 : exit_code); /* and return error status */ X X} /* end of main */ X SHAR_EOF $TOUCH -am 0814204290 'sea/ecusea.c' && chmod 0644 sea/ecusea.c || echo 'restore of sea/ecusea.c failed' Wc_c="`wc -c < 'sea/ecusea.c'`" test 35194 -eq "$Wc_c" || echo 'sea/ecusea.c: original size 35194, current size' "$Wc_c" # ============= sea/lint_args.h ============== echo 'x - extracting sea/lint_args.h (Text)' sed 's/^X//' << 'SHAR_EOF' > 'sea/lint_args.h' && X/*+----------------------------------------------------------------------- X lint_args.h X------------------------------------------------------------------------*/ X/*+:EDITS:*/ X/*:08-14-1990-21:03-afterlint-creation */ X X#ifndef BUILDING_LINT_ARGS X#ifdef LINT_ARGS X X/* ecusea.c */ X/* void send_file_block(struct UNNAMED *fp,int blknum); */ Xchar *arg_token(char *,char *); Xchar *fname_truncated(void ); Xchar *receive_file(void ); Xchar *sf_state_text(int ); Xint cancel_transaction(int ); Xint fname_too_long(char *); Xint main(int ,char **,char **); Xint receive_block(char *); Xint send_comm_block(char *,int ); Xint send_file(char *); Xint wait_for_rcvr_response(void ); Xunsigned int getspeed(int ); Xunsigned int lgetc_timeout(int ); Xunsigned short crc_update(int ,unsigned int ); Xvoid fname_split(char *,char **,int ,int *); Xvoid lgetc_timeout_SIGALRM(void ); Xvoid set_sf_state(int ,int ); Xvoid set_utime_1980(char *,long ); Xvoid xmit_ack(int ); Xvoid xmit_cancel(void ); Xvoid xmit_nak(int ); X/* scurses.c */ Xchar *get_elapsed_time(long ); Xchar *get_tod(int ,char *); Xint clear_area(struct _win_st *,int ,int ,int ); Xint clear_area_char(struct _win_st *,int ,int ,int ,char ); Xint report_error_count(void ); Xint report_file_byte_io(long ); Xint report_file_open_length(long ); Xint report_file_rcv_started(char *,long ,long ); Xint report_protocol_crc_type(char *); Xint report_rx_tx_count(void ); Xvoid report_file_close(void ); Xvoid report_file_open_tod(void ); Xvoid report_file_send_open(char *,struct stat *); Xvoid report_init(char *); Xvoid report_last_rxhdr(char *,int ); Xvoid report_last_txhdr(char *,int ); Xvoid report_line(unsigned int ,char *); Xvoid report_rx_ind(int ); Xvoid report_rxpos(long ); Xvoid report_str(char *,int ); Xvoid report_top_line(char *); Xvoid report_transaction(char *); Xvoid report_tx_ind(int ); Xvoid report_txpos(long ); Xvoid report_uninit(void ); X X#else /* compiler doesn't know about prototyping */ X X/* ecusea.c */ X/* void send_file_block(); Xchar *arg_token(); Xchar *fname_truncated(); Xchar *receive_file(); Xchar *sf_state_text(); Xunsigned int getspeed(); Xunsigned int lgetc_timeout(); Xunsigned short crc_update(); Xvoid fname_split(); Xvoid lgetc_timeout_SIGALRM(); Xvoid set_sf_state(); Xvoid set_utime_1980(); Xvoid xmit_ack(); Xvoid xmit_cancel(); Xvoid xmit_nak(); X/* scurses.c */ Xchar *get_elapsed_time(); Xchar *get_tod(); Xvoid report_file_close(); Xvoid report_file_open_tod(); Xvoid report_file_send_open(); Xvoid report_init(); Xvoid report_last_rxhdr(); Xvoid report_last_txhdr(); Xvoid report_line(); Xvoid report_rx_ind(); Xvoid report_rxpos(); Xvoid report_str(); Xvoid report_top_line(); Xvoid report_transaction(); Xvoid report_tx_ind(); Xvoid report_txpos(); Xvoid report_uninit(); X X#endif /* LINT_ARGS */ X#endif /* BUILDING_LINT_ARGS */ X X/* end of lint_args.h */ SHAR_EOF $TOUCH -am 0919224990 'sea/lint_args.h' && chmod 0644 sea/lint_args.h || echo 'restore of sea/lint_args.h failed' Wc_c="`wc -c < 'sea/lint_args.h'`" test 2779 -eq "$Wc_c" || echo 'sea/lint_args.h: original size 2779, current size' "$Wc_c" true || echo 'restore of sea/scurses.c failed' echo End of part 23, continue with part 24 exit 0 -------------------------------------------------------------------- Warren Tucker, TuckerWare emory!n4hgf!wht or wht@n4hgf.Mt-Park.GA.US Hacker Extraordinaire d' async PADs, pods, proteins and protocols exit 0 # Just in case... -- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM Sterling Software, IMD UUCP: uunet!sparky!kent Phone: (402) 291-8300 FAX: (402) 291-4362 Please send comp.sources.misc-related mail to kent@uunet.uu.net.