📄 zmodemr.c
字号:
#ifndef lintstatic const char rcsid[] = "$Id: zmodemr.c,v 1.1.1.1 2001/03/08 00:01:48 efalk Exp $" ;#endif/* * Copyright (c) 1995 by Edward A. Falk *//********** * * * @@@@@ @ @ @@@ @@@@ @@@@@ @ @ @@@@ * @ @@ @@ @ @ @ @ @ @@ @@ @ @ * @ @ @ @ @ @ @ @ @@@ @ @ @ @@@@ * @ @ @ @ @ @ @ @ @ @ @ @ @ @ * @@@@@ @ @ @ @@@ @@@@ @@@@@ @ @ @ @ @ * * ZMODEMR - receive side of zmodem protocol * * receive side of zmodem protocol * * This code is designed to be called from inside a larger * program, so it is implemented as a state machine where * practical. * * functions: * * ZmodemRInit(ZModem *info) * Initiate a connection * * ZmodemRAbort(ZModem *info) * abort transfer * * all functions return 0 on success, 1 on failure * * * Edward A. Falk * * January, 1995 * * * **********/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <errno.h>#include "zmodem.h"#include "crctab.h"extern int errno ;extern int ZWriteFile(u_char *buffer, int len, FILE *, ZModem *);extern int ZCloseFile(ZModem *info) ;extern void ZFlowControl(int onoff, ZModem *info) ;static u_char zeros[4] = {0,0,0,0} ;intZmodemRInit(ZModem *info){ info->packetCount = 0 ; info->offset = 0 ; info->errCount = 0 ; info->escCtrl = info->escHibit = info->atSign = info->escape = 0 ; info->InputState = Idle ; info->canCount = info->chrCount = 0 ; info->filename = NULL ; info->interrupt = 0 ; info->waitflag = 0 ; info->attn = NULL ; info->file = NULL ; info->buffer = (u_char *)malloc(8192) ; info->state = RStart ; info->timeoutCount = 0 ; ZIFlush(info) ; /* Don't send ZRINIT right away, there might be a ZRQINIT in * the input buffer. Instead, set timeout to zero and return. * This will allow ZmodemRcv() to check the input stream first. * If nothing found, a ZRINIT will be sent immediately. */ info->timeout = 0 ; zmodemlog("ZmodemRInit[%s]: flush input, new state = RStart\n", sname(info)) ; return 0 ;}intYmodemRInit(ZModem *info){ info->errCount = 0 ; info->InputState = Yrcv ; info->canCount = info->chrCount = 0 ; info->noiseCount = 0 ; info->filename = NULL ; info->file = NULL ; if( info->buffer == NULL ) info->buffer = (u_char *)malloc(1024) ; info->state = YRStart ; info->packetCount = -1 ; info->timeoutCount = 0 ; info->timeout = 10 ; info->offset = 0 ; ZIFlush(info) ; return ZXmitStr((u_char *)"C", 1, info) ;}extern int ZPF() ;extern int Ignore() ;extern int GotCommand() ;extern int GotStderr() ; int SendRinit() ;static int GotSinit() ;static int GotFile() ;static int GotFin() ;static int GotData() ;static int GotEof() ;static int GotFreecnt() ;static int GotFileCrc() ; int ResendCrcReq() ; int ResendRpos() ; /* sent ZRINIT, waiting for ZSINIT or ZFILE */ StateTable RStartOps[] = { {ZSINIT,GotSinit,0,1,RSinitWait}, /* SINIT, wait for attn str */ {ZFILE,GotFile,0,0,RFileName}, /* FILE, wait for filename */ {ZRQINIT,SendRinit,0,1,RStart}, /* sender confused, resend */ {ZFIN,GotFin,1,0,RFinish}, /* sender shutting down */ {ZNAK,SendRinit,1,0,RStart}, /* RINIT was bad, resend */#ifdef TODO {ZCOMPL,f,1,1,s},#endif /* TODO */ {ZFREECNT,GotFreecnt,0,0,RStart}, /* sender wants free space */ {ZCOMMAND,GotCommand,0,0,CommandData}, /* sender wants command */ {ZSTDERR,GotStderr,0,0,StderrData}, /* sender wants to send msg */ {99,ZPF,0,0,RStart}, /* anything else is an error */ } ; StateTable RSinitWaitOps[] = { /* waiting for data */ {99,ZPF,0,0,RSinitWait}, } ; StateTable RFileNameOps[] = { /* waiting for file name */ {99,ZPF,0,0,RFileName}, } ; StateTable RCrcOps[] = { /* waiting for CRC */ {ZCRC,GotFileCrc,0,0,RFile}, /* sender sent it */ {ZNAK,ResendCrcReq,0,0,RCrc}, /* ZCRC was bad, resend */ {ZRQINIT,SendRinit,1,1,RStart}, /* sender confused, restart */ {ZFIN,GotFin,1,1,RFinish}, /* sender signing off */ {99,ZPF,0,0,RCrc}, } ; StateTable RFileOps[] = { /* waiting for ZDATA */ {ZDATA,GotData,0,0,RData}, /* got it */ {ZNAK,ResendRpos,0,0,RFile}, /* ZRPOS was bad, resend */ {ZEOF,GotEof,0,0,RStart}, /* end of file */ {ZRQINIT,SendRinit,1,1,RStart}, /* sender confused, restart */ {ZFILE,ResendRpos,0,0,RFile}, /* ZRPOS was bad, resend */ {ZFIN,GotFin,1,1,RFinish}, /* sender signing off */ {99,ZPF,0,0,RFile}, } ; /* waiting for data, but a packet could possibly arrive due * to error recovery or something */ StateTable RDataOps[] = { {ZRQINIT,SendRinit,1,1,RStart}, /* sender confused, restart */ {ZFILE,GotFile,0,1,RFileName}, /* start a new file (??) */ {ZNAK,ResendRpos,1,1,RFile}, /* ZRPOS was bad, resend */ {ZFIN,GotFin,1,1,RFinish}, /* sender signing off */ {ZDATA,GotData,0,1,RData}, /* file data follows */ {ZEOF,GotEof,1,1,RStart}, /* end of file */ {99,ZPF,0,0,RData}, } ; /* here if we've sent ZFERR or ZABORT. Waiting for ZFIN */ StateTable RFinishOps[] = { {ZRQINIT,SendRinit,1,1,RStart}, /* sender confused, restart */ {ZFILE,GotFile,1,1,RFileName}, /* start a new file */ {ZNAK,GotFin,1,1,RFinish}, /* resend ZFIN */ {ZFIN,GotFin,1,1,RFinish}, /* sender signing off */ {99,ZPF,0,0,RFinish}, } ;extern char *hdrnames[] ;extern int dataSetup() ; /* RECEIVE-RELATED STUFF BELOW HERE */ /* resend ZRINIT header in response to ZRQINIT or ZNAK header */intSendRinit( register ZModem *info ){ u_char dbuf[4] ;#ifdef COMMENT if( info->timeoutCount >= 5 ) /* TODO: switch to Ymodem */#endif /* COMMENT */ zmodemlog("SendRinit[%s]: send ZRINIT\n", sname(info)) ; info->timeout = ResponseTime ; dbuf[0] = info->bufsize&0xff ; dbuf[1] = (info->bufsize>>8)&0xff ; dbuf[2] = 0 ; dbuf[3] = info->zrinitflags ; return ZXmitHdrHex(ZRINIT, dbuf, info) ;} /* received a ZSINIT header in response to ZRINIT */static intGotSinit( register ZModem *info ){ zmodemlog("GotSinit[%s]: call dataSetup\n", sname(info)) ; info->zsinitflags = info->hdrData[4] ; info->escCtrl = info->zsinitflags & TESCCTL ; info->escHibit = info->zsinitflags & TESC8 ; ZFlowControl(1, info) ; return dataSetup(info) ;} /* received rest of ZSINIT packet */intGotSinitData( register ZModem *info, int crcGood ){ info->InputState = Idle ; info->chrCount=0 ; info->state = RStart ; zmodemlog("GotSinitData[%s]: crcGood=%d\n", sname(info), crcGood) ; if( !crcGood ) return ZXmitHdrHex(ZNAK, zeros, info) ; if( info->attn != NULL ) free(info->attn) ; info->attn = NULL ; if( info->buffer[0] != '\0' ) info->attn = strdup((char *)info->buffer) ; return ZXmitHdrHex(ZACK, ZEnc4(SerialNo), info) ;} /* got ZFILE. Cache flags and set up to receive filename */static intGotFile( register ZModem *info ){ zmodemlog("GotFile[%s]: call dataSetup\n", sname(info)) ; info->errCount = 0 ; info->f0 = info->hdrData[4] ; info->f1 = info->hdrData[3] ; info->f2 = info->hdrData[2] ; info->f3 = info->hdrData[1] ; return dataSetup(info) ;} /* utility: see if ZOpenFile wants this file, and if * so, request it from sender. */static intrequestFile( register ZModem *info, u_long crc ){ info->file = ZOpenFile((char *)info->buffer, crc, info) ; if( info->file == NULL ) { zmodemlog("requestFile[%s]: send ZSKIP\n", sname(info)) ; info->state = RStart ; ZStatus(FileSkip, 0, info->filename) ; return ZXmitHdrHex(ZSKIP, zeros, info) ; } else { zmodemlog("requestFile[%s]: send ZRPOS(%ld)\n", sname(info), info->offset) ; info->offset = info->f0 == ZCRESUM ? ftell(info->file) : 0 ; info->state = RFile ; ZStatus(FileBegin, 0, info->filename) ; return ZXmitHdrHex(ZRPOS, ZEnc4(info->offset), info) ; }} /* parse filename info. */static voidparseFileName( register ZModem *info, char *fileinfo ){ char *ptr ; int serial=0 ; info->len = info->mode = info->filesRem = info->bytesRem = info->fileType = 0 ; ptr = fileinfo + strlen(fileinfo) + 1 ; if( info->filename != NULL ) free(info->filename) ; info->filename = strdup(fileinfo) ; sscanf(ptr, "%d %lo %o %o %d %d %d", &info->len, &info->date, &info->mode, &serial, &info->filesRem, &info->bytesRem, &info->fileType) ;} /* got filename. Parse arguments from it and execute * policy function ZOpenFile(), provided by caller */intGotFileName( register ZModem *info, int crcGood ){ info->InputState = Idle ; info->chrCount=0 ; if( !crcGood ) { zmodemlog("GotFileName[%s]: bad crc, send ZNAK\n", sname(info)) ; info->state = RStart ; return ZXmitHdrHex(ZNAK, zeros, info) ; } parseFileName(info, (char *)info->buffer) ; if( (info->f1 & ZMMASK) == ZMCRC ) { info->state = RCrc ; return ZXmitHdrHex(ZCRC, zeros, info) ; } zmodemlog("GotFileName[%s]: good crc, call requestFile\n", sname(info)) ; info->state = RFile ; return requestFile(info,0) ;}int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -