📄 zmodemt.c
字号:
/* here if an ACK arrived while transmitting data. Update * last known receiver offset, and try to send some more * data. */static intGotSendAck( register ZModem *info ){ u_long offset ; offset = ZDec4(info->hdrData+1) ; if( offset > info->lastOffset ) info->lastOffset = offset ; zmodemlog("GotSendAck[%s]: %ld\n", sname(info), info->offset) ; return 0 ; /* DONT send more data, that will happen * later anyway */} /* here if an ACK arrived after last file packet sent. Send * the EOF. */static intGotSendDoneAck( register ZModem *info ){ u_long offset ; offset = ZDec4(info->hdrData+1) ; if( offset > info->lastOffset ) info->lastOffset = offset ; zmodemlog("GotSendDoneAck[%s]: %ld\n", sname(info), info->offset) ; info->state = SendEof ; info->timeout = 60 ; return ZXmitHdrHex(ZEOF, ZEnc4(info->offset), info) ;} /* off to a bad start; ZDATA header was corrupt. Start * from beginning */static intGotSendNak( register ZModem *info ){ info->offset = info->zrposOffset ; fseek(info->file, info->offset, 0) ; /* TODO: what if fseek fails? Send EOF? */ zmodemlog("GotSendNak[%s]: %ld\n", sname(info), info->offset) ; return SendMoreFileData(info) ;} /* got a ZSKIP, receiver doesn't want this file. */static intSkipFile( register ZModem *info ){ zmodemlog("SkipFile[%s]\n", sname(info)) ; fclose(info->file) ; return ZmDone ;} /* got a ZRPOS packet in the middle of sending a file, * set new offset and try again */static intGotSendPos( register ZModem *info ){ ZStatus(DataErr, ++info->errCount, NULL) ; info->waitflag = 1 ; /* next pkt should wait, to resync */ zmodemlog("GotSendPos[%s]\n", sname(info), info->offset) ; return startFileData(info) ;} /* here if an ACK arrived while waiting while transmitting data. * Update last known receiver offset, and try to send some more * data. */static intGotSendWaitAck( register ZModem *info ){ u_long offset ; int err ; offset = ZDec4(info->hdrData+1) ; if( offset > info->lastOffset ) info->lastOffset = offset ; zmodemlog("GotSendWaitAck[%s]\n", sname(info), offset) ; if( (err = ZXmitHdr(ZDATA, ZBIN, ZEnc4(info->offset), info)) ) return err ; return SendMoreFileData(info) ;} /* utility: send a chunk of file data. Whether this is followed * by a ZCRCE, ZCRCG, ZCRCQ or ZCRCW depends on all * sorts of protocol flags, plus 'waitflag'. Exact amount of file * data transmitted is variable, as escape sequences may pad out * the buffer. */intSendMoreFileData( register ZModem *info ){ int type ; int qfull = 0 ; int err ; int len ; /* max # chars to send this packet */ long pending ; /* # of characters sent but not acknowledged */ /* ZCRCE: CRC next, frame ends, header follows * ZCRCG: CRC next, frame continues nonstop * ZCRCQ: CRC next, send ZACK, frame continues nonstop * ZCRCW: CRC next, send ZACK, frame ends, header follows */ if( info->interrupt ) { /* Bugger, receiver sent an interrupt. Enter a wait state * and see what they want. Next header *should* be ZRPOS. */ info->state = SendWait ; info->timeout = 60 ; return 0 ; } /* Find out how many bytes we can transfer in the next packet */ len = info->packetsize ; pending = info->offset - info->lastOffset ; if( info->windowsize != 0 && info->windowsize - pending <= len ){ len = info->windowsize - pending ; qfull = 1 ; } if( info->bufsize != 0 && info->bufsize - pending <= len ) { len = info->bufsize - pending ; qfull = 1 ; } if( len == 0 ) { /* window still full, keep waiting */ info->state = SendWait ; info->timeout = 60 ; return 0 ; } /* OK, we can safely transmit 'len' bytes of data. Start reading * file until buffer is full. */ len -= 10 ; /* Pre-deduct 10 bytes for trailing CRC */ /* find out what kind of packet to send */ if( info->waitflag ) { type = ZCRCW ; info->waitflag = 0 ; }#ifdef COMMENT else if( info->fileEof ) type = ZCRCE ;#endif /* COMMENT */ else if( qfull ) type = ZCRCW ; else switch( info->Streaming ) { case Full: case Segmented: type = ZCRCG ; break ; case StrWindow: if( (info->windowCount += len) < info->windowsize/4 ) type = ZCRCG ; else { type = ZCRCQ ; info->windowCount = 0 ; } break ; default: case SlidingWindow: type = ZCRCQ ; break ; } { int crc32 = info->crc32 ; register int c=0, c2, atSign=0 ; register u_long crc ; register u_char *ptr = info->buffer ; crc = crc32 ? 0xffffffff : 0 ; /* read characters from file and put into buffer until buffer is * full or file is exhausted */ while( len > 0 && (c = getc(info->file)) != EOF ) { if( !crc32 ) crc = updcrc(c, crc) ; else crc = UPDC32(c, crc) ; /* zmodem protocol requires that CAN(ZDLE), DLE, XON, XOFF and * a CR following '@' be escaped. In addition, I escape '^]' * to protect telnet, "<CR>~." to protect rlogin, and ESC for good * measure. */ c2 = c & 0177 ; if( c == ZDLE || c2 == 020 || c2 == 021 || c2 == 023 || c2 == 0177 || c2 == '\r' || c2 == '\n' || c2 == 033 || c2 == 035 || (c2 < 040 && info->escCtrl) ) { *ptr++ = ZDLE ; if( c == 0177 ) *ptr = ZRUB0 ; else if( c == 0377 ) *ptr = ZRUB1 ; else *ptr = c^0100 ; len -= 2 ; } else { *ptr = c ; --len ; } ++ptr ; atSign = c2 == '@' ; ++info->offset ; } /* if we've reached file end, a ZEOF header will follow. If * there's room in the outgoing buffer for it, end the packet * with ZCRCE and append the ZEOF header. If there isn't room, * we'll have to do a ZCRCW */ if( (info->fileEof = (c == EOF)) ) { if( qfull || (info->bufsize != 0 && len < 24) ) type = ZCRCW ; else type = ZCRCE ; } *ptr++ = ZDLE ; if( !crc32 ) crc = updcrc(type, crc) ; else crc = UPDC32(type, crc) ; *ptr++ = type ; if( !crc32 ) { crc = updcrc(0,crc) ; crc = updcrc(0,crc) ; ptr = putZdle(ptr, (crc>>8)&0xff, info) ; ptr = putZdle(ptr, crc&0xff, info) ; } else { crc = ~crc ; for(len=4; --len >= 0; crc >>= 8) ptr = putZdle(ptr, crc&0xff, info) ; } len = ptr - info->buffer ; } ZStatus(SndByteCount, info->offset, NULL) ; if( (err = ZXmitStr(info->buffer, len, info)) ) return err ;#ifdef COMMENT if( (err = ZXmitData(ZBIN, info->buffer, len, type, info)) ) return err ;#endif /* COMMENT */ /* finally, do we want to wait after this packet? */ switch( type ) { case ZCRCE: info->state = SendEof ; info->timeout = 60 ; return ZXmitHdrHex(ZEOF, ZEnc4(info->offset), info) ; case ZCRCW: info->state = info->fileEof ? SendDone : SendWait ; info->timeout = 60 ; break ; default: info->state = Sending ; info->timeout = 0 ; break ; }#ifdef COMMENT if( info->fileEof ) { /* Yes, file is done, send EOF and wait */ info->state = SendEof ; info->timeout = 60 ; return ZXmitHdrHex(ZEOF, ZEnc4(info->offset), info) ; } else if( type == ZCRCW ) { info->state = SendWait ; info->timeout = 60 ; } else { info->state = Sending ; info->timeout = 0 ; }#endif /* COMMENT */ return 0 ;}static intResendEof( register ZModem *info ){ return ZXmitHdrHex(ZEOF, ZEnc4(info->offset), info) ;}static intOverAndOut( ZModem *info ){ ZXmitStr((u_char *)"OO", 2, info) ; return ZmDone ;} /* YMODEM */static u_char eotstr[1] = {EOT} ; /* ymodem parser */intYsendChar( char c, register ZModem *info ){ int err ; if( info->canCount >= 2 ) { ZStatus(RmtCancel, 0, NULL) ; return ZmErrCancel ; } switch( info->state ) { case YTStart: /* wait for 'G', 'C' or NAK */ switch( c ) { case 'G': /* streaming YModem */ case 'C': /* CRC YModem */ case NAK: /* checksum YModem */ info->PacketType = c ; return ZmDone ; default: return 0 ; } case YTFile: /* sent filename, waiting for ACK or NAK */ switch( c ) { case NAK: /* resend */ case 'C': case 'G': ZStatus(DataErr, ++info->errCount, NULL) ; return YSendFilename(info) ; case ACK: info->state = YTDataWait ; default: return 0 ; } case YTDataWait: /* sent filename, waiting for G,C or NAK */ switch( c ) { case NAK: case 'C': case 'G': info->chrCount = 0 ; if( info->PacketType == 'G' ) /* send it all at once */ { while( info->state == YTData ) if( (err = YSendData(info)) ) return err ; return 0 ; } else return YSendData(info) ; default: return 0 ; } case YTData: /* sent data, waiting for ACK or NAK */ switch( c ) { case 'C': case 'G': /* protocol failure, resend filename */ if( info->Protocol == YMODEM ) { ZStatus(DataErr, ++info->errCount, NULL) ; info->state = YTFile ; rewind(info->file) ; return YSendFilename(info) ; } /* else XModem, treat it like a NAK */ case NAK: ZStatus(DataErr, ++info->errCount, NULL) ; return YXmitData(info->buffer + info->bufp, info->ylen, info) ; case ACK: info->offset += info->ylen ; info->bufp += info->ylen ; info->chrCount -= info->ylen ; ZStatus(SndByteCount, info->offset, NULL) ; return YSendData(info) ; default: return 0 ; } case YTEOF: /* sent EOF, waiting for ACK or NAK */ switch( c ) { case NAK: return ZXmitStr(eotstr, 1, info) ; case ACK: info->state = info->Protocol == YMODEM ? YTStart : Done ; return ZmDone ; default: return 0 ; } case YTFin: /* sent Fin, waiting for ACK or NAK */ switch( c ) { case NAK: return YSendFin(info) ; case ACK: return ZmDone ; default: return 0 ; } default: return 0 ; }}static intYXmitData( u_char *buffer, int len, ZModem *info ){ u_char hdr[3] ; u_char trail[2] ; u_long crc = 0 ; int i, err ; hdr[0] = len == 1024 ? STX : SOH ; hdr[1] = info->packetCount ; hdr[2] = ~hdr[1] ; if( (err = ZXmitStr(hdr, 3, info)) || (err = ZXmitStr(buffer, len, info)) ) return err ; if( info->PacketType == NAK ) { /* checksum */ for(i=0; i<len; ++i) crc += buffer[i] ; trail[0] = crc % 256 ; return ZXmitStr(trail,1, info) ; } else { for(i=0; i<len; ++i) crc = updcrc(buffer[i], crc) ; crc = updcrc(0,crc) ; crc = updcrc(0,crc) ; trail[0] = crc / 256 ; trail[1] = crc % 256 ; return ZXmitStr(trail,2, info) ; }}static intYSendFilename( ZModem *info ){ int i,len ; u_char obuf[1024] ; u_char *ptr = obuf ; info->state = info->PacketType != 'G' ? YTFile : YTDataWait ; info->packetCount = 0 ; info->offset = 0 ; i = strlen(info->rfilename) ; memcpy(ptr, info->rfilename, i+1) ; ptr += i+1 ; sprintf((char *)ptr, "%d %lo %o 0", info->len, info->date, info->mode); ptr += strlen((char *)ptr) ; *ptr++ = '\0' ; /* pad out to 128 bytes or 1024 bytes */ i = ptr-obuf ; len = i>128 ? 1024 : 128 ; for(; i<len; ++i) *ptr++ = '\0' ; return YXmitData(obuf, len, info) ;} /* send next buffer of data */static intYSendData( ZModem *info ){ int i ; /* are there characters still in the read buffer? */ if( info->chrCount <= 0 ) { info->bufp = 0 ; info->chrCount = fread(info->buffer, 1, info->packetsize, info->file); info->fileEof = feof(info->file) ; } if( info->chrCount <= 0 ) { fclose(info->file) ; info->state = YTEOF ; return ZXmitStr(eotstr, 1, info) ; } /* pad out to 128 bytes if needed */ if( info->chrCount < 128 ) { i = 128 - info->chrCount ; memset(info->buffer + info->bufp + info->chrCount, 0x1a, i) ; info->chrCount = 128 ; } info->ylen = info->chrCount >= 1024 ? 1024 : 128 ; ++info->packetCount ; info->state = YTData ; return YXmitData(info->buffer + info->bufp, info->ylen, info) ;}static intYSendFin( ZModem *info ){ u_char obuf[128] ; info->state = YTFin ; info->packetCount = 0 ; memset(obuf,0,128) ; return YXmitData(obuf, 128, info) ;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -