📄 zmodemt.c
字号:
#ifndef lintstatic const char rcsid[] = "$Id: zmodemt.c,v 1.1.1.1 2001/03/08 00:01:48 efalk Exp $" ;#endif/* * Copyright (c) 1995 by Edward A. Falk *//********** * * * @@@@@ @ @ @@@ @@@@ @@@@@ @ @ @@@@@ * @ @@ @@ @ @ @ @ @ @@ @@ @ * @ @ @ @ @ @ @ @ @@@ @ @ @ @ * @ @ @ @ @ @ @ @ @ @ @ @ @ * @@@@@ @ @ @ @@@ @@@@ @@@@@ @ @ @ @ * * ZMODEMT - transmit side of zmodem protocol * * transmit side of zmodem protocol * * Caller sets flags defined in zmodem.h as appropriate. * (default is basic zmodem) * * functions: * * ZmodemTInit(ZModem *info) * YmodemTInit(ZModem *info) * XmodemTInit(ZModem *info) * Initiate a connection * * ZmodemTFile(char *filename, u_char flags[4], ZModem *info) * Initiate a file transfer. Flags are as specified * under "ZCBIN" in zmodem.h * * ZmodemTFinish(ZModem *info) * last file * * ZmodemTAbort(ZModem *info) * abort transfer * * all functions return 0 on success, 1 on abort * * * Edward A. Falk * * January, 1995 * * * **********/#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <sys/stat.h>#include "zmodem.h"#include "crctab.h" int SendMoreFileData( register ZModem *info ) ;extern int ZXmitData(int, int, u_char, u_char *data, ZModem *) ;extern void ZFlowControl(int onoff, ZModem *info) ;static int YXmitData() ;static int YSendFilename() ;static int YSendData() ;static int YSendFin() ;static int sendFilename() ;static u_char zeros[4] = {0,0,0,0} ; /* called by user to establish protocol */intZmodemTInit( register ZModem *info ){ int err ; int i ; info->state = TStart ; info->Protocol = ZMODEM ; info->crc32 = 0 ; info->packetCount = 0 ; info->errCount = 0 ; info->escCtrl = info->escHibit = info->atSign = info->escape = 0 ; info->InputState = Idle ; info->canCount = info->chrCount = 0 ; info->windowCount = 0 ; info->filename = NULL ; info->bufsize = 0 ; info->interrupt = 0 ; info->waitflag = 0 ; if( info->packetsize == 0 ) info->packetsize = 256 ; /* we won't be receiving much data, pick a reasonable buffer * size (largest packet will do) */ i = info->packetsize*2 ; if( i < 1024 ) i = 1024 ; info->buffer = (u_char *)malloc(i) ; ZIFlush(info) ; /* optional: send "rz\r" to remote end */ if( DoInitRZ ) { if( (err = ZXmitStr((u_char *)"rz\r", 3, info)) ) return err ; } if( (err = ZXmitHdr(ZRQINIT, ZHEX, zeros, info)) ) /* nudge receiver */ return err ; info->timeout = 60 ; zmodemlog("ZmodemTInit[%s]: sent ZRQINIT\n", sname(info)) ; return 0 ;} /* called by user to establish Ymodem protocol */intYmodemTInit( register ZModem *info ){ info->state = YTStart ; info->Protocol = YMODEM ; info->errCount = 0 ; info->InputState = Ysend ; info->canCount = info->chrCount = 0 ; info->windowCount = 0 ; info->filename = NULL ; if( info->packetsize != 1024 ) info->packetsize = 128 ; info->buffer = (u_char *)malloc(1024) ; ZIFlush(info) ; ZFlowControl(0, info) ; info->timeout = 60 ; return 0 ;} /* called by user to establish Xmodem protocol */intXmodemTInit( register ZModem *info ){ (void) YmodemTInit(info) ; info->Protocol = XMODEM ; return 0 ;} /* called by user to begin transmission of a file */intZmodemTFile( char *file, char *rfile, u_int f0, u_int f1, u_int f2, u_int f3, int filesRem, int bytesRem, ZModem *info){ if( file == NULL || (info->file = fopen(file, "r")) == NULL ) return ZmErrCantOpen ; info->fileEof = 0 ; info->filename = file ; info->rfilename = (rfile != NULL) ? rfile : "noname" ; info->filesRem = filesRem ; info->bytesRem = bytesRem ; info->fileFlags[3] = f0 ; info->fileFlags[2] = f1 ; info->fileFlags[1] = f2 ; info->fileFlags[0] = f3 ; info->offset = info->lastOffset = 0 ; info->len = info->date = info->fileType = info->mode = 0 ; if( info->filename != NULL ) { struct stat buf ; if( stat(info->filename, &buf) == 0 ) { info->len = buf.st_size ; info->date = buf.st_mtime ; info->fileType = 0 ; info->mode = (buf.st_mode&0777)|0100000 ; } } if( info->Protocol == XMODEM ) return YSendData(info) ; if( info->Protocol == YMODEM ) return YSendFilename(info) ; info->state = FileWait ; zmodemlog("ZmodemTFile[%s]: send ZFILE(%s)\n", sname(info), info->rfilename) ; return sendFilename(info) ;} /* send ZFILE header and filename & info. Wait for response * from receiver. */static intsendFilename( ZModem *info ){ int err ; int i ; u_char obuf[2048] ; u_char *ptr = obuf ; info->state = FileWait ; if( (err = ZXmitHdr(ZFILE, ZBIN, info->fileFlags, info)) ) return err ; i = strlen(info->rfilename) ; memcpy(ptr, info->rfilename, i+1) ; ptr += i+1 ; sprintf((char *)ptr, "%d %lo %o 0 %d %d 0", info->len, info->date, info->mode, info->filesRem, info->bytesRem) ; ptr += strlen((char *)ptr) ; *ptr++ = '\0' ; return ZXmitData(ZBIN, ptr-obuf, ZCRCW, obuf, info) ;} /* called by user when there are no more files to send */intZmodemTFinish( ZModem *info ){ if( info->Protocol == XMODEM ) return ZmDone ; if( info->Protocol == YMODEM ) return YSendFin(info) ; info->state = TFinish ; if( info->buffer != NULL ) { free(info->buffer) ; info->buffer = NULL ; } zmodemlog("ZmodemTFinish[%s]: send ZFIN\n", sname(info)) ; return ZXmitHdr(ZFIN, ZHEX, zeros, info) ;}extern int ZPF() ;extern int AnswerChallenge() ;extern int GotAbort() ;extern int Ignore() ;extern int RetDone() ;extern int GotCommand() ;extern int GotStderr() ;static int GotRinit() ;static int SendZSInit() ;static int SendFileCrc() ;static int GotSendAck() ;static int GotSendDoneAck() ;static int GotSendNak() ;static int GotSendWaitAck() ;static int SkipFile() ;static int GotSendPos() ;static int SendFileData() ;static int ResendEof() ;static int OverAndOut() ; /* sent ZRQINIT, waiting for response */ StateTable TStartOps[] = { {ZRINIT,GotRinit,1,1,TStart}, {ZCHALLENGE,AnswerChallenge,1,0,TStart}, {ZABORT,GotAbort,1,1,TFinish}, {ZFERR,GotAbort,1,1,TFinish}, {ZNAK,Ignore,0,0,TStart}, {ZCOMMAND,GotCommand,0,0,CommandData}, {ZSTDERR,GotStderr,0,0,StderrData}, {99,ZPF,0,0,TStart}, } ; /* sent ZSINIT, waiting for response */ StateTable TInitOps[] = { {ZACK,RetDone,1,0,TInit}, {ZNAK,SendZSInit,1,0,TInit}, {ZRINIT,GotRinit,1,1,TInit}, /* redundant, but who cares */ {ZCHALLENGE,AnswerChallenge,1,0,TInit}, {ZABORT,GotAbort,1,1,TFinish}, {ZFERR,GotAbort,1,1,TFinish}, {ZCOMMAND,GotCommand,0,0,CommandData}, {ZSTDERR,GotStderr,0,0,StderrData}, {99,ZPF,0,0,TInit}, } ; /* sent ZFILE, waiting for response */ StateTable FileWaitOps[] = { {ZRPOS,SendFileData,1,0,Sending}, {ZSKIP,SkipFile,1,0,FileWait}, {ZCRC,SendFileCrc,1,0,FileWait}, {ZNAK,sendFilename,1,0,FileWait}, {ZRINIT,sendFilename,1,1,FileWait}, /* rcvr confused, retry file */ {ZABORT,GotAbort,1,1,TFinish}, {ZFERR,GotAbort,1,1,TFinish}, {ZCHALLENGE,AnswerChallenge,1,0,FileWait}, {ZCOMMAND,GotCommand,0,0,CommandData}, {ZSTDERR,GotStderr,0,0,StderrData}, {99,ZPF,0,0,FileWait}, } ; /* sent file CRC, waiting for response */ StateTable CrcWaitOps[] = { {ZRPOS,SendFileData,1,0,Sending}, {ZSKIP,SkipFile,1,0,FileWait}, {ZNAK,SendFileCrc,1,0,CrcWait}, {ZRINIT,sendFilename,1,1,FileWait}, /* rcvr confused, retry file */ {ZABORT,GotAbort,1,1,TFinish}, {ZFERR,GotAbort,1,1,TFinish}, {ZCRC,SendFileCrc,0,0,CrcWait}, {ZCHALLENGE,AnswerChallenge,0,0,CrcWait}, {ZCOMMAND,GotCommand,0,0,CommandData}, {ZSTDERR,GotStderr,0,0,StderrData}, {99,ZPF,0,0,CrcWait}, } ; /* sending data, interruptable */ StateTable SendingOps[] = { {ZACK,GotSendAck,0,0,Sending}, {ZRPOS,GotSendPos,1,1,Sending}, {ZSKIP,SkipFile,1,1,FileWait}, {ZNAK,GotSendNak,1,1,Sending}, {ZRINIT,sendFilename,1,1,FileWait}, /* rcvr confused, retry file */ {ZABORT,GotAbort,1,1,TFinish}, {ZFERR,GotAbort,1,1,TFinish}, {99,ZPF,0,0,SendWait}, } ; /* sent data, need to send EOF */ StateTable SendDoneOps[] = { {ZACK,GotSendDoneAck,0,0,SendWait}, {ZRPOS,GotSendPos,1,1,Sending}, {ZSKIP,SkipFile,1,1,FileWait}, {ZNAK,GotSendNak,1,1,Sending}, {ZRINIT,sendFilename,1,1,FileWait}, /* rcvr confused, retry file */ {ZABORT,GotAbort,1,1,TFinish}, {ZFERR,GotAbort,1,1,TFinish}, {99,ZPF,0,0,SendWait}, } ; /* sending data, waiting for ACK */ StateTable SendWaitOps[] = { {ZACK,GotSendWaitAck,0,0,Sending}, {ZRPOS,GotSendPos,0,0,SendWait}, {ZSKIP,SkipFile,1,1,FileWait}, {ZNAK,GotSendNak,0,0,Sending}, {ZRINIT,sendFilename,1,1,FileWait}, /* rcvr confused, retry file */ {ZABORT,GotAbort,1,1,TFinish}, {ZFERR,GotAbort,1,1,TFinish}, {99,ZPF,0,0,SendWait}, } ; /* sent ZEOF, waiting for new RINIT */ StateTable SendEofOps[] = { {ZRINIT,SkipFile,1,0,TStart}, /* successful completion */ {ZACK,Ignore,0,0,SendEof}, /* probably ACK from last packet */ {ZRPOS,GotSendPos,1,1,SendWait}, {ZSKIP,SkipFile,1,1,TStart}, {ZNAK,ResendEof,1,0,SendEof}, {ZRINIT,sendFilename,1,1,FileWait}, /* rcvr confused, retry file */ {ZABORT,GotAbort,1,1,TFinish}, {ZFERR,GotAbort,1,1,TFinish}, {99,ZPF,0,0,SendEof}, } ; StateTable TFinishOps[] = { {ZFIN,OverAndOut,1,1,Done}, {ZNAK,ZmodemTFinish,1,1,TFinish}, {ZRINIT,ZmodemTFinish,1,1,TFinish}, {ZABORT,GotAbort,1,1,TFinish}, {ZFERR,GotAbort,1,1,TFinish}, {99,ZPF,0,0,TFinish}, } ;extern char *hdrnames[] ; /* Received Rinit. Usually received while in start state, * this can also be an attempt to resync after a protocol * failure */static intGotRinit( register ZModem *info ){ info->bufsize = info->hdrData[1] + info->hdrData[2]*256 ; info->zrinitflags = info->hdrData[4] + info->hdrData[3]*256 ; info->crc32 = info->zrinitflags & CANFC32 ; info->escCtrl = info->zrinitflags & ESCCTL ; info->escHibit = info->zrinitflags & ESC8 ; /* Full streaming: If receiver can overlap I/O, and if * the sender can sample the reverse channel without hanging, * and the receiver has not specified a buffer size, then we * can simply blast away with ZCRCG packets. If the receiver * detects an error, it sends an attn sequence and a new ZRPOS * header to restart the file where the error occurred. * * [note that zmodem8.doc does not define how much noise is * required to trigger a ZCRCW packet. We arbitrarily choose * 64 bytes] * * If 'windowsize' is nonzero, and the receiver can do full * duplex, ZCRCQ packets are sent instead of ZCRCG, to keep track * of the number of characters in the queue. If the queue fills * up, we pause and wait for a ZACK. * * * Full Streaming with Reverse Interrupt: If sender cannot * sample the input stream, then we define an Attn sequence * that will be used to interrupt transmission. * * * Full Streaming with Sliding Window: If sender cannot * sample input stream or respond to Attn signal, we send * several ZCRCQ packets until we're sure the receiver must * have sent back at least one ZACK. Then we stop sending and * read that ZACK. Then we send one more packet and so on. * * * Segmented Streaming: If receiver cannot overlap I/O or can't do * full duplex and has specified a maximum receive buffer size, * whenever the buffer size is reached, we send a ZCRCW packet. * * TODO: what if receiver can't overlap, but hasn't set a buffer * size? * * 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 */ ZFlowControl(1,info) ; if( (info->zrinitflags & (CANFDX|CANOVIO)) == (CANFDX|CANOVIO) && (SendSample||SendAttn) && info->bufsize == 0 ) { if( info->windowsize == 0 ) info->Streaming = Full ; else info->Streaming = StrWindow ; } else if( (info->zrinitflags & (CANFDX|CANOVIO)) == (CANFDX|CANOVIO) && info->bufsize == 0 ) { info->Streaming = SlidingWindow ; } else info->Streaming = Segmented ; zmodemlog("GotRinit[%s]\n", sname(info)) ; if( AlwaysSinit || info->zsinitflags != 0 || info->attn != NULL ) return SendZSInit(info) ; else return ZmDone ; /* caller now calls ZmodemTFile() */}static intSendZSInit( ZModem *info ){ int err ; char *at = (info->attn != NULL) ? info->attn : "" ; u_char fbuf[4] ; /* TODO: zmodem8.doc states: "If the ZSINIT header specifies * ESCCTL or ESC8, a HEX header is used, and the receiver * activates the specified ESC modes before reading the following * data subpacket." What does that mean? */ zmodemlog("SendZSInit[%s]\n", sname(info)) ; info->state = TInit ; fbuf[0] = fbuf[1] = fbuf[2] = 0 ; fbuf[3] = info->zsinitflags ; if( (err = ZXmitHdr(ZSINIT, ZBIN, fbuf, info)) || (err = ZXmitData(ZBIN, strlen(at)+1, ZCRCW, (u_char *)at, info)) ) return err ; return 0 ;}static intSendFileCrc( register ZModem *info ){ u_long crc ; crc = FileCrc(info->filename) ; zmodemlog("SendFileCrc[%s]: %lx\n", sname(info), crc) ; return ZXmitHdrHex(ZCRC, ZEnc4(crc), info) ;} /* Utility: start sending data. */static intstartFileData( register ZModem *info ){ int err ; info->offset = info->lastOffset = info->zrposOffset = ZDec4(info->hdrData+1) ; fseek(info->file, info->offset, 0) ; /* TODO: what if fseek fails? Send EOF? */ zmodemlog("startFileData[%s]: %ld\n", sname(info), info->offset) ; if( (err = ZXmitHdr(ZDATA, ZBIN, info->hdrData+1, info)) ) return err ; return SendMoreFileData(info) ;} /* send a chunk of file data in response to a ZRPOS. Whether this * is followed by a ZCRCE, ZCRCG, ZCRCQ or ZCRCW depends on all * sorts of protocol flags */static intSendFileData( register ZModem *info ){ info->waitflag = 0 ; return startFileData(info) ;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -