754 lines
18 KiB
C
754 lines
18 KiB
C
|
/*****************************************************************************
|
||
|
*
|
||
|
* Purpose ...............: Zmodem sender
|
||
|
*
|
||
|
*****************************************************************************
|
||
|
* Copyright (C) 1997-2011
|
||
|
*
|
||
|
* Michiel Broek FIDO: 2:280/2802
|
||
|
* Beekmansbos 10
|
||
|
* 1971 BV IJmuiden
|
||
|
* the Netherlands
|
||
|
*
|
||
|
* This file is part of MBSE BBS.
|
||
|
*
|
||
|
* This BBS is free software; you can redistribute it and/or modify it
|
||
|
* under the terms of the GNU General Public License as published by the
|
||
|
* Free Software Foundation; either version 2, or (at your option) any
|
||
|
* later version.
|
||
|
*
|
||
|
* MBSE BBS is distributed in the hope that it will be useful, but
|
||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with MBSE BBS; see the file COPYING. If not, write to the Free
|
||
|
* Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#include "../config.h"
|
||
|
#include "../lib/mbselib.h"
|
||
|
#include "ttyio.h"
|
||
|
#include "zmmisc.h"
|
||
|
#include "transfer.h"
|
||
|
#include "openport.h"
|
||
|
#include "timeout.h"
|
||
|
|
||
|
|
||
|
static int initsend(void);
|
||
|
static int sendzfile(char*);
|
||
|
static int finsend(void);
|
||
|
|
||
|
static int getzrxinit(void);
|
||
|
static int sendzsinit(void);
|
||
|
static int zfilbuf(void);
|
||
|
static int zsendfile(char*,int);
|
||
|
static int zsendfdata(void);
|
||
|
static int getinsync(int);
|
||
|
void initzsendmsk(char *p);
|
||
|
|
||
|
static FILE *in;
|
||
|
static int Eofseen; /* EOF seen on input set by zfilbuf */
|
||
|
static int Rxflags = 0;
|
||
|
static int Wantfcs32=TRUE; /* Want to send 32 bit FCS */
|
||
|
static int Rxbuflen;
|
||
|
static unsigned Txwindow; /* Control the size of the transmitted window */
|
||
|
static unsigned Txwspac; /* Spacing between zcrcq requests */
|
||
|
static unsigned Txwcnt; /* Counter used to space ack requests */
|
||
|
static int blklen = 128; /* Length of transmitted records */
|
||
|
static int blkopt; /* Override value for zmodem blklen */
|
||
|
static int errors;
|
||
|
static int Lastsync;
|
||
|
static int bytcnt;
|
||
|
static int maxbytcnt;
|
||
|
static int Lrxpos=0;
|
||
|
static int Lztrans=0;
|
||
|
static int Lzmanag=0;
|
||
|
static int Lskipnocor=0;
|
||
|
static int Lzconv=0;
|
||
|
static int Beenhereb4;
|
||
|
static int Canseek = 1; /* 1: Can seek 0: only rewind -1: neither (pipe) */
|
||
|
/*
|
||
|
* Attention string to be executed by receiver to interrupt streaming data
|
||
|
* when an error is detected. A pause (0336) may be needed before the
|
||
|
* ^C (03) or after it.
|
||
|
*/
|
||
|
static char Myattn[]={ 0 };
|
||
|
static int skipsize;
|
||
|
static jmp_buf intrjmp; /* For the interrupt on RX CAN */
|
||
|
|
||
|
struct timeval starttime, endtime;
|
||
|
struct timezone tz;
|
||
|
static int use8k = FALSE;
|
||
|
extern unsigned int sentbytes;
|
||
|
extern int Rxhlen;
|
||
|
extern int Rxtimeout;
|
||
|
extern char *txbuf;
|
||
|
extern char *frametypes[];
|
||
|
|
||
|
extern unsigned Baudrate;
|
||
|
|
||
|
|
||
|
/* Called when ZMODEM gets an interrupt (^X) */
|
||
|
void onintr(int );
|
||
|
void onintr(int c)
|
||
|
{
|
||
|
signal(SIGINT, SIG_IGN);
|
||
|
Syslog('z', "Zmodem: got signal interrupt");
|
||
|
longjmp(intrjmp, -1);
|
||
|
}
|
||
|
|
||
|
|
||
|
int zmsndfiles(down_list *lst, int try8)
|
||
|
{
|
||
|
int rc, maxrc = 0;
|
||
|
down_list *tmpf;
|
||
|
|
||
|
Syslog('+', "Zmodem: start Zmodem%s send", try8 ? "-8K":"");
|
||
|
|
||
|
get_frame_buffer();
|
||
|
|
||
|
use8k = try8;
|
||
|
protocol = ZM_ZMODEM;
|
||
|
Rxtimeout = 60;
|
||
|
bytcnt = maxbytcnt = -1;
|
||
|
|
||
|
if ((rc = initsend())) {
|
||
|
if (txbuf)
|
||
|
free(txbuf);
|
||
|
txbuf = NULL;
|
||
|
del_frame_buffer();
|
||
|
return abs(rc);
|
||
|
}
|
||
|
|
||
|
for (tmpf = lst; tmpf && (maxrc < 2); tmpf = tmpf->next) {
|
||
|
if (tmpf->remote) {
|
||
|
rc = sendzfile(tmpf->remote);
|
||
|
rc = abs(rc);
|
||
|
if (rc > maxrc)
|
||
|
maxrc = rc;
|
||
|
if (rc == 0) {
|
||
|
tmpf->sent = TRUE;
|
||
|
} else {
|
||
|
tmpf->failed = TRUE;
|
||
|
}
|
||
|
} else if (maxrc == 0) {
|
||
|
tmpf->failed = TRUE;
|
||
|
}
|
||
|
Syslog('z', "zmsndfiles: unlink(%s) returns %d", tmpf->remote, unlink(tmpf->remote));
|
||
|
}
|
||
|
|
||
|
if (maxrc < 2) {
|
||
|
rc = finsend();
|
||
|
rc = abs(rc);
|
||
|
}
|
||
|
|
||
|
if (rc > maxrc)
|
||
|
maxrc = rc;
|
||
|
|
||
|
if (txbuf)
|
||
|
free(txbuf);
|
||
|
txbuf = NULL;
|
||
|
del_frame_buffer();
|
||
|
io_mode(0, 1);
|
||
|
|
||
|
Syslog('z', "Zmodem: send rc=%d", maxrc);
|
||
|
return (maxrc < 2)?0:maxrc;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
static int initsend(void)
|
||
|
{
|
||
|
Syslog('z', "Zmodem: initsend");
|
||
|
|
||
|
io_mode(0, 1);
|
||
|
PUTSTR((char *)"rz\r");
|
||
|
stohdr(0L);
|
||
|
zshhdr(ZRQINIT, Txhdr);
|
||
|
|
||
|
if (getzrxinit()) {
|
||
|
Syslog('+', "Zmodem: Unable to initiate send");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Say "bibi" to the receiver, try to do it cleanly
|
||
|
*/
|
||
|
static int finsend(void)
|
||
|
{
|
||
|
int i, rc = 0;
|
||
|
|
||
|
Syslog('z', "Zmodem: finsend");
|
||
|
while (GETCHAR(1) >= 0) /*nothing*/;
|
||
|
for (i = 0; i < 30; i++) {
|
||
|
stohdr(0L);
|
||
|
zshhdr(ZFIN, Txhdr);
|
||
|
if ((rc = zgethdr(Rxhdr)) == ZFIN)
|
||
|
PUTSTR((char *)"OO");
|
||
|
if ((rc == ZFIN) || (rc == ZCAN) || (rc < 0))
|
||
|
break;
|
||
|
}
|
||
|
return (rc != ZFIN);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
static int sendzfile(char *rn)
|
||
|
{
|
||
|
int rc = 0;
|
||
|
struct stat st;
|
||
|
int bufl;
|
||
|
int sverr;
|
||
|
|
||
|
if (txbuf == NULL)
|
||
|
txbuf = malloc(MAXBLOCK + 1024);
|
||
|
|
||
|
skipsize = 0L;
|
||
|
if ((in = fopen(rn, "r")) == NULL) {
|
||
|
sverr = errno;
|
||
|
if ((sverr == ENOENT) || (sverr == EINVAL)) {
|
||
|
Syslog('+', "File %s doesn't exist, removing", MBSE_SS(rn));
|
||
|
return 0;
|
||
|
} else {
|
||
|
WriteError("$Zmodem: cannot open file %s, skipping", MBSE_SS(rn));
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (stat(rn,&st) != 0) {
|
||
|
Syslog('+', "$Zmodem: cannot access \"%s\", skipping",MBSE_SS(rn));
|
||
|
fclose(in);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
Syslog('+', "Zmodem: send \"%s\", %lu bytes, dated %s", MBSE_SS(rn), (unsigned int)st.st_size, rfcdate(st.st_mtime));
|
||
|
gettimeofday(&starttime, &tz);
|
||
|
|
||
|
snprintf(txbuf,MAXBLOCK + 1024,"%s %u %o %o 0 0 0", rn,
|
||
|
(unsigned int)st.st_size, (int)st.st_mtime + (int)(st.st_mtime % 2), st.st_mode);
|
||
|
bufl = strlen(txbuf);
|
||
|
*(strchr(txbuf,' ')) = '\0'; /*hope no blanks in filename*/
|
||
|
|
||
|
Eofseen = 0;
|
||
|
rc = zsendfile(txbuf,bufl);
|
||
|
if (rc == ZSKIP) {
|
||
|
Syslog('+', "Zmodem: remote skipped %s, is OK",MBSE_SS(rn));
|
||
|
return 0;
|
||
|
} else if ((rc == OK) && (st.st_size - skipsize)) {
|
||
|
gettimeofday(&endtime, &tz);
|
||
|
Syslog('+', "Zmodem: OK %s", transfertime(starttime, endtime, (unsigned int)st.st_size - skipsize, TRUE));
|
||
|
sentbytes += (unsigned int)st.st_size - skipsize;
|
||
|
return 0;
|
||
|
} else
|
||
|
return 2;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Get the receiver's init parameters
|
||
|
*/
|
||
|
int getzrxinit(void)
|
||
|
{
|
||
|
int n, timeouts = 0;
|
||
|
int old_timeout = Rxtimeout;
|
||
|
|
||
|
Rxtimeout = 10;
|
||
|
for (n = 10; --n >= 0; ) {
|
||
|
Syslog('z', "getzrxinit n=%d", n);
|
||
|
|
||
|
switch (zgethdr(Rxhdr)) {
|
||
|
case ZCHALLENGE: /* Echo receiver's challenge numbr */
|
||
|
stohdr(Rxpos);
|
||
|
zshhdr(ZACK, Txhdr);
|
||
|
continue;
|
||
|
case ZCOMMAND: /* They didn't see out ZRQINIT */
|
||
|
/* A receiver cannot send a command */
|
||
|
Syslog('z', "getzrxinit got ZCOMMAND");
|
||
|
stohdr(0L);
|
||
|
zshhdr(ZACK, Txhdr);
|
||
|
continue;
|
||
|
case ZRINIT:
|
||
|
Rxflags = 0377 & Rxhdr[ZF0];
|
||
|
Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
|
||
|
Zctlesc |= Rxflags & TESCCTL;
|
||
|
if (Rxhdr[ZF1] & ZRRQQQ) { /* Escape ctrls */
|
||
|
initzsendmsk(Rxhdr + ZRPXQQ);
|
||
|
Syslog('z', "Zmodem: requested ZRPXQQ");
|
||
|
}
|
||
|
|
||
|
Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
|
||
|
if ( !(Rxflags & CANFDX))
|
||
|
Txwindow = 0;
|
||
|
Syslog('z', "Zmodem: Rxbuflen=%d", Rxbuflen);
|
||
|
|
||
|
signal(SIGINT, SIG_IGN);
|
||
|
io_mode(0, 2); /* Set cbreak, XON/XOFF, etc. */
|
||
|
|
||
|
/* Set initial subpacket length */
|
||
|
if (blklen < 1024) { /* Command line override? */
|
||
|
if (Baudrate > 300)
|
||
|
blklen = 256;
|
||
|
if (Baudrate > 1200)
|
||
|
blklen = 512;
|
||
|
if (Baudrate > 2400)
|
||
|
blklen = 1024;
|
||
|
if (Baudrate < 300)
|
||
|
blklen = 1024;
|
||
|
}
|
||
|
if (Rxbuflen && blklen>Rxbuflen)
|
||
|
blklen = Rxbuflen;
|
||
|
if (blkopt && blklen > blkopt)
|
||
|
blklen = blkopt;
|
||
|
Syslog('z', "Rxbuflen=%d blklen=%d", Rxbuflen, blklen);
|
||
|
Syslog('z', "Txwindow = %u Txwspac = %d", Txwindow, Txwspac);
|
||
|
|
||
|
Lztrans = 0;
|
||
|
Rxtimeout = old_timeout;
|
||
|
|
||
|
return (sendzsinit());
|
||
|
case ZCAN:
|
||
|
case TIMEOUT:
|
||
|
if (timeouts++==0)
|
||
|
continue;
|
||
|
return TERROR;
|
||
|
case HANGUP:
|
||
|
return HANGUP;
|
||
|
case ZRQINIT:
|
||
|
if (Rxhdr[ZF0] == ZCOMMAND)
|
||
|
continue;
|
||
|
default:
|
||
|
zshhdr(ZNAK, Txhdr);
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
return TERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Send send-init information
|
||
|
*/
|
||
|
int sendzsinit(void)
|
||
|
{
|
||
|
int c;
|
||
|
|
||
|
if (Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL)))
|
||
|
return OK;
|
||
|
errors = 0;
|
||
|
for (;;) {
|
||
|
stohdr(0L);
|
||
|
if (Zctlesc) {
|
||
|
Txhdr[ZF0] |= TESCCTL; zshhdr(ZSINIT, Txhdr);
|
||
|
} else
|
||
|
zsbhdr(ZSINIT, Txhdr);
|
||
|
Syslog('z', "sendzsinit Myattn \"%s\"", printable(Myattn, 0));
|
||
|
// zsdata(Myattn, 1 + strlen(Myattn), ZCRCW);
|
||
|
zsdata(Myattn, ZATTNLEN, ZCRCW);
|
||
|
c = zgethdr(Rxhdr);
|
||
|
switch (c) {
|
||
|
case ZCAN: return TERROR;
|
||
|
case HANGUP: return HANGUP;
|
||
|
case ZACK: return OK;
|
||
|
default: if (++errors > 19)
|
||
|
return TERROR;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Fill buffer with blklen chars
|
||
|
*/
|
||
|
int zfilbuf(void)
|
||
|
{
|
||
|
int n;
|
||
|
|
||
|
n = fread(txbuf, 1, blklen, in);
|
||
|
if (n < blklen) {
|
||
|
Eofseen = 1;
|
||
|
Syslog('z', "zfilbuf return %d", n);
|
||
|
}
|
||
|
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Send file name and related info
|
||
|
*/
|
||
|
int zsendfile(char *buf, int blen)
|
||
|
{
|
||
|
int c, i, m, n;
|
||
|
register unsigned int crc = -1;
|
||
|
int lastcrcrq = -1;
|
||
|
int lastcrcof = -1;
|
||
|
int l;
|
||
|
char *p;
|
||
|
|
||
|
Syslog('z', "zsendfile %s (%d)", buf, blen);
|
||
|
for (errors=0; ++errors<11;) {
|
||
|
Txhdr[ZF0] = Lzconv; /* file conversion request */
|
||
|
Txhdr[ZF1] = Lzmanag; /* file management request */
|
||
|
if (Lskipnocor)
|
||
|
Txhdr[ZF1] |= ZMSKNOLOC;
|
||
|
Txhdr[ZF2] = Lztrans; /* file transport request */
|
||
|
Txhdr[ZF3] = 0;
|
||
|
zsbhdr(ZFILE, Txhdr);
|
||
|
zsdata(buf, blen, ZCRCW);
|
||
|
again:
|
||
|
c = zgethdr(Rxhdr);
|
||
|
switch (c) {
|
||
|
case ZRINIT:
|
||
|
while ((c = GETCHAR(5)) > 0)
|
||
|
if (c == ZPAD) {
|
||
|
goto again;
|
||
|
}
|
||
|
continue;
|
||
|
case ZRQINIT:
|
||
|
Syslog('+', "got ZRQINIT, a zmodem sender talks to this sender");
|
||
|
return TERROR;
|
||
|
case ZCAN:
|
||
|
case TIMEOUT:
|
||
|
case ZABORT:
|
||
|
case ZFIN:
|
||
|
Syslog('+', "Zmodem: Got %s on pathname", frametypes[c+FTOFFSET]);
|
||
|
return TERROR;
|
||
|
default:
|
||
|
Syslog('+', "Zmodem: Got %d frame type on pathname", c);
|
||
|
continue;
|
||
|
case TERROR:
|
||
|
case ZNAK:
|
||
|
continue;
|
||
|
case ZCRC:
|
||
|
l = Rxhdr[9] & 0377;
|
||
|
l = (l<<8) + (Rxhdr[8] & 0377);
|
||
|
l = (l<<8) + (Rxhdr[7] & 0377);
|
||
|
l = (l<<8) + (Rxhdr[6] & 0377);
|
||
|
if (Rxpos != lastcrcrq || l != lastcrcof) {
|
||
|
lastcrcrq = Rxpos;
|
||
|
crc = 0xFFFFFFFFL;
|
||
|
// fseek(in, 0L, 0);
|
||
|
// while (((c = getc(in)) != EOF) && --lastcrcrq)
|
||
|
// crc = updcrc32(c, crc);
|
||
|
// crc = ~crc;
|
||
|
// clearerr(in); /* Clear possible EOF */
|
||
|
// lastcrcrq = Rxpos;
|
||
|
|
||
|
if (Canseek >= 0) {
|
||
|
fseek(in, bytcnt = l, 0); i = 0;
|
||
|
Syslog('z', "Zmodem: CRC32 on %ld bytes", Rxpos);
|
||
|
do {
|
||
|
/* No rx timeouts! */
|
||
|
if (--i < 0) {
|
||
|
i = 32768L/blklen;
|
||
|
PUTCHAR(SYN);
|
||
|
fflush(stdout);
|
||
|
}
|
||
|
bytcnt += m = n = zfilbuf();
|
||
|
if (bytcnt > maxbytcnt)
|
||
|
maxbytcnt = bytcnt;
|
||
|
for (p = txbuf; --m >= 0; ++p) {
|
||
|
c = *p & 0377;
|
||
|
crc = updcrc32(c, crc);
|
||
|
}
|
||
|
Syslog('z', "bytcnt=%d crc=%08X", bytcnt, crc);
|
||
|
} while (n && bytcnt < lastcrcrq);
|
||
|
crc = ~crc;
|
||
|
clearerr(in); /* Clear possible EOF */
|
||
|
}
|
||
|
}
|
||
|
stohdr(crc);
|
||
|
zsbhdr(ZCRC, Txhdr);
|
||
|
goto again;
|
||
|
case ZFERR:
|
||
|
case ZSKIP:
|
||
|
Syslog('+', "Zmodem: File skipped by receiver request");
|
||
|
fclose(in); return c;
|
||
|
case ZRPOS:
|
||
|
/*
|
||
|
* Suppress zcrcw request otherwise triggered by
|
||
|
* lastyunc==bytcnt
|
||
|
*/
|
||
|
Syslog('z', "got ZRPOS %d", Rxpos);
|
||
|
if (Rxpos > 0)
|
||
|
skipsize = Rxpos;
|
||
|
if (fseek(in, Rxpos, 0))
|
||
|
return TERROR;
|
||
|
Lastsync = (maxbytcnt = bytcnt = Txpos = Lrxpos = Rxpos) -1;
|
||
|
return zsendfdata();
|
||
|
}
|
||
|
}
|
||
|
fclose(in);
|
||
|
return TERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Send the data in the file
|
||
|
*/
|
||
|
int zsendfdata(void)
|
||
|
{
|
||
|
int c = 0, e, n;
|
||
|
int newcnt;
|
||
|
int tcount = 0;
|
||
|
int junkcount; /* Counts garbage chars received by TX */
|
||
|
int maxblklen;
|
||
|
|
||
|
if (use8k)
|
||
|
maxblklen = 8192;
|
||
|
else
|
||
|
maxblklen = 1024;
|
||
|
Syslog('z', "zsendfdata() maxblklen=%d", maxblklen);
|
||
|
|
||
|
junkcount = 0;
|
||
|
Beenhereb4 = 0;
|
||
|
somemore:
|
||
|
if (setjmp(intrjmp)) {
|
||
|
Syslog('z', "zsendfdata() at label somemore");
|
||
|
waitack:
|
||
|
junkcount = 0;
|
||
|
c = getinsync(0);
|
||
|
gotack:
|
||
|
switch (c) {
|
||
|
default:
|
||
|
case ZCAN: fclose(in);
|
||
|
return TERROR;
|
||
|
case ZRINIT: fclose(in);
|
||
|
return ZSKIP;
|
||
|
case ZSKIP: fclose(in);
|
||
|
return c;
|
||
|
case ZACK: Syslog('z', "zmsend: got ZACK");
|
||
|
break; // Possible bug, added 23-08-99
|
||
|
case ZRPOS: /* blklen = ((blklen >> 2) > 64) ? (blklen >> 2) : 64;
|
||
|
goodblks = 0;
|
||
|
goodneeded = ((goodneeded << 1) > 16) ? 16 : goodneeded << 1;
|
||
|
Syslog('z', "zmsend: blocklen now %d", blklen); */
|
||
|
break;
|
||
|
// case TIMEOUT: /* Put back here 08-09-1999 mb */
|
||
|
// Syslog('z', "zmsend: zsendfdata TIMEOUT");
|
||
|
// goto to;
|
||
|
// case HANGUP: /* New, added 08-09-1999 mb */
|
||
|
// Syslog('z', "zmsend: zsendfdata HANGUP");
|
||
|
// fclose(in);
|
||
|
// return c;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If the reverse channel can be tested for data,
|
||
|
* this logic may be used to detect error packets
|
||
|
* sent by the receiver, in place of setjmp/longjmp
|
||
|
* rdchk(fd) returns non 0 if a character is available
|
||
|
*/
|
||
|
if (TCHECK()) {
|
||
|
c = GETCHAR(1);
|
||
|
Syslog('z', "zsendfdata(): 1 check getchar(1)=%d %c", c, c);
|
||
|
if (c < 0) {
|
||
|
return c;
|
||
|
} else switch (c) {
|
||
|
case CAN:
|
||
|
case ZPAD: c = getinsync(1);
|
||
|
goto gotack;
|
||
|
case XOFF: /* Wait a while for an XON */
|
||
|
case XOFF|0200: GETCHAR(10);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
signal(SIGINT, onintr);
|
||
|
newcnt = Rxbuflen;
|
||
|
Txwcnt = 0;
|
||
|
stohdr(Txpos);
|
||
|
zsbhdr(ZDATA, Txhdr);
|
||
|
|
||
|
do {
|
||
|
n = zfilbuf();
|
||
|
if (Eofseen)
|
||
|
e = ZCRCE;
|
||
|
else if (junkcount > 3)
|
||
|
e = ZCRCW;
|
||
|
else if (bytcnt == Lastsync)
|
||
|
e = ZCRCW;
|
||
|
else if (Rxbuflen && (newcnt -= n) <= 0)
|
||
|
e = ZCRCW;
|
||
|
else if (Txwindow && (Txwcnt += n) >= Txwspac) {
|
||
|
Txwcnt = 0; e = ZCRCQ;
|
||
|
} else
|
||
|
e = ZCRCG;
|
||
|
Nopper();
|
||
|
alarm_on();
|
||
|
zsdata(txbuf, n, e);
|
||
|
bytcnt = Txpos += n;
|
||
|
if (bytcnt > maxbytcnt)
|
||
|
maxbytcnt = bytcnt;
|
||
|
|
||
|
// if ((blklen < maxblklen) && (++goodblks > goodneeded)) {
|
||
|
// blklen = ((blklen << 1) < maxblklen) ? blklen << 1 : maxblklen;
|
||
|
// goodblks = 0;
|
||
|
// Syslog('z', "zmsend: blocklen now %d", blklen);
|
||
|
// }
|
||
|
|
||
|
if (e == ZCRCW)
|
||
|
goto waitack;
|
||
|
/*
|
||
|
* If the reverse channel can be tested for data,
|
||
|
* this logic may be used to detect error packets
|
||
|
* sent by the receiver, in place of setjmp/longjmp
|
||
|
* rdchk(fd) returns non 0 if a character is available
|
||
|
*/
|
||
|
if (TCHECK()) {
|
||
|
c = GETCHAR(1);
|
||
|
Syslog('z', "zsendfdata(): 2 check getchar(1)=%d %c", c, c);
|
||
|
if (c < 0) {
|
||
|
return c;
|
||
|
} else switch (c) {
|
||
|
case CAN:
|
||
|
case ZPAD: c = getinsync(1);
|
||
|
if (c == ZACK)
|
||
|
break;
|
||
|
/* zcrce - dinna wanna starta ping-pong game */
|
||
|
zsdata(txbuf, 0, ZCRCE);
|
||
|
goto gotack;
|
||
|
case XOFF: /* Wait a while for an XON */
|
||
|
case XOFF|0200: GETCHAR(10);
|
||
|
default: ++junkcount;
|
||
|
}
|
||
|
}
|
||
|
if (Txwindow) {
|
||
|
while ((tcount = (Txpos - Lrxpos)) >= Txwindow) {
|
||
|
Syslog('z', "%ld window >= %u", tcount, Txwindow);
|
||
|
if (e != ZCRCQ)
|
||
|
zsdata(txbuf, 0, e = ZCRCQ);
|
||
|
c = getinsync(1);
|
||
|
if (c != ZACK) {
|
||
|
zsdata(txbuf, 0, ZCRCE);
|
||
|
goto gotack;
|
||
|
}
|
||
|
}
|
||
|
Syslog('z', "window = %ld", tcount);
|
||
|
}
|
||
|
} while (!Eofseen);
|
||
|
signal(SIGINT, SIG_IGN);
|
||
|
|
||
|
for (;;) {
|
||
|
stohdr(Txpos);
|
||
|
zsbhdr(ZEOF, Txhdr);
|
||
|
egotack:
|
||
|
switch (getinsync(0)) {
|
||
|
case ZACK: Syslog('z', "zsendfdata() ZACK");
|
||
|
goto egotack; // continue in old source
|
||
|
case ZNAK: continue;
|
||
|
case ZRPOS: goto somemore;
|
||
|
case ZRINIT: fclose(in);
|
||
|
return OK;
|
||
|
case ZSKIP: fclose(in);
|
||
|
Syslog('+', "Zmodem: File skipped by receiver request");
|
||
|
return ZSKIP;
|
||
|
default: Syslog('+', "Zmodem: Got %d trying to send end of file", c);
|
||
|
case TERROR: fclose(in);
|
||
|
return TERROR;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Respond to receiver's complaint, get back in sync with receiver
|
||
|
*/
|
||
|
int getinsync(int flag)
|
||
|
{
|
||
|
int c = 0;
|
||
|
|
||
|
Syslog('z', "getinsync(%d)", flag);
|
||
|
|
||
|
for (;;) {
|
||
|
c = zgethdr(Rxhdr);
|
||
|
switch (c) {
|
||
|
case HANGUP: return HANGUP;
|
||
|
case ZCAN:
|
||
|
case ZABORT:
|
||
|
case ZFIN:
|
||
|
/* case TERROR: */
|
||
|
case TIMEOUT: Syslog('+', "Zmodem: Got %s sending data", frametypes[c+FTOFFSET]);
|
||
|
return TERROR;
|
||
|
case ZRPOS: if (Rxpos > bytcnt) {
|
||
|
Syslog('z', "Zmodem: getinsync: Rxpos=%lx bytcnt=%lx Maxbytcnt=%lx",
|
||
|
Rxpos, bytcnt, maxbytcnt);
|
||
|
if (Rxpos > maxbytcnt)
|
||
|
Syslog('+', "Nonstandard Protocol at %lX", Rxpos);
|
||
|
return ZRPOS;
|
||
|
}
|
||
|
/* ************************************* */
|
||
|
/* If sending to a buffered modem, you */
|
||
|
/* might send a break at this point to */
|
||
|
/* dump the modem's buffer. */
|
||
|
clearerr(in); /* In case file EOF seen */
|
||
|
if (fseek(in, Rxpos, 0)) {
|
||
|
Syslog('+', "Zmodem: Bad Seek to %ld", Rxpos);
|
||
|
return TERROR;
|
||
|
}
|
||
|
Eofseen = 0;
|
||
|
bytcnt = Lrxpos = Txpos = Rxpos;
|
||
|
if (Lastsync == Rxpos) {
|
||
|
if (++Beenhereb4 > 12) {
|
||
|
Syslog('+', "Zmodem: Can't send block");
|
||
|
return TERROR;
|
||
|
}
|
||
|
if (Beenhereb4 > 4) {
|
||
|
if (blklen > 32) {
|
||
|
blklen /= 2;
|
||
|
Syslog('z', "Zmodem: blocklen now %d", blklen);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
Beenhereb4=0;
|
||
|
}
|
||
|
Lastsync = Rxpos;
|
||
|
return c;
|
||
|
case ZACK: Lrxpos = Rxpos;
|
||
|
if (flag || Txpos == Rxpos)
|
||
|
return ZACK;
|
||
|
continue;
|
||
|
case ZRINIT: return c;
|
||
|
case ZSKIP: Syslog('+', "Zmodem: File skipped by receiver request");
|
||
|
return c;
|
||
|
case TERROR:
|
||
|
default: zsbhdr(ZNAK, Txhdr);
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Set additional control chars to mask in Zsendmask
|
||
|
* according to bit array stored in char array at p
|
||
|
*/
|
||
|
void initzsendmsk(char *p)
|
||
|
{
|
||
|
int c;
|
||
|
|
||
|
for (c = 0; c < 33; ++c) {
|
||
|
if (p [c >> 3] & (1 << (c & 7))) {
|
||
|
Zsendmask[c] = 1;
|
||
|
Syslog('z', "Zmodem: escaping %02o", c);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|