/*% cc -O -DLDP -DUNIX -DDIAGS % -o isz; size isz; **************************************************************************** * * isz.c By Chuck Forsberg, Omen Technology INC * Copyright 2002 Omen Technology INC All Rights Reserved * Entry: see sample main() in code below * * External functions called: * * sendline(c) sends a character to host * mputs(s) sends null terminated string to host * * purgeline() empty receive queue * int readline(tenths) read char from host, timeout in seconds/10 return received byte 0 to 0377 negative return values indicate error: return -1 on recoverable error return -2 on timeout trap fatal errors (loss of carrier, etc.), close file * checkline() return non 0 if readline has 1 or more bytes ready * * zfilbuf() fill buffer with blklen bytes, set Eofseen if EOT, return count * zseek(whence) clear EOF, errors, seek * zclose(status) close the input dataset associated with zfilbuf() et al. * N.B: zclose might be called after the file is closed. * * When trapping on errors, close file, call canit() unless line dropped * **************************************************************************** */ #include #include #include #include #include #include #include #include "izm.h" #include "io_zmod.h" extern int errno; // COLETTI Globals used in ISZ char *secbuf; char *filebuf; /* BIGBUF for file */ int Eofahead; /* will we be running out of gas soon? */ unsigned long Txleft; /* number of characters left in FILE buf */ unsigned long filesize; unsigned long filebufsize; jmp_buf tohere; /* For Carrier Drop Out and CTS Timeout in readline() and checkline() and sendline() */ // /* Globals used in ISZ */ FILE *in; int Zmodem=0; /* ZMODEM protocol requested by receiver */ unsigned Txwindow=0; /* Control the size of the transmitted window */ unsigned Txwspac; /* Spacing between zcrcq requests */ unsigned Txwcnt; /* Counter used to space ack requests */ long vpos = 0; /* Number of bytes read from file */ long Lrxpos; /* Receiver's last reported offset */ int Lastrx; char Lzconv; /* Local ZMODEM file conversion request */ int blklen=1024; /* length of transmitted records */ int Eofseen; /* EOF seen on input set by zfilbuf */ unsigned Rxbuflen = 16384; /* Receiver's max buffer length */ int Tframlen = 0; /* Override for tx frame length */ int Rxflags = 0; long Lastsync; /* Last offset to which we got a ZRPOS */ int Beenhereb4; /* How many times we've been ZRPOS'd same place */ /* Globals used in ISZ and IZM functions */ char Rxhdr[4]; /* Received header */ char Txhdr[8]; /* Transmitted header */ int Zctlesc; /* Encode control characters */ int Zrwindow = 1400; /* RX window size (controls garbage count) */ int Rxtimeout = 600; int Txfcs32; /* TURE means send binary frames with 32 bit FCS */ long bytcnt; long Rxpos; /* Received file position */ long Txpos; /* Transmitted file position */ int SZ(char *fname, char *fsize) { int err_code = 0; if( UsbActive() == TRUE ) printfUSB("\nWelcome to ZMODEM\n"); if( ModemCDActive() != TRUE ){ if( UsbActive() == TRUE ) printfUSB("\nZMODEM CD Inactive on Entry!\n"); return(-10); } filebufsize = 16384U; //set file buf size a multiple of ZMODEM sub-packet if( filebufsize % blklen ){ return(-20); } if( (err_code = setjmp(tohere)) != OK ){ if( in != NULL ) //how rude, hanging up like that! fclose(in); if( filebuf != NULL ) free(filebuf); if( UsbActive() == TRUE ) printfUSB("\nEnding ZMODEM Transfer via SetJmp ret=%d\n", err_code); return( err_code ); } if( UsbActive() == TRUE ) printfUSB("\nStarting ZMODEM Transfer of file %s with %s bytes\n", fname, fsize); Lzconv = ZCRESUM; /* Ask receiver for crash recovery */ startz(); /* Initialize receiver */ err_code = wcs(fname, fsize); if( in != NULL ) fclose(in); if( filebuf != NULL ) free(filebuf); if( UsbActive() == TRUE ) printfUSB("\nEnding ZMODEM Transfer ret=%d\n", err_code); if( err_code == OK ) /* Orderly conclusion of ZMODEM session */ saybibi(); /* forces the remote ZMODEM session to exit */ return( err_code ); } startz() { #ifdef BOTH Rxtimeout = 600; #endif Zmodem = 0; // mputs("rz\r"); stohdr(0L); zshhdr(ZRQINIT, Txhdr); } wcs(char *name, char *size) { //COLETTI ADDED CODE STARTS HERE in = NULL; filebuf = NULL; filesize = strtoul(size, NULL, 10); if( filesize <= 0 ) return(-30); filebuf = malloc(filebufsize); if( filebuf == NULL ) return(-40); in = fopen(name, "rb"); if( in == NULL ){ fclose(in); free(filebuf); filebuf = NULL; return(-50); } if( setvbuf(in, filebuf, _IOFBF, filebufsize) != OK ) { fclose(in); free(filebuf); in = NULL; filebuf = NULL; return(-60); } //set Eofahead, pre-zfilbuf, don't need to but be safe for later... if( filesize < filebufsize ) Eofahead = 1; else Eofahead = 0; //set Txleft HERE! Txleft = 0; //keep it simple and use filebuf itself to send out filename secbuf = filebuf; //COLETTI ADDED CODE FINISH HERE Eofseen = 0; vpos = 0; switch (wctxpn(name, size)) { case ZSKIP: case ZFERR: return OK; case OK: break; default: return ERROR; } return 0; } /* * generate and transmit pathname block consisting of * pathname (null terminated), */ wctxpn(char *name, char *size) { long n, s; int length; if (!Zmodem) if (getnak()) return ERROR; Zmodem = 1; sprintf(secbuf,"%s%c%s%c", name, 0, size, 0); n=strlen(name); s=strlen(size); length = n + s + 2; return zsendfile(secbuf, length); } int zseek(n) long n; { //COLETTI ADDED CODE START HERE Txleft = 0; //COLETTI ADDED CODE FINISH HERE clearerr(in); /* Clear EOF */ return (fseek(in, n, 0)); } /* Fill buffer with blklen chars */ size_t zfilbuf() { register size_t length; length = fast_fread(NULL, sizeof(char), blklen, in); //length = fread(secbuf, sizeof(char), blklen, in); if(length < filebufsize) Eofahead = 1; else Eofahead = 0; return length; } zclose(status) { if (in != NULL) fclose(in); if(filebuf != NULL) free(filebuf); in = NULL; filebuf = NULL; } getnak() { register firstch; Lastrx = 0; for (;;) { switch (firstch = readline(800)) { case ZPAD: if (getzrxinit()) return ERROR; return FALSE; case TIMEOUT: return TRUE; case CAN: if ((firstch = readline(20)) == CAN && Lastrx == CAN) return TRUE; default: break; } Lastrx = firstch; } } /* * Get the receiver's init parameters */ getzrxinit() { register n; for (n=10; --n>=0; ) { switch (zgethdr()) { case ZCHALLENGE: /* Echo receiver's challenge numbr */ stohdr(Rxpos); zshhdr(ZACK, Txhdr); continue; case ZRINIT: Rxflags = 0377 & Rxhdr[ZF0]; #ifndef XEDCRC32 Txfcs32 = Rxflags & CANFC32; #endif Zctlesc |= Rxflags & TESCCTL; Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8); if ( !(Rxflags & CANFDX)) Txwindow = 0; /* Override to force shorter frame length */ if (Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32)) Rxbuflen = Tframlen; if ( !Rxbuflen && (Tframlen>=32) && (Tframlen<=1024)) Rxbuflen = Tframlen; /* Set initial subpacket length */ if (Rxbuflen && blklen>Rxbuflen) blklen = Rxbuflen; return OK; case ZCAN: case TIMEOUT: return ERROR; default: zshhdr(ZNAK, Txhdr); continue; } } return ERROR; } /* Send file name and related info */ zsendfile(buf, blen) char *buf; { register c; for (;;) { stohdr(0L); Txhdr[ZF0] = Lzconv; /* file conversion request */ zsbhdr(ZFILE, Txhdr); zsda32(buf, blen, ZCRCW); again: c = zgethdr(); switch (c) { case ZRINIT: while ((c = readline(50)) > 0) if (c == ZPAD) { goto again; } continue; default: case ZCAN: case TIMEOUT: case ZABORT: case ZFIN: return ERROR; case ZSKIP: zclose(ERROR); return c; case ZRPOS: /* * Suppress zcrcw request otherwise triggered by * lastyunc==bytcnt */ if (Rxpos && zseek(Rxpos)) return ERROR; Lastsync = (bytcnt = Txpos = Rxpos) -1; return zsendfdata(); } } } /* Send the data in the file */ zsendfdata() { register c, e, n; register newcnt; int junkcount; /* Counts garbage chars received by TX */ Lrxpos = 0; junkcount = 0; Beenhereb4 = FALSE; goto somemore; waitack: junkcount = 0; c = getinsync(0); gotack: switch (c) { default: case ZCAN: zclose(ERROR); return ERROR; case ZSKIP: zclose(ERROR); return c; case ZACK: case ZRPOS: break; case ZRINIT: zclose(ERROR); return OK; } while (checkline()) { switch (readline(1)) { case XOFF: /* Wait a while for an XON */ case XOFF|0200: readline(100); continue; case CAN: case ZPAD: c = getinsync(1); goto gotack; } } somemore: newcnt = Rxbuflen; Txwcnt = 0; e = ZCRCE; do { if (e == ZCRCE) { stohdr(Txpos); zsbhdr(ZDATA, Txhdr); } //COLETTI ADDED CODE STARTS HERE if( Txleft == 0 ){ Txleft = zfilbuf(); if( Eofahead == 0 ) n = blklen; } if( Eofahead == 1 ){ if( Txleft < blklen ){ n = Txleft; Eofseen = 1; } else n = blklen; } secbuf = (char *)in->_bp; //COLETTI ADDED CODE FINISH HERE if (Eofseen) e = ZCRCE; else if (junkcount > 3) e = ZCRCW; else if (bytcnt == Lastsync) e = ZCRCW; else if (Rxbuflen && (newcnt -= n) <= 0) e = ZCRCW; else if (Txwindow && (Txwcnt += n) >= Txwspac) { Txwcnt = 0; e = ZCRCQ; } else e = ZCRCG; zsda32(secbuf, n, e); bytcnt = Txpos += n; if (e == ZCRCW) goto waitack; while (checkline()) { switch (readline(1)) { case CAN: case ZPAD: c = getinsync(1); if (c == ZACK) break; /* zcrce - dinna wanna starta ping-pong game */ zsda32(secbuf, 0, ZCRCE); goto gotack; case XOFF: /* Wait a while for an XON */ case XOFF|0200: readline(100); default: ++junkcount; } } if (Txwindow) { while ((Txpos - Lrxpos) >= Txwindow) { if (e != ZCRCQ) zsda32(secbuf, 0, e = ZCRCQ); c = getinsync(1); if (c != ZACK) { zsda32(secbuf, 0, ZCRCE); goto gotack; } } } //COLETTI ADDED CODE STARTS HERE in->_bp += n; Txleft -= n; //COLETTI ADDED CODE FINISH HERE } while (!Eofseen); stohdr(Txpos); zshhdr(ZEOF, Txhdr); for (;;) { switch (getinsync(0)) { case ZACK: continue; case ZRPOS: goto somemore; case ZRINIT: zclose(OK); return OK; case ZSKIP: zclose(ERROR); return c; default: zclose(ERROR); return ERROR; } } } /* * Respond to receiver's complaint, get back in sync with receiver */ getinsync(flag) { register c; for (;;) { c = zgethdr(); switch (c) { case ZCAN: case ZABORT: case ZFIN: case TIMEOUT: return ERROR; case ZRPOS: /* ************************************* */ /* If sending to a buffered modem, you */ /* might send a break at this point to */ /* dump the modem's buffer. */ if (zseek(Rxpos)) return ERROR; Eofseen = 0; bytcnt = Lrxpos = Txpos = Rxpos; if (Lastsync == Rxpos) { if (++Beenhereb4 > 4) if (blklen > 32) blklen /= 2; } Lastsync = Rxpos; return c; case ZACK: Lrxpos = Rxpos; if (flag || Txpos == Rxpos) return ZACK; continue; case ZRINIT: return c; case ZSKIP: return c; case ERROR: default: zshhdr(ZNAK, Txhdr); continue; } } } /* Say "bibi" to the receiver, try to do it cleanly */ void saybibi() { for (;;) { stohdr(0L); /* CAF Was zsbhdr - minor change */ zshhdr(ZFIN, Txhdr); /* to make debugging easier */ switch (zgethdr()) { case ZFIN: sendline('O'); sendline('O'); /*FALLTHRU*/ case ZCAN: case TIMEOUT: return; } } } /* End of isz.c */