| /* |
| zm.c - zmodem protocol handling lowlevelstuff |
| Copyright (C) until 1998 Chuck Forsberg (OMEN Technology Inc) |
| Copyright (C) 1996, 1997 Uwe Ohse |
| |
| This program 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. |
| |
| This program 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 this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA |
| 02111-1307, USA. |
| |
| originally written by Chuck Forsberg |
| */ |
| /* historical comment: -- uwe |
| * Z M . C |
| * ZMODEM protocol primitives |
| * 05-09-88 Chuck Forsberg Omen Technology Inc |
| * |
| * Entry point Functions: |
| * zsbhdr(type, hdr) send binary header |
| * zshhdr(type, hdr) send hex header |
| * zgethdr(hdr, eflag) receive header - binary or hex |
| * zsdata(buf, len, frameend) send data |
| * zrdata(buf, len, bytes_received) receive data |
| * stohdr(pos) store position data in Txhdr |
| * long rclhdr(hdr) recover position offset from header |
| */ |
| |
| |
| #include "zglobal.h" |
| |
| #include <stdio.h> |
| |
| unsigned int Rxtimeout = 100; /* Tenths of seconds to wait for something */ |
| |
| /* Globals used by ZMODEM functions */ |
| int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */ |
| int Rxtype; /* Type of header received */ |
| char Rxhdr[4]; /* Received header */ |
| char Txhdr[4]; /* Transmitted header */ |
| long Txpos; /* Transmitted file position */ |
| int Txfcs32; /* TRUE means send binary frames with 32 bit FCS */ |
| int Crc32t; /* Display flag indicating 32 bit CRC being sent */ |
| int Crc32; /* Display flag indicating 32 bit CRC being received */ |
| int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ |
| char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ |
| |
| static char lastsent; /* Last char we sent */ |
| int turbo_escape; |
| int bytes_per_error=0; |
| |
| static const char *frametypes[] = { |
| "Carrier Lost", /* -3 */ |
| "TIMEOUT", /* -2 */ |
| "ERROR", /* -1 */ |
| #define FTOFFSET 3 |
| "ZRQINIT", |
| "ZRINIT", |
| "ZSINIT", |
| "ZACK", |
| "ZFILE", |
| "ZSKIP", |
| "ZNAK", |
| "ZABORT", |
| "ZFIN", |
| "ZRPOS", |
| "ZDATA", |
| "ZEOF", |
| "ZFERR", |
| "ZCRC", |
| "ZCHALLENGE", |
| "ZCOMPL", |
| "ZCAN", |
| "ZFREECNT", |
| "ZCOMMAND", |
| "ZSTDERR", |
| "xxxxx" |
| #define FRTYPES 22 /* Total number of frame types in this array */ |
| /* not including psuedo negative entries */ |
| }; |
| |
| #define badcrc _("Bad CRC") |
| /* static char *badcrc = "Bad CRC"; */ |
| static inline int noxrd7 __P ((void)); |
| static inline int zdlread __P ((void)); |
| static int zdlread2 __P ((int)) LRZSZ_ATTRIB_REGPARM(1); |
| static inline int zgeth1 __P ((void)); |
| static void zputhex __P ((int c, char *pos)); |
| static inline int zgethex __P ((void)); |
| static int zrbhdr __P ((char *hdr)); |
| static int zrbhdr32 __P ((char *hdr)); |
| static int zrhhdr __P ((char *hdr)); |
| static char zsendline_tab[256]; |
| static int zrdat32 __P ((char *buf, int length, size_t *)); |
| static void zsbh32 __P ((char *hdr, int type)); |
| static inline void zsendline_s __P((const char *s, size_t count)); |
| |
| extern int zmodem_requested; |
| |
| #define sendline(c) putchar((c) & 0377) |
| #define xsendline(c) putchar(c) |
| |
| /* |
| * Read a character from the modem line with timeout. |
| * Eat parity, XON and XOFF characters. |
| */ |
| static inline int |
| noxrd7(void) |
| { |
| register int c; |
| |
| for (;;) { |
| if ((c = READLINE_PF(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; |
| } |
| } |
| } |
| |
| static inline 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 ERROR; |
| if ((c = noxrd7()) < 0) |
| return c; |
| c -= '0'; |
| if (c > 9) |
| c -= ('a' - ':'); |
| if (c & ~0xF) |
| return ERROR; |
| c += (n<<4); |
| return c; |
| } |
| |
| /* Decode two lower case hex digits into an 8 bit byte value */ |
| static inline int |
| zgethex(void) |
| { |
| register int c; |
| |
| c = zgeth1(); |
| VPRINTF(9,("zgethex: %02X", c)); |
| return c; |
| } |
| |
| /* |
| * Read a byte, checking for ZMODEM escape encoding |
| * including CAN*5 which represents a quick abort |
| */ |
| static inline int |
| zdlread(void) |
| { |
| int c; |
| /* Quick check for non control characters */ |
| if ((c = READLINE_PF(Rxtimeout)) & 0140) |
| return c; |
| return zdlread2(c); |
| } |
| /* no, i don't like gotos. -- uwe */ |
| static int |
| zdlread2(int c) |
| { |
| goto jump_over; /* bad style */ |
| |
| again: |
| /* Quick check for non control characters */ |
| if ((c = READLINE_PF(Rxtimeout)) & 0140) |
| return c; |
| jump_over: |
| switch (c) { |
| case ZDLE: |
| break; |
| case XON: |
| case (XON|0200): |
| case XOFF: |
| case (XOFF|0200): |
| goto again; |
| default: |
| if (Zctlesc && !(c & 0140)) { |
| goto again; |
| } |
| return c; |
| } |
| again2: |
| if ((c = READLINE_PF(Rxtimeout)) < 0) |
| return c; |
| if (c == CAN && (c = READLINE_PF(Rxtimeout)) < 0) |
| return c; |
| if (c == CAN && (c = READLINE_PF(Rxtimeout)) < 0) |
| return c; |
| if (c == CAN && (c = READLINE_PF(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 XON: |
| case (XON|0200): |
| case XOFF: |
| case (XOFF|0200): |
| goto again2; |
| default: |
| if (Zctlesc && ! (c & 0140)) { |
| goto again2; |
| } |
| if ((c & 0140) == 0100) |
| return (c ^ 0100); |
| break; |
| } |
| VPRINTF(2,(_("Bad escape sequence %x"), c)); |
| return ERROR; |
| } |
| |
| |
| |
| /* |
| * Send character c with ZMODEM escape sequence encoding. |
| * Escape XON, XOFF. Escape CR following @ (Telenet net escape) |
| */ |
| inline void |
| zsendline(int c) |
| { |
| |
| switch(zsendline_tab[(unsigned) (c&=0377)]) |
| { |
| case 0: |
| xsendline(lastsent = c); |
| break; |
| case 1: |
| xsendline(ZDLE); |
| c ^= 0100; |
| xsendline(lastsent = c); |
| break; |
| case 2: |
| if ((lastsent & 0177) != '@') { |
| xsendline(lastsent = c); |
| } else { |
| xsendline(ZDLE); |
| c ^= 0100; |
| xsendline(lastsent = c); |
| } |
| break; |
| } |
| } |
| |
| static inline void |
| zsendline_s(const char *s, size_t count) |
| { |
| const char *end=s+count; |
| while(s!=end) { |
| int last_esc=0; |
| const char *t=s; |
| while (t!=end) { |
| last_esc=zsendline_tab[(unsigned) ((*t) & 0377)]; |
| if (last_esc) |
| break; |
| t++; |
| } |
| if (t!=s) { |
| fwrite(s,(size_t)(t-s),1,stdout); |
| lastsent=t[-1]; |
| s=t; |
| } |
| if (last_esc) { |
| int c=*s; |
| switch(last_esc) { |
| case 0: |
| xsendline(lastsent = c); |
| break; |
| case 1: |
| xsendline(ZDLE); |
| c ^= 0100; |
| xsendline(lastsent = c); |
| break; |
| case 2: |
| if ((lastsent & 0177) != '@') { |
| xsendline(lastsent = c); |
| } else { |
| xsendline(ZDLE); |
| c ^= 0100; |
| xsendline(lastsent = c); |
| } |
| break; |
| } |
| s++; |
| } |
| } |
| } |
| |
| |
| /* Send ZMODEM binary header hdr of type type */ |
| void |
| zsbhdr(int type, char *hdr) |
| { |
| register int n; |
| register unsigned short crc; |
| |
| VPRINTF(3,("zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr))); |
| if (type == ZDATA) |
| for (n = Znulls; --n >=0; ) |
| xsendline(0); |
| |
| xsendline(ZPAD); xsendline(ZDLE); |
| |
| Crc32t=Txfcs32; |
| if (Crc32t) |
| zsbh32(hdr, type); |
| else { |
| xsendline(ZBIN); zsendline(type); crc = updcrc(type, 0); |
| |
| for (n=4; --n >= 0; ++hdr) { |
| zsendline(*hdr); |
| crc = updcrc((0377& *hdr), crc); |
| } |
| crc = updcrc(0,updcrc(0,crc)); |
| zsendline(crc>>8); |
| zsendline(crc); |
| } |
| if (type != ZDATA) |
| flushmo(); |
| } |
| |
| |
| /* Send ZMODEM binary header hdr of type type */ |
| static void |
| zsbh32(char *hdr, int type) |
| { |
| register int n; |
| register unsigned long crc; |
| |
| xsendline(ZBIN32); zsendline(type); |
| crc = 0xFFFFFFFFL; crc = UPDC32(type, crc); |
| |
| for (n=4; --n >= 0; ++hdr) { |
| crc = UPDC32((0377 & *hdr), crc); |
| zsendline(*hdr); |
| } |
| crc = ~crc; |
| for (n=4; --n >= 0;) { |
| zsendline((int)crc); |
| crc >>= 8; |
| } |
| } |
| |
| /* Send ZMODEM HEX header hdr of type type */ |
| void |
| zshhdr(int type, char *hdr) |
| { |
| register int n; |
| register unsigned short crc; |
| char s[30]; |
| size_t len; |
| |
| VPRINTF(3,("zshhdr: %s %lx", frametypes[(type & 0x7f)+FTOFFSET], rclhdr(hdr))); |
| s[0]=ZPAD; |
| s[1]=ZPAD; |
| s[2]=ZDLE; |
| s[3]=ZHEX; |
| zputhex(type & 0x7f ,s+4); |
| len=6; |
| Crc32t = 0; |
| |
| crc = updcrc((type & 0x7f), 0); |
| for (n=4; --n >= 0; ++hdr) { |
| zputhex(*hdr,s+len); |
| len += 2; |
| crc = updcrc((0377 & *hdr), crc); |
| } |
| crc = updcrc(0,updcrc(0,crc)); |
| zputhex(crc>>8,s+len); |
| zputhex(crc,s+len+2); |
| len+=4; |
| |
| /* Make it printable on remote machine */ |
| s[len++]=015; |
| s[len++]=0212; |
| /* |
| * Uncork the remote in case a fake XOFF has stopped data flow |
| */ |
| if (type != ZFIN && type != ZACK) |
| { |
| s[len++]=021; |
| } |
| flushmo(); |
| write(1,s,len); |
| } |
| |
| /* |
| * Send binary array buf of length length, with ending ZDLE sequence frameend |
| */ |
| static const char *Zendnames[] = { "ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW"}; |
| void |
| zsdata(const char *buf, size_t length, int frameend) |
| { |
| register unsigned short crc; |
| |
| VPRINTF(3,("zsdata: %lu %s", (unsigned long) length, |
| Zendnames[(frameend-ZCRCE)&3])); |
| crc = 0; |
| do { |
| zsendline(*buf); crc = updcrc((0377 & *buf), crc); |
| buf++; |
| } while (--length>0); |
| xsendline(ZDLE); xsendline(frameend); |
| crc = updcrc(frameend, crc); |
| |
| crc = updcrc(0,updcrc(0,crc)); |
| zsendline(crc>>8); zsendline(crc); |
| if (frameend == ZCRCW) { |
| xsendline(XON); flushmo(); |
| } |
| } |
| |
| void |
| zsda32(const char *buf, size_t length, int frameend) |
| { |
| int c; |
| unsigned long crc; |
| int i; |
| VPRINTF(3,("zsdat32: %d %s", length, Zendnames[(frameend-ZCRCE)&3])); |
| |
| crc = 0xFFFFFFFFL; |
| zsendline_s(buf,length); |
| for (; length; length--) { |
| c = *buf & 0377; |
| crc = UPDC32(c, crc); |
| buf++; |
| } |
| xsendline(ZDLE); xsendline(frameend); |
| crc = UPDC32(frameend, crc); |
| |
| crc = ~crc; |
| for (i=4; --i >= 0;) { |
| c=(int) crc; |
| if (c & 0140) |
| xsendline(lastsent = c); |
| else |
| zsendline(c); |
| crc >>= 8; |
| } |
| if (frameend == ZCRCW) { |
| xsendline(XON); flushmo(); |
| } |
| } |
| |
| #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ <= 4) |
| # undef DEBUG_BLOCKSIZE |
| #endif |
| |
| #ifdef DEBUG_BLOCKSIZE |
| struct debug_blocksize { |
| int size; |
| long count; |
| }; |
| struct debug_blocksize blocksizes[]={ |
| {32,0}, |
| {64,0}, |
| {128,0}, |
| {256,0}, |
| {512,0}, |
| {1024,0}, |
| {2048,0}, |
| {4096,0}, |
| {8192,0}, |
| {0,0} |
| }; |
| static inline void |
| count_blk(int size) |
| { |
| int i; |
| for (i=0;blocksizes[i].size;i++) { |
| if (blocksizes[i].size==size) { |
| blocksizes[i].count++; |
| return; |
| } |
| } |
| blocksizes[i].count++; |
| } |
| |
| static void printout_blocksizes(void) __attribute__((__destructor__)); |
| static void |
| printout_blocksizes(void) |
| { |
| int i; |
| for (i=0;blocksizes[i].size;i++) { |
| if (blocksizes[i].count) { |
| lsyslog(LOG_DEBUG,"%4d byte: %ld blocks\n", |
| blocksizes[i].size,blocksizes[i].count); |
| } |
| } |
| if (blocksizes[i].count) { |
| lsyslog(LOG_DEBUG,"unk. byte: %ld blocks", |
| blocksizes[i].count); |
| } |
| } |
| #define COUNT_BLK(x) count_blk(x) |
| #else |
| #define COUNT_BLK(x) |
| #endif |
| |
| /* |
| * 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(char *buf, int length, size_t *bytes_received) |
| { |
| register int c; |
| register unsigned short crc; |
| register char *end; |
| register int d; |
| |
| *bytes_received=0; |
| if (Rxframeind == ZBIN32) |
| return zrdat32(buf, length, bytes_received); |
| |
| crc = 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 = updcrc(c, crc); |
| if ((c = zdlread()) & ~0377) |
| goto crcfoo; |
| crc = updcrc(c, crc); |
| if ((c = zdlread()) & ~0377) |
| goto crcfoo; |
| crc = updcrc(c, crc); |
| if (crc & 0xFFFF) { |
| zperr(badcrc); |
| return ERROR; |
| } |
| *bytes_received = length - (end - buf); |
| COUNT_BLK(*bytes_received); |
| VPRINTF(3,("zrdata: %lu %s", (unsigned long) (*bytes_received), |
| Zendnames[(d-GOTCRCE)&3])); |
| return d; |
| } |
| case GOTCAN: |
| zperr(_("Sender Canceled")); |
| return ZCAN; |
| case TIMEOUT: |
| zperr(_("TIMEOUT")); |
| return c; |
| default: |
| zperr(_("Bad data subpacket")); |
| return c; |
| } |
| } |
| *buf++ = c; |
| crc = updcrc(c, crc); |
| } |
| zperr(_("Data subpacket too long")); |
| return ERROR; |
| } |
| |
| static int |
| zrdat32(char *buf, int length, size_t *bytes_received) |
| { |
| register int c; |
| register unsigned long crc; |
| register char *end; |
| register int d; |
| |
| crc = 0xFFFFFFFFL; 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 = UPDC32(c, crc); |
| if ((c = zdlread()) & ~0377) |
| goto crcfoo; |
| crc = UPDC32(c, crc); |
| if ((c = zdlread()) & ~0377) |
| goto crcfoo; |
| crc = UPDC32(c, crc); |
| if ((c = zdlread()) & ~0377) |
| goto crcfoo; |
| crc = UPDC32(c, crc); |
| if ((c = zdlread()) & ~0377) |
| goto crcfoo; |
| crc = UPDC32(c, crc); |
| if (crc != 0xDEBB20E3) { |
| zperr(badcrc); |
| return ERROR; |
| } |
| *bytes_received = length - (end - buf); |
| COUNT_BLK(*bytes_received); |
| VPRINTF(3,("zrdat32: %lu %s", (unsigned long) *bytes_received, |
| Zendnames[(d-GOTCRCE)&3])); |
| return d; |
| case GOTCAN: |
| zperr(_("Sender Canceled")); |
| return ZCAN; |
| case TIMEOUT: |
| zperr(_("TIMEOUT")); |
| return c; |
| default: |
| zperr(_("Bad data subpacket")); |
| return c; |
| } |
| } |
| *buf++ = c; |
| crc = UPDC32(c, crc); |
| } |
| zperr(_("Data subpacket too long")); |
| return ERROR; |
| } |
| |
| /* |
| * Read a ZMODEM header to hdr, either binary or hex. |
| * eflag controls local display of non zmodem characters: |
| * 0: no display |
| * 1: display printing characters only |
| * 2: display all non ZMODEM characters |
| * 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 *hdr, int eflag, size_t *Rxpos) |
| { |
| register int c, cancount; |
| unsigned int max_garbage; /* Max bytes before start of frame */ |
| size_t rxpos=0; /* keep gcc happy */ |
| |
| max_garbage = Zrwindow + Baudrate; |
| Rxframeind = Rxtype = 0; |
| |
| startover: |
| cancount = 5; |
| again: |
| /* Return immediate ERROR if ZCRCW sequence seen */ |
| switch (c = READLINE_PF(Rxtimeout)) { |
| case RCDO: |
| case TIMEOUT: |
| goto fifi; |
| case CAN: |
| gotcan: |
| if (--cancount <= 0) { |
| c = ZCAN; goto fifi; |
| } |
| switch (c = READLINE_PF(1)) { |
| case TIMEOUT: |
| goto again; |
| case ZCRCW: |
| c = ERROR; |
| /* **** FALL THRU TO **** */ |
| case RCDO: |
| goto fifi; |
| default: |
| break; |
| case CAN: |
| if (--cancount <= 0) { |
| c = ZCAN; goto fifi; |
| } |
| goto again; |
| } |
| /* **** FALL THRU TO **** */ |
| default: |
| agn2: |
| if ( --max_garbage == 0) { |
| zperr(_("Garbage count exceeded")); |
| return(ERROR); |
| } |
| if (eflag && ((c &= 0177) & 0140) && Verbose) |
| vchar(c); |
| else if (eflag > 1 && Verbose) |
| vchar(c); |
| goto startover; |
| case ZPAD|0200: /* This is what we want. */ |
| case ZPAD: /* This is what we want. */ |
| break; |
| } |
| cancount = 5; |
| splat: |
| switch (c = noxrd7()) { |
| case ZPAD: |
| goto splat; |
| case RCDO: |
| case TIMEOUT: |
| goto fifi; |
| default: |
| goto agn2; |
| case ZDLE: /* This is what we want. */ |
| break; |
| } |
| |
| switch (c = noxrd7()) { |
| case RCDO: |
| case TIMEOUT: |
| goto fifi; |
| case ZBIN: |
| Rxframeind = ZBIN; Crc32 = FALSE; |
| c = zrbhdr(hdr); |
| break; |
| case ZBIN32: |
| Crc32 = Rxframeind = ZBIN32; |
| c = zrbhdr32(hdr); |
| break; |
| case ZHEX: |
| Rxframeind = ZHEX; Crc32 = FALSE; |
| c = zrhhdr(hdr); |
| break; |
| case CAN: |
| goto gotcan; |
| default: |
| goto agn2; |
| } |
| rxpos = hdr[ZP3] & 0377; |
| rxpos = (rxpos<<8) + (hdr[ZP2] & 0377); |
| rxpos = (rxpos<<8) + (hdr[ZP1] & 0377); |
| rxpos = (rxpos<<8) + (hdr[ZP0] & 0377); |
| fifi: |
| switch (c) { |
| case GOTCAN: |
| c = ZCAN; |
| /* **** FALL THRU TO **** */ |
| case ZNAK: |
| case ZCAN: |
| case ERROR: |
| case TIMEOUT: |
| case RCDO: |
| zperr(_("Got %s"), frametypes[c+FTOFFSET]); |
| /* **** FALL THRU TO **** */ |
| default: |
| if (c >= -3 && c <= FRTYPES) |
| VPRINTF(3,("zgethdr: %s %lx", frametypes[c+FTOFFSET], (unsigned long) rxpos)); |
| else |
| VPRINTF(3,("zgethdr: %d %lx", c, (unsigned long) rxpos)); |
| } |
| if (Rxpos) |
| *Rxpos=rxpos; |
| return c; |
| } |
| |
| /* Receive a binary style header (type and position) */ |
| static int |
| zrbhdr(char *hdr) |
| { |
| register int c, n; |
| register unsigned short crc; |
| |
| if ((c = zdlread()) & ~0377) |
| return c; |
| Rxtype = c; |
| crc = updcrc(c, 0); |
| |
| for (n=4; --n >= 0; ++hdr) { |
| if ((c = zdlread()) & ~0377) |
| return c; |
| crc = updcrc(c, crc); |
| *hdr = c; |
| } |
| if ((c = zdlread()) & ~0377) |
| return c; |
| crc = updcrc(c, crc); |
| if ((c = zdlread()) & ~0377) |
| return c; |
| crc = updcrc(c, crc); |
| if (crc & 0xFFFF) { |
| zperr(badcrc); |
| return ERROR; |
| } |
| protocol = ZM_ZMODEM; |
| zmodem_requested=TRUE; |
| return Rxtype; |
| } |
| |
| /* Receive a binary style header (type and position) with 32 bit FCS */ |
| static int |
| zrbhdr32(char *hdr) |
| { |
| register int c, n; |
| register unsigned long crc; |
| |
| if ((c = zdlread()) & ~0377) |
| return c; |
| Rxtype = c; |
| crc = 0xFFFFFFFFL; crc = UPDC32(c, crc); |
| #ifdef DEBUGZ |
| VPRINTF(3,("zrbhdr32 c=%X crc=%lX", c, crc)i); |
| #endif |
| |
| for (n=4; --n >= 0; ++hdr) { |
| if ((c = zdlread()) & ~0377) |
| return c; |
| crc = UPDC32(c, crc); |
| *hdr = c; |
| #ifdef DEBUGZ |
| VPRINTF(3,("zrbhdr32 c=%X crc=%lX", c, crc)); |
| #endif |
| } |
| for (n=4; --n >= 0;) { |
| if ((c = zdlread()) & ~0377) |
| return c; |
| crc = UPDC32(c, crc); |
| #ifdef DEBUGZ |
| VPRINTF(3,("zrbhdr32 c=%X crc=%lX", c, crc)); |
| #endif |
| } |
| if (crc != 0xDEBB20E3) { |
| zperr(badcrc); |
| return ERROR; |
| } |
| protocol = ZM_ZMODEM; |
| zmodem_requested=TRUE; |
| return Rxtype; |
| } |
| |
| |
| /* Receive a hex style header (type and position) */ |
| static int |
| zrhhdr(char *hdr) |
| { |
| register int c; |
| register unsigned short crc; |
| register int n; |
| |
| if ((c = zgethex()) < 0) |
| return c; |
| Rxtype = c; |
| crc = updcrc(c, 0); |
| |
| for (n=4; --n >= 0; ++hdr) { |
| if ((c = zgethex()) < 0) |
| return c; |
| crc = updcrc(c, crc); |
| *hdr = c; |
| } |
| if ((c = zgethex()) < 0) |
| return c; |
| crc = updcrc(c, crc); |
| if ((c = zgethex()) < 0) |
| return c; |
| crc = updcrc(c, crc); |
| if (crc & 0xFFFF) { |
| zperr(badcrc); return ERROR; |
| } |
| switch ( c = READLINE_PF(1)) { |
| case 0215: |
| /* **** FALL THRU TO **** */ |
| case 015: |
| /* Throw away possible cr/lf */ |
| READLINE_PF(1); |
| break; |
| } |
| protocol = ZM_ZMODEM; |
| zmodem_requested=TRUE; |
| return Rxtype; |
| } |
| |
| /* Write a byte as two hex digits */ |
| static void |
| zputhex(int c, char *pos) |
| { |
| static char digits[] = "0123456789abcdef"; |
| |
| VPRINTF(9,("zputhex: %02X", c)); |
| pos[0]=digits[(c&0xF0)>>4]; |
| pos[1]=digits[c&0x0F]; |
| } |
| |
| void |
| zsendline_init(void) |
| { |
| int i; |
| for (i=0;i<256;i++) { |
| if (i & 0140) |
| zsendline_tab[i]=0; |
| else { |
| switch(i) |
| { |
| case ZDLE: |
| case XOFF: /* ^Q */ |
| case XON: /* ^S */ |
| case (XOFF | 0200): |
| case (XON | 0200): |
| zsendline_tab[i]=1; |
| break; |
| case 020: /* ^P */ |
| case 0220: |
| if (turbo_escape) |
| zsendline_tab[i]=0; |
| else |
| zsendline_tab[i]=1; |
| break; |
| case 015: |
| case 0215: |
| if (Zctlesc) |
| zsendline_tab[i]=1; |
| else if (!turbo_escape) |
| zsendline_tab[i]=2; |
| else |
| zsendline_tab[i]=0; |
| break; |
| default: |
| if (Zctlesc) |
| zsendline_tab[i]=1; |
| else |
| zsendline_tab[i]=0; |
| } |
| } |
| } |
| } |
| |
| |
| |
| /* Store pos in Txhdr */ |
| void |
| stohdr(size_t pos) |
| { |
| long lpos=(long) pos; |
| Txhdr[ZP0] = lpos; |
| Txhdr[ZP1] = lpos>>8; |
| Txhdr[ZP2] = lpos>>16; |
| Txhdr[ZP3] = lpos>>24; |
| } |
| |
| /* Recover a long integer from a header */ |
| long |
| rclhdr(char *hdr) |
| { |
| long l; |
| |
| l = (hdr[ZP3] & 0377); |
| l = (l << 8) | (hdr[ZP2] & 0377); |
| l = (l << 8) | (hdr[ZP1] & 0377); |
| l = (l << 8) | (hdr[ZP0] & 0377); |
| return l; |
| } |
| |
| /* End of zm.c */ |