diff --git a/mbsebbs/Makefile b/mbsebbs/Makefile index b7b741e3..4bc5f799 100644 --- a/mbsebbs/Makefile +++ b/mbsebbs/Makefile @@ -132,6 +132,6 @@ dispfile.o: ../config.h ../lib/mbselib.h ../lib/mbse.h ../lib/users.h ../lib/msg userlist.o: ../config.h ../lib/mbselib.h ../lib/mbse.h ../lib/users.h userlist.h language.h input.h timeout.h term.h ttyio.h timestats.o: ../config.h ../lib/mbselib.h ../lib/mbse.h ../lib/users.h timestats.h funcs.h language.h input.h exitinfo.h term.h logentry.o: ../config.h ../lib/mbselib.h ../lib/mbse.h ../lib/users.h logentry.h -zmrle.o: ../config.h ../lib/mbselib.h ../lib/nodelist.h ttyio.h zmodem.h zmrle.h +zmrle.o: ../config.h ../lib/mbselib.h ../lib/nodelist.h ttyio.h zmodem.h zmrle.h zmmisc.h zmmisc.o: ../config.h ../lib/mbselib.h ../lib/nodelist.h ttyio.h zmodem.h zmrle.h zmmisc.h # End of generated dependencies diff --git a/mbsebbs/zmmisc.c b/mbsebbs/zmmisc.c new file mode 100644 index 00000000..de6b735f --- /dev/null +++ b/mbsebbs/zmmisc.c @@ -0,0 +1,995 @@ +/* + * $Id$ + * + * Z M . C + * Copyright 1994 Omen Technology Inc All Rights Reserved + * ZMODEM protocol primitives + * + * Entry point Functions: + * zsbhdr(type, hdr) send binary header + * zshhdr(type, hdr) send hex header + * zgethdr(hdr) receive header - binary or hex + * zsdata(buf, len, frameend) send data + * zrdata(buf, len) receive data + * stohdr(pos) store position data in Txhdr + * long rclhdr(hdr) recover position offset from header + * + * + * This version implements numerous enhancements including ZMODEM + * Run Length Encoding and variable length headers. These + * features were not funded by the original Telenet development + * contract. + * + * This software may be freely used for educational (didactic + * only) purposes. This software may also be freely used to + * support file transfer operations to or from licensed Omen + * Technology products. Use with other commercial or shareware + * programs (Crosstalk, Procomm, etc.) REQUIRES REGISTRATION. + * + * Any programs which use part or all of this software must be + * provided in source form with this notice intact except by + * written permission from Omen Technology Incorporated. + * + * Use of this software for commercial or administrative purposes + * except when exclusively limited to interfacing Omen Technology + * products requires a per port license payment of $20.00 US per + * port (less in quantity). Use of this code by inclusion, + * decompilation, reverse engineering or any other means + * constitutes agreement to these conditions and acceptance of + * liability to license the materials and payment of reasonable + * legal costs necessary to enforce this license agreement. + * + * + * Omen Technology Inc + * Post Office Box 4681 + * Portland OR 97208 + * + * This code is made available in the hope it will be useful, + * BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY + * DAMAGES OF ANY KIND. + * + */ + +static void zputhex(int); +static void zsbh32(int,char*,int,int); +static void zsda32(char*,int,int); +static int zrdat32(char*,int); +static int noxrd7(void); +static int zrbhd32(char*); +static int zrbhdr(char*); +static int zrhhdr(char*); +static int zgethex(void); +static int zgeth1(void); +static void garbitch(void); + +#include "../config.h" +#include "../lib/mbselib.h" +#include "../lib/nodelist.h" +#include "ttyio.h" +#include "zmodem.h" +#include "zmrle.h" +#include "zmmisc.h" + + +/* Original zm.c timing was in tenths of seconds, but our current ttyio driver + does timing in whole seconds. +*/ +static int Rxtimeout = 10; /* Seconds to wait for something */ +int Zctlesc; + +/* Globals used by ZMODEM functions */ +int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame */ +int Rxtype; /* Type of header received */ +int Rxhlen; /* Length of header received */ +int Rxcount; /* Count of data bytes received */ +char Rxhdr[ZMAXHLEN]; /* Received header */ +char Txhdr[ZMAXHLEN]; /* Transmitted header */ +long Rxpos; /* Received file position */ +long Txpos; /* Transmitted file position */ +int Txfcs32; /* TRUE means send binary frames with 32 bit FCS */ +int Crc32t; /* Controls 32 bit CRC being sent */ + /* 1 == CRC32, 2 == CRC32 + RLE */ +int Crc32r; /* Indicates/controls 32 bit CRC being received */ + /* 0 == CRC16, 1 == CRC32, 2 == CRC32 + RLE */ +int Usevhdrs; /* Use variable length headers */ +int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ +char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ +char *Altcan; /* Alternate canit string */ + +char *txbuf=NULL; +char *rxbuf=NULL; + +static int lastsent; /* Last char we sent */ +static int Not8bit; /* Seven bits seen on header */ + +char *frametypes[] = { + (char *)"EMPTY", /* -16 */ + (char *)"Can't be (-15)", + (char *)"Can't be (-14)", + (char *)"Can't be (-13)", + (char *)"Can't be (-12)", + (char *)"Can't be (-11)", + (char *)"Can't be (-10)", + (char *)"Can't be (-9)", + (char *)"HANGUP", /* -8 */ + (char *)"Can't be (-7)", + (char *)"Can't be (-6)", + (char *)"Can't be (-5)", + (char *)"EOFILE", /* -4 */ + (char *)"Can't be (-3)", + (char *)"TIMEOUT", /* -2 */ + (char *)"ERROR", /* -1 */ + (char *)"ZRQINIT", + (char *)"ZRINIT", + (char *)"ZSINIT", + (char *)"ZACK", + (char *)"ZFILE", + (char *)"ZSKIP", + (char *)"ZNAK", + (char *)"ZABORT", + (char *)"ZFIN", + (char *)"ZRPOS", + (char *)"ZDATA", + (char *)"ZEOF", + (char *)"ZFERR", + (char *)"ZCRC", + (char *)"ZCHALLENGE", + (char *)"ZCOMPL", + (char *)"ZCAN", + (char *)"ZFREECNT", + (char *)"ZCOMMAND", + (char *)"ZSTDERR", + (char *)"xxxxx" +#define FRTYPES 22 /* Total number of frame types in this array */ + /* not including psuedo negative entries */ +}; + + +/***** Hack by mj ***********************************************************/ +/* + * Buffer for outgoing frames. Sending them with single character write()'s + * is a waste of processor time and causes severe performance degradation + * on TCP and ISDN connections. + */ +#define FRAME_BUFFER_SIZE 16384 +static char *frame_buffer=NULL; +static int frame_length = 0; + +#define BUFFER_CLEAR() do { frame_length=0; } while(0) +#define BUFFER_BYTE(c) do { frame_buffer[frame_length++]=(c); } while(0) +#define BUFFER_FLUSH() do { PUT(frame_buffer, frame_length); \ + frame_length=0; } while(0); +/****************************************************************************/ + +void get_frame_buffer(void) +{ + if (frame_buffer == NULL) + frame_buffer = malloc(FRAME_BUFFER_SIZE); +} + + +void free_frame_buffer(void) +{ + if (frame_buffer) + free(frame_buffer); + frame_buffer = NULL; +} + + + +/* + * Send ZMODEM binary header hdr of type type + */ +void zsbhdr(int len, int type, register char *shdr) +{ + register int n; + register unsigned short crc; + + Syslog('z', "zsbhdr: %c %d %s %lx", Usevhdrs?'v':'f', len, frametypes[type+FTOFFSET], rclhdr(shdr)); + + BUFFER_CLEAR(); + + if (type == ZDATA) + for (n = Znulls; --n >=0; ) + BUFFER_BYTE(0); + + BUFFER_BYTE(ZPAD); BUFFER_BYTE(ZDLE); + + switch (Crc32t=Txfcs32) { + case 2: + zsbh32(len, shdr, type, Usevhdrs?ZVBINR32:ZBINR32); + BUFFER_FLUSH(); break; + case 1: + zsbh32(len, shdr, type, Usevhdrs?ZVBIN32:ZBIN32); break; + default: + if (Usevhdrs) { + BUFFER_BYTE(ZVBIN); + zsendline(len); + } + else + BUFFER_BYTE(ZBIN); + zsendline(type); + crc = updcrc16(type, 0); + + for (n=len; --n >= 0; ++shdr) { + zsendline(*shdr); + crc = updcrc16((0377& *shdr), crc); + } + crc = updcrc16(0,updcrc16(0,crc)); + zsendline(((int)(crc>>8))); + zsendline(crc); + } + + BUFFER_FLUSH(); +} + + + +/* + * Send ZMODEM binary header hdr of type type + */ +void zsbh32(int len, register char *shdr, int type, int flavour) +{ + register int n; + register unsigned long crc; + + BUFFER_BYTE(flavour); + if (Usevhdrs) + zsendline(len); + zsendline(type); + crc = 0xFFFFFFFFL; crc = updcrc32(type, crc); + + for (n=len; --n >= 0; ++shdr) { + crc = updcrc32((0377 & *shdr), crc); + zsendline(*shdr); + } + crc = ~crc; + for (n=4; --n >= 0;) { + zsendline((int)crc); + crc >>= 8; + } +} + + + +/* + * Send ZMODEM HEX header hdr of type type + */ +void zshhdr(int len, int type, register char *shdr) +{ + register int n; + register unsigned short crc; + + Syslog('z', "zshhdr: %c %d %s %ld", Usevhdrs?'v':'f', len, frametypes[type+FTOFFSET], rclhdr(shdr)); + + BUFFER_CLEAR(); + + BUFFER_BYTE(ZPAD); + BUFFER_BYTE(ZPAD); + BUFFER_BYTE(ZDLE); + if (Usevhdrs) { + BUFFER_BYTE(ZVHEX); + zputhex(len); + } + else + BUFFER_BYTE(ZHEX); + zputhex(type); + Crc32t = 0; + + crc = updcrc16(type, 0); + for (n=len; --n >= 0; ++shdr) { + zputhex(*shdr); crc = updcrc16((0377 & *shdr), crc); + } + crc = updcrc16(0,updcrc16(0,crc)); + zputhex(((int)(crc>>8))); zputhex(crc); + + /* + * Make it printable on remote machine + */ + BUFFER_BYTE(015); + BUFFER_BYTE(0212); + + /* + * Uncork the remote in case a fake XOFF has stopped data flow + */ + if (type != ZFIN && type != ZACK) + BUFFER_BYTE(021); + + BUFFER_FLUSH(); +} + + + +/* + * Send binary array buf of length length, with ending ZDLE sequence frameend + */ +char *Zendnames[] = {(char *)"ZCRCE",(char *)"ZCRCG",(char *)"ZCRCQ",(char *)"ZCRCW"}; +void zsdata(register char *buf, int length, int frameend) +{ + register unsigned short crc; + + Syslog('z', "zsdata: %d %s", length, Zendnames[(frameend-ZCRCE)&3]); + + BUFFER_CLEAR(); + + switch (Crc32t) { + case 1: + zsda32(buf, length, frameend); break; + case 2: + zsdar32(buf, length, frameend); break; + default: + crc = 0; + for (;--length >= 0; ++buf) { + zsendline(*buf); crc = updcrc16((0377 & *buf), crc); + } + BUFFER_BYTE(ZDLE); BUFFER_BYTE(frameend); + crc = updcrc16(frameend, crc); + + crc = updcrc16(0,updcrc16(0,crc)); + zsendline(((int)(crc>>8))); zsendline(crc); + } + if (frameend == ZCRCW) + BUFFER_BYTE(XON); + + BUFFER_FLUSH(); +} + + + +void zsda32(register char *buf, int length, int frameend) +{ + register int c; + register unsigned long crc; + + crc = 0xFFFFFFFFL; + for (;--length >= 0; ++buf) { + c = *buf & 0377; + if (c & 0140) + BUFFER_BYTE(lastsent = c); + else + zsendline(c); + crc = updcrc32(c, crc); + } + BUFFER_BYTE(ZDLE); + BUFFER_BYTE(frameend); + crc = updcrc32(frameend, crc); + + crc = ~crc; + for (c=4; --c >= 0;) { + zsendline((int)crc); crc >>= 8; + } +} + + + +/* + * Receive array buf of max length with ending ZDLE sequence + * and CRC. Returns the ending character or error code. + * NB: On errors may store length+1 bytes! + */ +int zrdata(register char *buf, int length) +{ + register int c; + register unsigned short crc; + register char *end; + register int d; + + switch (Crc32r) { + case 1: + return zrdat32(buf, length); + case 2: + return zrdatr32(buf, length); + } + + crc = Rxcount = 0; end = buf + length; + while (buf <= end) { + if ((c = zdlread()) & ~0377) { +crcfoo: + switch (c) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + crc = updcrc16((((d=c))&0377), crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc16(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc16(c, crc); + if (crc & 0xFFFF) { + Syslog('+', "Zmodem zrdata: Bad CRC"); + return TERROR; + } + Rxcount = length - (end - buf); + Syslog('z', "zrdata: %d %s", Rxcount, Zendnames[(d-GOTCRCE)&3]); + return d; + case GOTCAN: + Syslog('+', "Zmodem: Sender Canceled"); + return ZCAN; + case TIMEOUT: + Syslog('+', "Zmodem: TIMEOUT receiving data"); + return c; + case HANGUP: + Syslog('+', "Zmodem: Carrier lost while receiving"); + return c; + default: + garbitch(); + return c; + } + } + *buf++ = c; + crc = updcrc16(c, crc); + } + Syslog('+', "Zmodem: Data subpacket too long"); + return TERROR; +} + + + +int zrdat32(register char *buf, int length) +{ + register int c; + register unsigned long crc; + register char *end; + register int d; + + crc = 0xFFFFFFFFL; Rxcount = 0; end = buf + length; + while (buf <= end) { + if ((c = zdlread()) & ~0377) { +crcfoo: + switch (c) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + d = c; c &= 0377; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if (crc != 0xDEBB20E3) { + Syslog('+', "Zmodem zrdat32: Bad CRC"); + return TERROR; + } + Rxcount = length - (end - buf); + + Syslog('z', "zrdat32: %d %s", Rxcount, Zendnames[(d-GOTCRCE)&3]); + + return d; + case GOTCAN: + Syslog('+', "Zmodem: Sender Canceled"); + return ZCAN; + case TIMEOUT: + Syslog('+', "Zmodem: TIMEOUT"); + return c; + case HANGUP: + Syslog('+', "Zmodem: Carrier lost while receiving"); + return c; + default: + garbitch(); + return c; + } + } + *buf++ = c; + crc = updcrc32(c, crc); + } + Syslog('+', "Zmodem: Data subpacket too long"); + return TERROR; +} + + + +void garbitch(void) +{ + Syslog('+', "Zmodem: Garbled data subpacket"); +} + + + +/* + * Read a ZMODEM header to hdr, either binary or hex. + * + * Set Rxhlen to size of header (default 4) (valid if good hdr) + * On success, set Zmodem to 1, set Rxpos and return type of header. + * Otherwise return negative on error. + * Return ERROR instantly if ZCRCW sequence, for fast error recovery. + */ +int zgethdr(char *shdr) +{ + register int c, n, cancount; + + int Zrwindow = 1400; + int Baudrate = 9600; + n = Zrwindow + Baudrate; + Rxframeind = Rxtype = 0; + +startover: + cancount = 5; +again: + /* + * Return immediate ERROR if ZCRCW sequence seen + */ + if (((c = GETCHAR(Rxtimeout)) < 0) && (c != TIMEOUT)) + goto fifi; + else switch(c) { + case 021: case 0221: + goto again; + case HANGUP: + case TIMEOUT: + goto fifi; + case CAN: +gotcan: + if (--cancount <= 0) { + c = ZCAN; goto fifi; + } + switch (c = GETCHAR(Rxtimeout)) { + case TIMEOUT: + goto again; + case ZCRCW: + switch (GETCHAR(Rxtimeout)) { + case TIMEOUT: + c = TERROR; goto fifi; + case HANGUP: + goto fifi; + default: + goto agn2; + } + case HANGUP: + goto fifi; + default: + break; + case CAN: + if (--cancount <= 0) { + c = ZCAN; goto fifi; + } + goto again; + } + /* **** FALL THRU TO **** */ + default: +agn2: +#define GCOUNT (-4) + if ( --n == 0) { + c = GCOUNT; goto fifi; + } + goto startover; + case ZPAD|0200: /* This is what we want. */ + Not8bit = c; + case ZPAD: /* This is what we want. */ + break; + } + cancount = 5; +splat: + switch (c = noxrd7()) { + case ZPAD: + goto splat; + case HANGUP: + case TIMEOUT: + goto fifi; + default: + goto agn2; + case ZDLE: /* This is what we want. */ + break; + } + + + Rxhlen = 4; /* Set default length */ + Rxframeind = c = noxrd7(); + switch (c) { + case ZVBIN32: + if ((Rxhlen = c = zdlread()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 1; c = zrbhd32(shdr); break; + case ZBIN32: + if (Usevhdrs) + goto agn2; + Crc32r = 1; c = zrbhd32(shdr); break; + case ZVBINR32: + if ((Rxhlen = c = zdlread()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 2; c = zrbhd32(shdr); break; + case ZBINR32: + if (Usevhdrs) + goto agn2; + Crc32r = 2; c = zrbhd32(shdr); break; + case HANGUP: + case TIMEOUT: + goto fifi; + case ZVBIN: + if ((Rxhlen = c = zdlread()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 0; c = zrbhdr(shdr); break; + case ZBIN: + if (Usevhdrs) + goto agn2; + Crc32r = 0; c = zrbhdr(shdr); break; + case ZVHEX: + if ((Rxhlen = c = zgethex()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 0; c = zrhhdr(shdr); break; + case ZHEX: + if (Usevhdrs) + goto agn2; + Crc32r = 0; c = zrhhdr(shdr); break; + case CAN: + goto gotcan; + default: + goto agn2; + } + for (n = Rxhlen; ++n < ZMAXHLEN; ) /* Clear unused hdr bytes */ + shdr[n] = 0; + Rxpos = shdr[ZP3] & 0377; + Rxpos = (Rxpos<<8) + (shdr[ZP2] & 0377); + Rxpos = (Rxpos<<8) + (shdr[ZP1] & 0377); + Rxpos = (Rxpos<<8) + (shdr[ZP0] & 0377); +fifi: + switch (c) { + case GOTCAN: + c = ZCAN; + /* **** FALL THRU TO **** */ + case ZNAK: + case ZCAN: + case TERROR: + case TIMEOUT: + case HANGUP: + Syslog('+', "Zmodem: Got %s", frametypes[c+FTOFFSET]); + /* **** FALL THRU TO **** */ + default: + if (c >= -FTOFFSET && c <= FRTYPES) + Syslog('z', "zgethdr: %c %d %s %ld", Rxframeind, Rxhlen, frametypes[c+FTOFFSET], Rxpos); + else + Syslog('z', "zgethdr: %c %d %ld", Rxframeind, c, Rxpos); + } + /* Use variable length headers if we got one */ + if (c >= 0 && c <= FRTYPES && Rxframeind & 040) + Usevhdrs = 1; + return c; +} + + + +/* + * Receive a binary style header (type and position) + */ +int zrbhdr(register char *shdr) +{ + register int c, n; + register unsigned short crc; + + if ((c = zdlread()) & ~0377) + return c; + Rxtype = c; + crc = updcrc16(c, 0); + + for (n=Rxhlen; --n >= 0; ++shdr) { + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc16(c, crc); + *shdr = c; + } + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc16(c, crc); + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc16(c, crc); + if (crc & 0xFFFF) { + Syslog('+', "Zmodem zrbhdr: Bad CRC"); + return TERROR; + } + return Rxtype; +} + + + +/* + * Receive a binary style header (type and position) with 32 bit FCS + */ +int zrbhd32(register char *shdr) +{ + register int c, n; + register unsigned long crc; + + if ((c = zdlread()) & ~0377) + return c; + Rxtype = c; + crc = 0xFFFFFFFFL; crc = updcrc32(c, crc); + + for (n=Rxhlen; --n >= 0; ++shdr) { + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc32(c, crc); + *shdr = c; + } + for (n=4; --n >= 0;) { + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc32(c, crc); + } + if (crc != 0xDEBB20E3) { + Syslog('+', "Zmodem zrbhd32: Bad CRC"); + return TERROR; + } + return Rxtype; +} + + + +/* + * Receive a hex style header (type and position) + */ +int zrhhdr(char *shdr) +{ + register int c; + register unsigned short crc; + register int n; + + if ((c = zgethex()) < 0) + return c; + Rxtype = c; + crc = updcrc16(c, 0); + + for (n=Rxhlen; --n >= 0; ++shdr) { + if ((c = zgethex()) < 0) + return c; + crc = updcrc16(c, crc); + *shdr = c; + } + if ((c = zgethex()) < 0) + return c; + crc = updcrc16(c, crc); + if ((c = zgethex()) < 0) + return c; + crc = updcrc16(c, crc); + if (crc & 0xFFFF) { + Syslog('+', "Zmodem zrhhdr: Bad CRC"); + return TERROR; + } + switch (c = GETCHAR(Rxtimeout)) { + case 0215: + Not8bit = c; + /* **** FALL THRU TO **** */ + case 015: + /* Throw away possible cr/lf */ + switch (c = GETCHAR(Rxtimeout)) { + case 012: + Not8bit |= c; + } + } + if (c < 0) + return c; + return Rxtype; +} + + + +/* + * Send a byte as two hex digits + */ +void zputhex(register int c) +{ + static char digits[] = "0123456789abcdef"; + + BUFFER_BYTE(digits[(c&0xF0)>>4]); + BUFFER_BYTE(digits[(c)&0xF]); +} + + + +/* + * Send character c with ZMODEM escape sequence encoding. + * Escape XON, XOFF. Escape CR following @ (Telenet net escape) + */ +void zsendline(int c) +{ + /* Quick check for non control characters */ + if (c & 0140) + BUFFER_BYTE(lastsent = c); + else { + switch (c &= 0377) { + case ZDLE: + BUFFER_BYTE(ZDLE); + BUFFER_BYTE (lastsent = (c ^= 0100)); + break; + case 015: + case 0215: + if (!Zctlesc && (lastsent & 0177) != '@') + goto sendit; + /* **** FALL THRU TO **** */ + case 020: + case 021: + case 023: + case 0220: + case 0221: + case 0223: + BUFFER_BYTE(ZDLE); + c ^= 0100; + sendit: + BUFFER_BYTE(lastsent = c); + break; + default: + if (Zctlesc && ! (c & 0140)) { + BUFFER_BYTE(ZDLE); + c ^= 0100; + } + BUFFER_BYTE(lastsent = c); + } + } +} + + + +/* Decode two lower case hex digits into an 8 bit byte value */ +int zgethex(void) +{ + register int c; + + c = zgeth1(); + return c; +} + + + +int zgeth1(void) +{ + register int c, n; + + if ((c = noxrd7()) < 0) + return c; + n = c - '0'; + if (n > 9) + n -= ('a' - ':'); + if (n & ~0xF) + return TERROR; + if ((c = noxrd7()) < 0) + return c; + c -= '0'; + if (c > 9) + c -= ('a' - ':'); + if (c & ~0xF) + return TERROR; + c += (n<<4); + return c; +} + + + +/* + * Read a byte, checking for ZMODEM escape encoding + * including CAN*5 which represents a quick abort + */ +int zdlread(void) +{ + register int c; + +again: + /* Quick check for non control characters */ + if ((c = GETCHAR(Rxtimeout)) & 0140) + return c; + switch (c) { + case ZDLE: + break; + case 023: + case 0223: + case 021: + case 0221: + goto again; + default: + if (Zctlesc && !(c & 0140)) { + goto again; + } + return c; + } +again2: + if ((c = GETCHAR(Rxtimeout)) < 0) + return c; + if (c == CAN && (c = GETCHAR(Rxtimeout)) < 0) + return c; + if (c == CAN && (c = GETCHAR(Rxtimeout)) < 0) + return c; + if (c == CAN && (c = GETCHAR(Rxtimeout)) < 0) + return c; + switch (c) { + case CAN: + return GOTCAN; + case ZCRCE: + case ZCRCG: + case ZCRCQ: + case ZCRCW: + return (c | GOTOR); + case ZRUB0: + return 0177; + case ZRUB1: + return 0377; + case 023: + case 0223: + case 021: + case 0221: + goto again2; + default: + if (Zctlesc && ! (c & 0140)) { + goto again2; + } + if ((c & 0140) == 0100) + return (c ^ 0100); + break; + } + Syslog('+', "Zmodem: Bad escape sequence 0x%x", c); + return TERROR; +} + + + +/* + * Read a character from the modem line with timeout. + * Eat parity, XON and XOFF characters. + */ +int noxrd7(void) +{ + register int c; + + for (;;) { + if ((c = GETCHAR(Rxtimeout)) < 0) + return c; + switch (c &= 0177) { + case XON: + case XOFF: + continue; + default: + if (Zctlesc && !(c & 0140)) + continue; + case '\r': + case '\n': + case ZDLE: + return c; + } + } +} + + + +/* + * Store long integer pos in Txhdr + */ +void stohdr(long pos) +{ + Txhdr[ZP0] = pos; + Txhdr[ZP1] = pos>>8; + Txhdr[ZP2] = pos>>16; + Txhdr[ZP3] = pos>>24; +} + + + +/* + * Recover a long integer from a header + */ +long rclhdr(register char *shdr) +{ + register long l; + + l = (shdr[ZP3] & 0377); + l = (l << 8) | (shdr[ZP2] & 0377); + l = (l << 8) | (shdr[ZP1] & 0377); + l = (l << 8) | (shdr[ZP0] & 0377); + return l; +} + +/* End of zmmisc.c */ diff --git a/mbsebbs/zmmisc.h b/mbsebbs/zmmisc.h new file mode 100644 index 00000000..fcd0866c --- /dev/null +++ b/mbsebbs/zmmisc.h @@ -0,0 +1,30 @@ +#ifndef _ZMMISC_H +#define _ZMMISC_H + +/* $Id$ */ + +void get_frame_buffer(void); +void free_frame_buffer(void); +void zsbhdr(int, int, register char *); +void zsbh32(int, register char *, int, int); +void zshhdr(int, int, register char *); +void zsdata(register char *, int, int); +void zsda32(register char *, int, int); +int zrdata(register char *, int); +int zrdat32(register char *, int); +void garbitch(void); +int zgethdr(char *); +int zrbhdr(register char *); +int zrbhd32(register char *); +int zrhhdr(char *); +void zputhex(register int); +void zsendline(int); +int zgethex(void); +int zgeth1(void); +int zdlread(void); +int noxrd7(void); +void stohdr(long); +long rclhdr(register char *); + + +#endif diff --git a/mbsebbs/zmodem.h b/mbsebbs/zmodem.h new file mode 100644 index 00000000..303eb14e --- /dev/null +++ b/mbsebbs/zmodem.h @@ -0,0 +1,201 @@ +#ifndef ZMODEM_H +#define ZMODEM_H + +/* $Id$ */ + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef OK +#define OK 0 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define RETRYMAX 10 +#define MAXBLOCK 8192 + +/* + * Z M O D E M . H Manifest constants for ZMODEM + * application to application file transfer protocol + * 04-17-89 Chuck Forsberg Omen Technology Inc + */ +#define ZPAD '*' /* 052 Padding character begins frames */ +#define ZDLE 030 /* Ctrl-X Zmodem escape - `ala BISYNC DLE */ +#define ZDLEE (ZDLE^0100) /* Escaped ZDLE as transmitted */ +#define ZBIN 'A' /* Binary frame indicator (CRC-16) */ +#define ZHEX 'B' /* HEX frame indicator */ +#define ZBIN32 'C' /* Binary frame with 32 bit FCS */ +#define ZBINR32 'D' /* RLE packed Binary frame with 32 bit FCS */ +#define ZVBIN 'a' /* Binary frame indicator (CRC-16) */ +#define ZVHEX 'b' /* HEX frame indicator */ +#define ZVBIN32 'c' /* Binary frame with 32 bit FCS */ +#define ZVBINR32 'd' /* RLE packed Binary frame with 32 bit FCS */ +#define ZRESC 0176 /* RLE flag/escape character */ +#define ZMAXHLEN 16 /* Max header information length NEVER CHANGE */ +#define ZMAXSPLEN 1024 /* Max subpacket length NEVER CHANGE */ + +/* Frame types (see array "frametypes" in zm.c) */ +#define ZRQINIT 0 /* Request receive init */ +#define ZRINIT 1 /* Receive init */ +#define ZSINIT 2 /* Send init sequence (optional) */ +#define ZACK 3 /* ACK to above */ +#define ZFILE 4 /* File name from sender */ +#define ZSKIP 5 /* To sender: skip this file */ +#define ZNAK 6 /* Last packet was garbled */ +#define ZABORT 7 /* Abort batch transfers */ +#define ZFIN 8 /* Finish session */ +#define ZRPOS 9 /* Resume data trans at this position */ +#define ZDATA 10 /* Data packet(s) follow */ +#define ZEOF 11 /* End of file */ +#define ZFERR 12 /* Fatal Read or Write error Detected */ +#define ZCRC 13 /* Request for file CRC and response */ +#define ZCHALLENGE 14 /* Receiver's Challenge */ +#define ZCOMPL 15 /* Request is complete */ +#define ZCAN 16 /* Other end canned session with CAN*5 */ +#define ZFREECNT 17 /* Request for free bytes on filesystem */ +#define ZCOMMAND 18 /* Command from sending program */ +#define ZSTDERR 19 /* Output to standard error, data follows */ + +/* ZDLE sequences */ +#define ZCRCE 'h' /* CRC next, frame ends, header packet follows */ +#define ZCRCG 'i' /* CRC next, frame continues nonstop */ +#define ZCRCQ 'j' /* CRC next, frame continues, ZACK expected */ +#define ZCRCW 'k' /* CRC next, ZACK expected, end of frame */ +#define ZRUB0 'l' /* Translate to rubout 0177 */ +#define ZRUB1 'm' /* Translate to rubout 0377 */ + +/* zdlread return values (internal) */ +/* -1 is general error, -2 is timeout */ +#define GOTOR 0400 +#define GOTCRCE (ZCRCE|GOTOR) /* ZDLE-ZCRCE received */ +#define GOTCRCG (ZCRCG|GOTOR) /* ZDLE-ZCRCG received */ +#define GOTCRCQ (ZCRCQ|GOTOR) /* ZDLE-ZCRCQ received */ +#define GOTCRCW (ZCRCW|GOTOR) /* ZDLE-ZCRCW received */ +#define GOTCAN (GOTOR|030) /* CAN*5 seen */ + +/* Byte positions within header array */ +#define ZF0 3 /* First flags byte */ +#define ZF1 2 +#define ZF2 1 +#define ZF3 0 +#define ZP0 0 /* Low order 8 bits of position */ +#define ZP1 1 +#define ZP2 2 +#define ZP3 3 /* High order 8 bits of file position */ + +/* Parameters for ZRINIT header */ +#define ZRPXWN 8 /* 9th byte in header contains window size/256 */ +#define ZRPXQQ 9 /* 10th to 14th bytes contain quote mask */ +/* Bit Masks for ZRINIT flags byte ZF0 */ +#define CANFDX 01 /* Rx can send and receive true FDX */ +#define CANOVIO 02 /* Rx can receive data during disk I/O */ +#define CANBRK 04 /* Rx can send a break signal */ +#define CANRLE 010 /* Receiver can decode RLE */ +#define CANLZW 020 /* Receiver can uncompress */ +#define CANFC32 040 /* Receiver can use 32 bit Frame Check */ +#define ESCCTL 0100 /* Receiver expects ctl chars to be escaped */ +#define ESC8 0200 /* Receiver expects 8th bit to be escaped */ + +/* Bit Masks for ZRINIT flags byte ZF1 */ +#define CANVHDR 01 /* Variable headers OK */ +#define ZRRQWN 8 /* Receiver specified window size in ZRPXWN */ +#define ZRRQQQ 16 /* Additional control chars to quote in ZRPXQQ */ +#define ZRQNVH (ZRRQWN|ZRRQQQ) /* Variable len hdr reqd to access info */ + +/* Parameters for ZSINIT frame */ +#define ZATTNLEN 32 /* Max length of attention string */ +#define ALTCOFF ZF1 /* Offset to alternate canit string, 0 if not used */ +/* Bit Masks for ZSINIT flags byte ZF0 */ +#define TESCCTL 0100 /* Transmitter expects ctl chars to be escaped */ +#define TESC8 0200 /* Transmitter expects 8th bit to be escaped */ + +/* Parameters for ZFILE frame */ +/* Conversion options one of these in ZF0 */ +#define ZCBIN 1 /* Binary transfer - inhibit conversion */ +#define ZCNL 2 /* Convert NL to local end of line convention */ +#define ZCRESUM 3 /* Resume interrupted file transfer */ +/* Management include options, one of these ored in ZF1 */ +#define ZMSKNOLOC 0200 /* Skip file if not present at rx */ +/* Management options, one of these ored in ZF1 */ +#define ZMMASK 037 /* Mask for the choices below */ +#define ZMNEWL 1 /* Transfer if source newer or longer */ +#define ZMCRC 2 /* Transfer if different file CRC or length */ +#define ZMAPND 3 /* Append contents to existing file (if any) */ +#define ZMCLOB 4 /* Replace existing file */ +#define ZMNEW 5 /* Transfer if source newer */ + /* Number 5 is alive ... */ +#define ZMDIFF 6 /* Transfer if dates or lengths different */ +#define ZMPROT 7 /* Protect destination file */ +#define ZMCHNG 8 /* Change filename if destination exists */ +/* Transport options, one of these in ZF2 */ +#define ZTLZW 1 /* Lempel-Ziv compression */ +#define ZTRLE 3 /* Run Length encoding */ +/* Extended options for ZF3, bit encoded */ +#define ZXSPARS 64 /* Encoding for sparse file operations */ +#define ZCANVHDR 01 /* Variable headers OK */ +/* Receiver window size override */ +#define ZRWOVR 4 /* byte position for receive window override/256 */ + +/* Parameters for ZCOMMAND frame ZF0 (otherwise 0) */ +#define ZCACK1 1 /* Acknowledge, then do command */ + +long rclhdr(register char *); + +/* Globals used by ZMODEM functions */ +extern int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame */ +extern int Rxtype; /* Type of header received */ +extern int Rxcount; /* Count of data bytes received */ +extern int long Rxpos; /* Received file position */ +extern int long Txpos; /* Transmitted file position */ +extern int Txfcs32; /* TURE means send binary frames with 32 bit FCS */ +extern int Crc32t; /* Display flag indicating 32 bit CRC being sent */ +extern int Crc32r; /* Display flag indicating 32 bit CRC being received */ +extern int Crc32; /* Display flag indicating 32 bit CRC being received */ +extern int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ +extern char Rxhdr[]; +extern char Txhdr[]; +extern char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ +extern char *Altcan; /* Alternate canit string */ +extern char *Zendnames[]; +extern char *txbuf; +extern char *rxbuf; + +/* End of ZMODEM.H */ + +char Zsendmask[33]; /* Additional control characters to mask */ + +extern int Effbaud; +extern int Zmodem; +extern int Zctlesc; +extern int Filesleft; +extern long Totalleft; + +extern char *frametypes[]; +#define FTOFFSET 16 + +//extern void zsbhdr(int,int,char*); +//extern void zshhdr(int,int,char*); +//extern int zgethdr(char*); +//extern void zsdata(char*,int,int); +//extern int zrdata(char*,int); +//extern void stohdr(long); + +//extern void zsendline(int); +//extern void zsdar32(char*,int,int); +//extern int zrdatr32(char*,int); +//extern int zdlread(void); + +extern unsigned short crc16xmodemtab[]; +extern unsigned long crc32tab[]; +#define updcrc16(cp,crc) (crc16xmodemtab[(((int)crc >> 8) & 0xff)] ^ (crc << 8) ^ cp) +#define updcrc32(cp,crc) (crc32tab[((int)crc ^ cp) & 0xff] ^ ((crc >> 8) & 0x00ffffff)) + +//int zmsndfiles(file_list *); +int zmrcvfiles(void); + +#endif + diff --git a/mbsebbs/zmrle.c b/mbsebbs/zmrle.c index 3299b4dd..2fea9409 100644 --- a/mbsebbs/zmrle.c +++ b/mbsebbs/zmrle.c @@ -43,6 +43,7 @@ #include "ttyio.h" #include "zmodem.h" #include "zmrle.h" +#include "zmmisc.h" /* diff --git a/mbsebbs/zmrle.h b/mbsebbs/zmrle.h new file mode 100644 index 00000000..42f29410 --- /dev/null +++ b/mbsebbs/zmrle.h @@ -0,0 +1,9 @@ +#ifndef _ZMRLE_H +#define _ZMRLE_H + +/* $Id$ */ + +void zsdar32(char *, int, int); +int zrdatr32(register char *, int); + +#endif