/* * Receive a file with ZMODEM protocol * Assumes file name frame is in secbuf */ static int rzfile(void) { int c, n; long last_rxbytes = 0; long not_printed = 0; last_bps = 0; Eofseen = FALSE; n = 20; rxbytes = 0l; if (procheader(secbuf) == ERROR) { return (tryzhdrtype = ZSKIP); } for (;;) { stohdr(rxbytes); zshhdr(ZRPOS, Txhdr); nxthdr: switch (c = zgethdr(Rxhdr, 0)) { default: vfile("lrzfile: zgethdr returned %d", c); return ERROR; case ZNAK: case TIMEOUT: if (--n < 0) { vfile("lrzfile: zgethdr returned %d", c); return ERROR; } case ZFILE: zrdata(secbuf, MAX_BLOCK); continue; case ZEOF: if (rclhdr(Rxhdr) != rxbytes) { /* * Ignore eof if it's at wrong place - force * a timeout because the eof might have gone * out before we sent our zrpos. */ errors = 0; goto nxthdr; } if (Verbose > 1) { int minleft = 0; int secleft = 0; last_bps = (rxbytes / timing(0)); if (last_bps > 0) { minleft = (Bytesleft - rxbytes) / last_bps / 60; secleft = ((Bytesleft - rxbytes) / last_bps) % 60; } fprintf(stderr, "\rBytes Received: %7ld/%7ld BPS:%-6d \r\n", rxbytes, Bytesleft, last_bps); } closeok = 1; if (closeit()) { tryzhdrtype = ZFERR; vfile("lrzfile: closeit returned <> 0"); return ERROR; } vfile("lrzfile: normal EOF"); return c; case ERROR: /* Too much garbage in header search error */ if (--n < 0) { vfile("lrzfile: zgethdr returned %d", c); return ERROR; } zmputs(Attn); continue; case ZSKIP: closeit(); vfile("lrzfile: Sender SKIPPED file"); return c; case ZDATA: if (rclhdr(Rxhdr) != rxbytes) { if (--n < 0) { return ERROR; } zmputs(Attn); continue; } moredata: if (Verbose > 1 && (not_printed > 7 || rxbytes > last_bps / 2 + last_rxbytes)) { int minleft = 0; int secleft = 0; last_bps = (rxbytes / timing(0)); if (last_bps > 0) { minleft = (Bytesleft - rxbytes) / last_bps / 60; secleft = ((Bytesleft - rxbytes) / last_bps) % 60; } fprintf(stderr, "\rBytes Received: %7ld/%7ld BPS:%-6d ETA %02d:%02d ", rxbytes, Bytesleft, last_bps, minleft, secleft); last_rxbytes = rxbytes; not_printed = 0; if (nodeinf != -1 && ((time(0) - lup) > 5)) { lseek(nodeinf, 0, SEEK_SET); nin.ddn_bpsrate = last_bps; sprintf(nin.ddn_activity, "UL: %-34.34s", myname); write(nodeinf, &nin, sizeof(struct DayDream_NodeInfo)); lup = time(0); } } else if (Verbose) not_printed++; switch (c = zrdata(secbuf, MAX_BLOCK)) { case ZCAN: vfile("lrzfile: zgethdr returned %d", c); return ERROR; case ERROR: /* CRC error */ if (--n < 0) { vfile ("lrzfile: zgethdr returned %d", c); return ERROR; } zmputs(Attn); continue; case TIMEOUT: if (--n < 0) { vfile ("lrzfile: zgethdr returned %d", c); return ERROR; } continue; case GOTCRCW: n = 20; putsec(secbuf, Rxcount); rxbytes += Rxcount; stohdr(rxbytes); zshhdr(ZACK, Txhdr); xsendline(XON); goto nxthdr; case GOTCRCQ: n = 20; putsec(secbuf, Rxcount); rxbytes += Rxcount; stohdr(rxbytes); zshhdr(ZACK, Txhdr); goto moredata; case GOTCRCG: n = 20; putsec(secbuf, Rxcount); rxbytes += Rxcount; goto moredata; case GOTCRCE: n = 20; putsec(secbuf, Rxcount); rxbytes += Rxcount; goto nxthdr; } } } }
/* * Initialize for Zmodem receive attempt, try to activate Zmodem sender * Handles ZSINIT frame * Return ZFILE if Zmodem filename received, -1 on error, * ZCOMPL if transaction finished, else 0 */ static int tryz(void) { int c, n; int cmdzack1flg; for (n = Zmodem ? 15 : 5; --n >= 0;) { /* Set buffer length (0) and capability flags */ stohdr(0L); Txhdr[ZF0] = CANFC32 | CANFDX | CANOVIO | CANBRK; if (Zctlesc) Txhdr[ZF0] |= TESCCTL; /* TESCCTL == ESCCTL */ zshhdr(tryzhdrtype, Txhdr); if (tryzhdrtype == ZSKIP) /* Don't skip too far */ tryzhdrtype = ZRINIT; /* CAF 8-21-87 */ again: switch (zgethdr(Rxhdr, 0)) { case ZRQINIT: continue; case ZEOF: continue; case TIMEOUT: continue; case ZFILE: zconv = Rxhdr[ZF0]; zmanag = Rxhdr[ZF1]; ztrans = Rxhdr[ZF2]; tryzhdrtype = ZRINIT; c = zrdata(secbuf, MAX_BLOCK); mode(3); if (c == GOTCRCW) return ZFILE; zshhdr(ZNAK, Txhdr); goto again; case ZSINIT: Zctlesc = TESCCTL & Rxhdr[ZF0]; if (zrdata(Attn, ZATTNLEN) == GOTCRCW) { stohdr(1L); zshhdr(ZACK, Txhdr); goto again; } zshhdr(ZNAK, Txhdr); goto again; case ZFREECNT: stohdr(getfree()); zshhdr(ZACK, Txhdr); goto again; case ZCOMMAND: cmdzack1flg = Rxhdr[ZF0]; if (zrdata(secbuf, MAX_BLOCK) == GOTCRCW) { if (Verbose) { fprintf(stderr, "lrz: remote requested command\n"); fprintf(stderr, "lrz: %s\n", secbuf); } if (Verbose) fprintf(stderr, "lrz: not executed\n"); zshhdr(ZCOMPL, Txhdr); return ZCOMPL; } goto again; case ZCOMPL: goto again; default: continue; case ZFIN: ackbibi(); return ZCOMPL; case ZCAN: return ERROR; } } return 0; }
/* * Initialize for Zmodem receive attempt, try to activate Zmodem sender * Handles ZSINIT frame * Return ZFILE if Zmodem filename received, -1 on error, * ZCOMPL if transaction finished, else 0: can be ymodem. */ int tryz(void) { int c, n; int cmdzack1flg; if (protocol != ZM_ZMODEM) return 0; for (n = zmodem_requested ?15:10; --n >= 0; ) { /* * Set buffer length (0) and capability flags */ Syslog('z', "tryz attempt %d", n); stohdr(0L); Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO; if (Zctlesc) Txhdr[ZF0] |= TESCCTL; zshhdr(tryzhdrtype, Txhdr); if (tryzhdrtype == ZSKIP) /* Don't skip too far */ tryzhdrtype = ZRINIT; /* CAF 8-21-87 */ again: switch (zgethdr(Rxhdr)) { case ZRQINIT: continue; case ZEOF: continue; case TIMEOUT: Syslog('z', "Zmodem: tryz() timeout attempt %d", n); continue; case ZFILE: zconv = Rxhdr[ZF0]; if (!zconv) { Syslog('z', "*** !zconv %d", zconv); zconv = ZCBIN; } zmanag = Rxhdr[ZF1]; ztrans = Rxhdr[ZF2]; tryzhdrtype = ZRINIT; c = zrdata(secbuf, MAXBLOCK); io_mode(0, 3); if (c == GOTCRCW) { Syslog('z', "tryz return ZFILE"); return ZFILE; } zshhdr(ZNAK, Txhdr); goto again; case ZSINIT: /* this once was: * Zctlesc = TESCCTL & Rxhdr[ZF0]; * trouble: if rz get --escape flag: * - it sends TESCCTL to sz, * get a ZSINIT _without_ TESCCTL (yeah - sender didn't know), * overwrites Zctlesc flag ... * - sender receives TESCCTL and uses "|=..." * so: sz escapes, but rz doesn't unescape ... not good. */ Zctlesc |= TESCCTL & Rxhdr[ZF0]; if (zrdata(Attn, ZATTNLEN) == GOTCRCW) { stohdr(1L); zshhdr(ZACK, Txhdr); goto again; } zshhdr(ZNAK, Txhdr); goto again; case ZFREECNT: stohdr(getfree()); zshhdr(ZACK, Txhdr); goto again; case ZCOMMAND: cmdzack1flg = Rxhdr[ZF0]; if (zrdata(secbuf, MAXBLOCK) == GOTCRCW) { if (cmdzack1flg & ZCACK1) stohdr(0L); else Syslog('+', "Zmodem: request for command \"%s\" ignored", printable(secbuf,-32)); stohdr(0L); do { zshhdr(ZCOMPL, Txhdr); } while (++errors<20 && zgethdr(Rxhdr) != ZFIN); return ackbibi(); } zshhdr(ZNAK, Txhdr); goto again; case ZCOMPL: goto again; case ZRINIT: Syslog('z', "tryz: got ZRINIT"); return TERROR; case ZFIN: /* do not beleive in first ZFIN */ ackbibi(); return ZCOMPL; case TERROR: case HANGUP: case ZCAN: return TERROR; default: continue; } } return 0; }
/* * Receive a file with ZMODEM protocol * Assumes file name frame is in secbuf */ int rzfile(void) { int c, n; Eofseen=FALSE; rxbytes = 0l; if ((c = procheader(secbuf))) { return (tryzhdrtype = c); } n = 20; for (;;) { stohdr(rxbytes); zshhdr(ZRPOS, Txhdr); nxthdr: switch (c = zgethdr(Rxhdr)) { default: Syslog('z', "rzfile: Wrong header %d", c); if ( --n < 0) { Syslog('+', "Zmodem: wrong header %d", c); return TERROR; } continue; case ZCAN: Syslog('+', "Zmodem: sender CANcelled"); return TERROR; case ZNAK: if ( --n < 0) { Syslog('+', "Zmodem: Got ZNAK"); return TERROR; } continue; case TIMEOUT: if ( --n < 0) { Syslog('z', "Zmodem: TIMEOUT"); return TERROR; } continue; case ZFILE: zrdata(secbuf, MAXBLOCK); continue; case ZEOF: if (rclhdr(Rxhdr) != rxbytes) { /* * Ignore eof if it's at wrong place - force * a timeout because the eof might have gone * out before we sent our zrpos. */ errors = 0; goto nxthdr; } if (closeit(1)) { tryzhdrtype = ZFERR; Syslog('+', "Zmodem: error closing file"); return TERROR; } fout = NULL; Syslog('z', "rzfile: normal EOF"); return c; case HANGUP: Syslog('+', "Zmodem: Lost Carrier"); return TERROR; case TERROR: /* Too much garbage in header search error */ if (--n < 0) { Syslog('+', "Zmodem: Too many errors"); return TERROR; } zmputs(Attn); continue; case ZSKIP: Modtime = 1; closeit(1); Syslog('+', "Zmodem: Sender SKIPPED file"); return c; case ZDATA: if (rclhdr(Rxhdr) != rxbytes) { if ( --n < 0) { Syslog('+', "Zmodem: Data has bad address"); return TERROR; } zmputs(Attn); continue; } moredata: Nopper(); alarm_on(); switch (c = zrdata(secbuf, MAXBLOCK)) { case ZCAN: Syslog('+', "Zmodem: sender CANcelled"); return TERROR; case HANGUP: Syslog('+', "Zmodem: Lost Carrier"); return TERROR; case TERROR: /* CRC error */ if (--n < 0) { Syslog('+', "Zmodem: Too many errors"); return TERROR; } zmputs(Attn); continue; case TIMEOUT: if ( --n < 0) { Syslog('+', "Zmodem: TIMEOUT"); return TERROR; } continue; case GOTCRCW: n = 20; putsec(secbuf, Rxcount); rxbytes += Rxcount; stohdr(rxbytes); PUTCHAR(XON); zshhdr(ZACK, Txhdr); goto nxthdr; case GOTCRCQ: n = 20; putsec(secbuf, Rxcount); rxbytes += Rxcount; stohdr(rxbytes); zshhdr(ZACK, Txhdr); goto moredata; case GOTCRCG: n = 20; putsec(secbuf, Rxcount); rxbytes += Rxcount; goto moredata; case GOTCRCE: n = 20; putsec(secbuf, Rxcount); rxbytes += Rxcount; goto nxthdr; } } } }
/* ------------------------------------------------------------------------- */ int tx_zmodem(s_protinfo *pi, bool caller) { int startblk = 64; /* Initial Zmodem block size */ int minblk = 64; /* Minimal Z-protocol block size */ int maxblk = 1024;/* Maximal Z-protocol block size */ int blocklen = 0; /* Length of transmitted blocks */ int goodblk = 0; /* How many blocks we sent w/o ZRPOS'tion :) */ int txwindow = 0; /* Tranmitter window size (0 means streaming) */ int newcnt = 0; /* Count free bytes in receiver's buffer */ int rxbuflen = 0; /* Receiver's max buffer length */ int rxlastpos = 0; /* Receiver's last reported offset */ int beenhere = 0; /* How many times we've been ZRPOS'd same place */ long bytescnt = 0; /* Received bytes(current offset) */ long lastsync = 0; /* Last offset to which we got a ZRPOS */ char zconv = 0; /* Local ZMODEM file conversion request */ char zmanag = 0; /* Local ZMODEM file management request */ char ztrans = 0; /* Local ZMODEM file translation request */ char zexten = 0; /* Local ZMODEM file extended options */ char *txbuf = NULL;/* Buffer with ZMAXBLOCKLEN size */ int zrinitcnt = 0; /* Count received ZRINITs */ int rxflags1 = 0; int rxflags2 = 0; int txtries = 0; int junkcnt = 0; int initacked = 0; /* TRUE when at least one ZRQINIT was sent */ /* after first ZRINIT was received */ int rc = 0; /* Our return code */ int dtype, n; int ftype; char c, *p; long unsigned crc32; enum ztxstates txstate; time_t deadtimer; log("start %s send", Protocols[state.handshake->protocol]); DEB((D_PROT, "start %s send", Protocols[state.handshake->protocol])); /* Set time transfer started at */ if( pi->start_time == 0 ) pi->start_time = time(NULL); txbuf = (char *)xmalloc(ZMAXBLOCKLEN+1); zconv = ZCBIN; maxblk = (state.handshake->protocol == PROT_ZMODEM) ? 1024 : 8192; /* Set initial block size (default is 128b) */ if( (startblk = conf_number(cf_zmodem_start_block_size)) > 0 ) { if( startblk%64 || startblk > maxblk || startblk < 64 ) startblk = 256; } else startblk = 256; blocklen = startblk; txwindow = conf_number(cf_zmodem_tx_window); Z_Rxwait = ZWAITTIME; Z_Rxtout = ZRXTIMEOUT; txstate = ZTX_START; timer_set(&deadtimer, ZDEADTIMER); setalarm(Z_Rxtout); /* * At zmodem batches send empty netmail packet * if no real outgoing traffic available */ if( !pi->send_left_size && conf_boolean(cf_zmodem_send_dummy_pkt) ) zmodem_add_empty_packet(pi); while(1) { if( timer_expired(deadtimer) ) { log("brain dead! (abort)"); gotoexit(PRC_LOCALABORTED); } if( txstate == ZTX_RQINIT || txstate == ZTX_FINFO || txstate == ZTX_EOF || txstate == ZTX_FIN ) { #ifdef DEBUG if( txtries ) DEB((D_PROT, "tx_zmodem: try #%d", txtries)); #endif if( ++txtries > ZMAXTRIES ) { log("out of tries"); gotoexit(PRC_LOCALABORTED); } } switch(txstate) { case ZTX_START: DEB((D_PROT, "tx_zmodem: entering state ZTX_START")); if( PUTSTR("rz\r") < 0 ) gotoexit(PRC_ERROR); txtries = 0; txstate = ZTX_RQINIT; break; case ZTX_RQINIT: DEB((D_PROT, "tx_zmodem: entering state ZTX_RQINIT")); stohdr(Z_Txhdr, 0L); if( zshhdr(ZRQINIT, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); setalarm(Z_Rxtout); txstate = ZTX_RQINITACK; break; case ZTX_NEXTFILE: DEB((D_PROT, "tx_zmodem: entering state ZTX_NEXTFILE")); if (pi->send) p_tx_fclose(pi); txtries = 0; txstate = p_tx_fopen(pi, NULL) ? ZTX_FIN : ZTX_FINFO; log("nextfile next state: %d", txstate); break; case ZTX_FINFO: DEB((D_PROT, "tx_zmodem: entering state ZTX_FINFO")); zrinitcnt = 0; strnxcpy(txbuf, pi->send->net_name, ZMAXFNAME); p = txbuf + strlen(txbuf) + 1; sprintf(p, "%ld %lo %lo 0 %ld %ld", (long)pi->send->bytes_total, (long)pi->send->mod_time, (long)pi->send->mode, (long)pi->send_left_num, (long)pi->send_left_size); DEB((D_PROT, "tx_zmodem: send \"%s\\000%s\"", txbuf, p)); Z_Txhdr[ZF0] = zconv; /* file conversion request */ Z_Txhdr[ZF1] = zmanag; /* file management request */ Z_Txhdr[ZF2] = ztrans; /* file transport request */ Z_Txhdr[ZF3] = zexten; if( zsbhdr(ZFILE, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); if( zsdata(txbuf, (p - txbuf) + strlen(p), ZCRCW, 0) < 0 ) gotoexit(PRC_ERROR); setalarm(Z_Rxtout); txstate = ZTX_FINFOACK; break; case ZTX_STARTDATA: DEB((D_PROT, "tx_zmodem: entering state ZTX_STARTDATA")); newcnt = rxbuflen; junkcnt = 0; stohdr(Z_Txhdr, pi->send->bytes_sent); if( zsbhdr(ZDATA, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); txstate = ZTX_DATA; break; case ZTX_DATA: DEB((D_PROT, "tx_zmodem: entering state ZTX_DATA")); timer_set(&deadtimer, ZDEADTIMER); setalarm(Z_Rxtout); /* Remove annoing timeouts! */ if( (n = p_tx_readfile(txbuf, blocklen, pi)) < 0 ) { /* error occured, remote wait for DATA */ /* so send null ZCRCE data subpacket */ if( zsdata(txbuf, 0, ZCRCE, 0) < 0 ) gotoexit(PRC_ERROR); txstate = ZTX_NEXTFILE; break; } if( pi->send->eofseen ) dtype = ZCRCE; else if( junkcnt > 6 ) dtype = ZCRCW; else if( bytescnt == lastsync ) dtype = ZCRCW; else if( rxbuflen && (newcnt -= n) <= 0 ) dtype = ZCRCW; else if( txwindow && (bytescnt - rxlastpos + n) >= txwindow ) dtype = ZCRCQ; else dtype = ZCRCG; if( (rc = p_info(pi, 0)) ) gotoexit(rc); if( zsdata(txbuf, n, dtype, pi->send->bytes_sent) < 0 ) gotoexit(PRC_ERROR); if( ++goodblk > 5 && blocklen*2 <= maxblk ) { goodblk = 0; blocklen *= 2; DEB((D_PROT, "tx_zmodem: new blocklen = %ld byte(s)", blocklen)); } bytescnt = pi->send->bytes_sent += n; if( dtype == ZCRCW ) { junkcnt = 0; setalarm(Z_Rxtout); txstate = ZTX_CRCWACK; break; } else if( dtype == ZCRCQ ) { junkcnt = 0; setalarm(Z_Rxtout); txstate = ZTX_CRCQACK; break; } else if( dtype == ZCRCE ) { txtries = 0; txstate = ZTX_EOF; break; } if( CHARWAIT(0) ) { while( (rc = GETCHAR(1)) != ZTIMER ) { if( rc < 0 ) { gotoexit(PRC_ERROR); } else if( rc == CAN || rc == ZPAD ) { DEB((D_PROT, "tx_zmodem: got ZPAD or CAN!")); setalarm(Z_Rxtout); txstate = ZTX_READCHECK; break; } else if( rc == XOFF || rc == (XOFF|0200) ) { DEB((D_PROT, "tx_zmodem: got XOFF")); if( GETCHAR(5) < 0 ) gotoexit(PRC_ERROR); break; } else if( rc == XON || rc == (XON|0200) ) { DEB((D_PROT, "tx_zmodem: got XON")); } else { junkcnt++; DEB((D_PROT, "tx_zmodem: got JUNK = 0x%x (junkcnt = %d)", rc, junkcnt)); } } /* end of while( rc != ZTIMER ) */ } /* end of if( CHARWAIT(0) ) */ break; case ZTX_EOF: DEB((D_PROT, "tx_zmodem: entering state ZTX_EOF")); stohdr(Z_Txhdr, pi->send->bytes_sent); if( zsbhdr(ZEOF, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); setalarm(Z_Rxtout); txstate = ZTX_EOFACK; break; case ZTX_FIN: DEB((D_PROT, "tx_zmodem: entering state ZTX_FIN")); stohdr(Z_Txhdr, 0L); if( zshhdr(ZFIN, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); setalarm(Z_Rxtout); txstate = ZTX_FINACK; break; default: /* Ignore them all */ break; } /* end of switch(txstate) */ if( txstate != ZTX_START && txstate != ZTX_RQINIT && txstate != ZTX_FINFO && txstate != ZTX_DATA && txstate != ZTX_EOF && txstate != ZTX_FIN ) { switch( ftype = zgethdr(Z_Rxhdr) ) { case ZCAN: gotoexit(PRC_REMOTEABORTED); break; case ZHANGUP: case ZEXIT: gotoexit(PRC_ERROR); break; case ZTIMER: log("time out"); if( txstate == ZTX_READCHECK ) zsdata(txbuf, 0, ZCRCE, 0); switch(txstate) { case ZTX_RQINITACK: txstate = ZTX_RQINIT; break; case ZTX_FINFOACK: txstate = ZTX_FINFO; break; case ZTX_READCHECK: txstate = ZTX_STARTDATA; break; case ZTX_CRCWACK: txstate = ZTX_STARTDATA; break; case ZTX_CRCQACK: txstate = ZTX_STARTDATA; break; case ZTX_EOFACK: txstate = ZTX_EOF; break; case ZTX_FINACK: txstate = ZTX_FIN; break; default: break; } break; case ZERROR: case ZCRCERR: /* NAK them all! */ stohdr(Z_Txhdr, 0L); if( zshhdr(ZNAK, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); break; case ZRQINIT: if( txstate == ZTX_RQINITACK ) { if( Z_Rxhdr[0] == ZCOMMAND ) break; stohdr(Z_Txhdr, 0L); if( zshhdr(ZNAK, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); txstate = ZTX_RQINIT; } else if( txstate == ZTX_FINFOACK ) { /* remote is sender - abort */ log("zmodem: remote is sender"); gotoexit(PRC_LOCALABORTED); } break; case ZRINIT: if( txstate == ZTX_RQINITACK ) { if( initacked == 0 ) { /* Be sure ack first ZRINIT */ stohdr(Z_Txhdr, 0L); if( zshhdr(ZRQINIT, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); initacked = 1; } /* Get receiver's options */ rxflags1 = (0377 & Z_Rxhdr[ZF0]); rxflags2 = (0377 & Z_Rxhdr[ZF1]); Z_Txfcs32 = (rxflags1 & CANFC32); Z_Ctlesc |= (rxflags1 & TESCCTL); rxbuflen = (0377 & Z_Rxhdr[ZP0]); rxbuflen += ((0377 & Z_Rxhdr[ZP1])<<8); /* No ZCRCQ if remote doesn't indicate */ /* FDX ability */ if( !(rxflags1 & CANFDX) ) txwindow = 0; DEB((D_PROT, "tx_zmodem: Z_Txfcs32 = %d Z_Ctlesc = %d", Z_Txfcs32, Z_Ctlesc)); DEB((D_PROT, "tx_zmodem: rxbuflen = %d blocklen = %d", rxbuflen, blocklen)); DEB((D_PROT, "tx_zmodem: txwindow = %u", txwindow)); txstate = ZTX_NEXTFILE; } else if( txstate == ZTX_FINFOACK ) { /* Possible they didn't see */ /* our file information */ if( ++zrinitcnt > 2 ) txstate = ZTX_FINFO; } else if( txstate == ZTX_READCHECK || txstate == ZTX_CRCQACK || txstate == ZTX_CRCWACK ) { if( txstate == ZTX_READCHECK || txstate == ZTX_CRCQACK ) zsdata(txbuf, 0, ZCRCE, 0); /* Assume file normaly sent ? */ log("assume file normaly sent"); pi->send->status = FSTAT_SUCCESS; txstate = ZTX_NEXTFILE; } else if( txstate == ZTX_EOFACK ) { /* ok, send next */ pi->send->status = FSTAT_SUCCESS; txstate = ZTX_NEXTFILE; } else if( txstate == ZTX_FINACK ) { /* Possible we should ignore */ /* first ZRINIT. Because they */ /* didn't see our first ZFIN */ /* But I'm soo lazy .. :)) */ txstate = ZTX_FIN; } break; case ZACK: if( txstate == ZTX_CRCWACK ) { rxlastpos = Z_Rxpos; if( pi->send->bytes_sent == Z_Rxpos ) txstate = ZTX_STARTDATA; } else if( txstate == ZTX_READCHECK || txstate == ZTX_CRCQACK ) { rxlastpos = Z_Rxpos; txstate = ZTX_DATA; } break; case ZSKIP: if( txstate == ZTX_FINFOACK || txstate == ZTX_READCHECK || txstate == ZTX_CRCQACK || txstate == ZTX_CRCWACK || txstate == ZTX_EOFACK ) { if( txstate == ZTX_READCHECK || txstate == ZTX_CRCQACK ) zsdata(txbuf, 0, ZCRCE, 0); if( txstate == ZTX_READCHECK ) CLEAROUT(); pi->send->status = FSTAT_SKIPPED; log("remote side skipped file"); txstate = ZTX_NEXTFILE; } break; case ZFIN: /* BUG!BUG!BUG!BUG!BUG!BUG!BUG!BUG!BUG! */ /* BUG!BUG!BUG!BUG!BUG!BUG!BUG!BUG!BUG! */ log(" BUG!BUG!BUG!BUG!BUG!BUG!BUG!BUG!BUG! "); if( txstate == ZTX_FINACK ) { if( PUTSTR("OO") == 0 ) FLUSHOUT(); gotoexit(PRC_NOERROR); } break; case ZRPOS: if( txstate == ZTX_FINFOACK || txstate == ZTX_READCHECK || txstate == ZTX_CRCQACK || txstate == ZTX_CRCWACK || txstate == ZTX_EOFACK ) { rxlastpos = Z_Rxpos; /* Clear modem buffers */ /* if( txstate != FINFOACK ) SENDBREAK(); */ if( txstate == ZTX_READCHECK ) CLEAROUT(); if( txstate == ZTX_READCHECK || txstate == ZTX_CRCQACK ) { if( zsdata(txbuf, 0, ZCRCE, 0) < 0 ) gotoexit(PRC_ERROR); } /* Reset EOF flag! */ pi->send->eofseen = FALSE; /* Check pos */ if( (Z_Rxpos || txstate != ZTX_FINFOACK) && p_tx_rewind(pi, Z_Rxpos) ) { logerr("can't send file from requested position"); /* Open next file for send */ txstate = ZTX_NEXTFILE; break; } if( txstate == ZTX_FINFOACK ) { if( Z_Rxpos ) { log("resyncing at offset %d", Z_Rxpos); pi->send->bytes_skipped = Z_Rxpos; } } else if( txstate == ZTX_READCHECK || txstate == ZTX_CRCWACK || txstate == ZTX_CRCQACK ) { goodblk = 0; if( lastsync >= Z_Rxpos && ++beenhere > 4 ) if( blocklen > minblk ) { blocklen /= 2; DEB((D_PROT, "tx_zmodem: falldown to %ld BlockLen", blocklen)); } } lastsync = bytescnt = pi->send->bytes_sent = Z_Rxpos; if( txstate == ZTX_FINFOACK ) --lastsync; txstate = ZTX_STARTDATA; } break; case ZNAK: switch(txstate) { case ZTX_RQINITACK: txstate = ZTX_RQINIT; break; case ZTX_FINFOACK: txstate = ZTX_FINFO; break; case ZTX_EOFACK: txstate = ZTX_EOF; break; case ZTX_FINACK: txstate = ZTX_FIN; break; default: break; } break; case ZCRC: if( txstate == ZTX_FINFOACK ) { log(" Send file's CRC-32 "); crc32 = 0xFFFFFFFFL; while( ((c = getc(pi->send->fp)) != EOF) && --Z_Rxpos ) crc32 = updcrc32(c, crc32); crc32 = ~crc32; clearerr(pi->send->fp); /* Clear EOF */ fseek(pi->send->fp, 0L, 0); stohdr(Z_Txhdr, crc32); if( zsbhdr(ZCRC, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); } break; case ZCHALLENGE: if( txstate == ZTX_RQINITACK ) { /* Echo receiver's challenge number */ stohdr(Z_Txhdr, Z_Rxpos); if( zshhdr(ZACK, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); txstate = ZTX_RQINIT; } break; case ZCOMMAND: if( txstate == ZTX_RQINITACK ) { txstate = ZTX_RQINIT; } break; case ZABORT: log("remote requested for session abort"); stohdr(Z_Txhdr, 0L); if( zshhdr(ZFIN, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); gotoexit(PRC_REMOTEABORTED); break; case ZFERR: if( txstate == ZTX_FINFOACK || txstate == ZTX_READCHECK || txstate == ZTX_CRCWACK || txstate == ZTX_CRCQACK || txstate == ZTX_EOFACK ) { if( txstate == ZTX_READCHECK || txstate == ZTX_CRCQACK ) { if( zsdata(txbuf, 0, ZCRCE, 0) < 0 ) gotoexit(PRC_ERROR); } pi->send->status = FSTAT_REFUSED; log("remote side refused file"); txstate = ZTX_NEXTFILE; } break; default: log("got unexpected frame %d", ftype); break; } /* end of switch(hdr) */ } /* end of if */ } /* end of while */ exit: DEB((D_PROT, "tx_zmodem: SEND exit = %d", rc)); setalarm(0); if (pi->send) p_tx_fclose(pi); if( txbuf ) { free(txbuf); txbuf = NULL; } return(rc); }