Example #1
0
/*
 * Ack a ZFIN packet, let byegones be byegones
 */
int ackbibi(void)
{
    int n;
    int c;

    Syslog('z', "ackbibi:");
    stohdr(0L);
	
    for (n=3; --n>=0; ) {
	zshhdr(ZFIN, Txhdr);
		
	switch ((c = GETCHAR(10))) {
	    case 'O':	    GETCHAR(1);	/* Discard 2nd 'O' */
			    Syslog('z', "Zmodem: ackbibi complete");
			    return ZCOMPL;
	    case TERROR:
	    case HANGUP:    Syslog('z', "Zmodem: ackbibi got %d, ignore",c);
			    return 0;
	    case TIMEOUT:
	    default:	    Syslog('z', "Zmodem: ackbibi got '%s', continue", printablec(c));
			    break;
	}
    }
    return ZCOMPL;
}
Example #2
0
/*
 * Ack a ZFIN packet, let byegones be byegones
 */
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 TIMEOUT:
		default:
			break;
		}
	}
}
Example #3
0
/*
 * Receive a file with ZMODEM protocol
 *  Assumes file name frame is in secbuf
 */
static int rzfile(void)
{
	int c, n;
	long last_rxbytes = 0;
	long not_printed = 0;

	last_bps = 0;
	Eofseen = FALSE;

	n = 20;
	rxbytes = 0l;

	if (procheader(secbuf) == ERROR) {
		return (tryzhdrtype = ZSKIP);
	}


	for (;;) {
		stohdr(rxbytes);
		zshhdr(ZRPOS, Txhdr);
	      nxthdr:
		switch (c = zgethdr(Rxhdr, 0)) {
		default:
			vfile("lrzfile: zgethdr returned %d", c);
			return ERROR;
		case ZNAK:
		case TIMEOUT:
			if (--n < 0) {
				vfile("lrzfile: zgethdr returned %d", c);
				return ERROR;
			}
		case ZFILE:
			zrdata(secbuf, MAX_BLOCK);
			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 (Verbose > 1) {
				int minleft = 0;
				int secleft = 0;
				last_bps = (rxbytes / timing(0));
				if (last_bps > 0) {
					minleft =
					    (Bytesleft -
					     rxbytes) / last_bps / 60;
					secleft =
					    ((Bytesleft - rxbytes) /
					     last_bps) % 60;
				}
				fprintf(stderr,
					"\rBytes Received: %7ld/%7ld   BPS:%-6d                   \r\n",
					rxbytes, Bytesleft, last_bps);
			}
			closeok = 1;
			if (closeit()) {
				tryzhdrtype = ZFERR;
				vfile("lrzfile: closeit returned <> 0");
				return ERROR;
			}
			vfile("lrzfile: normal EOF");
			return c;
		case ERROR:	/* Too much garbage in header search error */
			if (--n < 0) {
				vfile("lrzfile: zgethdr returned %d", c);
				return ERROR;
			}
			zmputs(Attn);
			continue;
		case ZSKIP:
			closeit();
			vfile("lrzfile: Sender SKIPPED file");
			return c;
		case ZDATA:
			if (rclhdr(Rxhdr) != rxbytes) {
				if (--n < 0) {
					return ERROR;
				}
				zmputs(Attn);
				continue;
			}
		      moredata:
			if (Verbose > 1
			    && (not_printed > 7
				|| rxbytes >
				last_bps / 2 + last_rxbytes)) {
				int minleft = 0;
				int secleft = 0;
				last_bps = (rxbytes / timing(0));
				if (last_bps > 0) {
					minleft =
					    (Bytesleft -
					     rxbytes) / last_bps / 60;
					secleft =
					    ((Bytesleft - rxbytes) /
					     last_bps) % 60;
				}
				fprintf(stderr,
					"\rBytes Received: %7ld/%7ld   BPS:%-6d ETA %02d:%02d  ",
					rxbytes, Bytesleft, last_bps,
					minleft, secleft);
				last_rxbytes = rxbytes;
				not_printed = 0;
				if (nodeinf != -1 && ((time(0) - lup) > 5)) {
					lseek(nodeinf, 0, SEEK_SET);
					nin.ddn_bpsrate = last_bps;
					sprintf(nin.ddn_activity,
						"UL: %-34.34s", myname);
					write(nodeinf, &nin,
					      sizeof(struct
						     DayDream_NodeInfo));
					lup = time(0);
				}
			} else if (Verbose)
				not_printed++;
			switch (c = zrdata(secbuf, MAX_BLOCK)) {
			case ZCAN:
				vfile("lrzfile: zgethdr returned %d", c);
				return ERROR;
			case ERROR:	/* CRC error */
				if (--n < 0) {
					vfile
					    ("lrzfile: zgethdr returned %d",
					     c);
					return ERROR;
				}
				zmputs(Attn);
				continue;
			case TIMEOUT:
				if (--n < 0) {
					vfile
					    ("lrzfile: zgethdr returned %d",
					     c);
					return ERROR;
				}
				continue;
			case GOTCRCW:
				n = 20;
				putsec(secbuf, Rxcount);
				rxbytes += Rxcount;
				stohdr(rxbytes);
				zshhdr(ZACK, Txhdr);
				xsendline(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;
			}
		}
	}
}
Example #4
0
/*
 * 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;

	for (n = Zmodem ? 15 : 5; --n >= 0;) {
		/* Set buffer length (0) and capability flags */
		stohdr(0L);
		Txhdr[ZF0] = CANFC32 | CANFDX | CANOVIO | CANBRK;
		if (Zctlesc)
			Txhdr[ZF0] |= TESCCTL;	/* TESCCTL == ESCCTL */
		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 TIMEOUT:
			continue;
		case ZFILE:
			zconv = Rxhdr[ZF0];
			zmanag = Rxhdr[ZF1];
			ztrans = Rxhdr[ZF2];
			tryzhdrtype = ZRINIT;
			c = zrdata(secbuf, MAX_BLOCK);
			mode(3);
			if (c == GOTCRCW)
				return ZFILE;
			zshhdr(ZNAK, Txhdr);
			goto again;
		case ZSINIT:
			Zctlesc = TESCCTL & Rxhdr[ZF0];
			if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
				stohdr(1L);
				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, MAX_BLOCK) == GOTCRCW) {
				if (Verbose) {
					fprintf(stderr,
						"lrz: remote requested command\n");
					fprintf(stderr, "lrz: %s\n",
						secbuf);
				}
				if (Verbose)
					fprintf(stderr,
						"lrz: not executed\n");
				zshhdr(ZCOMPL, Txhdr);
				return ZCOMPL;
			}
			goto again;
		case ZCOMPL:
			goto again;
		default:
			continue;
		case ZFIN:
			ackbibi();
			return ZCOMPL;
		case ZCAN:
			return ERROR;
		}
	}
	return 0;
}
Example #5
0
static int wcs(const char *oname, const char *remotename)
{
#if !defined(S_ISDIR)
    int c;
#endif
    struct stat f;
    char *name;
    struct zm_fileinfo zi;

#ifdef HAVE_MMAP
    int dont_mmap_this = 0;
#endif


    if (Restricted) {
        /* restrict pathnames to current tree or uucppublic */
        if (strstr(oname, "../")
#ifdef PUBDIR
            || (oname[0] == '/' && strncmp(oname, MK_STRING(PUBDIR), strlen(MK_STRING(PUBDIR))))
#endif
            ) {
            canit(0);
            zmodem_error(1, 0, "security violation: not allowed to upload from %s", oname);
        }
    }

    if (0 == strcmp(oname, "-")) {
        char *p = getenv("ONAME");

        name = (char *)malloc(PATH_MAX + 1);
        if (p) {
            strcpy(name, p);
        } else {
            sprintf(name, "s%lu.lsz", (unsigned long) getpid());
        }
        input_f = stdin;
#ifdef HAVE_MMAP
        dont_mmap_this = 1;
#endif
    } else if ((input_f = fopen(oname, "r")) == NULL) {
        ++errcnt;
        return OK;              /* pass over it, there may be others */
    } else {
        name = (char *)malloc(PATH_MAX + 1);
        strcpy(name, oname);
    }
#ifdef HAVE_MMAP
    if (!use_mmap || dont_mmap_this)
#endif
    {
        static char *s = NULL;
        static size_t last_length = 0;
        struct stat st;

        if (fstat(fileno(input_f), &st) == -1)
            st.st_size = 1024 * 1024;
        if (buffersize == (size_t) - 1 && s) {
            if ((size_t) st.st_size > last_length) {
                free(s);
                s = NULL;
                last_length = 0;
            }
        }
        if (!s && buffersize) {
            last_length = 16384;
            if (buffersize == (size_t) - 1) {
                if (st.st_size > 0)
                    last_length = st.st_size;
            } else
                last_length = buffersize;
            /* buffer whole pages */
            last_length = (last_length + 4095) & 0xfffff000;
            s = malloc(last_length);
            if (!s) {
                exit(1);
            }
        }
        if (s) {
#ifdef SETVBUF_REVERSED
            setvbuf(input_f, _IOFBF, s, last_length);
#else
            setvbuf(input_f, s, _IOFBF, last_length);
#endif
        }
    }
    vpos = 0;
    /* Check for directory or block special files */
    fstat(fileno(input_f), &f);
#if defined(S_ISDIR)
    if (S_ISDIR(f.st_mode) || S_ISBLK(f.st_mode)) {
#else
    c = f.st_mode & S_IFMT;
    if (c == S_IFDIR || c == S_IFBLK) {
#endif
        fclose(input_f);
	free(name);
        return OK;
    }

    if (remotename) {
        /* disqualify const */
        union {
            const char *c;
            char *s;
        } cheat;

        cheat.c = remotename;
        zi.fname = cheat.s;
    } else
        zi.fname = name;
    zi.modtime = f.st_mtime;
    zi.mode = f.st_mode;
#if defined(S_ISFIFO)
    zi.bytes_total = (S_ISFIFO(f.st_mode)) ? DEFBYTL : f.st_size;
#else
    zi.bytes_total = c == S_IFIFO ? DEFBYTL : f.st_size;
#endif
    zi.bytes_sent = 0;
    zi.bytes_received = 0;
    zi.bytes_skipped = 0;
    zi.eof_seen = 0;

    ++Filcnt;
    free(name);
    switch (wctxpn(&zi)) {
    case ERROR:
        return ERROR;
    case ZSKIP:
        return OK;
    }
    if (!zmodem_requested && wctx(&zi) == ERROR) {
        return ERROR;
    }
    if (Unlinkafter)
        unlink(oname);

    return 0;
}

/*
 * generate and transmit pathname block consisting of
 *  pathname (null terminated),
 *  file length, mode time and file mode in octal
 *  as provided by the Unix fstat call.
 *  N.B.: modifies the passed name, may extend it!
 */
static int wctxpn(struct zm_fileinfo *zi)
{
    register char *p, *q;
    char *name2;
    struct stat f;

    name2 = (char *)malloc(PATH_MAX + 1);

    if (protocol == ZM_XMODEM) {
        free(name2);
        return OK;
    }
    if (!zmodem_requested)
        if (getnak()) {
            free(name2);
            return ERROR;
        }

    q = (char *) 0;
#if 0
    if (Dottoslash) {           /* change . to . */
        for (p = zi->fname; *p; ++p) {
            if (*p == '/')
                q = p;
            else if (*p == '.')
                *(q = p) = '/';
        }
        if (q && strlen(++q) > 8) {     /* If name>8 chars */
            q += 8;             /*   make it .ext */
            strcpy(name2, q);   /* save excess of name */
            *q = '.';
            strcpy(++q, name2); /* add it back */
        }
    }
#endif
    for (p = zi->fname, q = txbuf; *p;)
        if ((*q++ = *p++) == '/' && !Fullname)
            q = txbuf;
    *q++ = 0;
    p = q;
    while (q < (txbuf + MAX_BLOCK))
        *q++ = 0;
    /* note that we may lose some information here in case mode_t is wider than an 
     * int. But i believe sending %lo instead of %o _could_ break compatability
     */
    if (!Ascii && (input_f != stdin) && *zi->fname && fstat(fileno(input_f), &f) != -1)
        sprintf(p, "%lu %lo %o 0 %d %ld", (long) f.st_size, f.st_mtime, (unsigned int) ((no_unixmode) ? 0 : f.st_mode), Filesleft, Totalleft);
    Totalleft -= f.st_size;
    if (--Filesleft <= 0)
        Totalleft = 0;
    if (Totalleft < 0)
        Totalleft = 0;

    /* force 1k blocks if name won't fit in 128 byte block */
    if (txbuf[125])
        blklen = 1024;
    else {                      /* A little goodie for IMP/KMD */
        txbuf[127] = (f.st_size + 127) >> 7;
        txbuf[126] = (f.st_size + 127) >> 15;
    }
    if (zmodem_requested)
        free(name2);
        return zsendfile(zi, txbuf, 1 + strlen(p) + (p - txbuf));

	/*
    if (wcputsec(txbuf, 0, 128) == ERROR) {
        free(name2);
        return ERROR;
    }
    free(name2);
    return OK;
	*/
}

static int getnak(void)
{
    int firstch;
    int tries = 0;

    Lastrx = 0;
    for (;;) {
        tries++;
        switch (firstch = READLINE_PF(100)) {
        case ZPAD:
            if (getzrxinit())
                return ERROR;
            Ascii = 0;          /* Receiver does the conversion */
            return FALSE;
        case TIMEOUT:
            /* 30 seconds are enough */
            if (tries == 3) {
                return TRUE;
            }
            /* don't send a second ZRQINIT _directly_ after the
             * first one. Never send more then 4 ZRQINIT, because
             * omen rz stops if it saw 5 of them */
            if ((zrqinits_sent > 1 || tries > 1) && zrqinits_sent < 4) {
                /* if we already sent a ZRQINIT we are using zmodem
                 * protocol and may send further ZRQINITs 
                 */
                stohdr(0L);
                zshhdr(ZRQINIT, Txhdr);
                zrqinits_sent++;
            }
            continue;
        case WANTG:
            io_mode(io_mode_fd, 2);     /* Set cbreak, XON/XOFF, etc. */
            Optiong = TRUE;
            blklen = 1024;
        case WANTCRC:
            Crcflg = TRUE;
        case NAK:
            return FALSE;
        case CAN:
            if ((firstch = READLINE_PF(20)) == CAN && Lastrx == CAN)
                return TRUE;
        default:
            break;
        }
        Lastrx = firstch;
    }
}
Example #6
0
int bbs_zsendfile(char *filename, char *remote)
{
    struct stat f;

    if (stat(filename, &f) != 0)
        return ERROR;
    Totalleft = f.st_size;
    Filesleft = 1;
    calc_blklen(Totalleft);
    protocol = ZM_ZMODEM;
    io_mode_fd = 1;
    blklen = start_blklen = 1024;
    if (setjmp(zmodemjmp) == 0) {
        zsendline_init();
        io_mode(io_mode_fd, 1);
        readline_setup(io_mode_fd, 128, 256);
        raw_write(0, "rz\r", 3);

        /*   TODO : throw away received input */

        purgeline(io_mode_fd);
        stohdr(0L);
        zshhdr(ZRQINIT, Txhdr);
        zrqinits_sent++;
        oflush();

        Crcflg = FALSE;
        firstsec = TRUE;
        bytcnt = (size_t) - 1;
        Totsecs = 0;

        if (wcs(filename, remote) == ERROR) {
            readline_clean();
            return ERROR;
        }
        if (zmodem_requested)
            saybibi();
        else if (protocol != ZM_XMODEM) {
            struct zm_fileinfo zi;
            char *pa;

            pa = (char *)malloc(PATH_MAX + 1);
            *pa = '\0';
            zi.fname = pa;
            zi.modtime = 0;
            zi.mode = 0;
            zi.bytes_total = 0;
            zi.bytes_sent = 0;
            zi.bytes_received = 0;
            zi.bytes_skipped = 0;
            wctxpn(&zi);
            free(pa);
        }

        oflush();
        /* here needs a oflush */
        /* eat avalible input */
        /* better to eat some input here */
        io_mode(io_mode_fd, 0);
        readline_clean();
    } else {
        oflush();
        signal(SIGALRM, SIG_IGN);
        alarm(0);
        return ERROR;
    }
    return OK;
}
Example #7
0
/*
 * Receive a file with ZMODEM protocol
 *  Assumes file name frame is in secbuf
 */
int rzfile(void)
{
    int	c, n;

    Eofseen=FALSE;
    rxbytes = 0l;
    if ((c = procheader(secbuf))) {
	return (tryzhdrtype = c);
    }

    n = 20;

    for (;;) {
	stohdr(rxbytes);
	zshhdr(ZRPOS, Txhdr);
nxthdr:
	switch (c = zgethdr(Rxhdr)) {
	    default:	    Syslog('z', "rzfile: Wrong header %d", c);
			    if ( --n < 0) {
				Syslog('+', "Zmodem: wrong header %d", c);
				return TERROR;
			    }
			    continue;
	    case ZCAN:	    Syslog('+', "Zmodem: sender CANcelled");
			    return TERROR;
	    case ZNAK:	    if ( --n < 0) {
				Syslog('+', "Zmodem: Got ZNAK");
				return TERROR;
			    }
			    continue;
	    case TIMEOUT:   if ( --n < 0) {
				Syslog('z', "Zmodem: TIMEOUT");
				return TERROR;
			    }
			    continue;
	    case ZFILE:	    zrdata(secbuf, MAXBLOCK);
			    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(1)) {
				tryzhdrtype = ZFERR;
				Syslog('+', "Zmodem: error closing file");
				return TERROR;
			    }
			    fout = NULL;
			    Syslog('z', "rzfile: normal EOF");
			    return c;
	    case HANGUP:    Syslog('+', "Zmodem: Lost Carrier");
			    return TERROR;
	    case TERROR:    /* Too much garbage in header search error */
			    if (--n < 0) {
				Syslog('+', "Zmodem: Too many errors");
				return TERROR;
			    }
			    zmputs(Attn);
			    continue;
	    case ZSKIP:	    Modtime = 1;
			    closeit(1);
			    Syslog('+', "Zmodem: Sender SKIPPED file");
			    return c;
	    case ZDATA:	    if (rclhdr(Rxhdr) != rxbytes) {
				if ( --n < 0) {
				    Syslog('+', "Zmodem: Data has bad address");
				    return TERROR;
				}
				zmputs(Attn);  
				continue;
			    }
moredata:
			    Nopper();
			    alarm_on();
			    switch (c = zrdata(secbuf, MAXBLOCK)) {
				case ZCAN:	Syslog('+', "Zmodem: sender CANcelled");
						return TERROR;
				case HANGUP:	Syslog('+', "Zmodem: Lost Carrier");
						return TERROR;
				case TERROR:	/* CRC error */
						if (--n < 0) {
						    Syslog('+', "Zmodem: Too many errors");
						    return TERROR;
						}
						zmputs(Attn);
						continue;
				case TIMEOUT:	if ( --n < 0) {
						    Syslog('+', "Zmodem: TIMEOUT");
						    return TERROR;
						}
						continue;
				case GOTCRCW:	n = 20;
						putsec(secbuf, Rxcount);
						rxbytes += Rxcount;
						stohdr(rxbytes);
						PUTCHAR(XON);
						zshhdr(ZACK, Txhdr);
						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;
			    }
	}
    }
}
Example #8
0
/*
 * 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: can be ymodem.
 */
