home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
High Voltage Shareware
/
high1.zip
/
high1
/
DIR3
/
KA9Q212.ZIP
/
RZ.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-07-16
|
35KB
|
1,512 lines
/****************************************************************************
* Language : Turbo C 2.0 *
* Logfile : rz.c *
* Project : Comms library. *
* Date : 24 Jan 90 *
* Revision : 1.1 GT PC version. *
* 07 Mar 90 : 1.2 GT Background transfer. *
* 25 Oct 92 : 1.3 GT KA9Q mods. *
* 30 Jan 93 : 1.4 GT Fix KA9Q background transfer. *
* 20 Feb 93 : 1.5 GT Bump HOWMANY to 2048. *
* 21 Feb 93 : 1.6 GT Allocate buffer on heap. *
* 08 May 93 : 1.7 GT Fix warnings. *
*****************************************************************************
* Purpose : File receive driver. *
*****************************************************************************
* : This module is based on the equivalent module in the *
* : 31 Aug 87 version of rz/sz. *
* $Id: rz.c 1.5 93/07/16 11:49:53 ROOT_DOS Exp $
****************************************************************************/
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
#include <ctype.h>
#include <time.h>
#include <string.h>
#include <process.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dos.h>
#include "zmodem.h"
#include "sz.h"
#include "rbsb.h" /* most of the system dependent stuff here */
#include "zm.h"
#include "global.h"
#ifdef DEBUGZ
#include "tty.h"
#endif
/*
* Max value for HOWMANY is 255.
* A larger value reduces system overhead but may evoke kernel bugs.
* 133 corresponds to an XMODEM/CRC sector
*/
#ifndef HOWMANY
#define HOWMANY 2048 /* was 133 */
#endif
#undef RETRYMAX
#define RETRYMAX 5
#define UNIXFILE 0x8000 /* the S_IFREG file mask bit for stat */
#define DEFBYTL 2000000000L /* default rx file size */
#define CANBREAK
static int fout;
static int Eofseen; /* indicates cpm eof (^Z) has been received */
int Readnum = HOWMANY; /* Number of bytes to ask for in read () from
modem */
static long Bytesleft; /* number of bytes of incoming file left */
static long Modtime; /* Unix style mod time for incoming file */
static short Filemode; /* Unix style mode for incoming file */
static char Pathname[PATHLEN];
static int Batch = 0;
static int MakeLCPathname = TRUE; /* make received pathname lower case */
static int Nflag = 0; /* Don't really transfer files */
static int Rxbinary = FALSE; /* receive all files in bin mode */
static int Rxascii = FALSE; /* receive files in ascii (translate) mode */
static int Thisbinary; /* current file is to be received in bin mode */
static int rz_blklen; /* record length of received packets */
static char secbuf[KSIZE + 1];
#if 0
static char linbuf[HOWMANY];
#endif
static char *linbuf = 0; /* -> receive buffer */
int Lleft = 0; /* number of characters in linbuf */
static int Filcnt = 0; /* no of files transferred */
#if 0
time_t timep[2];
#endif
static int nocommand = FALSE; /* TRUE - disallow remote commands */
static int tryzhdrtype = ZRINIT; /* Header type to send corresponding to Last
rx close */
/****************************************************************************
* Local prototypes. *
****************************************************************************/
#if 0
static void bibi (int n);
#endif
static void chkinvok (char protocol);
static void purgeline (void);
static void uncaps (char *s);
static int IsAnyLower (char *s);
static void canit (void);
static void report (int sct);
static void checkpath (char *name);
static int tryz (void);
static int rzfiles (void);
static int rzfile (void);
static void zmputs (char *s);
static int closeit (void);
static void ackbibi (void);
static int sys2 (char *s);
static void exec2 (char *s);
static long getfree (void);
static int wcreceive (int argc, char **argp);
static int wcrxpn (char *rpn);
static int wcrx (void);
static int wcgetsec (char *rxbuf, int maxtime);
static int procheader (char *name);
static int putsec (char *buf, int n);
/****************************************************************************
* getfree *
* Routine to calculate the free bytes on the current file system. *
* ~0 means many free bytes (unknown). *
****************************************************************************/
static long getfree (void)
{
return (~0L); /* many free bytes ... */
} /* static long getfree (void) */
#if 0
/****************************************************************************
* bibi *
* Called by signal interrupt or terminate to clean things up. *
****************************************************************************/
static void bibi (int n)
{
n = n;
if (_Zmodem)
{
#ifdef DEBUGZ
_tout ("\r\n\nbibi: calling zmputs (_Attn)\r\n");
#endif
zmputs (_Attn);
}
canit ();
_zperr_ ("Interrupted\n");
closeit ();
#ifdef DEBUGZ
_tout ("bibi: doing longjmp (_tohere, -1)\r\n");
#endif
longjmp (_tohere, -1);
} /* static void bibi (int n) */
#endif
/****************************************************************************
* _getfile *
* Receives file(s). Returns 0 if successful. *
****************************************************************************/
int _getfile (int s, char protocol, char *options, char *filename,
void (*reporter) (int type, void *data))
{
char *cp;
int npats;
char **patts;
int exitcode = 0;
#if 0
void (*sigint_sav) (int);
void (*sigterm_sav) (int);
#endif
/* Initialise global variables. */
_z_socket = s;
Batch = 0;
_do_report = _zperr;
Filcnt = 0;
Lleft = 0;
MakeLCPathname = TRUE;
Nflag = 0;
nocommand = FALSE;
_Nozmodem = 0;
_Quiet = 0;
Readnum = HOWMANY;
Rxascii = FALSE;
Rxbinary = FALSE;
_Rxtimeout = 100;
_sending = FALSE;
tryzhdrtype = ZRINIT;
_Verbose = 0;
_Wcsmask = 0377;
_Zmodem = 0;
_Zrwindow = 1400;
chkinvok (protocol); /* choose protocol */
npats = 0;
/* Parse options. */
cp = options;
while (*cp != '\0')
{
switch (*cp++)
{
case '7': /* strip top bit */
_Wcsmask = 0177;
case 'a': /* ASCII transfer */
Rxascii = TRUE;
break;
case 'b': /* binary transfer */
Rxbinary = TRUE;
break;
case 'c': /* XMODEM/CRC */
_Crcflg = TRUE;
break;
case 'D': /* fake file transfer */
Nflag = TRUE;
break;
case 'i': /* disallow remote command */
nocommand = TRUE;
break;
case 'e': /* escape ctl chars */
_Zctlesc = 1;
break;
case 'p': /* 'protect' option */
_Lzmanag = ZMPROT;
break;
case 'q': /* quiet */
_Quiet = TRUE;
_Verbose = 0;
break;
case 't': /* change timeout */
sscanf (cp, "%d", &_Rxtimeout);
if (_Rxtimeout < 10 || _Rxtimeout > 1000)
return (ERROR);
cp = _stbnb (cp);
break;
case 'w': /* window size */
sscanf (cp, "%d", &_Zrwindow);
cp = _stbnb (cp);
break;
case 'u': /* no lower case convert */
MakeLCPathname = FALSE;
break;
case 'v': /* debug info */
++_Verbose;
break;
default:
return (ERROR);
} /* switch (*cp++) */
} /* while (*cp != '\0') */
/* Get filename. */
if (filename != NULL)
{
npats = 1;
patts = &filename;
}
if (npats > 1)
return (ERROR);
if (Batch && npats)
return (ERROR);
/* Get reporter function */
if (reporter != NULL)
_do_report = reporter; /* user supplied fn */
#if 0
if (_Verbose)
{
if ((_zperr_handle = open (LOGFILE,
O_CREAT | O_APPEND | O_WRONLY | O_TEXT,
S_IFREG | S_IWRITE)) == -1)
{
char buff[80];
sprintf (buff, "Can't open log file %s: %s\n",
LOGFILE, strerror (errno));
(*_do_report) (2, buff);
(*_do_report) (3, &Filcnt); /* report no of files */
return (ERROR);
}
_do_report = _zperr; /* use default reporter */
}
#endif
if (!_Quiet)
{
if (_Verbose == 0)
_Verbose = 2;
}
#if 0
if ((sigint_sav = signal (SIGINT, bibi)) == SIG_IGN)
signal (SIGINT, SIG_IGN);
else
signal (SIGINT, bibi);
#endif
#if 0
sigint_sav = signal (SIGINT, bibi);
sigterm_sav = signal (SIGTERM, bibi);
#endif
/* Set up escape routes. */
if (setjmp (_tohere) != 0)
{
#ifdef DEBUGZ
_tout ("getfile: exiting via _tohere jump\r\n");
#endif
(*_do_report) (3, &Filcnt); /* report files transferred */
#if 0
signal (SIGINT, sigint_sav);
signal (SIGTERM, sigterm_sav);
(void) close (_zperr_handle);
#endif
return (-2); /* user abort */
}
if (setjmp (_nocarrier) != 0)
{
#ifdef DEBUGZ
_tout ("getfile: exiting via _nocarrier jump\r\n");
#endif
(*_do_report) (3, &Filcnt); /* report files transferred */
#if 0
signal (SIGINT, sigint_sav);
signal (SIGTERM, sigterm_sav);
(void) close (_zperr_handle);
#endif
return (-3); /* lost carrier */
}
/* Get the file(s). */
if (wcreceive (npats, patts) == ERROR)
{
exitcode = 0200;
canit ();
}
if (exitcode && !_Zmodem) /* Bellow again with all thy might. */
canit ();
if (!_Quiet)
_say ("\n");
(*_do_report) (3, &Filcnt); /* report files transferred */
#if 0
signal (SIGINT, sigint_sav);
signal (SIGTERM, sigterm_sav);
(void) close (_zperr_handle);
#endif
return (exitcode);
} /* int _getfile (int s, char protocol, char *options, char *filename,
void (*reporter) (int type, void *data)) */
/****************************************************************************
* wcreceive *
* Let's receive something already. *
****************************************************************************/
#if 0
static char *rbmsg = "Ready to receive.\n"
"To begin transfer, issue the send command "
"to your modem program\r\n";
#endif
static int wcreceive (int argc, char **argp)
{
int c;
if (Batch || argc == 0)
{
/* ZMODEM / YMODEM BATCH */
_Crcflg = (_Wcsmask == 0377);
#if 0
if (!_Quiet)
_say (rbmsg);
#endif
if ((c = tryz ()) != 0)
{
if (c == ZCOMPL)
return OK;
if (c == ERROR)
goto fubar;
c = rzfiles ();
if (c)
goto fubar;
} /* if ((c = tryz ()) != 0) */
else
{
for (;;)
{
if (wcrxpn (secbuf) == ERROR)
goto fubar;
if (secbuf[0] == 0)
return OK;
if (procheader (secbuf) == ERROR)
goto fubar;
if (wcrx () == ERROR)
goto fubar;
} /* for (;;) */
} /* else */
} /* if (Batch || argc == 0) */
else
{
/* XMODEM */
Bytesleft = DEFBYTL;
Filemode = 0;
Modtime = 0L;
procheader ("");
strcpy (Pathname, *argp);
checkpath (Pathname);
(*_do_report) (0, Pathname);
_say ("\nReady to receive %s\r\n", Pathname);
if ((fout = open (Pathname,
O_CREAT | O_TRUNC | O_WRONLY | O_BINARY,
S_IFREG | S_IWRITE)) == -1)
return ERROR;
if (wcrx () == ERROR)
goto fubar;
++Filcnt;
} /* else */
return OK;
/* Transfer failed - clean up. */
fubar:
canit ();
if (fout != -1)
close (fout);
return ERROR;
} /* static int wcreceive (int argc, char **argp) */
/****************************************************************************
* wcrxpn *
* Fetch a pathname from the other end as a C ctyle ASCIZ string. Length *
* is indeterminate as long as less than rz_blklen. A null string *
* represents no more files (YMODEM). *
****************************************************************************/
static int wcrxpn (char *rpn)
{
int c;
purgeline ();
et_tu:
_firstsec = TRUE;
Eofseen = FALSE;
_sendline (_Crcflg ? WANTCRC : NAK);
Lleft = 0; /* Do read next time ... */
while ((c = wcgetsec (rpn, 100)) != 0)
{
if (c == WCEOT)
{
_zperr_ ("Pathname fetch returned %d", c);
_sendline (ACK);
Lleft = 0; /* Do read next time ... */
_readline (1);
goto et_tu;
}
return ERROR;
} /* while ((c = wcgetsec (rpn, 100)) != 0) */
_sendline (ACK);
return OK;
} /* static int wcrxpn (char *rpn) */
/****************************************************************************
* wcrx *
* Adapted from CMODEM13.C, written by Jack M Wierda and Roderick W Hart. *
****************************************************************************/
static int wcrx (void)
{
int sectnum, sectcurr;
char sendchar;
int cblklen; /* bytes to dump this block */
_firstsec = TRUE;
sectnum = 0;
Eofseen = FALSE;
sendchar = (char) (_Crcflg ? WANTCRC : NAK);
for (;;)
{
_sendline (sendchar); /* send it now, we're ready! */
Lleft = 0; /* Do read next time ... */
sectcurr = wcgetsec (secbuf, (sectnum & 0177) ? 50 : 130);
report (sectcurr);
if (sectcurr == (sectnum + 1 & _Wcsmask))
{
sectnum++;
cblklen = Bytesleft > rz_blklen ? rz_blklen : (int) Bytesleft;
if (putsec (secbuf, cblklen) == ERROR)
return ERROR;
if ((Bytesleft -= cblklen) < 0)
Bytesleft = 0;
sendchar = ACK;
}
else if (sectcurr == (sectnum & _Wcsmask))
{
_zperr_ ("Received dup Sector");
sendchar = ACK;
}
else if (sectcurr == WCEOT)
{
if (closeit ())
return ERROR;
_sendline (ACK);
Lleft = 0; /* Do read next time ... */
return OK;
}
else if (sectcurr == ERROR)
return ERROR;
else
{
_zperr_ ("Sync Error");
return ERROR;
}
} /* for (;;) */
} /* static int wcrx (void) */
/****************************************************************************
* wcgetsec *
* Fetches a Ward Christensen type sector. Returns sector number *
* encountered or ERROR if valid sector not received, or CAN CAN received *
* or WCEOT if eot sector. <maxtime> is timeout for first char, set to 4 *
* seconds thereafter. NO ACK IS SENT IF SECTOR IS RECEIVED OK (Caller *
* must do that when he is good and ready to get next sector). *
****************************************************************************/
static int wcgetsec (char *rxbuf, int maxtime)
{
int checksum, wcj, firstch;
unsigned short oldcrc;
char *p;
int sectcurr;
for (_Lastrx = _errors = 0; _errors < RETRYMAX; _errors++)
{
if ((firstch = _readline (maxtime)) == STX)
{
rz_blklen = KSIZE;
goto get2;
}
if (firstch == SOH)
{
rz_blklen = SECSIZ;
get2:
sectcurr = _readline (1);
if ((sectcurr + (oldcrc = _readline (1))) == _Wcsmask)
{
oldcrc = checksum = 0;
for (p = rxbuf, wcj = rz_blklen; --wcj >= 0;)
{
if ((firstch = _readline (1)) < 0)
goto bilge;
oldcrc = updcrc (firstch, oldcrc);
checksum += (*p++ = (char) firstch);
}
if ((firstch = _readline (1)) < 0)
goto bilge;
if (_Crcflg)
{
oldcrc = updcrc (firstch, oldcrc);
if ((firstch = _readline (1)) < 0)
goto bilge;
oldcrc = updcrc (firstch, oldcrc);
if (oldcrc & 0xFFFF)
_zperr_ ( "CRC");
else
{
_firstsec = FALSE;
return sectcurr;
}
} /* if (_Crcflg) */
else if (((checksum - firstch) & _Wcsmask) == 0)
{
_firstsec = FALSE;
return sectcurr;
}
else
_zperr_ ( "Checksum");
} /* if ((sectcurr + (oldcrc = _readline (1))) == _Wcsmask) */
else
_zperr_ ("Sector number garbled");
} /* if (firstch == SOH) */
else if (firstch == EOT && Lleft == 0) /* make sure eot really is
eot and not just mixmash */
return WCEOT;
else if (firstch == CAN)
{
if (_Lastrx == CAN)
{
_zperr_ ("Sender CANcelled");
return ERROR;
}
else
{
_Lastrx = CAN;
continue;
}
} /* else if (firstch == CAN) */
else if (firstch == ZTIMEOUT)
{
if (_firstsec)
goto humbug;
bilge:
_zperr_ ( "TIMEOUT");
}
else
_zperr_ ( "Got 0%o sector header", firstch);
humbug:
_Lastrx = 0;
while (_readline (1) != ZTIMEOUT)
;
if (_firstsec)
{
_sendline (_Crcflg ? WANTCRC : NAK);
Lleft = 0; /* Do read next time ... */
}
else
{
maxtime = 40;
_sendline (NAK);
Lleft = 0; /* Do read next time ... */
}
} /* for (_Lastrx = _errors = 0; _errors < RETRYMAX; _errors++) */
/* try to stop the bubble machine. */
canit ();
return ERROR;
} /* static int wcgetsec (char *rxbuf, int maxtime) */
/****************************************************************************
* _readline *
* This version of _readline is reasonably well suited for reading many *
* characters (except, currently, for the Regulus version!). Timeout is *
* in tenths of seconds. *
****************************************************************************/
int _readline (int timeout)
{
int n;
static char *cdq; /* pointer for removing chars from linbuf */
time_t start; /* start for timeout */
if (linbuf == 0)
linbuf = mallocw (HOWMANY);
if (--Lleft >= 0)
{
if (_Verbose > 8)
{
_say ("%02x ", *cdq & 0377);
}
return (*cdq++ & _Wcsmask);
}
n = timeout / 10;
if (n < 2)
n = 3;
time (&start);
if (_Verbose > 5)
_vfile ("Calling read: alarm=%d Readnum=%d ", n, Readnum);
_no_carrier ();
while (1)
{
Lleft = _receive ((unsigned char *) (cdq = linbuf), Readnum);
if (Lleft != 0)
break; /* got something */
if (time (NULL) >= start + n)
{
_zperr_ ("ZTIMEOUT");
return (ZTIMEOUT);
}
}
if (_Verbose > 5)
{
_say ("Read returned %d bytes\n", Lleft);
}
if (Lleft < 1)
return ZTIMEOUT;
--Lleft;
if (_Verbose > 8)
{
_say ("%02x ", *cdq & 0377);
}
return (*cdq++ & _Wcsmask);
} /* int _readline (int timeout) */
/****************************************************************************
* purgeline *
* Purge the modem input queue of all characters. *
****************************************************************************/
static void purgeline (void)
{
unsigned char c;
Lleft = 0;
while (_rdchk () > 0)
_receive (&c, 1);
} /* static void purgeline (void) */
/****************************************************************************
* procheader *
* Process incoming file information header. *
****************************************************************************/
static int procheader (char *name)
{
int openmode;
char *p;
/* set default parameters and overrides */
(*_do_report) (0, name);
openmode = O_CREAT | O_TRUNC | O_WRONLY | O_BINARY;
Thisbinary = (!Rxascii) || Rxbinary;
if (_Lzmanag)
_zmanag = _Lzmanag;
/* Process ZMODEM remote file management requests. */
if (!Rxbinary && _zconv == ZCNL) /* Remote ASCII override */
Thisbinary = 0;
if (_zconv == ZCBIN) /* Remote Binary override */
Thisbinary = TRUE;
else if (_zmanag == ZMAPND)
openmode = O_APPEND | O_WRONLY | O_BINARY;
/* ZMPROT check for existing file */
if (_zmanag == ZMPROT && (fout = open (name, O_RDONLY)) != -1)
{
close (fout);
return ERROR;
}
Bytesleft = DEFBYTL;
Filemode = 0;
Modtime = 0L;
p = name + 1 + strlen (name);
if (*p)
{
/* file coming from Unix or DOS system */
sscanf (p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
if (Filemode & UNIXFILE)
++Thisbinary;
if (_Verbose)
{
_say ("Incoming: %s %ld %lo %o\n",
name, Bytesleft, Modtime, Filemode);
}
} /* if (*p) */
else
{
/* File coming from CP/M system */
for (p = name; *p; ++p) /* change / to _ */
if ( *p == '/')
*p = '_';
if ( *--p == '.') /* zap trailing period */
*p = 0;
} /* else */
if (!_Zmodem && MakeLCPathname && !IsAnyLower (name))
uncaps (name);
strcpy (Pathname, name);
if (_Verbose)
{
_say ("Receiving %s %s\n",
name, Thisbinary ? "BIN" : "ASCII");
}
checkpath (name);
if (Nflag)
name = "nul"; /* send to bit bucket */
if ((fout = open (name, openmode, S_IFREG | S_IWRITE)) == -1)
{
_vfile ("Can't open %s mode %x, %s\n",
name, openmode, strerror (errno));
return ERROR;
}
return OK;
} /* static int procheader (char *name) */
/****************************************************************************
* putsec *
* Writes the <n> characters of <buf> to receive file fout. If not in *
* binary mode, carriage returns, and all characters starting with CPMEOF *
* are discarded. *
****************************************************************************/
static int putsec (char *buf, int n)
{
char *p, *q;
char locbuf[KSIZE + 1];
int qcount; /* no of chars in local buffer */
if (Thisbinary)
{
write (fout, buf, n);
#if 0
for (p = buf; --n >= 0;)
putc (*p++, fout);
#endif
}
else
{
if (Eofseen)
return OK;
q = locbuf;
qcount = 0;
for (p = buf; --n >= 0; ++p)
{
#if 0
/* We'll keep CR under MesS-DOS. */
if (*p == '\r')
continue;
#endif
if (*p == CPMEOF)
{
Eofseen = TRUE;
return OK;
}
*q++ = *p; /* put byte in write buffer */
qcount++;
#if 0
putc (*p ,fout);
#endif
} /* for (p = buf; --n >= 0; ++p) */
if (qcount != 0)
write (fout, locbuf, qcount);
} /* else */
return OK;
} /* static int putsec (char *buf, int n) */
/****************************************************************************
* uncaps *
* Make string <s> lower case. *
****************************************************************************/
static void uncaps (char *s)
{
for (; *s; ++s)
if (isupper (*s))
*s = tolower (*s);
} /* static void uncaps (char *s) */
/****************************************************************************
* IsAnyLower *
* IsAnyLower returns TRUE if string s has lower case letters. *
****************************************************************************/
static int IsAnyLower (char *s)
{
for (; *s; ++s)
if (islower (*s))
return TRUE;
return FALSE;
} /* static int IsAnyLower (char *s) */
/****************************************************************************
* canit *
* Send cancel string to get the other end to shut up. *
****************************************************************************/
static void canit (void)
{
#ifdef DEBUGZ
_tout ("canit: calling _canit ()\r\n");
#endif
_canit ();
Lleft = 0; /* Do read next time ... */
#ifdef DEBUGZ
_tout ("leaving canit ()\r\n");
#endif
} /* static void canit (void) */
/****************************************************************************
* report *
* Print <sct>. *
****************************************************************************/
static void report (int sct)
{
if (_Verbose > 1)
_say ("%03d%c", sct, sct % 10 ? ' ' : '\r');
} /* static void report (int sct) */
/****************************************************************************
* chkinvok *
* Set chosen protocol. *
****************************************************************************/
static void chkinvok (char protocol)
{
if (protocol == 'z')
Batch = TRUE;
if (protocol == 'y')
Batch = _Nozmodem = TRUE;
} /* static void chkinvok (char protocol) */
/****************************************************************************
* checkpath *
* Totalitarian Communist pathname processing. *
****************************************************************************/
static void checkpath (char *name)
{
/* No restrictions in this version. */
name = name; /* silence compiler */
} /* static void checkpath (char *name) */
/****************************************************************************
* tryz *
* Initialize for Zmodem receive attempt, try to activate Zmodem sender. *
* Handles ZSINIT frame. Return ZFILE if Zmodem filename received, -1 on *
* error, ZCOMPL if transaction finished, else 0. *
****************************************************************************/
static int tryz (void)
{
int c, n;
int cmdzack1flg;
if (_Nozmodem) /* Check for "rb" program name */
return 0;
for (n = _Zmodem ? 15 : 5; --n >= 0;)
{
/* Set buffer length (0) and capability flags. */
_stohdr (0L);
#ifdef CANBREAK
_Txhdr[ZF0] = CANFC32 | CANFDX | CANOVIO | CANBRK;
#else
_Txhdr[ZF0] = CANFC32 | CANFDX | CANOVIO;
#endif
if (_Zctlesc)
_Txhdr[ZF0] |= TESCCTL;
_zshhdr (tryzhdrtype, _Txhdr);
if (tryzhdrtype == ZSKIP) /* Don't skip too far */
tryzhdrtype = ZRINIT; /* CAF 8-21-87 */
again:
switch (_zgethdr (_Rxhdr, 0))
{
case ZRQINIT:
continue;
case ZEOF:
continue;
case ZTIMEOUT:
continue;
case ZFILE:
_zconv = _Rxhdr[ZF0];
_zmanag = _Rxhdr[ZF1];
_ztrans = _Rxhdr[ZF2];
tryzhdrtype = ZRINIT;
c = _zrdata (secbuf, KSIZE);
if (c == GOTCRCW)
return ZFILE;
_zshhdr (ZNAK, _Txhdr);
goto again;
case ZSINIT:
_Zctlesc = TESCCTL & _Rxhdr[ZF0];
if (_zrdata (_Attn, ZATTNLEN) == GOTCRCW)
{
_zshhdr (ZACK, _Txhdr);
goto again;
}
_zshhdr (ZNAK, _Txhdr);
goto again;
case ZFREECNT:
_stohdr (getfree ());
_zshhdr (ZACK, _Txhdr);
goto again;
case ZCOMMAND:
cmdzack1flg = _Rxhdr[ZF0];
if (_zrdata (secbuf, KSIZE) == GOTCRCW)
{
if (cmdzack1flg & ZCACK1)
_stohdr (0L);
else
{
if (nocommand)
_stohdr (0L); /* fake command ok */
else
_stohdr ((long) sys2 (secbuf));
}
purgeline (); /* dump impatient questions */
do
{
_zshhdr (ZCOMPL, _Txhdr);
} while (++_errors < 20 && _zgethdr (_Rxhdr,1) != ZFIN);
ackbibi ();
if (cmdzack1flg & ZCACK1)
if (nocommand)
longjmp (_tohere, -1); /* don't do it */
else
exec2 (secbuf);
return ZCOMPL;
} /* if (_zrdata (secbuf, KSIZE) == GOTCRCW) */
_zshhdr (ZNAK, _Txhdr);
goto again;
case ZCOMPL:
goto again;
default:
continue;
case ZFIN:
ackbibi ();
return ZCOMPL;
case ZCAN:
return ERROR;
} /* switch (_zgethdr (_Rxhdr, 0)) */
} /* for (n = _Zmodem ? 15 : 5; --n >= 0;) */
return 0;
} /* static int tryz (void) */
/****************************************************************************
* rzfiles *
* Receive one or more files with the ZMODEM protocol. *
****************************************************************************/
static int rzfiles (void)
{
int c;
for (;;)
{
switch (c = rzfile ())
{
case ZEOF:
case ZSKIP:
switch (tryz ())
{
case ZCOMPL:
return OK;
default:
return ERROR;
case ZFILE:
break;
}
continue;
default:
return c;
case ERROR:
return ERROR;
} /* switch (c = rzfile ()) */
} /* for (;;) */
} /* static int rzfiles (void) */
/****************************************************************************
* rzfile *
* Receive a file with ZMODEM protocol. Assumes file name frame is in *
* secbuf. *
****************************************************************************/
static int rzfile (void)
{
int c, n;
long rxbytes;
int sent_zm = FALSE; /* TRUE - sent ZMODEM string */
Eofseen = FALSE;
if (procheader (secbuf) == ERROR)
{
return (tryzhdrtype = ZSKIP);
}
n = 20;
rxbytes = 0l;
for (;;)
{
_stohdr (rxbytes);
_zshhdr (ZRPOS, _Txhdr);
nxthdr:
switch (c = _zgethdr (_Rxhdr, 0))
{
default:
_vfile ("rzfile: _zgethdr returned %d", c);
return ERROR;
case ZNAK:
case ZTIMEOUT:
if ( --n < 0)
{
_vfile ("rzfile: _zgethdr returned %d", c);
return ERROR;
}
case ZFILE:
_zrdata (secbuf, KSIZE);
continue;
case ZEOF:
if (_rclhdr (_Rxhdr) != rxbytes)
{
/*
* Ignore eof if it's at wrong place - force
* a timeout because the eof might have gone
* out before we sent our zrpos.
*/
_errors = 0;
goto nxthdr;
}
if (closeit ())
{
tryzhdrtype = ZFERR;
_vfile ("rzfile: closeit returned <> 0");
return ERROR;
}
_vfile ("rzfile: normal EOF");
++Filcnt;
return c;
case ERROR: /* Too much garbage in header search
error */
if (--n < 0)
{
_vfile ("rzfile: _zgethdr returned %d", c);
return ERROR;
}
zmputs (_Attn);
continue;
case ZDATA:
if (_rclhdr (_Rxhdr) != rxbytes)
{
if ( --n < 0)
{
return ERROR;
}
zmputs (_Attn);
continue;
}
moredata:
if (_Verbose > 1)
{
(*_do_report) (1, &rxbytes);
if (!sent_zm)
{
sent_zm = TRUE;
_say ("ZMODEM%s", _Crc32 ? " CRC-32" : "");
}
}
switch (c = _zrdata (secbuf, KSIZE))
{
case ZCAN:
_vfile ("rzfile: _zgethdr returned %d", c);
return ERROR;
case ERROR: /* CRC error */
if (--n < 0)
{
_vfile ("rzfile: _zgethdr returned %d", c);
return ERROR;
}
zmputs (_Attn);
continue;
case ZTIMEOUT:
if (--n < 0)
{
_vfile ("rzfile: _zgethdr returned %d", c);
return ERROR;
}
continue;
case GOTCRCW:
n = 20;
putsec (secbuf, _Rxcount);
rxbytes += _Rxcount;
_stohdr (rxbytes);
_zshhdr (ZACK, _Txhdr);
_sendline (XON);
goto nxthdr;
case GOTCRCQ:
n = 20;
putsec (secbuf, _Rxcount);
rxbytes += _Rxcount;
_stohdr (rxbytes);
_zshhdr (ZACK, _Txhdr);
goto moredata;
case GOTCRCG:
n = 20;
putsec (secbuf, _Rxcount);
rxbytes += _Rxcount;
goto moredata;
case GOTCRCE:
n = 20;
putsec (secbuf, _Rxcount);
rxbytes += _Rxcount;
goto nxthdr;
} /* switch (c = _zrdata (secbuf, KSIZE)) */
} /* switch (c = _zgethdr (_Rxhdr, 0)) */
} /* for (;;) */
} /* static int rzfile (void) */
/****************************************************************************
* zmputs *
* Send a string to the modem, processing for \336 (sleep 1 sec) and \335 *
* (break signal). *
****************************************************************************/
static void zmputs (char *s)
{
int c;
while (*s)
{
switch (c = *s++)
{
case '\336':
sleep (1);
continue;
case '\335':
_sendbrk ();
continue;
default:
_sendline (c);
} /* switch (c = *s++) */
} /* while (*s) */
} /* static void zmputs (char *s) */
/****************************************************************************
* closeit *
* Close the receive dataset, return OK or ERROR. *
****************************************************************************/
static int closeit (void)
{
if (close (fout) == -1)
{
_zperr_ ("file close ERROR\n");
return ERROR;
}
#if 0
/* Bit fancy for MesS-DOS, what? */
if (Modtime)
{
timep[0] = time (NULL);
timep[1] = Modtime;
utime (Pathname, timep);
}
if (Filemode)
chmod (Pathname, (07777 & Filemode));
#endif
return OK;
} /* static int closeit (void) */
/****************************************************************************
* ackbibi *
* Ack a ZFIN packet, let bygones be bygones. *
****************************************************************************/
static void ackbibi (void)
{
int n;
_vfile ("ackbibi:");
Readnum = 1;
_stohdr (0L);
for (n = 3; --n >= 0;)
{
purgeline ();
_zshhdr (ZFIN, _Txhdr);
switch (_readline (100))
{
case 'O':
_readline (1); /* Discard 2nd 'O' */
_vfile ("ackbibi complete");
return;
case RCDO:
return;
case ZTIMEOUT:
default:
break;
} /* switch (_readline (100)) */
} /* for (n = 3; --n >= 0;) */
} /* static void ackbibi (void) */
/****************************************************************************
* sys2 *
* Strip leading ! if present, do shell escape. *
****************************************************************************/
static int sys2 (char *s)
{
if (*s == '!')
++s;
return system (s);
} /* static int sys2 (char *s) */
/****************************************************************************
* exec2 *
* Strip leading '!' if present and do an exec. *
****************************************************************************/
static void exec2 (char *s)
{
char *comspec; /* -> command.com */
int result; /* result of exec */
#ifdef DEBUGZ
_vfile ("exec2: exec %s\n", s);
#endif
if (*s == '!')
++s;
if ((comspec = getenv ("COMSPEC")) != NULL)
result = execl (comspec, "command", "/c", s, NULL);
else
result = execl ("command", "command", "/c", s, NULL);
if (result == -1)
perror ("exec2");
} /* static void exec2 (char *s) */
/* End of rz.c */