home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
back2roots/padua
/
padua.7z
/
padua
/
ftp.vapor.com
/
microdot-1
/
md1_src_02.lzx
/
zm_receive.c
< prev
next >
Wrap
C/C++ Source or Header
|
2014-05-19
|
17KB
|
588 lines
/**********************************************************************
* Receive.c: File reception routines for xprzmodem.library;
* Version 2.10, 12 February 1991, by Rick Huebner.
* Based closely on Chuck Forsberg's rz.c example ZModem code,
* but too pervasively modified to even think of detailing the changes.
* Released to the Public Domain; do as you like with this code.
*
* Version 2.50, 15 November 1991, CRC-32 additions by William M. Perkins.
**********************************************************************/
/*#include <proto/all.h>
#include <exec/types.h>
#include <ctype.h>
#include <stdio.h>*/
#include <stdlib.h>
#include <string.h>
#include "xproto.h"
#include "zmodem.h"
#include "xprzmodem.h"
#ifdef DEBUGLOG
extern void *DebugLog;
#endif
/* Proto fⁿr Inlines */
static short rcvbatch(struct Vars *v);
static short tryz(struct Vars *v);
static short rzfiles(struct Vars *v);
static short rzfile(struct Vars *v);
static short procheader(struct Vars *v);
static short putsec(struct Vars *v);
static void ackbibi(struct Vars *v);
/**********************************************************
* long XProtocolReceive(struct XPR_IO *xio)
*
* Main file reception routine; called by comm program
**********************************************************/
long XProtocolReceive(struct XPR_IO *xio)
{
struct SetupVars *sv;
struct Vars *v;
UBYTE err = FALSE;
/* Perform common setup and initializations */
if (! (v = setup(xio)))
return XPRS_FAILURE;
v->Tryzhdrtype = ZRINIT;
v->Rxtimeout = 100;
sv = (void *) v->io.xpr_data;
if (sv->bufpos)
{
v->Modemchar = v->Modembuf;
if (sv->buflen > sizeof(v->Modembuf))
sv->buflen = sizeof(v->Modembuf);
memcpy(v->Modembuf, sv->bufpos,sv->buflen);
v->Modemcount = sv->buflen;
}
/* Transfer the files */
if (rcvbatch(v) == ERROR)
{
upderr(v, "Empfang abgebrochen oder Timeout!");
err = TRUE;
}
else
updmsg(v, "▄bertragung erfolgreich beendet.");
FreeMem(v, (long) sizeof(struct Vars));
#ifdef DEBUGLOG
if (DebugLog)
{
xpr_fclose(&v->io, DebugLog);
DebugLog = NULL;
}
#endif
return (err) ? XPRS_FAILURE : XPRS_SUCCESS;
} /* End of long XProtocolReceive() */
/**********************************************************
* short rcvbatch(struct Vars *v)
*
* Start the batch transfer
**********************************************************/
static short rcvbatch(struct Vars *v)
{
switch (tryz(v))
{
case ZCOMPL:
return OK;
case ZFILE:
if (rzfiles(v) == OK)
return OK;
}
canit(v);
return ERROR;
} /* End of short rcvbatch() */
/**********************************************************
* short tryz(struct Vars *v)
*
* Negotiate with sender to start a file transfer
**********************************************************/
static short tryz(struct Vars *v)
{
short n, errors = 0;
for (n = v->ErrorLimit; --n >= 0; )
{
/* Set max frame length and capability flags */
stohdr(v, (long) v->Tframlen);
v->Txhdr[ZF0] = CANFC32 | CANFDX | CANOVIO;
zshhdr(v, v->Tryzhdrtype);
sendbuf(v);
again:
/* Check for abort from comm program */
if (xpr_chkabort())
return ERROR;
switch (zgethdr(v))
{
case ZFILE: /* File name and info packet */
v->Zconv = v->Rxhdr[ZF0]; /* Suggested txt mode; ZCNL = text, */
/* ZCBIN = binary, 0 = don't know. */
v->Zmanag = v->Rxhdr[ZF1]; /* Suggested file management mode. */
v->Ztrans = v->Rxhdr[ZF2]; /* Suggested file transport mode. */
v->Tryzhdrtype = ZRINIT;
if (zrdata(v, v->Pktbuf, KSIZE) == GOTCRCW)
return ZFILE;
zshhdr(v, ZNAK); /* Packet mangled, ask for retry */
sendbuf(v);
goto again;
case ZSINIT: /* Special attention-grabbing string to use to */
/* interrupt sender */
if (zrdata(v, v->Attn, ZATTNLEN) == GOTCRCW)
zshhdr(v, ZACK);
else
zshhdr(v, ZNAK);
sendbuf(v);
goto again;
case ZFREECNT: /* Sender wants to know how much room we've got */
stohdr(v, getfree());
zshhdr(v, ZACK);
sendbuf(v);
goto again;
case ZCOMMAND: /* Sender wants us to do remote commands, */
/* but we don't do requests. */
if (zrdata(v, v->Pktbuf, KSIZE) == GOTCRCW)
{
mysprintf(v->Msgbuf, "Kommando %s ignoriert!", v->Pktbuf);
upderr(v, v->Msgbuf); /* Ignore and report all uploaded commands */
stohdr(v, 0L); /* whilst telling sender they worked; */
do
{
zshhdr(v, ZCOMPL); /* paranoia can be good for you... */
sendbuf(v);
}
while (++errors < v->ErrorLimit && zgethdr(v) != ZFIN);
ackbibi(v);
return ZCOMPL;
}
else
zshhdr(v, ZNAK);
sendbuf(v);
goto again;
case ZCOMPL:
goto again;
case ZFIN: /* Sender has ended batch */
ackbibi(v);
return ZCOMPL;
case ZCAN:
case RCDO:
upderr(v, v->Msgbuf);
return ERROR;
}
}
return ERROR;
} /* End of short tryz() */
/**********************************************************
* short rzfiles(struct Vars *v)
*
* Receive a batch of files
**********************************************************/
static short rzfiles(struct Vars *v)
{
short c;
/* Keep receiving files until end of batch or error */
while (TRUE)
{
switch (c = rzfile(v))
{
case ZEOF:
case ZSKIP:
switch (tryz(v))
{
case ZCOMPL:
return OK;
default:
return ERROR;
case ZFILE:
break;
}
break;
default:
bfclose(v);
updmsg(v, "Datei nur teilweise empfangen!");
return c;
}
}
} /* End of short rzfiles() */
/**********************************************************
* short rzfile(struct Vars *v)
*
* Receive one file; file name packet already read into
* Pktbuf by tryz()
**********************************************************/
static short rzfile(struct Vars *v)
{
short c, n;
/*
* Process file name packet; either open file and prepare to receive,
* or tell us to skip this one.
*/
if (procheader(v) == ERROR)
return v->Tryzhdrtype = ZSKIP;
n = v->ErrorLimit;
v->Rxbytes = v->Strtpos;
v->Eofseen = FALSE;
/* Receive ZDATA frames until finished */
while (TRUE)
{
stohdr(v, v->Rxbytes); /* Tell sender where to start frame */
zshhdr(v, ZRPOS);
sendbuf(v);
nxthdr:
/* Check for abort from comm program */
if (xpr_chkabort())
return ERROR;
switch (c = zgethdr(v)) /* Wait for frame header */
{
default:
#ifdef DEBUGLOG
mysprintf(v->Msgbuf, "rzfile: zgethdr returned %ld\n", (long) c);
dlog(v, v->Msgbuf);
#endif
return ERROR;
case ZNAK:
case TIMEOUT:
if (--n < 0)
return ERROR;
#ifdef DEBUGLOG
dlog(v, "rzfile: zgethdr NAK/Timeout\n");
#endif
v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_TIMEOUTS;
mysprintf(strchr(v->Msgbuf, '\0'), "@ %ld; noch %ld Versuche",
v->Rxbytes, (long) n);
v->xpru.xpru_errormsg = (char *) v->Msgbuf;
++v->xpru.xpru_timeouts;
xpr_update(&v->xpru);
continue;
case ZFILE: /* Sender didn't see our ZRPOS yet; try again */
zrdata(v, v->Pktbuf, KSIZE); /* Read and discard redundant */
continue; /* filename packet */
case ZEOF: /* End of file data */
if (v->Rxpos != v->Rxbytes) /* We aren't in sync; go back */
{
mysprintf(v->Msgbuf, "Falsches EOF: hier @%ld, Sender @%ld!",
v->Rxbytes, v->Rxpos);
upderr(v, v->Msgbuf);
continue;
}
bfclose(v); /* All done; close file */
#ifdef DEBUGLOG
dlog(v, "rzfile: EOF\n");
#endif
updmsg(v, "EOF empfangen; warte auf nΣchste Datei.");
return c;
case ERROR: /* Too much garbage while waiting for frame header */
if ( --n < 0)
return ERROR;
#ifdef DEBUGLOG
dlog(v, "rzfile: zgethdr garbage overflow\n");
#endif
v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_ERRORS;
mysprintf(strchr(v->Msgbuf, '\0'), "@ %ld; noch %ld Versuche",
v->Rxbytes, (long) n);
v->xpru.xpru_errormsg = (char *) v->Msgbuf;
++v->xpru.xpru_errors;
xpr_update(&v->xpru);
zmputs(v, v->Attn);
xpr_sflush();
v->Modemcount = 0;
continue;
case ZDATA: /* More file data packets forthcoming */
if (v->Rxpos != v->Rxbytes) /* We aren't in sync; go back */
{
if ( --n < 0)
return ERROR;
v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_ERRORS;
mysprintf(v->Msgbuf, "Synchronisationsfehler: hier @%ld, Sender @%ld!",
v->Rxbytes, v->Rxpos);
v->xpru.xpru_errormsg = (char *) v->Msgbuf;
++v->xpru.xpru_errors;
xpr_update(&v->xpru);
// flushen
v->Modemcount = 0;
zmputs(v, v->Attn);
xpr_sflush();
continue;
}
/* Receive file data packet(s) */
moredata:
/* Check for abort from comm program */
if (xpr_chkabort())
goto aborted;
switch (c = zrdata(v, v->Pktbuf,KSIZE))
{
case ZCAN:
case RCDO:
aborted:
#ifdef DEBUGLOG
dlog(v, "rzfile: zrdata returned CAN\n");
#endif
upderr(v, "▄bertragung abgebrochen!");
return ERROR;
case ERROR: /* CRC error or packet too long */
if ( --n < 0)
return ERROR;
#ifdef DEBUGLOG
dlog(v, "rzfile: zrdata returned error\n");
#endif
v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_ERRORS;
mysprintf(strchr(v->Msgbuf, '\0'), "@ %ld; noch %ld Versuche",
v->Rxbytes, (long) n);
v->xpru.xpru_errormsg = (char *) v->Msgbuf;
++v->xpru.xpru_errors;
xpr_update(&v->xpru);
#ifdef DEBUGLOG
dlog(v, v->Msgbuf);
dlog(v, "\n");
#endif
zmputs(v, v->Attn);
continue;
case TIMEOUT:
if ( --n < 0)
return ERROR;
#ifdef DEBUGLOG
dlog(v, "rzfile: zrdata returned timeout\n");
#endif
v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_TIMEOUTS;
mysprintf(strchr(v->Msgbuf, '\0'), "@ %ld; noch %ld Versuche",
v->Rxbytes, (long) n);
v->xpru.xpru_errormsg = (char *) v->Msgbuf;
++v->xpru.xpru_timeouts;
xpr_update(&v->xpru);
#ifdef DEBUGLOG
dlog(v, v->Msgbuf);
dlog(v, "\n");
#endif
continue;
case GOTCRCW: /* Sender says it's waiting for an ACK */
n = v->ErrorLimit;
if (putsec(v) == ERROR)
return ERROR;
stohdr(v, v->Rxbytes);
zshhdr(v, ZACK);
sendbuf(v);
goto nxthdr;
case GOTCRCQ: /* Sender says it's not waiting, */
/* but ACK anyway (rarely used) */
n = v->ErrorLimit;
if (putsec(v) == ERROR)
return ERROR;
stohdr(v, v->Rxbytes);
zshhdr(v, ZACK);
sendbuf(v);
goto moredata;
case GOTCRCG: /* Sender says keep receiving, there's more coming */
n = v->ErrorLimit;
if (putsec(v) == ERROR)
return ERROR;
goto moredata;
case GOTCRCE: /* Sender says this is the last packet */
n = v->ErrorLimit;
if (putsec(v) == ERROR)
return ERROR;
goto nxthdr;
}
}
}
} /* End of short rzfile() */
/**********************************************************
* short procheader(struct Vars *v)
*
* Process file name & info packet; either open file and
* prepare to receive, or return ERROR if we should skip
* this one for some reason
**********************************************************/
static short procheader(struct Vars *v)
{
UBYTE *p, *openmode;
openmode = "w";
v->Strtpos = 0;
/* Extract expected filesize from file info packet, if given */
v->Fsize = -1;
p = strchr(v->Pktbuf, '\0') + 1;
if (*p)
v->Fsize = atol(p);
/*
* Make sure we have room for file; skip it if not.
* Commented out for now, since getfree() isn't implemented yet.
if (v->Fsize > getfree())
{
mysprintf(v->Msgbuf, "Insufficient disk space; need %ld bytes, have %ld",
v->Fsize, getfree());
upderr(v, v->Msgbuf);
v->Noroom = TRUE;
return ERROR;
}
*/
/* else use the default directory path specified in the setup options */
p = strchr(v->Pktbuf, '\0'); /* start at end and scan back */
/* to start of name */
while (p >= v->Pktbuf && *p != '/' && *p != '\\' && *p != ':')
--p;
strcpy(v->Filename, ++p);
/* Display name of file being received for user */
v->xpru.xpru_updatemask = XPRU_FILENAME;
v->xpru.xpru_filename = (char *) v->Filename;
xpr_update(&v->xpru);
/*
* If a file with this name already exists, handle in
* accordance with O option
*/
if (exist(v))
{
openmode = "a";
v->Strtpos = xpr_finfo(v->Filename, 1L);
}
/* Set text/binary mode according to options before opening file */
set_textmode(v);
/*
* Figure out file translation mode to use; either binary (verbatim
* transfer) or ASCII (perform end-of-line conversions). If user has
* specified a mode (TY or TN), that's what we use. If user says use
* sender's suggestion (T?), set mode according to Zconv flag. If neither
* side specifies, default to binary mode.
*/
v->Thisbinary = v->Rxbinary || !v->Rxascii;
if (! v->Rxbinary && v->Zconv == ZCNL)
v->Thisbinary = FALSE;
if (! v->Rxascii && v->Zconv == ZCBIN)
v->Thisbinary = TRUE;
/* Open the file (finally) */
if (! (v->File = bfopen(v, openmode)))
{
++v->Errcnt;
upderr(v, "Kann Datei nicht ÷ffnen!");
return ERROR;
}
getsystime(&v->Starttime);
/* Initialize comm program transfer status display */
v->xpru.xpru_updatemask = XPRU_PROTOCOL | XPRU_FILESIZE | XPRU_MSG
| XPRU_BLOCKS | XPRU_ERRORS | XPRU_TIMEOUTS | XPRU_BLOCKCHECK
| XPRU_BYTES | XPRU_EXPECTTIME | XPRU_ELAPSEDTIME| XPRU_DATARATE;
v->xpru.xpru_protocol = "ZModem";
v->xpru.xpru_filesize = v->Fsize;
v->xpru.xpru_msg = "Empfange Datei...";
v->xpru.xpru_blocks = v->xpru.xpru_errors = v->xpru.xpru_timeouts = 0;
v->xpru.xpru_blockcheck = v->Crc32 ? "CRC-32" : "CRC-16";
v->xpru.xpru_bytes = v->Strtpos;
update_rate(v);
xpr_update(&v->xpru);
return OK;
} /* End of short procheader() */
/**********************************************************
* short putsec(struct Vars *v)
*
* Writes the received file data to the output file.
* If in ASCII mode, stops writing at first ^Z, and converts all
* \r\n pairs or solo \r's to \n's.
**********************************************************/
static short putsec(struct Vars *v)
{
static char nl = '\n';
UBYTE *p;
short n;
/* If in binary mode, write it out verbatim */
if (v->Thisbinary)
{
if (bfwrite(v, v->Pktbuf, (long) v->Rxcount) != v->Rxcount)
goto diskfull;
/* If in text mode, perform end-of-line cleanup */
}
else
{
if (v->Eofseen)
return OK;
for (p = v->Pktbuf, n = v->Rxcount; --n >= 0; ++p)
{
if (*p == CPMEOF)
{
v->Eofseen = TRUE;
return OK;
}
else if (*p != '\n' && v->Lastsent == '\r')
{
if (bfwrite(v, &nl, 1L) != 1)
goto diskfull;
}
if (*p != '\r' && bfwrite(v, p, 1L) != 1)
goto diskfull;
v->Lastsent = *p;
}
}
/* Update comm program status display */
v->xpru.xpru_updatemask = XPRU_BLOCKS | XPRU_BLOCKSIZE | XPRU_BYTES
| XPRU_EXPECTTIME | XPRU_ELAPSEDTIME | XPRU_DATARATE | XPRU_BLOCKCHECK;
++v->xpru.xpru_blocks;
v->xpru.xpru_blocksize = v->Rxcount;
v->xpru.xpru_bytes = v->Rxbytes += v->Rxcount;
v->xpru.xpru_blockcheck = v->Crc32 ? "CRC-32" : "CRC-16";
update_rate(v);
xpr_update(&v->xpru);
return OK;
diskfull:
upderr(v, "Fehler beim Schreiben in die Datei!");
v->Noroom = TRUE;
return ERROR;
} /* End of short putsec() */
/**********************************************************
* void ackbibi(struct Vars *v)
*
* End of batch transmission; disengage cleanly from sender
**********************************************************/
static void ackbibi(struct Vars *v)
{
short n;
#ifdef DEBUGLOG
dlog(v, "ackbibi:\n");
#endif
stohdr(v, 0L);
for (n = 4; --n; )
{
zshhdr(v, ZFIN);
sendbuf(v);
switch (readock(v, 100))
{
case 'O':
readock(v, 1); /* Discard 2nd 'O' */
case TIMEOUT:
case RCDO:
return;
}
}
} /* End of void ackbibi() */
/* End of Receive.c source */