int tryz(void)
{
    int	    c, n;
    int	    cmdzack1flg;

    if (protocol != ZM_ZMODEM)
	return 0;

    for (n = zmodem_requested ?15:10; --n >= 0; ) {
	/*
	 * Set buffer length (0) and capability flags
	 */
	Syslog('z', "tryz attempt %d", n);
	stohdr(0L);
	Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
	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)) {
	    case ZRQINIT:   continue;
	    case ZEOF:	    continue;
	    case TIMEOUT:   Syslog('z', "Zmodem: tryz() timeout attempt %d", n);
			    continue;
	    case ZFILE:	    zconv = Rxhdr[ZF0];
			    if (!zconv) {
				Syslog('z', "*** !zconv %d", zconv);
				zconv = ZCBIN;
			    }
			    zmanag = Rxhdr[ZF1];
			    ztrans = Rxhdr[ZF2];
			    tryzhdrtype = ZRINIT;
			    c = zrdata(secbuf, MAXBLOCK);
			    io_mode(0, 3);
			    if (c == GOTCRCW) {
				Syslog('z', "tryz return ZFILE");
				return ZFILE;
			    }
			    zshhdr(ZNAK, Txhdr);
			    goto again;
	    case ZSINIT:    /* this once was:
			     * Zctlesc = TESCCTL & Rxhdr[ZF0];
			     * trouble: if rz get --escape flag:
			     * - it sends TESCCTL to sz, 
			     *   get a ZSINIT _without_ TESCCTL (yeah - sender didn't know), 
			     *   overwrites Zctlesc flag ...
			     * - sender receives TESCCTL and uses "|=..."
			     * so: sz escapes, but rz doesn't unescape ... not good.
			     */
			    Zctlesc |= TESCCTL & Rxhdr[ZF0];
			    if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
				stohdr(1L);
				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, MAXBLOCK) == GOTCRCW) {
				if (cmdzack1flg & ZCACK1)
				    stohdr(0L);
				else
				    Syslog('+', "Zmodem: request for command \"%s\" ignored", printable(secbuf,-32));
				stohdr(0L);
				do {
				    zshhdr(ZCOMPL, Txhdr);
				} while (++errors<20 && zgethdr(Rxhdr) != ZFIN);
				return ackbibi();
			    }
			    zshhdr(ZNAK, Txhdr); 
			    goto again;
	    case ZCOMPL:    goto again;
	    case ZRINIT:    Syslog('z', "tryz: got ZRINIT");
			    return TERROR;
	    case ZFIN:	    /* do not beleive in first ZFIN */
			    ackbibi(); 
			    return ZCOMPL;
	    case TERROR:
	    case HANGUP:
	    case ZCAN:	    return TERROR;
	    default:	    continue;
	}
    }
    return 0;
}
Example #9
0
/* ------------------------------------------------------------------------- */
int tx_zmodem(s_protinfo *pi, bool caller)
{
	int   startblk  = 64;  /* Initial Zmodem block size                  */
	int   minblk    = 64;  /* Minimal Z-protocol block size              */
	int   maxblk    = 1024;/* Maximal Z-protocol block size              */
	int   blocklen  = 0;   /* Length of transmitted blocks               */
	int   goodblk   = 0;   /* How many blocks we sent w/o ZRPOS'tion :)  */
	int   txwindow  = 0;   /* Tranmitter window size (0 means streaming) */
	int   newcnt    = 0;   /* Count free bytes in receiver's buffer      */
	int   rxbuflen  = 0;   /* Receiver's max buffer length               */
	int   rxlastpos = 0;   /* Receiver's last reported offset            */
	int   beenhere  = 0;   /* How many times we've been ZRPOS'd same place */
	long  bytescnt  = 0;   /* Received bytes(current offset)             */
	long  lastsync  = 0;   /* Last offset to which we got a ZRPOS        */
	char  zconv     = 0;   /* Local ZMODEM file conversion request       */
	char  zmanag    = 0;   /* Local ZMODEM file management request       */
	char  ztrans    = 0;   /* Local ZMODEM file translation request      */
	char  zexten    = 0;   /* Local ZMODEM file extended options         */
	char *txbuf     = NULL;/* Buffer with ZMAXBLOCKLEN size              */
	int   zrinitcnt = 0;   /* Count received ZRINITs                     */
	int   rxflags1  = 0;
	int   rxflags2  = 0;
	int   txtries   = 0;
	int   junkcnt   = 0;
	int   initacked = 0;   /* TRUE when at least one ZRQINIT was sent    */
	                       /* after first ZRINIT was received            */
	int   rc        = 0;   /* Our return code                            */
	int   dtype, n;
	int   ftype;
	char  c, *p;
	long unsigned crc32;
	enum  ztxstates txstate;
	time_t deadtimer;
	
	log("start %s send", Protocols[state.handshake->protocol]);
	DEB((D_PROT, "start %s send", Protocols[state.handshake->protocol]));
	
	/* Set time transfer started at */
	if( pi->start_time == 0 )
		pi->start_time = time(NULL);
	
	txbuf      = (char *)xmalloc(ZMAXBLOCKLEN+1);
	zconv      = ZCBIN;
	maxblk     = (state.handshake->protocol == PROT_ZMODEM) ? 1024 : 8192;
	
	/* Set initial block size (default is 128b) */
	if( (startblk = conf_number(cf_zmodem_start_block_size)) > 0 )
	{
		if( startblk%64 || startblk > maxblk || startblk < 64 )
			startblk = 256;
	} else 
		startblk = 256;
	
	blocklen  = startblk;
	txwindow  = conf_number(cf_zmodem_tx_window);
	Z_Rxwait  = ZWAITTIME;
	Z_Rxtout  = ZRXTIMEOUT;
	txstate   = ZTX_START;

	timer_set(&deadtimer, ZDEADTIMER);
	
	setalarm(Z_Rxtout);
	
	/*
	 * At zmodem batches send empty netmail packet
	 * if no real outgoing traffic available
	 */
	if( !pi->send_left_size && conf_boolean(cf_zmodem_send_dummy_pkt) )
		zmodem_add_empty_packet(pi);
	
	while(1)
	{
		if( timer_expired(deadtimer) )
		{
			log("brain dead! (abort)");
			gotoexit(PRC_LOCALABORTED);
		}
		
		if( txstate == ZTX_RQINIT || txstate == ZTX_FINFO
		 || txstate == ZTX_EOF    || txstate == ZTX_FIN )
		{
#ifdef DEBUG
			if( txtries ) DEB((D_PROT, "tx_zmodem: try #%d", txtries));
#endif			
			if( ++txtries > ZMAXTRIES )
			{
				log("out of tries");
				gotoexit(PRC_LOCALABORTED);
			}
		}
		
		switch(txstate) {
		case ZTX_START:
			DEB((D_PROT, "tx_zmodem: entering state ZTX_START"));
			if( PUTSTR("rz\r") < 0 )
				gotoexit(PRC_ERROR);
			txtries = 0;
			txstate = ZTX_RQINIT;
			break;
			
		case ZTX_RQINIT:
			DEB((D_PROT, "tx_zmodem: entering state ZTX_RQINIT"));
			stohdr(Z_Txhdr, 0L);
			if( zshhdr(ZRQINIT, Z_Txhdr) < 0 )
				gotoexit(PRC_ERROR);
			setalarm(Z_Rxtout);
			txstate = ZTX_RQINITACK;
			break;
			
		case ZTX_NEXTFILE:
			DEB((D_PROT, "tx_zmodem: entering state ZTX_NEXTFILE"));
			if (pi->send) p_tx_fclose(pi);
			txtries = 0;
			txstate = p_tx_fopen(pi, NULL) ? ZTX_FIN : ZTX_FINFO;
			log("nextfile next state: %d", txstate);
			break;

		case ZTX_FINFO:
			DEB((D_PROT, "tx_zmodem: entering state ZTX_FINFO"));
			
			zrinitcnt = 0;
			
			strnxcpy(txbuf, pi->send->net_name, ZMAXFNAME);
			
			p = txbuf + strlen(txbuf) + 1; 
			sprintf(p, "%ld %lo %lo 0 %ld %ld",
				(long)pi->send->bytes_total, (long)pi->send->mod_time,
				(long)pi->send->mode, (long)pi->send_left_num,
				(long)pi->send_left_size);
			
			DEB((D_PROT, "tx_zmodem: send \"%s\\000%s\"", txbuf, p));
			
			Z_Txhdr[ZF0] = zconv;	/* file conversion request */
			Z_Txhdr[ZF1] = zmanag;  /* file management request */
			Z_Txhdr[ZF2] = ztrans;  /* file transport request  */
			Z_Txhdr[ZF3] = zexten;
			
			if( zsbhdr(ZFILE, Z_Txhdr) < 0 )
				gotoexit(PRC_ERROR);
			if( zsdata(txbuf, (p - txbuf) + strlen(p), ZCRCW, 0) < 0 )
				gotoexit(PRC_ERROR);
			
			setalarm(Z_Rxtout);
			txstate = ZTX_FINFOACK;
			break;
			
		case ZTX_STARTDATA:
			DEB((D_PROT, "tx_zmodem: entering state ZTX_STARTDATA"));
			
			newcnt   = rxbuflen;
			junkcnt  = 0;
			
			stohdr(Z_Txhdr, pi->send->bytes_sent);
			if( zsbhdr(ZDATA, Z_Txhdr) < 0 )
				gotoexit(PRC_ERROR);
			
			txstate = ZTX_DATA;
			break;
			
		case ZTX_DATA:
			DEB((D_PROT, "tx_zmodem: entering state ZTX_DATA"));
			
			timer_set(&deadtimer, ZDEADTIMER);
			setalarm(Z_Rxtout); /* Remove annoing timeouts! */
			
			if( (n = p_tx_readfile(txbuf, blocklen, pi)) < 0 )
			{
				/* error occured, remote wait for DATA */
				/* so send null ZCRCE data subpacket   */
				if( zsdata(txbuf, 0, ZCRCE, 0) < 0 )
					gotoexit(PRC_ERROR);
				txstate = ZTX_NEXTFILE;
				break;
			}
		
			if( pi->send->eofseen )
				dtype = ZCRCE;
			else if( junkcnt > 6 )
				dtype = ZCRCW;
			else if( bytescnt == lastsync )
				dtype = ZCRCW;
			else if( rxbuflen && (newcnt -= n) <= 0 )
				dtype = ZCRCW;
			else if( txwindow && (bytescnt - rxlastpos + n) >= txwindow )
				dtype = ZCRCQ;
			else
				dtype = ZCRCG;

			if( (rc = p_info(pi, 0)) )
				gotoexit(rc);
			
			if( zsdata(txbuf, n, dtype, pi->send->bytes_sent) < 0 )
				gotoexit(PRC_ERROR);
			
			if( ++goodblk > 5 && blocklen*2 <= maxblk )
			{
				goodblk = 0;
				blocklen *= 2;
				DEB((D_PROT, "tx_zmodem: new blocklen = %ld byte(s)", blocklen));
			}
			
			bytescnt = pi->send->bytes_sent += n;
			
			if( dtype == ZCRCW )
			{
				junkcnt = 0;
				setalarm(Z_Rxtout);
				txstate = ZTX_CRCWACK;
				break;
			}
			else if( dtype == ZCRCQ )
			{
				junkcnt = 0;
				setalarm(Z_Rxtout);
				txstate = ZTX_CRCQACK;
				break;
			}
			else if( dtype == ZCRCE )
			{
				txtries = 0;
				txstate = ZTX_EOF;
				break;
			}
			
			if( CHARWAIT(0) )
			{
				while( (rc = GETCHAR(1)) != ZTIMER )
				{
					if( rc < 0 )
					{
						gotoexit(PRC_ERROR);
					}
					else if( rc == CAN || rc == ZPAD )
					{
						DEB((D_PROT, "tx_zmodem: got ZPAD or CAN!"));
						setalarm(Z_Rxtout);
						txstate = ZTX_READCHECK;
						break;
					}
					else if( rc == XOFF || rc == (XOFF|0200) )
					{
						DEB((D_PROT, "tx_zmodem: got XOFF"));
						if( GETCHAR(5) < 0 )
							gotoexit(PRC_ERROR);
						break;
					}
					else if( rc == XON  || rc == (XON|0200) )
					{
						DEB((D_PROT, "tx_zmodem: got XON"));
					}
					else
					{
						junkcnt++;
						DEB((D_PROT, "tx_zmodem: got JUNK = 0x%x (junkcnt = %d)",
							rc, junkcnt));
					}
				} /* end of while( rc != ZTIMER ) */
			} /* end of if( CHARWAIT(0) ) */
			break;
		
		case ZTX_EOF:
			DEB((D_PROT, "tx_zmodem: entering state ZTX_EOF"));
			
			stohdr(Z_Txhdr, pi->send->bytes_sent);
			if( zsbhdr(ZEOF, Z_Txhdr) < 0 )
				gotoexit(PRC_ERROR);
			
			setalarm(Z_Rxtout);
			txstate = ZTX_EOFACK;
			break;
			
		case ZTX_FIN:
			DEB((D_PROT, "tx_zmodem: entering state ZTX_FIN"));
			
			stohdr(Z_Txhdr, 0L);
			if( zshhdr(ZFIN, Z_Txhdr) < 0 )
				gotoexit(PRC_ERROR);
			
			setalarm(Z_Rxtout);
			txstate = ZTX_FINACK;
			break;
			
		default:
			/* Ignore them all */
			break;
		} /* end of switch(txstate) */
	
		if( txstate != ZTX_START  && txstate != ZTX_RQINIT
		 && txstate != ZTX_FINFO  && txstate != ZTX_DATA
		 && txstate != ZTX_EOF    && txstate != ZTX_FIN )
		{
			switch( ftype = zgethdr(Z_Rxhdr) ) {
			case ZCAN:
				gotoexit(PRC_REMOTEABORTED);
				break;
				
			case ZHANGUP:
			case ZEXIT:
				gotoexit(PRC_ERROR);
				break;
				
			case ZTIMER:
				log("time out");
				
				if( txstate == ZTX_READCHECK )
					zsdata(txbuf, 0, ZCRCE, 0);
				
				switch(txstate) {
				case ZTX_RQINITACK: txstate = ZTX_RQINIT;    break;
				case ZTX_FINFOACK:  txstate = ZTX_FINFO;     break;
				case ZTX_READCHECK: txstate = ZTX_STARTDATA; break;
				case ZTX_CRCWACK:   txstate = ZTX_STARTDATA; break;
				case ZTX_CRCQACK:   txstate = ZTX_STARTDATA; break;
				case ZTX_EOFACK:    txstate = ZTX_EOF;       break;
				case ZTX_FINACK:    txstate = ZTX_FIN;       break;
				default:            break;
				}
				break;
				
			case ZERROR:
			case ZCRCERR:
				/* NAK them all! */
				stohdr(Z_Txhdr, 0L);
				if( zshhdr(ZNAK, Z_Txhdr) < 0 )
					gotoexit(PRC_ERROR);
				break;
				
			case ZRQINIT:
				if( txstate == ZTX_RQINITACK )
				{
					if( Z_Rxhdr[0] == ZCOMMAND )
						break;
					
					stohdr(Z_Txhdr, 0L);
					if( zshhdr(ZNAK, Z_Txhdr) < 0 )
						gotoexit(PRC_ERROR);
					
					txstate = ZTX_RQINIT;
				}
				else if( txstate == ZTX_FINFOACK )
				{
					/* remote is sender - abort */
					log("zmodem: remote is sender");
					gotoexit(PRC_LOCALABORTED);
				}
				break;
				
			case ZRINIT:
				if( txstate == ZTX_RQINITACK )
				{
					if( initacked == 0 )
					{
						/* Be sure ack first ZRINIT */
						stohdr(Z_Txhdr, 0L);
						if( zshhdr(ZRQINIT, Z_Txhdr) < 0 )
							gotoexit(PRC_ERROR);
						initacked = 1;
					}
					
					/* Get receiver's options */
					rxflags1  = (0377 & Z_Rxhdr[ZF0]);
					rxflags2  = (0377 & Z_Rxhdr[ZF1]);
					Z_Txfcs32 = (rxflags1 & CANFC32);
					Z_Ctlesc |= (rxflags1 & TESCCTL);
					rxbuflen  = (0377 & Z_Rxhdr[ZP0]);
					rxbuflen += ((0377 & Z_Rxhdr[ZP1])<<8);
					
					/* No ZCRCQ if remote doesn't indicate */
					/* FDX ability                         */ 
					if( !(rxflags1 & CANFDX) )
						txwindow = 0;
				
					DEB((D_PROT, "tx_zmodem: Z_Txfcs32 = %d Z_Ctlesc = %d",
						Z_Txfcs32, Z_Ctlesc));
					DEB((D_PROT, "tx_zmodem: rxbuflen = %d blocklen = %d",
						rxbuflen, blocklen));
					DEB((D_PROT, "tx_zmodem: txwindow = %u",
						txwindow));
				
					txstate   = ZTX_NEXTFILE;
				}
				else if( txstate == ZTX_FINFOACK )
				{
					/* Possible they didn't see */
					/* our file information     */
					if( ++zrinitcnt > 2 )
						txstate = ZTX_FINFO;
				}
				else if( txstate == ZTX_READCHECK
				      || txstate == ZTX_CRCQACK
				      || txstate == ZTX_CRCWACK )
				{
					if( txstate == ZTX_READCHECK
					 || txstate == ZTX_CRCQACK )
						zsdata(txbuf, 0, ZCRCE, 0);
					
					/* Assume file normaly sent ? */
					log("assume file normaly sent");
					
					pi->send->status = FSTAT_SUCCESS;
					txstate = ZTX_NEXTFILE;
				}
				else if( txstate == ZTX_EOFACK )
				{
					/* ok, send next */
					pi->send->status = FSTAT_SUCCESS;
					txstate = ZTX_NEXTFILE;
				}
				else if( txstate == ZTX_FINACK )
				{
					/* Possible we should ignore  */
					/* first ZRINIT. Because they */
					/* didn't see our first ZFIN  */
					/* But I'm soo lazy .. :))    */
					txstate = ZTX_FIN;
				}
				break;
				
			case ZACK:
				if( txstate == ZTX_CRCWACK )
				{
					rxlastpos = Z_Rxpos;
					if( pi->send->bytes_sent == Z_Rxpos )
						txstate = ZTX_STARTDATA;
				}
				else if( txstate == ZTX_READCHECK
				      || txstate == ZTX_CRCQACK )
				{
					rxlastpos = Z_Rxpos;
					txstate   = ZTX_DATA;
				}
				break;
				
			case ZSKIP:
				if( txstate == ZTX_FINFOACK
				 || txstate == ZTX_READCHECK
				 || txstate == ZTX_CRCQACK
				 || txstate == ZTX_CRCWACK
				 || txstate == ZTX_EOFACK )
				{
					if( txstate == ZTX_READCHECK
					 || txstate == ZTX_CRCQACK )
						zsdata(txbuf, 0, ZCRCE, 0);
					
					if( txstate == ZTX_READCHECK )
						CLEAROUT();
					
					pi->send->status = FSTAT_SKIPPED;
					log("remote side skipped file");
					
					txstate = ZTX_NEXTFILE;
				}
				break;
				
			case ZFIN:
				/* BUG!BUG!BUG!BUG!BUG!BUG!BUG!BUG!BUG! */
				/* BUG!BUG!BUG!BUG!BUG!BUG!BUG!BUG!BUG! */
				log(" BUG!BUG!BUG!BUG!BUG!BUG!BUG!BUG!BUG! ");
				if( txstate == ZTX_FINACK )
				{
					if( PUTSTR("OO") == 0 )
						FLUSHOUT();
					gotoexit(PRC_NOERROR);
				}
				break;
				
			case ZRPOS:
				if( txstate == ZTX_FINFOACK
				 || txstate == ZTX_READCHECK
				 || txstate == ZTX_CRCQACK
				 || txstate == ZTX_CRCWACK
				 || txstate == ZTX_EOFACK )
				{
					rxlastpos = Z_Rxpos;
					
					/* Clear modem buffers */
					/* if( txstate != FINFOACK ) SENDBREAK(); */
					if( txstate == ZTX_READCHECK ) CLEAROUT();

					if( txstate == ZTX_READCHECK
					 || txstate == ZTX_CRCQACK )
					{
						if( zsdata(txbuf, 0, ZCRCE, 0) < 0 )
							gotoexit(PRC_ERROR);
					}
					
					/* Reset EOF flag! */
					pi->send->eofseen = FALSE;
					
					/* Check pos */
					if( (Z_Rxpos || txstate != ZTX_FINFOACK)
					 && p_tx_rewind(pi, Z_Rxpos) )
					{
						logerr("can't send file from requested position");
						/* Open next file for send */
						txstate = ZTX_NEXTFILE;
						break;
					}
					
					if( txstate == ZTX_FINFOACK )
					{
						if( Z_Rxpos )
						{
							log("resyncing at offset %d", Z_Rxpos);
							pi->send->bytes_skipped = Z_Rxpos;
						}
					}
					else if( txstate == ZTX_READCHECK
					      || txstate == ZTX_CRCWACK
					      || txstate == ZTX_CRCQACK )
					{
						goodblk = 0;
						if( lastsync >= Z_Rxpos && ++beenhere > 4 )
							if( blocklen > minblk )
							{
								blocklen /= 2;
								DEB((D_PROT, "tx_zmodem: falldown to %ld BlockLen", blocklen));
							}
					}
					
					lastsync = bytescnt = pi->send->bytes_sent = Z_Rxpos;
					
					if( txstate == ZTX_FINFOACK )
						--lastsync;
					
					txstate = ZTX_STARTDATA;
				}
				break;
				
			case ZNAK:
				switch(txstate) {
				case ZTX_RQINITACK: txstate = ZTX_RQINIT; break;
				case ZTX_FINFOACK:  txstate = ZTX_FINFO;  break;
				case ZTX_EOFACK:    txstate = ZTX_EOF;    break;
				case ZTX_FINACK:    txstate = ZTX_FIN;    break;
				default:            break;
				}
				break;
				
			case ZCRC:
				if( txstate == ZTX_FINFOACK )
				{
					log(" Send file's CRC-32 ");
					crc32 = 0xFFFFFFFFL;
					
					while( ((c = getc(pi->send->fp)) != EOF) && --Z_Rxpos )
						crc32 = updcrc32(c, crc32);
					
					crc32 = ~crc32;
					
					clearerr(pi->send->fp); /* Clear EOF */
					fseek(pi->send->fp, 0L, 0);
					
					stohdr(Z_Txhdr, crc32);
					if( zsbhdr(ZCRC, Z_Txhdr) < 0 )
						gotoexit(PRC_ERROR);
				}
				break;
				
			case ZCHALLENGE:
				if( txstate == ZTX_RQINITACK )
				{
					/* Echo receiver's challenge number */
					stohdr(Z_Txhdr, Z_Rxpos);
					if( zshhdr(ZACK, Z_Txhdr) < 0 )
						gotoexit(PRC_ERROR);
					txstate = ZTX_RQINIT;
				}
				break;
				
			case ZCOMMAND:
				if( txstate == ZTX_RQINITACK )
				{
					txstate = ZTX_RQINIT;
				}
				break;

			case ZABORT:
				log("remote requested for session abort");
				stohdr(Z_Txhdr, 0L);
				if( zshhdr(ZFIN, Z_Txhdr) < 0 )
					gotoexit(PRC_ERROR);
				gotoexit(PRC_REMOTEABORTED);
				break;
				
			case ZFERR:
				if( txstate == ZTX_FINFOACK
				 || txstate == ZTX_READCHECK
				 || txstate == ZTX_CRCWACK
				 || txstate == ZTX_CRCQACK
				 || txstate == ZTX_EOFACK )
				{
					if( txstate == ZTX_READCHECK
					 || txstate == ZTX_CRCQACK )
					{
						if( zsdata(txbuf, 0, ZCRCE, 0) < 0 )
							gotoexit(PRC_ERROR);
					}

					pi->send->status = FSTAT_REFUSED;
					log("remote side refused file");
					
					txstate = ZTX_NEXTFILE;
				}
				break;
				
			default:
				log("got unexpected frame %d", ftype);
				break;
			} /* end of switch(hdr) */
		} /* end of if */
	} /* end of while */
	
exit:
	DEB((D_PROT, "tx_zmodem: SEND exit = %d", rc));
	
	setalarm(0);
	
	if (pi->send) p_tx_fclose(pi);
	
	if( txbuf ) {
		free(txbuf);
		txbuf = NULL;
	}
	
	
	return(rc);
}