home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
TELECOM
/
xyz.lzh
/
ftz.c
< prev
next >
Wrap
Text File
|
1995-08-18
|
77KB
|
2,619 lines
/*
Printed form of this source is Copyright (C) 1995 Coriolis
Group, Inc. All rights reserved. Individual users may
make printed copies for their own personal use.
All other forms are Copyright (C) 1995 Tim Kientzle. All
rights reserved.
Redistribution in source or binary form is permitted only under
the following conditions:
1. If you own a copy of `The Working Programmer's Guide To Serial
Protocols,' then you may redistribute this code as part of
a complete application program under the conditions
described in that book. (See pages xiv, xv.) In any case,
you must abide by terms 4-7 below.
2. Otherwise, if you have received this code as a part of an
application program, it may only be redistributed with the
complete source of that program, under whatever conditions
apply to redistribution of that program as a whole.
3. If you have received this source code by some other means,
you may not redistribute it without explicit written
permission from Tim Kientzle.
4. All advertising materials mentioning features or use of this
software must prominently display the following acknowledgement:
This product is partially based on source code appearing in
`The Working Programmer's Guide to Serial Protocols,'
Copyright (C) 1995 Coriolis Group, Inc. and Tim Kientzle.
5. All programs using this source code must display the above
acknowledgement prominently in the program documentation
and user interface.
6. Neither the name of the Tim Kientzle nor the Coriolis Group, Inc.,
may be used to endorse or promote products derived from this
software without specific prior written permission.
7. Any redistribution in source form must retain the above copyright
notice, this list of conditions, and the disclaimer below.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL TIM KIENTZLE OR THE CORIOLIS GROUP BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define I_CAN_SAMPLE (1)
#define I_CAN_FULL_DUPLEX (1)
#define I_CAN_OVERLAP_DISK (1)
#define I_CAN_SEND_BREAK (1) \
#define ATTENTION (NULL)
#define CR (0x0d)
#define LF (0x0a)
#define DLE (0x10)
#define XON (0x11)
#define XOFF (0x13)
#define CAN (0x18)
#define DEL (0x7F)
#define SetIgnore(c)(pZ->classify[c]|= 1)
#define TestIgnore(c)(pZ->classify[c]&1)
#define SetEncode(c)(pZ->classify[c]|= 2)
#define TestEncode(c)(pZ->classify[c]&2) \
#define ZRQINIT (0)
#define ZRINIT (1)
#define ZSINIT (2)
#define ZACK (3)
#define ZFILE (4)
#define ZSKIP (5)
#define ZNAK (6)
#define ZABORT (7)
#define ZFIN (8)
#define ZRPOS (9)
#define ZDATA (10)
#define ZEOF (11)
#define ZFERR (12)
#define ZCRC (13)
#define ZCHALLENGE (14)
#define ZCOMPL (15)
#define ZCAN (16)
#define ZFREECNT (17)
#define ZCOMMAND (18)
#define ZSTDERR (19)
#define DebugPacket(debug,type,arg) \
DebugString((debug),zPacketName[(type)]); \
DebugString((debug),"("); \
DebugIntHex((debug),(arg)); \
DebugString((debug),")");
#define CONV_BINARY (0x01000000)
#define CONV_TEXT (0x02000000)
#define CONV_RESUME (0x03000000)
#define CONV_MASK (0xFF000000U)
#define MAN_SKNOLOC (0x00800000)
#define MAN_NEW_LONG (0x00010000)
#define MAN_CRC_LENGTH (0x00020000)
#define MAN_APPEND (0x00030000)
#define MAN_REPLACE (0x00040000)
#define MAN_NEW (0x00050000)
#define MAN_DATE_LENGTH (0x00060000)
#define MAN_NONEXISTENT (0x00070000)
#define MAN_MASK (0x007F0000)
#define TRAN_LZW (0x00000100)
#define TRAN_CRYPT (0x00000200)
#define TRAN_RLE (0x00000300)
#define TRAN_MASK (0x0000FF00)
#define EXTEN_SPARSE (0x00000040)
#define EXTEN_MASK (0x000000FF)
#define CAN_FULL_DUPLEX (0x01000000)
#define CAN_OVERLAP_DISK (0x02000000)
#define CAN_SEND_BREAK (0x04000000)
#define KNOW_CRYPT (0x08000000)
#define KNOW_LZW (0x10000000)
#define KNOW_CRC32 (0x20000000)
#define ESCAPE_CONTROLS (0x40000000)
#define ESCAPE_8BIT (0x80000000)
#define StsRet(expr)do{int tmpErrorVal= (expr); \
if(tmpErrorVal!=zOK)return StsWarn(tmpErrorVal); \
}while(FALSE)
#define StsWarn(s)((pZ->debug)?ZDebugWarn(pZ,(s),__FILE__,__LINE__):(s))
#define debugWarn (1)
#define debugPacket (2)
#define debugPacketErr (4)
#define debugPacketLowLevel (8)
#define debugCache (16)
#define debugAttr (32)
#define debugInit (64)
#define debugEncoding (256)
#define debugSerial (512)
#define SendingCrc(pBuff,length,crc) \
((pZ->sendingCrc32)?ZCrc32((pBuff),(length),(crc)):ZCrc16((pBuff),(length),(crc)))
#define ZReadByteWithTimeout(pZ,timeout,pByte) \
(((pZ)->serialBufferRead<(pZ)->serialBufferLimit)? \
(*(pByte)= *((pZ)->serialBufferRead++),zOK): \
(ZReadByteWithTimeoutFcn((pZ),(timeout),(pByte))))
#define SetDecode(c)(pZ->classify[c]|= 4)
#define TestDecode(c)(pZ->classify[c]&4)
#define DEFAULT_WINDOW_SIZE (100000)
#define ACK_INTERVAL_MIN 512
#define ACK_INTERVAL_MAX 16384
#define HasLimits(flags)(!((flags)&(CAN_FULL_DUPLEX|CAN_OVERLAP_DISK)))
#define HALF_DUPLEX_BURST 1024
#define CloseDataPacket(pZ) \
if(pZ->txPacketType==ZDATA) \
StsRet(ZSendFileDataPacket(pZ,&window,0,TRUE,FALSE))
#define BufferFree (window.size-(window.endFilePos-pZ->receivePosition)) \
#define ZSendZRINIT(pZ)ZSendHexHeader(pZ,ZRINIT,pZ->myReceiverFlags)
#define IsWhitespace(c)((c==' ')||(c=='\t')||(c=='\r')||(c=='\n')||(c=='\f'))
#include "ftdisk.h"
#include "ftserial.h"
#include "ftdebug.h"
#include "ftprog.h"
#include "ftz.h"
#include <stddef.h>
#include <time.h>
#include <stdio.h>
#ifdef _UCC
#include <stdlib.h>
#include <string.h>
#else
int sprintf ();
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef NULL
#define NULL ((void *)0)
#endif
#define STATIC
typedef unsigned char BYTE;
typedef struct {
int crc32;
int timeout;
int retries;
int userCancel;
BYTE attention[40];
unsigned long zrqinitFlags;
unsigned long senderFlags;
unsigned long receiverFlags;
unsigned long myZrqinitFlags;
unsigned long mySenderFlags;
unsigned long myReceiverFlags;
unsigned long fileFlags;
unsigned char classify[256];
int sendingCrc32;
int txPacketType;
int receivingCrc32;
int rxPacketType;
unsigned long rxPacketArg;
unsigned long sendPosition;
unsigned long receivePosition;
DEBUG debug;
SERIAL_PORT port;
BYTE *serialBuffer;
int serialBufferSize;
BYTE *serialBufferRead;
BYTE *serialBufferLimit;
DISKFILE f;
long fileSize;
const char **filenames;
int currentFileName;
int numFileNames;
int fileType;
PROGRESS progress;
long noiseLimit;
int crashRecovery;
} ZMODEM_PRIVATE;
const char *zPacketName[] =
{
"ZRQINIT", "ZRINIT", "ZSINIT", "ZACK", "ZFILE", "ZSKIP", "ZNAK",
"ZABORT", "ZFIN", "ZRPOS", "ZDATA", "ZEOF", "ZFERR", "ZCRC",
"ZCHALLENGE", "ZCOMPL", "ZCAN", "ZFREECNT", "ZCOMMAND", "ZSTDERR",
NULL, NULL, NULL
};
enum {
zOK = 0,
zFail,
zFailed,
zBadPacket,
zEndOfSession,
zEOF,
zTimeout,
zSkip
};
STATIC int ZDebugWarn
(ZMODEM_PRIVATE *pZ, const int s, const char *file, const int line) {
const char *msg = NULL;
if (s != zOK) {
DebugBeginInternal (pZ->debug, debugWarn, file, line);
DebugString (pZ->debug, "?!?!?!:");
}
switch (s) {
case zOK:
return zOK;
case zFail:
msg = "zFail";
break;
case zFailed:
msg = "zFailed";
break;
case zBadPacket:
msg = "zBadPacket";
break;
case zEndOfSession:
msg = "zEndOfSession";
break;
case zEOF:
msg = "zEOF";
break;
case zTimeout:
msg = "zTimeout";
break;
}
if (msg != NULL)
DebugString (pZ->debug, msg);
else {
DebugString (pZ->debug, "Error ");
DebugInt (pZ->debug, s);
}
DebugEnd (pZ->debug);
return s;
}
STATIC void ZNewFile
(ZMODEM_PRIVATE *pZ) {
pZ->fileSize = -1;
pZ->sendPosition = 0;
pZ->receivePosition = 0;
}
STATIC unsigned short int zCrc16Table[256];
STATIC unsigned long int zCrc32Table[256];
STATIC void ZInitCrc
(void) {
static int crcDone = 0;
unsigned long i, j, crc;
if (crcDone)
return;
for (i = 0; i < 256; i++) {
crc = (i << 8);
for (j = 0; j < 8; j++)
crc = (crc << 1) ^ ((crc & 0x8000) ? 0x1021 : 0);
zCrc16Table[i] = crc & 0xffff;
}
for (i = 0; i < 256; i++) {
crc = i;
for (j = 0; j < 8; j++)
crc = (crc >> 1) ^ ((crc & 1) ? 0xEDB88320U : 0);
zCrc32Table[i] = crc & 0xffffffffU;
}
crcDone = 1;
}
STATIC unsigned long ZCrc16
(const BYTE *buff, unsigned int length,
unsigned long crc) {
const BYTE *p = buff;
while (length-- > 0)
crc = zCrc16Table[((crc >> 8) ^ *p++) & 0xFF] ^ (crc << 8);
return crc & 0xFFFF;
}
STATIC unsigned long ZCrc32
(const BYTE *buff,
unsigned int length, unsigned long crc) {
const BYTE *p = buff;
crc = ~crc;
while (length-- > 0)
crc = zCrc32Table[(crc ^ *p++) & 0xFF] ^ ((crc >> 8) & 0xFFFFFF);
return ~crc;
}
STATIC void ZTimeToTm
(long s, struct tm *pT) {
long m, h;
int d, M, y;
if (s <= 0) {
time_t t = time (NULL);
*pT = *localtime (&t);
return;
}
m = s / 60;
h = m / 60;
d = h / 24;
y = d / 365;
s %= 60;
m %= 60;
h %= 24;
d %= 365;
d -= (y + 1) / 4;
if (d < 0) {
y--;
d += 365;
}
pT->tm_sec = s;
pT->tm_min = m;
pT->tm_hour = h;
pT->tm_yday = d;
if (((y - 2) % 4 != 0) && (d >= 59))
d++;
if (d >= 60)
d++;
M = (d > 214) ? 7 : 0 + ((d % 214) / 61) * 2 + ((d % 214) % 61) / 31;
d = ((d % 214) % 61) % 31 + 1;
pT->tm_mday = d;
pT->tm_mon = M;
pT->tm_year = y + 70;
pT->tm_isdst = -1;
pT->tm_wday = -1;
}
STATIC long ZTime
(struct tm *pT) {
static const int mon[] =
{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335};
int y = pT->tm_year - 70, M = pT->tm_mon;
int d = pT->tm_mday - 1 + mon[M];
if (((y + 2) % 4 != 0) & (M > 1))
d--;
d += (y + 1) / 4;
return (((((long) y) * 365 + d) * 24 + pT->tm_hour) * 60 + pT->tm_min) * 60
+ pT->tm_sec;
}
STATIC void ZParseZRINIT
(ZMODEM_PRIVATE *pZ, unsigned long flags) {
pZ->receiverFlags = flags;
if (flags & KNOW_CRC32)
pZ->crc32 = TRUE;
if (flags & ESCAPE_CONTROLS) {
int i;
SetEncode (DEL);
SetEncode (DEL | 0x80);
SetIgnore (DEL);
SetIgnore (DEL | 0x80);
for (i = 0; i < 32; i++) {
SetEncode (i);
SetIgnore (i);
}
for (i = 128; i < 160; i++) {
SetEncode (i);
SetIgnore (i);
}
pZ->mySenderFlags |= ESCAPE_CONTROLS;
}
}
STATIC void ZParseZSINIT
(ZMODEM_PRIVATE *pZ, unsigned long flags) {
pZ->senderFlags = flags;
if (flags & ESCAPE_CONTROLS) {
int i;
SetEncode (DEL);
SetEncode (DEL | 0x80);
SetIgnore (DEL);
SetIgnore (DEL | 0x80);
for (i = 0; i < 32; i++) {
SetEncode (i);
SetIgnore (i);
}
for (i = 128; i < 160; i++) {
SetEncode (i);
SetIgnore (i);
}
pZ->myReceiverFlags |= ESCAPE_CONTROLS;
}
}
STATIC int ZReadBytesWithTimeout
(ZMODEM_PRIVATE *pZ, int timeout,
BYTE *pBuffer, unsigned long *pLength) {
int err, returnVal = zOK;
unsigned long lengthRead = 0;
unsigned long lengthToRead = *pLength;
if (pZ->serialBufferRead < pZ->serialBufferLimit) {
lengthRead = pZ->serialBufferLimit - pZ->serialBufferRead;
if (lengthRead > lengthToRead)
lengthRead = lengthToRead;
memcpy (pBuffer, pZ->serialBufferRead, lengthRead);
pZ->serialBufferRead += lengthRead;
pBuffer += lengthRead;
lengthToRead -= lengthRead;
}
if ((lengthToRead > 0) && (lengthToRead < pZ->serialBufferSize)) {
*pLength = pZ->serialBufferSize;
pZ->serialBufferRead = pZ->serialBufferLimit = pZ->serialBuffer;
err = SerialReadWithTimeout (pZ->port, 0, pZ->serialBuffer, pLength);
pZ->serialBufferLimit += *pLength;
switch (err) {
case serialOK:
returnVal = zOK;
break;
case serialTimeout:
returnVal = zOK;
break;
case serialUserCancel:
pZ->userCancel = TRUE;
returnVal = zFail;
break;
case serialFrame:
returnVal = zBadPacket;
break;
default:
return StsWarn (zFailed);
}
if (pZ->serialBufferRead < pZ->serialBufferLimit) {
lengthRead = pZ->serialBufferLimit - pZ->serialBufferRead;
if (lengthRead > lengthToRead)
lengthRead = lengthToRead;
memcpy (pBuffer, pZ->serialBufferRead, lengthRead);
pZ->serialBufferRead += lengthRead;
pBuffer += lengthRead;
lengthToRead -= lengthRead;
}
}
if ((lengthToRead > 0) && (returnVal == zOK)) {
*pLength = lengthToRead;
err = SerialReadWithTimeout (pZ->port, timeout, pBuffer, pLength);
switch (err) {
case serialOK:
returnVal = zOK;
break;
case serialTimeout:
returnVal = zTimeout;
break;
case serialUserCancel:
pZ->userCancel = TRUE;
returnVal = zFail;
break;
case serialFrame:
returnVal = zBadPacket;
break;
default:
return StsWarn (zFailed);
}
lengthRead += *pLength;
}
if (pZ->userCancel)
return StsWarn (zFail);
*pLength = lengthRead;
return returnVal;
}
STATIC int ZSendBytes
(ZMODEM_PRIVATE *pZ, const BYTE *pBuffer, unsigned length) {
int err, returnVal;
err = SerialSend (pZ->port, pBuffer, length);
switch (err) {
case serialOK:
returnVal = zOK;
break;
case serialUserCancel:
pZ->userCancel = TRUE;
returnVal = zFail;
break;
default:
return StsWarn (zFailed);
}
if (pZ->userCancel)
return StsWarn (zFail);
return StsWarn (returnVal);
}
STATIC int ZWaitForSentBytes
(ZMODEM_PRIVATE *pZ) {
int err, returnVal;
if (pZ->userCancel)
return StsWarn (zFail);
err = SerialWaitForSentBytes (pZ->port);
switch (err) {
case serialOK:
returnVal = zOK;
break;
case serialUserCancel:
pZ->userCancel = TRUE;
returnVal = zFail;
break;
default:
return StsWarn (zFailed);
}
if (pZ->userCancel)
return StsWarn (zFail);
return StsWarn (returnVal);
}
STATIC int ZSendByte
(ZMODEM_PRIVATE *pZ, BYTE b) {
return StsWarn (ZSendBytes (pZ, &b, 1));
}
STATIC int ZReadByteWithTimeoutFcn
(ZMODEM_PRIVATE *pZ, int timeout,
BYTE *pByte) {
unsigned long count = 1;
return ZReadBytesWithTimeout (pZ, timeout, pByte, &count);
}
STATIC int ZGobble
(ZMODEM_PRIVATE *pZ, int timeout) {
int err;
BYTE junk[50];
unsigned long junkSize = sizeof (junk);
do {
err = ZReadBytesWithTimeout (pZ, timeout, junk, &junkSize);
if (err == zBadPacket)
err = zOK;
} while (err == zOK);
if (err == zTimeout)
return zOK;
return StsWarn (err);
}
STATIC int ZSendBreak
(ZMODEM_PRIVATE *pZ) {
int returnVal;
int err = SerialSendBreak (pZ->port);
switch (err) {
case serialOK:
returnVal = zOK;
break;
case serialUserCancel:
pZ->userCancel = TRUE;
returnVal = zFail;
break;
default:
return StsWarn (zFailed);
}
if (pZ->userCancel)
return StsWarn (zFail);
return StsWarn (returnVal);
}
STATIC int ZPause
(ZMODEM_PRIVATE *pZ) {
int returnVal;
int err = SerialPause (pZ->port, 1);
switch (err) {
case serialOK:
returnVal = zOK;
break;
case serialUserCancel:
pZ->userCancel = TRUE;
returnVal = zFail;
break;
default:
return StsWarn (zFailed);
}
if (pZ->userCancel)
return StsWarn (zFail);
return StsWarn (returnVal);
}
STATIC int ZFileReadOpenNext
(ZMODEM_PRIVATE *pZ, int fileType) {
while (1) {
if (pZ->currentFileName == pZ->numFileNames)
return zEndOfSession;
switch (DiskReadOpen (&pZ->f, pZ->filenames[pZ->currentFileName++],
fileType)) {
case diskOK:
DiskFileSize (pZ->f, &(pZ->fileSize));
return zOK;
case diskCantRead:
case diskNoSuchFile:
break;
default:
return zFail;
}
}
}
STATIC int ZFileRead
(ZMODEM_PRIVATE *pZ, BYTE *pBuffer, unsigned long *pLength) {
int returnVal;
switch (DiskRead (pZ->f, pBuffer, *pLength, pLength)) {
case diskOK:
returnVal = zOK;
break;
case diskEOF:
returnVal = zEOF;
break;
default:
returnVal = zFail;
break;
}
return returnVal;
}
STATIC int ZFileReadSkip
(ZMODEM_PRIVATE *pZ, unsigned long length) {
BYTE buff[500];
while (length > 0) {
unsigned long readSize = sizeof (buff);
if (readSize > length)
readSize = length;
StsRet (ZFileRead (pZ, buff, &readSize));
length -= readSize;
}
return zOK;
}
STATIC int ZFileReadClose
(ZMODEM_PRIVATE *pZ) {
int returnVal;
switch (DiskReadClose (pZ->f)) {
case diskOK:
returnVal = zOK;
break;
default:
returnVal = zFail;
break;
}
pZ->f = NULL;
return returnVal;
}
STATIC int ZFileWriteOpen
(ZMODEM_PRIVATE *pZ, BYTE *pBuffer, unsigned length) {
const char *fileName = (char *) pBuffer;
long fileMode = -1;
long fileSize = -1;
struct tm fileDate;
int fileType;
int err;
((void) length);
if ((fileName == NULL) || (*fileName == 0))
fileName = "zmodem.000\0\0";
{
time_t t = time (NULL);
fileDate = *localtime (&t);
}
{
const char *p = fileName;
p += strlen (p) + 1;
if (*p) {
fileSize = atoi (p);
while ((*p) && (*p != ' '))
p++;
if (*p)
p++;
}
if (*p) {
long fileDateSeconds = 0;
while ((*p) && (*p != ' ')) {
fileDateSeconds = fileDateSeconds * 8 + (*p) - '0';
p++;
}
ZTimeToTm (fileDateSeconds, &fileDate);
if (*p)
p++;
}
if (*p) {
fileMode = 0;
while ((*p) && (*p != ' ')) {
fileMode = fileMode * 8 + (*p) - '0';
p++;
}
if (*p)
p++;
}
}
if (DiskWriteInit (&pZ->f, pZ->debug))
return StsWarn (zFail);
if (DiskWriteName (pZ->f, fileName))
return StsWarn (zFail);
pZ->fileSize = fileSize;
if (DiskWriteSize (pZ->f, fileSize))
return StsWarn (zFail);
if (DiskWriteDate (pZ->f, &fileDate))
return StsWarn (zFail);
if (DiskWriteMode (pZ->f, fileMode))
return StsWarn (zFail);
fileType = pZ->fileType;
if (fileType == diskFileUnknown) {
switch (pZ->fileFlags & CONV_MASK) {
case 0:
break;
case CONV_BINARY:
fileType = diskFileBinary;
break;
case CONV_TEXT:
fileType = diskFileText;
break;
case CONV_RESUME:
fileType = diskFileBinary;
break;
default:
if (pZ->debug) {
DebugBegin (pZ->debug, debugAttr);
DebugString (pZ->debug, "Unknown conversion option: ");
DebugIntHex (pZ->debug, pZ->fileFlags & CONV_MASK);
DebugEnd (pZ->debug);
}
}
}
if (DiskWriteType (pZ->f, fileType))
return StsWarn (zFail);
if (pZ->fileFlags & MAN_SKNOLOC) {
DISKFILE fTmp;
err = DiskReadOpen (&fTmp, fileName, diskFileUnknown);
if (err == diskNoSuchFile)
return StsWarn (zSkip);
DiskReadClose (fTmp);
}
switch (pZ->fileFlags & MAN_MASK) {
case MAN_APPEND:
err = DiskAppendOpen (pZ->f);
break;
case MAN_REPLACE:
err = DiskReplaceOpen (pZ->f);
break;
default:
err = DiskWriteOpen (pZ->f);
break;
}
if (err == diskError)
return StsWarn (zSkip);
else if (err != diskOK)
return StsWarn (zFail);
return zOK;
}
STATIC int ZFileWrite
(ZMODEM_PRIVATE *pZ, const BYTE *pBuffer,
unsigned long length) {
switch (DiskWrite (pZ->f, pBuffer, length)) {
case diskOK:
return zOK;
default:
return zFail;
}
}
STATIC int ZFileWriteClose
(ZMODEM_PRIVATE *pZ) {
int returnVal;
switch (DiskWriteClose (pZ->f)) {
case diskOK:
returnVal = zOK;
break;
default:
returnVal = zFail;
break;
}
pZ->f = NULL;
return returnVal;
}
STATIC long ZFileSize
(ZMODEM_PRIVATE *pZ) {
long size;
if (pZ->f == NULL)
return -1;
else if (DiskFileSize (pZ->f, &size))
return -1;
else
return size;
}
STATIC unsigned long ZFileSystemFree
(ZMODEM_PRIVATE *pZ, unsigned long *pFreeCount) {
((void) pZ);
*pFreeCount = 0L;
return zOK;
}
STATIC int ZFileCRC
(ZMODEM_PRIVATE *pZ, unsigned long numberBytes, unsigned long *pCrc) {
DISKFILE fTmp;
BYTE buff[4096];
unsigned long crc = 0;
const char *fileName;
int err;
*pCrc = 0;
DiskFileName (pZ->f, &fileName);
err = DiskReadOpen (&fTmp, fileName, diskFileBinary);
if (err != diskOK)
return StsWarn (zFail);
while (numberBytes > 0) {
unsigned long numberRead = numberBytes;
if (numberRead > sizeof (buff))
numberRead = sizeof (buff);
err = DiskRead (fTmp, buff, numberRead, &numberRead);
if (err != diskOK)
return StsWarn (zFail);
crc = ZCrc32 (buff, numberRead, crc);
numberBytes -= numberRead;
}
DiskReadClose (fTmp);
*pCrc = crc;
return zOK;
}
enum {
stsNegotiating = progNegotiating,
stsNewFile = progNewFile,
stsSending = progSending,
stsReceiving = progReceiving,
stsEnding = progEnding,
stsEOF = progEOF,
stsDone = progDone,
stsFailed = progFailed,
stsCancelled = progCancelled,
stsSkipped = progSkipped
};
STATIC void
ZProgress (ZMODEM_PRIVATE *pZ, int status)
{
if (pZ->f) {
const char *fileName = NULL;
int fileType = diskFileUnknown;
DiskFileName (pZ->f, &fileName);
ProgressFileName (pZ->progress, fileName);
DiskFileType (pZ->f, &fileType);
ProgressFileType (pZ->progress, fileType);
} else {
ProgressFileName (pZ->progress, NULL);
}
ProgressFileSize (pZ->progress, pZ->fileSize);
ProgressFilePosition (pZ->progress, pZ->receivePosition);
ProgressReport (pZ->progress, status);
}
STATIC int ZSendEncodeBytes
(ZMODEM_PRIVATE *pZ, const BYTE *pBuffer,
unsigned int length) {
BYTE buff[100];
unsigned buffPos;
int buffFree;
if (pZ->debug) {
DebugBegin (pZ->debug, debugPacketLowLevel | debugEncoding);
DebugString (pZ->debug, "ZSendEncodeBytes: encoding ");
DebugUInt (pZ->debug, length);
DebugString (pZ->debug, " bytes: ``");
if (length > 30) {
DebugStringCount (pZ->debug, (const char *) pBuffer, 30);
DebugString (pZ->debug, "...");
} else {
DebugStringCount (pZ->debug, (const char *) pBuffer, length);
DebugString (pZ->debug, "''");
}
DebugEnd (pZ->debug);
}
while (length > 0) {
buffPos = 0;
buffFree = sizeof (buff) - 5;
while ((buffFree > 0) && (length > 0)) {
int c = *pBuffer++;
length--;
if (TestEncode (c)) {
buff[buffPos++] = CAN;
if (c == 0x7F)
buff[buffPos++] = 'l';
else if (c == 0xFF)
buff[buffPos++] = 'm';
else
buff[buffPos++] = c | 0x40;
buffFree -= 2;
} else {
buff[buffPos++] = c;
buffFree--;
}
}
StsRet (ZSendBytes (pZ, buff, buffPos));
}
return zOK;
}
STATIC int ZSendHexBytes
(ZMODEM_PRIVATE *pZ, BYTE *pBuffer, int length) {
BYTE buff[100];
unsigned buffPos;
int buffFree;
static const char digits[] = "0123456789abcdef";
while (length > 0) {
buffPos = 0;
buffFree = sizeof (buff) - 2;
while ((length-- > 0) && (buffFree > 0)) {
int c = *pBuffer++;
buff[buffPos++] = digits[(c >> 4) & 15];
buff[buffPos++] = digits[c & 15];
buffFree -= 2;
}
StsRet (ZSendBytes (pZ, buff, buffPos));
}
return zOK;
}
STATIC BYTE zDecode[256];
STATIC int ZReadDecodeBytes
(ZMODEM_PRIVATE *pZ, int timeout, BYTE *pBuffer, int *pLength) {
BYTE byte;
int sawCAN = FALSE;
int lengthDesired = *pLength;
int canCount = 0;
while (1) {
StsRet (ZReadByteWithTimeout (pZ, timeout, &byte));
if (TestIgnore (byte)) {
} else if (byte == CAN) {
if (sawCAN) {
canCount++;
if (canCount >= 5)
return StsWarn (zFailed);
} else {
canCount = 1;
sawCAN = TRUE;
}
} else if (sawCAN) {
sawCAN = FALSE;
if (TestDecode (byte))
*pBuffer++ = zDecode[byte];
else {
*pLength -= lengthDesired;
return StsWarn (zBadPacket);
}
lengthDesired--;
} else {
*pBuffer++ = byte;
lengthDesired--;
}
if (lengthDesired == 0)
return zOK;
}
}
STATIC int ZReadDecodeHexBytes
(ZMODEM_PRIVATE *pZ, int timeout, BYTE *pBuffer,
int *pLength) {
BYTE byte;
int lengthDesired = *pLength;
int evenOdd = 0;
while (1) {
int digit = -1;
StsRet (ZReadByteWithTimeout (pZ, timeout, &byte));
byte &= 0x7F;
if ((byte >= '0') && (byte <= '9'))
digit = byte - '0';
else if ((byte >= 'a') && (byte <= 'f'))
digit = byte - 'a' + 10;
else if (!TestIgnore (byte))
return StsWarn (zBadPacket);
if (digit >= 0) {
if (evenOdd) {
*pBuffer++ |= digit;
lengthDesired--;
} else
*pBuffer = digit << 4;
evenOdd = !evenOdd;
}
if (lengthDesired == 0)
return zOK;
}
}
STATIC int ZSendAttention
(ZMODEM_PRIVATE *pZ) {
BYTE *pB = pZ->attention;
while (TRUE) {
switch (*pB) {
case 0:
return zOK;
case 0xDD:
ZSendBreak (pZ);
break;
case 0xDE:
ZPause (pZ);
break;
default:
StsRet (ZSendByte (pZ, *pB));
break;
}
pB++;
}
}
STATIC int ZSendCAN
(ZMODEM_PRIVATE *pZ) {
static const BYTE cancel[] =
{CAN, CAN, CAN, CAN, CAN, CAN, CAN, CAN, CAN, CAN, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8};
return ZSendBytes (pZ, cancel, sizeof (cancel) / sizeof (cancel[0]));
}
STATIC int ZSendHexHeader
(ZMODEM_PRIVATE *pZ, int headerType, unsigned long arg) {
BYTE headerStart[] =
{'*', '*', CAN, 'B'};
BYTE headerData[7];
BYTE headerEnd[] =
{CR, LF, XON};
pZ->txPacketType = headerType;
if (pZ->debug) {
DebugBegin (pZ->debug, debugPacket);
DebugString (pZ->debug, "Sending hex header ");
DebugPacket (pZ->debug, headerType, arg);
DebugEnd (pZ->debug);
}
if (headerType == ZCAN)
return ZSendCAN (pZ);
headerData[0] = headerType;
headerData[1] = arg & 0xFF;
headerData[2] = (arg >> 8) & 0xFF;
headerData[3] = (arg >> 16) & 0xFF;
headerData[4] = (arg >> 24) & 0xFF;
{
short crc = ZCrc16 (headerData, 5, 0);
headerData[5] = (crc >> 8) & 0xFF;
headerData[6] = crc & 0xFF;
}
StsRet (ZSendBytes (pZ, headerStart, sizeof (headerStart)));
StsRet (ZSendHexBytes (pZ, headerData, sizeof (headerData)));
if ((headerType == ZACK) || (headerType == ZFIN))
StsRet (ZSendBytes (pZ, headerEnd, 2));
else
StsRet (ZSendBytes (pZ, headerEnd, 3));
StsRet (ZWaitForSentBytes (pZ));
return zOK;
}
STATIC int ZSendHeader
(ZMODEM_PRIVATE *pZ, int headerType, unsigned long arg) {
BYTE headerStart[] =
{'*', CAN, 'A'};
BYTE headerData[9];
unsigned headerLength = 7;
pZ->txPacketType = headerType;
if (pZ->debug) {
DebugBegin (pZ->debug, debugPacket);
DebugString (pZ->debug, "Sending binary header ");
DebugPacket (pZ->debug, headerType, arg);
DebugEnd (pZ->debug);
}
if (headerType == ZCAN)
return ZSendCAN (pZ);
headerData[0] = headerType;
headerData[1] = arg & 0xFF;
headerData[2] = (arg >> 8) & 0xFF;
headerData[3] = (arg >> 16) & 0xFF;
headerData[4] = (arg >> 24) & 0xFF;
if (pZ->crc32) {
unsigned long crc = ZCrc32 (headerData, 5, 0);
headerData[5] = crc & 0xFF;
headerData[6] = (crc >> 8) & 0xFF;
headerData[7] = (crc >> 16) & 0xFF;
headerData[8] = (crc >> 24) & 0xFF;
headerStart[2] = 'C';
headerLength = 9;
pZ->sendingCrc32 = TRUE;
} else {
unsigned short crc = ZCrc16 (headerData, 5, 0);
headerData[5] = (crc >> 8) & 0xFF;
headerData[6] = crc & 0xFF;
pZ->sendingCrc32 = FALSE;
}
StsRet (ZSendBytes (pZ, headerStart, sizeof (headerStart)));
StsRet (ZSendEncodeBytes (pZ, headerData, headerLength));
StsRet (ZWaitForSentBytes (pZ));
return zOK;
}
STATIC int ZReadHeader
(ZMODEM_PRIVATE *pZ, int timeout) {
BYTE pad = 0, sync = 0, headerType = 0;
BYTE packet[15];
int canCount = 0;
int length;
int err;
unsigned long crc;
unsigned long arg;
int noiseCount = 0;
do {
err = ZReadByteWithTimeout (pZ, timeout, &pad);
if ((err != zOK) && (err != zBadPacket))
return err;
if (err == zOK) {
if (noiseCount++ > pZ->noiseLimit)
return StsWarn (zBadPacket);
if (pad == CAN) {
if (++canCount >= 5) {
pZ->rxPacketType = ZCAN;
return StsWarn (zFailed);
}
} else
canCount = 0;
}
} while (pad != '*');
headerType = '*';
do {
pad = sync;
sync = headerType;
StsRet (ZReadByteWithTimeout (pZ, 2, &headerType));
if (noiseCount++ > pZ->noiseLimit)
return StsWarn (zBadPacket);
if (headerType == CAN) {
if (++canCount >= 5) {
pZ->rxPacketType = ZCAN;
return StsWarn (zFail);
}
} else
canCount = 0;
} while ((pad != '*') || (sync != CAN) || ((headerType != 'A')
&& (headerType != 'B') && (headerType != 'C')));
switch (headerType) {
case 'A':
pZ->receivingCrc32 = FALSE;
length = 1 + 4 + 2;
StsRet (ZReadDecodeBytes (pZ, 2, packet, &length));
break;
case 'B':
pZ->receivingCrc32 = FALSE;
length = 1 + 4 + 2;
StsRet (ZReadDecodeHexBytes (pZ, 2, packet, &length));
break;
case 'C':
pZ->receivingCrc32 = TRUE;
length = 1 + 4 + 4;
StsRet (ZReadDecodeBytes (pZ, 2, packet, &length));
break;
}
arg = ((packet[4] * 256L + packet[3]) * 256 + packet[2]) * 256 + packet[1];
if (pZ->debug) {
DebugBegin (pZ->debug, debugPacket);
DebugString (pZ->debug, "Read packet: ");
switch (headerType) {
case 'A':
DebugString (pZ->debug, "Bin16 ");
break;
case 'B':
DebugString (pZ->debug, "Hex16 ");
break;
case 'C':
DebugString (pZ->debug, "Bin32 ");
break;
}
DebugPacket (pZ->debug, packet[0], arg);
if (pZ->receivingCrc32)
crc = ((packet[8] * 256L + packet[7]) * 256 + packet[6]) * 256 + packet[5];
else
crc = (packet[5] * 256 + packet[6]) & 0xFFFF;
DebugString (pZ->debug, " crc:");
DebugIntHex (pZ->debug, crc);
DebugEnd (pZ->debug);
}
if (pZ->receivingCrc32) {
crc = ((packet[8] * 256L + packet[7]) * 256 + packet[6]) * 256 + packet[5];
if (crc != ZCrc32 (packet, 5, 0)) {
DebugBegin (pZ->debug, debugPacketLowLevel | debugPacketErr);
DebugString (pZ->debug, "Computed CRC: ");
DebugIntHex (pZ->debug, ZCrc32 (packet, 5, 0));
DebugEnd (pZ->debug);
return StsWarn (zBadPacket);
}
} else {
crc = (packet[5] * 256 + packet[6]) & 0xFFFF;
if (crc != ZCrc16 (packet, 5, 0)) {
DebugBegin (pZ->debug, debugPacketLowLevel | debugPacketErr);
DebugString (pZ->debug, "Computed CRC: ");
DebugIntHex (pZ->debug, ZCrc16 (packet, 5, 0));
DebugEnd (pZ->debug);
return StsWarn (zBadPacket);
}
}
pZ->rxPacketType = packet[0];
pZ->rxPacketArg = arg;
if (pZ->rxPacketType == ZABORT)
return zFail;
return zOK;
}
STATIC int ZSendCrcEscape
(ZMODEM_PRIVATE *pZ, unsigned long crc,
int packetEnd, int needAck) {
unsigned char crcBuff[4];
BYTE crcEscape;
if (packetEnd)
pZ->txPacketType = -1;
if (needAck) {
if (packetEnd)
crcEscape = 'k';
else
crcEscape = 'j';
} else {
if (packetEnd)
crcEscape = 'h';
else
crcEscape = 'i';
}
StsRet (ZSendByte (pZ, CAN));
StsRet (ZSendByte (pZ, crcEscape));
if (pZ->sendingCrc32) {
crc = ZCrc32 (&crcEscape, 1, crc);
crcBuff[0] = crc & 0xFF;
crcBuff[1] = (crc >> 8) & 0xFF;
crcBuff[2] = (crc >> 16) & 0xFF;
crcBuff[3] = (crc >> 24) & 0xFF;
StsRet (ZSendEncodeBytes (pZ, crcBuff, 4));
} else {
crc = ZCrc16 (&crcEscape, 1, crc);
crcBuff[0] = (crc >> 8) & 0xFF;
crcBuff[1] = crc & 0xFF;
StsRet (ZSendEncodeBytes (pZ, crcBuff, 2));
}
return StsWarn (ZWaitForSentBytes (pZ));
}
STATIC int ZReceivePacketData
(ZMODEM_PRIVATE *pZ, BYTE *pBuffer, unsigned int *pLength) {
BYTE byte;
BYTE *pB = pBuffer;
int sawCAN = FALSE;
int canCount = 0;
*pLength = 0;
while (1) {
StsRet (ZReadByteWithTimeout (pZ, pZ->timeout, &byte));
if (TestIgnore (byte)) {
} else if (byte == CAN) {
if (sawCAN) {
canCount++;
if (canCount >= 5)
return StsWarn (zFailed);
} else {
canCount = 1;
sawCAN = TRUE;
}
} else if (sawCAN) {
sawCAN = FALSE;
if (TestDecode (byte))
*pB++ = zDecode[byte];
else
break;
(*pLength)++;
} else {
*pB++ = byte;
sawCAN = FALSE;
(*pLength)++;
}
if (*pLength > 1024)
return StsWarn (zBadPacket);
}
switch (byte) {
case 'h':
case 'i':
case 'j':
if (pZ->debug) {
DebugBegin (pZ->debug, debugEncoding | debugWarn);
DebugString (pZ->debug, "Non-conforming CRC escape: CAN ");
DebugChar (pZ->debug, byte);
DebugEnd (pZ->debug);
}
case 'k':
break;
default:
if (pZ->debug) {
DebugBegin (pZ->debug, debugEncoding | debugWarn);
DebugString (pZ->debug, "Illegal CAN sequence: CAN ");
DebugChar (pZ->debug, byte);
DebugEnd (pZ->debug);
}
return StsWarn (zBadPacket);
}
{
unsigned long crc, txCrc;
if (pZ->receivingCrc32) {
crc = ZCrc32 (pBuffer, *pLength, 0);
crc = ZCrc32 (&byte, 1, crc);
} else {
crc = ZCrc16 (pBuffer, *pLength, 0);
crc = ZCrc16 (&byte, 1, crc);
}
{
BYTE crcBuff[4];
int crcLength;
if (pZ->receivingCrc32)
crcLength = 4;
else
crcLength = 2;
StsRet (ZReadDecodeBytes (pZ, pZ->timeout, crcBuff, &crcLength));
if (pZ->receivingCrc32)
txCrc = ((crcBuff[3] * 256L + crcBuff[2]) * 256
+ crcBuff[1]) * 256 + crcBuff[0];
else
txCrc = crcBuff[0] * 256 + crcBuff[1];
}
if (crc != txCrc)
return StsWarn (zBadPacket);
}
if (pZ->debug) {
DebugBegin (pZ->debug, debugPacket);
DebugString (pZ->debug, "Received data following packet: ");
DebugUInt (pZ->debug, *pLength);
DebugString (pZ->debug, " bytes");
DebugEnd (pZ->debug);
}
return zOK;
}
STATIC int ZReceiveStream
(ZMODEM_PRIVATE *pZ, BYTE *buff) {
BYTE *pBuff = buff;
unsigned length = 0;
int packetEnd, needAck;
BYTE byte;
int byteDecoded;
int sawCAN = FALSE;
int canCount = 0;
while (length < 1025) {
StsRet (ZReadByteWithTimeout (pZ, pZ->timeout, &byte));
byteDecoded = -1;
if (TestIgnore (byte)) {
} else if (byte == CAN) {
if (sawCAN) {
canCount++;
if (canCount >= 5)
return zFailed;
} else {
canCount = 1;
sawCAN = TRUE;
}
} else if (sawCAN) {
sawCAN = FALSE;
if (TestDecode (byte))
byteDecoded = zDecode[byte];
else {
{
unsigned long crc, txCrc;
switch (byte) {
case 'h':
packetEnd = TRUE;
needAck = FALSE;
break;
case 'i':
packetEnd = FALSE;
needAck = FALSE;
break;
case 'j':
packetEnd = FALSE;
needAck = TRUE;
break;
case 'k':
packetEnd = TRUE;
needAck = TRUE;
break;
default:
if (pZ->debug) {
DebugBegin (pZ->debug, debugEncoding | debugWarn);
DebugString (pZ->debug, "Illegal CAN sequence: CAN ");
DebugChar (pZ->debug, byte);
DebugEnd (pZ->debug);
}
return StsWarn (zBadPacket);
}
if (pZ->receivingCrc32) {
crc = ZCrc32 (buff, length, 0);
crc = ZCrc32 (&byte, 1, crc);
} else {
crc = ZCrc16 (buff, length, 0);
crc = ZCrc16 (&byte, 1, crc);
}
{
BYTE crcBuff[4];
int crcLength;
if (pZ->receivingCrc32)
crcLength = 4;
else
crcLength = 2;
StsRet (ZReadDecodeBytes (pZ, pZ->timeout, crcBuff, &crcLength));
if (pZ->receivingCrc32)
txCrc = ((crcBuff[3] * 256L + crcBuff[2]) * 256
+ crcBuff[1]) * 256 + crcBuff[0];
else
txCrc = crcBuff[0] * 256 + crcBuff[1];
}
if (crc != txCrc) {
if (pZ->debug) {
DebugBegin (pZ->debug, debugPacketLowLevel | debugPacketErr);
DebugString (pZ->debug, "Erroneous data: ");
DebugStringCount (pZ->debug, (const char *) buff, length);
DebugEnd (pZ->debug);
DebugBegin (pZ->debug, debugPacketLowLevel | debugPacketErr);
DebugString (pZ->debug, "terminator: ");
DebugChar (pZ->debug, byte);
DebugString (pZ->debug, "length of data: ");
DebugUInt (pZ->debug, length);
DebugString (pZ->debug, ", CRC received: ");
DebugIntHex (pZ->debug, txCrc);
DebugString (pZ->debug, ", CRC calculated: ");
DebugIntHex (pZ->debug, crc);
DebugEnd (pZ->debug);
}
return StsWarn (zBadPacket);
}
}
if (pZ->sendPosition + length > pZ->receivePosition) {
BYTE *pDataBegin = buff + pZ->receivePosition - pZ->sendPosition;
unsigned long dataLength = length - pZ->receivePosition + pZ->sendPosition;
pZ->receivePosition += dataLength;
#if I_CAN_OVERLAP_DISK
if (needAck)
ZSendHexHeader (pZ, ZACK, pZ->receivePosition);
StsRet (ZFileWrite (pZ, pDataBegin, dataLength));
#else
StsRet (ZFileWrite (pZ, pDataBegin, dataLength));
if (needAck)
ZSendHexHeader (pZ, ZACK, pZ->receivePosition);
#endif
}
pZ->sendPosition += length;
ZProgress (pZ, stsReceiving);
if (packetEnd)
return zOK;
length = 0;
pBuff = buff;
}
} else {
byteDecoded = byte;
sawCAN = FALSE;
}
if (byteDecoded >= 0) {
*pBuff++ = byteDecoded;
length++;
}
}
if (pZ->debug) {
DebugBegin (pZ->debug, debugPacketErr | debugWarn);
DebugString (pZ->debug, "Data CRC not seen, buffer overflow");
DebugEnd (pZ->debug);
}
return StsWarn (zBadPacket);
}
typedef struct {
int atEOF;
BYTE *data;
unsigned long size;
unsigned long startFilePos;
unsigned long endFilePos;
BYTE *pStart;
BYTE *pEnd;
} WINDOW;
STATIC int ZInitWindow
(ZMODEM_PRIVATE *pZ, WINDOW * pWindow, long size, long startPos) {
int err;
pWindow->startFilePos = startPos;
pWindow->endFilePos = startPos;
pWindow->atEOF = FALSE;
pWindow->data = NULL;
err = ZFileReadSkip (pZ, startPos);
if (err == zEOF) {
pWindow->atEOF = TRUE;
return zOK;
} else
StsRet (err);
while ((pWindow->data == NULL) && (size > 256)) {
pWindow->size = size;
pWindow->data = malloc (pWindow->size);
size /= 2;
pWindow->pStart = pWindow->data;
pWindow->pEnd = pWindow->data;
}
if (pWindow->data == NULL)
return zFail;
else
return zOK;
}
STATIC int ZSendFillWindow
(ZMODEM_PRIVATE *pZ, WINDOW * pWindow, long readLimit) {
int err = zOK;
if (pZ->debug) {
DebugBegin (pZ->debug, debugCache);
DebugString (pZ->debug, "Filling window: readLimit = ");
DebugUInt (pZ->debug, readLimit);
DebugEnd (pZ->debug);
DebugBegin (pZ->debug, debugCache);
DebugString (pZ->debug, "Window: startFP: ");
DebugUInt (pZ->debug, pWindow->startFilePos);
DebugString (pZ->debug, " endFP: ");
DebugUInt (pZ->debug, pWindow->endFilePos);
DebugString (pZ->debug, " start: ");
DebugPtr (pZ->debug, pWindow->pStart);
DebugString (pZ->debug, " end: ");
DebugPtr (pZ->debug, pWindow->pEnd);
if (pWindow->atEOF)
DebugString (pZ->debug, " (atEOF)");
DebugEnd (pZ->debug);
}
if ((pWindow->endFilePos - pWindow->startFilePos) >= pWindow->size)
return zOK;
if (pWindow->atEOF)
return zEOF;
if (pWindow->pStart <= pWindow->pEnd) {
unsigned long readLength = pWindow->size - (pWindow->pEnd - pWindow->data);
if (pZ->debug) {
DebugBegin (pZ->debug, debugCache);
DebugString (pZ->debug, "Adjusting read: target Length: ");
DebugUInt (pZ->debug, readLength);
DebugString (pZ->debug, " limit: ");
DebugUInt (pZ->debug, readLimit);
DebugEnd (pZ->debug);
}
if (readLength > readLimit)
readLength = readLimit;
if (readLength > 0) {
err = ZFileRead (pZ, pWindow->pEnd, &readLength);
if (err == zOK) {
pWindow->endFilePos += readLength;
pWindow->pEnd += readLength;
readLimit -= readLength;
if ((pWindow->pEnd - pWindow->data) >= pWindow->size)
pWindow->pEnd = pWindow->data;
}
}
}
if ((err == zOK) && (pWindow->pEnd < pWindow->pStart)) {
unsigned long readLength = pWindow->pStart - pWindow->pEnd;
if (readLength > readLimit)
readLength = readLimit;
if (readLength > 0) {
err = ZFileRead (pZ, pWindow->pEnd, &readLength);
if (err == zOK) {
pWindow->endFilePos += readLength;
pWindow->pEnd += readLength;
}
}
}
if (err == zEOF)
pWindow->atEOF = TRUE;
return StsWarn (err);
}
STATIC int ZSendFileDataPacket
(ZMODEM_PRIVATE *pZ, WINDOW * pWindow,
unsigned size, int endOfPacket, int needAck) {
unsigned long crc = 0L;
unsigned packetLength = size;
BYTE *packetStart;
if (pZ->txPacketType != ZDATA)
StsRet (ZSendHeader (pZ, ZDATA, pZ->sendPosition));
packetStart = pWindow->pStart + (pZ->sendPosition - pWindow->startFilePos);
if ((packetStart - pWindow->data) >= pWindow->size)
packetStart -= pWindow->size;
if ((pZ->sendPosition + packetLength) > pWindow->endFilePos)
packetLength = pWindow->endFilePos - pZ->sendPosition;
if ((packetStart - pWindow->data + packetLength) >= pWindow->size)
packetLength = pWindow->data + pWindow->size - packetStart;
if (packetLength > 0) {
StsRet (ZSendEncodeBytes (pZ, packetStart, packetLength));
crc = SendingCrc (packetStart, packetLength, 0);
}
StsRet (ZSendCrcEscape (pZ, crc, endOfPacket, needAck));
if (pZ->debug) {
DebugBegin (pZ->debug, debugPacketLowLevel);
DebugString (pZ->debug, "Sent file data: ");
DebugUInt (pZ->debug, packetLength);
DebugString (pZ->debug, " bytes starting at ");
DebugIntHex (pZ->debug, pZ->sendPosition);
if (endOfPacket)
DebugString (pZ->debug, " (packetEnd)");
if (needAck)
DebugString (pZ->debug, " (needAck)");
DebugEnd (pZ->debug);
}
pZ->sendPosition += packetLength;
return zOK;
}
STATIC int ZSendFileData
(ZMODEM_PRIVATE *pZ, long startPos) {
int err = zTimeout;
long refillInterval = 4096;
WINDOW window;
int retries = pZ->retries;
unsigned crcInterval = 1024;
unsigned long ackInterval = 8192;
unsigned long lastAck = 0;
unsigned long burstLength = 0;
unsigned long lastBlock = 0;
unsigned long windowSize = 0;
int block = FALSE;
int blocked = FALSE;
long lastReposition = 0;
int repositionCount = 0;
StsRet (ZInitWindow (pZ, &window, DEFAULT_WINDOW_SIZE, startPos));
pZ->sendPosition = startPos;
pZ->receivePosition = startPos;
windowSize = window.size;
ackInterval = ZFileSize (pZ) / 100;
if (ackInterval < ACK_INTERVAL_MIN)
ackInterval = ACK_INTERVAL_MIN;
if (ackInterval > ACK_INTERVAL_MAX)
ackInterval = ACK_INTERVAL_MAX;
burstLength = pZ->receiverFlags & 0xFFFF;
if (HasLimits (pZ->receiverFlags) || !I_CAN_SAMPLE) {
if (burstLength == 0)
burstLength = HALF_DUPLEX_BURST;
ackInterval = burstLength * 2;
}
crcInterval = 1024;
if (crcInterval > ackInterval)
crcInterval = ackInterval;
while (TRUE) {
do {
if (pZ->debug) {
if (block || blocked) {
DebugBegin (pZ->debug, debugPacket);
DebugString (pZ->debug, blocked ? "Window blocked"
: "Window set to block");
DebugEnd (pZ->debug);
}
}
err = StsWarn (ZReadHeader (pZ, blocked ? pZ->timeout : block ? 2 : 0));
switch (err) {
case zTimeout:
if (blocked)
retries--;
break;
case zBadPacket:
block = TRUE;
if (blocked)
retries--;
break;
case zOK:
retries = pZ->retries;
break;
default:
if (window.data)
free (window.data);
return StsWarn (err);
}
if (retries <= 0) {
if (window.data)
free (window.data);
return StsWarn (zFail);
}
if (err == zOK) {
switch (pZ->rxPacketType) {
case ZRPOS:
if ((pZ->rxPacketArg >= pZ->receivePosition) &&
(pZ->rxPacketArg <= window.endFilePos)) {
pZ->receivePosition = pZ->rxPacketArg;
lastBlock -= (pZ->sendPosition - pZ->rxPacketArg);
CloseDataPacket (pZ);
pZ->sendPosition = pZ->rxPacketArg;
if (pZ->sendPosition == lastReposition)
repositionCount++;
else
repositionCount = 1;
lastReposition = pZ->sendPosition;
if (repositionCount > 4) {
if (crcInterval > 32) {
crcInterval /= 2;
repositionCount = 0;
} else if (repositionCount > pZ->retries) {
if (window.data)
free (window.data);
return StsWarn (zFail);
}
}
block = TRUE;
blocked = FALSE;
} else {
block = TRUE;
blocked = FALSE;
DebugBegin (pZ->debug, debugWarn);
DebugString (pZ->debug, "Bogus ZRPOS");
DebugEnd (pZ->debug);
}
break;
case ZACK:
if ((pZ->rxPacketArg >= pZ->receivePosition)
&& (pZ->rxPacketArg <= window.endFilePos)) {
pZ->receivePosition = pZ->rxPacketArg;
if (pZ->receivePosition == pZ->sendPosition) {
if (blocked)
lastBlock = pZ->sendPosition;
block = blocked = FALSE;
}
if (repositionCount-- < -4) {
crcInterval *= 2;
repositionCount = 0;
}
} else {
block = TRUE;
blocked = FALSE;
DebugBegin (pZ->debug, debugWarn);
DebugString (pZ->debug, "Bogus ZACK");
DebugEnd (pZ->debug);
}
break;
case ZRINIT:
ZParseZRINIT (pZ, pZ->rxPacketArg);
if (window.atEOF
&& (pZ->sendPosition >= window.endFilePos)) {
pZ->receivePosition = pZ->sendPosition;
ZProgress (pZ, stsSending);
if (window.data)
free (window.data);
return zOK;
} else {
block = TRUE;
blocked = FALSE;
DebugBegin (pZ->debug, debugWarn);
DebugString (pZ->debug, "Bogus ZRINIT");
DebugEnd (pZ->debug);
}
break;
case ZNAK:
CloseDataPacket (pZ);
pZ->sendPosition = pZ->receivePosition;
block = TRUE;
blocked = FALSE;
break;
default:
block = TRUE;
blocked = FALSE;
break;
}
ZProgress (pZ, stsSending);
}
if (crcInterval > 1024)
crcInterval = 1024;
if (crcInterval > ackInterval)
crcInterval = ackInterval;
if ((burstLength > 0) && (crcInterval > burstLength / 4))
crcInterval = burstLength / 4;
if (pZ->sendPosition - pZ->receivePosition >= windowSize)
block = blocked = TRUE;
if ((burstLength > 0)
&& (pZ->sendPosition + crcInterval > lastBlock + burstLength))
block = blocked = TRUE;
} while ((err == zOK) || (blocked));
if ((!window.atEOF)
&& (pZ->sendPosition + 1500 > window.endFilePos)
&& (BufferFree >= refillInterval)) {
window.pStart += (pZ->receivePosition - window.startFilePos);
if ((window.pStart - window.data) > window.size)
window.pStart -= window.size;
window.startFilePos = pZ->receivePosition;
err = ZSendFillWindow (pZ, &window, refillInterval);
if ((err != zEOF) && (err != zOK)) {
if (window.data)
free (window.data);
return StsWarn (err);
}
}
if (window.atEOF && (pZ->sendPosition + crcInterval >= window.endFilePos)) {
while (pZ->sendPosition < window.endFilePos)
StsRet (ZSendFileDataPacket (pZ, &window, crcInterval, TRUE, FALSE));
if (pZ->txPacketType == ZDATA)
StsRet (ZSendCrcEscape (pZ, 0, TRUE, FALSE));
StsRet (ZSendHeader (pZ, ZEOF, window.endFilePos));
block = TRUE;
} else {
if (pZ->sendPosition + crcInterval - lastAck >= ackInterval) {
StsRet (ZSendFileDataPacket (pZ, &window, crcInterval, block, TRUE));
lastAck = pZ->sendPosition;
} else {
StsRet (ZSendFileDataPacket (pZ, &window, crcInterval, block, block));
if (block)
lastAck = pZ->sendPosition;
}
}
blocked = block;
}
}
STATIC int ZSendGetZRINIT
(ZMODEM_PRIVATE *pZ) {
int timeout = 0;
int retries = pZ->retries;
int err;
do {
err = ZReadHeader (pZ, timeout);
timeout = pZ->timeout;
switch (err) {
case zOK:
if (pZ->rxPacketType == ZRINIT) {
ZParseZRINIT (pZ, pZ->rxPacketArg);
break;
} else
err = zBadPacket;
case zTimeout:
case zBadPacket:
StsRet (ZSendHexHeader (pZ, ZRQINIT, pZ->myZrqinitFlags));
if (retries-- <= 0)
return StsWarn (zFailed);
break;
default:
return StsWarn (err);
}
} while (err != zOK);
return StsWarn (err);
}
STATIC int ZSendZSINIT
(ZMODEM_PRIVATE *pZ) {
int retries = pZ->retries;
int err;
if ((pZ->mySenderFlags == 0) && (ATTENTION == NULL))
return zOK;
do {
StsRet (ZSendHeader (pZ, ZSINIT, pZ->mySenderFlags));
#ifdef ATTENTION
{
unsigned long crc;
StsRet (ZSendEncodeBytes (pZ, ATTENTION, strlen (ATTENTION)));
crc = SendingCrc (ATTENTION, strlen (ATTENTION), 0);
StsRet (ZSendCrcEscape (pZ, crc, TRUE, TRUE));
}
#else
StsRet (ZSendCrcEscape (pZ, 0, TRUE, TRUE));
#endif
err = ZReadHeader (pZ, pZ->timeout);
switch (err) {
case zOK:
if (pZ->rxPacketType == ZACK)
break;
else
err = zBadPacket;
case zTimeout:
case zBadPacket:
if (retries-- <= 0)
return StsWarn (zFail);
break;
default:
return StsWarn (err);
}
} while (err != zOK);
return StsWarn (err);
}
STATIC int ZSendEndSession
(ZMODEM_PRIVATE *pZ) {
int retries = pZ->retries;
int err;
do {
StsRet (ZSendHexHeader (pZ, ZFIN, 0));
err = ZReadHeader (pZ, pZ->timeout);
switch (err) {
case zOK:
if (pZ->rxPacketType == ZFIN)
break;
else
err = zBadPacket;
case zTimeout:
case zBadPacket:
if (retries-- < 0)
return StsWarn (zOK);
break;
default:
return StsWarn (zOK);
}
} while (err != zOK);
ZSendBytes (pZ, (const BYTE *) "OO", 2);
return zOK;
}
STATIC int ZSendZFile
(ZMODEM_PRIVATE *pZ) {
const char *fileName = NULL;
long fileSize = -1;
int fileType = diskFileUnknown;
long fileMode = -1;
struct tm fileDate;
BYTE data[1024];
unsigned length = 128;
unsigned long options = pZ->fileFlags;
char *p = (char *) data;
if (pZ->f) {
DiskFileName (pZ->f, &fileName);
fileSize = pZ->fileSize;
DiskFileType (pZ->f, &fileType);
DiskFileMode (pZ->f, &fileMode);
DiskFileDate (pZ->f, &fileDate);
}
if ((options & CONV_MASK) == 0)
if ((fileType == diskFileBinary) || (fileType == diskFileUnknown))
if (pZ->crashRecovery)
options |= CONV_RESUME;
else
options |= CONV_BINARY;
else
options |= CONV_TEXT;
StsRet (ZSendHeader (pZ, ZFILE, options));
memset (data, 0, sizeof (data));
if (fileName && fileName[0]) {
strcpy (p, fileName);
p += strlen (p) + 1;
if (fileSize >= 0) {
sprintf (p, "%ld", fileSize);
p += strlen (p);
sprintf (p, " %lo", ZTime (&(fileDate)));
p += strlen (p);
if (fileMode >= 0) {
sprintf (p, " %lo", fileMode);
p += strlen (p);
}
}
}
length = p - (char *) data;
StsRet (ZSendEncodeBytes (pZ, data, length));
{
unsigned long crc = SendingCrc (data, length, 0);
return StsWarn (ZSendCrcEscape (pZ, crc, TRUE, TRUE));
}
}
STATIC int ZSendFile
(ZMODEM_PRIVATE *pZ) {
int err = zOK;
long startPosition = 0;
ZProgress (pZ, stsNewFile);
do {
StsRet (ZSendZFile (pZ));
err = ZReadHeader (pZ, pZ->timeout * 5);
if (err == zOK) {
switch (pZ->rxPacketType) {
case ZSKIP:
ZProgress (pZ, stsSkipped);
return zOK;
case ZRPOS:
startPosition = pZ->rxPacketArg;
break;
case ZCRC:
break;
case ZRINIT:
ZParseZRINIT (pZ, pZ->rxPacketArg);
break;
case ZNAK:
break;
default:
break;
}
} else if ((err != zTimeout) && (err != zBadPacket))
return StsWarn (err);
} while ((err != zOK)
|| ((pZ->rxPacketType != ZRPOS) && (pZ->rxPacketType != ZCRC)));
if (pZ->rxPacketType == ZCRC) {
unsigned long crc;
err = ZFileCRC (pZ, pZ->rxPacketArg, &crc);
if (err == zFail)
crc = 0;
do {
StsRet (ZSendHexHeader (pZ, ZCRC, crc));
err = ZReadHeader (pZ, pZ->timeout * 5);
if (err == zOK) {
switch (pZ->rxPacketType) {
case ZSKIP:
return zOK;
case ZRPOS:
startPosition = pZ->rxPacketArg;
break;
case ZCRC:
break;
case ZNAK:
break;
default:
break;
}
} else if ((err != zTimeout) && (err != zBadPacket))
return StsWarn (err);
} while ((err != zOK) || (pZ->rxPacketType != ZRPOS));
}
ZProgress (pZ, stsSending);
StsRet (ZSendFileData (pZ, startPosition));
ZProgress (pZ, stsEOF);
return StsWarn (err);
}
STATIC int ZReceiveFile
(ZMODEM_PRIVATE *pZ, BYTE *buff,
unsigned fileInfoLength) {
int err = zOK;
unsigned length;
int repositionCount;
unsigned long lastReposition;
ZNewFile (pZ);
pZ->receivePosition = 0;
if (pZ->debug) {
char *p = (char *) buff;
DebugBegin (pZ->debug, debugPacket);
DebugString (pZ->debug, "Read ZFILE Data: options: ");
DebugIntHex (pZ->debug, pZ->fileFlags);
DebugString (pZ->debug, " filename: ``");
DebugString (pZ->debug, p);
DebugString (pZ->debug, "'' File attributes: ");
DebugString (pZ->debug, p + strlen (p) + 1);
DebugEnd (pZ->debug);
}
err = StsWarn (ZFileWriteOpen (pZ, buff, fileInfoLength));
if (err == zSkip) {
ZProgress (pZ, stsSkipped);
ZSendHexHeader (pZ, ZSKIP, 0);
return zOK;
}
if (err != zOK) {
StsWarn (ZSendHexHeader (pZ, ZFERR, 0));
return zOK;
}
StsRet (ZSendHexHeader (pZ, ZRPOS, pZ->receivePosition));
ZProgress (pZ, stsNewFile);
lastReposition = pZ->receivePosition;
repositionCount = 0;
while (1) {
err = StsWarn (ZReadHeader (pZ, pZ->timeout));
if ((err == zTimeout) || (err == zBadPacket)) {
ZSendAttention (pZ);
ZGobble (pZ, 0);
ZSendHexHeader (pZ, ZRPOS, pZ->receivePosition);
if (pZ->receivePosition == lastReposition)
repositionCount++;
else {
lastReposition = pZ->receivePosition;
repositionCount = 1;
}
} else if (err != zOK) {
return StsWarn (err);
} else {
switch (pZ->rxPacketType) {
case ZFILE:
length = 1024;
StsWarn (ZReceivePacketData (pZ, buff, &length));
ZSendHexHeader (pZ, ZRPOS, pZ->receivePosition);
break;
case ZEOF:
if (pZ->rxPacketArg == pZ->receivePosition) {
ZProgress (pZ, stsEOF);
StsRet (ZFileWriteClose (pZ));
ZSendHexHeader (pZ, ZRINIT, pZ->myReceiverFlags);
return zOK;
} else {
ZSendHexHeader (pZ, ZRPOS, pZ->receivePosition);
if (pZ->receivePosition == lastReposition)
repositionCount++;
else {
lastReposition = pZ->receivePosition;
repositionCount = 1;
}
}
break;
case ZDATA:
pZ->sendPosition = pZ->rxPacketArg;
err = StsWarn (ZReceiveStream (pZ, buff));
if (err == zOK)
break;
if ((err != zBadPacket) && (err != zTimeout))
return StsWarn (err);
ZSendAttention (pZ);
default:
ZGobble (pZ, 0);
ZSendHexHeader (pZ, ZRPOS, pZ->receivePosition);
if (pZ->receivePosition == lastReposition)
repositionCount++;
else {
lastReposition = pZ->receivePosition;
repositionCount = 1;
}
break;
}
}
if (repositionCount > 2 * pZ->retries) {
if (pZ->debug) {
DebugBegin (pZ->debug, debugWarn);
DebugString (pZ->debug, "No progress, terminating transfer...");
DebugEnd (pZ->debug);
}
return StsWarn (zFail);
}
}
}
STATIC int ZSendFiles
(ZMODEM_PRIVATE *pZ) {
int err = zOK;
ZNewFile (pZ);
ZProgress (pZ, stsNegotiating);
ZSendBytes (pZ, (const BYTE *) "rz\r", 3);
err = ZSendGetZRINIT (pZ);
if (err == zOK)
err = ZSendZSINIT (pZ);
while (err == zOK) {
err = ZFileReadOpenNext (pZ, pZ->fileType);
if (err == zOK) {
err = ZSendFile (pZ);
ZFileReadClose (pZ);
ZNewFile (pZ);
}
}
ZProgress (pZ, stsEnding);
if (err == zEndOfSession)
err = ZSendEndSession (pZ);
if (err == zFail) {
ZSendHeader (pZ, ZCAN, 0);
ZGobble (pZ, 2);
err = zFailed;
}
if (err == zOK)
ZProgress (pZ, stsDone);
else if (pZ->userCancel)
ZProgress (pZ, stsCancelled);
else
ZProgress (pZ, stsFailed);
return StsWarn (err);
}
STATIC int ZReceive
(ZMODEM_PRIVATE *pZ) {
BYTE buff[1200];
int retries = pZ->retries;
int err;
err = ZSendZRINIT (pZ);
while (err == zOK) {
ZProgress (pZ, stsNegotiating);
err = ZReadHeader (pZ, pZ->timeout);
if ((err == zTimeout) || (err == zBadPacket)) {
retries--;
if (retries == 0)
err = zFail;
else
err = ZSendZRINIT (pZ);
} else if (err == zOK) {
retries = pZ->retries;
switch (pZ->rxPacketType) {
case ZRQINIT:
err = ZSendZRINIT (pZ);
break;
case ZRINIT:
err = ZGobble (pZ, 2);
break;
case ZSINIT:
ZParseZSINIT (pZ, pZ->rxPacketArg);
err = ZSendHexHeader (pZ, ZACK, 0);
break;
case ZFILE:
pZ->fileFlags = pZ->rxPacketArg;
{
unsigned length;
err = ZReceivePacketData (pZ, buff, &length);
if (err == zOK)
err = ZReceiveFile (pZ, buff, length);
else
err = ZSendZRINIT (pZ);
}
break;
case ZEOF:
err = ZSendZRINIT (pZ);
break;
case ZFREECNT:
{
unsigned long freeCount = 0;
StsRet (ZFileSystemFree (pZ, &freeCount));
err = ZSendHexHeader (pZ, ZACK, freeCount);
}
break;
case ZCOMMAND:
{
unsigned length;
unsigned completion = 0;
err = ZReceivePacketData (pZ, buff, &length);
if (err == zOK) {
char *command = (char *) buff;
command[length] = 0;
{
if (pZ->rxPacketArg & (0x01000000)) {
if (pZ->debug) {
DebugBegin (pZ->debug, debugPacket);
DebugString (pZ->debug, "Immediate command: ");
DebugString (pZ->debug, command);
DebugEnd (pZ->debug);
}
} else {
if (pZ->debug) {
DebugBegin (pZ->debug, debugPacket);
DebugString (pZ->debug, "Normal command: ");
DebugString (pZ->debug, command);
DebugEnd (pZ->debug);
}
if (command[0] == '!') {
completion = system (command + 1);
} else {
if ((command[0] == 's') && (command[1] == 'z') && (command[2] == ' ')) {
char *p = command + 2;
char *names[32];
int numberNames = 0;
while (*p) {
while (IsWhitespace (*p))
p++;
if (*p)
names[numberNames++] = p;
while (*p && !IsWhitespace (*p))
p++;
if (*p)
*p++ = 0;
}
err = ZModemSend ((ZMODEM) pZ, (const char **) names, numberNames);
if (err)
completion = 1;
else
completion = 0;
} else {
completion = 1;
}
}
}
}
} else if ((err == zTimeout) || (err == zBadPacket)) {
err = ZSendHexHeader (pZ, ZNAK, 0);
break;
} else
return StsWarn (err);
ZGobble (pZ, 0);
do {
StsRet (ZSendHexHeader (pZ, ZCOMPL, completion));
err = ZReadHeader (pZ, pZ->timeout);
if ((err != zOK) && (err != zBadPacket) && (err != zTimeout))
return StsWarn (err);
} while ((err != zOK) || (pZ->rxPacketType != ZFIN));
}
case ZFIN:
err = ZSendHexHeader (pZ, ZFIN, 0);
{
BYTE overAndOut;
int oCount = 0;
while (err == zOK) {
err = ZReadByteWithTimeout (pZ, pZ->timeout,
&overAndOut);
if (err == zTimeout)
err = zEndOfSession;
else if (err == zOK) {
if (overAndOut == 'O') {
if (++oCount >= 2)
err = zEndOfSession;
} else if (overAndOut == '*')
break;
else
oCount = 0;
} else if (err == zBadPacket) {
err = zOK;
} else
return StsWarn (err);
}
}
break;
case ZCAN:
err = zFailed;
break;
case ZABORT:
err = zFail;
break;
default:
err = ZSendHexHeader (pZ, ZNAK, 0);
break;
}
}
}
if (err == zEndOfSession)
err = zOK;
if (err == zFail) {
ZSendHeader (pZ, ZCAN, 0);
ZGobble (pZ, 2);
err = zFailed;
}
if (err == zOK)
ZProgress (pZ, stsDone);
else if (pZ->userCancel)
ZProgress (pZ, stsCancelled);
else
ZProgress (pZ, stsFailed);
return StsWarn (err);
}
STATIC int ZSendZCommand
(ZMODEM_PRIVATE *pZ, int immediate, const char *cmd) {
int err;
int retries = pZ->retries;
size_t cmdLength = strlen (cmd) + 1;
unsigned long crc = SendingCrc ((const BYTE *) cmd, cmdLength, 0);
do {
StsRet (ZSendHeader (pZ, ZCOMMAND, (immediate) ? 1U : 0U));
StsRet (ZSendEncodeBytes (pZ, (const BYTE *) cmd, cmdLength));
StsRet (ZSendCrcEscape (pZ, crc, TRUE, TRUE));
err = ZReadHeader (pZ, (immediate) ? (pZ->timeout) : (pZ->timeout * 5));
if ((err == zTimeout) || (err == zBadPacket)) {
retries--;
if (retries == 0)
return StsWarn (zFail);
} else if (err != zOK)
return StsWarn (err);
else {
retries = pZ->retries;
switch (pZ->rxPacketType) {
case ZCOMPL:
return zEndOfSession;
case ZRINIT:
break;
case ZNAK:
break;
case ZRQINIT:
if ((pZ->rxPacketArg >> 24) & 0xFF == ZCOMMAND) {
StsRet (ZSendHeader (pZ, ZNAK, 0));
} else {
int packetType = pZ->rxPacketType;
int packetArg = pZ->rxPacketArg;
err = ZReceive (pZ);
pZ->rxPacketType = packetType;
pZ->rxPacketArg = packetArg;
if (err != zOK)
return StsWarn (err);
ZProgress (pZ, stsEnding);
}
break;
default:
if (pZ->debug) {
DebugBegin (pZ->debug, debugWarn);
DebugString (pZ->debug, "Unexpected response to ZCOMMAND :");
DebugPacket (pZ->debug, pZ->rxPacketType, pZ->rxPacketArg);
DebugEnd (pZ->debug);
}
break;
}
}
} while ((err != zOK) || (pZ->rxPacketType != ZRQINIT));
while (TRUE) {
err = ZReadHeader (pZ, (immediate) ? (pZ->timeout) : (pZ->timeout * 5));
if ((err == zTimeout) || (err == zBadPacket)) {
retries--;
if (retries == 0)
return StsWarn (zFail);
} else if (err != zOK)
return StsWarn (err);
else {
retries = pZ->retries;
switch (pZ->rxPacketType) {
case ZCOMPL:
return zEndOfSession;
case ZFIN:
StsRet (ZSendHexHeader (pZ, ZFIN, 0));
break;
default:
if (pZ->debug) {
DebugBegin (pZ->debug, debugWarn);
DebugString (pZ->debug,
"Unexpected packet after recursive receive:");
DebugPacket (pZ->debug, pZ->rxPacketType, pZ->rxPacketArg);
DebugEnd (pZ->debug);
}
break;
}
}
}
}
STATIC int ZSendCommand
(ZMODEM_PRIVATE *pZ, int immediate, const char *cmd) {
int err = zOK;
pZ->myZrqinitFlags = ZCOMMAND << 24;
ZNewFile (pZ);
ZProgress (pZ, stsNegotiating);
ZSendBytes (pZ, (const BYTE *) "rz\r", 3);
err = ZSendGetZRINIT (pZ);
if (err == zOK)
err = ZSendZSINIT (pZ);
err = ZSendZCommand (pZ, immediate, cmd);
ZProgress (pZ, stsEnding);
if (err == zEndOfSession)
err = ZSendEndSession (pZ);
if (err == zFail) {
ZSendHeader (pZ, ZCAN, 0);
ZGobble (pZ, 2);
err = zFailed;
}
if (err == zOK)
ZProgress (pZ, stsDone);
else if (pZ->userCancel)
ZProgress (pZ, stsCancelled);
else
ZProgress (pZ, stsFailed);
return StsWarn (err);
}
int ZModemInit
(ZMODEM *ppZ, SERIAL_PORT port) {
ZMODEM_PRIVATE *pZ;
pZ = malloc (sizeof (*pZ));
if (pZ == NULL)
return 1;
memset (pZ, 0, sizeof (*pZ));
pZ->crc32 = FALSE;
pZ->timeout = 10;
pZ->retries = 10;
pZ->userCancel = FALSE;
pZ->attention[0] = 0;
pZ->senderFlags = 0;
pZ->zrqinitFlags = 0;
pZ->receiverFlags = 0;
pZ->myZrqinitFlags = 0;
pZ->mySenderFlags = 0;
pZ->myReceiverFlags = KNOW_CRC32;
#if I_CAN_FULL_DUPLEX
pZ->myReceiverFlags |= CAN_FULL_DUPLEX;
#endif
#if I_CAN_OVERLAP_DISK
pZ->myReceiverFlags |= CAN_OVERLAP_DISK;
#endif
#if I_CAN_SEND_BREAK
pZ->myReceiverFlags |= CAN_SEND_BREAK;
#endif
pZ->fileFlags = 0;
{
memset (pZ->classify, 0, sizeof (pZ->classify));
SetEncode (CAN);
SetEncode (XON);
SetEncode (XON | 0x80);
SetEncode (XOFF);
SetEncode (XOFF | 0x80);
SetEncode (DLE);
SetEncode (DLE | 0x80);
SetIgnore (XON);
SetIgnore (XON | 0x80);
SetIgnore (XOFF);
SetIgnore (XOFF | 0x80);
}
pZ->sendingCrc32 = FALSE;
pZ->txPacketType = -1;
pZ->receivingCrc32 = FALSE;
pZ->rxPacketType = -1;
pZ->rxPacketArg = 0;
pZ->sendPosition = 0;
pZ->receivePosition = 0;
pZ->debug = NULL;
ZInitCrc ();
pZ->port = NULL;
pZ->serialBuffer = malloc (256);
if (pZ->serialBuffer == NULL)
return 1;
pZ->serialBufferSize = 256;
pZ->serialBufferRead = pZ->serialBuffer;
pZ->serialBufferLimit = pZ->serialBuffer;
pZ->f = NULL;
pZ->fileSize = -1;
pZ->filenames = NULL;
pZ->currentFileName = 0;
pZ->numFileNames = 0;
pZ->fileType = diskFileUnknown;
pZ->progress = NULL;
{
int i;
for (i = 0x40; i < 0x60; i++)
SetDecode (i);
for (i = 0xc0; i < 0xe0; i++)
SetDecode (i);
SetDecode ('l');
SetDecode ('m');
}
{
int i;
for (i = 0; i < 256; i++)
zDecode[i] = 0;
for (i = 0x40; i < 0x60; i++)
zDecode[i] = i & 0xBF;
for (i = 0xc0; i < 0xe0; i++)
zDecode[i] = i & 0xBF;
zDecode['l'] = 0x7F;
zDecode['m'] = 0xFF;
}
pZ->noiseLimit = 25000;
pZ->crashRecovery = FALSE;
pZ->port = port;
*ppZ = pZ;
return 0;
}
int ZModemDestroy
(ZMODEM zPublic) {
ZMODEM_PRIVATE *pZ = (ZMODEM_PRIVATE *) zPublic;
if (pZ->serialBuffer)
free (pZ->serialBuffer);
free (zPublic);
return zOK;
}
int ZModemSetDebug
(ZMODEM zPublic, DEBUG debug) {
ZMODEM_PRIVATE *pZ = (ZMODEM_PRIVATE *) zPublic;
pZ->debug = debug;
return zOK;
}
int ZModemSetProgress
(ZMODEM zPublic, PROGRESS progress) {
ZMODEM_PRIVATE *pZ = (ZMODEM_PRIVATE *) zPublic;
pZ->progress = progress;
return zOK;
}
int ZModemSetFileType
(ZMODEM zPublic, int fileType) {
ZMODEM_PRIVATE *pZ = (ZMODEM_PRIVATE *) zPublic;
pZ->fileType = fileType;
return zOK;
}
int ZModemCancel
(ZMODEM zPublic) {
ZMODEM_PRIVATE *pZ = (ZMODEM_PRIVATE *) zPublic;
pZ->userCancel = TRUE;
return zOK;
}
int ZModemReceive
(ZMODEM zPublic) {
ZMODEM_PRIVATE *pZ = (ZMODEM_PRIVATE *) zPublic;
int returnVal = 0;
ProgressReceiving (pZ->progress);
if (ZReceive (pZ) != zOK)
returnVal = 1;
return returnVal;
}
int ZModemSend
(ZMODEM zPublic, const char *filenames[], int count) {
ZMODEM_PRIVATE *pZ = (ZMODEM_PRIVATE *) zPublic;
int returnVal = 0;
pZ->currentFileName = 0;
pZ->filenames = filenames;
pZ->numFileNames = count;
ProgressSending (pZ->progress);
if (ZSendFiles (pZ) != zOK)
returnVal = 1;
return returnVal;
}
int ZModemSendCommand
(ZMODEM zPublic, const char *command) {
ZMODEM_PRIVATE *pZ = (ZMODEM_PRIVATE *) zPublic;
int returnVal = 0;
ProgressSending (pZ->progress);
if (ZSendCommand (pZ, 0, command) != zOK)
returnVal = 1;
return returnVal;
}