This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
magicka/Xmodem/zmodem.h

710 lines
24 KiB
C
Raw Normal View History

2016-04-02 23:26:17 +00:00
/* $Id: zmodem.h,v 1.2 2001/10/25 23:56:29 efalk Exp $ */
#ifndef ZMODEM_H
#define ZMODEM_H
/* Master header file for Zmodem protocol driver routines */
#if 0
These routines are intended to be incorportated into other programs,
and do not constitute a zmodem program by themselves, although a
demo zmodem program that uses these routines has been included.
All information pertaining to a transfer session is kept in a data
structure defined by the caller. This makes it possible for the
caller to drive multiple simultaneous sessions.
Caller provides I/O, timing and query routines. Caller remains
in control at all times. Typical use is to call these routines
from a select(2) loop.
Overview:
Transmit files:
1 Init ZModem structure and open communications channel.
2 Call ZmodemTInit() to begin protocol.
3 Read characters from remote end and pass them to
ZmodemRcv() until ZmodemRcv() returns ZmDone or an error.
4 Call ZmodemTFile() to begin transfer of a file.
5 Read characters from remote end and pass them to
ZmodemRcv() until ZmodemRcv() returns ZmDone or an error.
6 repeat steps 4&5 for all files.
7 Call ZmodemTFinish() to indicate that all files have been
transfered.
8 Read characters from remote end and pass them to
ZmodemRcv() until ZmodemRcv() returns ZmDone or an error.
Receive files:
1 Init ZModem structure and open communications channel.
2 Call ZmodemRInit() to begin protocol.
3 Read characters from remote end and pass them to
ZmodemRcv() until ZmodemRcv() returns ZmDone or an error.
In detail:
1) Create a ZModem structure as defined below and fill it in.
'ifd', 'ofd' are the file descriptors used for input and output.
The interpretation of ifd and ofd is entirely up to the calling
routines, since the caller will be providing I/O functions.
'zrinitflags' is composed of the flags described below.
They describe the receive channel capabilities
and affect how the protocol will be carried out.
Define these to receive files. When sending files, these
flags will be defined from the remote end.
'zsinitflags' is composed of the flags described below.
They describe the transmit channel capabilities
and affect how the protocol will be carried out.
Define these to send files. When receiving files, these
flags will be defined from the remote end.
'attn': For transmit, this is the optional nul-terminated
attention string to be sent by the receiver to interrupt the
transmission. For example, it might simply contain ^O to flush
the buffers, or it might interrupt the sending program. Caller
needs to handle this interrupt properly and call ZmodemAttention().
For receive, this is the optional nul-terminated attention string
defined at the remote end. Caller needs to provide a function that
can execute this sequence.
'timeout' is read-only, set by the zmodem package. It is the
timeout value in seconds. If this much time passes without
anything being received, caller should call the ZmodemTimeout()
function. Note that timeout may be zero, in which case the
ZTimeout function should be called immediately if no characters
are ready to be received.
'packetsize' is set to the preferred data packet size. Define
this when sending files. Recommended length values are 256
bytes below 2400 bps, 512 at 2400 bps, and 1024 above 4800 bps
or when the data link is known to be relatively error free.
Ignored during receive.
'bufsize' is set to the size of the receive buffer size. Define
this when receiving files. When sending files, this will be
defined at the other end.
'windowsize' is used to prevent network connections from
buffering too many characters during transmit. Setting
'windowsize' to nonzero causes zmodem to request status reports
from the receiver during transmit, and to pause if more than
this many bytes have been sent but not yet acknowledged. Set
to zero to turn off windowing. Ignored during receive.
Other fields are used to track the internal state of the zmodem
driver functions.
Since this is a source package, you are, of course, free to extend
the ZModem structure as you see fit.
2) Define the following functions:
int
ZXmitStr(u_char *str, int len, ZModem *info)
Transmit a buffer. Return 0 on success, ZmErrSys on error.
void
ZIFlush(ZModem *info)
Flush all unread input on receive channel. Do nothing if
this is not possible.
void
ZOFlush(ZModem *info)
Flush all buffered but not-yet-transmitted output
on transmit channel. Do nothing if this is not possible.
int
ZAttn(ZModem *info)
Send attention signal defined in ZModem->attn. Do
nothing if this field is NULL. Otherwise, this field
is a nul-terminated character string to be
transmitted. There are two special characters defined
below: ATTNBRK (0335) indicates that a BREAK signal
should be sent, and ATTNPSE (0336) represents a
1-second pause.
void
ZFlowControl(int onoff, ZModem *info)
Turn flow control on or off depending on the onoff flag.
void
ZStatus(int type, int value, char *status)
Called to provide status information. Ignore or display
at your option. Status string is not static, so copy
it if you need it beyond this call. Type is defined
below under "ZStatus() types".
FILE *
ZOpenFile(char *name, u_long crc, ZModem *info)
Called when receiving files, this function decides
whether or not to accept the specified file, and
if so, opens it for writing and returns the stdio
file handle. If this function decides not to accept
the file, or cannot open the file, it returns NULL
and the remote sender is told to skip this file.
info->f0-f3 are the transfer flags, described below under
"ZFILE transfer flags". These describe the type of
transfer desired (binary/ascii), and conditions for the
transfer, such as 'transfer if source newer or longer'.
info->len is the length of the file in bytes. info->date is
the last modification date of the file, in seconds since
1-jan-1970. info->mode is the unix file mode + 01000000, or
zero if not known. info->filesRem and info->bytesRem are the
number of files and bytes remaining to be transferred
if known, zero otherwise. 'crc' is the file crc-32 value.
This is only provided if F1 contains ZMCRC.
int
ZWriteFile(u_char *buffer, int len, FILE *file, ZModem *info)
Write a buffer of data to the file. Normally, you would
simply call fwrite(buffer, 1, len, file), but you may
want to translate line endings, etc. File transfer
flags are available as info->f0,f1,f2,f3.
Return 0 on success, ZmErrSys on failure, with errno
describing the failure.
int
ZCloseFile(ZModem *info)
Close file after successful completion. File modification
date and modes should be set at this time.
void
ZIdleStr(u_char *buffer, int len, ZModem *info)
Called to pass text that is received out-of-protocol.
This function may ignore or display this text at your
option.
3) Open the communications channel.
If possible, this should be a full-duplex channel with full
8-bit transmission. Hardware flow control and/or XON/XOFF
flow control should be enabled.
4) Call these routines:
All functions return 0 on success, nonzero on failure. See
"error code definitions", below.
Send:
int
ZmodemTInit(ZModem *info)
Begin a Zmodem transmit session.
int
ZmodemRcv(u_char *buffer, int len, ZModem *info)
Call whenever characters are received. If this function
returns ZmDone, previous function has completed successfully,
either call ZmodemTFile() to start next file, or call
ZmodemTFinish() to terminate the session.
int
ZmodemTimeout(ZModem *info)
Call whenever the timeout period expires and no
characters have been received.
int
ZmodemAttention(ZModem *info)
Call whenever the attention sequence has been received
from the remote end. It is safe to call this function
from an interrupt handler.
int
ZmodemTFile(char *filename, char *rfilename,
u_char f0,f1,f2,f3, int filesRem, int bytesRem, ZModem *info)
Begin transmitting a file. If filename is not NULL,
then this function will open it. Otherwise, info->file
must point to a stdio stream that is open for input.
It is preferable to provide the filename, so that
Zmodem can transmit file size and other information.
'rfilename' is the filename given to the remote end.
This may be the same as filename, the file part of
filename, or something else alltogether. 'rfilename'
must not be longer than the smallest data packet the
remote end might be willing to receive (about 200
characters). f0-f3 are transfer flags, see "ZCBIN"
below. 'filesRem' and 'bytesRem' are the number of files
and bytes remaining to be transmitted, if known; zero if
not.
If 'filename' cannot be accessed, ZmodemTFile() returns
ZmErrCantOpen. The link is still established, so you
need to either proceed with the next file or call
ZmodemTFinish().
int
ZmodemTFinish(ZModem *info)
Call after final file transfer has completed successfully.
int
ZmodemAbort(ZModem *info)
Call to abort transfer. Physical connection remains
open until you close it.
Receive:
int
ZmodemRInit(ZModem *info)
Call to get ready to receive first file. This function
will inform the sender that we are ready to receive.
int
ZmodemRcv(u_char *buffer, int len, ZModem *info)
Call whenever characters are received. If this
function returns ZmDone, all file transfers have
completed successfully.
int
ZmodemTimeout(ZModem *info)
Call whenever the timeout period expires and no
characters have been received.
int
ZmodemAbort(ZModem *info)
Call to abort transfer.
Ymodem and Xmodem:
int YmodemTInit(ZModem *info)
int XmodemTInit(ZModem *info)
int YmodemRInit(ZModem *info)
int XmodemRInit(ZModem *info)
Same semantics as ZmodemTInit and ZmodemRInit. It is
not normally necessary to call the Ymodem*Init() functions
as the Zmodem protocol will automatically switch to Ymodem
when needed.
Utility:
u_long
FileCrc(char *name)
Return CRC-32 of file.
5) Return Values:
ZmDone Done. Proceed with next file or ZmodemTFinish
(transmit) or exit (receive).
ZmErrInt Internal error. Link has been closed.
ZmErrSys System error, see errno. Link is closed.
ZmErrNotOpen not used.
ZmFileTooLong not used.
ZmFileCantWrite not used.
ZmErrCantOpen Can not open file, see errno. Link is still open.
ZmErrInitTo Transmitter failed to respond to init req. Link closed.
ZmErrSequence Packet received out of sequence. Link is closed.
ZmErrCancel Cancelled by remote end. Link is closed.
ZmErrRcvTo Remote end timed out during transfer. Link is closed.
ZmErrSndTo Remote end timed out during transfer. Link is closed.
ZmErrCmdTo Remote end timed out during transfer. Link is closed.
Note that "link is closed" means that the remote end is (presumably)
no longer operating. The actual communications channel is not
closed unless you close it. "Link is still open" means that the
remote end is still ready to receive the next file.
#endif
/* PARAMETERS
*
* The following #defines control the behavior of the Zmodem
* package. Note that these may be replaced with variables
* if you like. For example, "#define DoInitRZ" may be replaced
* with "extern int DoInitRz" to use a global variable, or with
* "#define DoInitRZ (info->doInitRz)" to use a variable you
* add to the ZModem structure.
*
* It is assumed that the compiler is good enough to optimize
* "if( 0 )" and "if( 1 )" cases. If not, you may wish to modify
* the source code to use #ifdef instead.
*/
#define DoInitRZ 1 /* send initial "rz\r" when transmitting */
#define AllowCommand 0 /* allow remote end to execute commands */
#define SendSample 1 /* sender can sample reverse channel */
#define SendAttn 1 /* sender can be interrupted with Attn signal */
#define ResponseTime 10 /* reasonable response time for sender to
* respond to requests from receiver */
#define SerialNo 1 /* receiver serial # */
#define MaxNoise 64 /* max "noise" characters before transmission
* pauses */
#define MaxErrs 20 /* Max receive errors before cancel */
#define AlwaysSinit 1 /* always send ZSINIT header, even if not
* needed, this makes protocol more robust */
#define SendOnly 0 /* compiles smaller version for send only */
#define RcvOnly 0 /* compiles smaller version for receive only */
/* constants */
#include <stdio.h>
#include <sys/types.h>
/* Internal State */
typedef enum zmstate {
/* receive */
RStart, /* sent RINIT, waiting for ZFILE or SINIT */
RSinitWait, /* got SINIT, waiting for data */
RFileName, /* got ZFILE, waiting for filename & info */
RCrc, /* got filename, want crc too */
RFile, /* got filename, ready to read */
RData, /* reading data */
RDataErr, /* encountered error, ignoring input */
RFinish, /* sent ZFIN, waiting for 'OO' */
/* transmit */
TStart, /* waiting for INIT frame from other end */
TInit, /* received INIT, sent INIT, waiting for ZACK */
FileWait, /* sent file header, waiting for ZRPOS */
CrcWait, /* sent file crc, waiting for ZRPOS */
Sending, /* sending data subpackets, ready for int */
SendWait, /* waiting for ZACK */
SendDone, /* file finished, need to send EOF */
SendEof, /* sent EOF, waiting for ZACK */
TFinish, /* sent ZFIN, waiting for ZFIN */
/* general */
CommandData, /* waiting for command data */
CommandWait, /* waiting for command to execute */
StderrData, /* waiting for stderr data */
Done,
/* x/ymodem transmit */
YTStart, /* waiting for 'G', 'C' or NAK */
YTFile, /* sent filename, waiting for ACK */
YTDataWait, /* ready to send data, waiting for 'C' */
YTData, /* sent data, waiting for ACK */
YTEOF, /* sent eof, waiting for ACK */
YTFin, /* sent null filename, waiting for ACK */
/* x/ymodem receive */
YRStart, /* sent 'C', waiting for filename */
YRDataWait, /* received filename, waiting for data */
YRData, /* receiving filename or data */
YREOF /* received first EOT, waiting for 2nd */
} ZMState ;
typedef struct {
int ifd ; /* input fd, for use by caller's routines */
int ofd ; /* output fd, for use by caller's routines */
FILE *file ; /* file being transfered */
int zrinitflags ; /* receiver capabilities, see below */
int zsinitflags ; /* sender capabilities, see below */
char *attn ; /* attention string, see below */
int timeout ; /* timeout value, in seconds */
int bufsize ; /* receive buffer size, bytes */
int packetsize ; /* preferred transmit packet size */
int windowsize ; /* max window size */
/* file attributes: read-only */
int filesRem, bytesRem ;
u_char f0,f1,f2,f3 ; /* file flags */
int len,mode,fileType ; /* file flags */
u_long date ; /* file date */
/* From here down, internal to Zmodem package */
ZMState state ; /* protocol internal state */
char *filename ; /* filename */
char *rfilename ; /* remote filename */
int crc32 ; /* use 32-bit crc */
int pktLen ; /* length of this packet */
int DataType ; /* input data type */
int PacketType ; /* type of this packet */
int rcvlen ;
int chrCount ; /* chars received in current header/buffer */
int crcCount ; /* crc characters remaining at end of buffer */
int canCount ; /* how many CAN chars received? */
int noiseCount ; /* how many noise chars received? */
int errorFlush ; /* ignore incoming data because of error */
u_char *buffer ; /* data buffer */
u_long offset ; /* file offset */
u_long lastOffset ; /* last acknowledged offset */
u_long zrposOffset ; /* last offset specified w/zrpos */
int ylen, bufp ; /* len,location of last Ymodem packet */
int fileEof ; /* file eof reached */
int packetCount ; /* # packets received */
int errCount ; /* how many data errors? */
int timeoutCount ; /* how many times timed out? */
int windowCount ; /* how much data sent in current window */
int atSign ; /* last char was '@' */
int lastCR ; /* last char was CR */
int escCtrl ; /* other end requests ctrl chars be escaped */
int escHibit ; /* other end requests hi bit be escaped */
int escape ; /* next character is escaped */
int interrupt ; /* received attention signal */
int waitflag ; /* next send should wait */
/* parser state */
enum {Idle, Padding, Inhdr, Indata, Finish, Ysend, Yrcv} InputState ;
enum {XMODEM, YMODEM, ZMODEM} Protocol ;
u_char hdrData[9] ; /* header type and data */
u_char fileFlags[4] ; /* file xfer flags */
u_long crc ; /* crc of incoming header/data */
enum {Full, StrWindow, SlidingWindow, Segmented} Streaming ;
} ZModem ;
/* ZRINIT flags. Describe receiver capabilities */
#define CANFDX 1 /* Rx is Full duplex */
#define CANOVIO 2 /* Rx can overlap I/O */
#define CANBRK 4 /* Rx can send a break */
#define CANCRY 010 /* Rx can decrypt */
#define CANLZW 020 /* Rx can uncompress */
#define CANFC32 040 /* Rx can use 32-bit crc */
#define ESCCTL 0100 /* Rx needs control chars escaped */
#define ESC8 0200 /* Rx needs 8th bit escaped. */
/* ZSINIT flags. Describe sender capabilities */
#define TESCCTL 0100 /* Tx needs control chars escaped */
#define TESC8 0200 /* Tx needs 8th bit escaped. */
/* ZFILE transfer flags */
/* F0 */
#define ZCBIN 1 /* binary transfer */
#define ZCNL 2 /* convert NL to local eol convention */
#define ZCRESUM 3 /* resume interrupted file xfer, or append to a
growing file. */
/* F1 */
#define ZMNEWL 1 /* transfer if source newer or longer */
#define ZMCRC 2 /* transfer if different CRC or length */
#define ZMAPND 3 /* append to existing file, if any */
#define ZMCLOB 4 /* replace existing file */
#define ZMNEW 5 /* transfer if source is newer */
#define ZMDIFF 6 /* transfer if dates or lengths different */
#define ZMPROT 7 /* protect: transfer only if dest doesn't exist */
#define ZMCHNG 8 /* change filename if destination exists */
#define ZMMASK 037 /* mask for above. */
#define ZMSKNOLOC 0200 /* skip if not present at Rx end */
/* F2 */
#define ZTLZW 1 /* lzw compression */
#define ZTRLE 3 /* run-length encoding */
/* F3 */
#define ZCANVHDR 1 /* variable headers ok */
#define ZRWOVR 4 /* byte position for receive window override/256 */
#define ZXSPARS 64 /* encoding for sparse file ops. */
/* ATTN string special characters. All other characters sent verbose */
#define ATTNBRK '\335' /* send break signal */
#define ATTNPSE '\336' /* pause for one second */
/* ZStatus() types */
#define RcvByteCount 0 /* value is # bytes received */
#define SndByteCount 1 /* value is # bytes sent */
#define RcvTimeout 2 /* receiver did not respond, aborting */
#define SndTimeout 3 /* value is # of consecutive send timeouts */
#define RmtCancel 4 /* remote end has cancelled */
#define ProtocolErr 5 /* protocol error has occurred, val=hdr */
#define RemoteMessage 6 /* message from remote end */
#define DataErr 7 /* data error, val=error count */
#define FileErr 8 /* error writing file, val=errno */
#define FileBegin 9 /* file transfer begins, str=name */
#define FileEnd 10 /* file transfer ends, str=name */
#define FileSkip 11 /* file being skipped, str=name */
/* error code definitions [O] means link still open */
#define ZmDone -1 /* done */
#define ZmErrInt -2 /* internal error */
#define ZmErrSys -3 /* system error, see errno */
#define ZmErrNotOpen -4 /* communication channel not open */
#define ZmErrCantOpen -5 /* can't open file, see errno [O] */
#define ZmFileTooLong -6 /* remote filename too long [O] */
#define ZmFileCantWrite -7 /* could not write file, see errno */
#define ZmDataErr -8 /* too many data errors */
#define ZmErrInitTo -10 /* transmitter failed to respond to init req. */
#define ZmErrSequence -11 /* packet received out of sequence */
#define ZmErrCancel -12 /* cancelled by remote end */
#define ZmErrRcvTo -13 /* remote receiver timed out during transfer */
#define ZmErrSndTo -14 /* remote sender timed out during transfer */
#define ZmErrCmdTo -15 /* remote command timed out */
/* zmodem-supplied functions: */
extern int ZmodemTInit(ZModem *info) ;
extern int ZmodemTFile(char *file, char *rmtname,
u_int f0, u_int f1, u_int f2, u_int f3,
int filesRem, int bytesRem, ZModem *info) ;
extern int ZmodemTFinish(ZModem *info) ;
extern int ZmodemAbort(ZModem *info) ;
extern int ZmodemRInit(ZModem *info) ;
extern int ZmodemRcv(u_char *str, int len, ZModem *info) ;
extern int ZmodemTimeout(ZModem *info) ;
extern int ZmodemAttention(ZModem *info) ;
extern int YmodemTInit(ZModem *info) ;
extern int XmodemTInit(ZModem *info) ;
extern int YmodemRInit(ZModem *info) ;
extern int XmodemRInit(ZModem *info) ;
extern u_long FileCrc(char *name) ;
extern char *sname(ZModem *) ;
extern char *sname2(ZMState) ;
#ifdef DEBUG
extern FILE *zmodemlogfile ;
extern void zmodemlog(const char *, ...) ;
#else
#define zmodemlog
#endif
/* caller-supplied functions: */
extern int ZXmitChr(u_char c, ZModem *info) ;
extern int ZXmitStr(u_char *str, int len, ZModem *info) ;
extern void ZIFlush(ZModem *info) ;
extern void ZOFlush(ZModem *info) ;
extern int ZAttn(ZModem *info) ;
extern void ZStatus(int type, int value, char *status) ;
extern FILE *ZOpenFile(char *name, u_long crc, ZModem *info) ;
/* From here on down, internal to Zmodem package */
/* ZModem character definitions */
#define ZDLE 030 /* zmodem escape is CAN */
#define ZPAD '*' /* pad */
#define ZBIN 'A' /* introduces 16-bit crc binary header */
#define ZHEX 'B' /* introduces 16-bit crc hex header */
#define ZBIN32 'C' /* introduces 32-bit crc binary header */
#define ZBINR32 'D' /* introduces RLE packed binary frame w/32-bit crc */
#define ZVBIN 'a' /* alternate ZBIN */
#define ZVHEX 'b' /* alternate ZHEX */
#define ZVBIN32 'c' /* alternate ZBIN32 */
#define ZVBINR32 'd' /* alternate ZBINR32 */
#define ZRESC 0177 /* RLE flag/escape character */
/* ZModem header type codes */
#define ZRQINIT 0 /* request receive init */
#define ZRINIT 1 /* receive init */
#define ZSINIT 2 /* send init sequence, define Attn */
#define ZACK 3 /* ACK */
#define ZFILE 4 /* file name, from sender */
#define ZSKIP 5 /* skip file command, from receiver */
#define ZNAK 6 /* last packet was garbled */
#define ZABORT 7 /* abort */
#define ZFIN 8 /* finish session */
#define ZRPOS 9 /* resume file from this position, from receiver */
#define ZDATA 10 /* data packets to follow, from sender */
#define ZEOF 11 /* end of file, from sender */
#define ZFERR 12 /* fatal i/o error, from receiver */
#define ZCRC 13 /* request for file crc, from receiver */
#define ZCHALLENGE 14 /* "send this number back to me", from receiver */
#define ZCOMPL 15 /* request is complete */
#define ZCAN 16 /* other end cancelled with CAN-CAN-CAN-CAN-CAN */
#define ZFREECNT 17 /* request for free bytes on filesystem */
#define ZCOMMAND 18 /* command, from sending program */
#define ZSTDERR 19 /* output this message to stderr */
/* ZDLE escape sequences */
#define ZCRCE 'h' /* CRC next, frame ends, header follows */
#define ZCRCG 'i' /* CRC next, frame continues nonstop */
#define ZCRCQ 'j' /* CRC next, send ZACK, frame continues nonstop */
#define ZCRCW 'k' /* CRC next, send ZACK, frame ends */
#define ZRUB0 'l' /* translate to 0177 */
#define ZRUB1 'm' /* translate to 0377 */
/* ascii definitions */
#define SOH 1 /* ^A */
#define STX 2 /* ^B */
#define EOT 4 /* ^D */
#define ACK 6 /* ^F */
#define DLE 16 /* ^P */
#define XON 17 /* ^Q */
#define XOFF 19 /* ^S */
#define NAK 21 /* ^U */
#define SYN 22 /* ^V */
#define CAN 24 /* ^X */
extern int ZXmitHdr() ;
extern int ZXmitHdrHex() ;
extern int ZXmitHdrBin() ;
extern int ZXmitHdrBin32() ;
extern u_char *putZdle( u_char *ptr, u_char c, ZModem *info ) ;
extern u_char *ZEnc4() ;
extern u_long ZDec4() ;
/* state table entry. There is one row of the table per
* possible state. Each row is a row of all reasonable
* inputs for this state. The entries are sorted so that
* the most common inputs occur first, to reduce search time
* Unexpected input is reported and ignored, as it might be
* caused by echo or something.
*
* Extra ZRINIT headers are the receiver trying to resync.
*/
typedef struct {
int type ; /* frame type */
int (*func)() ; /* transition function */
int IFlush ; /* flag: flush input first */
int OFlush ; /* flag: flush output first */
ZMState newstate ; /* new state. May be overridden by func */
} StateTable ;
#endif